@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.
- package/CHANGELOG.md +57 -0
- package/README.md +107 -7
- package/dist/application/projectWorkflowService.d.ts +18 -1
- package/dist/application/projectWorkflowService.js +40 -2
- package/dist/application/projectWorkflowService.js.map +1 -1
- package/dist/application/visualAnnotationContractPromotionService.d.ts +41 -0
- package/dist/application/visualAnnotationContractPromotionService.js +143 -0
- package/dist/application/visualAnnotationContractPromotionService.js.map +1 -0
- package/dist/application/visualAnnotationPersistenceService.d.ts +34 -0
- package/dist/application/visualAnnotationPersistenceService.js +68 -0
- package/dist/application/visualAnnotationPersistenceService.js.map +1 -0
- package/dist/application/visualAnnotationReferenceMaterializationService.d.ts +53 -0
- package/dist/application/visualAnnotationReferenceMaterializationService.js +194 -0
- package/dist/application/visualAnnotationReferenceMaterializationService.js.map +1 -0
- package/dist/artifacts/visualAnnotationArtifactReader.d.ts +19 -0
- package/dist/artifacts/visualAnnotationArtifactReader.js +66 -0
- package/dist/artifacts/visualAnnotationArtifactReader.js.map +1 -0
- package/dist/artifacts/visualAnnotationArtifactWriter.d.ts +42 -0
- package/dist/artifacts/visualAnnotationArtifactWriter.js +85 -0
- package/dist/artifacts/visualAnnotationArtifactWriter.js.map +1 -0
- package/dist/cli.js +464 -454
- package/dist/cli.js.map +1 -1
- package/dist/domain/visualAnnotation.d.ts +217 -0
- package/dist/domain/visualAnnotation.js +584 -0
- package/dist/domain/visualAnnotation.js.map +1 -0
- package/dist/domain/visualAnnotationIdentity.d.ts +17 -0
- package/dist/domain/visualAnnotationIdentity.js +47 -0
- package/dist/domain/visualAnnotationIdentity.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/projectWorkflow/projectPaths.d.ts +9 -0
- package/dist/projectWorkflow/projectPaths.js +21 -0
- package/dist/projectWorkflow/projectPaths.js.map +1 -1
- package/dist/viewer/assets/{index-CN_yb9Uf.css → index-BN41MI7m.css} +1 -1
- package/dist/viewer/assets/index-CkKXnlrI.js +9 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer/sw.js +1 -1
- package/dist/viewerServer/annotationAuthoring.d.ts +64 -0
- package/dist/viewerServer/annotationAuthoring.js +230 -0
- package/dist/viewerServer/annotationAuthoring.js.map +1 -0
- package/dist/viewerServer/annotationContractPromotion.d.ts +51 -0
- package/dist/viewerServer/annotationContractPromotion.js +105 -0
- package/dist/viewerServer/annotationContractPromotion.js.map +1 -0
- package/dist/viewerServer/annotationReferenceMaterialization.d.ts +40 -0
- package/dist/viewerServer/annotationReferenceMaterialization.js +91 -0
- package/dist/viewerServer/annotationReferenceMaterialization.js.map +1 -0
- package/dist/viewerServer/authoringSecurity.d.ts +59 -0
- package/dist/viewerServer/authoringSecurity.js +112 -0
- package/dist/viewerServer/authoringSecurity.js.map +1 -0
- package/dist/viewerServer/evidence/annotationView.d.ts +28 -0
- package/dist/viewerServer/evidence/annotationView.js +43 -0
- package/dist/viewerServer/evidence/annotationView.js.map +1 -0
- package/dist/viewerServer/evidence/classify.d.ts +3 -1
- package/dist/viewerServer/evidence/classify.js +12 -0
- package/dist/viewerServer/evidence/classify.js.map +1 -1
- package/dist/viewerServer/evidence/discovery.d.ts +2 -0
- package/dist/viewerServer/evidence/discovery.js +6 -0
- package/dist/viewerServer/evidence/discovery.js.map +1 -1
- package/dist/viewerServer/evidence/handles.js +1 -0
- package/dist/viewerServer/evidence/handles.js.map +1 -1
- package/dist/viewerServer/evidence/index.d.ts +29 -0
- package/dist/viewerServer/evidence/index.js +43 -1
- package/dist/viewerServer/evidence/index.js.map +1 -1
- package/dist/viewerServer/evidence/mediaResolver.d.ts +1 -1
- package/dist/viewerServer/evidence/mediaResolver.js +28 -2
- package/dist/viewerServer/evidence/mediaResolver.js.map +1 -1
- package/dist/viewerServer/evidence/projection.d.ts +5 -1
- package/dist/viewerServer/evidence/projection.js +19 -0
- package/dist/viewerServer/evidence/projection.js.map +1 -1
- package/dist/viewerServer/httpServer.d.ts +13 -2
- package/dist/viewerServer/httpServer.js +278 -4
- package/dist/viewerServer/httpServer.js.map +1 -1
- package/dist/viewerServer/viewerService.d.ts +8 -0
- package/dist/viewerServer/viewerService.js +38 -2
- package/dist/viewerServer/viewerService.js.map +1 -1
- package/docs/ARCHITECTURE.md +108 -21
- package/docs/CI_CD.md +57 -1
- package/docs/COMMANDS.md +44 -4
- package/docs/CONTRACTS.md +78 -8
- package/docs/CURRENT_STATE.md +157 -35
- package/docs/DEVELOPMENT.md +8 -3
- package/docs/PROJECT_DESCRIPTION.md +4 -1
- package/docs/PROJECT_MILESTONES.md +4 -0
- package/docs/PROJECT_OVERVIEW.md +41 -17
- package/docs/QUICKSTART.md +52 -39
- package/docs/RELEASE.md +16 -11
- package/docs/ROADMAP.md +406 -66
- package/docs/SECURITY.md +71 -14
- package/docs/WORKFLOWS.md +151 -23
- package/docs/plans/v0.9-implementation-plan.md +1529 -0
- package/docs/reports/v0.9-architecture-retrieval.md +567 -0
- package/docs/reports/v0.9-batch1-visual-annotation-foundation.md +351 -0
- package/docs/reports/v0.9-batch2-viewer-annotation-authoring-boundary.md +438 -0
- package/docs/reports/v0.9-batch3-runtime-screenshot-annotation-authoring.md +412 -0
- package/docs/reports/v0.9-batch4-external-reference-annotation-authoring.md +452 -0
- package/docs/reports/v0.9-batch5-runtime-intent-contract-promotion.md +535 -0
- package/docs/reports/v0.9-batch6-reference-materialization.md +514 -0
- package/docs/reports/v0.9-batch7-integrated-acceptance.md +644 -0
- package/docs/reports/v0.9-demo-foundation.md +589 -0
- package/docs/reports/v0.9-final-pre-release-readiness.md +209 -0
- package/docs/reports/v0.9-final-readiness-corrections.md +530 -0
- package/docs/reports/v0.9-pre-release-readiness.md +170 -0
- package/docs/reports/v0.9-tutorial-end-to-end-acceptance.md +980 -0
- package/docs/reports/v0.9-tutorial-integration.md +731 -0
- package/package.json +2 -2
- package/dist/viewer/assets/index-D98S1_2d.js +0 -9
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
# v0.9 Batch 6 Report: Reference Materialization
|
|
2
|
+
|
|
3
|
+
## 1. VERDICT
|
|
4
|
+
|
|
5
|
+
PASS_V0_9_BATCH6_REFERENCE_MATERIALIZATION
|
|
6
|
+
|
|
7
|
+
## 2. Repository identity
|
|
8
|
+
|
|
9
|
+
1. Repository: `C:\Users\daile\Projects\my-frontend-observer`
|
|
10
|
+
2. Branch: `master`
|
|
11
|
+
3. Starting HEAD: `44415bc652f73e44bbfd5c457edf7f0f7daf2b5d`
|
|
12
|
+
4. Ending HEAD before the final commit: `44415bc652f73e44bbfd5c457edf7f0f7daf2b5d`
|
|
13
|
+
5. Package version: `0.8.1` (unchanged in `package.json` and `package-lock.json`)
|
|
14
|
+
6. Viewer protocol version: `1.3.0` (was `1.2.0`)
|
|
15
|
+
|
|
16
|
+
## 3. Prompt 5 entry gate
|
|
17
|
+
|
|
18
|
+
1. Prompt 5 verdict: `PASS_V0_9_BATCH5_RUNTIME_INTENT_CONTRACT_PROMOTION`
|
|
19
|
+
2. Prompt 5 commit: `44415bc652f73e44bbfd5c457edf7f0f7daf2b5d`
|
|
20
|
+
3. Viewer protocol at entry: `1.2.0`
|
|
21
|
+
4. Annotation schema: `1.0.0` (unchanged)
|
|
22
|
+
5. External-reference schema: `1.0.0` (unchanged)
|
|
23
|
+
6. Preflight found a clean tracked worktree on `master` at the required HEAD.
|
|
24
|
+
7. `git ls-files -v docs/reports/v0.9-architecture-retrieval.md` printed `S`
|
|
25
|
+
at entry and before commit. The `skip-worktree` state was preserved. The
|
|
26
|
+
file was not restored, overwritten, deleted, or committed. No pull,
|
|
27
|
+
rebase, reset, stash, or clean was run.
|
|
28
|
+
|
|
29
|
+
## 4. Materializable intent boundary
|
|
30
|
+
|
|
31
|
+
1. Only confirmed `reference-region` (`create` or `refine`) and confirmed
|
|
32
|
+
`reference-requirement` items can be materialized.
|
|
33
|
+
2. `referenceMaterializationBlockReason` in the new application service is
|
|
34
|
+
the single server rule:
|
|
35
|
+
1. uninterpreted items are refused;
|
|
36
|
+
2. candidate items are refused;
|
|
37
|
+
3. `inspect` and `asset-sensitive` are refused as informational intent;
|
|
38
|
+
4. runtime `change` intent is refused as not external-reference intent.
|
|
39
|
+
3. Only the explicitly selected item ids are used. Unselected items never
|
|
40
|
+
contribute, even when they are confirmed.
|
|
41
|
+
4. Selection is atomic. An empty, oversized (more than 100), duplicate, or
|
|
42
|
+
unknown selection, or any blocked item, rejects the whole request before
|
|
43
|
+
any write.
|
|
44
|
+
5. The annotation must be saved. The API takes a saved annotation handle only,
|
|
45
|
+
and the UI disables materialization while the draft is unsaved or dirty.
|
|
46
|
+
|
|
47
|
+
## 5. Source reference validation
|
|
48
|
+
|
|
49
|
+
The service `materializeVisualAnnotationReference` checks, in order:
|
|
50
|
+
|
|
51
|
+
1. The annotation passes the canonical `isValidVisualAnnotationArtifact`.
|
|
52
|
+
2. `annotation.source.kind` is `external-reference`. A runtime annotation is
|
|
53
|
+
`invalid-source`.
|
|
54
|
+
3. The supplied source passes the canonical
|
|
55
|
+
`isValidExternalReferenceArtifact`.
|
|
56
|
+
4. The source exactly matches the annotation source identity:
|
|
57
|
+
`referenceId`, `referenceRequestId`, schema version, lifecycle, image owner
|
|
58
|
+
id, image SHA-256, and coordinate width and height. For an approved source
|
|
59
|
+
the image fields come from `sourceReference.image`. A mismatch is
|
|
60
|
+
`source-mismatch`.
|
|
61
|
+
5. The supplied `sourceReferenceRoot` is read through the canonical
|
|
62
|
+
`readExternalReferenceArtifact` and must hold the same `referenceId`.
|
|
63
|
+
This keeps canonical supersession tied to the verified source.
|
|
64
|
+
|
|
65
|
+
## 6. Source image resolution and verification
|
|
66
|
+
|
|
67
|
+
1. The route never builds an image path from browser data or from the
|
|
68
|
+
annotation's image owner id.
|
|
69
|
+
2. The route reads image bytes only through the existing safe
|
|
70
|
+
`resolveMedia` boundary:
|
|
71
|
+
1. `image` role for an imported source;
|
|
72
|
+
2. `source-image` role for an approved source (the owning imported image).
|
|
73
|
+
3. The source artifact root comes from the source's own viewer handle through
|
|
74
|
+
`decodeArtifactHandle` and `resolveContainedDir`.
|
|
75
|
+
4. The service recomputes SHA-256 over the supplied bytes and requires it to
|
|
76
|
+
equal the source image SHA-256.
|
|
77
|
+
5. The bytes are passed unchanged to `importExternalReference`. Nothing is
|
|
78
|
+
transcoded, recompressed, or rasterized. Annotation marks are never baked
|
|
79
|
+
into the image.
|
|
80
|
+
|
|
81
|
+
## 7. Region composition
|
|
82
|
+
|
|
83
|
+
1. Final regions start from a copy of `sourceReference.regions ?? []`. The
|
|
84
|
+
source array and its region objects are never mutated.
|
|
85
|
+
2. Selected refinements are applied first, in place.
|
|
86
|
+
3. Selected creates are then appended in selection order.
|
|
87
|
+
4. The final set is validated with the canonical
|
|
88
|
+
`isValidReferenceRegions(finalRegions, image.width, image.height)`. A
|
|
89
|
+
failure is `invalid-materialized-reference` and nothing is written.
|
|
90
|
+
|
|
91
|
+
## 8. Region create behavior
|
|
92
|
+
|
|
93
|
+
1. The confirmed `intent.region` is used exactly: id casing and rectangle are
|
|
94
|
+
kept, and no geometry is inferred from the mark.
|
|
95
|
+
2. A create id that case-insensitively matches an existing source region is
|
|
96
|
+
rejected.
|
|
97
|
+
3. Two selected creates with case-insensitively equal ids are rejected.
|
|
98
|
+
4. Nothing is renamed.
|
|
99
|
+
|
|
100
|
+
## 9. Region refine behavior
|
|
101
|
+
|
|
102
|
+
1. A refine must target a region that exists in the selected source
|
|
103
|
+
reference. Ids match case-insensitively, as canonical region ids do.
|
|
104
|
+
2. The refined region keeps its source id spelling and its position. Only the
|
|
105
|
+
rectangle changes. Unrelated regions keep their order and geometry.
|
|
106
|
+
3. Two selected refinements of the same source region are rejected. Item
|
|
107
|
+
order never chooses a winner.
|
|
108
|
+
4. Create then refine of the same new region in one request is rejected,
|
|
109
|
+
because the refine target is not a source region.
|
|
110
|
+
|
|
111
|
+
## 10. Requirement composition
|
|
112
|
+
|
|
113
|
+
1. Requirements are composed after regions, so a selected requirement may use
|
|
114
|
+
a region created in the same request.
|
|
115
|
+
2. Each selected `intent.requirement` is validated with the canonical
|
|
116
|
+
`isValidRawReferenceRequirement` and is not reinterpreted.
|
|
117
|
+
3. A requirement that references a region that is not in the final set (for
|
|
118
|
+
example an unselected create) is rejected by the canonical
|
|
119
|
+
`isValidReferenceRequirements`.
|
|
120
|
+
4. A selected `region-relationship` requirement must hold for the final
|
|
121
|
+
geometry. The service checks it through the canonical
|
|
122
|
+
`deriveReferenceRequirementExpectation`. A contradicted relationship is
|
|
123
|
+
`invalid-materialized-reference`. This was needed because
|
|
124
|
+
`importExternalReference` validates relationship subjects structurally but
|
|
125
|
+
not against geometry.
|
|
126
|
+
5. `region-measurement` requirements persist only the raw subject and
|
|
127
|
+
tolerance. No measured value is stored.
|
|
128
|
+
6. Duplicates and conflicts are left to the canonical
|
|
129
|
+
`buildReferenceRequirement` and `isValidReferenceRequirements`. Nothing is
|
|
130
|
+
silently dropped.
|
|
131
|
+
|
|
132
|
+
## 11. Existing requirement preservation
|
|
133
|
+
|
|
134
|
+
1. Source requirements stay first, in their existing order.
|
|
135
|
+
2. A private `toRawReferenceRequirement` copies only `category`,
|
|
136
|
+
`expectedDependentMode`, `subject`, and `tolerance`. `requirementId` is
|
|
137
|
+
never copied.
|
|
138
|
+
3. The canonical import recomputes the ids. A unit test proves the ids of
|
|
139
|
+
unchanged source requirements are identical in the new reference.
|
|
140
|
+
4. Selected new requirements are appended in `selectedItemIds` order.
|
|
141
|
+
|
|
142
|
+
## 12. Applicability and label preservation
|
|
143
|
+
|
|
144
|
+
1. `sourceReference.applicability` is passed through exactly when present and
|
|
145
|
+
omitted when absent. The annotation never changes viewport, theme,
|
|
146
|
+
application state, or authenticated state.
|
|
147
|
+
2. `sourceReference.provenance.label` is passed through when present. When the
|
|
148
|
+
source has no label, none is invented. Viewer alias text is never used.
|
|
149
|
+
|
|
150
|
+
## 13. Canonical external-reference import
|
|
151
|
+
|
|
152
|
+
1. The new reference is persisted by exactly one call to the canonical
|
|
153
|
+
`importExternalReference(imageBytes, { outputLocation, cwd, label,
|
|
154
|
+
supersedesReferenceRoot, regions, requirements, applicability })`.
|
|
155
|
+
2. `referenceRequestId` and `referenceId` are exactly the canonical service
|
|
156
|
+
output. Neither is constructed by Observer code outside that service.
|
|
157
|
+
3. Import diagnostics `invalid-reference-region`,
|
|
158
|
+
`invalid-reference-requirement`, and `invalid-reference-applicability` map
|
|
159
|
+
to `invalid-materialized-reference`. Any other failure maps to
|
|
160
|
+
`persistence-failure`.
|
|
161
|
+
4. `importExternalReference` and the external-reference writer were not
|
|
162
|
+
changed. No `BLOCKED_V0_9_BATCH6_CANONICAL_REFERENCE_SERVICE_CONFLICT` was
|
|
163
|
+
needed.
|
|
164
|
+
5. New project path helpers in `src/projectWorkflow/projectPaths.ts`:
|
|
165
|
+
`projectReferencesRoot(projectRoot)` and `referenceOutputLocation()`
|
|
166
|
+
(`.frontend-observer/evidence/references`). Existing references are not
|
|
167
|
+
migrated.
|
|
168
|
+
|
|
169
|
+
## 14. Supersession and lifecycle
|
|
170
|
+
|
|
171
|
+
1. `supersedesReferenceRoot` is the verified source root, so the canonical
|
|
172
|
+
import sets `supersedesReferenceId` to the selected source `referenceId`.
|
|
173
|
+
2. For an approved source this is the approved reference id, not the imported
|
|
174
|
+
image owner id. Unit and browser tests prove it.
|
|
175
|
+
3. The new lifecycle is always `imported`, even from an approved source.
|
|
176
|
+
4. Identical inputs give the same canonical `referenceRequestId` and a fresh
|
|
177
|
+
distinct `referenceId` (unit-tested).
|
|
178
|
+
5. Source manifests and images are byte-identical after materialization. For
|
|
179
|
+
an approved source both the approved directory and the owning imported
|
|
180
|
+
directory were snapshotted.
|
|
181
|
+
|
|
182
|
+
## 15. Materialization API
|
|
183
|
+
|
|
184
|
+
1. Route: `POST /api/annotations/:handle/materialize-reference`, in
|
|
185
|
+
`src/viewerServer/httpServer.ts`. The use case lives in the new
|
|
186
|
+
`src/viewerServer/annotationReferenceMaterialization.ts` so the HTTP layer
|
|
187
|
+
stays thin.
|
|
188
|
+
2. It uses the shared Prompt 2/5 gate `readAuthoringJsonRequest` (Host,
|
|
189
|
+
Origin, token, JSON content type, content encoding, body limit) and the
|
|
190
|
+
shared session write queue `runSerializedAuthoringWrite`. No second parser
|
|
191
|
+
or queue exists.
|
|
192
|
+
3. The body is exactly `{ itemIds }`. The `itemIds` rule is now one shared
|
|
193
|
+
helper, `parseAuthoringItemIds` in `annotationAuthoring.ts`: a non-empty
|
|
194
|
+
array of at most 100 unique non-empty strings. The promotion parser uses
|
|
195
|
+
the same helper, with identical behavior and messages. Unknown fields
|
|
196
|
+
return 400.
|
|
197
|
+
4. Resolution:
|
|
198
|
+
1. `getAnnotationView` resolves the annotation and its exact source handle.
|
|
199
|
+
2. The source must be `available` with family
|
|
200
|
+
`external-reference-imported` or `external-reference-approved`.
|
|
201
|
+
3. `loadArtifactByHandle` loads the source artifact.
|
|
202
|
+
4. Image bytes and the source root are resolved as in section 6.
|
|
203
|
+
5. The canonical service is called once with `referenceOutputLocation()`
|
|
204
|
+
and `cwd` set to the authoring project root.
|
|
205
|
+
5. Success returns 201 with exactly `ok`, `referenceId`, `referenceRequestId`,
|
|
206
|
+
`handle` (`external-reference-imported:references%2F<referenceId>`),
|
|
207
|
+
`lifecycle: 'imported'`, `supersedesReferenceId`, `regionCount`,
|
|
208
|
+
`requirementCount`, and `approvalRequired: true`. It contains no paths, no
|
|
209
|
+
project root, and no token.
|
|
210
|
+
6. Failure status mapping:
|
|
211
|
+
1. 400: malformed handle, invalid JSON, or invalid body shape.
|
|
212
|
+
2. 403: authoring or security failure, including a read-only viewer.
|
|
213
|
+
3. 404: unknown annotation, source reference unavailable, or source image
|
|
214
|
+
unavailable.
|
|
215
|
+
4. 409: handle is not a visual annotation, runtime annotation, invalid
|
|
216
|
+
source, or source mismatch.
|
|
217
|
+
5. 413: body too large.
|
|
218
|
+
6. 415: wrong content type or content encoding.
|
|
219
|
+
7. 422: unsupported or unconfirmed selection, invalid region or requirement
|
|
220
|
+
composition, stale relationship, or create/refine conflict.
|
|
221
|
+
8. 500: image read failure or persistence failure.
|
|
222
|
+
9. 405 with `Allow: POST` for GET and HEAD on the route. PUT, PATCH, and
|
|
223
|
+
DELETE keep the existing global 405.
|
|
224
|
+
7. `VIEWER_PROTOCOL_VERSION` is `1.3.0`. The allowed POST surface is exactly
|
|
225
|
+
`POST /api/annotations`, `POST /api/annotations/:handle/promote-contract`,
|
|
226
|
+
and `POST /api/annotations/:handle/materialize-reference`.
|
|
227
|
+
8. `materializeVisualAnnotationReference` and its options, result, and failure
|
|
228
|
+
code types are exported from `src/index.ts`.
|
|
229
|
+
|
|
230
|
+
## 16. Viewer materialization UI
|
|
231
|
+
|
|
232
|
+
1. `ReferenceAnnotationPanel` has a new "Confirmed reference intent" section,
|
|
233
|
+
shown only when authoring is available.
|
|
234
|
+
2. It lists reference-region, reference-requirement, inspect, and
|
|
235
|
+
asset-sensitive items.
|
|
236
|
+
1. Only confirmed region and requirement items have enabled checkboxes.
|
|
237
|
+
2. Informational items are disabled with "Informational annotation intent
|
|
238
|
+
is not materialized into the external-reference contract."
|
|
239
|
+
3. Candidate items are disabled with "Candidate intent must be confirmed
|
|
240
|
+
before materialization."
|
|
241
|
+
3. While the draft is unsaved or dirty, the section shows "Save the annotation
|
|
242
|
+
before materializing reference intent." and the button stays disabled.
|
|
243
|
+
4. The button is "Materialize selected into new reference revision".
|
|
244
|
+
5. The warning is always shown: "This creates a new imported reference
|
|
245
|
+
revision. The current reference remains unchanged. The new reference is
|
|
246
|
+
not approved automatically."
|
|
247
|
+
6. Success shows the new reference id, lifecycle imported, supersedes,
|
|
248
|
+
region and requirement counts, approval required, and "The new reference
|
|
249
|
+
is imported but not approved. Use the existing explicit approval workflow
|
|
250
|
+
when ready."
|
|
251
|
+
7. The selection resets after success and when the loaded annotation changes.
|
|
252
|
+
8. The viewed reference is never switched. The new reference is discoverable
|
|
253
|
+
through the normal evidence index.
|
|
254
|
+
9. The new hook `viewer/src/hooks/useAnnotationReferenceMaterialization.ts`
|
|
255
|
+
sends the in-memory token only in the authoring header, uses
|
|
256
|
+
`cache: 'no-store'`, never retries, and maps each failure status to a
|
|
257
|
+
bounded message.
|
|
258
|
+
10. The presentation helpers `referenceMaterializationStatus` and
|
|
259
|
+
`isReferenceMaterializationListItem` were added to
|
|
260
|
+
`viewer/src/annotation/referenceIntent.ts`. The server remains
|
|
261
|
+
authoritative.
|
|
262
|
+
11. There is no approval button and no project reference activation.
|
|
263
|
+
|
|
264
|
+
## 17. No-approval/no-config-mutation guarantees
|
|
265
|
+
|
|
266
|
+
1. The materialization path never calls `approveExternalReference`.
|
|
267
|
+
2. Unit, route, and browser tests prove the reference directory gains exactly
|
|
268
|
+
one new imported artifact and no approved sibling.
|
|
269
|
+
3. The route never reads or writes the project config. Route and browser tests
|
|
270
|
+
configure `acceptance.reference.approvedArtifact` and prove
|
|
271
|
+
`frontend-observer.json` is byte-identical after materialization.
|
|
272
|
+
4. `src/projectWorkflow/projectConfig.ts` and its schema are unchanged.
|
|
273
|
+
5. A unit test proves the new imported reference is accepted by the existing
|
|
274
|
+
explicit `approveExternalReference` workflow when run separately.
|
|
275
|
+
|
|
276
|
+
## 18. Existing relationship and adequacy behavior
|
|
277
|
+
|
|
278
|
+
1. A unit test runs the canonical `deriveReferenceRegionRelationships` on the
|
|
279
|
+
new reference and finds the normal `content follows-vertically header`
|
|
280
|
+
relationship.
|
|
281
|
+
2. The same test runs the canonical `deriveReferenceRequirementAdequacy` and
|
|
282
|
+
gets the normal `adequate` result over all requirements.
|
|
283
|
+
3. No annotation-specific relationship, adequacy, fidelity, or contract result
|
|
284
|
+
was added.
|
|
285
|
+
|
|
286
|
+
## 19. Unit tests
|
|
287
|
+
|
|
288
|
+
1. New `tests/unit/visualAnnotationReferenceMaterialization.test.ts` (17
|
|
289
|
+
tests):
|
|
290
|
+
1. Imported source create: regions appended after the source, imported
|
|
291
|
+
lifecycle, supersession, canonical identity, the canonical import called
|
|
292
|
+
exactly once, and source bytes unchanged.
|
|
293
|
+
2. Refine in place with order kept and the source rectangle untouched.
|
|
294
|
+
3. Case-insensitive refine that keeps the source id spelling.
|
|
295
|
+
4. Create plus requirement succeeds. The requirement alone (unselected
|
|
296
|
+
create) is rejected with no write.
|
|
297
|
+
5. Existing requirements stay first with identical recomputed ids, and new
|
|
298
|
+
requirements follow selection order.
|
|
299
|
+
6. Selected-only composition.
|
|
300
|
+
7. Applicability, label, image SHA, format, dimensions, and exact bytes are
|
|
301
|
+
preserved.
|
|
302
|
+
8. No invented label or applicability.
|
|
303
|
+
9. Approved source: supersedes the approved id, imported lifecycle, owning
|
|
304
|
+
image, both source directories unchanged, and no approved sibling.
|
|
305
|
+
10. The result is accepted by the existing approval workflow.
|
|
306
|
+
11. Same request identity with a fresh reference id.
|
|
307
|
+
12. Canonical relationship and adequacy output.
|
|
308
|
+
13. Rejections with no import call and no write: candidate, informational
|
|
309
|
+
(inspect and asset-sensitive), uninterpreted, unknown, empty,
|
|
310
|
+
duplicate, and mixed selections.
|
|
311
|
+
14. Create collisions, duplicate refine, and create then refine.
|
|
312
|
+
15. Stale `left-of` relationship after refine is rejected. The same
|
|
313
|
+
relationship with unchanged geometry succeeds.
|
|
314
|
+
16. A duplicate of an existing source requirement is rejected.
|
|
315
|
+
17. Runtime annotation, mismatched source, mismatched root, and wrong image
|
|
316
|
+
bytes.
|
|
317
|
+
2. New `tests/unit/viewerAnnotationReferenceMaterialization.test.ts` (9
|
|
318
|
+
tests):
|
|
319
|
+
1. Closed body parser rules, including the 100-id bound.
|
|
320
|
+
2. Shared gate: bad token, Origin, Host 403, content type and content
|
|
321
|
+
encoding 415, shape and invalid JSON 400, oversized body 413, method
|
|
322
|
+
405. The service is never called and nothing is written.
|
|
323
|
+
3. Read-only viewer 403.
|
|
324
|
+
4. Unknown 404, malformed handle 400, wrong family 409, runtime annotation
|
|
325
|
+
409.
|
|
326
|
+
5. Source image moved away 404, approved source moved away 404.
|
|
327
|
+
6. Candidate, informational, unknown, and uncomposable selections 422 with
|
|
328
|
+
no write.
|
|
329
|
+
7. Selected-only success with an exact bounded key set, no paths or token,
|
|
330
|
+
a loadable `external-reference-imported` handle, imported lifecycle, no
|
|
331
|
+
approved sibling, and byte-identical project config with
|
|
332
|
+
`acceptance.reference` configured.
|
|
333
|
+
8. Approved source supersession and exact image bytes.
|
|
334
|
+
9. Shared write queue: while a materialization is held inside the queue, a
|
|
335
|
+
concurrent annotation save and a contract promotion do not complete.
|
|
336
|
+
Both complete only after it is released.
|
|
337
|
+
3. Updated `tests/unit/viewerAuthoringSecurity.test.ts`: protocol `1.3.0`
|
|
338
|
+
(two assertions), and the materialize path removed from the POST 405 list
|
|
339
|
+
because the route now exists.
|
|
340
|
+
4. Updated `tests/unit/viewerAnnotationContractPromotion.test.ts`: the earlier
|
|
341
|
+
"materialize-reference is 405" assertion now expects 400, because the route
|
|
342
|
+
exists and its closed body rejects `{}`.
|
|
343
|
+
5. Updated `tests/unit/viewerPwaBuild.test.ts` (+1 test): the built service
|
|
344
|
+
worker still has one route with the `/api/` denylist, and precaches no
|
|
345
|
+
annotation or materialization path.
|
|
346
|
+
|
|
347
|
+
## 20. Browser tests
|
|
348
|
+
|
|
349
|
+
New `tests/browser/referenceAnnotationMaterialization.test.ts` has 4
|
|
350
|
+
real-Chromium tests. It reuses `writeReferenceCandidateFixture`,
|
|
351
|
+
`TestResources`, and the Prompt 4 interaction patterns. No new fixture
|
|
352
|
+
framework was added.
|
|
353
|
+
|
|
354
|
+
1. Create, through the real UI, in a project with `acceptance.reference`
|
|
355
|
+
configured:
|
|
356
|
+
1. draw a rectangle, create a candidate region, and confirm;
|
|
357
|
+
2. the unsaved message, disabled button, and warning are shown;
|
|
358
|
+
3. save, select, and materialize.
|
|
359
|
+
It then checks:
|
|
360
|
+
1. 201 with imported lifecycle, approval required, and supersession;
|
|
361
|
+
2. every success UI line;
|
|
362
|
+
3. the selection reset;
|
|
363
|
+
4. canonical regions;
|
|
364
|
+
5. exactly one new directory and no approved sibling;
|
|
365
|
+
6. byte-identical sources and project config;
|
|
366
|
+
7. the new handle in `/api/index` as `external-reference-imported`, while
|
|
367
|
+
the inspector still shows the original reference;
|
|
368
|
+
8. after reload, two imported references in the evidence list.
|
|
369
|
+
2. Refine from an approved source: select `sidebar`, draw, refine, confirm,
|
|
370
|
+
save, and materialize. The new geometry is correct and `header` is
|
|
371
|
+
unchanged. Supersession is the approved id. Image bytes equal the owning
|
|
372
|
+
imported image. Both source directories are unchanged and there is still
|
|
373
|
+
one approved record.
|
|
374
|
+
3. Create plus requirement, selected only: two confirmed creates and a
|
|
375
|
+
confirmed protected `region-a width` requirement with an
|
|
376
|
+
absolute-reference-px 4 tolerance. Selecting `region-a` and the
|
|
377
|
+
requirement materializes both. `region-b` is absent.
|
|
378
|
+
4. Informational and candidate: confirmed inspect and asset-sensitive items
|
|
379
|
+
show the informational reason with disabled checkboxes. A candidate create
|
|
380
|
+
is disabled with its reason. Forced API requests for each return 422, and
|
|
381
|
+
no reference is written.
|
|
382
|
+
5. `tests/browser/pwaHardening.test.ts` now also sends a POST to the
|
|
383
|
+
materialization route from the page. It returns 403 with `no-store`, and
|
|
384
|
+
cache storage holds zero `/api/` entries.
|
|
385
|
+
6. Focused run of the new browser test plus the affected
|
|
386
|
+
`referenceAnnotationAuthoring`, `runtimeAnnotationContractPromotion`,
|
|
387
|
+
`referenceCandidateWorkspace`, `referenceBindingFidelityWorkspace`, and
|
|
388
|
+
`pwaHardening` suites: PASS (6 files, 53 tests).
|
|
389
|
+
|
|
390
|
+
## 21. Regression validation
|
|
391
|
+
|
|
392
|
+
Every command below was run on Windows in the repository root.
|
|
393
|
+
|
|
394
|
+
1. Focused unit run of the two new unit suites plus
|
|
395
|
+
`externalReferencePersistenceService`, `externalReferenceRequirements`,
|
|
396
|
+
`externalReferenceRegions`, `externalReferenceRegionRelationships`,
|
|
397
|
+
`viewerReferenceAnnotationModel`, and `evidenceDiscoveryTempDirectories`:
|
|
398
|
+
PASS (8 files, 138 tests)
|
|
399
|
+
2. `npm run typecheck`: PASS
|
|
400
|
+
3. `npm run lint`: PASS. The first run reported one unused test helper, which
|
|
401
|
+
was removed. The rerun passed.
|
|
402
|
+
4. `npm test`: PASS (84 files, 1378 tests)
|
|
403
|
+
5. `npm run build`: PASS
|
|
404
|
+
6. `npm run test:browser`: PASS (25 files, 231 tests, real Chromium)
|
|
405
|
+
7. `npm run test:security`: PASS (unit: 16 files, 167 tests. Browser: 3 files,
|
|
406
|
+
77 tests)
|
|
407
|
+
8. `npm run check:docs`: PASS (17 required files)
|
|
408
|
+
9. `npm pack --dry-run`: PASS (359 files, 934.5 kB, version 0.8.1)
|
|
409
|
+
|
|
410
|
+
## 22. Security regression
|
|
411
|
+
|
|
412
|
+
1. All three authoring POST routes share one gate and one session write
|
|
413
|
+
queue. The Prompt 2 Host, Origin, token, body, content-type,
|
|
414
|
+
content-encoding, and method tests pass. The new route's own gate tests
|
|
415
|
+
pass.
|
|
416
|
+
2. The browser supplies only item ids. It cannot choose the output location,
|
|
417
|
+
source root, image path, or project path. Unknown body fields return 400.
|
|
418
|
+
3. Image bytes are read only through the existing `resolveMedia` containment
|
|
419
|
+
and symlink checks. The source root is resolved only through
|
|
420
|
+
`resolveContainedDir`.
|
|
421
|
+
4. Responses contain no filesystem paths or token. Failures return bounded
|
|
422
|
+
messages and no stack traces.
|
|
423
|
+
5. The PWA service worker does not cache the new route. This is proven both
|
|
424
|
+
at build level and in live Chromium cache storage.
|
|
425
|
+
6. `package.json` (script only): `test:security` now also runs
|
|
426
|
+
`tests/unit/viewerAnnotationReferenceMaterialization.test.ts`. No version
|
|
427
|
+
or dependency changed.
|
|
428
|
+
|
|
429
|
+
## 23. Temporary-directory hardening regression
|
|
430
|
+
|
|
431
|
+
1. The canonical reference writer still uses its existing temporary directory
|
|
432
|
+
and atomic rename. Writer retry behavior was not changed.
|
|
433
|
+
2. The Prompt 5 discovery rule that skips `.tmp-*` directories covers the
|
|
434
|
+
reference writer too. `tests/unit/evidenceDiscoveryTempDirectories.test.ts`
|
|
435
|
+
passes (2 tests), in the focused run and in `npm test` and
|
|
436
|
+
`npm run test:security`.
|
|
437
|
+
3. Browser tests that materialize through the live viewer and then read
|
|
438
|
+
`/api/index` saw only complete artifacts.
|
|
439
|
+
|
|
440
|
+
## 24. Scope audit
|
|
441
|
+
|
|
442
|
+
1. external-reference schema changed: false
|
|
443
|
+
2. annotation schema changed: false
|
|
444
|
+
3. reference approval changed: false
|
|
445
|
+
4. automatic reference approval added: false
|
|
446
|
+
5. project reference acceptance updated: false
|
|
447
|
+
6. project config schema changed: false
|
|
448
|
+
7. alias catalog schema changed: false
|
|
449
|
+
8. runtime contract promotion semantics changed: false
|
|
450
|
+
9. ContractPrimitive vocabulary changed: false
|
|
451
|
+
10. annotation evaluator added: false
|
|
452
|
+
11. reference evaluator added: false
|
|
453
|
+
12. package version changed: false
|
|
454
|
+
13. dependency changed: false
|
|
455
|
+
|
|
456
|
+
No file under `src/domain/` or `src/artifacts/` changed.
|
|
457
|
+
`externalReferencePersistenceService.ts`,
|
|
458
|
+
`visualAnnotationContractPromotionService.ts`, and `projectConfig.ts` are
|
|
459
|
+
unchanged. The promotion route parser now calls the shared `itemIds` helper
|
|
460
|
+
with identical rules and messages. Its tests pass unchanged except for the
|
|
461
|
+
materialize assertion described in section 19. No broad documentation file
|
|
462
|
+
was changed. `dist/`, `node_modules/`, and workflow state are not tracked.
|
|
463
|
+
|
|
464
|
+
## 25. Changed files
|
|
465
|
+
|
|
466
|
+
### 25.1 Added production files
|
|
467
|
+
|
|
468
|
+
1. `src/application/visualAnnotationReferenceMaterializationService.ts`
|
|
469
|
+
2. `src/viewerServer/annotationReferenceMaterialization.ts` (route use case,
|
|
470
|
+
keeps the HTTP layer thin)
|
|
471
|
+
3. `viewer/src/hooks/useAnnotationReferenceMaterialization.ts`
|
|
472
|
+
|
|
473
|
+
### 25.2 Modified production files
|
|
474
|
+
|
|
475
|
+
1. `src/viewerServer/httpServer.ts` (route, status map, protocol 1.3.0)
|
|
476
|
+
2. `src/viewerServer/annotationAuthoring.ts` (shared `parseAuthoringItemIds`
|
|
477
|
+
and `MAX_AUTHORING_ITEM_IDS`, so the new route reuses the Prompt 5 body
|
|
478
|
+
rule instead of copying it)
|
|
479
|
+
3. `src/viewerServer/annotationContractPromotion.ts` (uses the shared helper,
|
|
480
|
+
behavior unchanged)
|
|
481
|
+
4. `src/projectWorkflow/projectPaths.ts`
|
|
482
|
+
5. `src/index.ts`
|
|
483
|
+
6. `viewer/src/components/ReferenceAnnotationPanel.tsx`
|
|
484
|
+
7. `viewer/src/components/ReferenceWorkspace.tsx` (wires the hook and the
|
|
485
|
+
in-memory token into the panel)
|
|
486
|
+
8. `viewer/src/annotation/referenceIntent.ts` (presentation eligibility
|
|
487
|
+
helpers)
|
|
488
|
+
9. `viewer/src/styles/index.css`
|
|
489
|
+
10. `package.json` (`test:security` script only)
|
|
490
|
+
|
|
491
|
+
### 25.3 Tests and report
|
|
492
|
+
|
|
493
|
+
1. Added: `tests/unit/visualAnnotationReferenceMaterialization.test.ts`
|
|
494
|
+
2. Added: `tests/unit/viewerAnnotationReferenceMaterialization.test.ts`
|
|
495
|
+
3. Added: `tests/browser/referenceAnnotationMaterialization.test.ts`
|
|
496
|
+
4. Modified: `tests/unit/viewerAuthoringSecurity.test.ts`
|
|
497
|
+
5. Modified: `tests/unit/viewerAnnotationContractPromotion.test.ts`
|
|
498
|
+
6. Modified: `tests/unit/viewerPwaBuild.test.ts`
|
|
499
|
+
7. Modified: `tests/browser/pwaHardening.test.ts`
|
|
500
|
+
8. Added: `docs/reports/v0.9-batch6-reference-materialization.md`
|
|
501
|
+
|
|
502
|
+
### 25.4 Generated paths
|
|
503
|
+
|
|
504
|
+
Test temporary directories were created under the OS temp directory by the
|
|
505
|
+
existing test resource helpers and removed after each test. Validation logs
|
|
506
|
+
were written to the session scratchpad, outside the repository. `npm run
|
|
507
|
+
build` refreshed the ignored `dist/`. No workflow state was created.
|
|
508
|
+
|
|
509
|
+
## 26. Remaining next step
|
|
510
|
+
|
|
511
|
+
v0.9 Prompt 7: integrated acceptance, packaging, documentation, and
|
|
512
|
+
regression. Prompt 7 owns broad documentation reconciliation for the new
|
|
513
|
+
route, the protocol version 1.3.0, the project reference output location, and
|
|
514
|
+
the materialization UI.
|