@dailephd/my-frontend-observer 0.9.1 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +490 -471
- package/LICENSE +21 -21
- package/README.md +375 -357
- package/dist/application/projectCheckService.d.ts +6 -0
- package/dist/application/projectCheckService.js +8 -1
- package/dist/application/projectCheckService.js.map +1 -1
- package/dist/application/projectWorkflowService.d.ts +7 -2
- package/dist/application/projectWorkflowService.js +10 -3
- package/dist/application/projectWorkflowService.js.map +1 -1
- package/dist/application/visualChangeAgentHandoffService.d.ts +28 -0
- package/dist/application/visualChangeAgentHandoffService.js +111 -0
- package/dist/application/visualChangeAgentHandoffService.js.map +1 -0
- package/dist/application/visualChangeProjectWorkflowService.d.ts +95 -0
- package/dist/application/visualChangeProjectWorkflowService.js +376 -0
- package/dist/application/visualChangeProjectWorkflowService.js.map +1 -0
- package/dist/application/visualChangeReviewService.d.ts +50 -0
- package/dist/application/visualChangeReviewService.js +69 -0
- package/dist/application/visualChangeReviewService.js.map +1 -0
- package/dist/application/visualChangeWorkflowPersistenceService.d.ts +26 -0
- package/dist/application/visualChangeWorkflowPersistenceService.js +15 -0
- package/dist/application/visualChangeWorkflowPersistenceService.js.map +1 -0
- package/dist/artifacts/visualChangeWorkflowArtifactReader.d.ts +9 -0
- package/dist/artifacts/visualChangeWorkflowArtifactReader.js +47 -0
- package/dist/artifacts/visualChangeWorkflowArtifactReader.js.map +1 -0
- package/dist/artifacts/visualChangeWorkflowArtifactWriter.d.ts +20 -0
- package/dist/artifacts/visualChangeWorkflowArtifactWriter.js +41 -0
- package/dist/artifacts/visualChangeWorkflowArtifactWriter.js.map +1 -0
- package/dist/cli.js +9 -7
- package/dist/cli.js.map +1 -1
- package/dist/domain/visualChangeAgentHandoff.d.ts +82 -0
- package/dist/domain/visualChangeAgentHandoff.js +80 -0
- package/dist/domain/visualChangeAgentHandoff.js.map +1 -0
- package/dist/domain/visualChangeAgentHandoffSerialization.d.ts +2 -0
- package/dist/domain/visualChangeAgentHandoffSerialization.js +11 -0
- package/dist/domain/visualChangeAgentHandoffSerialization.js.map +1 -0
- package/dist/domain/visualChangeCycle.d.ts +8 -0
- package/dist/domain/visualChangeCycle.js +7 -0
- package/dist/domain/visualChangeCycle.js.map +1 -0
- package/dist/domain/visualChangeWorkflow.d.ts +125 -0
- package/dist/domain/visualChangeWorkflow.js +109 -0
- package/dist/domain/visualChangeWorkflow.js.map +1 -0
- package/dist/domain/visualChangeWorkflowIdentity.d.ts +5 -0
- package/dist/domain/visualChangeWorkflowIdentity.js +24 -0
- package/dist/domain/visualChangeWorkflowIdentity.js.map +1 -0
- package/dist/index.d.ts +21 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/projectWorkflow/projectPaths.d.ts +3 -0
- package/dist/projectWorkflow/projectPaths.js +7 -0
- package/dist/projectWorkflow/projectPaths.js.map +1 -1
- package/dist/viewer/assets/index-DglJ6f28.css +1 -0
- package/dist/viewer/assets/index-DsODREY5.js +9 -0
- package/dist/viewer/index.html +15 -15
- package/dist/viewer/sw.js +1 -1
- package/dist/viewerServer/evidence/classify.d.ts +3 -1
- package/dist/viewerServer/evidence/classify.js +10 -0
- package/dist/viewerServer/evidence/classify.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/projection.d.ts +5 -0
- package/dist/viewerServer/evidence/projection.js +19 -0
- package/dist/viewerServer/evidence/projection.js.map +1 -1
- package/dist/viewerServer/evidence/visualChangeWorkflowView.d.ts +31 -0
- package/dist/viewerServer/evidence/visualChangeWorkflowView.js +36 -0
- package/dist/viewerServer/evidence/visualChangeWorkflowView.js.map +1 -0
- package/dist/viewerServer/httpServer.js +323 -1
- package/dist/viewerServer/httpServer.js.map +1 -1
- package/dist/viewerServer/referenceApproval.d.ts +22 -0
- package/dist/viewerServer/referenceApproval.js +42 -0
- package/dist/viewerServer/referenceApproval.js.map +1 -0
- package/dist/viewerServer/referenceVisualChangeAuthoring.d.ts +28 -0
- package/dist/viewerServer/referenceVisualChangeAuthoring.js +134 -0
- package/dist/viewerServer/referenceVisualChangeAuthoring.js.map +1 -0
- package/dist/viewerServer/runtimeVisualChangeAuthoring.d.ts +33 -0
- package/dist/viewerServer/runtimeVisualChangeAuthoring.js +81 -0
- package/dist/viewerServer/runtimeVisualChangeAuthoring.js.map +1 -0
- package/dist/viewerServer/visualChangeAuthoring.d.ts +46 -0
- package/dist/viewerServer/visualChangeAuthoring.js +63 -0
- package/dist/viewerServer/visualChangeAuthoring.js.map +1 -0
- package/dist/viewerServer/visualChangeHandoff.d.ts +23 -0
- package/dist/viewerServer/visualChangeHandoff.js +31 -0
- package/dist/viewerServer/visualChangeHandoff.js.map +1 -0
- package/dist/viewerServer/visualChangeReview.d.ts +30 -0
- package/dist/viewerServer/visualChangeReview.js +46 -0
- package/dist/viewerServer/visualChangeReview.js.map +1 -0
- package/docs/ARCHITECTURE.md +1394 -1373
- package/docs/CI_CD.md +349 -327
- package/docs/COMMANDS.md +1035 -1012
- package/docs/CONTRACTS.md +1971 -1926
- package/docs/CURRENT_STATE.md +1277 -1238
- package/docs/DEVELOPMENT.md +240 -237
- package/docs/DOCUMENTATION_PRESERVATION_POLICY.md +50 -50
- package/docs/PROJECT_DESCRIPTION.md +2248 -2224
- package/docs/PROJECT_MILESTONES.md +2681 -2558
- package/docs/PROJECT_OVERVIEW.md +200 -191
- package/docs/QUICKSTART.md +100 -96
- package/docs/RELEASE.md +37 -33
- package/docs/ROADMAP.md +1105 -1033
- package/docs/SECURITY.md +297 -275
- package/docs/WORKFLOWS.md +806 -770
- package/docs/plans/v0.10-implementation-plan.md +1509 -0
- package/docs/plans/v0.8-implementation-plan.md +655 -655
- package/docs/plans/v0.8.1-cli-usability-patch-plan.md +505 -505
- package/docs/plans/v0.9-implementation-plan.md +1529 -1529
- package/docs/plans/v0.9.1-implementation-plan.md +468 -468
- package/docs/reports/v0.10-batch1-visual-change-workflow-foundation.md +102 -0
- package/docs/reports/v0.10-batch2-project-composition-check-recording.md +103 -0
- package/docs/reports/v0.10-batch3-viewer-visual-change-workspace.md +93 -0
- package/docs/reports/v0.10-batch4-actual-frontend-entry.md +59 -0
- package/docs/reports/v0.10-batch5-reference-driven-entry.md +238 -0
- package/docs/reports/v0.10-batch6-coding-agent-handoff.md +85 -0
- package/docs/reports/v0.10-batch7-correction-review-acceptance.md +145 -0
- package/docs/reports/v0.10-batch8-integrated-acceptance.md +109 -0
- package/docs/reports/v0.10-implementation-completeness-documentation-reconciliation.md +344 -0
- package/docs/reports/v0.10-pre-release-readiness.md +120 -0
- package/docs/reports/v0.10-release-preparation.md +70 -0
- package/docs/reports/v0.10.1-project-check-baseline-context-implementation.md +86 -0
- package/docs/reports/v0.7-bounded-fidelity-context-prompt7.md +243 -243
- package/docs/reports/v0.7-implementation-completeness-documentation-reconciliation.md +497 -497
- package/docs/reports/v0.7-pre-release-readiness.md +337 -337
- package/docs/reports/v0.7-reference-binding-prompt5.md +223 -223
- package/docs/reports/v0.7-reference-compatibility-prompt4.md +234 -234
- package/docs/reports/v0.7-reference-correction-workflow-prompt8.md +222 -222
- package/docs/reports/v0.7-reference-fidelity-prompt6.md +216 -216
- package/docs/reports/v0.7-reference-foundation-prompt1.md +151 -151
- package/docs/reports/v0.7-reference-regions-prompt2.md +195 -195
- package/docs/reports/v0.7-reference-requirements-prompt3.md +217 -217
- package/docs/reports/v0.7-release-prep.md +423 -423
- package/docs/reports/v0.8-binding-fidelity-interaction-batch6.md +279 -279
- package/docs/reports/v0.8-bounded-context-correlation-batch7.md +233 -233
- package/docs/reports/v0.8-comparison-contract-inspection-batch4.md +279 -279
- package/docs/reports/v0.8-evidence-index-readers-batch2.md +247 -247
- package/docs/reports/v0.8-implementation-completeness-documentation-reconciliation.md +741 -741
- package/docs/reports/v0.8-integrated-viewer-acceptance-batch8.md +128 -128
- package/docs/reports/v0.8-observation-svg-inspection-batch3.md +223 -223
- package/docs/reports/v0.8-prerelease-readiness-cross-platform-security-code-rot.md +687 -687
- package/docs/reports/v0.8-reference-candidate-inspection-batch5.md +232 -232
- package/docs/reports/v0.8-viewer-runtime-pwa-batch1.md +278 -278
- package/docs/reports/v0.8.1-implementation-completeness-documentation-reconciliation.md +114 -114
- package/docs/reports/v0.8.1-prerelease-readiness-cross-platform-security-code-rot.md +170 -170
- package/docs/reports/v0.9-architecture-retrieval.md +14 -37
- package/docs/reports/v0.9-final-pre-release-readiness.md +209 -209
- package/docs/reports/v0.9-final-readiness-corrections.md +530 -530
- package/docs/reports/v0.9-pre-release-readiness.md +169 -169
- package/docs/reports/v0.9.1-batch1-pwa-hard-gate-isolation.md +359 -359
- package/docs/reports/v0.9.1-batch2-hard-gate-validation-integration.md +262 -262
- package/docs/reports/v0.9.1-pre-release-readiness.md +206 -206
- package/package.json +59 -59
- package/dist/viewer/assets/index-BN41MI7m.css +0 -1
- package/dist/viewer/assets/index-CkKXnlrI.js +0 -9
|
@@ -1,234 +1,234 @@
|
|
|
1
|
-
# v0.7 Prompt 4 — Reference Applicability and Candidate-State Compatibility
|
|
2
|
-
|
|
3
|
-
**VERDICT: PASS_V0_7_REFERENCE_COMPATIBILITY_PROMPT4**
|
|
4
|
-
|
|
5
|
-
## Repository / branch / heads
|
|
6
|
-
|
|
7
|
-
- Repository: `my-frontend-observer` (path: `Z:\Users\newuser\Projects\my-frontend-observer`)
|
|
8
|
-
- Branch: `implementation/v0.7-reference-compatibility`, branched from Prompt 3's exact completed HEAD
|
|
9
|
-
- Prior HEAD (Prompt 3 report commit): `271087309386342a87aeec5b47d668bc02c457c9`
|
|
10
|
-
- Implementation commit (this prompt): `4da60be63c68a8c2138a0a28c1c6fa48242c2856` — "Add v0.7 Prompt 4 reference applicability and candidate-state compatibility"
|
|
11
|
-
- `git merge-base --is-ancestor` confirmed the branch point is exactly Prompt 3's report commit before any implementation work began.
|
|
12
|
-
|
|
13
|
-
## Git status at time of report
|
|
14
|
-
|
|
15
|
-
Working tree clean except for this report file (about to be added and committed separately). `git status --short` immediately before staging the implementation showed exactly the intentional Prompt 4 file set — 15 modified source files, 3 new source files, 11 modified test files, 3 new test files, and 4 modified docs files — nothing else. `git stash list` still shows exactly one entry, the Prompt 1 stray-fork-writes stash, untouched throughout this prompt (`stash@{0}: On implementation/v0.7-reference-foundation: stray-fork-writes-preserved-for-reference: ...`).
|
|
16
|
-
|
|
17
|
-
## Tooling
|
|
18
|
-
|
|
19
|
-
- `@dailephd/my-dev-kit` resolved version: `1.12.2` (via `npx @dailephd/my-dev-kit --version`).
|
|
20
|
-
- Fresh per-prompt code index built at `.my-dev-kit/index-prompt4/` before any implementation code was written, consulted during precedent review.
|
|
21
|
-
- Package version at time of work: `0.6.0` (unchanged — no schema/package version bump this prompt).
|
|
22
|
-
|
|
23
|
-
## Precedent review
|
|
24
|
-
|
|
25
|
-
Before writing any Prompt 4 code, the following existing modules were read in full (source, not memory, and not the fresh index's summaries alone):
|
|
26
|
-
|
|
27
|
-
- `src/domain/comparison.ts` — v0.4's frozen `ComparabilityState`/`ComparabilityReasonCode`/`ComparabilityReasonSeverity`/`ComparabilityReason`/`ComparabilityResult` vocabulary and its `isValidComparabilityReason` validator.
|
|
28
|
-
- `src/domain/comparisonEngine.ts` — v0.4's `evaluateComparability(before, after)`, including its three unconditional `theme-unassessed`/`authenticated-state-unassessed`/`application-state-unassessed` reason emissions (the exact hook point for this prompt's "additive improvement" requirement).
|
|
29
|
-
- `src/request/request.ts` — `NormalizedObservationRequest`/`RawObservationRequest`, `normalizeRequest()`'s validation-and-diagnostics pattern, and the existing `scrollScenario` additive-field precedent (validate raw input, push `invalid-request` diagnostics on failure, spread the field into the result only when defined).
|
|
30
|
-
- `src/domain/identity.ts` — `buildRequestIdentity`'s exact "new optional trailing parameter, omitted (never `null`) from the hashed semantic view when `undefined`" pattern, applied previously for `scrollScenario`.
|
|
31
|
-
- `src/domain/externalReference.ts`, `externalReferenceIdentity.ts`, `externalReferenceRegions.ts`, `externalReferenceRequirements.ts` — Prompt 1–3's additive-field/identity-parameter conventions, region/requirement validation shape, and the CLI file-loading precedent (`loadScrollScenarioFile`, `--regions-file`/`--requirements-file` wrapped-object convention vs. an unwrapped single-object convention).
|
|
32
|
-
- `src/application/externalReferencePersistenceService.ts` — the `importExternalReference`/`approveExternalReference` validate-then-persist-then-carry-forward pattern used for `regions`/`requirements`, reused identically for `applicability`.
|
|
33
|
-
- `src/domain/diagnostics.ts` — the single-diagnostic-code-per-validation-domain convention (`invalid-reference-region`, `invalid-reference-requirement`) that `invalid-reference-applicability` follows.
|
|
34
|
-
- `src/domain/frontendContracts.ts` — confirmed `AuthoredChangeScopeCategory` reuse precedent was not applicable here (Prompt 4 introduces no new authored-scope concept).
|
|
35
|
-
- `src/cli.ts` — the full `observe`/`import-reference`/`approve-reference` command implementations, their help-text blocks, and argument-parsing conventions (`--scroll-scenario-file`, `--regions-file`, `--requirements-file`) that `--state-file`/`--applicability-file` mirror.
|
|
36
|
-
|
|
37
|
-
No architecture blocker was hit; no `BLOCKED_ESCALATE_TO_FULL_STAGE_CONTEXT` condition applied at any point.
|
|
38
|
-
|
|
39
|
-
## Previous owners reused (not duplicated)
|
|
40
|
-
|
|
41
|
-
- `ComparabilityState`/`ComparabilityReasonCode`/`ComparabilityReasonSeverity`/`ComparabilityReason`/`ComparabilityResult` (from `domain/comparison.ts`) — reused wholesale as the compatibility result's `compatibility` field type. No parallel "compatibility state" enum was invented.
|
|
42
|
-
- `assessOptionalComparabilityDimension` — newly extracted from `comparisonEngine.ts` as an exported pure helper, and reused by both v0.4's `evaluateComparability` and the new `evaluateReferenceCandidateCompatibility`. This is the one point of actual code-sharing between the Observation↔Observation and Reference↔Observation compatibility checks; everything else about the two functions (their input types, their result envelopes) remains separately owned.
|
|
43
|
-
- `AuthenticatedState`/`ExplicitStateDimensions`/label pattern (`domain/explicitState.ts`) — one new, small, independently-owned module shared by both `ExternalReferenceApplicability` (via `extends ExplicitStateDimensions`) and `ObservationArtifact.requestConfig.explicitState`. This is a genuinely new vocabulary (nothing pre-existing captured "explicit state identity"), not a duplication of anything.
|
|
44
|
-
- `isValidStateLabel`/`STATE_LABEL_PATTERN` reuse of the existing `^[A-Za-z0-9_-]{1,64}$` convention already used for target names/region ids — not reinvented.
|
|
45
|
-
- `DIAGNOSTIC_CODES`/`DIAGNOSTIC_SEVERITY` (from `domain/diagnostics.ts`) — extended additively with one new code (`invalid-reference-applicability`), not a new diagnostics subsystem.
|
|
46
|
-
|
|
47
|
-
## State/applicability model
|
|
48
|
-
|
|
49
|
-
```ts
|
|
50
|
-
// domain/explicitState.ts
|
|
51
|
-
export const STATE_LABEL_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
52
|
-
export const AUTHENTICATED_STATE_VALUES = ['authenticated', 'unauthenticated'] as const;
|
|
53
|
-
export type AuthenticatedState = (typeof AUTHENTICATED_STATE_VALUES)[number];
|
|
54
|
-
export interface ExplicitStateDimensions {
|
|
55
|
-
theme?: string;
|
|
56
|
-
applicationState?: string;
|
|
57
|
-
authenticatedState?: AuthenticatedState;
|
|
58
|
-
}
|
|
59
|
-
// isValidExplicitStateDimensions: rejects unknown keys, validates each present
|
|
60
|
-
// field, and requires at least one declared dimension.
|
|
61
|
-
|
|
62
|
-
// domain/externalReferenceApplicability.ts
|
|
63
|
-
export const APPLICABLE_VIEWPORT_MIN = 200;
|
|
64
|
-
export const APPLICABLE_VIEWPORT_MAX = 3840;
|
|
65
|
-
export interface ApplicableViewport { width: number; height: number }
|
|
66
|
-
export interface ExternalReferenceApplicability extends ExplicitStateDimensions {
|
|
67
|
-
viewport?: ApplicableViewport;
|
|
68
|
-
}
|
|
69
|
-
// isValidExternalReferenceApplicability: its own independent validator (not a
|
|
70
|
-
// delegation to isValidExplicitStateDimensions, whose "at least one of three"
|
|
71
|
-
// rule would incorrectly reject a viewport-only object).
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
This is a bounded, closed shape — never an arbitrary `Record<string, unknown>` metadata bag. Unknown fields are rejected outright by both validators. Nothing in either module reads a browser, the DOM, a screenshot, a URL, source code, a filename, an accessibility label, `localStorage`, or a cookie; both are pure structural validators over caller-supplied plain objects.
|
|
75
|
-
|
|
76
|
-
## Exact image dimensions vs. applicable viewport
|
|
77
|
-
|
|
78
|
-
`ExternalReferenceImageReference.width/height` (Prompt 1, unchanged) continues to describe only the reference image file's own pixel dimensions, detected from header bytes. `ExternalReferenceApplicability.viewport` is a wholly distinct, independently-validated field describing the CSS-pixel runtime viewport the design represents. Neither field is derived from the other anywhere in the codebase; a reference image may be captured at any resolution/DPI relative to its declared applicable viewport, and `isValidExternalReferenceApplicability` never consults `image.width`/`image.height`.
|
|
79
|
-
|
|
80
|
-
## Provenance / state-identity source
|
|
81
|
-
|
|
82
|
-
`theme`, `applicationState`, and `authenticatedState` are accepted only as caller/config-supplied JSON input, on both the reference-import side (`--applicability-file`) and the observation side (`--state-file`). Neither `chromiumAdapter.ts`, `evidenceCapture.ts`, nor any other browser-facing module was touched by this prompt — there is no automatic state-detection code path anywhere in the repository, and none was added. `authenticatedState` is restricted to the closed two-value vocabulary `authenticated`/`unauthenticated`; nothing in `ExplicitStateDimensions`/`ExternalReferenceApplicability` can carry a password, token, cookie, session id, API key, or authorization header — the type system has no field for any of them, and the validators reject any unrecognized key.
|
|
83
|
-
|
|
84
|
-
## Compatibility result model
|
|
85
|
-
|
|
86
|
-
```ts
|
|
87
|
-
// domain/externalReferenceCompatibility.ts
|
|
88
|
-
export interface ReferenceCandidateCompatibilityResult {
|
|
89
|
-
referenceId: string;
|
|
90
|
-
referenceRequestId: string;
|
|
91
|
-
candidateObservationId: string;
|
|
92
|
-
candidateRequestId: string;
|
|
93
|
-
compatibility: ComparabilityResult; // reused v0.4 type: { state, reasons[] }
|
|
94
|
-
}
|
|
95
|
-
export function evaluateReferenceCandidateCompatibility(
|
|
96
|
-
reference: ExternalReferenceArtifact,
|
|
97
|
-
candidate: ObservationArtifact,
|
|
98
|
-
): ReferenceCandidateCompatibilityResult;
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Structured, never boolean, never a numeric/visual score. `compatibility.reasons` carries per-dimension `{ code, severity, message, referenceValue?, candidateValue? }` records; `referenceValue`/`candidateValue` are populated only on a mismatch reason (never on an unassessed reason, since there is nothing to compare). The function is pure and synchronous — verified by an explicit "same inputs produce a deep-equal result" test.
|
|
102
|
-
|
|
103
|
-
## Blocking / unassessed / missing-dimension semantics (behaviors A–I)
|
|
104
|
-
|
|
105
|
-
All nine required behaviors are implemented via the single shared helper `assessOptionalComparabilityDimension(mismatchCode, unassessedCode, referenceValue, candidateValue, mismatchMessage, unassessedMessage)`:
|
|
106
|
-
|
|
107
|
-
- Both values defined and equal → no reason emitted (comparable on that dimension).
|
|
108
|
-
- Both values defined and different → a `blocking`-severity mismatch reason, with `referenceValue`/`candidateValue` populated (behaviors B, D, E, F for viewport/theme/application-state/authenticated-state mismatches — all four dimensions use the identical rule).
|
|
109
|
-
- Either value `undefined` (reference constrains but candidate lacks it, reference omits it entirely, or both omit it) → an `unassessed`-severity reason, **never** a fabricated match and **never** a fabricated mismatch (behaviors G, H, I). This is fail-closed: an unassessed dimension never contributes to `compatible`, but it also never forces `incomparable` — only an actual detected mismatch does that.
|
|
110
|
-
- Overall `compatibility.state` is `incomparable` if any reason is `blocking`, else `comparable-with-warnings` if any is `warning` (this prompt introduces no warning-severity reasons of its own — only blocking/unassessed), else `comparable`.
|
|
111
|
-
- A reference declaring no `applicability` at all produces a fully unassessed result across every dimension — verified explicitly; Prompt 1/2/3 references remain fully usable, just unassessed for compatibility until `applicability` is authored.
|
|
112
|
-
|
|
113
|
-
All nine behaviors (A–I) plus the "no applicability at all" and "pure function" cases are covered by dedicated tests in `tests/unit/externalReferenceCompatibility.test.ts`.
|
|
114
|
-
|
|
115
|
-
## v0.4 reuse / refactor proof
|
|
116
|
-
|
|
117
|
-
`assessOptionalComparabilityDimension` was extracted directly out of the body of `evaluateComparability` (its three `theme`/`authenticatedState`/`applicationState` blocks previously called `add('theme-unassessed', ...)` etc. unconditionally). After extraction:
|
|
118
|
-
|
|
119
|
-
- `evaluateComparability`'s three state-dimension blocks now call the shared helper against `before.requestConfig.explicitState`/`after.requestConfig.explicitState`.
|
|
120
|
-
- `evaluateReferenceCandidateCompatibility` calls the identical helper against `reference.applicability`/`candidate.requestConfig` (viewport) and `candidate.requestConfig.explicitState` (theme/authenticatedState/applicationState).
|
|
121
|
-
- The reason-code sort rule (`reasons.sort((a, b) => COMPARABILITY_REASON_CODES.indexOf(a.code) - COMPARABILITY_REASON_CODES.indexOf(b.code))`) and the `state` derivation (`hasBlocking → incomparable`, else `hasWarning → comparable-with-warnings`, else `comparable`) are duplicated verbatim in `externalReferenceCompatibility.ts` (deliberately not extracted into a second shared helper, since a two-line duplication was judged lower-risk than adding a third shared dependency between v0.4 and v0.7 module boundaries for something this small).
|
|
122
|
-
|
|
123
|
-
## Old-behavior-unchanged proof
|
|
124
|
-
|
|
125
|
-
The pre-existing frozen regression test in `tests/unit/comparisonEngine.test.ts` (`'is comparable with no reasons beyond the always-present unassessed dimensions'`) asserts `result.reasons.map((r) => r.code)` equals exactly `['theme-unassessed', 'authenticated-state-unassessed', 'application-state-unassessed']` for a before/after pair with no `explicitState` on either side — this test was **not modified** and still passes unchanged, because neither observation declares `explicitState`, so the shared helper's "either value undefined" branch fires for all three dimensions, exactly reproducing the pre-Prompt-4 unconditional-unassessed behavior. Three new tests were added alongside it exercising the additive "both declare, match", "both declare, mismatch", and "only one declares" cases. Full v0.1–v0.6 regression suites (unit + browser + security) were re-run and are unaffected — see Validation below.
|
|
126
|
-
|
|
127
|
-
## Identity impacts
|
|
128
|
-
|
|
129
|
-
- `buildExternalReferenceRequestIdentity(imageSha256, format, width, height, supersedesReferenceId?, regions?, requirements?, applicability?)` — `applicability` is the new 8th, final, optional parameter, omitted entirely (never `null`) from the hashed semantic view when `undefined`. Verified: `buildExternalReferenceRequestIdentity(...args)` and `buildExternalReferenceRequestIdentity(...args, undefined)` produce byte-identical hashes.
|
|
130
|
-
- `buildRequestIdentity(request)` — `request.explicitState` is now included in the semantic view only when present (`...(request.explicitState ? { explicitState: request.explicitState } : {})`), mirroring the existing `scrollScenario` treatment exactly. The pre-existing frozen regression vector (`buildRequestIdentity(baseRequest())` === a specific fixed hash string) is asserted unchanged by a new test in `identity.test.ts`.
|
|
131
|
-
- No operational file path (`--state-file`'s or `--applicability-file`'s path argument) enters either identity function — both functions take only already-parsed, in-memory values, never a path.
|
|
132
|
-
|
|
133
|
-
## Schema / version decisions
|
|
134
|
-
|
|
135
|
-
No `SCHEMA_VERSION`/`EXTERNAL_REFERENCE_SCHEMA_VERSION` bump. Both new fields (`requestConfig.explicitState`, `ExternalReferenceArtifact.applicability`) are purely additive and optional, following the exact precedent set by `scrollScenario` (Prompt/Batch 3) and `regions`/`requirements` (v0.7 Prompts 2/3), none of which bumped their respective schema versions either.
|
|
136
|
-
|
|
137
|
-
## CLI changes
|
|
138
|
-
|
|
139
|
-
- `observe` gains `--state-file <json-file>`: unwrapped `{theme?, applicationState?, authenticatedState?}` object, no wrapper field, mirroring `--scroll-scenario-file`'s file-loading shape exactly (read → JSON.parse → plain-object-root check only; all semantic validation deferred to `normalizeRequest()`/`isValidExplicitStateDimensions`). Compatible with `--target`/`--targets-file`/`--scroll-scenario-file` (independent, non-conflicting flag).
|
|
140
|
-
- `import-reference` gains `--applicability-file <json-file>`: unwrapped raw applicability object (not a `{"requirements": [...]}`-style wrapper, since applicability is a single object, not a named list) — read → JSON.parse → plain-object-root check only; all semantic validation deferred to `isValidExternalReferenceApplicability`.
|
|
141
|
-
- Both commands' `--help` text, and `approve-reference --help`, were updated to document the new flag and its failure modes.
|
|
142
|
-
- `import-reference`/`approve-reference` success output gained one new line: `Applicability: declared|none`.
|
|
143
|
-
- CLI code owns only flag syntax, file reading, JSON parsing, and object-root shape validation for both new flags — zero semantic validation logic lives in `cli.ts` itself; every actual rule (label pattern, authenticated-state vocabulary, viewport bounds, "at least one dimension") is owned by `domain/explicitState.ts`/`domain/externalReferenceApplicability.ts`.
|
|
144
|
-
|
|
145
|
-
## Persistence decision
|
|
146
|
-
|
|
147
|
-
No new persisted artifact kind was introduced for the compatibility result. `evaluateReferenceCandidateCompatibility` is a pure, synchronous, on-demand function over two already-persisted artifacts (an `ExternalReferenceArtifact` and an `ObservationArtifact`), invoked directly by a caller (application code, a future CLI command, or a test) — never something the observer writes to disk automatically. Rationale: the result is cheap to recompute deterministically from its two inputs; persisting it would introduce a drift risk (a re-imported/re-observed artifact could silently disagree with a stale persisted compatibility record) with no corresponding benefit at this stage of the architecture. This decision may be revisited only if a later v0.7 prompt's architecture proves persistence necessary — documented per instruction, not assumed.
|
|
148
|
-
|
|
149
|
-
## Files changed
|
|
150
|
-
|
|
151
|
-
New:
|
|
152
|
-
- `src/domain/explicitState.ts`
|
|
153
|
-
- `src/domain/externalReferenceApplicability.ts`
|
|
154
|
-
- `src/domain/externalReferenceCompatibility.ts`
|
|
155
|
-
- `tests/unit/explicitState.test.ts`
|
|
156
|
-
- `tests/unit/externalReferenceApplicability.test.ts`
|
|
157
|
-
- `tests/unit/externalReferenceCompatibility.test.ts`
|
|
158
|
-
|
|
159
|
-
Modified:
|
|
160
|
-
- `src/domain/comparison.ts` (4 new reason codes, 2 new optional `ComparabilityReason` fields)
|
|
161
|
-
- `src/domain/comparisonEngine.ts` (extracted+exported `assessOptionalComparabilityDimension`; `evaluateComparability` now uses it additively)
|
|
162
|
-
- `src/domain/diagnostics.ts` (`invalid-reference-applicability` code)
|
|
163
|
-
- `src/domain/externalReference.ts` (`applicability?` field + validation)
|
|
164
|
-
- `src/domain/externalReferenceIdentity.ts` (`applicability` identity parameter)
|
|
165
|
-
- `src/domain/identity.ts` (`explicitState` identity inclusion)
|
|
166
|
-
- `src/domain/schema.ts` (`requestConfig.explicitState` defense-in-depth validation)
|
|
167
|
-
- `src/request/request.ts` (`explicitState` request field + validation)
|
|
168
|
-
- `src/application/externalReferencePersistenceService.ts` (`applicability` import/approve wiring, `hasApplicability` result field)
|
|
169
|
-
- `src/cli.ts` (`--state-file`, `--applicability-file`, help text, output lines)
|
|
170
|
-
- `src/index.ts` (public export surface for all of the above)
|
|
171
|
-
- `docs/ARCHITECTURE.md`, `docs/CONTRACTS.md`, `docs/WORKFLOWS.md`, `docs/COMMANDS.md`
|
|
172
|
-
- 11 existing test files extended with Prompt 4 coverage (see Tests below)
|
|
173
|
-
|
|
174
|
-
## Tests
|
|
175
|
-
|
|
176
|
-
857 unit tests total (779 pre-existing + 78 new/extended this prompt), across:
|
|
177
|
-
- New: `explicitState.test.ts` (10 tests), `externalReferenceApplicability.test.ts` (8 tests), `externalReferenceCompatibility.test.ts` (14 tests covering behaviors A–I plus identity/purity checks).
|
|
178
|
-
- Extended: `comparisonEngine.test.ts` (+3, v0.4 additive-assessment behavior), `identity.test.ts` (+4, `explicitState` identity), `externalReferenceIdentity.test.ts` (+4, `applicability` identity), `externalReference.test.ts` (+4, `applicability` schema validation), `schema.test.ts` (+3, `requestConfig.explicitState` validation), `request.test.ts` (+7, `explicitState` request normalization), `externalReferencePersistenceService.test.ts` (+4, import/approve applicability wiring), `cli.test.ts` (+9, `--state-file` CLI boundary + help text), `cliExternalReference.test.ts` (+6, `--applicability-file` CLI boundary + end-to-end import/approve).
|
|
179
|
-
|
|
180
|
-
## Validation results
|
|
181
|
-
|
|
182
|
-
All commands run from the repository root, after the implementation commit:
|
|
183
|
-
|
|
184
|
-
- `npm run typecheck` — pass, zero errors.
|
|
185
|
-
- `npm run lint` — pass, zero errors/warnings.
|
|
186
|
-
- `npm test` — 45 test files, 857 tests, all pass.
|
|
187
|
-
- `npm run build` — pass, clean `tsc` compile.
|
|
188
|
-
- `npm run check:docs` — pass (17 required files present, `ROADMAP.md` format intact).
|
|
189
|
-
- `git diff --check` — exit 0 (only benign LF→CRLF normalization notices on Windows checkout, no actual whitespace-error content).
|
|
190
|
-
- `npm pack --dry-run` — pass; new `dist/domain/explicitState.js`, `externalReferenceApplicability.js`, `externalReferenceCompatibility.js` (and their `.d.ts`/`.js.map`) confirmed present in the tarball listing alongside updated `dist/index.d.ts`.
|
|
191
|
-
- `npm run test:security` — pass (5 + 63 = 68 tests: `policy.test.ts` + real-Chromium `chromiumAdapter.test.ts`), run because this prompt changes state/config input surface.
|
|
192
|
-
- `npm run test:browser` — pass (9 files, 120 tests, real Chromium), run as full regression confirmation.
|
|
193
|
-
|
|
194
|
-
## Regression results
|
|
195
|
-
|
|
196
|
-
- Full v0.1–v0.6 unit suite: unaffected, all passing (779 pre-existing tests unchanged in assertions, all still passing verbatim).
|
|
197
|
-
- Full real-Chromium browser suite: 120/120 passing, unaffected.
|
|
198
|
-
- Full security suite: 68/68 passing, unaffected.
|
|
199
|
-
- The one pre-existing frozen `evaluateComparability` regression test (no-`explicitState` case) passes unchanged, proving the v0.4 additive-assessment change is genuinely additive, not a behavior change for any historical/legacy observation pair.
|
|
200
|
-
- The one pre-existing frozen `buildRequestIdentity` regression hash (`baseRequest()` with no `scrollScenario`/`explicitState`) passes unchanged, proving the `explicitState` identity extension is genuinely additive.
|
|
201
|
-
|
|
202
|
-
## Security impact
|
|
203
|
-
|
|
204
|
-
- No new external input surface beyond local JSON files the caller already controls (same trust boundary as `--targets-file`/`--scroll-scenario-file`/`--regions-file`/`--requirements-file`).
|
|
205
|
-
- `authenticatedState`'s closed two-value vocabulary and the complete absence of any credential/token/cookie/session-id field in `ExplicitStateDimensions`/`ExternalReferenceApplicability` were verified by direct type/field inspection — there is no field anywhere in either interface capable of holding a secret.
|
|
206
|
-
- `test:security` (policy + real-Chromium adapter tests) re-run and passing, confirming no regression to the existing safety/navigation policy surface (this prompt touches none of that code).
|
|
207
|
-
|
|
208
|
-
## Documentation changes
|
|
209
|
-
|
|
210
|
-
- `docs/CONTRACTS.md` — new "v0.7 Prompt 4 reference applicability and candidate-state compatibility" section (full type shapes, key rules, image-vs-viewport distinction, v0.4 reuse proof, persistence decision, identity impact, CLI summary).
|
|
211
|
-
- `docs/ARCHITECTURE.md` — new paragraph in the "Planned v0.7–v0.10" section describing the Prompt 4 module additions and the v0.4 extraction/reuse story.
|
|
212
|
-
- `docs/WORKFLOWS.md` — "Current external-reference foundation workflow" section retitled to "Prompts 1-4" and extended with `--applicability-file`/`--state-file` steps and the new compatibility-evaluation paragraph.
|
|
213
|
-
- `docs/COMMANDS.md` — `observe` options list extended with `--state-file`.
|
|
214
|
-
|
|
215
|
-
## Tooling incidents
|
|
216
|
-
|
|
217
|
-
None this prompt. No orchestrator was invoked (direct-implementation mode used throughout, consistent with Prompts 2–3); no background/speculative subagent writes occurred; the Prompt 1 stray-fork-writes stash remains untouched, unapplied, and unmined as precedent.
|
|
218
|
-
|
|
219
|
-
## Out-of-scope confirmation
|
|
220
|
-
|
|
221
|
-
This prompt implements no region/runtime binding, no candidate/reference geometry comparison, no fidelity PASS/FAIL evaluation, no style/color/typography comparison, no image/pixel similarity, no change to source correlation, no coding-agent correction logic, no rerender loop, no viewer, no annotation UI, and no automatic state/authentication detection of any kind. `evaluateReferenceCandidateCompatibility` reads only `reference.applicability` and `candidate.requestConfig` (viewport/explicitState) — it never reads `reference.regions`, `reference.requirements`, or any target/geometry evidence from the candidate.
|
|
222
|
-
|
|
223
|
-
## Known limitations
|
|
224
|
-
|
|
225
|
-
- Applicable-viewport comparison is an exact string-equality check on `"WxH"` — there is no tolerance/near-match concept for viewport compatibility (deliberately; a viewport is either the one the reference represents or it isn't, unlike the pixel-tolerance semantics that belong to Prompt 3's region-property requirements).
|
|
226
|
-
- `evaluateReferenceCandidateCompatibility` has no CLI command of its own yet (no `check-compatibility`-style entry point) — it is exposed only as a library function via `src/index.ts`, since Prompt 4's scope was the domain model and its reuse story, not a new user-facing workflow entry point. A future prompt may add a CLI surface once region binding (Prompt 5) makes an end-to-end command meaningful.
|
|
227
|
-
|
|
228
|
-
## Remaining risks
|
|
229
|
-
|
|
230
|
-
- None identified that block this prompt's own scope. The main forward risk is Prompt 5 (region↔runtime-target binding) needing to compose region-level and page-level (this prompt's) compatibility results coherently — flagged for that prompt's own precedent review, not something this prompt can or should preempt.
|
|
231
|
-
|
|
232
|
-
## Exact next action
|
|
233
|
-
|
|
234
|
-
v0.7 Prompt 5 — explicit reference-region ↔ runtime-target binding.
|
|
1
|
+
# v0.7 Prompt 4 — Reference Applicability and Candidate-State Compatibility
|
|
2
|
+
|
|
3
|
+
**VERDICT: PASS_V0_7_REFERENCE_COMPATIBILITY_PROMPT4**
|
|
4
|
+
|
|
5
|
+
## Repository / branch / heads
|
|
6
|
+
|
|
7
|
+
- Repository: `my-frontend-observer` (path: `Z:\Users\newuser\Projects\my-frontend-observer`)
|
|
8
|
+
- Branch: `implementation/v0.7-reference-compatibility`, branched from Prompt 3's exact completed HEAD
|
|
9
|
+
- Prior HEAD (Prompt 3 report commit): `271087309386342a87aeec5b47d668bc02c457c9`
|
|
10
|
+
- Implementation commit (this prompt): `4da60be63c68a8c2138a0a28c1c6fa48242c2856` — "Add v0.7 Prompt 4 reference applicability and candidate-state compatibility"
|
|
11
|
+
- `git merge-base --is-ancestor` confirmed the branch point is exactly Prompt 3's report commit before any implementation work began.
|
|
12
|
+
|
|
13
|
+
## Git status at time of report
|
|
14
|
+
|
|
15
|
+
Working tree clean except for this report file (about to be added and committed separately). `git status --short` immediately before staging the implementation showed exactly the intentional Prompt 4 file set — 15 modified source files, 3 new source files, 11 modified test files, 3 new test files, and 4 modified docs files — nothing else. `git stash list` still shows exactly one entry, the Prompt 1 stray-fork-writes stash, untouched throughout this prompt (`stash@{0}: On implementation/v0.7-reference-foundation: stray-fork-writes-preserved-for-reference: ...`).
|
|
16
|
+
|
|
17
|
+
## Tooling
|
|
18
|
+
|
|
19
|
+
- `@dailephd/my-dev-kit` resolved version: `1.12.2` (via `npx @dailephd/my-dev-kit --version`).
|
|
20
|
+
- Fresh per-prompt code index built at `.my-dev-kit/index-prompt4/` before any implementation code was written, consulted during precedent review.
|
|
21
|
+
- Package version at time of work: `0.6.0` (unchanged — no schema/package version bump this prompt).
|
|
22
|
+
|
|
23
|
+
## Precedent review
|
|
24
|
+
|
|
25
|
+
Before writing any Prompt 4 code, the following existing modules were read in full (source, not memory, and not the fresh index's summaries alone):
|
|
26
|
+
|
|
27
|
+
- `src/domain/comparison.ts` — v0.4's frozen `ComparabilityState`/`ComparabilityReasonCode`/`ComparabilityReasonSeverity`/`ComparabilityReason`/`ComparabilityResult` vocabulary and its `isValidComparabilityReason` validator.
|
|
28
|
+
- `src/domain/comparisonEngine.ts` — v0.4's `evaluateComparability(before, after)`, including its three unconditional `theme-unassessed`/`authenticated-state-unassessed`/`application-state-unassessed` reason emissions (the exact hook point for this prompt's "additive improvement" requirement).
|
|
29
|
+
- `src/request/request.ts` — `NormalizedObservationRequest`/`RawObservationRequest`, `normalizeRequest()`'s validation-and-diagnostics pattern, and the existing `scrollScenario` additive-field precedent (validate raw input, push `invalid-request` diagnostics on failure, spread the field into the result only when defined).
|
|
30
|
+
- `src/domain/identity.ts` — `buildRequestIdentity`'s exact "new optional trailing parameter, omitted (never `null`) from the hashed semantic view when `undefined`" pattern, applied previously for `scrollScenario`.
|
|
31
|
+
- `src/domain/externalReference.ts`, `externalReferenceIdentity.ts`, `externalReferenceRegions.ts`, `externalReferenceRequirements.ts` — Prompt 1–3's additive-field/identity-parameter conventions, region/requirement validation shape, and the CLI file-loading precedent (`loadScrollScenarioFile`, `--regions-file`/`--requirements-file` wrapped-object convention vs. an unwrapped single-object convention).
|
|
32
|
+
- `src/application/externalReferencePersistenceService.ts` — the `importExternalReference`/`approveExternalReference` validate-then-persist-then-carry-forward pattern used for `regions`/`requirements`, reused identically for `applicability`.
|
|
33
|
+
- `src/domain/diagnostics.ts` — the single-diagnostic-code-per-validation-domain convention (`invalid-reference-region`, `invalid-reference-requirement`) that `invalid-reference-applicability` follows.
|
|
34
|
+
- `src/domain/frontendContracts.ts` — confirmed `AuthoredChangeScopeCategory` reuse precedent was not applicable here (Prompt 4 introduces no new authored-scope concept).
|
|
35
|
+
- `src/cli.ts` — the full `observe`/`import-reference`/`approve-reference` command implementations, their help-text blocks, and argument-parsing conventions (`--scroll-scenario-file`, `--regions-file`, `--requirements-file`) that `--state-file`/`--applicability-file` mirror.
|
|
36
|
+
|
|
37
|
+
No architecture blocker was hit; no `BLOCKED_ESCALATE_TO_FULL_STAGE_CONTEXT` condition applied at any point.
|
|
38
|
+
|
|
39
|
+
## Previous owners reused (not duplicated)
|
|
40
|
+
|
|
41
|
+
- `ComparabilityState`/`ComparabilityReasonCode`/`ComparabilityReasonSeverity`/`ComparabilityReason`/`ComparabilityResult` (from `domain/comparison.ts`) — reused wholesale as the compatibility result's `compatibility` field type. No parallel "compatibility state" enum was invented.
|
|
42
|
+
- `assessOptionalComparabilityDimension` — newly extracted from `comparisonEngine.ts` as an exported pure helper, and reused by both v0.4's `evaluateComparability` and the new `evaluateReferenceCandidateCompatibility`. This is the one point of actual code-sharing between the Observation↔Observation and Reference↔Observation compatibility checks; everything else about the two functions (their input types, their result envelopes) remains separately owned.
|
|
43
|
+
- `AuthenticatedState`/`ExplicitStateDimensions`/label pattern (`domain/explicitState.ts`) — one new, small, independently-owned module shared by both `ExternalReferenceApplicability` (via `extends ExplicitStateDimensions`) and `ObservationArtifact.requestConfig.explicitState`. This is a genuinely new vocabulary (nothing pre-existing captured "explicit state identity"), not a duplication of anything.
|
|
44
|
+
- `isValidStateLabel`/`STATE_LABEL_PATTERN` reuse of the existing `^[A-Za-z0-9_-]{1,64}$` convention already used for target names/region ids — not reinvented.
|
|
45
|
+
- `DIAGNOSTIC_CODES`/`DIAGNOSTIC_SEVERITY` (from `domain/diagnostics.ts`) — extended additively with one new code (`invalid-reference-applicability`), not a new diagnostics subsystem.
|
|
46
|
+
|
|
47
|
+
## State/applicability model
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// domain/explicitState.ts
|
|
51
|
+
export const STATE_LABEL_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
|
|
52
|
+
export const AUTHENTICATED_STATE_VALUES = ['authenticated', 'unauthenticated'] as const;
|
|
53
|
+
export type AuthenticatedState = (typeof AUTHENTICATED_STATE_VALUES)[number];
|
|
54
|
+
export interface ExplicitStateDimensions {
|
|
55
|
+
theme?: string;
|
|
56
|
+
applicationState?: string;
|
|
57
|
+
authenticatedState?: AuthenticatedState;
|
|
58
|
+
}
|
|
59
|
+
// isValidExplicitStateDimensions: rejects unknown keys, validates each present
|
|
60
|
+
// field, and requires at least one declared dimension.
|
|
61
|
+
|
|
62
|
+
// domain/externalReferenceApplicability.ts
|
|
63
|
+
export const APPLICABLE_VIEWPORT_MIN = 200;
|
|
64
|
+
export const APPLICABLE_VIEWPORT_MAX = 3840;
|
|
65
|
+
export interface ApplicableViewport { width: number; height: number }
|
|
66
|
+
export interface ExternalReferenceApplicability extends ExplicitStateDimensions {
|
|
67
|
+
viewport?: ApplicableViewport;
|
|
68
|
+
}
|
|
69
|
+
// isValidExternalReferenceApplicability: its own independent validator (not a
|
|
70
|
+
// delegation to isValidExplicitStateDimensions, whose "at least one of three"
|
|
71
|
+
// rule would incorrectly reject a viewport-only object).
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This is a bounded, closed shape — never an arbitrary `Record<string, unknown>` metadata bag. Unknown fields are rejected outright by both validators. Nothing in either module reads a browser, the DOM, a screenshot, a URL, source code, a filename, an accessibility label, `localStorage`, or a cookie; both are pure structural validators over caller-supplied plain objects.
|
|
75
|
+
|
|
76
|
+
## Exact image dimensions vs. applicable viewport
|
|
77
|
+
|
|
78
|
+
`ExternalReferenceImageReference.width/height` (Prompt 1, unchanged) continues to describe only the reference image file's own pixel dimensions, detected from header bytes. `ExternalReferenceApplicability.viewport` is a wholly distinct, independently-validated field describing the CSS-pixel runtime viewport the design represents. Neither field is derived from the other anywhere in the codebase; a reference image may be captured at any resolution/DPI relative to its declared applicable viewport, and `isValidExternalReferenceApplicability` never consults `image.width`/`image.height`.
|
|
79
|
+
|
|
80
|
+
## Provenance / state-identity source
|
|
81
|
+
|
|
82
|
+
`theme`, `applicationState`, and `authenticatedState` are accepted only as caller/config-supplied JSON input, on both the reference-import side (`--applicability-file`) and the observation side (`--state-file`). Neither `chromiumAdapter.ts`, `evidenceCapture.ts`, nor any other browser-facing module was touched by this prompt — there is no automatic state-detection code path anywhere in the repository, and none was added. `authenticatedState` is restricted to the closed two-value vocabulary `authenticated`/`unauthenticated`; nothing in `ExplicitStateDimensions`/`ExternalReferenceApplicability` can carry a password, token, cookie, session id, API key, or authorization header — the type system has no field for any of them, and the validators reject any unrecognized key.
|
|
83
|
+
|
|
84
|
+
## Compatibility result model
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
// domain/externalReferenceCompatibility.ts
|
|
88
|
+
export interface ReferenceCandidateCompatibilityResult {
|
|
89
|
+
referenceId: string;
|
|
90
|
+
referenceRequestId: string;
|
|
91
|
+
candidateObservationId: string;
|
|
92
|
+
candidateRequestId: string;
|
|
93
|
+
compatibility: ComparabilityResult; // reused v0.4 type: { state, reasons[] }
|
|
94
|
+
}
|
|
95
|
+
export function evaluateReferenceCandidateCompatibility(
|
|
96
|
+
reference: ExternalReferenceArtifact,
|
|
97
|
+
candidate: ObservationArtifact,
|
|
98
|
+
): ReferenceCandidateCompatibilityResult;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Structured, never boolean, never a numeric/visual score. `compatibility.reasons` carries per-dimension `{ code, severity, message, referenceValue?, candidateValue? }` records; `referenceValue`/`candidateValue` are populated only on a mismatch reason (never on an unassessed reason, since there is nothing to compare). The function is pure and synchronous — verified by an explicit "same inputs produce a deep-equal result" test.
|
|
102
|
+
|
|
103
|
+
## Blocking / unassessed / missing-dimension semantics (behaviors A–I)
|
|
104
|
+
|
|
105
|
+
All nine required behaviors are implemented via the single shared helper `assessOptionalComparabilityDimension(mismatchCode, unassessedCode, referenceValue, candidateValue, mismatchMessage, unassessedMessage)`:
|
|
106
|
+
|
|
107
|
+
- Both values defined and equal → no reason emitted (comparable on that dimension).
|
|
108
|
+
- Both values defined and different → a `blocking`-severity mismatch reason, with `referenceValue`/`candidateValue` populated (behaviors B, D, E, F for viewport/theme/application-state/authenticated-state mismatches — all four dimensions use the identical rule).
|
|
109
|
+
- Either value `undefined` (reference constrains but candidate lacks it, reference omits it entirely, or both omit it) → an `unassessed`-severity reason, **never** a fabricated match and **never** a fabricated mismatch (behaviors G, H, I). This is fail-closed: an unassessed dimension never contributes to `compatible`, but it also never forces `incomparable` — only an actual detected mismatch does that.
|
|
110
|
+
- Overall `compatibility.state` is `incomparable` if any reason is `blocking`, else `comparable-with-warnings` if any is `warning` (this prompt introduces no warning-severity reasons of its own — only blocking/unassessed), else `comparable`.
|
|
111
|
+
- A reference declaring no `applicability` at all produces a fully unassessed result across every dimension — verified explicitly; Prompt 1/2/3 references remain fully usable, just unassessed for compatibility until `applicability` is authored.
|
|
112
|
+
|
|
113
|
+
All nine behaviors (A–I) plus the "no applicability at all" and "pure function" cases are covered by dedicated tests in `tests/unit/externalReferenceCompatibility.test.ts`.
|
|
114
|
+
|
|
115
|
+
## v0.4 reuse / refactor proof
|
|
116
|
+
|
|
117
|
+
`assessOptionalComparabilityDimension` was extracted directly out of the body of `evaluateComparability` (its three `theme`/`authenticatedState`/`applicationState` blocks previously called `add('theme-unassessed', ...)` etc. unconditionally). After extraction:
|
|
118
|
+
|
|
119
|
+
- `evaluateComparability`'s three state-dimension blocks now call the shared helper against `before.requestConfig.explicitState`/`after.requestConfig.explicitState`.
|
|
120
|
+
- `evaluateReferenceCandidateCompatibility` calls the identical helper against `reference.applicability`/`candidate.requestConfig` (viewport) and `candidate.requestConfig.explicitState` (theme/authenticatedState/applicationState).
|
|
121
|
+
- The reason-code sort rule (`reasons.sort((a, b) => COMPARABILITY_REASON_CODES.indexOf(a.code) - COMPARABILITY_REASON_CODES.indexOf(b.code))`) and the `state` derivation (`hasBlocking → incomparable`, else `hasWarning → comparable-with-warnings`, else `comparable`) are duplicated verbatim in `externalReferenceCompatibility.ts` (deliberately not extracted into a second shared helper, since a two-line duplication was judged lower-risk than adding a third shared dependency between v0.4 and v0.7 module boundaries for something this small).
|
|
122
|
+
|
|
123
|
+
## Old-behavior-unchanged proof
|
|
124
|
+
|
|
125
|
+
The pre-existing frozen regression test in `tests/unit/comparisonEngine.test.ts` (`'is comparable with no reasons beyond the always-present unassessed dimensions'`) asserts `result.reasons.map((r) => r.code)` equals exactly `['theme-unassessed', 'authenticated-state-unassessed', 'application-state-unassessed']` for a before/after pair with no `explicitState` on either side — this test was **not modified** and still passes unchanged, because neither observation declares `explicitState`, so the shared helper's "either value undefined" branch fires for all three dimensions, exactly reproducing the pre-Prompt-4 unconditional-unassessed behavior. Three new tests were added alongside it exercising the additive "both declare, match", "both declare, mismatch", and "only one declares" cases. Full v0.1–v0.6 regression suites (unit + browser + security) were re-run and are unaffected — see Validation below.
|
|
126
|
+
|
|
127
|
+
## Identity impacts
|
|
128
|
+
|
|
129
|
+
- `buildExternalReferenceRequestIdentity(imageSha256, format, width, height, supersedesReferenceId?, regions?, requirements?, applicability?)` — `applicability` is the new 8th, final, optional parameter, omitted entirely (never `null`) from the hashed semantic view when `undefined`. Verified: `buildExternalReferenceRequestIdentity(...args)` and `buildExternalReferenceRequestIdentity(...args, undefined)` produce byte-identical hashes.
|
|
130
|
+
- `buildRequestIdentity(request)` — `request.explicitState` is now included in the semantic view only when present (`...(request.explicitState ? { explicitState: request.explicitState } : {})`), mirroring the existing `scrollScenario` treatment exactly. The pre-existing frozen regression vector (`buildRequestIdentity(baseRequest())` === a specific fixed hash string) is asserted unchanged by a new test in `identity.test.ts`.
|
|
131
|
+
- No operational file path (`--state-file`'s or `--applicability-file`'s path argument) enters either identity function — both functions take only already-parsed, in-memory values, never a path.
|
|
132
|
+
|
|
133
|
+
## Schema / version decisions
|
|
134
|
+
|
|
135
|
+
No `SCHEMA_VERSION`/`EXTERNAL_REFERENCE_SCHEMA_VERSION` bump. Both new fields (`requestConfig.explicitState`, `ExternalReferenceArtifact.applicability`) are purely additive and optional, following the exact precedent set by `scrollScenario` (Prompt/Batch 3) and `regions`/`requirements` (v0.7 Prompts 2/3), none of which bumped their respective schema versions either.
|
|
136
|
+
|
|
137
|
+
## CLI changes
|
|
138
|
+
|
|
139
|
+
- `observe` gains `--state-file <json-file>`: unwrapped `{theme?, applicationState?, authenticatedState?}` object, no wrapper field, mirroring `--scroll-scenario-file`'s file-loading shape exactly (read → JSON.parse → plain-object-root check only; all semantic validation deferred to `normalizeRequest()`/`isValidExplicitStateDimensions`). Compatible with `--target`/`--targets-file`/`--scroll-scenario-file` (independent, non-conflicting flag).
|
|
140
|
+
- `import-reference` gains `--applicability-file <json-file>`: unwrapped raw applicability object (not a `{"requirements": [...]}`-style wrapper, since applicability is a single object, not a named list) — read → JSON.parse → plain-object-root check only; all semantic validation deferred to `isValidExternalReferenceApplicability`.
|
|
141
|
+
- Both commands' `--help` text, and `approve-reference --help`, were updated to document the new flag and its failure modes.
|
|
142
|
+
- `import-reference`/`approve-reference` success output gained one new line: `Applicability: declared|none`.
|
|
143
|
+
- CLI code owns only flag syntax, file reading, JSON parsing, and object-root shape validation for both new flags — zero semantic validation logic lives in `cli.ts` itself; every actual rule (label pattern, authenticated-state vocabulary, viewport bounds, "at least one dimension") is owned by `domain/explicitState.ts`/`domain/externalReferenceApplicability.ts`.
|
|
144
|
+
|
|
145
|
+
## Persistence decision
|
|
146
|
+
|
|
147
|
+
No new persisted artifact kind was introduced for the compatibility result. `evaluateReferenceCandidateCompatibility` is a pure, synchronous, on-demand function over two already-persisted artifacts (an `ExternalReferenceArtifact` and an `ObservationArtifact`), invoked directly by a caller (application code, a future CLI command, or a test) — never something the observer writes to disk automatically. Rationale: the result is cheap to recompute deterministically from its two inputs; persisting it would introduce a drift risk (a re-imported/re-observed artifact could silently disagree with a stale persisted compatibility record) with no corresponding benefit at this stage of the architecture. This decision may be revisited only if a later v0.7 prompt's architecture proves persistence necessary — documented per instruction, not assumed.
|
|
148
|
+
|
|
149
|
+
## Files changed
|
|
150
|
+
|
|
151
|
+
New:
|
|
152
|
+
- `src/domain/explicitState.ts`
|
|
153
|
+
- `src/domain/externalReferenceApplicability.ts`
|
|
154
|
+
- `src/domain/externalReferenceCompatibility.ts`
|
|
155
|
+
- `tests/unit/explicitState.test.ts`
|
|
156
|
+
- `tests/unit/externalReferenceApplicability.test.ts`
|
|
157
|
+
- `tests/unit/externalReferenceCompatibility.test.ts`
|
|
158
|
+
|
|
159
|
+
Modified:
|
|
160
|
+
- `src/domain/comparison.ts` (4 new reason codes, 2 new optional `ComparabilityReason` fields)
|
|
161
|
+
- `src/domain/comparisonEngine.ts` (extracted+exported `assessOptionalComparabilityDimension`; `evaluateComparability` now uses it additively)
|
|
162
|
+
- `src/domain/diagnostics.ts` (`invalid-reference-applicability` code)
|
|
163
|
+
- `src/domain/externalReference.ts` (`applicability?` field + validation)
|
|
164
|
+
- `src/domain/externalReferenceIdentity.ts` (`applicability` identity parameter)
|
|
165
|
+
- `src/domain/identity.ts` (`explicitState` identity inclusion)
|
|
166
|
+
- `src/domain/schema.ts` (`requestConfig.explicitState` defense-in-depth validation)
|
|
167
|
+
- `src/request/request.ts` (`explicitState` request field + validation)
|
|
168
|
+
- `src/application/externalReferencePersistenceService.ts` (`applicability` import/approve wiring, `hasApplicability` result field)
|
|
169
|
+
- `src/cli.ts` (`--state-file`, `--applicability-file`, help text, output lines)
|
|
170
|
+
- `src/index.ts` (public export surface for all of the above)
|
|
171
|
+
- `docs/ARCHITECTURE.md`, `docs/CONTRACTS.md`, `docs/WORKFLOWS.md`, `docs/COMMANDS.md`
|
|
172
|
+
- 11 existing test files extended with Prompt 4 coverage (see Tests below)
|
|
173
|
+
|
|
174
|
+
## Tests
|
|
175
|
+
|
|
176
|
+
857 unit tests total (779 pre-existing + 78 new/extended this prompt), across:
|
|
177
|
+
- New: `explicitState.test.ts` (10 tests), `externalReferenceApplicability.test.ts` (8 tests), `externalReferenceCompatibility.test.ts` (14 tests covering behaviors A–I plus identity/purity checks).
|
|
178
|
+
- Extended: `comparisonEngine.test.ts` (+3, v0.4 additive-assessment behavior), `identity.test.ts` (+4, `explicitState` identity), `externalReferenceIdentity.test.ts` (+4, `applicability` identity), `externalReference.test.ts` (+4, `applicability` schema validation), `schema.test.ts` (+3, `requestConfig.explicitState` validation), `request.test.ts` (+7, `explicitState` request normalization), `externalReferencePersistenceService.test.ts` (+4, import/approve applicability wiring), `cli.test.ts` (+9, `--state-file` CLI boundary + help text), `cliExternalReference.test.ts` (+6, `--applicability-file` CLI boundary + end-to-end import/approve).
|
|
179
|
+
|
|
180
|
+
## Validation results
|
|
181
|
+
|
|
182
|
+
All commands run from the repository root, after the implementation commit:
|
|
183
|
+
|
|
184
|
+
- `npm run typecheck` — pass, zero errors.
|
|
185
|
+
- `npm run lint` — pass, zero errors/warnings.
|
|
186
|
+
- `npm test` — 45 test files, 857 tests, all pass.
|
|
187
|
+
- `npm run build` — pass, clean `tsc` compile.
|
|
188
|
+
- `npm run check:docs` — pass (17 required files present, `ROADMAP.md` format intact).
|
|
189
|
+
- `git diff --check` — exit 0 (only benign LF→CRLF normalization notices on Windows checkout, no actual whitespace-error content).
|
|
190
|
+
- `npm pack --dry-run` — pass; new `dist/domain/explicitState.js`, `externalReferenceApplicability.js`, `externalReferenceCompatibility.js` (and their `.d.ts`/`.js.map`) confirmed present in the tarball listing alongside updated `dist/index.d.ts`.
|
|
191
|
+
- `npm run test:security` — pass (5 + 63 = 68 tests: `policy.test.ts` + real-Chromium `chromiumAdapter.test.ts`), run because this prompt changes state/config input surface.
|
|
192
|
+
- `npm run test:browser` — pass (9 files, 120 tests, real Chromium), run as full regression confirmation.
|
|
193
|
+
|
|
194
|
+
## Regression results
|
|
195
|
+
|
|
196
|
+
- Full v0.1–v0.6 unit suite: unaffected, all passing (779 pre-existing tests unchanged in assertions, all still passing verbatim).
|
|
197
|
+
- Full real-Chromium browser suite: 120/120 passing, unaffected.
|
|
198
|
+
- Full security suite: 68/68 passing, unaffected.
|
|
199
|
+
- The one pre-existing frozen `evaluateComparability` regression test (no-`explicitState` case) passes unchanged, proving the v0.4 additive-assessment change is genuinely additive, not a behavior change for any historical/legacy observation pair.
|
|
200
|
+
- The one pre-existing frozen `buildRequestIdentity` regression hash (`baseRequest()` with no `scrollScenario`/`explicitState`) passes unchanged, proving the `explicitState` identity extension is genuinely additive.
|
|
201
|
+
|
|
202
|
+
## Security impact
|
|
203
|
+
|
|
204
|
+
- No new external input surface beyond local JSON files the caller already controls (same trust boundary as `--targets-file`/`--scroll-scenario-file`/`--regions-file`/`--requirements-file`).
|
|
205
|
+
- `authenticatedState`'s closed two-value vocabulary and the complete absence of any credential/token/cookie/session-id field in `ExplicitStateDimensions`/`ExternalReferenceApplicability` were verified by direct type/field inspection — there is no field anywhere in either interface capable of holding a secret.
|
|
206
|
+
- `test:security` (policy + real-Chromium adapter tests) re-run and passing, confirming no regression to the existing safety/navigation policy surface (this prompt touches none of that code).
|
|
207
|
+
|
|
208
|
+
## Documentation changes
|
|
209
|
+
|
|
210
|
+
- `docs/CONTRACTS.md` — new "v0.7 Prompt 4 reference applicability and candidate-state compatibility" section (full type shapes, key rules, image-vs-viewport distinction, v0.4 reuse proof, persistence decision, identity impact, CLI summary).
|
|
211
|
+
- `docs/ARCHITECTURE.md` — new paragraph in the "Planned v0.7–v0.10" section describing the Prompt 4 module additions and the v0.4 extraction/reuse story.
|
|
212
|
+
- `docs/WORKFLOWS.md` — "Current external-reference foundation workflow" section retitled to "Prompts 1-4" and extended with `--applicability-file`/`--state-file` steps and the new compatibility-evaluation paragraph.
|
|
213
|
+
- `docs/COMMANDS.md` — `observe` options list extended with `--state-file`.
|
|
214
|
+
|
|
215
|
+
## Tooling incidents
|
|
216
|
+
|
|
217
|
+
None this prompt. No orchestrator was invoked (direct-implementation mode used throughout, consistent with Prompts 2–3); no background/speculative subagent writes occurred; the Prompt 1 stray-fork-writes stash remains untouched, unapplied, and unmined as precedent.
|
|
218
|
+
|
|
219
|
+
## Out-of-scope confirmation
|
|
220
|
+
|
|
221
|
+
This prompt implements no region/runtime binding, no candidate/reference geometry comparison, no fidelity PASS/FAIL evaluation, no style/color/typography comparison, no image/pixel similarity, no change to source correlation, no coding-agent correction logic, no rerender loop, no viewer, no annotation UI, and no automatic state/authentication detection of any kind. `evaluateReferenceCandidateCompatibility` reads only `reference.applicability` and `candidate.requestConfig` (viewport/explicitState) — it never reads `reference.regions`, `reference.requirements`, or any target/geometry evidence from the candidate.
|
|
222
|
+
|
|
223
|
+
## Known limitations
|
|
224
|
+
|
|
225
|
+
- Applicable-viewport comparison is an exact string-equality check on `"WxH"` — there is no tolerance/near-match concept for viewport compatibility (deliberately; a viewport is either the one the reference represents or it isn't, unlike the pixel-tolerance semantics that belong to Prompt 3's region-property requirements).
|
|
226
|
+
- `evaluateReferenceCandidateCompatibility` has no CLI command of its own yet (no `check-compatibility`-style entry point) — it is exposed only as a library function via `src/index.ts`, since Prompt 4's scope was the domain model and its reuse story, not a new user-facing workflow entry point. A future prompt may add a CLI surface once region binding (Prompt 5) makes an end-to-end command meaningful.
|
|
227
|
+
|
|
228
|
+
## Remaining risks
|
|
229
|
+
|
|
230
|
+
- None identified that block this prompt's own scope. The main forward risk is Prompt 5 (region↔runtime-target binding) needing to compose region-level and page-level (this prompt's) compatibility results coherently — flagged for that prompt's own precedent review, not something this prompt can or should preempt.
|
|
231
|
+
|
|
232
|
+
## Exact next action
|
|
233
|
+
|
|
234
|
+
v0.7 Prompt 5 — explicit reference-region ↔ runtime-target binding.
|