dsh-archify-projects 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +204 -2
  2. package/cordis.patch.yml +99 -0
  3. package/dist/client.js +2261 -0
  4. package/dist/client.js.map +1 -0
  5. package/docs/CONTAINER.md +197 -0
  6. package/docs/DESIGN.md +905 -0
  7. package/docs/HANDOVER.md +391 -0
  8. package/docs/PUBLISH.md +107 -0
  9. package/icon.svg +12 -0
  10. package/lib/host/archify-skill.js +116 -0
  11. package/lib/host/archify-skill.js.map +1 -0
  12. package/lib/host/config.js +95 -0
  13. package/lib/host/config.js.map +1 -0
  14. package/lib/host/context.js +28 -0
  15. package/lib/host/context.js.map +1 -0
  16. package/lib/host/git.js +185 -0
  17. package/lib/host/git.js.map +1 -0
  18. package/lib/host/http.js +184 -0
  19. package/lib/host/http.js.map +1 -0
  20. package/lib/host/index.js +90 -0
  21. package/lib/host/index.js.map +1 -0
  22. package/lib/host/policy.js +124 -0
  23. package/lib/host/policy.js.map +1 -0
  24. package/lib/host/routes.js +667 -0
  25. package/lib/host/routes.js.map +1 -0
  26. package/lib/host/runner.js +913 -0
  27. package/lib/host/runner.js.map +1 -0
  28. package/lib/host/store.js +370 -0
  29. package/lib/host/store.js.map +1 -0
  30. package/lib/host/workspace.js +65 -0
  31. package/lib/host/workspace.js.map +1 -0
  32. package/lib/shared/format.js +138 -0
  33. package/lib/shared/format.js.map +1 -0
  34. package/lib/shared/prompt.js +257 -0
  35. package/lib/shared/prompt.js.map +1 -0
  36. package/lib/shared/protocol.js +31 -0
  37. package/lib/shared/protocol.js.map +1 -0
  38. package/lib/shared/types.js +173 -0
  39. package/lib/shared/types.js.map +1 -0
  40. package/locale/en.json +6 -0
  41. package/locale/zh.json +6 -0
  42. package/package.json +98 -4
  43. package/skills/archify/LICENSE +22 -0
  44. package/skills/archify/SKILL.md +109 -0
  45. package/skills/archify/THIRD_PARTY_NOTICES.md +69 -0
  46. package/skills/archify/assets/JetBrainsMono-OFL.txt +93 -0
  47. package/skills/archify/assets/template.html +13709 -0
  48. package/skills/archify/bin/archify.mjs +6936 -0
  49. package/skills/archify/bin/delivery-update.mjs +91 -0
  50. package/skills/archify/bin/finalize.mjs +895 -0
  51. package/skills/archify/bin/open-artifact.mjs +146 -0
  52. package/skills/archify/bin/preview.mjs +969 -0
  53. package/skills/archify/bin/recover-output.mjs +41 -0
  54. package/skills/archify/bin/visual-check.mjs +2667 -0
  55. package/skills/archify/brand-marks/README.md +31 -0
  56. package/skills/archify/brand-marks/catalog.json +131 -0
  57. package/skills/archify/delta/architecture-delta.mjs +1313 -0
  58. package/skills/archify/examples/agent-run.lifecycle.json +55 -0
  59. package/skills/archify/examples/agent-tool-call.workflow.json +74 -0
  60. package/skills/archify/examples/async-job-roundtrip.sequence.json +56 -0
  61. package/skills/archify/examples/brand-aware-delivery.architecture.json +34 -0
  62. package/skills/archify/examples/cache-miss-request.sequence.json +77 -0
  63. package/skills/archify/examples/checkout-platform.base.architecture.json +32 -0
  64. package/skills/archify/examples/checkout-platform.head.architecture.json +32 -0
  65. package/skills/archify/examples/dataflow-product-analytics.html +13820 -0
  66. package/skills/archify/examples/deployment-release.lifecycle.json +48 -0
  67. package/skills/archify/examples/event-stream.dataflow.json +52 -0
  68. package/skills/archify/examples/holiday-planning.workflow.json +143 -0
  69. package/skills/archify/examples/incident-response.workflow.json +59 -0
  70. package/skills/archify/examples/lifecycle-agent-run.html +13765 -0
  71. package/skills/archify/examples/locales/de.json +425 -0
  72. package/skills/archify/examples/locales/es.json +440 -0
  73. package/skills/archify/examples/locales/fr.json +425 -0
  74. package/skills/archify/examples/locales/fr.partial.json +22 -0
  75. package/skills/archify/examples/locales/it.json +425 -0
  76. package/skills/archify/examples/locales/ja.json +425 -0
  77. package/skills/archify/examples/locales/ko.json +440 -0
  78. package/skills/archify/examples/locales/pt.json +425 -0
  79. package/skills/archify/examples/locales/ru.json +425 -0
  80. package/skills/archify/examples/product-analytics.dataflow.json +71 -0
  81. package/skills/archify/examples/production-deployment.architecture.json +51 -0
  82. package/skills/archify/examples/release-delivery.workflow.json +57 -0
  83. package/skills/archify/examples/sequence-cache-miss-request.html +13835 -0
  84. package/skills/archify/examples/web-app-rendered.html +13808 -0
  85. package/skills/archify/examples/web-app.architecture.json +41 -0
  86. package/skills/archify/examples/workflow-agent-tool-call-rendered.html +13826 -0
  87. package/skills/archify/migrations/workflow-v2.mjs +280 -0
  88. package/skills/archify/package.json +17 -0
  89. package/skills/archify/recipes/scenarios.mjs +430 -0
  90. package/skills/archify/references/architecture-layout-repair.md +18 -0
  91. package/skills/archify/references/authoring-contract.md +419 -0
  92. package/skills/archify/references/authoring-defaults.md +41 -0
  93. package/skills/archify/references/brand-marks.md +82 -0
  94. package/skills/archify/references/delivery-contract.md +588 -0
  95. package/skills/archify/references/repository-authoring.md +105 -0
  96. package/skills/archify/references/update-awareness.md +12 -0
  97. package/skills/archify/references/viewer-runtime.md +35 -0
  98. package/skills/archify/renderers/architecture/grid.mjs +62 -0
  99. package/skills/archify/renderers/architecture/labels.mjs +215 -0
  100. package/skills/archify/renderers/architecture/render-architecture.mjs +1001 -0
  101. package/skills/archify/renderers/architecture/routing.mjs +1157 -0
  102. package/skills/archify/renderers/dataflow/README.md +105 -0
  103. package/skills/archify/renderers/dataflow/render-dataflow.mjs +544 -0
  104. package/skills/archify/renderers/lifecycle/README.md +171 -0
  105. package/skills/archify/renderers/lifecycle/grid-routing.mjs +429 -0
  106. package/skills/archify/renderers/lifecycle/render-lifecycle.mjs +938 -0
  107. package/skills/archify/renderers/sequence/README.md +129 -0
  108. package/skills/archify/renderers/sequence/render-sequence.mjs +526 -0
  109. package/skills/archify/renderers/shared/atomic-output.mjs +1982 -0
  110. package/skills/archify/renderers/shared/brand-marks.mjs +670 -0
  111. package/skills/archify/renderers/shared/cli.mjs +451 -0
  112. package/skills/archify/renderers/shared/desktop-readability.mjs +132 -0
  113. package/skills/archify/renderers/shared/diagnostics.mjs +173 -0
  114. package/skills/archify/renderers/shared/engineering-profiles.mjs +157 -0
  115. package/skills/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
  116. package/skills/archify/renderers/shared/generated-validators.mjs +134 -0
  117. package/skills/archify/renderers/shared/geometry.mjs +1941 -0
  118. package/skills/archify/renderers/shared/i18n.mjs +603 -0
  119. package/skills/archify/renderers/shared/layout-report.mjs +42 -0
  120. package/skills/archify/renderers/shared/legend.mjs +217 -0
  121. package/skills/archify/renderers/shared/output-path.mjs +440 -0
  122. package/skills/archify/renderers/shared/path-semantics.mjs +1017 -0
  123. package/skills/archify/renderers/shared/portable-path.mjs +408 -0
  124. package/skills/archify/renderers/shared/repository-evidence.mjs +352 -0
  125. package/skills/archify/renderers/shared/repository-location.mjs +59 -0
  126. package/skills/archify/renderers/shared/route-quality.mjs +614 -0
  127. package/skills/archify/renderers/shared/sidecar-path.mjs +38 -0
  128. package/skills/archify/renderers/shared/spatial-grid.mjs +66 -0
  129. package/skills/archify/renderers/shared/text-fit.mjs +105 -0
  130. package/skills/archify/renderers/shared/utils.mjs +254 -0
  131. package/skills/archify/renderers/shared/validator.mjs +86 -0
  132. package/skills/archify/renderers/workflow/README.md +301 -0
  133. package/skills/archify/renderers/workflow/render-workflow.mjs +37 -0
  134. package/skills/archify/renderers/workflow/workflow-compiler.mjs +4913 -0
  135. package/skills/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  136. package/skills/archify/schemas/README.md +256 -0
  137. package/skills/archify/schemas/architecture.schema.json +152 -0
  138. package/skills/archify/schemas/common.schema.json +181 -0
  139. package/skills/archify/schemas/dataflow.schema.json +254 -0
  140. package/skills/archify/schemas/lifecycle.schema.json +280 -0
  141. package/skills/archify/schemas/sequence.schema.json +234 -0
  142. package/skills/archify/schemas/workflow.schema.json +439 -0
  143. package/skills/archify/scripts/check-render-output.mjs +1388 -0
  144. package/skills/archify/scripts/check-update.mjs +1710 -0
  145. package/skills/archify/scripts/delivery-update-child.mjs +23 -0
  146. package/skills/archify/scripts/render-examples.mjs +26 -0
  147. package/skills/archify/scripts/update-contract.mjs +182 -0
  148. package/skills/archify/skill-release.json +10 -0
@@ -0,0 +1,588 @@
1
+ # Delivery contract
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.
6
+
7
+ 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](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
+
9
+ 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. If an issue survives two focused repairs, inspect measured geometry or the relevant contract; after one evidence-based retry, report the concrete gap.
10
+
11
+ 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.
12
+
13
+ ## Validate and deliver
14
+
15
+ `render` and direct renderer entry points print classified authoring failures
16
+ to stderr as readable diagnostics and exit 1. Input read/JSON parse failures
17
+ use `input/read` or `input/json-parse`; output filesystem failures use
18
+ `output/write` and identify the output path. Schema and layout failures keep
19
+ their existing rule codes. Use the advertised `validate --json` or
20
+ `deliver --json` interface for a machine receipt; `render` has no `--json` flag.
21
+ Unexpected implementation failures retain debugging information in human
22
+ mode and remain `internal/unclassified` in machine receipts.
23
+
24
+ Each delivered output has two artifact-specific metadata paths. When an output
25
+ stem is too long for those derived filenames, Archify shortens it and appends a
26
+ stable hash:
27
+
28
+ - `<output-stem>.delivery.json` records the latest completed attempt.
29
+ - `<output-stem>.delivery-pending.json` is the recovery journal for an attempt
30
+ in progress.
31
+
32
+ For a literal artifact stem that already matches Archify's reserved bounded-name
33
+ marker, a pre-namespace raw provenance sidecar remains a read fallback when the
34
+ encoded sidecar is absent. A pre-namespace raw pending journal is an independent
35
+ fail-closed barrier: it blocks checks and redelivery even when an encoded pending
36
+ journal also exists, and neither journal is silently replaced.
37
+
38
+ One directory-wide `.archify-delivery-lock.json` serializes every delivery that
39
+ resolves into the same physical output directory. This deliberately prevents
40
+ case, Unicode-normalization, Windows short-name, and symbolic-link aliases from
41
+ creating independent owners for one filesystem location. The tradeoff is that
42
+ deliveries to different artifact names in one directory also run serially;
43
+ provenance and pending journals remain artifact-specific.
44
+
45
+ For migration safety, Archify also detects and preserves a legacy
46
+ `<output-stem>.delivery-lock.json` beside the requested artifact. An existing
47
+ legacy entry is a fail-closed recovery barrier. While a new delivery owns the
48
+ directory mutex, it also holds temporary legacy-format fences for the requested
49
+ spelling and an existing artifact's physical target spelling. It acquires the
50
+ directory lock first, then all required compatibility fences before writing a
51
+ journal or artifact, and removes the directory lock before those fences during
52
+ release. This blocks an older Archify binary using
53
+ either known spelling from entering the delivery. A legacy fence whose raw
54
+ HEAD-era filename exceeds the host component limit is omitted because the old
55
+ binary could not create that lock or deliver that artifact on the host either.
56
+
57
+ `deliver` acquires the lock by exclusive `open(..., "wx")` before creating or
58
+ replacing the recovery journal. A successful exclusive create yields an
59
+ internal opaque ownership capability bound to that attempt. Journal creation,
60
+ failed-provenance recording, pair commit, rollback, journal finalization, and
61
+ lock release each verify the current capability inside the operation that
62
+ would mutate shared state. A rejected contender does not create a journal or
63
+ write failed provenance.
64
+
65
+ An existing directory or legacy lock is handled without automatic recovery:
66
+
67
+ | Observed lock state | Required `deliver` result |
68
+ | --- | --- |
69
+ | No directory entry | Attempt exclusive creation; only its success grants ownership. |
70
+ | Valid schema-v1 lock whose PID is running, or whose death cannot be established | Exit 1 with `delivery/concurrent-attempt`; preserve every shared path. |
71
+ | 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. |
72
+ | 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. |
73
+ | An acquired capability no longer matches the current lock or journal | Exit 1 with `delivery/ownership-lost`; stop all shared-path mutation. |
74
+ | The matching owner cannot remove its lock | Exit 1 with `delivery/lock-release`; preserve the lock. |
75
+
76
+ A `delivery/lock-stale` diagnostic identifies the absolute output and lock
77
+ paths plus the original PID and receipt ID. Recovery is deliberately explicit
78
+ and serial: stop all delivery attempts for that physical output directory,
79
+ confirm that no active delivery owns it and that the reported stale entry has
80
+ not been replaced, remove only the reported lock, then rerun `deliver`. Do not
81
+ remove an artifact, current provenance, or pending journal as part of
82
+ stale-lock recovery.
83
+
84
+ The lock protocol targets Node.js 18 or later on a local filesystem with
85
+ cooperating Archify processes. PID, receipt, and file-identity comparisons are
86
+ defensive checks, not an atomic compare-and-swap. Compatibility fences cover
87
+ the requested spelling and an existing physical-target spelling; they cannot
88
+ enumerate arbitrary hard-link names or previously unknown filesystem aliases,
89
+ so mixed-version delivery through such aliases remains out of scope. This
90
+ contract does not claim distributed-lock correctness on NFS, SMB, or other
91
+ network filesystems, and it cannot prevent an external process that ignores
92
+ the protocol from replacing shared paths.
93
+
94
+ Every no-clobber HTML publisher (`render`, `deliver`, `compare`, and `preview`)
95
+ captures the requested directory entry, canonical write slot, physical parent,
96
+ and existing target type, device/inode identity, and mode before staging, then
97
+ revalidates that snapshot immediately before replacement. An existing write
98
+ target must be a regular file with exactly one hard-link name. A target with
99
+ multiple hard-link names fails closed with `output/target-hardlinked`: replacing
100
+ the requested name cannot update unknown sibling names as one publication.
101
+ Hard links remain supported for read identity and input/alias collision checks;
102
+ they are unsupported only as write targets. A symbolic link to a single-link regular
103
+ file remains supported: publication preserves the symbolic-link entry and
104
+ applies the same protocol to its resolved target. Directory, FIFO, socket,
105
+ device, changing mode, new claimant, and indeterminate identity cases fail
106
+ before replacement.
107
+
108
+ Publication is no-clobber and recoverable, not crash-atomic replacement of an
109
+ existing target. To avoid overwriting a claimant that appears after the last
110
+ identity check, Archify first retains the bound old file in a private recovery
111
+ backup, removes the public name through identity-bound quarantine, and then
112
+ creates the new public name with an exclusive hard link. A caught failure rolls
113
+ back when the public slot and recovery binding still permit it. A process
114
+ interruption between those namespace operations can instead leave the public
115
+ path absent while the verified previous bytes remain in an adjacent private
116
+ recovery backup. Single-artifact publication records the original slot/alias
117
+ identity and backup inode, mode, SHA-256, and byte count in private
118
+ `.archify-remove-*/publication-recovery-v1.json`, beside `previous`. To make a
119
+ specific interrupted publication visible again, stop concurrent writers and run:
120
+
121
+ ```bash
122
+ node bin/recover-output.mjs /absolute/path/to/.archify-remove-<id> --json
123
+ ```
124
+
125
+ This is explicit recovery, not a directory scanner. Before linking, the helper
126
+ checks for a changed parent or alias, an altered/hardlinked record or backup,
127
+ digest or inode mismatch, and any existing public target. It restores only by
128
+ no-clobber hard link, so a new claimant is preserved rather than overwritten;
129
+ it never recursively removes unknown entries. A completed recovery is
130
+ idempotent. The record is evidence to be independently verified, not an
131
+ authority to restore arbitrary private bytes: the helper accepts it only from
132
+ the recorded generated child of the original physical target parent, with the
133
+ same directory identity. Name the exact directory reported by the interrupted
134
+ process and inspect an uncertain record manually. A non-cooperating process can
135
+ still swap pathnames after those checks and before Node.js `linkSync`; Node does
136
+ not expose a descriptor-bound link operation. Post-link identity verification
137
+ then fails closed and retains recovery evidence, rather than claiming recovery
138
+ or deleting an uncertain name. If recovery itself is interrupted after the
139
+ link, the old public bytes and private backup can both remain; a later recovery
140
+ run preserves the public target and needs explicit operator resolution. The
141
+ record is fsynced before the old public name is retired on platforms supporting
142
+ directory sync, and the tested guarantee is recovery after a killed process;
143
+ this is not a claim of power-loss, storage-controller, NFS, or SMB durability.
144
+ Paired flows retain their backup in private transaction staging. For `deliver`,
145
+ the pending journal and lock keep strict checkers fail-closed. The portable
146
+ Node.js filesystem API has no pathname
147
+ compare-and-swap that both replaces an existing name atomically and refuses to
148
+ overwrite a late claimant: `rename` would close the visibility gap only by
149
+ overwriting that claimant.
150
+
151
+ After ownership is established, `deliver` creates the journal before rendering
152
+ and keeps it through the recoverable HTML/sidecar pair commit. It removes the
153
+ journal only after that commit completes. A validation, render, or pair-commit
154
+ failure, or a process interruption, may therefore leave a journal. The journal
155
+ is a safety barrier: `check`, `browser-check`, and `visual-check` fail closed when any directory
156
+ entry exists at the journal or lock path, including an unreadable file,
157
+ symlink, or dangling symlink. Run deliveries targeting the same physical output
158
+ directory serially; one attempt must finish or be recovered before another
159
+ begins.
160
+
161
+ A successful sidecar has `schemaVersion: 1`, `status: "current"`,
162
+ `command: "deliver"`, a unique `receiptId`, the diagram `type`, an absolute
163
+ `input` path, an absolute `output` path matching the inspected
164
+ artifact, and specification/artifact SHA-256 and byte counts. Checkers treat a
165
+ missing, malformed, unsupported, or inconsistent field as invalid. They also
166
+ reject a sidecar symlink, including a dangling one. A checker binds provenance
167
+ to the artifact bytes it actually checks and verifies that binding again before
168
+ reporting success; a concurrent byte change fails. The provenance directory
169
+ entry itself must be a single-link regular file: `deliver` and strict check fail
170
+ closed with `delivery/provenance-hardlink-unsupported` when it has another hard
171
+ link, without scanning for or guessing the sibling name.
172
+
173
+ If a currently verified owner fails after an older HTML exists, Archify writes
174
+ a new `status: "failed"` sidecar and leaves the journal until recovery is
175
+ complete. An unreadable old HTML does not prevent that marker; its artifact hash
176
+ and byte count may be absent. If the sidecar is locked or otherwise unwritable,
177
+ Archify keeps the prior sidecar rather than deleting evidence, and the journal
178
+ prevents checkers from trusting it. A rejected concurrent, stale, or invalid
179
+ lock attempt does not write failed provenance. If ownership is lost, Archify
180
+ reports `delivery/ownership-lost`, does not overwrite or remove the successor's
181
+ artifact, provenance, journal, or lock, and does not claim recorded failed
182
+ provenance; a failure receipt may report `provenance: "unrecorded"`. If every
183
+ metadata path is unavailable, the same unrecorded status applies; no tool can
184
+ preserve that fact across processes. Restore metadata-path access and complete
185
+ a successful `deliver` before trusting the output.
186
+
187
+ Artifacts with no sidecar, journal, or lock remain supported for backward
188
+ compatibility and for the lower-level `render` command. Their checker receipts
189
+ report `provenance: "unknown"`; use `--require-provenance` to turn that state
190
+ into a non-zero failure when the workflow requires a successfully delivered
191
+ artifact:
192
+
193
+ ```bash
194
+ node bin/archify.mjs check <output.html> --require-provenance
195
+ node bin/archify.mjs browser-check <output.html> --json --require-provenance
196
+ ```
197
+
198
+ ## Output path contracts
199
+
200
+ Archify intentionally separates durable authored paths from command-line paths:
201
+
202
+ - Required authored `meta.output` is a portable POSIX-relative path such as
203
+ `reports/diagram.html`. It uses `/`, ends in a non-empty `.html` basename,
204
+ and cannot contain an absolute or drive-relative prefix, URI, backslash,
205
+ empty or dot segment, control character, unpaired UTF-16 surrogate, Windows
206
+ alternate-data-stream separator or invalid filename character, trailing dot
207
+ or space, DOS device name, or a component over either the 255-byte UTF-8 or
208
+ 255-code-unit UTF-16 limit. It resolves from the current working directory
209
+ and must remain physically inside that directory, with an `.html` target,
210
+ after symbolic links are followed. The durable output/archive profile also
211
+ conservatively rejects a Windows 8.3 short-name shape such as `PROGRA~1`;
212
+ descriptive repo/Git POSIX paths use a separate profile and are exempt.
213
+ - Explicit CLI output arguments use the active host's native syntax. They may
214
+ be relative or absolute, use native separators, and resolve outside the
215
+ current working directory. On Windows, ordinary drive-absolute, UNC, and
216
+ relative paths (including ordinary `.` and `..` navigation) are supported.
217
+ A system-resolved 8.3 spelling of an existing file or directory is accepted
218
+ when Archify can prove its physical identity; this native alias support does
219
+ not relax the durable output/archive profile's 8.3-shaped-name rejection.
220
+ Extended-length paths are limited to raw backslash-only `\\?\C:\...` and
221
+ `\\?\UNC\server\share\...` forms without dot segments; device namespaces,
222
+ malformed roots, drive-relative paths such as `C:file.html`, current-drive
223
+ roots such as `\file.html`, alternate data streams, reserved device names,
224
+ invalid or trailing filename characters, and overlong components fail
225
+ closed. POSIX CLI paths retain POSIX filename rules rather than inheriting
226
+ Windows spelling restrictions. Every host rejects NUL, unpaired surrogates,
227
+ and components that exceed its supported bound.
228
+
229
+ These contracts are not interchangeable: an explicit CLI output does not hide
230
+ an invalid durable `meta.output` (including a missing value), and `validate`
231
+ checks the authored output even when it does not publish to that path. A
232
+ workflow v1-to-v2 migration may explicitly receive a portable durable
233
+ replacement through `migrate workflow old.json new.json --to-schema 2 --output
234
+ reports/diagram.html`; that value is written only to its separate verified v2
235
+ destination. This migration-candidate exception does not repair the source or
236
+ bypass any non-output schema or compiler error. For every other repair, add a
237
+ portable POSIX-relative `.html` path to `meta.output`; no schema-version change
238
+ is otherwise required.
239
+
240
+ 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
241
+ `.html`, including after symbolic-link resolution. Compare receipt paths must
242
+ end in `.json`. A type mismatch fails before writing with
243
+ `output/cli-extension` or `output/cli-resolved-extension`. These checks prevent
244
+ accidental file-type overwrites; they do not sandbox explicit CLI directories
245
+ or prevent replacement of an existing artifact of the expected type.
246
+
247
+ Use final verified delivery only after the candidate is frozen:
248
+
249
+ ```bash
250
+ node bin/archify.mjs deliver <type> <candidate.json> <output.html> --quality showcase --json
251
+ ```
252
+
253
+ 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`.
254
+
255
+ For the ordinary agent handoff path, prefer the finalizer:
256
+
257
+ ```bash
258
+ node bin/archify.mjs finalize <type> <candidate.json> <output.html> --quality showcase --json
259
+ ```
260
+
261
+ `finalize` invokes verified `deliver` once, reuses its embedded showcase
262
+ validation result, then runs strict `check --require-provenance` and
263
+ `browser-check --require-provenance`. It stops at the first failed or skipped stage
264
+ and preserves that stage's full receipt. Its stdout is one compact JSON
265
+ object with gate statuses, bounded actionable diagnostics, artifact identity,
266
+ and evidence paths. The same compact object is written atomically to
267
+ `<output-stem>.finalize-summary.json`; use that file for normal failure repair.
268
+ Complete stage receipts and timings remain available for auditing in
269
+ `<output-stem>.finalize.json`. With `--out-dir`, both files are written there;
270
+ `--receipt <path.json>` overrides the full receipt path and derives a distinct
271
+ `<path>-summary.json`. Read the full receipt only when the compact summary is
272
+ truncated and its shown subjects and evidence cannot identify a coherent local
273
+ repair, or when complete audit evidence was explicitly requested. The compact
274
+ 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](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.
275
+
276
+ For a measured automatic Architecture with a large unused leading area, the
277
+ compact receipt may include `layoutReviewRecommendation`. Its
278
+ `composition.leadingSpace` evidence accounts for nodes, boundary titles,
279
+ routes and labels. Check whether that space is intentional; if not, reposition
280
+ the connected scene while preserving meaning and user-fixed geometry, then
281
+ finalize again. This suggestion changes no gate or exit status and requires
282
+ no screenshot. A fixed canvas or uncertain measurement receives no suggestion.
283
+
284
+ A passing finalizer receipt is sufficient evidence for all four gates. Merely
285
+ naming the gates or requiring each one to pass does not require replaying their
286
+ standalone commands. Replay an individual command only when the request
287
+ explicitly requires separate executions or focused failure diagnosis needs it.
288
+
289
+ The individual commands remain authoritative and backward compatible. Use
290
+ them directly for focused diagnosis, recovery, or when only one gate is
291
+ required. A finalize failure does not relax any gate and does not turn a
292
+ preserved older artifact into a current successful delivery.
293
+
294
+ `finalize` overlaps private Chrome startup with delivery and strict checking.
295
+ It loads the artifact only after those gates pass and current provenance is
296
+ verified. The browser gate retains every viewport, theme, and stability check;
297
+ the browser closes at completion or an earlier failure. Its full stage receipt
298
+ records `execution: "in-process"` and the equivalent standalone `command` for
299
+ replay. Use total finalize duration to compare performance because Chrome
300
+ startup overlaps the earlier stages.
301
+
302
+ The pair commit is recoverable, not a claim that two filesystem paths change
303
+ atomically or are durable across power loss. Journal finalization is part of
304
+ that commit: a caught failure while verifying or removing the journal rolls
305
+ back the replaced files when possible and while ownership remains current. If
306
+ ownership is lost, the old attempt immediately stops renaming, rolling back,
307
+ finalizing the journal, recording failure provenance, or cleaning up shared
308
+ paths. Any private staging or recoverable backups remain available and are
309
+ identified by the failure diagnostic. If restoration fails for another reason,
310
+ the failure receipt likewise identifies retained backups for recovery. A
311
+ process interruption can leave the journal, backups, or private staging behind;
312
+ checkers then fail closed. Follow the reported recovery evidence before rerunning
313
+ `deliver` serially on the same output. A failed attempt exits non-zero and never invokes an opener; it never
314
+ authorizes visual evidence collection.
315
+
316
+ If exclusive creation succeeds but lock initialization fails, Archify may
317
+ record failed provenance and remove the incomplete lock only while its
318
+ capability still identifies that exact entry. A replacement is preserved.
319
+ Filesystem and cleanup errors are reported separately from an active concurrent
320
+ delivery. An active, stale, unrecognized, or otherwise preserved lock
321
+ independently prevents checkers from accepting the prior artifact. Fix the
322
+ reported filesystem error before retrying, and use another physical output
323
+ directory if the lock path contains unrelated data.
324
+
325
+ Lock release is part of delivery completion. If the artifact/provenance pair
326
+ has committed and the journal has finalized but the matching lock cannot be
327
+ removed, `deliver` exits 1 with `delivery/lock-release`, preserves the lock,
328
+ does not print a success receipt, and does not invoke an opener. The preserved
329
+ lock keeps strict checkers fail-closed. Only after pair commit, journal
330
+ finalization, and lock release all succeed may `deliver` exit zero, print its
331
+ success receipt, or run `--open`.
332
+
333
+ Run strict `check` after `deliver` exits zero. Run `browser-check` or optional
334
+ `visual-check` only after that strict check exits zero. A failed marker,
335
+ recovery journal, or delivery lock makes every checker fail before accepting
336
+ the preserved HTML; report the diagnostics and complete a successful recovery
337
+ delivery before collecting new browser evidence.
338
+
339
+ The delivery interface exposes four separate claims:
340
+
341
+ 1. `deliver` proves deterministic artifact checks and byte identity.
342
+ 2. `browser-check` collects required automated browser evidence from the exact artifact without capturing images.
343
+ 3. `visual-check` optionally adds artifact-bound screenshots and a contact sheet.
344
+ 4. Perceptual visual review records a human or image-capable reviewer's judgment.
345
+
346
+ Passing one claim never implies the others. Never claim that the deterministic receipt includes browser or perceptual review evidence.
347
+
348
+ ## Recovering a failed comparison
349
+
350
+ `compare` commits an HTML artifact and its JSON receipt as a pair. If that commit
351
+ fails, it attempts to restore the previous files. A complete rollback removes
352
+ the temporary directory as usual.
353
+
354
+ If a previous file cannot be restored, compare exits non-zero with
355
+ `delta/commit-rollback-failed` and retains the recovery directory. In the JSON
356
+ failure receipt, `diagnostics[].evidence.recoveryDirectory` identifies that
357
+ directory and `recoveryFiles` lists `{ backup, target }` paths for the files whose
358
+ restoration failed. Human-readable diagnostics also print the recovery paths.
359
+
360
+ Resolve the filesystem error, inspect the current targets, and restore each
361
+ listed backup to its corresponding target before retrying. Keep the recovery
362
+ directory until both previous files have been recovered and verified; it can
363
+ also contain rejected candidate files, which must not be mistaken for backups.
364
+ Successful comparisons and failures before commit retain their normal cleanup.
365
+
366
+ ## Automated browser evidence
367
+
368
+ `finalize` runs the required browser gate against the exact trusted HTML without
369
+ rerendering or modifying it. For focused diagnosis, the equivalent standalone
370
+ command is:
371
+
372
+ ```bash
373
+ node bin/archify.mjs browser-check <output.html> --json --require-provenance
374
+ ```
375
+
376
+ The zero-dependency command uses Chrome/Chromium through the DevTools pipe. It
377
+ measures light-theme containment at 1440×900, 1600×1000, 1920×1080, and
378
+ 2048×1320, and verifies the requested light theme at all four viewports, the dark
379
+ theme at both endpoints, and READ/Still runtime states. A requested theme that
380
+ resolves to a different theme fails with measured evidence. It creates one
381
+ `<output-stem>.browser-check.json` receipt and no screenshots or contact sheet.
382
+ Pass `--out-dir <dir>` to place the receipt in a separate evidence directory.
383
+ The receipt binds the artifact SHA-256 and byte count, identifies
384
+ `evidenceKind: "automated-browser"`, and reports
385
+ `visualReview: "not-requested"`.
386
+
387
+ Horizontal overflow always fails. Normal document-level vertical scrolling is
388
+ accepted only with a renderer-declared contract and measured readable text.
389
+ Automatic canvases declare `data-reader-fit="intrinsic-height"`; their adaptive
390
+ Reader must reach its readable width and expose `data-reader-overflow="authored"`.
391
+ Architecture with an explicit `meta.viewBox` instead declares
392
+ `data-diagram-type="architecture"` and `data-reader-fit="authored-height"`:
393
+ its SVG coordinates, aspect ratio and existing Reader width behavior stay
394
+ unchanged. Its full SVG must remain inside the diagram panel without internal
395
+ scrolling or clipping, and the document must permit vertical scrolling.
396
+ The receipt records `verticalScrollAccepted: true` and
397
+ `overflowDisposition: "readable-vertical-scroll"`. Missing or unknown declarations,
398
+ explicit viewBoxes in other modes, unreadable text, horizontal overflow,
399
+ clipping and Viewer chrome collisions remain failures. Do not add an internal
400
+ diagram scroller or hide overflow.
401
+
402
+ `browser_evidence` in the handoff records only the outcome of this automated
403
+ command:
404
+
405
+ - `passed` maps from exit 0 and receipt `status: "pass"` after every required measurement completes and passes.
406
+ - `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.
407
+ - `skipped` maps only from exit 2 and receipt `status: "skipped"` when Chrome/Chromium is unavailable and the inspection does not run.
408
+
409
+ Runtime failures leave incomplete evidence and must not be normalized to
410
+ `skipped`. They do not invalidate an already successful deterministic delivery.
411
+ Retry an environmental failure in a browser-capable execution context when
412
+ practical. Keep the packaged transport unchanged unless the failure reproduces
413
+ through that seam in a capable environment.
414
+
415
+ A provenance failure exits before browser inspection and persists a failed
416
+ browser-check receipt bound to the attempted artifact. If the failure receipt
417
+ cannot be written, the diagnostic names that incomplete evidence.
418
+
419
+ Both browser commands inspect the exact delivered HTML without modifying or rerendering it.
420
+
421
+ ## Sequence width review
422
+
423
+ 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.
424
+
425
+ For a newly authored candidate with omitted `meta.column_fit` and no user-fixed column geometry, 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 an explicitly fixed layout or a supplied legacy candidate and disclose the suggestion without changing it. This review is about horizontal composition; a passing receipt still does not claim perceptual approval.
426
+
427
+ ## Optional capture evidence
428
+
429
+ `visual-check` remains backward compatible for a requested or escalated
430
+ perceptual review:
431
+
432
+ ```bash
433
+ node bin/archify.mjs visual-check <output.html> --summary --require-provenance
434
+ ```
435
+
436
+ `--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.
437
+
438
+ It performs the same automated browser measurements, captures light/dark
439
+ screenshots at 1440×900 and 2048×1320, and writes four viewport PNG sidecars,
440
+ one relative-path HTML contact sheet, and one JSON receipt. `--out-dir <dir>` moves all of these sidecars together.
441
+ 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
442
+ make a perceptual judgment. Capture and provenance failures follow the ownership rules below.
443
+
444
+ The receipt, contact sheet, and four PNGs form one owned evidence set. Before
445
+ capture, `visual-check` freezes every requested directory entry, its
446
+ canonical write slot and physical parent, and the target's absent/file state,
447
+ type, device/inode identity, and mode. Hard-linked evidence targets are not safe
448
+ write targets. All candidate files are created exclusively inside one random,
449
+ private staging directory beneath the physical evidence directory; the receipt
450
+ is published last. Each staged candidate must have exactly one hard-link name
451
+ before publication. The no-clobber publish link temporarily gives the staged
452
+ and final names a link count of two; unlinking the verified staged name must
453
+ leave the final entry with a link count of one. An unexpected external hard
454
+ link fails closed and its alias is never removed.
455
+
456
+ Chrome inspects one identity- and content-checked copy of the captured artifact
457
+ in a private local temporary directory, so browser file loading does not depend
458
+ on UNC or long-path support. The six publication candidates remain on the
459
+ evidence volume. Both temporary directories are cleaned without recursively
460
+ deleting unknown contents; retained entries include their recovery locations.
461
+
462
+ Immediately before committing anything, `visual-check` re-resolves and verifies
463
+ the complete six-path set. An absent-path claimant, existing-path replacement,
464
+ symbolic-link or dangling-link retarget, parent-topology change, hard link, or
465
+ indeterminate identity fails closed with `viewer/evidence-path-conflict`. The
466
+ claimant and every other final evidence path remain untouched. Cleanup removes
467
+ only this run's staged or published entries after rechecking their captured
468
+ identities; a changed or unknown entry is preserved.
469
+
470
+ An existing visual evidence set is replaceable only when a regular
471
+ `visual-check` receipt proves ownership of the same artifact and evidence
472
+ directory, and its exact sidecar manifest matches every existing contact-sheet
473
+ or PNG byte count and SHA-256 digest. A missing, malformed, unknown, mismatched,
474
+ or incomplete ownership record never authorizes deletion. Failed and skipped
475
+ runs retire prior screenshots/contact sheets only as part of the same verified
476
+ transaction when that ownership proof succeeds; otherwise they preserve all
477
+ unknown evidence and report `viewer/evidence-path-conflict`.
478
+
479
+ This rule also applies when Chrome is unavailable or provenance fails before
480
+ browser inspection: neither path may blindly delete stale-looking evidence. A
481
+ verified owned set may be recoverably retired before publishing a skipped or
482
+ failed receipt; unowned evidence remains intact. These outcomes do not invalidate an already
483
+ successful deterministic delivery and do not turn a perceptual visual review
484
+ into passed or failed. Retry an environmental failure through the supported
485
+ command in a browser-capable execution context when practical. Keep the
486
+ packaged transport unchanged unless the failure reproduces through that seam in
487
+ a capable environment.
488
+
489
+ `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.
490
+
491
+ ## A new candidate at an existing output path
492
+
493
+ 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:
494
+
495
+ ```bash
496
+ node bin/archify.mjs finalize architecture candidate.json diagram.html --quality showcase --repo-root <root> --out-dir diagram.review-2 --json
497
+ node bin/archify.mjs visual-check diagram.html --out-dir diagram.review-2 --summary --require-provenance
498
+ ```
499
+
500
+ 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.
501
+
502
+ ## Optional opening
503
+
504
+ Add `--open` only when the user wants an immediate local preview. It runs after
505
+ the verified pair commit has completed, its recovery journal has been removed,
506
+ and the delivery lock has been released successfully. It uses one argument-array
507
+ OS opener with a five-second bound on macOS and Linux, and a fifteen-second bound
508
+ for PowerShell startup on Windows. The receipt records `open.status`; failed or
509
+ unavailable launch attempts also include normalized `open.failure` details.
510
+ Keep it off for CI, unattended agents, and non-interactive environments.
511
+ Failure or unsupported opening does not invalidate delivery; its
512
+ status proves only whether the local opener invocation succeeded.
513
+
514
+ ## Last-Good Live Preview
515
+
516
+ For an active desktop authoring loop only:
517
+
518
+ ```bash
519
+ node bin/archify.mjs preview <type> <input>.json <output>.html --quality showcase
520
+ ```
521
+
522
+ 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.
523
+
524
+ The preview runtime ships inside the zero-dependency Skill ZIP and must work without `node_modules`.
525
+
526
+ 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.
527
+
528
+ ## Perceptual review
529
+
530
+ The automated path ends with the deterministic browser gate and reports
531
+ `visual_review: not_requested`. Ordinary generation does not require screenshots
532
+ or an image-reading step, including newly authored or repositioned Architecture.
533
+ Perceptual review is optional; use it for an explicit request or a concrete visual
534
+ investigation. Possible reasons include:
535
+
536
+ - the compact finalizer includes `visualReviewRecommendation` for crossings or detours (advisory, not a delivery gate);
537
+ - the user explicitly requests an aesthetic or visual review;
538
+ - a template, renderer, or Viewer change needs visual regression evidence;
539
+ - a novel layout or browser diagnostic leaves low confidence;
540
+ - the run is selected for sampled audit or dogfood.
541
+
542
+ 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.
543
+
544
+ For an escalation, run `visual-check` on the current finalized artifact, inspect
545
+ its contact sheet with a capable image reader or human, and check both endpoint
546
+ themes, the default READ view, line crossings/corridors, label masks, node/card
547
+ fit, focus/search/passport closure, and export cleanliness. This review is
548
+ supplementary and never changes `browser_evidence`. An unconstrained browser
549
+ glance can support perceptual review only.
550
+
551
+ Report one truthful optional-review status:
552
+
553
+ - `visual_review: not_requested` — no review trigger applies; this is not a visual acceptance claim.
554
+ - `visual_review: passed` — only after inspecting the rendered artifact.
555
+ - `visual_review: skipped (image reader unavailable)` — a requested or triggered review could not run.
556
+ - `visual_review: failed` — with the concrete visible defect.
557
+
558
+ For an escalated review, use `correction_rounds: 0`, `correction_rounds: 1`, or
559
+ `correction_rounds: 2`; never exceed two focused correction rounds. When review
560
+ is not requested, use `correction_rounds: 0`. Never report
561
+ `visual_review: passed` without inspecting the artifact. If perceptual review
562
+ changes the candidate, rerun `finalize` because the previous specification and
563
+ artifact receipts are no longer current.
564
+
565
+ ## Handoff receipt
566
+
567
+ Return:
568
+
569
+ ```text
570
+ diagram_type: architecture|workflow|sequence|dataflow|lifecycle
571
+ output: /absolute/path/to/file.html
572
+ specification_sha256: <receipt value>
573
+ artifact_sha256: <receipt value>
574
+ validation: 9/9 showcase, 0 errors, 0 warnings
575
+ browser_evidence: passed|failed|skipped
576
+ visual_review: not_requested|passed|skipped (image reader unavailable)|failed
577
+ correction_rounds: 0|1|2
578
+ ```
579
+
580
+ Derive `browser_evidence` only from the latest artifact-bound `browser-check`
581
+ receipt, normally the stage embedded by `finalize`. Record optional capture or
582
+ manual browser work separately with its artifact binding, viewport/theme scope,
583
+ and observations; never use it or `visual_review` to overwrite the automated
584
+ status.
585
+
586
+ Opening, preview status, Share Cards, and other viewer exports are not validation claims.
587
+
588
+ 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.