@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,535 @@
|
|
|
1
|
+
# v0.9 Batch 5 Report: Runtime Intent and Contract Promotion
|
|
2
|
+
|
|
3
|
+
## 1. VERDICT
|
|
4
|
+
|
|
5
|
+
PASS_V0_9_BATCH5_RUNTIME_INTENT_CONTRACT_PROMOTION
|
|
6
|
+
|
|
7
|
+
## 2. Repository identity
|
|
8
|
+
|
|
9
|
+
1. Repository: `C:\Users\daile\Projects\my-frontend-observer`
|
|
10
|
+
2. Branch: `master`
|
|
11
|
+
3. Starting HEAD: `194c8e3df49017e803c2b99c6cad7d7c7cd69508`
|
|
12
|
+
4. Ending HEAD before the final commit: `194c8e3df49017e803c2b99c6cad7d7c7cd69508`
|
|
13
|
+
5. Package version: `0.8.1` (unchanged in `package.json` and `package-lock.json`)
|
|
14
|
+
6. Viewer protocol version: `1.2.0` (was `1.1.0`)
|
|
15
|
+
|
|
16
|
+
## 3. Prompt 4 entry gate
|
|
17
|
+
|
|
18
|
+
1. Prompt 4 verdict: `PASS_V0_9_BATCH4_EXTERNAL_REFERENCE_ANNOTATION_AUTHORING`
|
|
19
|
+
2. Prompt 4 commit: `194c8e3df49017e803c2b99c6cad7d7c7cd69508`
|
|
20
|
+
3. Viewer protocol at entry: `1.1.0`
|
|
21
|
+
4. Annotation schema: `1.0.0` (unchanged)
|
|
22
|
+
5. Frontend contract 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 and
|
|
26
|
+
the file was not restored, overwritten, or committed. No pull, rebase,
|
|
27
|
+
reset, or clean was run.
|
|
28
|
+
|
|
29
|
+
## 4. Runtime intent vocabulary
|
|
30
|
+
|
|
31
|
+
1. New pure model `viewer/src/annotation/runtimeIntent.ts` builds only the
|
|
32
|
+
already-frozen runtime `VisualAnnotationIntent`.
|
|
33
|
+
2. Operations are exactly `inspect`, `move`, `resize`, `remove`, `preserve`.
|
|
34
|
+
3. Categories are exactly `requested`, `expected-dependent`, `protected`, and
|
|
35
|
+
`preserved`.
|
|
36
|
+
1. `unexpected` is never offered.
|
|
37
|
+
2. If `unexpected` is supplied anyway, construction refuses it
|
|
38
|
+
(unit-tested).
|
|
39
|
+
3. The domain validator is unchanged.
|
|
40
|
+
4. `expected-dependent` requires `required` or `permitted`. For every other
|
|
41
|
+
category the mode is absent.
|
|
42
|
+
5. The model never reads mark geometry, never calls an API, and never
|
|
43
|
+
persists or evaluates anything.
|
|
44
|
+
|
|
45
|
+
## 5. Move mappings
|
|
46
|
+
|
|
47
|
+
Move requires an explicit `runtime-target` association.
|
|
48
|
+
|
|
49
|
+
1. `right` maps to `property-increases x`.
|
|
50
|
+
2. `left` maps to `property-decreases x`.
|
|
51
|
+
3. `down` maps to `property-increases y`.
|
|
52
|
+
4. `up` maps to `property-decreases y`.
|
|
53
|
+
|
|
54
|
+
`minimumDeltaPx` is never set. Arrow direction and drawing position never
|
|
55
|
+
choose the direction. This is browser-verified: an arrow drawn pointing right
|
|
56
|
+
stays `uninterpreted`, and an explicit "move left" gives
|
|
57
|
+
`property-decreases header.x`.
|
|
58
|
+
|
|
59
|
+
## 6. Resize mappings
|
|
60
|
+
|
|
61
|
+
Resize requires an explicit `runtime-target` association.
|
|
62
|
+
|
|
63
|
+
1. `wider` maps to `property-increases width`.
|
|
64
|
+
2. `narrower` maps to `property-decreases width`.
|
|
65
|
+
3. `taller` maps to `property-increases height`.
|
|
66
|
+
4. `shorter` maps to `property-decreases height`.
|
|
67
|
+
|
|
68
|
+
`minimumDeltaPx` is never set.
|
|
69
|
+
|
|
70
|
+
## 7. Preserve mappings
|
|
71
|
+
|
|
72
|
+
1. With a `runtime-target` association, the user picks one property (`x`,
|
|
73
|
+
`y`, `width`, `height`) and a contract tolerance (`exact`, `absolute-px`,
|
|
74
|
+
or `percent`, amount between 0 and 100). The result is
|
|
75
|
+
`property-unchanged-within-tolerance`.
|
|
76
|
+
2. `absolute-px` is labeled "runtime CSS pixels". It is kept distinct from
|
|
77
|
+
the reference vocabulary's `absolute-reference-px`.
|
|
78
|
+
3. With a `runtime-relationship` association, the result is
|
|
79
|
+
`relationship-unchanged` with the association's `relationshipKind`, and
|
|
80
|
+
with `subjectTarget` and `relatedTarget` only when present. Page-level
|
|
81
|
+
relationships get no invented targets.
|
|
82
|
+
4. No preserve UI exists for visibility, clipping, scroll, document width,
|
|
83
|
+
bounds, fit, overlap, or relative width.
|
|
84
|
+
|
|
85
|
+
## 8. Remove unsupported behavior
|
|
86
|
+
|
|
87
|
+
1. `remove` requires a target association and has no `contractPrimitive`.
|
|
88
|
+
2. Once confirmed, the UI shows exactly: "Confirmed but not canonically
|
|
89
|
+
promotable: the current frontend-contract vocabulary has no target-absent
|
|
90
|
+
primitive."
|
|
91
|
+
3. Its promotion checkbox is disabled with that reason.
|
|
92
|
+
4. A forced API promotion returns 422 and writes no contract
|
|
93
|
+
(browser-verified).
|
|
94
|
+
|
|
95
|
+
## 9. Inspect informational behavior
|
|
96
|
+
|
|
97
|
+
1. `inspect` can be bound or unbound.
|
|
98
|
+
2. It can be a candidate and then confirmed.
|
|
99
|
+
3. It is never listed for promotion.
|
|
100
|
+
4. A forced API promotion returns 422 (browser-verified).
|
|
101
|
+
|
|
102
|
+
## 10. Runtime confirmation workflow
|
|
103
|
+
|
|
104
|
+
1. "Set candidate intent" sets `{ state: 'candidate', intent }` only after
|
|
105
|
+
the form is complete and the association is compatible.
|
|
106
|
+
2. When the item is unbound, the UI shows "Select and explicitly associate a
|
|
107
|
+
runtime target or relationship first." and the button stays disabled.
|
|
108
|
+
3. The selected item shows the exact intent as JSON: operation, category,
|
|
109
|
+
mode, and primitive.
|
|
110
|
+
4. The item also shows a promotion status line.
|
|
111
|
+
5. "Confirm runtime intent" is enabled only for a candidate. It sets
|
|
112
|
+
`confirmed` with a new `confirmedAt`.
|
|
113
|
+
6. Nothing confirms automatically: not selecting an intent, association,
|
|
114
|
+
drawing, Save, or the promotion checkbox.
|
|
115
|
+
7. The shared helper `viewer/src/annotation/confirmation.ts` now holds
|
|
116
|
+
`confirmCandidate` and `withdrawChangedConfirmation`. The code moved there
|
|
117
|
+
unchanged from `referenceIntent.ts`, which still re-exports
|
|
118
|
+
`confirmCandidate`. The Prompt 4 unit and browser tests pass unchanged.
|
|
119
|
+
|
|
120
|
+
## 11. Confirmation invalidation
|
|
121
|
+
|
|
122
|
+
1. `useRuntimeAnnotationDraft` now routes every edit through
|
|
123
|
+
`applyRuntimeItemEdit`: reconcile, then withdraw a changed confirmation.
|
|
124
|
+
Edits here are mark moves, note text, association set or clear, and new
|
|
125
|
+
intents.
|
|
126
|
+
2. Reconciliation:
|
|
127
|
+
1. A target change retargets `primitive.target`.
|
|
128
|
+
2. A relationship change rewrites the `relationship-unchanged` primitive.
|
|
129
|
+
3. An incompatible association, or clearing it, sets the change
|
|
130
|
+
interpretation back to `uninterpreted`. It is never coerced.
|
|
131
|
+
3. A confirmed item whose mark, association, or intent changes goes back to
|
|
132
|
+
`candidate` without `confirmedAt`. A no-op edit keeps confirmation.
|
|
133
|
+
4. Browser-verified: changing a confirmed move from `header` to `footer`
|
|
134
|
+
gives `primitive.target: footer` and state candidate. Reconfirmation
|
|
135
|
+
works. Moving the mark again gives candidate.
|
|
136
|
+
|
|
137
|
+
## 12. Promotable-item rules
|
|
138
|
+
|
|
139
|
+
An item is promotable only when all of these hold:
|
|
140
|
+
|
|
141
|
+
1. It is `confirmed`.
|
|
142
|
+
2. `intent.kind` is `change`.
|
|
143
|
+
3. The operation is `move`, `resize`, or `preserve`.
|
|
144
|
+
4. A valid `contractPrimitive` is present, checked with the existing
|
|
145
|
+
`isValidContractPrimitive`.
|
|
146
|
+
5. A runtime association is present.
|
|
147
|
+
6. The primitive matches both the association and the operation:
|
|
148
|
+
1. `move` uses `x` or `y`; `resize` uses `width` or `height`.
|
|
149
|
+
2. Both use increases or decreases on the associated target, with no
|
|
150
|
+
`minimumDeltaPx`.
|
|
151
|
+
3. Preserve on a target uses a property primitive on that target.
|
|
152
|
+
4. Preserve on a relationship uses exactly that relationship.
|
|
153
|
+
|
|
154
|
+
Uninterpreted, candidate, inspect, remove, missing-primitive, unbound, and
|
|
155
|
+
mismatched items are not promotable. The viewer's `runtimePromotionStatus`
|
|
156
|
+
drives presentation only. The server repeats every check.
|
|
157
|
+
|
|
158
|
+
## 13. Annotation-to-contract application service
|
|
159
|
+
|
|
160
|
+
New `src/application/visualAnnotationContractPromotionService.ts`,
|
|
161
|
+
`promoteVisualAnnotationContract(options)`:
|
|
162
|
+
|
|
163
|
+
1. Validates the annotation with the canonical `isValidVisualAnnotationArtifact`.
|
|
164
|
+
2. Requires a `runtime-observation` source. Anything else is
|
|
165
|
+
`unsupported-source`.
|
|
166
|
+
3. Requires the supplied observation to exactly match the source.
|
|
167
|
+
Otherwise it is `source-mismatch`. The fields compared are
|
|
168
|
+
`observationId`, `requestId`, schema version, screenshot recorded and path
|
|
169
|
+
equal, and viewport width and height.
|
|
170
|
+
4. Rejects the whole promotion (`invalid-selection`, nothing written) for any
|
|
171
|
+
of these: empty, more than 100, duplicate, unknown, or any non-promotable
|
|
172
|
+
selected item. It never writes a partial contract.
|
|
173
|
+
5. Clause order follows `selectedItemIds` exactly.
|
|
174
|
+
6. Persists exactly once through `persistPerChangeContract`, which is
|
|
175
|
+
unit-verified with a spy.
|
|
176
|
+
7. The result is a discriminated union with a failure `code` and `reason`,
|
|
177
|
+
consistent with the other application-service result shapes.
|
|
178
|
+
|
|
179
|
+
## 14. Contract identity and clauses
|
|
180
|
+
|
|
181
|
+
1. Each clause is
|
|
182
|
+
`{ clauseId: buildClauseIdentity(primitive), category, expectedDependentMode?, primitive, supportingEvidence }`.
|
|
183
|
+
There is no `supersedesBaselineClauseIds`.
|
|
184
|
+
2. `contractRequestId` is
|
|
185
|
+
`buildFrontendContractRequestIdentity(source.observationId, clauses.map(({ primitive }) => ({ primitive })), [])`.
|
|
186
|
+
3. `contractId` is `buildFrontendContractInstanceIdentity(contractRequestId)`.
|
|
187
|
+
Unit-verified: the same request id with a fresh instance id.
|
|
188
|
+
4. The contract is an ordinary `PerChangeContract` with canonical kind,
|
|
189
|
+
schema version `1.0.0`, and class `change`. It gets no annotation-specific
|
|
190
|
+
fields.
|
|
191
|
+
|
|
192
|
+
## 15. Supporting evidence references
|
|
193
|
+
|
|
194
|
+
Each clause carries exactly these two existing `EvidenceReference` values:
|
|
195
|
+
|
|
196
|
+
1. `visualAnnotation.<annotationId>.source`
|
|
197
|
+
2. `visualAnnotation.<annotationId>.items.<annotationItemId>`
|
|
198
|
+
|
|
199
|
+
The annotation is never embedded (unit and browser verified).
|
|
200
|
+
|
|
201
|
+
## 16. Configured baseline resolution
|
|
202
|
+
|
|
203
|
+
1. The server promotion module reads the project config with
|
|
204
|
+
`readProjectConfig`.
|
|
205
|
+
2. When `acceptance.contract` exists, it resolves `baselineArtifact` with
|
|
206
|
+
`resolveContainedAcceptancePath` and reads it with
|
|
207
|
+
`readPersistentBaselineContract`.
|
|
208
|
+
1. A missing, unsafe, unreadable, or invalid baseline gives 409 and no
|
|
209
|
+
contract.
|
|
210
|
+
2. Otherwise `activeBaselineIds` is `[baseline.baselineId]`.
|
|
211
|
+
3. Without contract acceptance, `activeBaselineIds` is `[]`.
|
|
212
|
+
4. Nothing is inferred from aliases, observations, annotations, existing
|
|
213
|
+
change contracts, or directory names.
|
|
214
|
+
|
|
215
|
+
## 17. Project activation behavior
|
|
216
|
+
|
|
217
|
+
1. `projectPaths.ts` adds `projectContractsRoot(projectRoot)` and
|
|
218
|
+
`contractOutputLocation()`, which returns
|
|
219
|
+
`.frontend-observer/evidence/contracts`.
|
|
220
|
+
2. `projectWorkflowService.ts` adds
|
|
221
|
+
`activateProjectChangeContract(projectRoot, changeArtifactPath)`:
|
|
222
|
+
1. It reads the raw on-disk JSON and validates it.
|
|
223
|
+
2. It requires an existing `acceptance.contract`. Otherwise it returns
|
|
224
|
+
`not-configured` without writing.
|
|
225
|
+
3. It changes only `acceptance.contract.changeArtifact`, keeping key order
|
|
226
|
+
and every other value.
|
|
227
|
+
4. It validates the full updated configuration before writing and never
|
|
228
|
+
writes an invalid one.
|
|
229
|
+
5. It writes atomically with the existing `atomicTextWrite`.
|
|
230
|
+
3. Activation happens only when `activateForCheck` is `true`. The result is
|
|
231
|
+
`not-requested`, `activated`, `not-configured` (with the exact bounded
|
|
232
|
+
reason), or `failed`. A failure never deletes the persisted contract and
|
|
233
|
+
never retries.
|
|
234
|
+
4. Unit-verified: the updated config is re-read through the unchanged
|
|
235
|
+
`check` acceptance helpers (`resolveContainedAcceptancePath` and
|
|
236
|
+
`readPerChangeContract`), and the new contract loads. `projectCheckService.ts`
|
|
237
|
+
was not modified.
|
|
238
|
+
|
|
239
|
+
## 18. Promotion API
|
|
240
|
+
|
|
241
|
+
1. `POST /api/annotations/:handle/promote-contract`. `GET` and `HEAD` on it
|
|
242
|
+
return 405 `Allow: POST`.
|
|
243
|
+
2. `POST /api/annotations/:handle/materialize-reference` still returns 405.
|
|
244
|
+
PUT, PATCH, and DELETE stay unsupported.
|
|
245
|
+
3. The route uses one shared gate, `readAuthoringJsonRequest`, extracted from
|
|
246
|
+
the Prompt 2 save handler and now used by both routes. It covers authoring
|
|
247
|
+
enabled, Host, Origin, token, JSON content type, identity encoding, the
|
|
248
|
+
262144-byte limit, and JSON parsing. There is no second token, session, or
|
|
249
|
+
parser.
|
|
250
|
+
4. The body is closed to `{ itemIds, activateForCheck }`:
|
|
251
|
+
1. `itemIds` is non-empty, at most 100, non-empty strings, unique.
|
|
252
|
+
2. `activateForCheck` is a required boolean.
|
|
253
|
+
3. Unknown fields give 400.
|
|
254
|
+
5. The new module `src/viewerServer/annotationContractPromotion.ts` owns the
|
|
255
|
+
route use case. It was added so the route stays thin.
|
|
256
|
+
1. It resolves the annotation with `getAnnotationView`, which uses
|
|
257
|
+
`loadArtifactByHandle`.
|
|
258
|
+
2. It requires the runtime source. Reference annotations give 409.
|
|
259
|
+
3. It resolves the exact source through the Prompt 2 annotation source
|
|
260
|
+
view plus `loadArtifactByHandle`. A missing source gives 404.
|
|
261
|
+
4. It resolves the configured baseline, calls
|
|
262
|
+
`promoteVisualAnnotationContract` once with `contractOutputLocation()`
|
|
263
|
+
and the project root, and then optionally activates.
|
|
264
|
+
5. It runs through the session's single authoring write queue. That queue
|
|
265
|
+
is the Prompt 2 queue exposed as `runSerializedAuthoringWrite`, so
|
|
266
|
+
promotion never interleaves with saves.
|
|
267
|
+
6. Status mapping:
|
|
268
|
+
1. 201: success.
|
|
269
|
+
2. 400: request shape or malformed handle.
|
|
270
|
+
3. 403: security gate.
|
|
271
|
+
4. 404: unknown annotation or missing source.
|
|
272
|
+
5. 409: not an annotation, a reference annotation, invalid project config,
|
|
273
|
+
invalid configured baseline, or source mismatch.
|
|
274
|
+
6. 413: body too large. 415: media type or encoding.
|
|
275
|
+
7. 422: non-promotable selection.
|
|
276
|
+
8. 500: persistence failure.
|
|
277
|
+
7. The 201 body is exactly
|
|
278
|
+
`{ ok, contractId, contractRequestId, handle, clauseCount, activation }`.
|
|
279
|
+
The handle is `change-contract:contracts%2F<contractId>`. No paths are
|
|
280
|
+
returned.
|
|
281
|
+
8. `VIEWER_PROTOCOL_VERSION` is now `1.2.0`. The Prompt 2 security test was
|
|
282
|
+
updated for the new version and for the now-real promote route. Its 405
|
|
283
|
+
list still includes `materialize-reference`.
|
|
284
|
+
|
|
285
|
+
## 19. Runtime promotion UI
|
|
286
|
+
|
|
287
|
+
1. `RuntimeAnnotationPanel` gains two sections. No runtime controls were
|
|
288
|
+
added to the reference panel.
|
|
289
|
+
1. "Runtime intent": operation, direction, category, mode, property,
|
|
290
|
+
tolerance, "Set candidate intent", the promotion status line, and
|
|
291
|
+
"Confirm runtime intent".
|
|
292
|
+
2. "Confirmed contract intent".
|
|
293
|
+
2. Promotion is disabled with "Save the annotation before promoting contract
|
|
294
|
+
intent." while the draft is dirty or unsaved. The draft is never saved
|
|
295
|
+
silently.
|
|
296
|
+
3. For a saved, clean annotation there is one checkbox per confirmed change
|
|
297
|
+
item, showing operation, category, and primitive summary.
|
|
298
|
+
1. Non-promotable confirmed items such as remove show a disabled checkbox
|
|
299
|
+
and a reason.
|
|
300
|
+
2. Inspect and candidate items are not listed.
|
|
301
|
+
4. "Activate this change contract for project check" defaults to unchecked.
|
|
302
|
+
5. "Promote selected to change contract" sends only the checked item ids, in
|
|
303
|
+
check order, through the new hook `useAnnotationContractPromotion` with the
|
|
304
|
+
in-memory token.
|
|
305
|
+
6. Success shows the contract id, clause count, and activation state in
|
|
306
|
+
words. Local decision: a successful promotion clears the checkbox
|
|
307
|
+
selection so the same items are not promoted again by accident.
|
|
308
|
+
7. Errors show a bounded message per status, keep the draft and
|
|
309
|
+
confirmations, and never retry.
|
|
310
|
+
|
|
311
|
+
## 20. Existing evaluator authority
|
|
312
|
+
|
|
313
|
+
1. Unit test: an annotation over real before/after observations (workspace
|
|
314
|
+
width 600 to 650) is promoted into a contract with
|
|
315
|
+
`resize wider (expected-dependent required)` and
|
|
316
|
+
`preserve height (absolute-px 2)`.
|
|
317
|
+
2. The existing `evaluateFrontendContract` gives the same `overallVerdict`,
|
|
318
|
+
the same clause ids, and the same per-clause statuses (pass, pass) for
|
|
319
|
+
that contract and for an equivalent hand-authored `PerChangeContract`.
|
|
320
|
+
3. A source search of all new and changed Batch 5 source found no PASS/FAIL
|
|
321
|
+
logic and no call to the evaluator. The only hit is a doc comment saying
|
|
322
|
+
the evaluator is the only authority.
|
|
323
|
+
4. No annotation evaluator exists.
|
|
324
|
+
|
|
325
|
+
## 21. Temporary-directory discovery hardening
|
|
326
|
+
|
|
327
|
+
1. Implemented. `src/viewerServer/evidence/discovery.ts` never descends into a
|
|
328
|
+
directory whose basename starts with `.tmp-`, at any depth. The prefix is
|
|
329
|
+
the new exported `WRITER_TEMP_DIRECTORY_PREFIX`. Every canonical writer in
|
|
330
|
+
`src/artifacts/` uses it for its sibling temp directory.
|
|
331
|
+
2. The skipped directory is not read, classified, returned, or deleted.
|
|
332
|
+
3. Final artifact discovery is unchanged:
|
|
333
|
+
1. A normal directory is discovered.
|
|
334
|
+
2. The same artifact renamed from `.tmp-abc` to `final-abc` is discovered.
|
|
335
|
+
3. A name like `x.tmp-y` is still discovered.
|
|
336
|
+
4. All existing discovery tests pass.
|
|
337
|
+
4. Structural test (`tests/unit/evidenceDiscoveryTempDirectories.test.ts`):
|
|
338
|
+
manifests under `.tmp-top`, `annotations/.tmp-abc`, `contracts/.tmp-def`,
|
|
339
|
+
and `references/nested/.tmp-ghi` are not discovered. This test failed
|
|
340
|
+
before the change and passes after it.
|
|
341
|
+
5. Concurrency regression: 25 atomic annotation saves while
|
|
342
|
+
`buildEvidenceIndexMetadata` runs continuously. Before committing, a
|
|
343
|
+
heavier ad-hoc probe also ran against the unfixed code: 4 concurrent
|
|
344
|
+
refresh loops and 60 saves of 40 items each. The probe file was deleted.
|
|
345
|
+
Neither reproduced `EPERM` in-process, before or after the change.
|
|
346
|
+
6. Conclusion: the Windows writer/discovery race is structurally mitigated.
|
|
347
|
+
Discovery can no longer hold handles inside a writer's temp directory. It
|
|
348
|
+
is not claimed as proven fixed, because no deterministic reproduction was
|
|
349
|
+
available.
|
|
350
|
+
7. The concurrency test remains as a regression guard. The writers were not
|
|
351
|
+
changed and no retry loop was added.
|
|
352
|
+
|
|
353
|
+
## 22. Unit tests
|
|
354
|
+
|
|
355
|
+
1. `tests/unit/viewerRuntimeIntentModel.test.ts` (15 tests):
|
|
356
|
+
1. Vocabulary and `unexpected` refused.
|
|
357
|
+
2. All 4 move and all 4 resize mappings.
|
|
358
|
+
3. Arrow geometry never used.
|
|
359
|
+
4. Preserve property, tolerance bounds, pairwise and page-level
|
|
360
|
+
relationships.
|
|
361
|
+
5. Remove without a primitive, inspect.
|
|
362
|
+
6. Expected-dependent mode rule.
|
|
363
|
+
7. Unbound and incompatible combinations refused.
|
|
364
|
+
8. Built items accepted by the canonical annotation validator.
|
|
365
|
+
9. Retargeting, relationship rewrite, and clearing on incompatible
|
|
366
|
+
association.
|
|
367
|
+
10. Invalidation on move, intent change, and note edit; no-op keeps
|
|
368
|
+
confirmation.
|
|
369
|
+
11. Promotion status, including the exact remove message.
|
|
370
|
+
2. `tests/unit/visualAnnotationContractPromotion.test.ts` (5 tests):
|
|
371
|
+
1. Canonical contract equality, including clause ids, request id, evidence
|
|
372
|
+
paths, selection order, and selected-only.
|
|
373
|
+
2. Persistence called once, fresh contract id, `activeBaselineIds`
|
|
374
|
+
preserved.
|
|
375
|
+
3. Expected-dependent mode, no `supersedesBaselineClauseIds`.
|
|
376
|
+
4. Reference source rejected, and four source-identity mismatches.
|
|
377
|
+
5. Ten invalid selections rejected atomically, and evaluator authority.
|
|
378
|
+
3. `tests/unit/viewerAnnotationContractPromotion.test.ts` (9 tests):
|
|
379
|
+
1. Security gate reuse: token, Origin, Host, 415, 413, closed shape, 405,
|
|
380
|
+
and materialize still 405.
|
|
381
|
+
2. Read-only viewer 403.
|
|
382
|
+
3. Unknown, malformed, wrong family, and reference annotation.
|
|
383
|
+
4. Invalid configured baseline 409, source gone 404.
|
|
384
|
+
5. Unsupported, mixed, or unknown selection 422 with no contract.
|
|
385
|
+
6. Selected-only success with bounded response, no paths, loadable change
|
|
386
|
+
contract, config untouched.
|
|
387
|
+
7. `not-configured` activation.
|
|
388
|
+
8. Configured baseline id plus `activated` changing only `changeArtifact`,
|
|
389
|
+
with the check acceptance path readable.
|
|
390
|
+
9. `failed` activation (mocked writer failure) keeps the contract.
|
|
391
|
+
4. `tests/unit/projectWorkflow.test.ts` (+4 tests): contract path helpers;
|
|
392
|
+
activation updates only `changeArtifact` with key order preserved; no
|
|
393
|
+
acceptance means no mutation; an invalid full config is never written.
|
|
394
|
+
5. `tests/unit/evidenceDiscoveryTempDirectories.test.ts` (2 tests), see
|
|
395
|
+
section 21.
|
|
396
|
+
6. `tests/unit/viewerAuthoringSecurity.test.ts` updated for protocol `1.2.0`
|
|
397
|
+
and the new real POST route.
|
|
398
|
+
|
|
399
|
+
## 23. Browser tests
|
|
400
|
+
|
|
401
|
+
New `tests/browser/runtimeAnnotationContractPromotion.test.ts` has 6
|
|
402
|
+
real-Chromium tests. It reuses `writeInitializedProject` and `TestResources`.
|
|
403
|
+
The file passed on repeated runs.
|
|
404
|
+
|
|
405
|
+
1. Move to contract, and arrow non-inference:
|
|
406
|
+
1. An arrow pointing right is uninterpreted and blocked while unbound.
|
|
407
|
+
2. Associating `header` and choosing move left gives
|
|
408
|
+
`property-decreases header.x`.
|
|
409
|
+
3. A rectangle on `sidebar` with move right gives
|
|
410
|
+
`property-increases sidebar.x`.
|
|
411
|
+
4. Both are confirmed.
|
|
412
|
+
5. Promotion is disabled until saved.
|
|
413
|
+
6. Promotion yields exact clauses, evidence paths, and empty
|
|
414
|
+
`activeBaselineIds`.
|
|
415
|
+
2. Selected only:
|
|
416
|
+
1. Expected-dependent resize wider requires a mode (permitted).
|
|
417
|
+
2. Preserve `sidebar.width` with absolute-px 2.
|
|
418
|
+
3. Preserve a canonical relationship.
|
|
419
|
+
4. Selecting 2 of 3 gives exactly 2 clauses in selection order. The third
|
|
420
|
+
item is promoted separately.
|
|
421
|
+
3. Remove, inspect, and candidate:
|
|
422
|
+
1. Confirmed remove shows the exact unsupported message and a disabled
|
|
423
|
+
checkbox.
|
|
424
|
+
2. Inspect and candidate are not listed, and Promote is disabled.
|
|
425
|
+
3. Forced API promotion of each gives 422, and no contract exists.
|
|
426
|
+
4. Confirmation invalidation: target change retargets to `footer` and goes
|
|
427
|
+
back to candidate; reconfirm; a mark move goes back to candidate;
|
|
428
|
+
reconfirm; promotion yields `property-increases footer.y`.
|
|
429
|
+
5. Explicit activation: with a configured baseline, promotion with the
|
|
430
|
+
checkbox gives `activated`. The config equals the original except
|
|
431
|
+
`changeArtifact`, and `activeBaselineIds` is the configured baseline id.
|
|
432
|
+
6. Not configured: activation requested gives `not-configured`, the contract
|
|
433
|
+
is persisted, and the config bytes are unchanged.
|
|
434
|
+
|
|
435
|
+
## 24. Regression validation
|
|
436
|
+
|
|
437
|
+
Every command below was run on Windows in the repository root.
|
|
438
|
+
|
|
439
|
+
1. `npm run typecheck`: PASS
|
|
440
|
+
2. `npm run lint`: PASS
|
|
441
|
+
3. `npm test`: PASS (82 files, 1351 tests)
|
|
442
|
+
4. `npm run build`: PASS
|
|
443
|
+
5. `npm run test:browser`: PASS (24 files, 227 tests, real Chromium). This
|
|
444
|
+
includes `runtimeAnnotationAuthoring`, `referenceAnnotationAuthoring`,
|
|
445
|
+
`projectWorkflowViewer`, `pwaHardening`, `observationSvgWorkspace`, and
|
|
446
|
+
the existing contract evaluation and reference suites.
|
|
447
|
+
6. `npm run test:security`: PASS (unit: 15 files, 158 tests. Browser: 3 files,
|
|
448
|
+
77 tests). This is after adding the two new security-relevant unit suites
|
|
449
|
+
to the script.
|
|
450
|
+
7. `npm run check:docs`: PASS
|
|
451
|
+
8. `npm pack --dry-run`: PASS (352 files, 919.1 kB)
|
|
452
|
+
|
|
453
|
+
## 25. Security regression
|
|
454
|
+
|
|
455
|
+
1. Both authoring POST routes share one gate. The Prompt 2 Host, Origin,
|
|
456
|
+
token, body, method, and PWA tests pass, and the promotion route's own
|
|
457
|
+
gate tests pass.
|
|
458
|
+
2. The token stays in React memory only. The promotion request sends it only
|
|
459
|
+
in the authoring header.
|
|
460
|
+
3. The promotion route returns no filesystem paths. It writes only a
|
|
461
|
+
canonical contract under `.frontend-observer/evidence/contracts` and, when
|
|
462
|
+
explicitly requested and configured, one field of the project config.
|
|
463
|
+
4. `package.json` (additional file): the `test:security` script now also runs
|
|
464
|
+
`viewerAnnotationContractPromotion.test.ts` and
|
|
465
|
+
`evidenceDiscoveryTempDirectories.test.ts`. No version or dependency
|
|
466
|
+
changed.
|
|
467
|
+
|
|
468
|
+
## 26. Scope audit
|
|
469
|
+
|
|
470
|
+
1. ContractPrimitive vocabulary changed: false
|
|
471
|
+
2. frontend-contract schema changed: false
|
|
472
|
+
3. annotation schema changed: false
|
|
473
|
+
4. reference materialization implemented: false
|
|
474
|
+
5. external-reference schema changed: false
|
|
475
|
+
6. reference approval changed: false
|
|
476
|
+
7. project config schema changed: false
|
|
477
|
+
8. alias catalog schema changed: false
|
|
478
|
+
9. annotation evaluator added: false
|
|
479
|
+
10. package version changed: false
|
|
480
|
+
11. dependency changed: false
|
|
481
|
+
|
|
482
|
+
No file under `src/domain/` or `src/artifacts/` changed.
|
|
483
|
+
`frontendContractPersistenceService.ts`, `frontendContractEvaluationService.ts`,
|
|
484
|
+
and `projectCheckService.ts` are unchanged. Prompt 4 reference authoring is
|
|
485
|
+
unchanged (its 19 browser tests and 18 unit tests pass).
|
|
486
|
+
|
|
487
|
+
## 27. Changed files
|
|
488
|
+
|
|
489
|
+
### 27.1 Added production files
|
|
490
|
+
|
|
491
|
+
1. `src/application/visualAnnotationContractPromotionService.ts`
|
|
492
|
+
2. `src/viewerServer/annotationContractPromotion.ts` (route use case, keeps
|
|
493
|
+
the HTTP layer thin)
|
|
494
|
+
3. `viewer/src/annotation/runtimeIntent.ts`
|
|
495
|
+
4. `viewer/src/annotation/confirmation.ts` (shared confirmation rules moved
|
|
496
|
+
from `referenceIntent.ts`)
|
|
497
|
+
5. `viewer/src/hooks/useAnnotationContractPromotion.ts` (promotion request
|
|
498
|
+
state)
|
|
499
|
+
|
|
500
|
+
### 27.2 Modified production files
|
|
501
|
+
|
|
502
|
+
1. `src/viewerServer/httpServer.ts`
|
|
503
|
+
2. `src/viewerServer/annotationAuthoring.ts` (exposes the shared write queue)
|
|
504
|
+
3. `src/viewerServer/evidence/discovery.ts`
|
|
505
|
+
4. `src/projectWorkflow/projectPaths.ts`
|
|
506
|
+
5. `src/application/projectWorkflowService.ts`
|
|
507
|
+
6. `viewer/src/components/RuntimeAnnotationPanel.tsx`
|
|
508
|
+
7. `viewer/src/components/ObservationWorkspace.tsx`
|
|
509
|
+
8. `viewer/src/hooks/useRuntimeAnnotationDraft.ts`
|
|
510
|
+
9. `viewer/src/annotation/referenceIntent.ts` (imports the shared confirmation
|
|
511
|
+
helpers, behavior unchanged)
|
|
512
|
+
10. `viewer/src/types/contracts.ts` (type-only `ContractTolerance` re-export)
|
|
513
|
+
11. `viewer/src/styles/index.css`
|
|
514
|
+
12. `package.json` (`test:security` script only)
|
|
515
|
+
|
|
516
|
+
### 27.3 Tests and report
|
|
517
|
+
|
|
518
|
+
1. Added: `tests/browser/runtimeAnnotationContractPromotion.test.ts`
|
|
519
|
+
2. Added: `tests/unit/visualAnnotationContractPromotion.test.ts`
|
|
520
|
+
3. Added: `tests/unit/viewerAnnotationContractPromotion.test.ts`
|
|
521
|
+
4. Added: `tests/unit/viewerRuntimeIntentModel.test.ts`
|
|
522
|
+
5. Added: `tests/unit/evidenceDiscoveryTempDirectories.test.ts`
|
|
523
|
+
6. Modified: `tests/unit/projectWorkflow.test.ts`
|
|
524
|
+
7. Modified: `tests/unit/viewerAuthoringSecurity.test.ts`
|
|
525
|
+
8. Added: `docs/reports/v0.9-batch5-runtime-intent-contract-promotion.md`
|
|
526
|
+
|
|
527
|
+
### 27.4 Generated paths
|
|
528
|
+
|
|
529
|
+
1. `dist/` was rebuilt. It is ignored.
|
|
530
|
+
2. Tests create and remove temporary directories under the OS temp directory.
|
|
531
|
+
3. Validation logs went to the session scratchpad.
|
|
532
|
+
|
|
533
|
+
## 28. Remaining next step
|
|
534
|
+
|
|
535
|
+
v0.9 Prompt 6 — Canonical external-reference region/requirement materialization
|