Skill Tracer
Skills › Archify › archify › delivery-contract.md

delivery-contract.md

665 lines · archify/references/delivery-contract.md at a406594

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Delivery contract
2

Delivery contract

Raw lines 1 to 2
3## Failed finalize and candidate repair
4
5`finalize` stops at the first non-passing gate. Use compact stdout or `evidence.summaryReceipt`; read its full sidecar only when the summary lacks evidence needed for a coherent repair. A receipt with four artifact checks is basic validation, not showcase acceptance: require all nine checks, zero composition errors, and zero warnings. Fix `meta.quality_profile` and schema errors before geometry. A dense full-schema ERD may keep `standard` for its first complete-field pass: require zero structural errors, no edge-through-node failures, complete field rows, and a readable grouped grid, and record composition warnings instead of spending unbounded time on them.
6
7For a validation failure, edit the existing JSON in the connected neighborhood named by diagnostics before rerunning a command. Preserve requested semantics, meaningful labels, source evidence, and fixed or agreed topology. Several routes sharing nodes call for one placement repair; read [Architecture layout repair](architecture-layout-repair.md) for that case. Reflow a blocked main path rather than nudging unrelated labels. Keep unrelated geometry when its composition already reads clearly. Use `--layout-json` before editing only when compact evidence lacks needed measurements. Workflow v2 uses its stable compiler receipt, not solver internals, as authoring evidence.
8
9Keep the best candidate that cleared route checks before a viewport repair. If that repair introduces new route collisions, restore the measured layout and address its remaining canvas or text constraint.
11After the edit, rerun the complete `finalize` command with `--quality showcase` and, for repository-backed work, `--repo-root <repo-root>`. If the output path already has browser evidence from another candidate, use a fresh `--out-dir <output-stem>.review-<revision>` for both the new `finalize` and any `visual-check`. Omit an earlier `--candidate-sha256` after editing because it binds the previous candidate. Compare diagnostics by code, subject, stage, and evidence, never by declining error count alone. Track the repair limit per persistent issue, using that code, subject, stage, and evidence: a newly exposed issue starts its own repair sequence. If an issue survives two focused repairs, inspect measured geometry or the relevant contract; after one evidence-based retry, report the concrete gap.
13Use standalone `validate` only for focused diagnosis, passing `--repo-root` for repository-backed work. Its passing receipt marks `candidateFrozen: true`; run `nextAction.arguments`, replacing only `<output.html>`, without editing, revalidating, or rereading the candidate. Retry later environmental or evidence failures against those frozen bytes. A measured reason to edit creates a new candidate and calls for the complete `finalize` without the old hash.

Failed finalize and candidate repair

finalize stops at the first non-passing gate. Use compact stdout or evidence.summaryReceipt; read its full sidecar only when the summary lacks evidence needed for a coherent repair. A receipt with four artifact checks is basic validation, not showcase acceptance: require all nine checks, zero composition errors, and zero warnings. Fix meta.quality_profile and schema errors before geometry. A dense full-schema ERD may keep standard for its first complete-field pass: require zero structural errors, no edge-through-node failures, complete field rows, and a readable grouped grid, and record composition warnings instead of spending unbounded time on them.

For a validation failure, edit the existing JSON in the connected neighborhood named by diagnostics before rerunning a command. Preserve requested semantics, meaningful labels, source evidence, and fixed or agreed topology. Several routes sharing nodes call for one placement repair; read Architecture layout repair for that case. Reflow a blocked main path rather than nudging unrelated labels. Keep unrelated geometry when its composition already reads clearly. Use --layout-json before editing only when compact evidence lacks needed measurements. Workflow v2 uses its stable compiler receipt, not solver internals, as authoring evidence.

Keep the best candidate that cleared route checks before a viewport repair. If that repair introduces new route collisions, restore the measured layout and address its remaining canvas or text constraint.

After the edit, rerun the complete finalize command with --quality showcase and, for repository-backed work, --repo-root <repo-root>. If the output path already has browser evidence from another candidate, use a fresh --out-dir <output-stem>.review-<revision> for both the new finalize and any visual-check. Omit an earlier --candidate-sha256 after editing because it binds the previous candidate. Compare diagnostics by code, subject, stage, and evidence, never by declining error count alone. Track the repair limit per persistent issue, using that code, subject, stage, and evidence: a newly exposed issue starts its own repair sequence. If an issue survives two focused repairs, inspect measured geometry or the relevant contract; after one evidence-based retry, report the concrete gap.

Use standalone validate only for focused diagnosis, passing --repo-root for repository-backed work. Its passing receipt marks candidateFrozen: true; run nextAction.arguments, replacing only <output.html>, without editing, revalidating, or rereading the candidate. Retry later environmental or evidence failures against those frozen bytes. A measured reason to edit creates a new candidate and calls for the complete finalize without the old hash.

Raw lines 3 to 14
15## Validate and deliver
17`render` and direct renderer entry points print classified authoring failures
18to stderr as readable diagnostics and exit 1. Input read/JSON parse failures
19use `input/read` or `input/json-parse`; output filesystem failures use
20`output/write` and identify the output path. Schema and layout failures keep
21their existing rule codes. Use the advertised `validate --json` or
22`deliver --json` interface for a machine receipt; `render` has no `--json` flag.
23Unexpected implementation failures retain debugging information in human
24mode and remain `internal/unclassified` in machine receipts.
26Each delivered output has two artifact-specific metadata paths. When an output
27stem is too long for those derived filenames, Archify shortens it and appends a
28stable hash:
30- `<output-stem>.delivery.json` records the latest completed attempt.
31- `<output-stem>.delivery-pending.json` is the recovery journal for an attempt
32 in progress.
34For a literal artifact stem that already matches Archify's reserved bounded-name
35marker, a pre-namespace raw provenance sidecar remains a read fallback when the
36encoded sidecar is absent. A pre-namespace raw pending journal is an independent
37fail-closed barrier: it blocks checks and redelivery even when an encoded pending
38journal also exists, and neither journal is silently replaced.
40One directory-wide `.archify-delivery-lock.json` serializes every delivery that
41resolves into the same physical output directory. This deliberately prevents
42case, Unicode-normalization, Windows short-name, and symbolic-link aliases from
43creating independent owners for one filesystem location. The tradeoff is that
44deliveries to different artifact names in one directory also run serially;
45provenance and pending journals remain artifact-specific.
47For migration safety, Archify also detects and preserves a legacy
48`<output-stem>.delivery-lock.json` beside the requested artifact. An existing
49legacy entry is a fail-closed recovery barrier. While a new delivery owns the
50directory mutex, it also holds temporary legacy-format fences for the requested
51spelling and an existing artifact's physical target spelling. It acquires the
52directory lock first, then all required compatibility fences before writing a
53journal or artifact, and removes the directory lock before those fences during
54release. This blocks an older Archify binary using
55either known spelling from entering the delivery. A legacy fence whose raw
56HEAD-era filename exceeds the host component limit is omitted because the old
57binary could not create that lock or deliver that artifact on the host either.
59`deliver` acquires the lock by exclusive `open(..., "wx")` before creating or
60replacing the recovery journal. A successful exclusive create yields an
61internal opaque ownership capability bound to that attempt. Journal creation,
62failed-provenance recording, pair commit, rollback, journal finalization, and
63lock release each verify the current capability inside the operation that
64would mutate shared state. A rejected contender does not create a journal or
65write failed provenance.
67An existing directory or legacy lock is handled without automatic recovery:
69| Observed lock state | Required `deliver` result |
70| --- | --- |
71| No directory entry | Attempt exclusive creation; only its success grants ownership. |
72| Valid schema-v1 lock whose PID is running, or whose death cannot be established | Exit 1 with `delivery/concurrent-attempt`; preserve every shared path. |
73| Valid schema-v1 lock whose PID is known to have exited | Exit 1 with `delivery/lock-stale`; preserve the lock, artifact, journal, and current provenance exactly. |
74| Unreadable, malformed, symlink, dangling symlink, directory, or other non-regular lock entry | Exit 1 with `delivery/lock-invalid`; preserve the entry and every other shared path. |
75| An acquired capability no longer matches the current lock or journal | Exit 1 with `delivery/ownership-lost`; stop all shared-path mutation. |
76| The matching owner cannot remove its lock | Exit 1 with `delivery/lock-release`; preserve the lock. |
78A `delivery/lock-stale` diagnostic identifies the absolute output and lock
79paths plus the original PID and receipt ID. Recovery is deliberately explicit
80and serial: stop all delivery attempts for that physical output directory,
81confirm that no active delivery owns it and that the reported stale entry has
82not been replaced, remove only the reported lock, then rerun `deliver`. Do not
83remove an artifact, current provenance, or pending journal as part of
84stale-lock recovery.
86The lock protocol targets Node.js 18 or later on a local filesystem with
87cooperating Archify processes. PID, receipt, and file-identity comparisons are
88defensive checks, not an atomic compare-and-swap. Compatibility fences cover
89the requested spelling and an existing physical-target spelling; they cannot
90enumerate arbitrary hard-link names or previously unknown filesystem aliases,
91so mixed-version delivery through such aliases remains out of scope. This
92contract does not claim distributed-lock correctness on NFS, SMB, or other
93network filesystems, and it cannot prevent an external process that ignores
94the protocol from replacing shared paths.
96Every no-clobber HTML publisher (`render`, `deliver`, `compare`, and `preview`)
97captures the requested directory entry, canonical write slot, physical parent,
98and existing target type, device/inode identity, and mode before staging, then
99revalidates that snapshot immediately before replacement. An existing write
100target must be a regular file with exactly one hard-link name. A target with
101multiple hard-link names fails closed with `output/target-hardlinked`: replacing
102the requested name cannot update unknown sibling names as one publication.
103Hard links remain supported for read identity and input/alias collision checks;
104they are unsupported only as write targets. A symbolic link to a single-link regular
105file remains supported: publication preserves the symbolic-link entry and
106applies the same protocol to its resolved target. Directory, FIFO, socket,
107device, changing mode, new claimant, and indeterminate identity cases fail
108before replacement.
110Publication is no-clobber and recoverable, not crash-atomic replacement of an
111existing target. To avoid overwriting a claimant that appears after the last
112identity check, Archify first retains the bound old file in a private recovery
113backup, removes the public name through identity-bound quarantine, and then
114creates the new public name with an exclusive hard link. A caught failure rolls
115back when the public slot and recovery binding still permit it. A process
116interruption between those namespace operations can instead leave the public
117path absent while the verified previous bytes remain in an adjacent private
118recovery backup. Single-artifact publication records the original slot/alias
119identity and backup inode, mode, SHA-256, and byte count in private
120`.archify-remove-*/publication-recovery-v1.json`, beside `previous`. To make a
121specific interrupted publication visible again, stop concurrent writers and run:
123```bash
124node bin/recover-output.mjs /absolute/path/to/.archify-remove-<id> --json
125```
127This is explicit recovery, not a directory scanner. Before linking, the helper
128checks for a changed parent or alias, an altered/hardlinked record or backup,
129digest or inode mismatch, and any existing public target. It restores only by
130no-clobber hard link, so a new claimant is preserved rather than overwritten;
131it never recursively removes unknown entries. A completed recovery is
132idempotent. The record is evidence to be independently verified, not an
133authority to restore arbitrary private bytes: the helper accepts it only from
134the recorded generated child of the original physical target parent, with the
135same directory identity. Name the exact directory reported by the interrupted
136process and inspect an uncertain record manually. A non-cooperating process can
137still swap pathnames after those checks and before Node.js `linkSync`; Node does
138not expose a descriptor-bound link operation. Post-link identity verification
139then fails closed and retains recovery evidence, rather than claiming recovery
140or deleting an uncertain name. If recovery itself is interrupted after the
141link, the old public bytes and private backup can both remain; a later recovery
142run preserves the public target and needs explicit operator resolution. The
143record is fsynced before the old public name is retired on platforms supporting
144directory sync, and the tested guarantee is recovery after a killed process;
145this is not a claim of power-loss, storage-controller, NFS, or SMB durability.
146Paired flows retain their backup in private transaction staging. For `deliver`,
147the pending journal and lock keep strict checkers fail-closed. The portable
148Node.js filesystem API has no pathname
149compare-and-swap that both replaces an existing name atomically and refuses to
150overwrite a late claimant: `rename` would close the visibility gap only by
151overwriting that claimant.
153After ownership is established, `deliver` creates the journal before rendering
154and keeps it through the recoverable HTML/sidecar pair commit. It removes the
155journal only after that commit completes. A validation, render, or pair-commit
156failure, or a process interruption, may therefore leave a journal. The journal
157is a safety barrier: `check`, `browser-check`, and `visual-check` fail closed when any directory
158entry exists at the journal or lock path, including an unreadable file,
159symlink, or dangling symlink. Run deliveries targeting the same physical output
160directory serially; one attempt must finish or be recovered before another
161begins.
163A successful sidecar has `schemaVersion: 1`, `status: "current"`,
164`command: "deliver"`, a unique `receiptId`, the diagram `type`, an absolute
165`input` path, an absolute `output` path matching the inspected
166artifact, and specification/artifact SHA-256 and byte counts. Checkers treat a
167missing, malformed, unsupported, or inconsistent field as invalid. They also
168reject a sidecar symlink, including a dangling one. A checker binds provenance
169to the artifact bytes it actually checks and verifies that binding again before
170reporting success; a concurrent byte change fails. The provenance directory
171entry itself must be a single-link regular file: `deliver` and strict check fail
172closed with `delivery/provenance-hardlink-unsupported` when it has another hard
173link, without scanning for or guessing the sibling name.
175If a currently verified owner fails after an older HTML exists, Archify writes
176a new `status: "failed"` sidecar and leaves the journal until recovery is
177complete. An unreadable old HTML does not prevent that marker; its artifact hash
178and byte count may be absent. If the sidecar is locked or otherwise unwritable,
179Archify keeps the prior sidecar rather than deleting evidence, and the journal
180prevents checkers from trusting it. A rejected concurrent, stale, or invalid
181lock attempt does not write failed provenance. If ownership is lost, Archify
182reports `delivery/ownership-lost`, does not overwrite or remove the successor's
183artifact, provenance, journal, or lock, and does not claim recorded failed
184provenance; a failure receipt may report `provenance: "unrecorded"`. If every
185metadata path is unavailable, the same unrecorded status applies; no tool can
186preserve that fact across processes. Restore metadata-path access and complete
187a successful `deliver` before trusting the output.
189Artifacts with no sidecar, journal, or lock remain supported for backward
190compatibility and for the lower-level `render` command. Their checker receipts
191report `provenance: "unknown"`; use `--require-provenance` to turn that state
192into a non-zero failure when the workflow requires a successfully delivered
193artifact:
195```bash
196node bin/archify.mjs check <output.html> --require-provenance
197node bin/archify.mjs browser-check <output.html> --json --require-provenance
198```

Validate and deliver

render and direct renderer entry points print classified authoring failures to stderr as readable diagnostics and exit 1. Input read/JSON parse failures use input/read or input/json-parse; output filesystem failures use output/write and identify the output path. Schema and layout failures keep their existing rule codes. Use the advertised validate --json or deliver --json interface for a machine receipt; render has no --json flag. Unexpected implementation failures retain debugging information in human mode and remain internal/unclassified in machine receipts.

Each delivered output has two artifact-specific metadata paths. When an output stem is too long for those derived filenames, Archify shortens it and appends a stable hash:

  • <output-stem>.delivery.json records the latest completed attempt.
  • <output-stem>.delivery-pending.json is the recovery journal for an attempt in progress.

For a literal artifact stem that already matches Archify's reserved bounded-name marker, a pre-namespace raw provenance sidecar remains a read fallback when the encoded sidecar is absent. A pre-namespace raw pending journal is an independent fail-closed barrier: it blocks checks and redelivery even when an encoded pending journal also exists, and neither journal is silently replaced.

One directory-wide .archify-delivery-lock.json serializes every delivery that resolves into the same physical output directory. This deliberately prevents case, Unicode-normalization, Windows short-name, and symbolic-link aliases from creating independent owners for one filesystem location. The tradeoff is that deliveries to different artifact names in one directory also run serially; provenance and pending journals remain artifact-specific.

For migration safety, Archify also detects and preserves a legacy <output-stem>.delivery-lock.json beside the requested artifact. An existing legacy entry is a fail-closed recovery barrier. While a new delivery owns the directory mutex, it also holds temporary legacy-format fences for the requested spelling and an existing artifact's physical target spelling. It acquires the directory lock first, then all required compatibility fences before writing a journal or artifact, and removes the directory lock before those fences during release. This blocks an older Archify binary using either known spelling from entering the delivery. A legacy fence whose raw HEAD-era filename exceeds the host component limit is omitted because the old binary could not create that lock or deliver that artifact on the host either.

deliver acquires the lock by exclusive open(..., "wx") before creating or replacing the recovery journal. A successful exclusive create yields an internal opaque ownership capability bound to that attempt. Journal creation, failed-provenance recording, pair commit, rollback, journal finalization, and lock release each verify the current capability inside the operation that would mutate shared state. A rejected contender does not create a journal or write failed provenance.

An existing directory or legacy lock is handled without automatic recovery:

Observed lock stateRequired deliver result
No directory entryAttempt exclusive creation; only its success grants ownership.
Valid schema-v1 lock whose PID is running, or whose death cannot be establishedExit 1 with delivery/concurrent-attempt; preserve every shared path.
Valid schema-v1 lock whose PID is known to have exitedExit 1 with delivery/lock-stale; preserve the lock, artifact, journal, and current provenance exactly.
Unreadable, malformed, symlink, dangling symlink, directory, or other non-regular lock entryExit 1 with delivery/lock-invalid; preserve the entry and every other shared path.
An acquired capability no longer matches the current lock or journalExit 1 with delivery/ownership-lost; stop all shared-path mutation.
The matching owner cannot remove its lockExit 1 with delivery/lock-release; preserve the lock.

A delivery/lock-stale diagnostic identifies the absolute output and lock paths plus the original PID and receipt ID. Recovery is deliberately explicit and serial: stop all delivery attempts for that physical output directory, confirm that no active delivery owns it and that the reported stale entry has not been replaced, remove only the reported lock, then rerun deliver. Do not remove an artifact, current provenance, or pending journal as part of stale-lock recovery.

The lock protocol targets Node.js 18 or later on a local filesystem with cooperating Archify processes. PID, receipt, and file-identity comparisons are defensive checks, not an atomic compare-and-swap. Compatibility fences cover the requested spelling and an existing physical-target spelling; they cannot enumerate arbitrary hard-link names or previously unknown filesystem aliases, so mixed-version delivery through such aliases remains out of scope. This contract does not claim distributed-lock correctness on NFS, SMB, or other network filesystems, and it cannot prevent an external process that ignores the protocol from replacing shared paths.

Every no-clobber HTML publisher (render, deliver, compare, and preview) captures the requested directory entry, canonical write slot, physical parent, and existing target type, device/inode identity, and mode before staging, then revalidates that snapshot immediately before replacement. An existing write target must be a regular file with exactly one hard-link name. A target with multiple hard-link names fails closed with output/target-hardlinked: replacing the requested name cannot update unknown sibling names as one publication. Hard links remain supported for read identity and input/alias collision checks; they are unsupported only as write targets. A symbolic link to a single-link regular file remains supported: publication preserves the symbolic-link entry and applies the same protocol to its resolved target. Directory, FIFO, socket, device, changing mode, new claimant, and indeterminate identity cases fail before replacement.

Publication is no-clobber and recoverable, not crash-atomic replacement of an existing target. To avoid overwriting a claimant that appears after the last identity check, Archify first retains the bound old file in a private recovery backup, removes the public name through identity-bound quarantine, and then creates the new public name with an exclusive hard link. A caught failure rolls back when the public slot and recovery binding still permit it. A process interruption between those namespace operations can instead leave the public path absent while the verified previous bytes remain in an adjacent private recovery backup. Single-artifact publication records the original slot/alias identity and backup inode, mode, SHA-256, and byte count in private .archify-remove-*/publication-recovery-v1.json, beside previous. To make a specific interrupted publication visible again, stop concurrent writers and run:

node bin/recover-output.mjs /absolute/path/to/.archify-remove-<id> --json

This is explicit recovery, not a directory scanner. Before linking, the helper checks for a changed parent or alias, an altered/hardlinked record or backup, digest or inode mismatch, and any existing public target. It restores only by no-clobber hard link, so a new claimant is preserved rather than overwritten; it never recursively removes unknown entries. A completed recovery is idempotent. The record is evidence to be independently verified, not an authority to restore arbitrary private bytes: the helper accepts it only from the recorded generated child of the original physical target parent, with the same directory identity. Name the exact directory reported by the interrupted process and inspect an uncertain record manually. A non-cooperating process can still swap pathnames after those checks and before Node.js linkSync; Node does not expose a descriptor-bound link operation. Post-link identity verification then fails closed and retains recovery evidence, rather than claiming recovery or deleting an uncertain name. If recovery itself is interrupted after the link, the old public bytes and private backup can both remain; a later recovery run preserves the public target and needs explicit operator resolution. The record is fsynced before the old public name is retired on platforms supporting directory sync, and the tested guarantee is recovery after a killed process; this is not a claim of power-loss, storage-controller, NFS, or SMB durability. Paired flows retain their backup in private transaction staging. For deliver, the pending journal and lock keep strict checkers fail-closed. The portable Node.js filesystem API has no pathname compare-and-swap that both replaces an existing name atomically and refuses to overwrite a late claimant: rename would close the visibility gap only by overwriting that claimant.

After ownership is established, deliver creates the journal before rendering and keeps it through the recoverable HTML/sidecar pair commit. It removes the journal only after that commit completes. A validation, render, or pair-commit failure, or a process interruption, may therefore leave a journal. The journal is a safety barrier: check, browser-check, and visual-check fail closed when any directory entry exists at the journal or lock path, including an unreadable file, symlink, or dangling symlink. Run deliveries targeting the same physical output directory serially; one attempt must finish or be recovered before another begins.

A successful sidecar has schemaVersion: 1, status: "current", command: "deliver", a unique receiptId, the diagram type, an absolute input path, an absolute output path matching the inspected artifact, and specification/artifact SHA-256 and byte counts. Checkers treat a missing, malformed, unsupported, or inconsistent field as invalid. They also reject a sidecar symlink, including a dangling one. A checker binds provenance to the artifact bytes it actually checks and verifies that binding again before reporting success; a concurrent byte change fails. The provenance directory entry itself must be a single-link regular file: deliver and strict check fail closed with delivery/provenance-hardlink-unsupported when it has another hard link, without scanning for or guessing the sibling name.

If a currently verified owner fails after an older HTML exists, Archify writes a new status: "failed" sidecar and leaves the journal until recovery is complete. An unreadable old HTML does not prevent that marker; its artifact hash and byte count may be absent. If the sidecar is locked or otherwise unwritable, Archify keeps the prior sidecar rather than deleting evidence, and the journal prevents checkers from trusting it. A rejected concurrent, stale, or invalid lock attempt does not write failed provenance. If ownership is lost, Archify reports delivery/ownership-lost, does not overwrite or remove the successor's artifact, provenance, journal, or lock, and does not claim recorded failed provenance; a failure receipt may report provenance: "unrecorded". If every metadata path is unavailable, the same unrecorded status applies; no tool can preserve that fact across processes. Restore metadata-path access and complete a successful deliver before trusting the output.

Artifacts with no sidecar, journal, or lock remain supported for backward compatibility and for the lower-level render command. Their checker receipts report provenance: "unknown"; use --require-provenance to turn that state into a non-zero failure when the workflow requires a successfully delivered artifact:

node bin/archify.mjs check <output.html> --require-provenance
node bin/archify.mjs browser-check <output.html> --json --require-provenance
Raw lines 15 to 199
Runs code bin/recover-output.mjs :124
Runs code bin/archify.mjs :196
200## Output path contracts
202Archify intentionally separates durable authored paths from command-line paths:
204- Required authored `meta.output` is a portable POSIX-relative path such as
205 `reports/diagram.html`. It uses `/`, ends in a non-empty `.html` basename,
206 and cannot contain an absolute or drive-relative prefix, URI, backslash,
207 empty or dot segment, control character, unpaired UTF-16 surrogate, Windows
208 alternate-data-stream separator or invalid filename character, trailing dot
209 or space, DOS device name, or a component over either the 255-byte UTF-8 or
210 255-code-unit UTF-16 limit. It resolves from the current working directory
211 and must remain physically inside that directory, with an `.html` target,
212 after symbolic links are followed. The durable output/archive profile also
213 conservatively rejects a Windows 8.3 short-name shape such as `PROGRA~1`;
214 descriptive repo/Git POSIX paths use a separate profile and are exempt.
215- Explicit CLI output arguments use the active host's native syntax. They may
216 be relative or absolute, use native separators, and resolve outside the
217 current working directory. On Windows, ordinary drive-absolute, UNC, and
218 relative paths (including ordinary `.` and `..` navigation) are supported.
219 A system-resolved 8.3 spelling of an existing file or directory is accepted
220 when Archify can prove its physical identity; this native alias support does
221 not relax the durable output/archive profile's 8.3-shaped-name rejection.
222 Extended-length paths are limited to raw backslash-only `\\?\C:\...` and
223 `\\?\UNC\server\share\...` forms without dot segments; device namespaces,
224 malformed roots, drive-relative paths such as `C:file.html`, current-drive
225 roots such as `\file.html`, alternate data streams, reserved device names,
226 invalid or trailing filename characters, and overlong components fail
227 closed. POSIX CLI paths retain POSIX filename rules rather than inheriting
228 Windows spelling restrictions. Every host rejects NUL, unpaired surrogates,
229 and components that exceed its supported bound.
231These contracts are not interchangeable: an explicit CLI output does not hide
232an invalid durable `meta.output` (including a missing value), and `validate`
233checks the authored output even when it does not publish to that path. A
234workflow v1-to-v2 migration may explicitly receive a portable durable
235replacement through `migrate workflow old.json new.json --to-schema 2 --output
236reports/diagram.html`; that value is written only to its separate verified v2
237destination. This migration-candidate exception does not repair the source or
238bypass any non-output schema or compiler error. For every other repair, add a
239portable POSIX-relative `.html` path to `meta.output`; no schema-version change
240is otherwise required.
242Run `finalize` directly on a complete first candidate and after every repair edit. Its embedded validation checks the candidate before delivery; use standalone `validate` only for focused diagnosis. After an edit, omit any earlier `--candidate-sha256`, which binds the previous candidate. CLI HTML output paths must end in
243`.html`, including after symbolic-link resolution. Compare receipt paths must
244end in `.json`. A type mismatch fails before writing with
245`output/cli-extension` or `output/cli-resolved-extension`. These checks prevent
246accidental file-type overwrites; they do not sandbox explicit CLI directories
247or prevent replacement of an existing artifact of the expected type.
249Use final verified delivery only after the candidate is frozen:
251```bash
252node bin/archify.mjs deliver <type> <candidate.json> <output.html> --quality showcase --json
253```
255Deliver reads the specification once, writes those exact bytes to a private same-directory candidate snapshot, renders that snapshot, runs the complete artifact checker, and only replaces the target after all artifact checks pass. The JSON receipt includes SHA-256 and byte counts for both `specification` and `artifact`.
257For the ordinary agent handoff path, prefer the finalizer:
259```bash
260node bin/archify.mjs finalize <type> <candidate.json> <output.html> --quality showcase --json
261```
263`finalize` invokes verified `deliver` once, reuses its embedded showcase
264validation result, then runs strict `check --require-provenance` and
265`browser-check --require-provenance`. It stops at the first failed or skipped stage
266and preserves that stage's full receipt. Its stdout is one compact JSON
267object with gate statuses, bounded actionable diagnostics, artifact identity,
268and evidence paths. The same compact object is written atomically to
269`<output-stem>.finalize-summary.json`; use that file for normal failure repair. When diagnostics are truncated, `diagnosticSummary.omittedByCode` counts the unshown entries by diagnostic code without replacing their full subject and repair evidence in the full receipt.
270Complete stage receipts and timings remain available for auditing in
271`<output-stem>.finalize.json`. With `--out-dir`, both files are written there (unless an explicit `--receipt` overrides the finalize receipt path; the artifact HTML stays at the requested output path);
272`--receipt <path.json>` overrides the full receipt path and derives a distinct
273`<path>-summary.json`. Read the full receipt only when the compact summary is
274truncated and its shown subjects and evidence cannot identify a coherent local
275repair, or when complete audit evidence was explicitly requested. The compact
276receipt reports `visualReview: "not-requested"`; the automated gate does not create images or require a perceptual reviewer. A compact `visualReviewRecommendation` retains positive crossover and route-detour metrics from the strict check so the author can apply the review escalation below without reading the full receipt. A recommendation does not change the machine exit code or claim that review happened. Its `affectedRoutes` identifies crossing pairs and detours (up to eight of each, with a truncation flag); the full strict-check `composition.routeReview` retains all affected relationships. Use these IDs to trace the routes in the captured default viewport. Detours may include `directCorridorBlockers`, identifying nodes between aligned endpoints. These are geometric review clues, not new validation failures or inferred main-path semantics. For a blocked main path or several tangled routes, follow [Architecture layout repair](architecture-layout-repair.md) and reflow the connected scene before tuning individual sides or labels. Preserve every semantic fact; retain unrelated positions only when their surrounding composition is already accepted.
278For a measured automatic Architecture with a large unused leading area, the
279compact receipt may include `layoutReviewRecommendation`. Its
280`composition.leadingSpace` evidence accounts for nodes, boundary titles,
281routes and labels. Check whether that space is intentional; if not, reposition
282the connected scene while preserving meaning and user-fixed geometry, then
283finalize again. This suggestion changes no gate or exit status and requires
284no screenshot. A fixed canvas or uncertain measurement receives no suggestion.
286A passing finalizer receipt is sufficient evidence for all four gates. Merely
287naming the gates or requiring each one to pass does not require replaying their
288standalone commands. Replay an individual command only when the request
289explicitly requires separate executions or focused failure diagnosis needs it.
291The individual commands remain authoritative and backward compatible. Use
292them directly for focused diagnosis, recovery, or when only one gate is
293required. A finalize failure does not relax any gate and does not turn a
294preserved older artifact into a current successful delivery.
296`finalize` discovers and starts private Chrome only after delivery and strict
297checking pass. Failed input, repository-evidence, delivery, or artifact checks
298therefore do not launch a browser. It loads the artifact only after current
299provenance is verified. The browser gate retains every viewport, theme, and
300stability check; the browser closes at completion or a browser-stage failure.
301Its full stage receipt records `execution: "in-process"` and the equivalent
302standalone `command` for replay. Chrome startup no longer overlaps the earlier
303stages, so successful runs may take slightly longer. This avoids unnecessary
304startup on invalid candidates; it does not fix host sandbox restrictions on
305Chrome startup or relax a browser gate.
307The pair commit is recoverable, not a claim that two filesystem paths change
308atomically or are durable across power loss. Journal finalization is part of
309that commit: a caught failure while verifying or removing the journal rolls
310back the replaced files when possible and while ownership remains current. If
311ownership is lost, the old attempt immediately stops renaming, rolling back,
312finalizing the journal, recording failure provenance, or cleaning up shared
313paths. Any private staging or recoverable backups remain available and are
314identified by the failure diagnostic. If restoration fails for another reason,
315the failure receipt likewise identifies retained backups for recovery. A
316process interruption can leave the journal, backups, or private staging behind;
317checkers then fail closed. Follow the reported recovery evidence before rerunning
318`deliver` serially on the same output. A failed attempt exits non-zero and never invokes an opener; it never
319authorizes visual evidence collection.
321If exclusive creation succeeds but lock initialization fails, Archify may
322record failed provenance and remove the incomplete lock only while its
323capability still identifies that exact entry. A replacement is preserved.
324Filesystem and cleanup errors are reported separately from an active concurrent
325delivery. An active, stale, unrecognized, or otherwise preserved lock
326independently prevents checkers from accepting the prior artifact. Fix the
327reported filesystem error before retrying, and use another physical output
328directory if the lock path contains unrelated data.
330Lock release is part of delivery completion. If the artifact/provenance pair
331has committed and the journal has finalized but the matching lock cannot be
332removed, `deliver` exits 1 with `delivery/lock-release`, preserves the lock,
333does not print a success receipt, and does not invoke an opener. The preserved
334lock keeps strict checkers fail-closed. Only after pair commit, journal
335finalization, and lock release all succeed may `deliver` exit zero, print its
336success receipt, or run `--open`.
338Run strict `check` after `deliver` exits zero. Run `browser-check` or optional
339`visual-check` only after that strict check exits zero. A failed marker,
340recovery journal, or delivery lock makes every checker fail before accepting
341the preserved HTML; report the diagnostics and complete a successful recovery
342delivery before collecting new browser evidence.
344Static `check` uses the same SVG path analysis for inspected relationships and
345structural frames. It supports `M/L/H/V/Q/Z`, their lowercase relative forms,
346repeated parameters, and finite numbers. Each `M` starts an independent subpath;
347`Z` closes only the current subpath. Separate subpaths never create connecting
348segments that are absent from the drawing. Straight segments separated by a
349non-collinear `Q` also remain separate in route analysis; curve sample points
350do not become micro-segments in straight-route budgets or rhythm checks.
351Segment lengths and stretch are measured per continuous piece, while actual
352bends are summed per relationship. A relationship exceeding a budget is counted
353once, and internal piece boundaries do not receive the short shared-trunk
354exception reserved for semantic endpoints.
356This is not a promise of full SVG command support: `A/C/S/T` produce
357`artifact/svg-path-unsupported`; missing parameters, invalid numbers, and other
358syntax errors produce `artifact/svg-path-malformed`. The checker exits non-zero
359instead of skipping a bad path or waiting indefinitely. Path failures append a
360`svg_path_data` check; normal valid artifacts retain the existing nine checks.
361Diagnostics carry the inspected `pathIndex`, `role`, available relationship/frame
362`id`, parsing `tokenOffset`, available `command`, and `reason` so the generating
363source can be located and repaired. `pathIndex` is one-based; `tokenOffset` is a
364zero-based UTF-16 offset in `d` after numeric character references are decoded.
365Apparent tags in comments, CDATA, and attribute text are ignored. Passing static
366path checks does not establish browser or perceptual visual acceptance.
368<details>
369<summary>中文说明</summary>
371静态 `check` 对受检关系线和结构边界的 SVG 路径使用同一解析结果,支持
372`M/L/H/V/Q/Z` 及其小写相对形式、重复参数和有限数值。每个 `M` 开始独立
373子路径,`Z` 只闭合当前子路径;子路径之间不会被拼接成图中不存在的线段。
374非共线 `Q` 前后的直线也保持分离,不会把曲线采样点计为直线路由预算或
375节奏检查中的微线段。线段长度和伸长率按连续片段测量,真实转弯数汇总到原关系;超预算关系
376只计一次,内部子路径断点不享有语义起终点的短共享线例外。
377这不是完整 SVG 命令集的支持承诺:`A/C/S/T` 返回
378`artifact/svg-path-unsupported`;缺少参数、非法数值等格式错误返回
379`artifact/svg-path-malformed`,检查以非零状态结束,不跳过坏路径或无限等待。
380路径失败时追加 `svg_path_data` 检查;普通有效产物仍保留原来的 9 项检查。
381诊断携带受检路径的 `pathIndex`、`role`、可用的关系/边界 `id`,以及解析位置
382`tokenOffset`、可用的 `command` 和 `reason`,用于定位并修复生成路径的来源。
383`pathIndex` 从 1 开始;`tokenOffset` 是数字字符引用解码后的 `d` 字符串中
384从 0 开始的 UTF-16 位置。注释、CDATA 和属性文本中的伪标签不参与检查。
385静态路径检查通过仍不代表浏览器或感知视觉验收通过。
387</details>
389The delivery interface exposes four separate claims:
3911. `deliver` proves deterministic artifact checks and byte identity.
3922. `browser-check` collects required automated browser evidence from the exact artifact without capturing images.
3933. `visual-check` optionally adds artifact-bound screenshots and a contact sheet.
3944. Perceptual visual review records a human or image-capable reviewer's judgment.
396Passing one claim never implies the others. Never claim that the deterministic receipt includes browser or perceptual review evidence.

Output path contracts

Archify intentionally separates durable authored paths from command-line paths:

  • Required authored meta.output is a portable POSIX-relative path such as reports/diagram.html. It uses /, ends in a non-empty .html basename, and cannot contain an absolute or drive-relative prefix, URI, backslash, empty or dot segment, control character, unpaired UTF-16 surrogate, Windows alternate-data-stream separator or invalid filename character, trailing dot or space, DOS device name, or a component over either the 255-byte UTF-8 or 255-code-unit UTF-16 limit. It resolves from the current working directory and must remain physically inside that directory, with an .html target, after symbolic links are followed. The durable output/archive profile also conservatively rejects a Windows 8.3 short-name shape such as PROGRA~1; descriptive repo/Git POSIX paths use a separate profile and are exempt.
  • Explicit CLI output arguments use the active host's native syntax. They may be relative or absolute, use native separators, and resolve outside the current working directory. On Windows, ordinary drive-absolute, UNC, and relative paths (including ordinary . and .. navigation) are supported. A system-resolved 8.3 spelling of an existing file or directory is accepted when Archify can prove its physical identity; this native alias support does not relax the durable output/archive profile's 8.3-shaped-name rejection. Extended-length paths are limited to raw backslash-only \\?\C:\... and \\?\UNC\server\share\... forms without dot segments; device namespaces, malformed roots, drive-relative paths such as C:file.html, current-drive roots such as \file.html, alternate data streams, reserved device names, invalid or trailing filename characters, and overlong components fail closed. POSIX CLI paths retain POSIX filename rules rather than inheriting Windows spelling restrictions. Every host rejects NUL, unpaired surrogates, and components that exceed its supported bound.

These contracts are not interchangeable: an explicit CLI output does not hide an invalid durable meta.output (including a missing value), and validate checks the authored output even when it does not publish to that path. A workflow v1-to-v2 migration may explicitly receive a portable durable replacement through migrate workflow old.json new.json --to-schema 2 --output reports/diagram.html; that value is written only to its separate verified v2 destination. This migration-candidate exception does not repair the source or bypass any non-output schema or compiler error. For every other repair, add a portable POSIX-relative .html path to meta.output; no schema-version change is otherwise required.

Run finalize directly on a complete first candidate and after every repair edit. Its embedded validation checks the candidate before delivery; use standalone validate only for focused diagnosis. After an edit, omit any earlier --candidate-sha256, which binds the previous candidate. CLI HTML output paths must end in .html, including after symbolic-link resolution. Compare receipt paths must end in .json. A type mismatch fails before writing with output/cli-extension or output/cli-resolved-extension. These checks prevent accidental file-type overwrites; they do not sandbox explicit CLI directories or prevent replacement of an existing artifact of the expected type.

Use final verified delivery only after the candidate is frozen:

node bin/archify.mjs deliver <type> <candidate.json> <output.html> --quality showcase --json

Deliver reads the specification once, writes those exact bytes to a private same-directory candidate snapshot, renders that snapshot, runs the complete artifact checker, and only replaces the target after all artifact checks pass. The JSON receipt includes SHA-256 and byte counts for both specification and artifact.

For the ordinary agent handoff path, prefer the finalizer:

node bin/archify.mjs finalize <type> <candidate.json> <output.html> --quality showcase --json

finalize invokes verified deliver once, reuses its embedded showcase validation result, then runs strict check --require-provenance and browser-check --require-provenance. It stops at the first failed or skipped stage and preserves that stage's full receipt. Its stdout is one compact JSON object with gate statuses, bounded actionable diagnostics, artifact identity, and evidence paths. The same compact object is written atomically to <output-stem>.finalize-summary.json; use that file for normal failure repair. When diagnostics are truncated, diagnosticSummary.omittedByCode counts the unshown entries by diagnostic code without replacing their full subject and repair evidence in the full receipt. Complete stage receipts and timings remain available for auditing in <output-stem>.finalize.json. With --out-dir, both files are written there (unless an explicit --receipt overrides the finalize receipt path; the artifact HTML stays at the requested output path); --receipt <path.json> overrides the full receipt path and derives a distinct <path>-summary.json. Read the full receipt only when the compact summary is truncated and its shown subjects and evidence cannot identify a coherent local repair, or when complete audit evidence was explicitly requested. The compact receipt reports visualReview: "not-requested"; the automated gate does not create images or require a perceptual reviewer. A compact visualReviewRecommendation retains positive crossover and route-detour metrics from the strict check so the author can apply the review escalation below without reading the full receipt. A recommendation does not change the machine exit code or claim that review happened. Its affectedRoutes identifies crossing pairs and detours (up to eight of each, with a truncation flag); the full strict-check composition.routeReview retains all affected relationships. Use these IDs to trace the routes in the captured default viewport. Detours may include directCorridorBlockers, identifying nodes between aligned endpoints. These are geometric review clues, not new validation failures or inferred main-path semantics. For a blocked main path or several tangled routes, follow Architecture layout repair and reflow the connected scene before tuning individual sides or labels. Preserve every semantic fact; retain unrelated positions only when their surrounding composition is already accepted.

For a measured automatic Architecture with a large unused leading area, the compact receipt may include layoutReviewRecommendation. Its composition.leadingSpace evidence accounts for nodes, boundary titles, routes and labels. Check whether that space is intentional; if not, reposition the connected scene while preserving meaning and user-fixed geometry, then finalize again. This suggestion changes no gate or exit status and requires no screenshot. A fixed canvas or uncertain measurement receives no suggestion.

A passing finalizer receipt is sufficient evidence for all four gates. Merely naming the gates or requiring each one to pass does not require replaying their standalone commands. Replay an individual command only when the request explicitly requires separate executions or focused failure diagnosis needs it.

The individual commands remain authoritative and backward compatible. Use them directly for focused diagnosis, recovery, or when only one gate is required. A finalize failure does not relax any gate and does not turn a preserved older artifact into a current successful delivery.

finalize discovers and starts private Chrome only after delivery and strict checking pass. Failed input, repository-evidence, delivery, or artifact checks therefore do not launch a browser. It loads the artifact only after current provenance is verified. The browser gate retains every viewport, theme, and stability check; the browser closes at completion or a browser-stage failure. Its full stage receipt records execution: "in-process" and the equivalent standalone command for replay. Chrome startup no longer overlaps the earlier stages, so successful runs may take slightly longer. This avoids unnecessary startup on invalid candidates; it does not fix host sandbox restrictions on Chrome startup or relax a browser gate.

The pair commit is recoverable, not a claim that two filesystem paths change atomically or are durable across power loss. Journal finalization is part of that commit: a caught failure while verifying or removing the journal rolls back the replaced files when possible and while ownership remains current. If ownership is lost, the old attempt immediately stops renaming, rolling back, finalizing the journal, recording failure provenance, or cleaning up shared paths. Any private staging or recoverable backups remain available and are identified by the failure diagnostic. If restoration fails for another reason, the failure receipt likewise identifies retained backups for recovery. A process interruption can leave the journal, backups, or private staging behind; checkers then fail closed. Follow the reported recovery evidence before rerunning deliver serially on the same output. A failed attempt exits non-zero and never invokes an opener; it never authorizes visual evidence collection.

If exclusive creation succeeds but lock initialization fails, Archify may record failed provenance and remove the incomplete lock only while its capability still identifies that exact entry. A replacement is preserved. Filesystem and cleanup errors are reported separately from an active concurrent delivery. An active, stale, unrecognized, or otherwise preserved lock independently prevents checkers from accepting the prior artifact. Fix the reported filesystem error before retrying, and use another physical output directory if the lock path contains unrelated data.

Lock release is part of delivery completion. If the artifact/provenance pair has committed and the journal has finalized but the matching lock cannot be removed, deliver exits 1 with delivery/lock-release, preserves the lock, does not print a success receipt, and does not invoke an opener. The preserved lock keeps strict checkers fail-closed. Only after pair commit, journal finalization, and lock release all succeed may deliver exit zero, print its success receipt, or run --open.

Run strict check after deliver exits zero. Run browser-check or optional visual-check only after that strict check exits zero. A failed marker, recovery journal, or delivery lock makes every checker fail before accepting the preserved HTML; report the diagnostics and complete a successful recovery delivery before collecting new browser evidence.

Static check uses the same SVG path analysis for inspected relationships and structural frames. It supports M/L/H/V/Q/Z, their lowercase relative forms, repeated parameters, and finite numbers. Each M starts an independent subpath; Z closes only the current subpath. Separate subpaths never create connecting segments that are absent from the drawing. Straight segments separated by a non-collinear Q also remain separate in route analysis; curve sample points do not become micro-segments in straight-route budgets or rhythm checks. Segment lengths and stretch are measured per continuous piece, while actual bends are summed per relationship. A relationship exceeding a budget is counted once, and internal piece boundaries do not receive the short shared-trunk exception reserved for semantic endpoints.

This is not a promise of full SVG command support: A/C/S/T produce artifact/svg-path-unsupported; missing parameters, invalid numbers, and other syntax errors produce artifact/svg-path-malformed. The checker exits non-zero instead of skipping a bad path or waiting indefinitely. Path failures append a svg_path_data check; normal valid artifacts retain the existing nine checks. Diagnostics carry the inspected pathIndex, role, available relationship/frame id, parsing tokenOffset, available command, and reason so the generating source can be located and repaired. pathIndex is one-based; tokenOffset is a zero-based UTF-16 offset in d after numeric character references are decoded. Apparent tags in comments, CDATA, and attribute text are ignored. Passing static path checks does not establish browser or perceptual visual acceptance.

<details> <summary>中文说明</summary>

静态 check 对受检关系线和结构边界的 SVG 路径使用同一解析结果,支持 M/L/H/V/Q/Z 及其小写相对形式、重复参数和有限数值。每个 M 开始独立 子路径,Z 只闭合当前子路径;子路径之间不会被拼接成图中不存在的线段。 非共线 Q 前后的直线也保持分离,不会把曲线采样点计为直线路由预算或 节奏检查中的微线段。线段长度和伸长率按连续片段测量,真实转弯数汇总到原关系;超预算关系 只计一次,内部子路径断点不享有语义起终点的短共享线例外。 这不是完整 SVG 命令集的支持承诺:A/C/S/T 返回 artifact/svg-path-unsupported;缺少参数、非法数值等格式错误返回 artifact/svg-path-malformed,检查以非零状态结束,不跳过坏路径或无限等待。 路径失败时追加 svg_path_data 检查;普通有效产物仍保留原来的 9 项检查。 诊断携带受检路径的 pathIndex、role、可用的关系/边界 id,以及解析位置 tokenOffset、可用的 command 和 reason,用于定位并修复生成路径的来源。 pathIndex 从 1 开始;tokenOffset 是数字字符引用解码后的 d 字符串中 从 0 开始的 UTF-16 位置。注释、CDATA 和属性文本中的伪标签不参与检查。 静态路径检查通过仍不代表浏览器或感知视觉验收通过。

</details>

The delivery interface exposes four separate claims:

  1. deliver proves deterministic artifact checks and byte identity.
  2. browser-check collects required automated browser evidence from the exact artifact without capturing images.
  3. visual-check optionally adds artifact-bound screenshots and a contact sheet.
  4. Perceptual visual review records a human or image-capable reviewer's judgment.

Passing one claim never implies the others. Never claim that the deterministic receipt includes browser or perceptual review evidence.

Raw lines 200 to 397
Runs code bin/archify.mjs :252
398## Recovering a failed comparison
400`compare` commits an HTML artifact and its JSON receipt as a pair. If that commit
401fails, it attempts to restore the previous files. A complete rollback removes
402the temporary directory as usual.
404If a previous file cannot be restored, compare exits non-zero with
405`delta/commit-rollback-failed` and retains the recovery directory. In the JSON
406failure receipt, `diagnostics[].evidence.recoveryDirectory` identifies that
407directory and `recoveryFiles` lists `{ backup, target }` paths for the files whose
408restoration failed. Human-readable diagnostics also print the recovery paths.
410Resolve the filesystem error, inspect the current targets, and restore each
411listed backup to its corresponding target before retrying. Keep the recovery
412directory until both previous files have been recovered and verified; it can
413also contain rejected candidate files, which must not be mistaken for backups.
414Successful comparisons and failures before commit retain their normal cleanup.

Recovering a failed comparison

compare commits an HTML artifact and its JSON receipt as a pair. If that commit fails, it attempts to restore the previous files. A complete rollback removes the temporary directory as usual.

If a previous file cannot be restored, compare exits non-zero with delta/commit-rollback-failed and retains the recovery directory. In the JSON failure receipt, diagnostics[].evidence.recoveryDirectory identifies that directory and recoveryFiles lists { backup, target } paths for the files whose restoration failed. Human-readable diagnostics also print the recovery paths.

Resolve the filesystem error, inspect the current targets, and restore each listed backup to its corresponding target before retrying. Keep the recovery directory until both previous files have been recovered and verified; it can also contain rejected candidate files, which must not be mistaken for backups. Successful comparisons and failures before commit retain their normal cleanup.

Raw lines 398 to 415
416## Automated browser evidence
418`finalize` runs the required browser gate against the exact trusted HTML without
419rerendering or modifying it. For focused diagnosis, the equivalent standalone
420command is:
422```bash
423node bin/archify.mjs browser-check <output.html> --json --require-provenance
424```
426The zero-dependency command uses Chrome/Chromium (or Microsoft Edge)
427through the DevTools pipe. `ARCHIFY_CHROME` is authoritative when set, including
428an invalid path: Archify does not silently fall back to another browser. Automatic
429Windows discovery checks every Chrome/Chromium install location and PATH command
430first, then Edge under `%ProgramFiles(x86)%`, `%ProgramFiles%`, and `%LocalAppData%`,
431followed by `msedge` on PATH. On macOS and Linux, discovery also checks
432Chrome/Chromium first, then the Edge application bundle (macOS) and
433`microsoft-edge`/`microsoft-edge-stable` on PATH. It
434measures light-theme containment at 1440×900, 1600×1000, 1920×1080, and
4352048×1320, and verifies the requested light theme at all four viewports, the dark
436theme at both endpoints, and READ/Still runtime states. A requested theme that
437resolves to a different theme fails with measured evidence. It creates one
438`<output-stem>.browser-check.json` receipt and no screenshots or contact sheet.
439Pass `--out-dir <dir>` to place the receipt in a separate evidence directory.
440The receipt binds the artifact SHA-256 and byte count, identifies
441`evidenceKind: "automated-browser"`, and reports
442`visualReview: "not-requested"`.
444Horizontal overflow always fails. Normal document-level vertical scrolling is
445accepted only with a renderer-declared contract and measured readable text.
446Automatic canvases declare `data-reader-fit="intrinsic-height"` (height fitting)
447or `data-reader-fit="width-first"` (Sequence and Waterfall reading width); their adaptive
448Reader must reach its readable width and expose `data-reader-overflow="authored"`.
449Architecture with an explicit `meta.viewBox` instead declares
450`data-diagram-type="architecture"` and `data-reader-fit="authored-height"`:
451its SVG coordinates, aspect ratio and existing Reader width behavior stay
452unchanged. Its full SVG must remain inside the diagram panel without internal
453scrolling or clipping, and the document must permit vertical scrolling.
454The receipt records `verticalScrollAccepted: true` and
455`overflowDisposition: "readable-vertical-scroll"`. Missing or unknown declarations,
456explicit viewBoxes in other modes, unreadable text, horizontal overflow,
457clipping and Viewer chrome collisions remain failures. Do not add an internal
458diagram scroller or hide overflow.
460`browser_evidence` in the handoff records only the outcome of this automated
461command:
463- `passed` maps from exit 0 and receipt `status: "pass"` after every required measurement completes and passes.
464- `failed` maps from exit 1 and receipt `status: "fail"` when the inspection finds a defect, the command fails, or a runtime error leaves the evidence incomplete.
465- `skipped` maps only from exit 2 and receipt `status: "skipped"` when no supported browser is available and the inspection does not run.
467Runtime failures leave incomplete evidence and must not be normalized to
468`skipped`. They do not invalidate an already successful deterministic delivery.
469Retry an environmental failure in a browser-capable execution context when
470practical. Keep the packaged transport unchanged unless the failure reproduces
471through that seam in a capable environment.
473On Windows, Chrome/Edge startup relaunches can lose the inherited DevTools
474pipe before any response arrives. Archify removes a standalone
475`__COMPAT_LAYER=DetectorsAppHealth` from the browser child's environment only
476(case-insensitive name and value); the parent environment, unknown layers,
477combined layers, and privilege-related compatibility settings are unchanged.
478This targets the reported non-elevated Git Bash app-health case, not every
479AppCompat mode. Elevated-shell relaunches remain unsupported: rerun from a
480non-elevated PowerShell opened normally, outside an elevated or compatibility-mode
481parent. Archify does not suppress browser de-elevation or disable the sandbox
482as a relaunch workaround. A zero-response startup diagnostic suggests this
483remedy without claiming that elevation or AppCompat caused every pipe failure.
485A provenance failure exits before browser inspection and persists a failed
486browser-check receipt bound to the attempted artifact. If the failure receipt
487cannot be written, the diagnostic names that incomplete evidence.
489Both browser commands inspect the exact delivered HTML without modifying or rerendering it.

Automated browser evidence

finalize runs the required browser gate against the exact trusted HTML without rerendering or modifying it. For focused diagnosis, the equivalent standalone command is:

node bin/archify.mjs browser-check <output.html> --json --require-provenance

The zero-dependency command uses Chrome/Chromium (or Microsoft Edge) through the DevTools pipe. ARCHIFY_CHROME is authoritative when set, including an invalid path: Archify does not silently fall back to another browser. Automatic Windows discovery checks every Chrome/Chromium install location and PATH command first, then Edge under %ProgramFiles(x86)%, %ProgramFiles%, and %LocalAppData%, followed by msedge on PATH. On macOS and Linux, discovery also checks Chrome/Chromium first, then the Edge application bundle (macOS) and microsoft-edge/microsoft-edge-stable on PATH. It measures light-theme containment at 1440×900, 1600×1000, 1920×1080, and 2048×1320, and verifies the requested light theme at all four viewports, the dark theme at both endpoints, and READ/Still runtime states. A requested theme that resolves to a different theme fails with measured evidence. It creates one <output-stem>.browser-check.json receipt and no screenshots or contact sheet. Pass --out-dir <dir> to place the receipt in a separate evidence directory. The receipt binds the artifact SHA-256 and byte count, identifies evidenceKind: "automated-browser", and reports visualReview: "not-requested".

Horizontal overflow always fails. Normal document-level vertical scrolling is accepted only with a renderer-declared contract and measured readable text. Automatic canvases declare data-reader-fit="intrinsic-height" (height fitting) or data-reader-fit="width-first" (Sequence and Waterfall reading width); their adaptive Reader must reach its readable width and expose data-reader-overflow="authored". Architecture with an explicit meta.viewBox instead declares data-diagram-type="architecture" and data-reader-fit="authored-height": its SVG coordinates, aspect ratio and existing Reader width behavior stay unchanged. Its full SVG must remain inside the diagram panel without internal scrolling or clipping, and the document must permit vertical scrolling. The receipt records verticalScrollAccepted: true and overflowDisposition: "readable-vertical-scroll". Missing or unknown declarations, explicit viewBoxes in other modes, unreadable text, horizontal overflow, clipping and Viewer chrome collisions remain failures. Do not add an internal diagram scroller or hide overflow.

browser_evidence in the handoff records only the outcome of this automated command:

  • passed maps from exit 0 and receipt status: "pass" after every required measurement completes and passes.
  • failed maps from exit 1 and receipt status: "fail" when the inspection finds a defect, the command fails, or a runtime error leaves the evidence incomplete.
  • skipped maps only from exit 2 and receipt status: "skipped" when no supported browser is available and the inspection does not run.

Runtime failures leave incomplete evidence and must not be normalized to skipped. They do not invalidate an already successful deterministic delivery. Retry an environmental failure in a browser-capable execution context when practical. Keep the packaged transport unchanged unless the failure reproduces through that seam in a capable environment.

On Windows, Chrome/Edge startup relaunches can lose the inherited DevTools pipe before any response arrives. Archify removes a standalone __COMPAT_LAYER=DetectorsAppHealth from the browser child's environment only (case-insensitive name and value); the parent environment, unknown layers, combined layers, and privilege-related compatibility settings are unchanged. This targets the reported non-elevated Git Bash app-health case, not every AppCompat mode. Elevated-shell relaunches remain unsupported: rerun from a non-elevated PowerShell opened normally, outside an elevated or compatibility-mode parent. Archify does not suppress browser de-elevation or disable the sandbox as a relaunch workaround. A zero-response startup diagnostic suggests this remedy without claiming that elevation or AppCompat caused every pipe failure.

A provenance failure exits before browser inspection and persists a failed browser-check receipt bound to the attempted artifact. If the failure receipt cannot be written, the diagnostic names that incomplete evidence.

Both browser commands inspect the exact delivered HTML without modifying or rerendering it.

Raw lines 416 to 490
Runs code bin/archify.mjs :423
491## Sequence width review
493A passing `finalize` may report `layoutReviewRecommendation.action: "inspect-sequence-width"`. Its `evidence` measures the fixed participant columns' unused right-hand space after accounting for message labels, notes and segment titles. This advice adds no warning, failure, screenshot requirement or automatic geometry change.
495A passing `validate --json`, `deliver`, or `finalize` receipt may carry `diagnostics[]` entries with `severity: "warning"` for Viewer locale fallbacks (`i18n/*`). They fail no gate. When the artifact should be fully localized, repair the listed keys from their `evidence` and rerun `finalize`.
497Sequence canvases with omitted `meta.column_fit` use `spread`, whether or not `meta.viewBox` is supplied. An authored viewBox remains authoritative; infeasible participant capacity fails without silently enlarging it. Explicit `meta.column_fit: "fixed"` preserves historical fixed columns. For a candidate whose fixed-column width suggestion remains, first check whether the fixed geometry is intentional. Only when a change to that geometry is authorized, save the candidate, set only `meta.column_fit` to `"spread"`, and rerun the complete `finalize` once with `--out-dir <folder>/width-review`. Keep participant order, messages and their y positions, labels, notes, sources and canvas dimensions. If that attempt fails, restore the candidate and finalize it with `--out-dir <folder>/width-restore`; report the remaining layout suggestion rather than iterating. Preserve intentional fixed geometry and disclose the suggestion when a change is not authorized. To retain historical fixed coordinates for an older omitted-fit input, set `meta.column_fit: "fixed"` explicitly. This review is about horizontal composition; a passing receipt still does not claim perceptual approval.

Sequence width review

A passing finalize may report layoutReviewRecommendation.action: "inspect-sequence-width". Its evidence measures the fixed participant columns' unused right-hand space after accounting for message labels, notes and segment titles. This advice adds no warning, failure, screenshot requirement or automatic geometry change.

A passing validate --json, deliver, or finalize receipt may carry diagnostics[] entries with severity: "warning" for Viewer locale fallbacks (i18n/*). They fail no gate. When the artifact should be fully localized, repair the listed keys from their evidence and rerun finalize.

Sequence canvases with omitted meta.column_fit use spread, whether or not meta.viewBox is supplied. An authored viewBox remains authoritative; infeasible participant capacity fails without silently enlarging it. Explicit meta.column_fit: "fixed" preserves historical fixed columns. For a candidate whose fixed-column width suggestion remains, first check whether the fixed geometry is intentional. Only when a change to that geometry is authorized, save the candidate, set only meta.column_fit to "spread", and rerun the complete finalize once with --out-dir <folder>/width-review. Keep participant order, messages and their y positions, labels, notes, sources and canvas dimensions. If that attempt fails, restore the candidate and finalize it with --out-dir <folder>/width-restore; report the remaining layout suggestion rather than iterating. Preserve intentional fixed geometry and disclose the suggestion when a change is not authorized. To retain historical fixed coordinates for an older omitted-fit input, set meta.column_fit: "fixed" explicitly. This review is about horizontal composition; a passing receipt still does not claim perceptual approval.

Raw lines 491 to 498
499## Optional capture evidence
501`visual-check` remains backward compatible for a requested or escalated
502perceptual review:
504```bash
505node bin/archify.mjs visual-check <output.html> --summary --require-provenance
506```
508`--summary` returns compact JSON with all diagnostics and absolute paths to the complete receipt, contact sheet, and every screenshot. For a chosen visual review, inspect the relevant captures; capture success is not perceptual approval. `--json` retains the full receipt output for existing consumers. Both modes run the same checks and keep the same exit status. If cleanup fails after publication, the summary retains the final failure diagnostics and `publication` recovery details; the linked receipt records the earlier committed evidence.
510It performs the same automated browser measurements, captures light/dark
511screenshots at 1440×900 and 2048×1320, and writes four viewport PNG sidecars,
512one relative-path HTML contact sheet, and one JSON receipt. `--out-dir <dir>` moves all of these sidecars together.
513Open the HTML contact sheet in a browser or inspect the viewport PNGs with an image reader. Its receipt reports `visualReview: "pending"` because captures do not themselves
514make a perceptual judgment. Capture and provenance failures follow the ownership rules below.
516The receipt, contact sheet, and four PNGs form one owned evidence set. Before
517capture, `visual-check` freezes every requested directory entry, its
518canonical write slot and physical parent, and the target's absent/file state,
519type, device/inode identity, and mode. Hard-linked evidence targets are not safe
520write targets. All candidate files are created exclusively inside one random,
521private staging directory beneath the physical evidence directory; the receipt
522is published last. Each staged candidate must have exactly one hard-link name
523before publication. The no-clobber publish link temporarily gives the staged
524and final names a link count of two; unlinking the verified staged name must
525leave the final entry with a link count of one. An unexpected external hard
526link fails closed and its alias is never removed.
528Chrome inspects one identity- and content-checked copy of the captured artifact
529in a private local temporary directory, so browser file loading does not depend
530on UNC or long-path support. The six publication candidates remain on the
531evidence volume. Both temporary directories are cleaned without recursively
532deleting unknown contents; retained entries include their recovery locations.
534Immediately before committing anything, `visual-check` re-resolves and verifies
535the complete six-path set. An absent-path claimant, existing-path replacement,
536symbolic-link or dangling-link retarget, parent-topology change, hard link, or
537indeterminate identity fails closed with `viewer/evidence-path-conflict`. The
538claimant and every other final evidence path remain untouched. Cleanup removes
539only this run's staged or published entries after rechecking their captured
540identities; a changed or unknown entry is preserved.
542An existing visual evidence set is replaceable only when a regular
543`visual-check` receipt proves ownership of the same artifact and evidence
544directory, and its exact sidecar manifest matches every existing contact-sheet
545or PNG byte count and SHA-256 digest. A missing, malformed, unknown, mismatched,
546or incomplete ownership record never authorizes deletion. Failed and skipped
547runs retire prior screenshots/contact sheets only as part of the same verified
548transaction when that ownership proof succeeds; otherwise they preserve all
549unknown evidence and report `viewer/evidence-path-conflict`.
551This rule also applies when Chrome is unavailable or provenance fails before
552browser inspection: neither path may blindly delete stale-looking evidence. A
553verified owned set may be recoverably retired before publishing a skipped or
554failed receipt; unowned evidence remains intact. These outcomes do not invalidate an already
555successful deterministic delivery and do not turn a perceptual visual review
556into passed or failed. Retry an environmental failure through the supported
557command in a browser-capable execution context when practical. Keep the
558packaged transport unchanged unless the failure reproduces through that seam in
559a capable environment.
561`browser-check` applies the same private-snapshot, identity, ownership, and no-clobber rules to its single JSON receipt. Its namespace is separate from `visual-check`, so a browser-only rerun cannot remove capture evidence.

Optional capture evidence

visual-check remains backward compatible for a requested or escalated perceptual review:

node bin/archify.mjs visual-check <output.html> --summary --require-provenance

--summary returns compact JSON with all diagnostics and absolute paths to the complete receipt, contact sheet, and every screenshot. For a chosen visual review, inspect the relevant captures; capture success is not perceptual approval. --json retains the full receipt output for existing consumers. Both modes run the same checks and keep the same exit status. If cleanup fails after publication, the summary retains the final failure diagnostics and publication recovery details; the linked receipt records the earlier committed evidence.

It performs the same automated browser measurements, captures light/dark screenshots at 1440×900 and 2048×1320, and writes four viewport PNG sidecars, one relative-path HTML contact sheet, and one JSON receipt. --out-dir <dir> moves all of these sidecars together. Open the HTML contact sheet in a browser or inspect the viewport PNGs with an image reader. Its receipt reports visualReview: "pending" because captures do not themselves make a perceptual judgment. Capture and provenance failures follow the ownership rules below.

The receipt, contact sheet, and four PNGs form one owned evidence set. Before capture, visual-check freezes every requested directory entry, its canonical write slot and physical parent, and the target's absent/file state, type, device/inode identity, and mode. Hard-linked evidence targets are not safe write targets. All candidate files are created exclusively inside one random, private staging directory beneath the physical evidence directory; the receipt is published last. Each staged candidate must have exactly one hard-link name before publication. The no-clobber publish link temporarily gives the staged and final names a link count of two; unlinking the verified staged name must leave the final entry with a link count of one. An unexpected external hard link fails closed and its alias is never removed.

Chrome inspects one identity- and content-checked copy of the captured artifact in a private local temporary directory, so browser file loading does not depend on UNC or long-path support. The six publication candidates remain on the evidence volume. Both temporary directories are cleaned without recursively deleting unknown contents; retained entries include their recovery locations.

Immediately before committing anything, visual-check re-resolves and verifies the complete six-path set. An absent-path claimant, existing-path replacement, symbolic-link or dangling-link retarget, parent-topology change, hard link, or indeterminate identity fails closed with viewer/evidence-path-conflict. The claimant and every other final evidence path remain untouched. Cleanup removes only this run's staged or published entries after rechecking their captured identities; a changed or unknown entry is preserved.

An existing visual evidence set is replaceable only when a regular visual-check receipt proves ownership of the same artifact and evidence directory, and its exact sidecar manifest matches every existing contact-sheet or PNG byte count and SHA-256 digest. A missing, malformed, unknown, mismatched, or incomplete ownership record never authorizes deletion. Failed and skipped runs retire prior screenshots/contact sheets only as part of the same verified transaction when that ownership proof succeeds; otherwise they preserve all unknown evidence and report viewer/evidence-path-conflict.

This rule also applies when Chrome is unavailable or provenance fails before browser inspection: neither path may blindly delete stale-looking evidence. A verified owned set may be recoverably retired before publishing a skipped or failed receipt; unowned evidence remains intact. These outcomes do not invalidate an already successful deterministic delivery and do not turn a perceptual visual review into passed or failed. Retry an environmental failure through the supported command in a browser-capable execution context when practical. Keep the packaged transport unchanged unless the failure reproduces through that seam in a capable environment.

browser-check applies the same private-snapshot, identity, ownership, and no-clobber rules to its single JSON receipt. Its namespace is separate from visual-check, so a browser-only rerun cannot remove capture evidence.

Raw lines 499 to 562
Runs code bin/archify.mjs :505
563## A new candidate at an existing output path
565Browser evidence belongs to exact artifact bytes. After editing a candidate whose previous HTML already has browser evidence, choose a fresh evidence directory before running the next `finalize`; this preserves the old receipts and captures without an avoidable ownership-conflict retry. `--out-dir` relocates the new browser-check receipt and, by default, the finalize receipt and summary. An explicit `--receipt` overrides the finalize receipt path; its summary follows that path. Successful delivery still rewrites the requested HTML and its sibling `*.delivery.json`. Earlier browser or visual evidence remains bound to its original artifact bytes and must not be treated as evidence for changed HTML:
567```bash
568node bin/archify.mjs finalize architecture candidate.json diagram.html --quality showcase --repo-root <root> --out-dir diagram.review-2 --json
569node bin/archify.mjs visual-check diagram.html --out-dir diagram.review-2 --summary --require-provenance
570```
572The evidence directory is not an archive of the HTML. Copying the HTML there alone does not rebind receipt paths or provenance. If a historical snapshot is needed, preserve the candidate and artifact separately before overwriting them; do not assume copied receipts validate a relocated artifact.
574Keep the requested HTML path stable. Use a new revision directory for each changed candidate, and retain the same directory for retries of unchanged bytes. For a diagram without repository evidence, omit `--repo-root`. Let the commands create their output directory. A prior validation failure that produced no HTML or browser evidence needs no new directory. Never remove unknown evidence to make a retry pass.

A new candidate at an existing output path

Browser evidence belongs to exact artifact bytes. After editing a candidate whose previous HTML already has browser evidence, choose a fresh evidence directory before running the next finalize; this preserves the old receipts and captures without an avoidable ownership-conflict retry. --out-dir relocates the new browser-check receipt and, by default, the finalize receipt and summary. An explicit --receipt overrides the finalize receipt path; its summary follows that path. Successful delivery still rewrites the requested HTML and its sibling *.delivery.json. Earlier browser or visual evidence remains bound to its original artifact bytes and must not be treated as evidence for changed HTML:

node bin/archify.mjs finalize architecture candidate.json diagram.html --quality showcase --repo-root <root> --out-dir diagram.review-2 --json
node bin/archify.mjs visual-check diagram.html --out-dir diagram.review-2 --summary --require-provenance

The evidence directory is not an archive of the HTML. Copying the HTML there alone does not rebind receipt paths or provenance. If a historical snapshot is needed, preserve the candidate and artifact separately before overwriting them; do not assume copied receipts validate a relocated artifact.

Keep the requested HTML path stable. Use a new revision directory for each changed candidate, and retain the same directory for retries of unchanged bytes. For a diagram without repository evidence, omit --repo-root. Let the commands create their output directory. A prior validation failure that produced no HTML or browser evidence needs no new directory. Never remove unknown evidence to make a retry pass.

Raw lines 563 to 575
Runs code bin/archify.mjs :568
576## Optional opening
578Add `--open` only when the user wants an immediate local preview. It runs after
579the verified pair commit has completed, its recovery journal has been removed,
580and the delivery lock has been released successfully. It uses one argument-array
581OS opener with a five-second bound on macOS and Linux, and a fifteen-second bound
582for PowerShell startup on Windows. The receipt records `open.status`; failed or
583unavailable launch attempts also include normalized `open.failure` details.
584Keep it off for CI, unattended agents, and non-interactive environments.
585Failure or unsupported opening does not invalidate delivery; its
586status proves only whether the local opener invocation succeeded.

Optional opening

Add --open only when the user wants an immediate local preview. It runs after the verified pair commit has completed, its recovery journal has been removed, and the delivery lock has been released successfully. It uses one argument-array OS opener with a five-second bound on macOS and Linux, and a fifteen-second bound for PowerShell startup on Windows. The receipt records open.status; failed or unavailable launch attempts also include normalized open.failure details. Keep it off for CI, unattended agents, and non-interactive environments. Failure or unsupported opening does not invalidate delivery; its status proves only whether the local opener invocation succeeded.

Raw lines 576 to 587
588## Last-Good Live Preview
590For an active desktop authoring loop only:
592```bash
593node bin/archify.mjs preview <type> <input>.json <output>.html --quality showcase
594```
596Preview watches one explicit input on loopback, binds each stable digest to a private snapshot, and advances only after the existing verified delivery pipeline passes. Invalid, half-written, deleted, or superseded input leaves the previous verified revision on screen and on disk. Identical bytes do not rebuild or reload.
598The preview runtime ships inside the zero-dependency Skill ZIP and must work without `node_modules`.
600Never start it by default. Do not use it for CI, unattended agents, remote sharing, or mobile use. `--no-open` is only for a user who will open the printed local URL or for loop testing. Stop it with Ctrl-C before handoff. The first Ctrl-C drains the active delivery without publishing it; a second Ctrl-C forces shutdown of both delivery processes and HTTP connections, including incomplete requests. Shutdown preserves the last verified artifact and removes only staging files whose ownership can be verified. If delivery is interrupted before its receipt reaches Preview, unconfirmed files and recovery material may remain in the private staging directory; shutdown does not recursively delete unknown contents. Server state, port, source path, diagnostics, error text, and reload tokens must never enter the generated artifact or any export.

Last-Good Live Preview

For an active desktop authoring loop only:

node bin/archify.mjs preview <type> <input>.json <output>.html --quality showcase

Preview watches one explicit input on loopback, binds each stable digest to a private snapshot, and advances only after the existing verified delivery pipeline passes. Invalid, half-written, deleted, or superseded input leaves the previous verified revision on screen and on disk. Identical bytes do not rebuild or reload.

The preview runtime ships inside the zero-dependency Skill ZIP and must work without node_modules.

Never start it by default. Do not use it for CI, unattended agents, remote sharing, or mobile use. --no-open is only for a user who will open the printed local URL or for loop testing. Stop it with Ctrl-C before handoff. The first Ctrl-C drains the active delivery without publishing it; a second Ctrl-C forces shutdown of both delivery processes and HTTP connections, including incomplete requests. Shutdown preserves the last verified artifact and removes only staging files whose ownership can be verified. If delivery is interrupted before its receipt reaches Preview, unconfirmed files and recovery material may remain in the private staging directory; shutdown does not recursively delete unknown contents. Server state, port, source path, diagnostics, error text, and reload tokens must never enter the generated artifact or any export.

Raw lines 588 to 601
Runs code bin/archify.mjs :593
602## Perceptual review
604The automated path ends with the deterministic browser gate and reports
605`visual_review: not_requested`. Ordinary generation does not require screenshots
606or an image-reading step, including newly authored or repositioned Architecture.
607Perceptual review is optional; use it for an explicit request or a concrete visual
608investigation. Possible reasons include:
610- the compact finalizer includes `visualReviewRecommendation` for crossings or detours (advisory, not a delivery gate);
611- the user explicitly requests an aesthetic or visual review;
612- a template, renderer, or Viewer change needs visual regression evidence;
613- a novel layout or browser diagnostic leaves low confidence;
614- the run is selected for sampled audit or dogfood.
616For the default standalone desktop viewer, measure 1440×900, 1600×1000, 1920×1080, and 2048×1320. Require `document.documentElement.scrollWidth <= window.innerWidth` at every checked size. Prefer `scrollHeight <= window.innerHeight`; accept page-level vertical scrolling only through the Reader-declared readable exception defined above. At the largest checked viewport, inspect the rendered composition for a conspicuous empty lower band: the main panel and necessary conclusion cards should use the available height as a balanced whole, not collapse into a shallow strip. For unexpected overflow, repair the authored composition by removing only genuinely redundant content or compacting spacing before shrinking nodes, labels, or the main panel. Do not hide overflow, clip content, introduce an internal diagram scroller, or reduce node/label typography to make the measurement pass. Narrow/mobile containment may retain vertical page scrolling.
618For an escalation, run `visual-check` on the current finalized artifact, inspect
619its contact sheet with a capable image reader or human, and check both endpoint
620themes, the default READ view, line crossings/corridors, label masks, node/card
621fit, focus/search/passport closure, and export cleanliness. This review is
622supplementary and never changes `browser_evidence`. An unconstrained browser
623glance can support perceptual review only.
625In a diagnostic or structured handoff, report one truthful optional-review
626status:
628- `visual_review: not_requested` — no review trigger applies; this is not a visual acceptance claim.
629- `visual_review: passed` — only after inspecting the rendered artifact.
630- `visual_review: skipped (image reader unavailable)` — a requested or triggered review could not run.
631- `visual_review: failed` — with the concrete visible defect.
633For an escalated review, use `correction_rounds: 0`, `correction_rounds: 1`, or
634`correction_rounds: 2`; never exceed two focused correction rounds. When review
635is not requested, use `correction_rounds: 0`. Never report
636`visual_review: passed` without inspecting the artifact. If perceptual review
637changes the candidate, rerun `finalize` because the previous specification and
638artifact receipts are no longer current.

Perceptual review

The automated path ends with the deterministic browser gate and reports visual_review: not_requested. Ordinary generation does not require screenshots or an image-reading step, including newly authored or repositioned Architecture. Perceptual review is optional; use it for an explicit request or a concrete visual investigation. Possible reasons include:

  • the compact finalizer includes visualReviewRecommendation for crossings or detours (advisory, not a delivery gate);
  • the user explicitly requests an aesthetic or visual review;
  • a template, renderer, or Viewer change needs visual regression evidence;
  • a novel layout or browser diagnostic leaves low confidence;
  • the run is selected for sampled audit or dogfood.

For the default standalone desktop viewer, measure 1440×900, 1600×1000, 1920×1080, and 2048×1320. Require document.documentElement.scrollWidth <= window.innerWidth at every checked size. Prefer scrollHeight <= window.innerHeight; accept page-level vertical scrolling only through the Reader-declared readable exception defined above. At the largest checked viewport, inspect the rendered composition for a conspicuous empty lower band: the main panel and necessary conclusion cards should use the available height as a balanced whole, not collapse into a shallow strip. For unexpected overflow, repair the authored composition by removing only genuinely redundant content or compacting spacing before shrinking nodes, labels, or the main panel. Do not hide overflow, clip content, introduce an internal diagram scroller, or reduce node/label typography to make the measurement pass. Narrow/mobile containment may retain vertical page scrolling.

For an escalation, run visual-check on the current finalized artifact, inspect its contact sheet with a capable image reader or human, and check both endpoint themes, the default READ view, line crossings/corridors, label masks, node/card fit, focus/search/passport closure, and export cleanliness. This review is supplementary and never changes browser_evidence. An unconstrained browser glance can support perceptual review only.

In a diagnostic or structured handoff, report one truthful optional-review status:

  • visual_review: not_requested — no review trigger applies; this is not a visual acceptance claim.
  • visual_review: passed — only after inspecting the rendered artifact.
  • visual_review: skipped (image reader unavailable) — a requested or triggered review could not run.
  • visual_review: failed — with the concrete visible defect.

For an escalated review, use correction_rounds: 0, correction_rounds: 1, or correction_rounds: 2; never exceed two focused correction rounds. When review is not requested, use correction_rounds: 0. Never report visual_review: passed without inspecting the artifact. If perceptual review changes the candidate, rerun finalize because the previous specification and artifact receipts are no longer current.

Raw lines 602 to 639
640## Handoff receipt
642For a requested diagnostic or structured handoff, derive the following details
643from the existing receipts. Ordinary user-facing replies follow
644[Output](../SKILL.md#output); this checklist is not a default chat response.
646```text
647diagram_type: <actual diagram type>
648output: /absolute/path/to/file.html
649specification_sha256: <receipt value>
650artifact_sha256: <receipt value>
651validation: <actual quality profile, check counts, errors, and warnings>
652browser_evidence: passed|failed|skipped
653visual_review: not_requested|passed|skipped (image reader unavailable)|failed
654correction_rounds: 0|1|2
655```
657Derive `browser_evidence` only from the latest artifact-bound `browser-check`
658receipt, normally the stage embedded by `finalize`. Record optional capture or
659manual browser work separately with its artifact binding, viewport/theme scope,
660and observations; never use it or `visual_review` to overwrite the automated
661status.
663Opening, preview status, Share Cards, and other viewer exports are not validation claims.
665Finalize receipt publication uses the same identity-bound, no-clobber publisher and explicit recovery records described above. The full and summary receipts must be distinct from the candidate, artifact, delivery metadata, and browser receipt. Their targets must be absent or single-link regular files; symlink receipt entries and hardlinked targets fail closed. A later claimant or changed parent stops publication and remains untouched. Default receipt names share the physical artifact namespace and are bounded for the host filename limit. The two receipts are published individually, not as a crash-atomic pair; only a completed passing command is a successful handoff.

Handoff receipt

For a requested diagnostic or structured handoff, derive the following details from the existing receipts. Ordinary user-facing replies follow Output; this checklist is not a default chat response.

diagram_type: <actual diagram type>
output: /absolute/path/to/file.html
specification_sha256: <receipt value>
artifact_sha256: <receipt value>
validation: <actual quality profile, check counts, errors, and warnings>
browser_evidence: passed|failed|skipped
visual_review: not_requested|passed|skipped (image reader unavailable)|failed
correction_rounds: 0|1|2

Derive browser_evidence only from the latest artifact-bound browser-check receipt, normally the stage embedded by finalize. Record optional capture or manual browser work separately with its artifact binding, viewport/theme scope, and observations; never use it or visual_review to overwrite the automated status.

Opening, preview status, Share Cards, and other viewer exports are not validation claims.

Finalize receipt publication uses the same identity-bound, no-clobber publisher and explicit recovery records described above. The full and summary receipts must be distinct from the candidate, artifact, delivery metadata, and browser receipt. Their targets must be absent or single-link regular files; symlink receipt entries and hardlinked targets fail closed. A later claimant or changed parent stops publication and remains untouched. Default receipt names share the physical artifact namespace and are bounded for the host filename limit. The two receipts are published individually, not as a crash-atomic pair; only a completed passing command is a successful handoff.

Raw lines 640 to 665