# Deterministic verification Development and independent review run focused tests for the changed semantic owner and its consumers. An executable edit does not by itself require the complete suite. Complete behavioral validation runs on a stable executable candidate for delivery proof, an explicit full-validation/timing request, or a cross-suite risk that focused evidence cannot settle. [ADR 0036](adr/0036-separate-focused-development-from-delivery-verification.md) owns this scheduling decision. | Scope | Entry and required selection | | --- | --- | | Backend | `npm run test:backend:focus -- --file test/.test.js --test-name-pattern=""` | | Client | `npm run test:client:focus -- ""` | | Layout | `npm run test:client:layout:focus -- --case ` | | Fallback/native fixture | `npm run test:client:fallback:focus -- --case ` | Backend and browser entries accept `--list`, and selections can repeat. Omitting selection from a focused execution fails before starting the suite. `test:semantics` selects six files and is not a quick diagnostic; choose its relevant file/case through `test:backend:focus`. An independent layout invocation exports fresh HTML through `test:client:fixtures`, which selects only the two tests that own all 26 states. Its browser assertions remain unchanged. The complete visual gate still runs the full Client suite once and reuses its exports. Fixtures supplied through `--fixtures-dir` must come from the current candidate. `npm run check` classifies the complete source candidate against HEAD, runs the appropriate checks below, checks source/ledger stability, and records the verified tree and verification scope for the commit hook. Run `check` alone when the ledger is absent or resolved; while findings remain unresolved, use `verify`. Do not run complete component suites around the same final command: that duplicates its work. Focused evidence is not a source-bound commit proof. Inspect a failed gate's stage/case, reproduce it with a focused entry, repair it, and rerun the final command only after the candidate is stable. The full branch of `check` runs `npm run verify:check`: `review:validate`, `host:channels:verify`, `host:shape-check`, `semantic:check`, `build:check`, the syntax checks and `scripts/deterministic-test-groups.mjs --check`, which selects `npm run test:client` and `npm run test:backend:fast`. The Client units run in the gate because a change can be covered only by them; the backend tier is the set of test files `semantic-obligations.json` names as evidence for at least one obligation, excluding coverage-only paths and the verification-tooling probes that fail by construction outside their harness. It targets a few minutes so the commit gate is actually run; [ADR 0046](adr/0046-gate-the-commit-with-the-semantic-evidence-tier.md) owns this split and its evidence. `npm run verify` keeps the complete behavioral gate: `test:client:visual` plus the whole ordinary backend inventory. CI runs `verify:ci`; release preparation runs `verify`, and coverage stays release-only. A change that touches a semantic owner missing from the graph must extend the graph, which widens the fast tier at the same time. The browser suites are not part of the commit gate: they are the complete visual contract and run in `verify`, in CI, and on demand. Stage runners print inventory, concurrency and elapsed times. Start a permitted long gate with a short tool yield and retain its process/session ID. Tell the user the command, start time and expected range before waiting. Keep verbose diagnostics in ignored logs and wait on the same process in intervals no longer than 60 seconds. Report completed stages, failures or changed timing expectations. Inspect process activity and stage output before treating a slow run as stalled; elapsed time alone is insufficient. Stop only the owned process on cancellation, and never report an interrupted run as verified. Do not start another copy while waiting. ## Change classification `npm run verify:docs` checks a documentation-only candidate without starting builds, runtime tests, browsers or models. It rejects a mixed candidate instead of expanding into the full gate. `npm run check` chooses this same path automatically when every change from HEAD is a regular non-executable Markdown file in `docs/`, `AGENTS.md`, `CONTEXT.md`, `README.md` or `README.en.md`. Additions and deletions count, as do unstaged and untracked source files. Markdown fixtures, templates, symlinks, executable modes, configuration, tests and implementation changes select full verification. An explicit complete-validation request uses `npm run check -- --full` for a source proof or `npm run verify` for behavioral validation alone, regardless of changed paths. An unchanged tree also uses the full path when a new check is explicitly requested; reuse an existing matching proof instead. The documentation path checks diff whitespace, local link target existence and literal `npm run` commands in changed documents and documents linking to them. It does not execute code blocks, visit remote links, check heading anchors or establish semantic accuracy. Independent review checks anchors, contracts, examples and instruction behavior against their owners. A deleted document is checked through its remaining referrers. Source, `HEAD` and findings stay unchanged through verification; after that stability check, a resolved local findings ledger may be archived. The proof records `documentation` or `full`. `check` does not enforce the review plan, lane evidence or prospective-index identity: `review:finalize` enforces the first two after the proof, and pre-commit enforces the last against the staged tree. [ADR 0039](adr/0039-verify-documentation-without-runtime-suites.md) owns this distinction. For test-description or comment changes, inspect the diff and verify that test registration, selectors, executable fixtures and assertions retain their meaning. Select changed cases when execution can distinguish a possible behavior change; cosmetic wording does not justify unrelated runtime or browser matrices. Runtime or verification-owner changes use their focused regressions. These development observations do not replace the candidate classification used for a later commit. ## Reading test output Start with the selected inventory and a case pattern. Keep lengthy complete-run output in an ignored log, report the command, exit status, elapsed time and failures, then read the failing case's local context. Do not replay successful-case inventories or entire prior logs into progress messages and handoffs. Preserve exact failure text and its log location; summaries are not substitutes for evidence when diagnosing a failure. Test descriptions follow [the semantic naming guidance](semantic-validation.md#test-descriptions). ## Findings ledger Before creating or updating findings, read [Findings ledger](review-procedure.md#findings-ledger). ## Incremental independent review Before independent review or a review-state command, read [Incremental independent review](review-procedure.md#incremental-independent-review). Keep reviewer reports outside the checkout or in an ignored path so they cannot become candidate source after the plan is frozen. Both documentation and executable changes retain source-bound proof, independent review and prospective-index checks. ## Complete behavioral validation The full local and CI behavioral gates run `test:client:visual`: one Client suite exports fresh renderer fixtures, followed by deterministic browser layout and visual assertions. Install its locked browser first with `npx playwright install --with-deps chromium`; missing browsers fail verification. The [Client visual contract](client-visual-contract.md) owns the bounded control/state inventory, reference palettes, fault counterexamples and official-Host evidence limits. Use the selection-required browser entries for focused diagnostics; `test:client:visual` is the complete gate and is not a development feedback loop. `npm run verify` and the full branch of `npm run check` validate the ledger, compare generated bundles, check syntax, run Client tests, and run all ordinary backend tests through `npm run test:backend` without coverage instrumentation. The ordinary runner selects the sorted root `test/*.test.js` inventory. Coverage-only runner/report tests and collection probes live under `test/coverage/` and are excluded from daily execution. The release coverage runner includes both inventories and sets `DSH_PTC_TEST_COVERAGE_SUITE=1` for mixed instrumented cases; the ordinary runner clears that marker. Both runners share the concurrency calculation. Backend test files run in separate Node processes. Compiler boundary protocols are divided into disjoint storage, Promise and reflection files so the bounded file pool can execute them alongside the parameter/namespace/error cases without sharing their native or PTC realms. The default process count is half the available CPUs, rounded down and bounded between one and eight; each process can also own runtime Workers. Tests within each file retain their existing ordering. The ordinary runner enables module mocks without preloading coverage hooks and removes inherited coverage and temporary bytecode settings from its test-process environment. After the shared ledger, channel, semantic, build and syntax prerequisites pass, `scripts/deterministic-test-groups.mjs` selects its groups by gate: `--check` (the commit gate) runs only the semantic-evidence backend tier, the default `verify` runs the complete Client visual and backend groups concurrently on machines with at least 12 available CPUs, and `--ci` keeps the focused runtime group. Smaller machines retain serial phases. Every selected group must settle, and any nonzero exit, signal or startup failure rejects verification. Each browser pool retains its own CPU bound and process isolation. Both verification scopes produce a review-bound proof. Coverage runs only before a new version is released, as specified by [ADR 0035](adr/0035-run-coverage-only-before-a-new-release.md). CI starts from a clean lockfile install and runs `verify:ci` on every supported Node and operating-system entry: channel-manifest validation, semantic ownership, generated builds, Client tests, and focused runtime contracts covering compiler startup, helper-process lifecycle, plugin takeover, native-call transport, and durable argument diagnostics. A separate job per host channel packs the plugin and runs the host contracts against that channel's installed release. Normal CI therefore proves portable installation and runtime integration without running coverage-specific suites, collecting coverage, or running the exhaustive semantic suite on hosted runners. `host:channels:verify`, which is part of deterministic verification, is offline: it validates the tracked channel manifest — schema, per-channel dist-tag and blocking role, full coverage of the probed host packages, one release per pinned cohort, and a recorded integrity for each — without resolving a tag or installing a host. It also reports which channel the development graph declares and whether the lock materializes that record, so the checkout's own graph is read against the manifest the CI jobs install from. CI runs `test:host-contract` as one job per channel. Each job installs its channel on demand from the manifest into an ignored cache, proves the installed versions against the manifest, packs the plugin, and runs the host contracts through a repository-external consumer; the `alpha` job reports without failing the workflow. Registry resolution belongs only to `host:channels:update` and the scheduled channel-refresh workflow. That workflow publishes a changed manifest as a pull request and explicitly dispatches this CI workflow once because its `GITHUB_TOKEN`-authored events cannot start another run; ordinary gates never install a floating channel. ## Release coverage Coverage runs only when preparing a new version. Read [Release coverage](release-coverage.md) before its commands; ordinary development, review and commit preparation do not run it. Browser scripts accept `--list` without launching a browser or generating fixtures, repeated exact `--case ` selections, and `--concurrency `. Default invocations execute every case. Focused layout measurements use `measurements-focused.json`, separate from complete layout evidence. Ordinary backend diagnostics accept repeated `--file ` and `--list`; unknown files and coverage-only paths are rejected before execution, while supported Node name/skip patterns, reporters and destinations, timeout, concurrency, only and force-exit options remain available. Additional positional paths, unknown options and coverage flags are rejected by the same parser for both CLI and library execution. For example, `npm run test:backend -- --file test/semantic-boundary-promises.test.js --test-name-pattern="promise catch"` runs only that responsibility through the ordinary environment owner. Focused runs cannot establish the complete verification proof. For development diagnostics, use the selection-required entries above. `test:semantics`, `test:client:visual` and the default backend entry are complete inventories for their respective scopes, so they are not short feedback loops. Focused execution does not replace a requested delivery gate. Model-backed evaluation remains separate and opt-in; see [Evaluation](evaluation.md).