@dailephd/my-frontend-observer 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +107 -7
  3. package/dist/application/projectWorkflowService.d.ts +18 -1
  4. package/dist/application/projectWorkflowService.js +40 -2
  5. package/dist/application/projectWorkflowService.js.map +1 -1
  6. package/dist/application/visualAnnotationContractPromotionService.d.ts +41 -0
  7. package/dist/application/visualAnnotationContractPromotionService.js +143 -0
  8. package/dist/application/visualAnnotationContractPromotionService.js.map +1 -0
  9. package/dist/application/visualAnnotationPersistenceService.d.ts +34 -0
  10. package/dist/application/visualAnnotationPersistenceService.js +68 -0
  11. package/dist/application/visualAnnotationPersistenceService.js.map +1 -0
  12. package/dist/application/visualAnnotationReferenceMaterializationService.d.ts +53 -0
  13. package/dist/application/visualAnnotationReferenceMaterializationService.js +194 -0
  14. package/dist/application/visualAnnotationReferenceMaterializationService.js.map +1 -0
  15. package/dist/artifacts/visualAnnotationArtifactReader.d.ts +19 -0
  16. package/dist/artifacts/visualAnnotationArtifactReader.js +66 -0
  17. package/dist/artifacts/visualAnnotationArtifactReader.js.map +1 -0
  18. package/dist/artifacts/visualAnnotationArtifactWriter.d.ts +42 -0
  19. package/dist/artifacts/visualAnnotationArtifactWriter.js +85 -0
  20. package/dist/artifacts/visualAnnotationArtifactWriter.js.map +1 -0
  21. package/dist/cli.js +464 -454
  22. package/dist/cli.js.map +1 -1
  23. package/dist/domain/visualAnnotation.d.ts +217 -0
  24. package/dist/domain/visualAnnotation.js +584 -0
  25. package/dist/domain/visualAnnotation.js.map +1 -0
  26. package/dist/domain/visualAnnotationIdentity.d.ts +17 -0
  27. package/dist/domain/visualAnnotationIdentity.js +47 -0
  28. package/dist/domain/visualAnnotationIdentity.js.map +1 -0
  29. package/dist/index.d.ts +11 -0
  30. package/dist/index.js +6 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/projectWorkflow/projectPaths.d.ts +9 -0
  33. package/dist/projectWorkflow/projectPaths.js +21 -0
  34. package/dist/projectWorkflow/projectPaths.js.map +1 -1
  35. package/dist/viewer/assets/{index-CN_yb9Uf.css → index-BN41MI7m.css} +1 -1
  36. package/dist/viewer/assets/index-CkKXnlrI.js +9 -0
  37. package/dist/viewer/index.html +2 -2
  38. package/dist/viewer/sw.js +1 -1
  39. package/dist/viewerServer/annotationAuthoring.d.ts +64 -0
  40. package/dist/viewerServer/annotationAuthoring.js +230 -0
  41. package/dist/viewerServer/annotationAuthoring.js.map +1 -0
  42. package/dist/viewerServer/annotationContractPromotion.d.ts +51 -0
  43. package/dist/viewerServer/annotationContractPromotion.js +105 -0
  44. package/dist/viewerServer/annotationContractPromotion.js.map +1 -0
  45. package/dist/viewerServer/annotationReferenceMaterialization.d.ts +40 -0
  46. package/dist/viewerServer/annotationReferenceMaterialization.js +91 -0
  47. package/dist/viewerServer/annotationReferenceMaterialization.js.map +1 -0
  48. package/dist/viewerServer/authoringSecurity.d.ts +59 -0
  49. package/dist/viewerServer/authoringSecurity.js +112 -0
  50. package/dist/viewerServer/authoringSecurity.js.map +1 -0
  51. package/dist/viewerServer/evidence/annotationView.d.ts +28 -0
  52. package/dist/viewerServer/evidence/annotationView.js +43 -0
  53. package/dist/viewerServer/evidence/annotationView.js.map +1 -0
  54. package/dist/viewerServer/evidence/classify.d.ts +3 -1
  55. package/dist/viewerServer/evidence/classify.js +12 -0
  56. package/dist/viewerServer/evidence/classify.js.map +1 -1
  57. package/dist/viewerServer/evidence/discovery.d.ts +2 -0
  58. package/dist/viewerServer/evidence/discovery.js +6 -0
  59. package/dist/viewerServer/evidence/discovery.js.map +1 -1
  60. package/dist/viewerServer/evidence/handles.js +1 -0
  61. package/dist/viewerServer/evidence/handles.js.map +1 -1
  62. package/dist/viewerServer/evidence/index.d.ts +29 -0
  63. package/dist/viewerServer/evidence/index.js +43 -1
  64. package/dist/viewerServer/evidence/index.js.map +1 -1
  65. package/dist/viewerServer/evidence/mediaResolver.d.ts +1 -1
  66. package/dist/viewerServer/evidence/mediaResolver.js +28 -2
  67. package/dist/viewerServer/evidence/mediaResolver.js.map +1 -1
  68. package/dist/viewerServer/evidence/projection.d.ts +5 -1
  69. package/dist/viewerServer/evidence/projection.js +19 -0
  70. package/dist/viewerServer/evidence/projection.js.map +1 -1
  71. package/dist/viewerServer/httpServer.d.ts +13 -2
  72. package/dist/viewerServer/httpServer.js +278 -4
  73. package/dist/viewerServer/httpServer.js.map +1 -1
  74. package/dist/viewerServer/viewerService.d.ts +8 -0
  75. package/dist/viewerServer/viewerService.js +38 -2
  76. package/dist/viewerServer/viewerService.js.map +1 -1
  77. package/docs/ARCHITECTURE.md +108 -21
  78. package/docs/CI_CD.md +57 -1
  79. package/docs/COMMANDS.md +44 -4
  80. package/docs/CONTRACTS.md +78 -8
  81. package/docs/CURRENT_STATE.md +157 -35
  82. package/docs/DEVELOPMENT.md +8 -3
  83. package/docs/PROJECT_DESCRIPTION.md +4 -1
  84. package/docs/PROJECT_MILESTONES.md +4 -0
  85. package/docs/PROJECT_OVERVIEW.md +41 -17
  86. package/docs/QUICKSTART.md +52 -39
  87. package/docs/RELEASE.md +16 -11
  88. package/docs/ROADMAP.md +406 -66
  89. package/docs/SECURITY.md +71 -14
  90. package/docs/WORKFLOWS.md +151 -23
  91. package/docs/plans/v0.9-implementation-plan.md +1529 -0
  92. package/docs/reports/v0.9-architecture-retrieval.md +567 -0
  93. package/docs/reports/v0.9-batch1-visual-annotation-foundation.md +351 -0
  94. package/docs/reports/v0.9-batch2-viewer-annotation-authoring-boundary.md +438 -0
  95. package/docs/reports/v0.9-batch3-runtime-screenshot-annotation-authoring.md +412 -0
  96. package/docs/reports/v0.9-batch4-external-reference-annotation-authoring.md +452 -0
  97. package/docs/reports/v0.9-batch5-runtime-intent-contract-promotion.md +535 -0
  98. package/docs/reports/v0.9-batch6-reference-materialization.md +514 -0
  99. package/docs/reports/v0.9-batch7-integrated-acceptance.md +644 -0
  100. package/docs/reports/v0.9-demo-foundation.md +589 -0
  101. package/docs/reports/v0.9-final-pre-release-readiness.md +209 -0
  102. package/docs/reports/v0.9-final-readiness-corrections.md +530 -0
  103. package/docs/reports/v0.9-pre-release-readiness.md +170 -0
  104. package/docs/reports/v0.9-tutorial-end-to-end-acceptance.md +980 -0
  105. package/docs/reports/v0.9-tutorial-integration.md +731 -0
  106. package/package.json +2 -2
  107. package/dist/viewer/assets/index-D98S1_2d.js +0 -9
@@ -0,0 +1,351 @@
1
+ # v0.9 Batch 1 Report: Visual Annotation Foundation
2
+
3
+ ## 1. VERDICT
4
+
5
+ PASS_V0_9_BATCH1_VISUAL_ANNOTATION_FOUNDATION
6
+
7
+ ## 2. Repository identity
8
+
9
+ 1. Repository: `C:\Users\daile\Projects\my-frontend-observer`
10
+ 2. Branch: `master`
11
+ 3. Local HEAD at session start: `473713d240af09e752eeb8e00735738c4927b16d`
12
+ 4. Starting HEAD for implementation: `59cfb6fd29a0c3c394d6115213edf92c1106104f`
13
+ (the expected v0.9 planning commit on `origin/master`)
14
+ 5. Ending HEAD before the final commit: `59cfb6fd29a0c3c394d6115213edf92c1106104f`
15
+ 6. Package version: `0.8.1` (unchanged in `package.json` and `package-lock.json`)
16
+
17
+ ### 2.1 Preflight handling
18
+
19
+ The first preflight found local `master` three commits behind `origin/master`.
20
+ It also found one untracked local file,
21
+ `docs/reports/v0.9-architecture-retrieval.md`. That path is tracked on
22
+ `origin/master` with different content. The first run stopped with
23
+ `BLOCKED_V0_9_BATCH1_DIRTY_WORKTREE`.
24
+
25
+ The user then told the agent to keep the local copy, not delete it, and
26
+ continue. The agent did the following:
27
+
28
+ 1. Copied the local file to
29
+ `.my-dev-kit-workflow/adhoc/preserved-local-docs/v0.9-architecture-retrieval.md`.
30
+ It checked that the SHA-256 of the copy matched the original. This folder is
31
+ ignored by Git.
32
+ 2. Moved the original to
33
+ `.my-dev-kit-workflow/adhoc/preserved-local-docs/v0.9-architecture-retrieval.md.moved`.
34
+ 3. Ran `git merge --ff-only origin/master`. This fast-forwarded `master` to `59cfb6f`.
35
+ 4. Copied the local content back to `docs/reports/v0.9-architecture-retrieval.md`.
36
+ 5. Ran `git update-index --skip-worktree docs/reports/v0.9-architecture-retrieval.md`.
37
+ Git now leaves the local copy alone and the worktree reports clean.
38
+
39
+ This commit does not include that file. To go back to the tracked version, run
40
+ `git update-index --no-skip-worktree docs/reports/v0.9-architecture-retrieval.md`.
41
+
42
+ ## 3. Frozen scope implemented
43
+
44
+ 1. `src/domain/visualAnnotation.ts` holds the frozen constants and all
45
+ annotation types: source, mark, association, intent, interpretation, item,
46
+ and artifact. It also holds the one canonical structural validator,
47
+ `isValidVisualAnnotationArtifact`, and the pure deterministic overlay
48
+ renderer, `renderVisualAnnotationOverlaySvg`.
49
+ 2. `src/domain/visualAnnotationIdentity.ts` holds
50
+ `buildVisualAnnotationRequestIdentity`, a deterministic semantic SHA-256
51
+ identity. It also holds `buildVisualAnnotationInstanceIdentity`, a fresh
52
+ `randomBytes(16)` instance identity.
53
+ 3. `src/artifacts/visualAnnotationArtifactWriter.ts` is an immutable, atomic,
54
+ manifest-last writer. It re-derives the overlay and verifies its digest
55
+ before writing.
56
+ 4. `src/artifacts/visualAnnotationArtifactReader.ts` is the canonical reader.
57
+ It validates the manifest and checks that the owned overlay is a regular
58
+ file whose SHA-256 matches the manifest.
59
+ 5. `src/application/visualAnnotationPersistenceService.ts` holds
60
+ `persistVisualAnnotation`, the one Batch 1 save use case.
61
+ 6. `src/index.ts` adds the public Batch 1 exports.
62
+
63
+ ## 4. Domain contract
64
+
65
+ 1. Artifact kind: `my-frontend-observer/visual-annotation`
66
+ 2. Schema version: `1.0.0`
67
+ 3. Source contexts (2): `runtime-observation` and `external-reference`
68
+ 4. Coordinate kinds: `runtime-css-px` for runtime sources and
69
+ `reference-image-px` for reference sources. A cross-domain coordinate kind
70
+ is rejected.
71
+ 5. Mark kinds (5): `point`, `rectangle`, `line`, `arrow`, `note`
72
+ 6. Intent kinds: `inspect`, `change`, `reference-region`,
73
+ `reference-requirement`, `asset-sensitive`. Runtime sources accept
74
+ `inspect` and `change`. Reference sources accept `inspect`,
75
+ `reference-region`, `reference-requirement`, and `asset-sensitive`.
76
+ 7. Interpretation states: `uninterpreted`, `candidate`, `confirmed`
77
+ 8. Item bound: `MAX_VISUAL_ANNOTATION_ITEMS = 100`
78
+ 9. Note bound: `MAX_VISUAL_ANNOTATION_NOTE_LENGTH = 2000`
79
+
80
+ ### 4.1 Canonical validators reused
81
+
82
+ 1. Change categories use `isAuthoredChangeScopeCategory`. `unexpected` is not
83
+ a member, so it cannot be authored.
84
+ 2. Expected-dependent mode uses `isValidExpectedDependentMode`. The mode is
85
+ required when the category is `expected-dependent` and must be absent
86
+ otherwise. This is the same rule `PerChangeClause` and
87
+ `RawReferenceRequirement` apply. Neither owning module exports the combined
88
+ check as a function, so Batch 1 applies the rule using the two exported
89
+ validators.
90
+ 3. Contract primitives use `isValidContractPrimitive`.
91
+ 4. Reference-region intent uses `isValidReferenceRegions([region], width, height)`.
92
+ This covers the region id pattern, rectangle validity, and the source image
93
+ bounds.
94
+ 5. Reference-requirement intent uses `isValidRawReferenceRequirement`.
95
+ 6. Relationship kinds come from `PAIRWISE_RELATIONSHIP_KINDS` and
96
+ `PAGE_LEVEL_RELATIONSHIP_KINDS`.
97
+
98
+ ### 4.2 Local implementation choices
99
+
100
+ These choices were left open by the frozen plan and this prompt.
101
+
102
+ 1. Every annotation object is a closed shape. Unknown fields are rejected, the
103
+ same way `isValidContractPrimitive` already rejects them. This is how the
104
+ validator rejects mixed forms, such as a candidate with `confirmedAt`, and
105
+ stray fields such as an alias or a viewer URL.
106
+ 2. A runtime `runtime-relationship` with a pairwise kind needs two non-empty,
107
+ distinct targets. This matches `PairwiseLayoutRelationship`. A page-level
108
+ kind must not carry targets. This matches `PageLevelLayoutRelationship`.
109
+ 3. A reference source with lifecycle `imported` must have
110
+ `imageOwnerReferenceId` equal to `referenceId`. A reference source with
111
+ lifecycle `approved` must name a different owning reference. This mirrors
112
+ the existing external-reference ownership model.
113
+ 4. `annotationId` names the artifact directory. The validator requires it to
114
+ be a single safe path segment: no separators, no colon, no NUL, and not
115
+ `.` or `..`. `source.screenshot.path` follows the same bare-filename rule.
116
+ 5. Invalid content given to the persistence service is refused with the
117
+ existing `invalid-request` diagnostic. No new diagnostic code was added.
118
+ 6. Batch 1 does not check whether an associated target or region exists in
119
+ another artifact. It does not check `contractPrimitive` against the item's
120
+ association either. Those checks belong to later batches.
121
+
122
+ ## 5. Identity contract
123
+
124
+ 1. The request identity hashes exactly
125
+ `{ source, items, supersedes: supersedesAnnotationId ?? null }`. The hash is
126
+ built by sorting object keys recursively, keeping array order, serializing
127
+ to JSON, and taking the lowercase SHA-256 hex. The module has its own
128
+ private `canonicalize`, which follows the repository convention.
129
+ 2. Excluded from the request identity: `createdAt`, the output location, cwd,
130
+ project root, alias, viewer port, HTTP handle, temporary directory, overlay
131
+ SHA, and `annotationId`. The function accepts none of these as inputs.
132
+ 3. Instance identity is `${annotationRequestId}-${randomBytes(16).toString('hex')}`.
133
+ It is never based on a timestamp.
134
+ 4. Supersession is carried forward as given. It is part of the request
135
+ identity, and the validator rejects an empty value or a value equal to
136
+ `annotationId`. Batch 1 does not resolve lineage.
137
+
138
+ ## 6. Overlay contract
139
+
140
+ 1. Owned filename: `annotation-overlay.svg`. The manifest `overlay.path` must
141
+ be exactly this value, and `overlay.format` must be `svg`.
142
+ 2. The root element uses the source dimensions:
143
+ `<svg xmlns="http://www.w3.org/2000/svg" width="W" height="H" viewBox="0 0 W H">`.
144
+ The manifest `overlay.width` and `overlay.height` must equal the source
145
+ coordinate-space dimensions.
146
+ 3. Determinism:
147
+ 1. Output depends only on the source dimensions and the marks, rendered in
148
+ the persisted item order.
149
+ 2. Style values are fixed constants.
150
+ 3. Numbers are formatted with `String(n)`, and `-0` is written as `0`.
151
+ 4. Lines end with `\n`.
152
+ 5. The arrowhead is built with `Math.sqrt` vector math, not trigonometry.
153
+ 6. Output never depends on interpretation state, item ids, timestamps,
154
+ random values, environment, locale, or the filesystem.
155
+ 4. Mark mapping:
156
+ 1. A point becomes a circle.
157
+ 2. A rectangle becomes a rect.
158
+ 3. A line becomes a line.
159
+ 4. An arrow becomes a line plus a filled polygon arrowhead. A zero-length
160
+ arrow gets no arrowhead.
161
+ 5. A note becomes a filled anchor circle plus a text element.
162
+ 5. The SVG has no image, script, foreignObject, href, marker ids, CSS imports,
163
+ or event handlers. It never embeds the source image.
164
+ 6. SHA-256 verification:
165
+ 1. The service hashes the rendered UTF-8 bytes.
166
+ 2. The writer re-renders the overlay and refuses to write if the digest
167
+ differs from `overlay.sha256`.
168
+ 3. The reader hashes the bytes on disk and refuses them if the digest does
169
+ not match.
170
+ 7. Text escaping: note text escapes `&`, `<`, `>`, `"`, and `'`. Characters
171
+ that XML 1.0 does not allow are replaced with U+FFFD in the overlay only.
172
+ The manifest keeps the authored text exactly as written.
173
+
174
+ ## 7. Persistence contract
175
+
176
+ 1. Final directory: `<outputLocation>/<annotationId>/`
177
+ 2. Temporary directory: `<outputLocation>/.tmp-<annotationId>`
178
+ 3. Write order:
179
+ 1. Validate the artifact.
180
+ 2. Render the overlay and verify its digest.
181
+ 3. Refuse if the final directory already exists.
182
+ 4. Remove this artifact's own stale temporary directory, if one exists.
183
+ 5. Create the temporary directory.
184
+ 6. Write `annotation-overlay.svg`.
185
+ 7. Write `manifest.json`.
186
+ 4. Atomic rename: the temporary directory is renamed to the final directory in
187
+ one `rename` call.
188
+ 5. No overwrite: if the final directory already exists, the writer returns
189
+ `artifact-write-failure` and leaves the existing files untouched.
190
+ 6. Failure cleanup: on any failure after the temporary directory is created,
191
+ the writer removes it and returns `artifact-write-failure`.
192
+ 7. The writer never reads or copies source observation or reference bytes.
193
+ 8. The service checks the output location with `normalizeOutputLocation`. It
194
+ uses `getProducerInfo()` and sets `provenance.origin` to `viewer`. It
195
+ writes exactly once.
196
+
197
+ ## 8. Tests added
198
+
199
+ 1. `tests/unit/visualAnnotationFixtures.ts` is a shared fixture helper, not a
200
+ test file.
201
+ 2. `tests/unit/visualAnnotation.test.ts` covers:
202
+ 1. The frozen constants.
203
+ 2. A: a valid runtime artifact.
204
+ 3. B: a valid reference artifact, both imported and approved.
205
+ 4. An empty item list, and all five mark kinds.
206
+ 5. C: cross-domain associations, and association shapes checked against
207
+ the relationship vocabularies.
208
+ 6. D: cross-domain intents, and every intent valid in its own context.
209
+ 7. Delegation to the canonical validators for primitives, regions,
210
+ requirements, category, and mode.
211
+ 8. E: bounds for all out-of-frame and non-finite marks, freehand and
212
+ polygon rejection, and an edge-touching rectangle.
213
+ 9. F: notes of 2000 characters (valid), 2001 characters (invalid), and
214
+ empty (invalid).
215
+ 10. G: 100 items (valid) and 101 items (invalid).
216
+ 11. H: duplicate and empty item ids.
217
+ 12. I: interpretation states and malformed mixtures.
218
+ 13. J: authored `unexpected` is rejected.
219
+ 14. K: remove with a primitive is rejected, remove without one is accepted.
220
+ 15. Malformed sources and artifact envelopes.
221
+ 16. Overlay tests: root frame and item order, determinism, independence
222
+ from interpretation, no forbidden content, escaping of malicious text,
223
+ and a zero-length arrow.
224
+ 3. `tests/unit/visualAnnotationIdentity.test.ts` covers:
225
+ 1. The hex format of the request identity.
226
+ 2. The same content gives the same identity.
227
+ 3. Key insertion order does not change the identity.
228
+ 4. Item order does change it.
229
+ 5. Changes to the source, coordinates, association, interpretation, or
230
+ supersession change it.
231
+ 6. Timestamp and output location are excluded.
232
+ 7. Instance identity is fresh on every call.
233
+ 4. `tests/unit/visualAnnotationArtifactWriter.test.ts` covers:
234
+ 1. A successful write, with the exact directory name, `manifest.json`, and
235
+ `annotation-overlay.svg`.
236
+ 2. Reader round trips for runtime and reference artifacts.
237
+ 3. Refusal to overwrite an existing directory.
238
+ 4. No source bytes copied into the annotation directory.
239
+ 5. No temporary directory after success, including a stale one.
240
+ 6. No temporary directory after a filesystem failure.
241
+ 7. Refusal on an overlay SHA mismatch.
242
+ 5. `tests/unit/visualAnnotationArtifactWriterFailure.test.ts` covers the
243
+ section 19 failure cases:
244
+ 1. Case 1: an invalid artifact is refused.
245
+ 2. Case 2: an existing final directory is left unchanged.
246
+ 3. Case 3: the manifest write fails after the overlay write. The test
247
+ checks write order, that no artifact appears, and that temp is cleaned.
248
+ 4. Case 4: the atomic rename fails.
249
+ 5. Case 5: malformed JSON, plus a missing manifest.
250
+ 6. Case 6: a structurally invalid artifact and an unsupported schema version.
251
+ 7. Case 7: a missing overlay, plus an overlay path that is a directory.
252
+ 8. Case 8: an overlay SHA mismatch.
253
+ 9. Case 9: malicious note text is persisted as escaped SVG, and the
254
+ manifest text is preserved.
255
+ 6. `tests/unit/visualAnnotationPersistence.test.ts` covers:
256
+ 1. Runtime persistence: identity, producer, provenance, overlay metadata,
257
+ overlay SHA, and a reader round trip.
258
+ 2. External-reference persistence.
259
+ 3. Saving the same content twice gives the same request identity and a
260
+ fresh `annotationId`.
261
+ 4. `supersedesAnnotationId` is carried forward, and the prior artifact's
262
+ bytes are unchanged.
263
+ 5. Invalid content, an empty supersedes value, and unsafe output locations
264
+ are refused, and nothing is written.
265
+
266
+ The focused run passed: 5 test files and 59 tests.
267
+
268
+ ## 9. Validation
269
+
270
+ Every command below was actually run on Windows in the repository root.
271
+
272
+ 1. `npm run typecheck`: PASS (exit 0)
273
+ 2. `npm run lint`: PASS (exit 0)
274
+ 3. `npm test`: PASS (73 test files and 1239 tests passed)
275
+ 4. `npm run build`: PASS (exit 0, TypeScript build plus viewer Vite/PWA build)
276
+ 5. `npm run check:docs`: PASS ("Documentation check passed (17 required files).")
277
+ 6. `npm pack --dry-run`: PASS (333 files, 856.2 kB package size). The five new
278
+ `dist` modules are included. No agent-control files are included.
279
+
280
+ Additional check: after the build, `node` imported `dist/index.js`. It
281
+ resolved all the new public functions and constants with the frozen values.
282
+
283
+ Skipped: browser tests (`npm run test:browser`) and packed clean-consumer
284
+ proof. Batch 1 changes no browser, viewer, CLI, or package-entry behavior, and
285
+ this prompt does not require them.
286
+
287
+ ## 10. Scope audit
288
+
289
+ 1. viewer source changed: false
290
+ 2. viewer server changed: false
291
+ 3. CLI changed: false
292
+ 4. project workflow changed: false
293
+ 5. contract primitives changed: false
294
+ 6. external-reference schema changed: false
295
+ 7. package version changed: false
296
+
297
+ No dependency was added or changed. No POST route, UI, CLI command, contract
298
+ promotion, reference materialization, or project authoring support was added.
299
+
300
+ ## 11. Changed files
301
+
302
+ 1. `src/domain/visualAnnotation.ts` (added)
303
+ 2. `src/domain/visualAnnotationIdentity.ts` (added)
304
+ 3. `src/artifacts/visualAnnotationArtifactWriter.ts` (added)
305
+ 4. `src/artifacts/visualAnnotationArtifactReader.ts` (added)
306
+ 5. `src/application/visualAnnotationPersistenceService.ts` (added)
307
+ 6. `src/index.ts` (modified, exports only)
308
+ 7. `tests/unit/visualAnnotationFixtures.ts` (added)
309
+ 8. `tests/unit/visualAnnotation.test.ts` (added)
310
+ 9. `tests/unit/visualAnnotationIdentity.test.ts` (added)
311
+ 10. `tests/unit/visualAnnotationArtifactWriter.test.ts` (added)
312
+ 11. `tests/unit/visualAnnotationArtifactWriterFailure.test.ts` (added)
313
+ 12. `tests/unit/visualAnnotationPersistence.test.ts` (added)
314
+ 13. `docs/reports/v0.9-batch1-visual-annotation-foundation.md` (added)
315
+
316
+ ### 11.1 Additional public exports
317
+
318
+ These go beyond the minimum export list:
319
+
320
+ 1. `VISUAL_ANNOTATION_OVERLAY_PATH`
321
+ 2. `isValidVisualAnnotationContent`, the content half of the artifact
322
+ validator. The service uses it before deriving identity.
323
+ 3. `VISUAL_ANNOTATION_MANIFEST_FILENAME` and `VISUAL_ANNOTATION_OVERLAY_FILENAME`
324
+ 4. `computeVisualAnnotationOverlaySha256`, shared by the writer, reader, and
325
+ service.
326
+ 5. Result and options types: `PersistedVisualAnnotationResult`,
327
+ `WriteVisualAnnotationArtifactOptions`, `ReadVisualAnnotationArtifactResult`,
328
+ `PersistVisualAnnotationOptions`, `ApplicationPersistVisualAnnotationResult`.
329
+
330
+ ### 11.2 Generated paths
331
+
332
+ 1. `dist/` was rebuilt by `npm run build`. It is ignored by Git.
333
+ 2. `.my-dev-kit-workflow/adhoc/preserved-local-docs/` holds the preserved
334
+ local retrieval report. It is ignored by Git.
335
+ 3. Unit tests create temporary directories with `mkdtemp` under the OS temp
336
+ directory, following the existing test convention. Each test removes its
337
+ own directories.
338
+ 4. Validation logs were written to the session scratchpad, outside the
339
+ repository.
340
+
341
+ ### 11.3 Remaining risks
342
+
343
+ 1. The local retrieval report is hidden from Git by `skip-worktree`. A later
344
+ pull that changes the tracked version of that file will stop until the
345
+ flag is cleared.
346
+ 2. Resolving targets and regions across artifacts, and checking revision
347
+ lineage, are deferred to later batches by design.
348
+
349
+ ## 12. Remaining next step
350
+
351
+ v0.9 Prompt 2 — Viewer discovery, project authoring boundary, and secure POST API