@dailephd/my-frontend-observer 0.8.1

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 (316) hide show
  1. package/CHANGELOG.md +397 -0
  2. package/LICENSE +21 -0
  3. package/README.md +255 -0
  4. package/dist/application/browserCaptureService.d.ts +11 -0
  5. package/dist/application/browserCaptureService.js +12 -0
  6. package/dist/application/browserCaptureService.js.map +1 -0
  7. package/dist/application/comparisonService.d.ts +56 -0
  8. package/dist/application/comparisonService.js +77 -0
  9. package/dist/application/comparisonService.js.map +1 -0
  10. package/dist/application/externalReferencePersistenceService.d.ts +75 -0
  11. package/dist/application/externalReferencePersistenceService.js +182 -0
  12. package/dist/application/externalReferencePersistenceService.js.map +1 -0
  13. package/dist/application/frontendContractEvaluationService.d.ts +49 -0
  14. package/dist/application/frontendContractEvaluationService.js +112 -0
  15. package/dist/application/frontendContractEvaluationService.js.map +1 -0
  16. package/dist/application/frontendContractPersistenceService.d.ts +56 -0
  17. package/dist/application/frontendContractPersistenceService.js +91 -0
  18. package/dist/application/frontendContractPersistenceService.js.map +1 -0
  19. package/dist/application/observationPersistence.d.ts +59 -0
  20. package/dist/application/observationPersistence.js +79 -0
  21. package/dist/application/observationPersistence.js.map +1 -0
  22. package/dist/application/projectCheckService.d.ts +3 -0
  23. package/dist/application/projectCheckService.js +169 -0
  24. package/dist/application/projectCheckService.js.map +1 -0
  25. package/dist/application/projectWorkflowService.d.ts +46 -0
  26. package/dist/application/projectWorkflowService.js +92 -0
  27. package/dist/application/projectWorkflowService.js.map +1 -0
  28. package/dist/application/referenceFidelityEvaluationService.d.ts +28 -0
  29. package/dist/application/referenceFidelityEvaluationService.js +45 -0
  30. package/dist/application/referenceFidelityEvaluationService.js.map +1 -0
  31. package/dist/artifacts/artifactReader.d.ts +19 -0
  32. package/dist/artifacts/artifactReader.js +36 -0
  33. package/dist/artifacts/artifactReader.js.map +1 -0
  34. package/dist/artifacts/artifactWriter.d.ts +25 -0
  35. package/dist/artifacts/artifactWriter.js +68 -0
  36. package/dist/artifacts/artifactWriter.js.map +1 -0
  37. package/dist/artifacts/comparisonArtifactReader.d.ts +18 -0
  38. package/dist/artifacts/comparisonArtifactReader.js +35 -0
  39. package/dist/artifacts/comparisonArtifactReader.js.map +1 -0
  40. package/dist/artifacts/comparisonArtifactWriter.d.ts +41 -0
  41. package/dist/artifacts/comparisonArtifactWriter.js +67 -0
  42. package/dist/artifacts/comparisonArtifactWriter.js.map +1 -0
  43. package/dist/artifacts/externalReferenceArtifactReader.d.ts +18 -0
  44. package/dist/artifacts/externalReferenceArtifactReader.js +35 -0
  45. package/dist/artifacts/externalReferenceArtifactReader.js.map +1 -0
  46. package/dist/artifacts/externalReferenceArtifactWriter.d.ts +44 -0
  47. package/dist/artifacts/externalReferenceArtifactWriter.js +77 -0
  48. package/dist/artifacts/externalReferenceArtifactWriter.js.map +1 -0
  49. package/dist/artifacts/frontendContractArtifactReader.d.ts +24 -0
  50. package/dist/artifacts/frontendContractArtifactReader.js +47 -0
  51. package/dist/artifacts/frontendContractArtifactReader.js.map +1 -0
  52. package/dist/artifacts/frontendContractArtifactWriter.d.ts +34 -0
  53. package/dist/artifacts/frontendContractArtifactWriter.js +70 -0
  54. package/dist/artifacts/frontendContractArtifactWriter.js.map +1 -0
  55. package/dist/artifacts/frontendContractEvaluationArtifactReader.d.ts +17 -0
  56. package/dist/artifacts/frontendContractEvaluationArtifactReader.js +34 -0
  57. package/dist/artifacts/frontendContractEvaluationArtifactReader.js.map +1 -0
  58. package/dist/artifacts/frontendContractEvaluationArtifactWriter.d.ts +32 -0
  59. package/dist/artifacts/frontendContractEvaluationArtifactWriter.js +58 -0
  60. package/dist/artifacts/frontendContractEvaluationArtifactWriter.js.map +1 -0
  61. package/dist/artifacts/types.d.ts +17 -0
  62. package/dist/artifacts/types.js +2 -0
  63. package/dist/artifacts/types.js.map +1 -0
  64. package/dist/browser/chromiumAdapter.d.ts +21 -0
  65. package/dist/browser/chromiumAdapter.js +204 -0
  66. package/dist/browser/chromiumAdapter.js.map +1 -0
  67. package/dist/browser/evidenceCapture.d.ts +62 -0
  68. package/dist/browser/evidenceCapture.js +500 -0
  69. package/dist/browser/evidenceCapture.js.map +1 -0
  70. package/dist/browser/scrollCapture.d.ts +32 -0
  71. package/dist/browser/scrollCapture.js +163 -0
  72. package/dist/browser/scrollCapture.js.map +1 -0
  73. package/dist/browser/types.d.ts +24 -0
  74. package/dist/browser/types.js +2 -0
  75. package/dist/browser/types.js.map +1 -0
  76. package/dist/cli.d.ts +8 -0
  77. package/dist/cli.js +2411 -0
  78. package/dist/cli.js.map +1 -0
  79. package/dist/domain/boundedAgentContext.d.ts +226 -0
  80. package/dist/domain/boundedAgentContext.js +355 -0
  81. package/dist/domain/boundedAgentContext.js.map +1 -0
  82. package/dist/domain/boundedAgentContextCorrelation.d.ts +74 -0
  83. package/dist/domain/boundedAgentContextCorrelation.js +441 -0
  84. package/dist/domain/boundedAgentContextCorrelation.js.map +1 -0
  85. package/dist/domain/boundedAgentContextIdentity.d.ts +26 -0
  86. package/dist/domain/boundedAgentContextIdentity.js +69 -0
  87. package/dist/domain/boundedAgentContextIdentity.js.map +1 -0
  88. package/dist/domain/boundedAgentContextProjection.d.ts +71 -0
  89. package/dist/domain/boundedAgentContextProjection.js +477 -0
  90. package/dist/domain/boundedAgentContextProjection.js.map +1 -0
  91. package/dist/domain/comparison.d.ts +220 -0
  92. package/dist/domain/comparison.js +350 -0
  93. package/dist/domain/comparison.js.map +1 -0
  94. package/dist/domain/comparisonEngine.d.ts +76 -0
  95. package/dist/domain/comparisonEngine.js +734 -0
  96. package/dist/domain/comparisonEngine.js.map +1 -0
  97. package/dist/domain/comparisonIdentity.d.ts +13 -0
  98. package/dist/domain/comparisonIdentity.js +46 -0
  99. package/dist/domain/comparisonIdentity.js.map +1 -0
  100. package/dist/domain/completion.d.ts +30 -0
  101. package/dist/domain/completion.js +22 -0
  102. package/dist/domain/completion.js.map +1 -0
  103. package/dist/domain/diagnostics.d.ts +17 -0
  104. package/dist/domain/diagnostics.js +77 -0
  105. package/dist/domain/diagnostics.js.map +1 -0
  106. package/dist/domain/evidence.d.ts +29 -0
  107. package/dist/domain/evidence.js +59 -0
  108. package/dist/domain/evidence.js.map +1 -0
  109. package/dist/domain/explicitState.d.ts +40 -0
  110. package/dist/domain/explicitState.js +54 -0
  111. package/dist/domain/explicitState.js.map +1 -0
  112. package/dist/domain/externalReference.d.ts +158 -0
  113. package/dist/domain/externalReference.js +167 -0
  114. package/dist/domain/externalReference.js.map +1 -0
  115. package/dist/domain/externalReferenceApplicability.d.ts +43 -0
  116. package/dist/domain/externalReferenceApplicability.js +52 -0
  117. package/dist/domain/externalReferenceApplicability.js.map +1 -0
  118. package/dist/domain/externalReferenceCompatibility.d.ts +40 -0
  119. package/dist/domain/externalReferenceCompatibility.js +48 -0
  120. package/dist/domain/externalReferenceCompatibility.js.map +1 -0
  121. package/dist/domain/externalReferenceFidelity.d.ts +171 -0
  122. package/dist/domain/externalReferenceFidelity.js +419 -0
  123. package/dist/domain/externalReferenceFidelity.js.map +1 -0
  124. package/dist/domain/externalReferenceIdentity.d.ts +38 -0
  125. package/dist/domain/externalReferenceIdentity.js +70 -0
  126. package/dist/domain/externalReferenceIdentity.js.map +1 -0
  127. package/dist/domain/externalReferenceImage.d.ts +35 -0
  128. package/dist/domain/externalReferenceImage.js +160 -0
  129. package/dist/domain/externalReferenceImage.js.map +1 -0
  130. package/dist/domain/externalReferenceRegionRelationships.d.ts +63 -0
  131. package/dist/domain/externalReferenceRegionRelationships.js +98 -0
  132. package/dist/domain/externalReferenceRegionRelationships.js.map +1 -0
  133. package/dist/domain/externalReferenceRegions.d.ts +65 -0
  134. package/dist/domain/externalReferenceRegions.js +105 -0
  135. package/dist/domain/externalReferenceRegions.js.map +1 -0
  136. package/dist/domain/externalReferenceRequirementIdentity.d.ts +12 -0
  137. package/dist/domain/externalReferenceRequirementIdentity.js +35 -0
  138. package/dist/domain/externalReferenceRequirementIdentity.js.map +1 -0
  139. package/dist/domain/externalReferenceRequirements.d.ts +215 -0
  140. package/dist/domain/externalReferenceRequirements.js +401 -0
  141. package/dist/domain/externalReferenceRequirements.js.map +1 -0
  142. package/dist/domain/externalReferenceRuntimeBinding.d.ts +146 -0
  143. package/dist/domain/externalReferenceRuntimeBinding.js +183 -0
  144. package/dist/domain/externalReferenceRuntimeBinding.js.map +1 -0
  145. package/dist/domain/frontendContractEvaluation.d.ts +57 -0
  146. package/dist/domain/frontendContractEvaluation.js +454 -0
  147. package/dist/domain/frontendContractEvaluation.js.map +1 -0
  148. package/dist/domain/frontendContractEvaluationArtifact.d.ts +65 -0
  149. package/dist/domain/frontendContractEvaluationArtifact.js +108 -0
  150. package/dist/domain/frontendContractEvaluationArtifact.js.map +1 -0
  151. package/dist/domain/frontendContractIdentity.d.ts +39 -0
  152. package/dist/domain/frontendContractIdentity.js +70 -0
  153. package/dist/domain/frontendContractIdentity.js.map +1 -0
  154. package/dist/domain/frontendContracts.d.ts +188 -0
  155. package/dist/domain/frontendContracts.js +260 -0
  156. package/dist/domain/frontendContracts.js.map +1 -0
  157. package/dist/domain/identity.d.ts +21 -0
  158. package/dist/domain/identity.js +47 -0
  159. package/dist/domain/identity.js.map +1 -0
  160. package/dist/domain/referenceCorrectionIdentity.d.ts +40 -0
  161. package/dist/domain/referenceCorrectionIdentity.js +77 -0
  162. package/dist/domain/referenceCorrectionIdentity.js.map +1 -0
  163. package/dist/domain/referenceCorrectionWorkflow.d.ts +160 -0
  164. package/dist/domain/referenceCorrectionWorkflow.js +165 -0
  165. package/dist/domain/referenceCorrectionWorkflow.js.map +1 -0
  166. package/dist/domain/referenceFidelityProjection.d.ts +65 -0
  167. package/dist/domain/referenceFidelityProjection.js +135 -0
  168. package/dist/domain/referenceFidelityProjection.js.map +1 -0
  169. package/dist/domain/relationships.d.ts +210 -0
  170. package/dist/domain/relationships.js +352 -0
  171. package/dist/domain/relationships.js.map +1 -0
  172. package/dist/domain/schema.d.ts +269 -0
  173. package/dist/domain/schema.js +442 -0
  174. package/dist/domain/schema.js.map +1 -0
  175. package/dist/domain/scrollEvidence.d.ts +51 -0
  176. package/dist/domain/scrollEvidence.js +134 -0
  177. package/dist/domain/scrollEvidence.js.map +1 -0
  178. package/dist/index.d.ts +114 -0
  179. package/dist/index.js +64 -0
  180. package/dist/index.js.map +1 -0
  181. package/dist/projectWorkflow/aliasCatalog.d.ts +21 -0
  182. package/dist/projectWorkflow/aliasCatalog.js +67 -0
  183. package/dist/projectWorkflow/aliasCatalog.js.map +1 -0
  184. package/dist/projectWorkflow/checkAcceptance.d.ts +25 -0
  185. package/dist/projectWorkflow/checkAcceptance.js +55 -0
  186. package/dist/projectWorkflow/checkAcceptance.js.map +1 -0
  187. package/dist/projectWorkflow/checkResult.d.ts +85 -0
  188. package/dist/projectWorkflow/checkResult.js +101 -0
  189. package/dist/projectWorkflow/checkResult.js.map +1 -0
  190. package/dist/projectWorkflow/projectConfig.d.ts +43 -0
  191. package/dist/projectWorkflow/projectConfig.js +84 -0
  192. package/dist/projectWorkflow/projectConfig.js.map +1 -0
  193. package/dist/projectWorkflow/projectDiscovery.d.ts +9 -0
  194. package/dist/projectWorkflow/projectDiscovery.js +20 -0
  195. package/dist/projectWorkflow/projectDiscovery.js.map +1 -0
  196. package/dist/projectWorkflow/projectPaths.d.ts +8 -0
  197. package/dist/projectWorkflow/projectPaths.js +23 -0
  198. package/dist/projectWorkflow/projectPaths.js.map +1 -0
  199. package/dist/request/paths.d.ts +14 -0
  200. package/dist/request/paths.js +33 -0
  201. package/dist/request/paths.js.map +1 -0
  202. package/dist/request/request.d.ts +111 -0
  203. package/dist/request/request.js +464 -0
  204. package/dist/request/request.js.map +1 -0
  205. package/dist/safety/policy.d.ts +14 -0
  206. package/dist/safety/policy.js +81 -0
  207. package/dist/safety/policy.js.map +1 -0
  208. package/dist/viewer/assets/index-CN_yb9Uf.css +1 -0
  209. package/dist/viewer/assets/index-D98S1_2d.js +9 -0
  210. package/dist/viewer/icons/icon-192.png +0 -0
  211. package/dist/viewer/icons/icon-512.png +0 -0
  212. package/dist/viewer/index.html +15 -0
  213. package/dist/viewer/manifest.webmanifest +1 -0
  214. package/dist/viewer/registerSW.js +1 -0
  215. package/dist/viewer/sw.js +1 -0
  216. package/dist/viewer/workbox-9c191d2f.js +1 -0
  217. package/dist/viewerServer/context.d.ts +48 -0
  218. package/dist/viewerServer/context.js +60 -0
  219. package/dist/viewerServer/context.js.map +1 -0
  220. package/dist/viewerServer/evidence/classify.d.ts +59 -0
  221. package/dist/viewerServer/evidence/classify.js +124 -0
  222. package/dist/viewerServer/evidence/classify.js.map +1 -0
  223. package/dist/viewerServer/evidence/comparisonView.d.ts +28 -0
  224. package/dist/viewerServer/evidence/comparisonView.js +43 -0
  225. package/dist/viewerServer/evidence/comparisonView.js.map +1 -0
  226. package/dist/viewerServer/evidence/contextSourceView.d.ts +25 -0
  227. package/dist/viewerServer/evidence/contextSourceView.js +20 -0
  228. package/dist/viewerServer/evidence/contextSourceView.js.map +1 -0
  229. package/dist/viewerServer/evidence/discovery.d.ts +31 -0
  230. package/dist/viewerServer/evidence/discovery.js +78 -0
  231. package/dist/viewerServer/evidence/discovery.js.map +1 -0
  232. package/dist/viewerServer/evidence/evaluationView.d.ts +32 -0
  233. package/dist/viewerServer/evidence/evaluationView.js +50 -0
  234. package/dist/viewerServer/evidence/evaluationView.js.map +1 -0
  235. package/dist/viewerServer/evidence/handles.d.ts +21 -0
  236. package/dist/viewerServer/evidence/handles.js +43 -0
  237. package/dist/viewerServer/evidence/handles.js.map +1 -0
  238. package/dist/viewerServer/evidence/index.d.ts +41 -0
  239. package/dist/viewerServer/evidence/index.js +82 -0
  240. package/dist/viewerServer/evidence/index.js.map +1 -0
  241. package/dist/viewerServer/evidence/limits.d.ts +27 -0
  242. package/dist/viewerServer/evidence/limits.js +28 -0
  243. package/dist/viewerServer/evidence/limits.js.map +1 -0
  244. package/dist/viewerServer/evidence/linkedEvidence.d.ts +43 -0
  245. package/dist/viewerServer/evidence/linkedEvidence.js +151 -0
  246. package/dist/viewerServer/evidence/linkedEvidence.js.map +1 -0
  247. package/dist/viewerServer/evidence/mediaResolver.d.ts +16 -0
  248. package/dist/viewerServer/evidence/mediaResolver.js +85 -0
  249. package/dist/viewerServer/evidence/mediaResolver.js.map +1 -0
  250. package/dist/viewerServer/evidence/observationView.d.ts +29 -0
  251. package/dist/viewerServer/evidence/observationView.js +46 -0
  252. package/dist/viewerServer/evidence/observationView.js.map +1 -0
  253. package/dist/viewerServer/evidence/pathSafety.d.ts +11 -0
  254. package/dist/viewerServer/evidence/pathSafety.js +31 -0
  255. package/dist/viewerServer/evidence/pathSafety.js.map +1 -0
  256. package/dist/viewerServer/evidence/projection.d.ts +55 -0
  257. package/dist/viewerServer/evidence/projection.js +152 -0
  258. package/dist/viewerServer/evidence/projection.js.map +1 -0
  259. package/dist/viewerServer/evidence/referenceView.d.ts +133 -0
  260. package/dist/viewerServer/evidence/referenceView.js +169 -0
  261. package/dist/viewerServer/evidence/referenceView.js.map +1 -0
  262. package/dist/viewerServer/httpServer.d.ts +27 -0
  263. package/dist/viewerServer/httpServer.js +381 -0
  264. package/dist/viewerServer/httpServer.js.map +1 -0
  265. package/dist/viewerServer/openBrowser.d.ts +7 -0
  266. package/dist/viewerServer/openBrowser.js +32 -0
  267. package/dist/viewerServer/openBrowser.js.map +1 -0
  268. package/dist/viewerServer/port.d.ts +16 -0
  269. package/dist/viewerServer/port.js +19 -0
  270. package/dist/viewerServer/port.js.map +1 -0
  271. package/dist/viewerServer/viewerService.d.ts +62 -0
  272. package/dist/viewerServer/viewerService.js +88 -0
  273. package/dist/viewerServer/viewerService.js.map +1 -0
  274. package/docs/ARCHITECTURE.md +1286 -0
  275. package/docs/CI_CD.md +250 -0
  276. package/docs/COMMANDS.md +972 -0
  277. package/docs/CONTRACTS.md +1856 -0
  278. package/docs/CURRENT_STATE.md +1049 -0
  279. package/docs/DEVELOPMENT.md +202 -0
  280. package/docs/DOCUMENTATION_PRESERVATION_POLICY.md +50 -0
  281. package/docs/PROJECT_DESCRIPTION.md +2221 -0
  282. package/docs/PROJECT_MILESTONES.md +2526 -0
  283. package/docs/PROJECT_OVERVIEW.md +150 -0
  284. package/docs/QUICKSTART.md +83 -0
  285. package/docs/RELEASE.md +27 -0
  286. package/docs/ROADMAP.md +641 -0
  287. package/docs/SECURITY.md +218 -0
  288. package/docs/WORKFLOWS.md +642 -0
  289. package/docs/plans/v0.8-implementation-plan.md +655 -0
  290. package/docs/plans/v0.8.1-cli-usability-patch-plan.md +505 -0
  291. package/docs/reports/v0.7-bounded-fidelity-context-prompt7.md +243 -0
  292. package/docs/reports/v0.7-implementation-completeness-documentation-reconciliation.md +497 -0
  293. package/docs/reports/v0.7-pre-release-readiness.md +337 -0
  294. package/docs/reports/v0.7-reference-binding-prompt5.md +223 -0
  295. package/docs/reports/v0.7-reference-compatibility-prompt4.md +234 -0
  296. package/docs/reports/v0.7-reference-correction-workflow-prompt8.md +222 -0
  297. package/docs/reports/v0.7-reference-fidelity-prompt6.md +216 -0
  298. package/docs/reports/v0.7-reference-foundation-prompt1.md +151 -0
  299. package/docs/reports/v0.7-reference-regions-prompt2.md +195 -0
  300. package/docs/reports/v0.7-reference-requirements-prompt3.md +217 -0
  301. package/docs/reports/v0.7-release-prep.md +423 -0
  302. package/docs/reports/v0.8-binding-fidelity-interaction-batch6.md +279 -0
  303. package/docs/reports/v0.8-bounded-context-correlation-batch7.md +233 -0
  304. package/docs/reports/v0.8-comparison-contract-inspection-batch4.md +279 -0
  305. package/docs/reports/v0.8-evidence-index-readers-batch2.md +247 -0
  306. package/docs/reports/v0.8-implementation-completeness-documentation-reconciliation.md +741 -0
  307. package/docs/reports/v0.8-integrated-viewer-acceptance-batch8.md +128 -0
  308. package/docs/reports/v0.8-observation-svg-inspection-batch3.md +223 -0
  309. package/docs/reports/v0.8-prerelease-readiness-cross-platform-security-code-rot.md +687 -0
  310. package/docs/reports/v0.8-reference-candidate-inspection-batch5.md +232 -0
  311. package/docs/reports/v0.8-viewer-runtime-pwa-batch1.md +278 -0
  312. package/docs/reports/v0.8.1-check-orchestration-prompt2.md +69 -0
  313. package/docs/reports/v0.8.1-implementation-completeness-documentation-reconciliation.md +114 -0
  314. package/docs/reports/v0.8.1-prerelease-readiness-cross-platform-security-code-rot.md +170 -0
  315. package/docs/reports/v0.8.1-project-workflow-foundation-prompt1.md +66 -0
  316. package/package.json +58 -0
@@ -0,0 +1,1286 @@
1
+ # Architecture
2
+
3
+ ## v0.8.1 project workflow
4
+
5
+ Versioned project configuration (`1.0.0` compatibility plus current `1.1.0`
6
+ acceptance input), upward discovery, centralized managed paths, and the atomic
7
+ alias catalog live under `src/projectWorkflow`. Aliases select exact canonical
8
+ artifact directories; they never replace artifact identities.
9
+
10
+ `src/application/projectCheckService.ts` composes the existing observation,
11
+ comparison, contract-evaluation, reference-reader, explicit-binding,
12
+ compatibility, and fidelity owners. `src/projectWorkflow/checkAcceptance.ts`
13
+ owns contained acceptance-input resolution and shared file-wrapper parsing.
14
+ `checkResult.ts` owns the bounded ephemeral projection, not a persisted check
15
+ artifact or evaluation engine. Status precedence is `BLOCKED`, then `FAIL`,
16
+ then `PASS` when all configured executable dimensions pass, then
17
+ `REVIEW_REQUIRED` when comparison is the only evidence. Canonical observations,
18
+ comparisons, and contract evaluations remain persisted; reference fidelity and
19
+ the workflow result remain in memory/presentation.
20
+
21
+ ## Current package architecture
22
+
23
+ The current repository is one published TypeScript ESM package
24
+ (`@dailephd/my-frontend-observer@0.8.1`). The CLI remains
25
+ `my-frontend-observer`; the npm scope does not rename the product or artifact
26
+ identities.
27
+
28
+ - `src/cli.ts` is the real, thin public CLI parsing/dispatch/presentation
29
+ boundary for the current command surface (`observe`, `compare`,
30
+ `approve-baseline`, `save-change-contract`, `evaluate-contract`,
31
+ `import-reference`, `approve-reference`, `evaluate-reference-fidelity`);
32
+ argument parsing and output formatting only, per command - the commands do
33
+ not share domain semantics in the CLI. v0.6 added no new CLI command; v0.7
34
+ added the three external-reference commands.
35
+ - `src/index.ts` is the library entry point re-exporting the observer-owned
36
+ contracts/functions from every layer below, including the v0.6 bounded-agent-
37
+ context projection and runtime/static correlation surface, and the v0.7
38
+ external-reference/region/requirement/applicability/compatibility/binding/
39
+ fidelity/correction-workflow surface (`prepareReferenceCorrection`/
40
+ `reviewReferenceCorrectionAttempt` remain programmatic-only, with no CLI
41
+ command).
42
+ - `scripts/clean.mjs` safely removes only the project `dist/` directory.
43
+ - `scripts/check-docs.mjs` validates the canonical documentation foundation,
44
+ roadmap version presence, and the no-batches rule.
45
+ - TypeScript, ESLint, Vitest, and package configuration provide foundation
46
+ validation, now exercised by real product tests (`tests/unit/`,
47
+ `tests/browser/`).
48
+
49
+ Batch 1 added the observation domain/schema and safety-policy layer
50
+ (`src/domain/`, `src/request/`, `src/safety/`). Batch 2 added a real
51
+ Playwright Chromium browser adapter (`src/browser/`), a minimal application
52
+ seam invoking it (`src/application/`), and a deterministic browser
53
+ fixture/test boundary (`tests/fixtures/`, `tests/browser/`, run via
54
+ `npm run test:browser`). Batch 3 extended that single browser adapter with an
55
+ internal page/target measurement module (`src/browser/evidenceCapture.ts`)
56
+ that reads page and explicit-CSS-target evidence from the same live,
57
+ already-ready page used for the screenshot - no second browser/page is ever
58
+ opened, and Playwright objects still never leave `src/browser/`. Batch 4
59
+ added the artifact ownership boundary itself: `src/artifacts/artifactWriter.ts`
60
+ is the one canonical place that writes an observation to disk (temp
61
+ directory, then one atomic rename into `<outputLocation>/<observationId>/`),
62
+ and `src/application/observationPersistence.ts` assembles the frozen
63
+ `ObservationArtifact` from a browser-capture result before handing it to the
64
+ writer. The artifact layer has no Playwright dependency and is testable
65
+ without launching Chromium. Batch 5 completed the boundary chain: `src/cli.ts`
66
+ parses `observe` arguments (CLI-syntax errors only - e.g. malformed
67
+ `WIDTHxHEIGHT`), constructs a raw request, and hands it to the existing
68
+ Batch 1 `normalizeRequest`; on success it calls one new application-level use
69
+ case, `observe()` in `src/application/observationPersistence.ts`, which runs
70
+ the existing `runBrowserCapture` exactly once and, only on success, the
71
+ existing artifact writer exactly once, then returns a small observer-owned
72
+ `ApplicationObservationResult` (observation id, completion state, artifact
73
+ path, target/diagnostic counts) for the CLI to print. The CLI never imports
74
+ Playwright or the filesystem-write path directly. Batch 6 closed the
75
+ remaining real-Chromium coverage gap (a genuine navigation failure, distinct
76
+ from a readiness timeout or a pre-launch safety rejection) and validated the
77
+ packed npm tarball end to end in a clean consumer environment, independent
78
+ of the source checkout. At the end of the v0.1 implementation there was no
79
+ controlled-scroll or comparison behavior.
80
+
81
+ ## Current v0.2 architecture (released/current architecture)
82
+
83
+ v0.2 extends the same architecture rather than adding a parallel one.
84
+ `src/request/request.ts` now owns a canonical `{name, locators}` target
85
+ model (`TargetLocator`, six frozen kinds) in place of the old CSS-only
86
+ shape; the legacy `{name, selector}` input still normalizes into it. The one
87
+ existing browser-side target resolver/measurement module,
88
+ `src/browser/evidenceCapture.ts`, was extended - not replaced - to resolve
89
+ all six locator kinds against the live page through a single Playwright
90
+ `Locator` per attempt, honor the frozen ordered-fallback/ambiguity/
91
+ unavailable-no-fallback contract, and converge every kind on the same
92
+ measurement path (`captureResolvedTargetRecord`); it additionally computes
93
+ bounded semantic state, derived landmark identity, and configured-target-
94
+ only DOM containment from the same already-resolved elements in the same
95
+ capture pass - no second browser/page, no second resolution algorithm.
96
+ `src/domain/schema.ts` extends `TargetEvidenceRecord`/`TargetResolution`
97
+ additively for schema `1.1.0`, with matching structural validation in
98
+ `isValidObservationArtifact`. `src/cli.ts` gained one CLI/input-boundary-
99
+ only addition, `--targets-file`: it reads and validates only the JSON root
100
+ wrapper (via the already-imported `node:fs`, never `node:fs/promises`) and
101
+ hands the parsed `targets` value into the existing `RawObservationRequest`/
102
+ `normalizeRequest()` path unchanged - there is no second application
103
+ observation use case, and Playwright objects still never leave
104
+ `src/browser/`. The artifact writer, application observation use case, and
105
+ overall boundary chain (`CLI → normalizeRequest → observe() →
106
+ runBrowserCapture → artifact writer`) are unchanged from v0.1.
107
+
108
+ ## Current v0.3 architecture (released/current architecture)
109
+
110
+ v0.3 extends the same single-observation architecture again; it does not add
111
+ a second browser lifecycle, target resolver, or artifact path.
112
+ `src/request/request.ts` adds one optional `scrollScenario` field to
113
+ `NormalizedObservationRequest` (`ScrollScenario { action }`, exactly
114
+ `window-scroll-by` or `target-scroll-by`); `src/domain/schema.ts` adds the
115
+ matching bounded runtime evidence types (`ScrollRuntimeSnapshot`,
116
+ `ViewportRelationEvidence`, `OverflowEvidence`, `ScrollScenarioTransition`,
117
+ `ScrollOwnerInterpretation`) and structural validation for schema `1.2.0`
118
+ (additive over `1.1.0`). `src/domain/scrollEvidence.ts` holds the pure,
119
+ browser-independent derivations (viewport relation, actual overflow,
120
+ transitions, and `deriveScrollOwner`) so they are unit-testable without
121
+ Chromium. `src/browser/scrollCapture.ts` holds the one browser-side scenario
122
+ capture module: it reuses `evidenceCapture.ts#resolveConfiguredTargets` (now
123
+ exported) to resolve configured targets exactly once, captures an initial
124
+ `ScrollRuntimeSnapshot`, performs the one immediate scroll
125
+ (`window.scrollBy`/`element.scrollBy`, both `behavior: 'instant'`), waits
126
+ exactly two `requestAnimationFrame` cycles, and captures a final snapshot -
127
+ all inside `chromiumAdapter.ts#captureViewportInternal`'s existing single
128
+ navigate → ready → capture flow, strictly before the unchanged
129
+ screenshot/`capturePageEvidence`/`captureTargetEvidence` calls, so every
130
+ downstream capture (including a no-scenario request, which skips this block
131
+ entirely) describes only the final state. `src/cli.ts` gained one CLI/input-
132
+ boundary-only addition, `--scroll-scenario-file`: mirroring
133
+ `--targets-file`, it reads and validates only the file readability/JSON-
134
+ validity/non-array-object-root shape and hands the parsed value straight
135
+ into `RawObservationRequest.scrollScenario` - every scenario/action rule
136
+ (kind, deltas, target reference) stays owned by `normalizeRequest()`. There
137
+ is still one canonical `observe()` application use case and one artifact
138
+ writer; `scrollScenarioEvidence` is simply one more optional field on the
139
+ same `ObservationArtifact`.
140
+
141
+ ## Current v0.4 architecture (released/current architecture)
142
+
143
+ v0.4 adds one new downstream pipeline that consumes `ObservationArtifact`
144
+ values rather than producing them - it never adds a second browser lifecycle,
145
+ target resolver, or observation engine:
146
+
147
+ ```text
148
+ ObservationArtifact before ObservationArtifact after
149
+ \ /
150
+ `--------. .-------'
151
+ \ /
152
+ artifact reader (src/artifacts/artifactReader.ts)
153
+ ↓
154
+ comparability evaluation (src/domain/comparisonEngine.ts)
155
+ ↓
156
+ canonical relationship derivation, called for each side independently
157
+ (src/domain/relationships.ts#deriveLayoutRelationships)
158
+ ↓
159
+ canonical comparison derivation
160
+ (src/domain/comparisonEngine.ts#compareObservations)
161
+ ↓
162
+ ComparisonArtifact
163
+ ↓
164
+ atomic comparison writer (src/artifacts/comparisonArtifactWriter.ts)
165
+
166
+ CLI `compare`
167
+ ↓
168
+ application service only (src/application/comparisonService.ts)
169
+ ↓
170
+ [reader → domain comparison → writer, as above]
171
+ ```
172
+
173
+ `src/domain/relationships.ts` froze the layout-relationship contract and
174
+ implements the one canonical pure derivation,
175
+ `deriveLayoutRelationships(observation, options?)`: horizontal/vertical
176
+ order, area overlap, relative width, geometric fit, vertical sequencing,
177
+ page-width fit/exceeds, and a standalone `deriveTargetClipping(record)` -
178
+ all computed only from an already-captured `ObservationArtifact`'s own
179
+ `targetEvidence`/`pageEvidence`, never from a second browser query. DOM
180
+ containment is read directly from the existing v0.2 `TargetContainment`
181
+ evidence rather than re-derived, and stays a distinct concept from
182
+ geometric fit.
183
+
184
+ `src/domain/comparisonEngine.ts` implements the one canonical pure
185
+ before/after engine, `compareObservations(before, after, config?)`:
186
+ validates both source artifacts, evaluates comparability *before* any
187
+ rendered difference is calculated, calls `deriveLayoutRelationships` once
188
+ per side with the same tolerance, and derives target/page differences and
189
+ relationship changes. `src/artifacts/comparisonArtifactWriter.ts` persists
190
+ the result atomically (sibling temp directory, then one rename) as
191
+ `<outputLocation>/<comparisonId>/manifest.json` only - no screenshot is
192
+ copied; the manifest's `before`/`after` references point back to the
193
+ source observations' own `screenshot.path`. `src/application/
194
+ comparisonService.ts` is the one application-layer seam: `compareAndPersist`
195
+ takes two in-memory `ObservationArtifact`s and does exactly one comparison
196
+ plus exactly one persist; `compareAndPersistFromArtifactRoots` is a thin
197
+ wrapper that additionally reads both sides from disk via the existing
198
+ `src/artifacts/artifactReader.ts#readObservationArtifact` reader (itself
199
+ just a `manifest.json` parse plus the same `isValidObservationArtifact`
200
+ structural gate the writer uses).
201
+
202
+ `src/cli.ts` gained one new top-level command, `compare`
203
+ (`--before`/`--after`/`--output`/`--config-file`), implemented with the same
204
+ thin-CLI-boundary discipline as `observe`: `parseCompareArgs` handles only
205
+ argument shape/duplication, an optional `loadComparisonConfigFile` reads and
206
+ validates only file readability/JSON-validity/non-array-object-root (exactly
207
+ like `--targets-file`/`--scroll-scenario-file`), and the command body calls
208
+ `compareAndPersistFromArtifactRoots` exactly once. **The CLI's comparison
209
+ path never launches Chromium** - `src/cli.ts` imports nothing from
210
+ `src/browser/` or `src/artifacts/` (it only reaches persistence and artifact
211
+ reading indirectly, through the application-layer seam above), matching the
212
+ same import-boundary discipline already enforced for `observe`.
213
+
214
+ ## Current v0.5 architecture (released/current architecture)
215
+
216
+ v0.5 adds one new downstream layer that consumes `ComparisonArtifact` values
217
+ (plus the source `ObservationArtifact` pair) rather than producing them - no
218
+ new browser lifecycle, target resolver, or comparison engine is added:
219
+
220
+ ```text
221
+ ObservationArtifact before + after
222
+ ↓
223
+ existing v0.4 comparison/relationship pipeline (unchanged)
224
+ ↓
225
+ ComparisonArtifact
226
+ ↓ PersistentBaselineContract
227
+ | +
228
+ `------------------------→ PerChangeContract
229
+ ↓
230
+ canonical contract evaluation
231
+ (src/domain/frontendContractEvaluation.ts#evaluateFrontendContract)
232
+ ↓
233
+ clause results + unexpected changes + overall PASS/FAIL
234
+ ```
235
+
236
+ `src/domain/frontendContracts.ts` froze the contract/change-scope type,
237
+ constant, and structural-validator vocabulary (Batch 1); `src/domain/
238
+ frontendContractIdentity.ts` froze deterministic contract/baseline/clause
239
+ identity in the same canonicalize+sha256(+opaque-nonce) style as `src/domain/
240
+ comparisonIdentity.ts`. `src/domain/frontendContractEvaluation.ts#evaluateFrontendContract`
241
+ (Batch 2) is the one canonical pure evaluation entry point: it validates its
242
+ five inputs (before/after `ObservationArtifact`, `ComparisonArtifact`,
243
+ `PersistentBaselineContract`, `PerChangeContract`) are structurally coherent
244
+ and mutually consistent, calculates the active baseline clause set after
245
+ explicit supersession, detects bounded structural conflicts, evaluates every
246
+ active clause via the frozen 15-primitive vocabulary against the existing
247
+ `ComparisonArtifact`/`ObservationArtifact` evidence (never re-deriving
248
+ clipping/relationship/scroll-owner facts), classifies unaccounted-for
249
+ `ComparisonArtifact.differences` entries as `unexpected`, and derives one
250
+ overall `PASS`/`FAIL` verdict. It performs no I/O, launches no browser, and
251
+ persists nothing - `src/domain/frontendContractEvaluation.ts` itself remains
252
+ untouched by the persistence layer below (Batch 3).
253
+
254
+ Batch 3 adds the persistence/application boundary around this frozen domain,
255
+ without redefining it:
256
+
257
+ ```text
258
+ ComparisonArtifact (read via new src/artifacts/comparisonArtifactReader.ts)
259
+ +
260
+ PersistentBaselineContract / PerChangeContract
261
+ (read/written via src/artifacts/frontendContractArtifactReader.ts / ...Writer.ts)
262
+ ↓
263
+ src/application/frontendContractEvaluationService.ts#evaluateAndPersist
264
+ ↓
265
+ evaluateFrontendContract() [called exactly once, unmodified]
266
+ ↓
267
+ src/domain/frontendContractEvaluationArtifact.ts
268
+ (minimal additive persisted envelope around the frozen result)
269
+ ↓
270
+ src/artifacts/frontendContractEvaluationArtifactWriter.ts
271
+ (atomic write, exactly once on a structurally constructible result)
272
+ ```
273
+
274
+ `evaluateAndPersistFromArtifactRoots` is the CLI-facing wrapper, reading
275
+ before/after observations through the existing `readObservationArtifact` (no
276
+ second observation reader), the comparison and both contract classes
277
+ through the new readers, then delegating to `evaluateAndPersist` exactly
278
+ once - mirroring `application/comparisonService.ts#compareAndPersistFromArtifactRoots`'s
279
+ own thin-wrapper shape.
280
+
281
+ Batch 4 exposes this through the same thin-CLI boundary already established
282
+ by `observe`/`compare`:
283
+
284
+ ```text
285
+ src/cli.ts (argument parsing, JSON-file-shape checks, help/output formatting,
286
+ exit-code selection only)
287
+ ↓
288
+ src/application/frontendContractPersistenceService.ts#approveAndPersistBaseline
289
+ src/application/frontendContractPersistenceService.ts#persistPerChangeContract
290
+ src/application/frontendContractEvaluationService.ts#evaluateAndPersistFromArtifactRoots
291
+ ↓
292
+ domain validators (isValidPersistentBaselineContract / isValidPerChangeContract)
293
+ + artifact readers/writers (Batch 3)
294
+ + evaluateFrontendContract() (Batch 2, unmodified)
295
+ ```
296
+
297
+ Three new top-level commands - `approve-baseline`, `save-change-contract`,
298
+ `evaluate-contract` - each parse only CLI-syntax concerns (duplicate/missing
299
+ flags, JSON-file readability/parseability/object-root shape) and delegate to
300
+ exactly one application-layer call; `src/cli.ts` imports no artifact writer/
301
+ reader module and no browser code, matching the existing `observe`/`compare`
302
+ import-boundary discipline exactly. `approveAndPersistBaseline` adds the one
303
+ new coherence check Batch 3 did not need: verifying a baseline contract's
304
+ frozen `sourceObservation` reference actually matches the supplied
305
+ observation artifact before persisting - explicit approval only, never
306
+ inferred from a `compare` or `evaluate-contract` result. `--enforce` on
307
+ `evaluate-contract` is applied only after evaluation and persistence have
308
+ already completed; it selects the process exit status for an already-final
309
+ `FAIL` result and is never part of any identity or persisted field.
310
+
311
+ ## Current v0.6 architecture (released as `0.6.0`)
312
+
313
+ v0.6 adds one new downstream, read-only layer that consumes existing v0.1-v0.5
314
+ evidence (`ObservationArtifact`, `ComparisonArtifact`,
315
+ `PersistentBaselineContract`/`PerChangeContract`, and evaluation results)
316
+ plus caller-supplied bounded static candidate evidence - it adds no new
317
+ browser lifecycle, target resolver, observation/comparison/contract engine,
318
+ or persisted artifact family:
319
+
320
+ ```text
321
+ ObservationArtifact(s) + ComparisonArtifact + contract/evaluation evidence
322
+ ↓
323
+ src/domain/boundedAgentContextProjection.ts#projectBoundedAgentContext
324
+ ↓
325
+ BoundedRuntimeTargetProjection
326
+ (page/viewport identity, stable targets, geometry, runtime behavior,
327
+ relationships, before/after differences, contract results,
328
+ requested/expected-dependent/protected/preserved scope reused verbatim
329
+ from src/domain/frontendContracts.ts, diagnostics, artifact/screenshot
330
+ references, provenance, adequacy, omission, truncation)
331
+ ↓
332
+ src/domain/boundedAgentContextCorrelation.ts
333
+ #deriveRuntimeStaticCorrelations / #attachRuntimeStaticCorrelations
334
+ ↓
335
+ RuntimeStaticCorrelation[] (correlated / ambiguous / unavailable,
336
+ competing candidates preserved verbatim - never collapsed to one owner)
337
+ ↓
338
+ src/index.ts (public export/correlation boundary only)
339
+ ```
340
+
341
+ `src/domain/boundedAgentContext.ts` freezes the bounded-projection and
342
+ correlation type/constant vocabulary (`Adequacy`, `ADEQUACY_REASON_CODES`,
343
+ `OmissionRecord`, `TruncationRecord`, `BOUNDED_AGENT_CONTEXT_ARTIFACT_KIND`,
344
+ schema `1.0.0`). `src/domain/boundedAgentContextIdentity.ts` derives a
345
+ deterministic logical identity distinct from a fresh per-execution instance
346
+ identity, in the same canonicalize+hash style as
347
+ `comparisonIdentity.ts`/`frontendContractIdentity.ts`.
348
+ `boundedAgentContextProjection.ts` performs no browser I/O and re-derives
349
+ nothing already owned upstream - it reads already-captured artifacts and
350
+ reuses the existing v0.4 relationship/comparison evidence and v0.5
351
+ change-scope clause types directly. `boundedAgentContextCorrelation.ts`
352
+ accepts only plain, caller-supplied candidate static-evidence records; it has
353
+ **no** dependency on `@dailephd/my-dev-kit`, since the audit that preceded
354
+ implementation found no generic static-side retrieval capability actually
355
+ missing (see `docs/ROADMAP.md` v0.6 "Dependency direction" - the "determine
356
+ whether my-dev-kit requires a static-side change" step concluded no).
357
+ Runtime target identity is carried through this module verbatim; the module
358
+ never adds a `sourceOwner`/`causedBy`-shaped field, preserving the
359
+ architectural rule that runtime identity never silently becomes source
360
+ ownership.
361
+
362
+ This layer is a programmatic export/correlation boundary only: `src/index.ts`
363
+ re-exports its full type/function surface, but there is no new CLI command,
364
+ no `src/artifacts/boundedAgentContext*` writer/reader, and no orchestrator or
365
+ lab code in this repository - those remain separate sibling-repository
366
+ responsibilities per the Milestone 6 ownership split in
367
+ `docs/PROJECT_MILESTONES.md`.
368
+
369
+ ## v0.7 (released as `0.7.0`), v0.8 (released as `0.8.0`), and planned v0.9–v0.10 reference-evidence architecture constraints
370
+
371
+ The external visual-reference capability (v0.7) is released as package
372
+ version `0.7.0` - see "v0.7 Prompt 1" through "v0.7 Prompt 8" below for the
373
+ actual architecture, and `docs/CURRENT_STATE.md` for release state. It
374
+ extends the existing v0.1-v0.6 evidence architecture rather than becoming a
375
+ UI-only feature or a parallel visual-comparison stack. v0.8 (interactive
376
+ viewer) is released as package version `0.8.0`. v0.9 (structured visual
377
+ annotation) and v0.10 (full graphical human-LLM workflow) remain future and
378
+ unimplemented; the constraints below apply to that still-future work.
379
+
380
+ The evidence domains remain distinct:
381
+
382
+ ```text
383
+ runtime observation A ↔ runtime observation B
384
+ → existing before/after comparison
385
+
386
+ approved baseline/per-change contract ↔ candidate runtime evidence
387
+ → existing canonical contract evaluation
388
+
389
+ external visual reference ↔ candidate runtime evidence
390
+ → reference applicability + structured fidelity evaluation (v0.7,
391
+ released as `0.7.0` - see "v0.7 Prompt 4" and "v0.7 Prompt 6" below)
392
+ ```
393
+
394
+ An external reference is not an `ObservationArtifact`, and a reference region
395
+ is not a runtime target. The released v0.7 implementation preserves explicit
396
+ identity and provenance for the reference image/version, reference regions,
397
+ applicable viewport/theme/application state, authored requirements, tolerances,
398
+ approval/supersession state, and reference-region/runtime-target bindings.
399
+ Bindings are explicit and evaluate to `bound`, `ambiguous`, or `unavailable`;
400
+ they never silently become source ownership.
401
+
402
+ The non-UI reference model and structured reference-vs-candidate evaluation
403
+ were established in v0.7 before v0.8. v0.8 may render side-by-side images,
404
+ overlays, measurements, bindings, provenance, and fidelity results, but it must
405
+ consume those existing engines and must not invent a second reference model or
406
+ evaluation engine. v0.9 may author annotations against either runtime
407
+ screenshots or external references, but both coordinate/identity domains remain
408
+ explicit and feed the same canonical contract/change-scope semantics. v0.10
409
+ combines both visual entry modes with the existing correction loop.
410
+
411
+ Where a reference requirement is executable, it uses the existing v0.5
412
+ requested/expected-dependent/protected/preserved semantics. Informational or
413
+ unassessed reference evidence remains non-executable until explicitly selected.
414
+ There is no reference-only PASS/FAIL taxonomy.
415
+
416
+ The released reference evaluation reuses existing relationship/value
417
+ conventions where they mean the same thing and adds distinct reference-owned
418
+ units only where the image evidence requires them. v0.7 does not use pixel or
419
+ image-region similarity as a success mechanism; a later bounded similarity
420
+ feature may supplement structured evidence if separately designed, but it must
421
+ not replace browser-authoritative runtime geometry, canonical contract
422
+ evaluation, or explicit relationship evidence.
423
+
424
+ Candidate rendering still uses the one existing Chromium observation engine.
425
+ The observer remains non-mutating. `my-dev-kit` remains the static/source
426
+ evidence owner, and the v0.6 correlation/bounded-context boundary remains the
427
+ route for attaching relevant source evidence to reference-driven correction
428
+ packets. Heavy reference image bytes are referenced rather than copied into
429
+ every downstream context/evaluation record.
430
+
431
+ Theme, application-state, viewport, and authenticated-state applicability are
432
+ checked before reference fidelity is interpreted through the released v0.7
433
+ compatibility path, which reuses v0.4 comparability conventions. If reference
434
+ and candidate do not represent compatible intended states, the result is
435
+ explicitly incompatible/incomparable rather than a fabricated visual difference
436
+ set. v0.8, released as package version `0.8.0`, displays this result exactly
437
+ as required rather than redefining the state model - see "v0.8 Batch 5"
438
+ below.
439
+
440
+ The constraints above were carried out by the actual v0.7 implementation
441
+ described in "v0.7 Prompt 1" through "v0.7 Prompt 8" below: explicit
442
+ identity/provenance, applicability/compatibility, region-to-target bindings,
443
+ requested/expected-dependent/protected/preserved reuse, and the non-mutating
444
+ Chromium/correlation boundaries all remain as constrained here. v0.8 (see
445
+ "v0.8 Batch 1" through "v0.8 Batch 8" below) applied them unchanged; they
446
+ continue to apply unchanged to the still-future v0.9-v0.10 work.
447
+
448
+ The exact public artifact names, schema versions, persistence layout, supported
449
+ image formats, coordinate model, requirement/tolerance primitives, and fidelity
450
+ behavior were frozen by the actual v0.7 implementation below, not by earlier
451
+ planning language. Style/asset-similarity mechanisms remain future unless
452
+ separately implemented.
453
+
454
+ ## v0.8 Batch 1 (Viewer runtime and PWA foundation) — implemented
455
+
456
+ Batch 1 of the frozen `docs/plans/v0.8-implementation-plan.md` establishes
457
+ only the viewer runtime/build shell — no evidence indexing, artifact reading,
458
+ or evidence UI. It does not implement any of the v0.7-derived reference/
459
+ fidelity/binding display constraints above; those remain future work for
460
+ later v0.8 batches, which must consume this runtime boundary rather than
461
+ redefine it.
462
+
463
+ ```text
464
+ my-frontend-observer view [--root <evidence-root>]
465
+ |
466
+ v
467
+ thin CLI dispatch (src/cli.ts: parseViewArgs/runViewCommand)
468
+ |
469
+ v
470
+ viewer application seam (src/viewerServer/viewerService.ts: startViewer)
471
+ |
472
+ v
473
+ Node local server, loopback-only (src/viewerServer/httpServer.ts)
474
+ |
475
+ +---------------------+----------------------+
476
+ | |
477
+ v v
478
+ built viewer assets (dist/viewer) GET /api/status
479
+ (React + TypeScript + Vite PWA) (session/root identity only)
480
+ ```
481
+
482
+ - **Node server boundary** (`src/viewerServer/`): binds only to `127.0.0.1`
483
+ on one fixed default port (`4319`, `src/viewerServer/port.ts`); serves only
484
+ the built viewer assets plus the one read-only status endpoint; resolves
485
+ every requested path against the built assets root and fails closed on any
486
+ path that would resolve outside it; accepts no write HTTP methods; performs
487
+ no artifact reading, browser observation, or mutation. `--root` is
488
+ validated operationally (exists, is a directory) and exposed only as an
489
+ opaque status string — it is never interpreted as Observer evidence in this
490
+ batch.
491
+ - **Browser application** (`viewer/`): a React + TypeScript + Vite app, built
492
+ independently of `src/` via `viewer/tsconfig.json` and `viewer/vite.config.ts`,
493
+ output to `dist/viewer` inside the existing package `dist` allowlist (no
494
+ second npm package). Renders an honest foundation shell only — product
495
+ identity, live session status via `/api/status`, and placeholder
496
+ navigation/workspace/details regions — never fabricated evidence.
497
+ - **PWA**: `vite-plugin-pwa` generates a web app manifest (`standalone`
498
+ display, stable `start_url`/`scope`, installability icons) and a service
499
+ worker that precaches only the built application shell. It declares no
500
+ `runtimeCaching` rules, so future evidence/media/API routes remain
501
+ network/server-backed rather than silently served as stale cached truth
502
+ when the local server is unavailable (enforced by
503
+ `tests/unit/viewerPwaBuild.test.ts`, which asserts on the actual built
504
+ `sw.js`, not a hand-written approximation). An install affordance appears
505
+ only when the browser actually fires `beforeinstallprompt`; its absence is
506
+ shown honestly, never as a disabled-looking fake control.
507
+ - **CLI**: `view [--root <evidence-root>] [--port <n>] [--no-open]` remains a
508
+ thin dispatcher — it parses syntax, delegates once to `startViewer`, prints
509
+ the URL/root, and optionally best-effort opens the system browser (failure
510
+ there is never fatal to server startup). All v0.1-v0.7 commands are
511
+ unchanged.
512
+
513
+ This batch introduces no second observer, relationship engine, comparison
514
+ engine, contract engine, reference model, or bounded-context builder — there
515
+ is nothing yet for the viewer to consume beyond its own runtime identity.
516
+
517
+ ## v0.8 Batch 2 (Evidence indexing, canonical readers, and lazy data boundary) — implemented
518
+
519
+ Batch 2 adds the safe, read-only data boundary between existing on-disk
520
+ Observer evidence and the Batch 1 viewer runtime, entirely under
521
+ `src/viewerServer/evidence/`. It introduces no new persisted artifact family,
522
+ no schema migration, and no second validator — every recognized candidate is
523
+ decided exclusively by the existing canonical reader/validator for its
524
+ family (`src/artifacts/*Reader.ts`).
525
+
526
+ ```text
527
+ GET /api/index bounded discovery + classification -> metadata only
528
+ GET /api/artifacts/<handle> one canonical-reader read, on demand -> full projection
529
+ GET /api/media/<handle>/<role> one resolved, contained media file, streamed on demand
530
+ ```
531
+
532
+ - **Discovery** (`evidence/discovery.ts`): a bounded, deterministic walk
533
+ beneath `--root` that opens only files literally named `manifest.json` (the
534
+ one filename every current persisted family uses) — no other file is ever
535
+ read or classified, so arbitrary files can never become evidence merely by
536
+ existing under the root. Directory entries that are symlinks/junctions are
537
+ never followed. Bounds (`evidence/limits.ts`): traversal depth 6,
538
+ directories visited 2000, candidate manifests 1000, index records 500,
539
+ manifest read size 2,000,000 bytes — chosen after inspecting that every
540
+ current writer produces a shallow `<outputLocation>/<id>/manifest.json`
541
+ shape (see `docs/CONTRACTS.md`), not a deep tree.
542
+ - **Classification is not validation** (`evidence/classify.ts`): peeks only
543
+ `artifactKind`/`schemaVersion` (plus, where the shared kind is ambiguous,
544
+ tries each existing reader/validator in turn — e.g. baseline vs. per-change
545
+ contract) to decide *which* existing canonical reader to call; the reader's
546
+ own structural validator remains the sole authority. Six honest, mutually
547
+ exclusive states: `supported`, `unsupported-version`, `invalid-structure`,
548
+ `unrecognized-kind`, `malformed-json`, `unreadable` — never collapsed into
549
+ one boolean, and never conflated with an artifact's own `completion`
550
+ state (passed through separately, only for the families that carry one:
551
+ observation and external-reference). A manifest declaring the
552
+ `bounded-agent-context` kind is classified `unrecognized-kind`: v0.6/v0.7
553
+ never added a disk writer/reader for that family (confirmed via direct
554
+ source inspection and `@dailephd/my-dev-kit` search), so Batch 2 does not
555
+ invent persistence-shaped handling for it.
556
+ - **Viewer handles** (`evidence/handles.ts`, `evidence/pathSafety.ts`): a
557
+ handle is a family-prefixed, percent-encoded, root-relative directory path
558
+ — never a raw filesystem path accepted from the browser. Every route that
559
+ accepts a handle re-decodes and re-resolves it against the evidence root,
560
+ re-checks containment, and re-classifies that one candidate before serving
561
+ anything; a handle whose backing directory or manifest no longer matches
562
+ what was indexed fails closed as unknown, never stale.
563
+ - **Ephemeral projection** (`evidence/projection.ts`): `EvidenceMetadataRecord`
564
+ (bounded, `/api/index`-shaped: handle, family, support state, logical id,
565
+ schema version, completion where applicable, media availability summary,
566
+ a handful of related ids) and `EvidenceArtifactDetail` (the already-
567
+ validated domain object, wrapped with `handle`/`family` — no new evidence
568
+ schema, no recomputation, no persistence).
569
+ - **Media resolution** (`evidence/mediaResolver.ts`): `screenshot` (observation),
570
+ `image` (imported external reference), and `source-image` (approved
571
+ external reference) are the only three recognized roles. An approved
572
+ reference's image is never assumed to live in the approved artifact's own
573
+ directory — its `sourceReference.referenceId` is looked up against the
574
+ current index to find the actual owning imported artifact
575
+ (`evidence/index.ts#findImportedReferenceDir`), exactly matching the v0.7
576
+ reference-ownership contract in `docs/CONTRACTS.md`. A genuinely missing
577
+ screenshot/image/source artifact is reported as 404, never fabricated.
578
+ - **PWA cache boundary preserved, not re-verified from scratch**: every new
579
+ route lives under `/api/`, already covered by Batch 1's
580
+ `denylist:[/^\/api\//]` navigation-fallback rule — no new `runtimeCaching`
581
+ entry was needed or added (`tests/unit/viewerPwaBuild.test.ts` asserts this
582
+ against the real built `sw.js`).
583
+ - **Minimal UI** (`viewer/src/hooks/useEvidenceIndex.ts`,
584
+ `useArtifactDetail.ts`, `components/EvidenceList.tsx`,
585
+ `ArtifactPreview.tsx`): a bounded evidence list (metadata-first) plus
586
+ on-demand full-artifact loading on selection, with every support state
587
+ shown honestly. No screenshot rendering, SVG overlay, or comparison/
588
+ contract/reference visualization exists yet — that begins in Batch 3.
589
+
590
+ ## v0.8 Batch 3 (Runtime observation inspection and SVG overlays) — implemented
591
+
592
+ Batch 3 makes one already-supported `ObservationArtifact` (Batch 2's data
593
+ boundary, unchanged) genuinely understandable: a real screenshot, SVG target
594
+ overlays in the observation's own canonical coordinate domain, target
595
+ selection/inspection, and canonical layout-relationship display. No second
596
+ relationship engine, no client-side evidence derivation, no new persisted
597
+ artifact.
598
+
599
+ **Coordinate audit (the load-bearing decision for this batch)**: target
600
+ geometry (`TargetGeometry.x/y/width/height`) is captured via
601
+ `el.getBoundingClientRect()` (`src/browser/evidenceCapture.ts`) - CSS pixels,
602
+ relative to the current viewport's top-left, at the same live page state the
603
+ screenshot is taken from. The screenshot itself is `page.screenshot({type:
604
+ 'png'})` (`src/browser/chromiumAdapter.ts`), Playwright's default
605
+ (non-fullPage) mode, against a browser context created with no
606
+ `deviceScaleFactor` override (`browser.newContext({viewport})`) - so it
607
+ defaults to `1`, meaning every observation this repository can currently
608
+ produce has a screenshot whose raw PNG pixel dimensions equal
609
+ `requestConfig.viewport.width × requestConfig.viewport.height` exactly (1
610
+ CSS pixel = 1 PNG pixel). `requestConfig.viewport` (a required, strongly-typed
611
+ field on every valid `ObservationArtifact`, distinct from the loosely-typed
612
+ `pageEvidence` bag) is therefore the canonical, always-present source for the
613
+ SVG display frame.
614
+
615
+ **SVG coordinate model** (`viewer/src/components/TargetOverlaySvg.tsx`): the
616
+ `<svg>` root's `viewBox` is `0 0 {requestConfig.viewport.width}
617
+ {requestConfig.viewport.height}` - the exact frame `getBoundingClientRect()`
618
+ already used. The screenshot loads into a `<image>` element filling that same
619
+ viewBox (`preserveAspectRatio="none"`, since the two frames are already
620
+ pixel-identical). Target `<rect>` elements use `geometry.x/y/width/height`
621
+ completely unchanged - no rounding, no `devicePixelRatio` multiplication, no
622
+ clamping; geometry lying partly outside the viewBox is drawn at its real
623
+ coordinates and clipped only by the SVG root's default `overflow: hidden`
624
+ (a display-only effect, verified never to touch the underlying evidence
625
+ value - `tests/unit/observationCoordinateMapping.test.ts`). This is robust
626
+ even if a future capture path used a different `deviceScaleFactor`: the
627
+ `<image>`/viewBox scaling is presentation-only browser behavior, never a
628
+ manual pixel calculation in this codebase. `devicePixelRatio` (captured as
629
+ `pageEvidence.devicePixelRatio`) is shown as informational observation-level
630
+ evidence only and is never consulted for any geometry calculation.
631
+
632
+ **Server additions** (`src/viewerServer/evidence/observationView.ts`, one new
633
+ route `GET /api/observations/<handle>/relationships`): the only new
634
+ server-side computation this batch adds is one thin, defense-in-depth-wrapped
635
+ call to the existing canonical, pure `deriveLayoutRelationships` (`src/domain/
636
+ relationships.ts`) - never a second relationship predicate implementation.
637
+ Mirrors the exact handle-decode → contained-dir-resolve → re-classify
638
+ discipline `loadArtifactByHandle`/`resolveMedia` already established in
639
+ Batch 2; a handle for a non-`observation` family or a non-`supported`
640
+ candidate is rejected (`409`) before derivation is even attempted. The
641
+ existing `GET /api/artifacts/<handle>` (full `ObservationArtifact`) and
642
+ `GET /api/media/<handle>/screenshot` (Batch 2, unchanged) remain the only
643
+ other data sources the observation workspace uses - no new artifact
644
+ projection endpoint was needed, since the full validated domain object
645
+ already contains everything the target/observation inspector displays.
646
+
647
+ **Client-side presentation only** (`viewer/src/observation/targetOrder.ts`,
648
+ `viewer/src/components/{ObservationWorkspace,TargetList,TargetOverlaySvg,
649
+ ObservationInspector,EvidenceFieldView}.tsx`): React selects, orders
650
+ (by the observation's own authored `requestConfig.targets` order, not
651
+ incidental object-key order), and formats already-fetched canonical fields.
652
+ It never resolves targets, computes relationships, or derives
653
+ visibility/overflow/scroll-owner semantics - `deriveLayoutRelationships`
654
+ runs exclusively on the server (above). An unresolved target (`not-found`/
655
+ `ambiguous`/`unavailable`) is selectable from the target list and shown
656
+ honestly in the inspector, but never receives a fabricated `<rect>` -
657
+ `orderedTargets()`'s `hasGeometry` flag is `true` only when
658
+ `geometry.state` is `'available'` or `'partial'`.
659
+
660
+ **Selection**: viewer presentation state only (React `useState`, reset on
661
+ observation change), never persisted, synchronized in both directions
662
+ between the target list, the SVG `<rect>` (`role="button"`, keyboard-
663
+ operable), and the inspector via the target's existing stable `name`.
664
+
665
+ **Overlay toggles**: geometry, labels (disabled when geometry is off), and
666
+ relationships - each independently toggleable and purely presentational
667
+ (hiding/showing already-rendered elements), never altering the underlying
668
+ evidence or the fetched artifact/graph.
669
+
670
+ **PWA cache boundary preserved**: the new `/api/observations/*` route lives
671
+ under the same `/api/` prefix Batch 1's `navigateFallbackDenylist` already
672
+ denylists - no service-worker configuration change was needed
673
+ (`tests/unit/viewerPwaBuild.test.ts` asserts this against the real built
674
+ `sw.js`).
675
+
676
+ ## v0.8 Batch 4 (Before/after comparison and contract/change-scope inspection) — implemented
677
+
678
+ Batch 4 exposes the existing v0.4 `ComparisonArtifact` and v0.5
679
+ `FrontendContractEvaluationArtifact` through the viewer, entirely under
680
+ `src/viewerServer/evidence/{linkedEvidence,comparisonView,evaluationView}.ts`
681
+ and `viewer/src/components/{ComparisonWorkspace,EvaluationWorkspace,
682
+ ComparisonObservationPane,ClauseResultRow}.tsx`. **`compareObservations` and
683
+ `evaluateFrontendContract` are never called anywhere in this batch** - every
684
+ displayed comparison/evaluation field is read unchanged from its persisted
685
+ artifact via the existing Batch 2 `GET /api/artifacts/<handle>`.
686
+
687
+ - **Exact linked-evidence resolution** (`evidence/linkedEvidence.ts`): given
688
+ a `ComparisonSourceObservationReference`/`FrontendContractObservationReference`,
689
+ a `comparisonId`+`comparisonRequestId` pair, or a `baselineId`/`contractId`,
690
+ resolves the matching indexed artifact by **exact identity only**
691
+ (`observationId`+`requestId`+`producer.version`+`observationSchemaVersion`
692
+ for observations; the id fields themselves for comparisons/contracts) -
693
+ never by folder name, screenshot filename, URL, target-set, or geometry
694
+ similarity. Zero matches → `missing`; two or more exact matches →
695
+ `ambiguous` (never silently picks one). Mirrors the exact bounded-walk
696
+ pattern Batch 2's `findImportedReferenceDir` already established.
697
+ - **Two additive, read-only routes**: `GET /api/comparisons/<handle>/view`
698
+ (resolves the comparison's `before`/`after`) and
699
+ `GET /api/evaluations/<handle>/view` (resolves `comparison`, `baseline`,
700
+ `change`, `before`, `after`) - both under `/api/`, both GET/HEAD-only, both
701
+ returning only resolved-handle-or-missing-or-ambiguous status, never a
702
+ duplicated copy of the linked artifact's own payload (the browser fetches
703
+ that separately through the existing `GET /api/artifacts/<handle>`, reusing
704
+ Batch 2's on-demand-loading contract exactly).
705
+ - **Before/after visual reuse, not reimplementation**: `ComparisonObservationPane.tsx`
706
+ is built entirely from Batch 3's existing lower-level primitives
707
+ (`useArtifactDetail`, `orderedTargets`, `TargetOverlaySvg`) - no second
708
+ screenshot-loading, coordinate-transform, or geometry-rendering code
709
+ exists. The comparison's own persisted `relationshipsBefore`/
710
+ `relationshipsAfter` are passed directly into `TargetOverlaySvg`'s existing
711
+ `relationships` prop - never recomputed via `deriveLayoutRelationships`.
712
+ `TargetOverlaySvg` gained one small additive, optional `highlightNames`
713
+ prop (alongside the existing single-select `selected`) so a
714
+ relationship-subject difference or a two-target contract primitive
715
+ (`targets-do-not-overlap`, `target-fits-inside`, etc.) can emphasize both
716
+ named targets at once without changing Batch 3's existing single-select
717
+ interaction contract.
718
+ - **Difference/relationship-change/clause presentation is evidence display,
719
+ not re-derivation**: `ComparisonWorkspace.tsx` renders `differences`,
720
+ `relationshipChanges`, `configurationChanges` (kept visually distinct from
721
+ appeared/disappeared runtime differences), and `expectedDependencyEvidence`
722
+ exactly as persisted, labeling dependency outcomes as explicit non-causal
723
+ evidence. `comparability` (comparable/comparable-with-warnings/incomparable
724
+ plus blocking/warning/unassessed reasons) is shown honestly; an
725
+ `incomparable` result is visually unmistakable
726
+ (`.comparability-banner--incomparable`).
727
+ - **Clause joining by exact `clauseId` only** (`EvaluationWorkspace.tsx`):
728
+ baseline clauses (from the linked `PersistentBaselineContract`) and
729
+ per-change clauses (from the linked `PerChangeContract`) are joined to the
730
+ evaluation's `clauseResults` by exact id - never by target/primitive-shape/
731
+ category/position. A `clauseId` absent from both loaded contracts is shown
732
+ as an honest "unresolved clause definition", never fabricated. Baseline
733
+ clause active/superseded status comes exclusively from the evaluation
734
+ artifact's own `activeBaselineClauseIds`/`supersededBaselineClauseIds` -
735
+ never recomputed from clause overlap. `pass`/`fail`/`unavailable`/
736
+ `conflict` are preserved exactly (never collapsed to a boolean);
737
+ `unavailable` shows its reason, `conflict` shows its reason and
738
+ `conflictingClauseIds`.
739
+ - **Overall verdict is authoritative and unmistakable**: `overallVerdict`
740
+ (`PASS`/`FAIL`) is rendered directly from the artifact, in a large
741
+ `.overall-verdict--PASS`/`.overall-verdict--FAIL` banner - the UI never
742
+ computes it from visible rows. The required safety case (a `requested`
743
+ clause `pass` alongside a `protected`/`preserved` clause `fail` still
744
+ producing overall `FAIL`) and the all-pass case are both proven against
745
+ real, canonically-evaluated fixtures (`tests/support/evidenceFixtures.ts#writeFullPipelineFixture`/
746
+ `writeAllPassPipelineFixture`) in real Chromium
747
+ (`tests/browser/comparisonEvaluationWorkspace.test.ts`) - `overallVerdict`
748
+ is never hand-edited to construct either demonstration.
749
+ - **Target/relationship cross-highlighting uses only explicit canonical
750
+ identity**: `primitiveTargetNames()` (`viewer/src/contract/clauseTargets.ts`)
751
+ extracts a contract primitive's named target field(s) (`target`, `targetA`/
752
+ `targetB`, `target`+`container`, `subjectTarget`/`relatedTarget`) by an
753
+ exhaustive switch over `ContractPrimitiveKind` - page-level primitives
754
+ (`document-width-fits-viewport`, `scroll-owner-is-document`) return no
755
+ names, so clicking them never fabricates a target highlight.
756
+ - **PWA cache boundary preserved**: both new routes live under `/api/`,
757
+ already covered by Batch 1's `navigateFallbackDenylist`; verified against
758
+ the real built `sw.js`.
759
+
760
+ ## v0.8 Batch 5 (External reference and reference/candidate inspection) — implemented
761
+
762
+ - **Reference indexing/media already existed (Batch 2), unchanged**: the
763
+ `external-reference-imported`/`external-reference-approved` families,
764
+ `GET /api/media/<handle>/image` (imported), and
765
+ `GET /api/media/<handle>/source-image` (approved, resolved through
766
+ `findImportedReferenceDir`'s exact `referenceId` walk) were already built
767
+ in Batch 2 and required no change here - Batch 5 only adds the visual
768
+ workspace consuming them.
769
+ - **Two new additive, read-only routes**
770
+ (`src/viewerServer/evidence/referenceView.ts`):
771
+ `GET /api/references/<handle>/view` derives the selected reference's own
772
+ region-relationship graph (`deriveReferenceRegionRelationships`) and
773
+ requirement adequacy (`deriveReferenceRequirementAdequacy`) - both pure
774
+ functions over the artifact's own persisted `regions`/`requirements`,
775
+ never persisted, never a second derivation engine (mirrors Batch 3's
776
+ `getObservationRelationships` server-side-derivation pattern).
777
+ `GET /api/references/<handle>/candidate/<handle>/view` evaluates
778
+ reference/candidate compatibility through the existing canonical
779
+ `evaluateReferenceCandidateCompatibility` (never a second, viewer-owned
780
+ compatibility model) and separately lists every existing
781
+ `FrontendContractEvaluationArtifact` whose own persisted `after` reference
782
+ exactly identifies the candidate, for explicit, never-auto-selected
783
+ optional display.
784
+ - **Reference-image SVG coordinate model is a genuinely distinct domain from
785
+ the candidate's runtime SVG** (`ReferenceRegionOverlaySvg.tsx`): `viewBox`
786
+ is the reference image's own pixel dimensions (never the candidate's CSS
787
+ viewport, never devicePixelRatio-multiplied); each region's canonical
788
+ `{x, y, width, height}` is rendered unchanged. Because this is a different
789
+ coordinate domain and data source from `TargetOverlaySvg` (runtime CSS
790
+ pixels, `TargetGeometry`), it is a separate, sibling component rather than
791
+ a parameterization of the existing one - reuse would have silently
792
+ conflated the two domains. The candidate side, in contrast, reuses Batch
793
+ 3/4's exact `ComparisonObservationPane`/`TargetOverlaySvg` machinery
794
+ unchanged (a synthetic `{status:'resolved', handle}` `LinkStatus` is
795
+ constructed once a candidate is explicitly chosen).
796
+ - **Reference region selection and runtime target selection are two
797
+ independent, never-synchronized selection domains**
798
+ (`ReferenceWorkspace.tsx`): selecting a reference region never selects or
799
+ highlights a runtime target, even when both happen to share the same
800
+ string name (proven with a real Chromium fixture deliberately naming both
801
+ `"header"` - `tests/browser/referenceCandidateWorkspace.test.ts`, Case E).
802
+ No binding connector/highlight-across-panes exists in this batch - that is
803
+ Batch 6's explicit-binding-interaction scope.
804
+ - **Compatibility vs. reference adequacy vs. candidate fidelity are kept
805
+ strictly distinct, never conflated**: compatibility
806
+ (`comparable`/`comparable-with-warnings`/`incomparable` plus
807
+ blocking/warning/unassessed reasons) comes only from
808
+ `evaluateReferenceCandidateCompatibility`; reference-side requirement
809
+ adequacy (`adequate`/`partial`/`inadequate`) comes only from
810
+ `deriveReferenceRequirementAdequacy`; candidate fidelity is never computed
811
+ in this batch at all - the UI always shows an explicit "not evaluated in
812
+ this batch" note rather than ever implying a fidelity PASS from a
813
+ compatibility PASS or an adequate reference (task §32/§33 boundary,
814
+ `evaluateReferenceCandidateFidelity` is never imported/called anywhere in
815
+ Batch 5).
816
+ - **Optional contract/evaluation context is opt-in, never inferred**
817
+ (`ReferenceWorkspace.tsx`): when the reference/candidate view lists more
818
+ than one exactly-matching evaluation artifact, the developer must
819
+ explicitly pick one from a `<select>` - the newest/first match is never
820
+ silently chosen, and with zero selected the candidate's contract status
821
+ reads "not selected/not available", never a fabricated PASS.
822
+ - **Imported vs. approved image ownership preserved exactly as Batch 2 built
823
+ it**: an imported reference's image is fetched from its own directory; an
824
+ approved reference's image is fetched from its exact imported source via
825
+ `sourceReference.referenceId`, never assumed co-located, never
826
+ duplicated - proven with a real Chromium fixture asserting the two
827
+ `<image href>` values resolve to the `image`/`source-image` roles
828
+ respectively (Cases A/B).
829
+ - **PWA cache boundary preserved**: both new routes live under `/api/`,
830
+ already covered by Batch 1's `navigateFallbackDenylist`; verified against
831
+ the real built `sw.js` (no new `registerRoute`, no `/api/references`
832
+ precache entry).
833
+
834
+ ## v0.8 Batch 6 (Explicit-binding interaction, zoom/pan, conditional lock, and on-demand reference fidelity) — implemented
835
+
836
+ - **`view --bindings-file <json-file>`**: reuses the exact same operational
837
+ binding-file wrapper parser (`loadBindingsFile` in `src/cli.ts`) that
838
+ `evaluate-reference-fidelity --bindings-file` already used - one shared
839
+ parser, never a second divergent one. The file is read once at startup;
840
+ its declarations become `ViewerServerState.bindingDeclarations` (an opaque
841
+ `unknown[]` until validated against a specific reference); the file path
842
+ itself is never persisted, returned, or exposed to the browser. Reference-
843
+ specific declaration validity (region existence, shape) is deferred to the
844
+ moment a reference is actually selected server-side, via the existing
845
+ canonical `isValidReferenceRuntimeBindingDeclarations` - never checked at
846
+ startup without a reference.
847
+ - **Two new additive, read-only routes**
848
+ (`src/viewerServer/evidence/referenceView.ts`):
849
+ `GET /api/references/<handle>/candidate/<handle>/bindings` validates the
850
+ session's declarations against the selected reference and calls the
851
+ existing canonical `evaluateReferenceRuntimeBindings` exactly once.
852
+ `GET /api/references/<handle>/candidate/<handle>/fidelity` is the explicit
853
+ on-demand fidelity trigger - calls the existing canonical
854
+ `evaluateReferenceCandidateFidelity` exactly once, using the exact same
855
+ session declarations, so its embedded `bindings` field and the `/bindings`
856
+ route's own result always structurally agree for identical inputs (same
857
+ pure function, same arguments). Neither route persists anything; both are
858
+ `GET` (idempotent, deterministic, ephemeral over already-selected explicit
859
+ input) - no mutation route was added.
860
+ - **`deriveCoordinateScale` exported additively** from
861
+ `externalReferenceFidelity.ts` (previously module-private) - Batch 6's
862
+ view-lock eligibility reuses this exact function unchanged (same formula,
863
+ same `ASPECT_RATIO_MAPPING_TOLERANCE`, same no-applicable-viewport
864
+ failure) rather than a second aspect-ratio/scale implementation. The
865
+ existing `GET /api/references/<handle>/candidate/<handle>/view` route now
866
+ additionally returns `coordinateMapping: DeriveCoordinateScaleResult` -
867
+ purely a function of the reference, independent of the candidate.
868
+ - **Explicit-binding cross-selection uses only canonical
869
+ `ReferenceRuntimeBindingResult.referenceRegion`/`.runtimeTarget` fields**
870
+ (`ReferenceWorkspace.tsx`): selecting a `bound` reference region
871
+ highlights (via `TargetOverlaySvg`'s existing Batch 4 `highlightNames`
872
+ prop - never the primary `selected`/`aria-pressed` target) its exact
873
+ declared runtime target; selecting a runtime target highlights every
874
+ region whose `bound` result names it (many-to-one, via a new additive
875
+ `highlightRegionIds` prop on `ReferenceRegionOverlaySvg`, matching
876
+ `TargetOverlaySvg`'s established highlight pattern). `ambiguous`/
877
+ `unavailable` results never cross-select. Proven with a real equal-name
878
+ ("header" region + "header" target) Chromium fixture: no cross-selection
879
+ without an explicit declaration, real cross-selection with one.
880
+ - **Zoom/pan is a repository-owned, presentation-only hook**
881
+ (`viewer/src/hooks/useZoomPan.ts`): bounded `[1x, 8x]` scale, `×1.25`/
882
+ `÷1.25` step, expressed as one `{scale, focalX, focalY}` triple in the
883
+ pane's own source-coordinate frame (reference-image pixels or candidate
884
+ CSS pixels - never rewritten). Renders via an SVG `viewBox` override
885
+ (additive `viewBoxOverride`/`svgRef`/pointer-handler props on
886
+ `TargetOverlaySvg`/`ReferenceRegionOverlaySvg`, defaulting to Batch 3/5's
887
+ exact prior behavior when omitted) - image and overlay stay one
888
+ transformed unit automatically since both live inside the same `<svg>`
889
+ root, and native SVG hit-testing means selection keeps working correctly
890
+ under zoom/pan with no extra coordinate math. Panning uses the SVG
891
+ element's own `getScreenCTM()` to convert screen-space pointer deltas into
892
+ source-space deltas - reuses the browser's native transform rather than a
893
+ custom aspect-ratio-aware pixel calculation - and only engages (calling
894
+ `setPointerCapture`) once the pointer has moved past a small threshold, so
895
+ an ordinary click on a region/target rect is never hijacked into a
896
+ phantom drag. Fit and Reset are the same fitted-1x/centered default (task
897
+ §26 - no second presentation-only default was introduced).
898
+ - **View lock reuses one single shared state, never two independently
899
+ synchronized states**: `ReferenceWorkspace.tsx` owns `refZoom`/`candZoom`
900
+ directly (always-controlled `useZoomPan` calls) and each pane's zoom/pan
901
+ action handler updates both states in one synchronous call when locked -
902
+ no reactive effect watches one pane's state to update the other, so no
903
+ feedback-loop risk exists. Lock is available only when a candidate is
904
+ selected, compatibility is not `incomparable`, and `coordinateMapping.ok`
905
+ is `true`; any change to that eligibility (including selecting a
906
+ different reference/candidate) immediately disables lock and shows an
907
+ actionable reason. Synchronization converts a candidate CSS-pixel focal
908
+ point/scale into reference-image-pixel space (and back) using only
909
+ `coordinateMapping.scale.scaleX`/`scaleY` - the exact same canonical
910
+ factor `deriveCoordinateScale` already produces, applied as a straight
911
+ multiply/divide (its own algebraic inverse), never a second mapping rule.
912
+ - **Contract/fidelity independence is never collapsed into one status**:
913
+ the existing Batch 5 "Optional contract/evaluation context" section
914
+ (unchanged) and the new on-demand `ReferenceFidelityPanel` are two
915
+ separate sections rendering two separate canonical results
916
+ (`FrontendContractEvaluationArtifact.overallVerdict` and
917
+ `ReferenceCandidateFidelityEvaluation.state`) side by side; when both are
918
+ present, an explicit note states that fidelity does not override an
919
+ active contract failure. No new coordinator/aggregate verdict is computed
920
+ anywhere in this batch.
921
+ - **PWA cache boundary preserved**: both new routes live under `/api/`,
922
+ already covered by Batch 1's `navigateFallbackDenylist`.
923
+
924
+ ## v0.8 Batch 7 (Bounded agent context, correlation, provenance, and raw evidence navigation) — implemented
925
+
926
+ - **Bounded agent context remains programmatic-only**: no filesystem writer
927
+ was added for `BoundedAgentContextArtifact` (it is still not an
928
+ Observer-evidence-root artifact family - `src/viewerServer/evidence/classify.ts`'s
929
+ "known but unreadered kind" comment is unchanged). `view --context-file
930
+ <json-file>` reads exactly one already-serialized
931
+ `BoundedAgentContextArtifact` value directly (no wrapper object) as
932
+ explicit, session-only viewer input - read once at startup
933
+ (`src/cli.ts#loadContextFile`, mirroring `loadBindingsFile`'s exact
934
+ read/size-bound/parse shape), classified by
935
+ `src/viewerServer/context.ts#classifyContextFileContent` (reuses the
936
+ existing canonical `isValidBoundedAgentContextArtifact` - never a second
937
+ validator), and held only in `ViewerServerState.context` for the life of
938
+ the process. The file's size is bounded by the existing Batch 2
939
+ `MAX_MANIFEST_CANDIDATE_BYTES` (2,000,000 bytes) rather than a second
940
+ bound, since a context artifact's own frozen numeric caps already make it
941
+ far smaller in any realistic case.
942
+ - **Three honest session states, never coerced into one another**: `'none'`
943
+ (no `--context-file`; every Batch 1-6 feature stays fully available),
944
+ `'unsupported-version'` (recognized `artifactKind`, a `schemaVersion`
945
+ other than the current one - the viewer still starts, showing this
946
+ state explicitly rather than either failing or misinterpreting the
947
+ fields), and `'valid'` (structurally validated current-schema context).
948
+ Every other problem (unreadable file, wrong `artifactKind`, a
949
+ structurally invalid *current*-schema artifact) fails viewer startup
950
+ clearly - an explicitly supplied file is never silently ignored.
951
+ - **`GET /api/context`** (`httpServer.ts`) returns the session's exact
952
+ classified state; for `'valid'`, it additionally returns
953
+ `sourceResolution` - the result of resolving
954
+ `artifact.sources` against the current evidence root by **exact
955
+ canonical identity only**
956
+ (`src/viewerServer/evidence/contextSourceView.ts`, reusing/extending
957
+ Batch 4's `linkedEvidence.ts` resolver pattern with three additive
958
+ functions: `resolveObservationById` (bare `observationId`, the only
959
+ identity a context source reference actually carries),
960
+ `resolveEvaluationByIdentity`, and `resolveReferenceByIdentity`). Zero
961
+ matches → `missing`; two or more → `ambiguous` (never silently picks
962
+ one) - the same discipline every other Batch 4/5 resolver already
963
+ established.
964
+ - **Raw structured evidence reuses the existing Batch 2 artifact-detail
965
+ route unchanged**: `RawEvidenceViewer.tsx` calls the existing
966
+ `useArtifactDetail`/`GET /api/artifacts/<handle>` for any exactly-resolved
967
+ source - no second full-artifact retrieval mechanism, no local filesystem
968
+ read, no arbitrary path accepted from the browser.
969
+ `EvidenceReference.path` values are always displayed as plain provenance
970
+ text, never passed to `fs.readFile`/`path.resolve`/a static file server.
971
+ - **Bounded runtime targets, adequacy, omissions, truncations, and
972
+ correlation are rendered exactly as the validated artifact states them** -
973
+ never recomputed, never boolean-collapsed
974
+ (`ContextWorkspace.tsx`): `Adequacy.state`
975
+ (`adequate`/`partial`/`inadequate`) and reasons are shown verbatim;
976
+ absent bounded-target fields render "not included in this bounded
977
+ context", never a fabricated falsy/zero value; `required: true`
978
+ omissions/truncations render in a visually distinct
979
+ `.context-required-loss` block, separate from optional ones;
980
+ `correlations` absent renders "Static correlation not included in this
981
+ context" - never "unavailable" (that status is reserved for a real
982
+ per-target `RuntimeStaticCorrelationRecord` with zero candidates).
983
+ `correlated`/`ambiguous`/`unavailable` are preserved exactly; a
984
+ `correlated` record's one candidate is labeled "Correlated candidate", an
985
+ `ambiguous` record shows **every** supplied candidate with none visually
986
+ promoted, and `unavailable` fabricates zero candidates - matching the
987
+ frozen `CORRELATION_STATUSES` invariants
988
+ (`domain/boundedAgentContext.ts`) the validator itself already enforces.
989
+ All new UI text was audited against ownership/edit-authorization language
990
+ (no "owner"/"source owner"/"owned by") - correlation is presented as
991
+ evidence, never as edit authorization.
992
+ - **Context-target ↔ runtime-target interaction never infers source
993
+ ownership**: selecting a bounded target or a correlation record uses only
994
+ exact `targetId`/`runtimeTargetId` string matching; for each *exactly
995
+ resolved* source observation, `SourceObservationTargetCheck` checks
996
+ membership in that observation's own already-fetched `targetEvidence`
997
+ (a plain lookup over already-loaded JSON, never a new derivation) and, if
998
+ more than one resolved source observation contains the same target id,
999
+ lists all of them rather than picking one.
1000
+ - **Bounded reference-fidelity projection is never recomputed, and is kept
1001
+ visibly distinct from a live on-demand evaluation**: absent `fidelity`
1002
+ renders "Reference fidelity not included in this bounded context" - never
1003
+ implied as passing. When present, `mismatches` and `protectedContext` are
1004
+ rendered in separate sections from the artifact's own fields exactly as
1005
+ supplied; a `state: 'not-evaluated'` blocked projection always shows
1006
+ `blockedBy` prominently and never renders an empty mismatch list as "no
1007
+ problems". When the context's `referenceId`/`candidateObservationId`
1008
+ exactly resolve within the current evidence root, `ContextWorkspace.tsx`
1009
+ embeds the existing, unchanged Batch 6 `ReferenceFidelityPanel` (the same
1010
+ on-demand `evaluateReferenceCandidateFidelity` trigger) directly beneath
1011
+ the bounded projection, labeled "Bounded context fidelity projection"
1012
+ above and "Current on-demand fidelity evaluation" below - two separate,
1013
+ clearly labeled evidence instances, never silently merged or replaced.
1014
+ - **No runtime rebuild of context or correlation, and no my-dev-kit
1015
+ execution from the shipped viewer**: grep-verified - `projectBoundedAgentContext(`,
1016
+ `deriveRuntimeStaticCorrelations(`, and `attachRuntimeStaticCorrelations(`
1017
+ appear nowhere under `src/viewerServer/` or `viewer/src/` (only in test/
1018
+ fixture-generation code, per the frozen plan's explicit test-fixture
1019
+ exception); no `child_process`/`npx @dailephd/my-dev-kit` invocation
1020
+ exists in the viewer server or browser bundle.
1021
+ - **PWA cache boundary preserved**: `GET /api/context` lives under `/api/`,
1022
+ already covered by Batch 1's `navigateFallbackDenylist`.
1023
+
1024
+ ## v0.8 Batch 8 (Integrated viewer acceptance, PWA hardening, and packaged proof) — implemented
1025
+
1026
+ Batch 8 is the final v0.8 implementation batch. It is integration/hardening,
1027
+ not a new architecture layer: no new API route, no new CLI flag, and no new
1028
+ canonical-engine call site were added. See
1029
+ `docs/reports/v0.8-integrated-viewer-acceptance-batch8.md` for the full
1030
+ record.
1031
+
1032
+ - **Closed three named real-browser coverage gaps**, each proved against the
1033
+ actual built viewer through the actual loopback server, never a hand-edited
1034
+ fixture verdict: many reference regions bound to one runtime target all
1035
+ cross-highlight together (the pre-existing target→regions loop in
1036
+ `ReferenceWorkspace.tsx` already iterated every matching binding - the gap
1037
+ was in real-browser proof, not in the derivation); reference-fidelity
1038
+ `fail` alongside a genuine frontend-contract `PASS` for the same candidate
1039
+ display independently (the pre-existing independence note in
1040
+ `ReferenceWorkspace.tsx` was already verdict-agnostic); a bounded context
1041
+ whose sources include two observations sharing a stable target id lists
1042
+ every matching source observation (the pre-existing
1043
+ `SourceObservationTargetCheck` in `ContextWorkspace.tsx` already checked
1044
+ membership per source independently, never picking one).
1045
+ - **One real accessibility defect found and fixed**: a cross-highlighted,
1046
+ non-selected region/target `<rect>` (`TargetOverlaySvg.tsx`,
1047
+ `ReferenceRegionOverlaySvg.tsx`) exposed no accessible state distinguishing
1048
+ it from a plain unselected rect - `aria-pressed` correctly stayed `false`
1049
+ (it is not the primary single-selection), but nothing else communicated
1050
+ the highlight to assistive technology. Fixed by adding
1051
+ `data-highlighted="true"` and an `aria-label` suffix
1052
+ (`" (highlighted: related to current selection)"`) when highlighted and
1053
+ not selected, leaving `aria-pressed` semantics untouched.
1054
+ - **First live-browser PWA proof suite** (`tests/browser/pwaHardening.test.ts`):
1055
+ real service-worker registration and activation against the built shell;
1056
+ the manifest fetched and confirmed `display: "standalone"`; zero Cache
1057
+ Storage entries under any `/api/` pathname after normal use, confirming
1058
+ the `navigateFallbackDenylist` boundary holds live, not just in the built
1059
+ `sw.js` regex; and the hard server-down gate - after the server is closed
1060
+ and the same page reloaded, the app shell still renders from the precache,
1061
+ but the evidence-dependent surface shows the explicit
1062
+ `.evidence-list__error` "Evidence index unavailable" state, with the
1063
+ previously-visible evidence asserted absent. Install-control is proven
1064
+ only via synthetic `beforeinstallprompt` dispatch (a genuine browser
1065
+ install prompt was not observed under automation). Standalone-mode CDP
1066
+ display-mode emulation was attempted but not observed to take effect -
1067
+ recorded honestly, never overstated as actual OS-level installation proof.
1068
+ - **Packaged-candidate proof**: `npm pack` → clean consumer install (outside
1069
+ the repository) → the actually-installed CLI executable (not repo
1070
+ `dist/cli.js`) → the installed `view` server → real Chromium against the
1071
+ packaged/installed server, not a source-checkout dev server. Read-only
1072
+ evidence-hash proof (SHA-256 of every file in the exercised evidence root,
1073
+ taken before and after the packaged-browser session) confirmed no
1074
+ mutation and no new viewer-created artifact anywhere in the evidence root.
1075
+ - **Re-confirmed the no-second-engine invariant** across all eight batches by
1076
+ re-running the exact `grep -rn` audit from earlier batches - unchanged
1077
+ findings, no duplicate evidence engine exists.
1078
+
1079
+ ## Retained v0.1 architecture constraints
1080
+
1081
+ v0.1 planning preserved these approved boundaries without treating module
1082
+ names from the historical run as mandatory:
1083
+
1084
+ ```text
1085
+ thin command-line boundary
1086
+ ↓
1087
+ reusable observation engine/application layer
1088
+ ↓
1089
+ browser automation boundary
1090
+ ↓
1091
+ observer-owned runtime evidence
1092
+
1093
+ observer-owned domain/schema
1094
+ ↓
1095
+ artifact ownership boundary
1096
+
1097
+ deterministic fixture/test boundary
1098
+ ↓
1099
+ browser-level validation
1100
+ ```
1101
+
1102
+ Use one browser engine implementation, keep browser logic out of presentation,
1103
+ avoid speculative plugin/multi-browser abstractions, and keep observed
1104
+ applications external. Versions before v0.6 did not add runtime coupling to
1105
+ sibling ecosystem projects. v0.6 adds only explicit bounded context and
1106
+ correlation/export contracts within this repository, preserving independent
1107
+ ownership; orchestrator-consumption and lab-compatibility work are separate
1108
+ sibling-repository deliverables, not part of this repository's architecture.
1109
+
1110
+ The text/config-driven coding-agent workflow and the non-UI external-reference
1111
+ evidence foundation are operational as of v0.7. The viewer and annotation
1112
+ layers must consume the same canonical observation, relationship, comparison,
1113
+ contract, change-scope, reference, correlation, and context boundaries rather
1114
+ than creating parallel engines. The concrete implementation plan and module
1115
+ layout for each future version must be designed only after that version's
1116
+ planning workflow inspects the current repositories.
1117
+
1118
+ v0.7 Prompt 1 implements only the bottom of that external-reference stack: a
1119
+ new, standalone `ExternalReferenceArtifact` evidence root
1120
+ (`src/domain/externalReference.ts`, `externalReferenceImage.ts`,
1121
+ `externalReferenceIdentity.ts`, `src/artifacts/externalReferenceArtifact{Writer,Reader}.ts`,
1122
+ `src/application/externalReferencePersistenceService.ts`) with its own
1123
+ identity, provenance, bounded image metadata, and a two-state
1124
+ (`imported`/`approved`) lifecycle - see `docs/CONTRACTS.md` "v0.7 Prompt 1
1125
+ external-reference artifact contract" for the exact shape. It follows the
1126
+ same identity/persistence/diagnostics/export conventions as every existing
1127
+ artifact family (deterministic canonicalize-then-sha256 request identity,
1128
+ nonce-based fresh instance identity, atomic temp-dir-then-rename persistence,
1129
+ the shared `DIAGNOSTIC_CODES` vocabulary) without reusing or duplicating the
1130
+ observation, comparison, or contract engines themselves - an external
1131
+ reference is desired-design evidence, never an `ObservationArtifact`, an
1132
+ approved baseline, or a runtime target.
1133
+
1134
+ v0.7 Prompt 2 adds explicit reference regions and reusable reference-region
1135
+ relationships on top of that foundation (`domain/externalReferenceRegions.ts`,
1136
+ `externalReferenceRegionRelationships.ts`) - see `docs/CONTRACTS.md` "v0.7
1137
+ Prompt 2 explicit reference regions and relationships" for the exact shape.
1138
+ The relationship-derivation predicates are reused verbatim (now exported
1139
+ additively) from `domain/relationships.ts` rather than reimplemented, so
1140
+ reference-region geometry and runtime-target geometry can never diverge on
1141
+ the same underlying formula; only the geometry-only relationship families
1142
+ apply, since a static image exposes no DOM, scroll, or viewport evidence.
1143
+ v0.7 Prompt 3 adds selected design requirements, tolerance semantics, and
1144
+ reference-evidence adequacy on top of that region model
1145
+ (`domain/externalReferenceRequirements.ts`,
1146
+ `externalReferenceRequirementIdentity.ts`) - see `docs/CONTRACTS.md` "v0.7
1147
+ Prompt 3 selected design requirements, tolerance semantics, and
1148
+ reference-evidence adequacy" for the exact shape. Requirement categories are
1149
+ the exact v0.5 `AuthoredChangeScopeCategory` vocabulary, imported directly
1150
+ rather than reinvented, since that type carries no runtime-only coupling of
1151
+ its own; tolerance is a genuinely new, reference-owned type (never a reuse
1152
+ of `frontendContracts.ts`'s runtime/CSS-pixel-implicit `ContractTolerance`);
1153
+ and reference-evidence adequacy is a small, independently-owned vocabulary
1154
+ distinct from `boundedAgentContext.ts`'s runtime/static-correlation
1155
+ `Adequacy`. A region property or derived relationship is never promoted to
1156
+ an executable requirement automatically - only explicit user/configuration
1157
+ selection does that.
1158
+
1159
+ v0.7 Prompt 4 adds explicit reference applicability
1160
+ (`domain/externalReferenceApplicability.ts`) and observation-side explicit
1161
+ state identity (`domain/explicitState.ts`, shared by both artifact
1162
+ families), plus one new pure domain module,
1163
+ `domain/externalReferenceCompatibility.ts`, that evaluates whether a
1164
+ candidate `ObservationArtifact` describes the same frontend state as a
1165
+ given `ExternalReferenceArtifact` - see `docs/CONTRACTS.md` "v0.7 Prompt 4
1166
+ reference applicability and candidate-state compatibility" for the exact
1167
+ shape. This is page/state-level only, never geometry or fidelity, and
1168
+ remains a wholly separate concern from Prompt 3's reference-evidence
1169
+ adequacy - the two can independently disagree (an adequate reference can be
1170
+ incomparable against a given candidate, and vice versa). Rather than
1171
+ inventing a second comparability engine, Prompt 4 extracts one new exported
1172
+ pure helper from v0.4's own `domain/comparisonEngine.ts`
1173
+ (`assessOptionalComparabilityDimension`) and reuses it from both v0.4's
1174
+ `evaluateComparability` (Observation-vs-Observation) and the new
1175
+ `evaluateReferenceCandidateCompatibility` (Reference-vs-Observation) - the
1176
+ one additive behavior change to v0.4 itself is that `evaluateComparability`
1177
+ now assesses (rather than always reporting unassessed) theme/authenticated-
1178
+ state/application-state whenever both observations declare
1179
+ `requestConfig.explicitState`, while every historical/legacy observation
1180
+ pair retains the exact prior unassessed-only behavior. No new persisted
1181
+ artifact kind is introduced for the compatibility result; it is a pure,
1182
+ on-demand function of two already-persisted artifacts.
1183
+
1184
+ v0.7 Prompt 5 adds explicit reference-region <-> runtime-target binding
1185
+ (`domain/externalReferenceRuntimeBinding.ts`) - see `docs/CONTRACTS.md`
1186
+ "v0.7 Prompt 5 explicit reference-region <-> runtime-target binding" for
1187
+ the exact shape. It answers only "which stable v0.2 runtime target does
1188
+ this candidate observation resolve for each explicitly declared reference
1189
+ region", strictly downstream of Prompt 4's compatibility gate (reused
1190
+ verbatim, never duplicated) and strictly upstream of v0.6's own
1191
+ runtime/static correlation - the two identity domains (a Prompt 2
1192
+ `ReferenceRegion.id` and a v0.2 `NamedTarget.name`) never collapse into
1193
+ each other, and this stage stops at the runtime target, never reaching
1194
+ source ownership. Following v0.6's uncertainty discipline
1195
+ (`domain/boundedAgentContextCorrelation.ts`), binding never guesses through
1196
+ ambiguity - an ambiguously or unavailably resolved v0.2 target is reported
1197
+ as such, never silently treated as bound - though the actual per-status
1198
+ mapping (`bound`/`ambiguous`/`unavailable`) is binding's own, independently
1199
+ owned vocabulary, not a reuse of v0.6's `correlated`/`ambiguous`/
1200
+ `unavailable` correlation-status semantics (a different evidence boundary:
1201
+ correlation ranks *static candidates* for one runtime target, whereas
1202
+ binding resolves *one runtime target's own existence* for one declared
1203
+ correspondence). No second target resolver, no browser execution, and no
1204
+ new persisted artifact family were introduced; neither
1205
+ `ExternalReferenceArtifact` nor `ObservationArtifact` is mutated to carry a
1206
+ binding result, since a reference may later be evaluated against several
1207
+ candidates and an observation against several references.
1208
+
1209
+ v0.7 Prompt 6 adds structured reference-vs-candidate fidelity evaluation
1210
+ (`domain/externalReferenceFidelity.ts`, `application/referenceFidelityEvaluationService.ts`,
1211
+ and the `evaluate-reference-fidelity` CLI command) - the first point in this
1212
+ stack where a reference's authored expectation is compared against live
1213
+ candidate evidence. See `docs/CONTRACTS.md` "v0.7 Prompt 6 structured
1214
+ reference-vs-candidate fidelity evaluation" for the exact shape. It is
1215
+ downstream of every prior v0.7 prompt and reuses each verbatim: Prompt 3's
1216
+ `deriveReferenceRequirementAdequacy`/`deriveReferenceRequirementExpectation`/
1217
+ `deriveReferenceRequirementMeasurement` (never redefined), Prompt 4's
1218
+ `evaluateReferenceCandidateCompatibility` (a hard gate, never duplicated),
1219
+ and Prompt 5's `evaluateReferenceRuntimeBindings` (the sole source of
1220
+ runtime-target identity - no automatic binding, no second target resolver).
1221
+ It also reuses v0.4's `deriveLayoutRelationships` for runtime relationship
1222
+ evidence, scoped to the exact requested relationship family (the same
1223
+ Prompt 3 bug-fix precedent). The one genuinely new problem this prompt
1224
+ solves is the reference-image-pixel <-> CSS-pixel coordinate mapping: a
1225
+ single explicit, deterministic full-frame scale derived from
1226
+ `reference.applicability.viewport` and the reference image's own
1227
+ dimensions, with a tiny independent aspect-ratio-coherence check (never a
1228
+ design tolerance) gating whether that mapping exists at all. No new
1229
+ persisted artifact family, no browser execution, and no source-ownership
1230
+ attribution - this is reference fidelity only, a separate concern from any
1231
+ later v0.5 baseline/per-change contract result or v0.7 overall verdict.
1232
+
1233
+ v0.7 Prompt 7 adds bounded reference-fidelity projection into the existing
1234
+ v0.6 bounded-agent-context architecture (`domain/referenceFidelityProjection.ts`,
1235
+ plus additive extensions to `domain/boundedAgentContext.ts`,
1236
+ `domain/boundedAgentContextIdentity.ts`, and
1237
+ `domain/boundedAgentContextProjection.ts`) - see `docs/CONTRACTS.md` "v0.7
1238
+ Prompt 7 bounded reference-fidelity projection and v0.6 bounded-agent-
1239
+ context integration" for the exact shape. `projectBoundedAgentContext`
1240
+ itself, not a new parallel context system, gains one new optional input (an
1241
+ already-computed Prompt 6 fidelity evaluation): fidelity-relevant runtime
1242
+ targets fold into the exact same required/permitted-target-allocation,
1243
+ evidence-tiering, omission/truncation, and adequacy machinery v0.5 contract
1244
+ clauses already compete in, and a new `fidelity?` field on
1245
+ `BoundedAgentContextArtifact` (mirroring `correlations?`'s own additive,
1246
+ non-version-bumping precedent from v0.6 Batch 3) carries a bounded,
1247
+ priority-ordered selection of Prompt 6's non-passing requirement results
1248
+ plus passing protected/preserved context. No second bounded-context
1249
+ architecture, no recomputation of Prompt 2-6/v0.4/v0.5 logic, and no change
1250
+ to v0.6's own runtime/static correlation (`deriveRuntimeStaticCorrelations`/
1251
+ `attachRuntimeStaticCorrelations` are untouched and reused exactly as
1252
+ before) - a caller joins fidelity, target, and correlation evidence by the
1253
+ one stable v0.2 runtime target id all three already share. Every new field
1254
+ is optional and additive; a pre-Prompt-7 caller supplying no fidelity
1255
+ evidence receives byte-identical output, including logical identity.
1256
+
1257
+ v0.7 Prompt 8 adds the first complete, controlled end-to-end external-
1258
+ reference correction workflow (`domain/referenceCorrectionWorkflow.ts`,
1259
+ `domain/referenceCorrectionIdentity.ts`) - see `docs/CONTRACTS.md` "v0.7
1260
+ Prompt 8 controlled end-to-end external-reference coding-agent correction
1261
+ workflow" for the exact shape. This is a narrowly-scoped coordinator, not a
1262
+ second workflow engine: it exposes exactly two pure operations -
1263
+ `prepareReferenceCorrection` (pre-change evidence -> a bounded coding-agent
1264
+ handoff, built from Prompt 1/3/4/5/6/7's existing engines) and
1265
+ `reviewReferenceCorrectionAttempt` (a fresh post-edit candidate -> one
1266
+ composed overall result, built from v0.4's `compareObservations`, v0.7
1267
+ Prompt 6's `evaluateReferenceCandidateFidelity`, and v0.5's
1268
+ `evaluateFrontendContract`) - with an explicit, un-automatable seam between
1269
+ them where an external implementation actor edits target source. Overall
1270
+ `'pass'` requires both reference fidelity `'pass'` and v0.5 contract
1271
+ evaluation `'PASS'` - matching the selected design reference is necessary
1272
+ but never sufficient, so a candidate that visually satisfies the reference
1273
+ while regressing an active protected or preserved contract clause still
1274
+ resolves to overall `'fail'`. Review identity is a deterministic hash of
1275
+ `{referenceRequestId, baselineObservationId, baselineContractId,
1276
+ baselineContractClauses, changeContractId, changeContractClauses,
1277
+ bindingDeclarations}`; attempt identity is a deterministic hash of
1278
+ `{reviewRequestId, candidateObservationId}`. `reviewReferenceCorrectionAttempt`
1279
+ rejects any call whose supplied `reviewRequestId` does not match what its own
1280
+ baseline/contract/reference/binding inputs recompute - the mechanism that
1281
+ makes "every attempt evaluates against the same approved baseline" an
1282
+ enforced invariant, not just a documented one. No new persisted artifact
1283
+ family, no CLI surface, and - most importantly - no code path anywhere in
1284
+ this module (or anything it calls) that opens, parses, or writes a target
1285
+ source file: real candidate capture remains the caller's own responsibility
1286
+ through the existing, unmodified real-Chromium observation pipeline.