my-frontend-observer 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +32 -8
  3. package/dist/application/comparisonService.d.ts +56 -0
  4. package/dist/application/comparisonService.js +77 -0
  5. package/dist/application/comparisonService.js.map +1 -0
  6. package/dist/artifacts/artifactReader.d.ts +19 -0
  7. package/dist/artifacts/artifactReader.js +36 -0
  8. package/dist/artifacts/artifactReader.js.map +1 -0
  9. package/dist/artifacts/comparisonArtifactWriter.d.ts +41 -0
  10. package/dist/artifacts/comparisonArtifactWriter.js +67 -0
  11. package/dist/artifacts/comparisonArtifactWriter.js.map +1 -0
  12. package/dist/cli.js +220 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/domain/comparison.d.ts +198 -0
  15. package/dist/domain/comparison.js +324 -0
  16. package/dist/domain/comparison.js.map +1 -0
  17. package/dist/domain/comparisonEngine.d.ts +48 -0
  18. package/dist/domain/comparisonEngine.js +694 -0
  19. package/dist/domain/comparisonEngine.js.map +1 -0
  20. package/dist/domain/comparisonIdentity.d.ts +13 -0
  21. package/dist/domain/comparisonIdentity.js +46 -0
  22. package/dist/domain/comparisonIdentity.js.map +1 -0
  23. package/dist/domain/evidence.d.ts +2 -0
  24. package/dist/domain/evidence.js +4 -0
  25. package/dist/domain/evidence.js.map +1 -1
  26. package/dist/domain/relationships.d.ts +168 -0
  27. package/dist/domain/relationships.js +343 -0
  28. package/dist/domain/relationships.js.map +1 -0
  29. package/dist/index.d.ts +14 -1
  30. package/dist/index.js +8 -1
  31. package/dist/index.js.map +1 -1
  32. package/docs/ARCHITECTURE.md +76 -3
  33. package/docs/CI_CD.md +29 -0
  34. package/docs/COMMANDS.md +137 -0
  35. package/docs/CONTRACTS.md +96 -4
  36. package/docs/CURRENT_STATE.md +102 -9
  37. package/docs/DEVELOPMENT.md +33 -10
  38. package/docs/PROJECT_OVERVIEW.md +16 -12
  39. package/docs/QUICKSTART.md +5 -0
  40. package/docs/RELEASE.md +10 -8
  41. package/docs/ROADMAP.md +4 -0
  42. package/docs/SECURITY.md +14 -1
  43. package/docs/WORKFLOWS.md +56 -6
  44. package/package.json +1 -1
package/docs/COMMANDS.md CHANGED
@@ -225,6 +225,143 @@ persists honestly - typically as `partial` - carrying the same
225
225
  `target-missing`/`target-ambiguous`/`browser-evidence-unavailable` diagnostic
226
226
  that any other unresolved configured target would produce.
227
227
 
228
+ ## `compare`
229
+
230
+ **Current status: shipped as part of the published `my-frontend-observer@0.4.0`
231
+ package.** Comparison schema is `1.0.0`, independent of and never reused for
232
+ the observation schema (`1.2.0`).
233
+
234
+ `my-frontend-observer compare` (or `node dist/cli.js compare` from a source
235
+ checkout) reads two already-persisted observation artifacts and derives
236
+ before/after evidence purely from their existing content:
237
+
238
+ ```text
239
+ my-frontend-observer compare --before <observation-artifact-root> --after <observation-artifact-root> --output <directory> [options]
240
+ ```
241
+
242
+ Required:
243
+
244
+ - `--before <path>` — root directory of the "before" persisted observation
245
+ artifact (the directory containing its `manifest.json`, as produced by
246
+ `observe`).
247
+ - `--after <path>` — root directory of the "after" persisted observation
248
+ artifact.
249
+ - `--output <directory>` — portable, relative output location for the
250
+ comparison artifact (same contract as `observe --output`).
251
+
252
+ Options:
253
+
254
+ - `--config-file <json-file>` — loads a comparison configuration directly
255
+ (no wrapper field): `{ "geometryTolerancePx": <0-10>,
256
+ "expectedDependencies": [...] }`. Without it, `geometryTolerancePx`
257
+ defaults to `0.5` CSS px with no declared dependencies. As with
258
+ `--targets-file`/`--scroll-scenario-file`, `--config-file` only validates
259
+ file readability, JSON validity, and a non-array object root; every
260
+ semantic rule (tolerance bounds, dependency property/direction
261
+ vocabulary, dependency source marker) is enforced by the same domain
262
+ validator the comparison engine itself uses.
263
+ - `--help` — show `compare` usage.
264
+
265
+ **Comparison never launches a browser.** It reads two manifests through the
266
+ existing observation-artifact reader, runs the pure comparison engine, and
267
+ persists a portable `manifest.json` — no navigation, no target
268
+ re-resolution, no Chromium process.
269
+
270
+ On success the command prints exactly:
271
+
272
+ ```text
273
+ Comparison: <comparison-id>
274
+ State: <comparable|comparable-with-warnings|incomparable>
275
+ Artifact: <comparison-artifact-root>
276
+ Differences: <count>
277
+ Relationship changes: <count>
278
+ Diagnostics: <count>
279
+ ```
280
+
281
+ and exits `0` — **including when `State` is `incomparable`**: comparison
282
+ determining that two observations should not be treated as equivalent
283
+ frontend states is itself a successful outcome, not a failure. The command
284
+ exits nonzero only for invalid CLI syntax, an unreadable/malformed/
285
+ structurally-invalid source artifact, invalid comparison configuration, or
286
+ a failed artifact write.
287
+
288
+ ### Comparability
289
+
290
+ Before any rendered difference is calculated, the engine evaluates whether
291
+ the two observations are comparable at all:
292
+
293
+ - **Hard incompatibilities** (force `incomparable`): different logical page
294
+ URL, different viewport, different browser engine, or a mismatched scroll
295
+ scenario configuration (no scenario vs. a scenario, or two different
296
+ scenario configurations).
297
+ - **Warnings** (still `comparable-with-warnings`, comparison proceeds):
298
+ different producer package version, different browser version, or a
299
+ changed/added/removed configured target.
300
+ - **Unassessed dimensions** the observer does not yet model (theme,
301
+ authenticated state, application state) are always recorded, never
302
+ silently claimed identical.
303
+
304
+ An `incomparable` result still persists a structurally valid
305
+ `ComparisonArtifact`: the comparability reasons are recorded, and ordinary
306
+ rendered differences/relationship changes stay empty rather than fabricated.
307
+
308
+ ### Difference and relationship evidence
309
+
310
+ For a `comparable`/`comparable-with-warnings` result, the manifest's
311
+ `differences` and `relationshipChanges` arrays carry structured before/
312
+ after evidence: appeared/disappeared targets (only for a stable target name
313
+ configured on both sides — a target added/removed from configuration is
314
+ recorded separately as a `configurationChanges` entry, never fabricated as
315
+ appeared/disappeared), moved/resized targets, visibility changes, clipping
316
+ changes, actual dimensional overflow changes, DOM containment changes,
317
+ page-size changes, scroll-owner changes, and layout-relationship
318
+ transitions (e.g. `does-not-overlap` → `overlaps`, or
319
+ `document-width-fits-viewport` → `document-width-exceeds-viewport`) reused
320
+ verbatim from the same canonical relationship engine `observe` output feeds
321
+ Batch 2's `deriveLayoutRelationships`.
322
+
323
+ ### Explicit dependency evidence (non-causal)
324
+
325
+ `--config-file`'s `expectedDependencies` lets you declare an expected
326
+ layout relationship such as "`navigation.width` decreases →
327
+ `workspace.width` increases" using only the frozen `x`/`y`/`width`/`height`
328
+ property vocabulary and `increase`/`decrease`/`change`/`unchanged`
329
+ direction vocabulary. Each declaration is evaluated independently against
330
+ the two observations and persists exactly one outcome: `consistent`,
331
+ `not-observed`, `contradictory-to-declaration`, or `unavailable`. **The
332
+ observer never infers a dependency from co-change, and never emits a
333
+ causal claim, a PASS/FAIL verdict, or a change-contract decision** — v0.4
334
+ produces comparison evidence; whether that evidence satisfies some
335
+ contract is v0.5+ scope.
336
+
337
+ ### Path privacy
338
+
339
+ `--before`, `--after`, `--config-file`, and `--output` are operational
340
+ filesystem input only. None of them affect `comparisonRequestId`, and none
341
+ of them are written into the persisted manifest — the manifest instead
342
+ retains logical source references (`observationId`, `requestId`,
343
+ `producer`, `observationSchemaVersion`, and the source `screenshot.path`).
344
+ Two semantically identical observation/config pairs read from different
345
+ filesystem locations produce the same `comparisonRequestId`; each execution
346
+ still gets a fresh `comparisonId`.
347
+
348
+ ### Source observations remain immutable
349
+
350
+ Comparison is read-only with respect to its inputs: it never modifies
351
+ either source observation's `manifest.json` or `screenshot.png`, and it
352
+ never copies screenshot bytes into the comparison directory — the
353
+ comparison artifact directory contains `manifest.json` only.
354
+
355
+ Example:
356
+
357
+ ```powershell
358
+ node dist/cli.js compare `
359
+ --before observations/<before-id> `
360
+ --after observations/<after-id> `
361
+ --output comparisons `
362
+ --config-file .\comparison-config.json
363
+ ```
364
+
228
365
  ## Foundation commands
229
366
 
230
367
  - `npm install` — install dependencies (includes the `playwright` runtime
package/docs/CONTRACTS.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Current contracts
4
4
 
5
- The observation artifact contract is published as `my-frontend-observer@0.3.0`
5
+ The observation artifact contract is published as `my-frontend-observer@0.4.0`
6
6
  and proven both from the source checkout and from the packed npm tarball,
7
7
  on Windows, Linux, and macOS. The observation schema is `1.2.0` (see "v0.2
8
8
  target contract" and "v0.3 scroll scenario contract" below):
@@ -81,9 +81,13 @@ supplies the structured `{ "targets": [...] }` collection (see
81
81
  existing `--target id=css-selector` shorthand - the two are mutually
82
82
  exclusive per invocation, and both converge on the same
83
83
  `normalizeRequest()`/browser-resolver/artifact path, so a semantic
84
- observation produces exactly the same `manifest.json` shape (schema `1.1.0`)
85
- as a CSS-shorthand one. `--targets-file`'s local input path is never part of
86
- the persisted request identity or artifact.
84
+ observation produces exactly the same `manifest.json` shape as a
85
+ CSS-shorthand one. Schema `1.1.0` was the v0.2 published artifact schema;
86
+ the current v0.4 package emits schema `1.2.0` for both target-input modes
87
+ (target semantics are unchanged from v0.2 - see the v0.3 scroll scenario
88
+ contract below for what schema `1.2.0` actually adds). `--targets-file`'s
89
+ local input path is never part of the persisted request identity or
90
+ artifact.
87
91
 
88
92
  ## v0.3 scroll scenario contract (shipped as part of this release)
89
93
 
@@ -158,6 +162,94 @@ public entry point is `my-frontend-observer observe --scroll-scenario-file
158
162
  directly, and its local path is operational input only, exactly like
159
163
  `--targets-file`'s path - never persisted, never part of request identity.
160
164
 
165
+ ## v0.4 comparison contract (shipped as part of this release)
166
+
167
+ **Current status: shipped as part of the published `my-frontend-observer@0.4.0`
168
+ package.** Observation schema remains `1.2.0`. Comparison is a distinct
169
+ artifact kind and schema, never a bump to the observation schema:
170
+
171
+ - artifact kind: `my-frontend-observer/comparison`;
172
+ - comparison schema: `1.0.0`.
173
+
174
+ **Geometry tolerance**: `ComparisonConfig.geometryTolerancePx`, default
175
+ `0.5` CSS px, bounded `[0, 10]`. Suppresses insignificant subpixel noise
176
+ only - never a design contract, never permission for a change.
177
+
178
+ **Layout relationship graph**: `deriveLayoutRelationships(observation,
179
+ options?)` derives, per observation, a bounded `LayoutRelationshipGraph`
180
+ among configured targets only (≤20 targets, ≤190 unordered pairs):
181
+ horizontal order (`left-of`/`right-of`/`horizontally-overlapping`),
182
+ vertical order (`above`/`below`/`vertically-overlapping`), area overlap
183
+ (`overlaps`/`does-not-overlap`), relative width (`wider-than`/
184
+ `narrower-than`/`equal-width-within-tolerance`), geometric fit
185
+ (`fits-inside`/`does-not-fit-inside` - geometry-only, deliberately distinct
186
+ from DOM containment), vertical sequencing (`follows-vertically`), and one
187
+ page-level relationship (`document-width-fits-viewport`/
188
+ `document-width-exceeds-viewport`). Every relationship carries explicit
189
+ evidence-path provenance back to the source observation. A configured
190
+ target lacking usable geometry is listed as honestly unresolved
191
+ (`not-found`/`ambiguous`/`unavailable`/`hidden`), never fabricated as a
192
+ zero-sized region.
193
+
194
+ **Comparability**: evaluated before any rendered difference, using exactly
195
+ three states (`comparable`/`comparable-with-warnings`/`incomparable`) with
196
+ structured reasons, never a bare boolean. Hard incompatibilities (page URL,
197
+ viewport, browser engine, scroll-scenario configuration mismatch) force
198
+ `incomparable`; producer-version, browser-version, and target-configuration
199
+ differences are warning-only; theme/authenticated-state/application-state
200
+ identity are recorded as `unassessed` dimensions the observer does not yet
201
+ model - never silently claimed identical. An `incomparable` result still
202
+ persists a structurally valid `ComparisonArtifact` with empty rendered
203
+ differences, not a fabricated comparison.
204
+
205
+ **Difference categories**: `appeared`/`disappeared` (only for a stable
206
+ target name configured on both sides, transitioning between a definite
207
+ `not-found` and `matched` resolution status - never for a target merely
208
+ added/removed from configuration, which is its own separate
209
+ `configurationChanges` entry), `moved`/`resized` (tolerance-aware, a target
210
+ may be both), `visibility-changed`, `clipping-changed` (reusing the
211
+ canonical `deriveTargetClipping` helper, never re-derived), `horizontal-
212
+ overflow-changed`/`vertical-overflow-changed` (actual dimensional overflow,
213
+ reusing the existing `deriveOverflowEvidence` helper - never inferred from
214
+ a CSS declaration alone), `containment-changed` (reusing existing v0.2
215
+ `TargetContainment` evidence), `page-size-changed`, `scroll-owner-changed`
216
+ (comparing `scrollScenarioEvidence.scrollOwner` only when scenario
217
+ *configuration* already matched), `relative-position-changed` (a relation
218
+ in the horizontal-order/vertical-order/area-overlap families changed - kept
219
+ distinct from plain absolute target movement) and `relationship-changed`
220
+ (every other relationship-family transition). Relationship changes are
221
+ matched by structural identity (family + subject/related target, or the
222
+ page-level key), never by array position.
223
+
224
+ **Explicit dependency evidence**: `ComparisonConfig.expectedDependencies`
225
+ lets a caller declare an expected relationship between two targets' numeric
226
+ properties (`x`/`y`/`width`/`height`) and directions (`increase`/
227
+ `decrease`/`change`/`unchanged`), always carrying `source:
228
+ "explicit-config"`. The observer never synthesizes a declaration from
229
+ observed co-change. Each declaration evaluates independently to exactly one
230
+ of `consistent`/`not-observed`/`contradictory-to-declaration`/
231
+ `unavailable` - never a causal claim (no `causedBy`/`causalConfidence`/
232
+ `causalScore`/`dependencyStrength`) and never a PASS/FAIL/approval verdict.
233
+ That distinction (evidence vs. contract verdict) is the boundary between
234
+ v0.4 and v0.5+.
235
+
236
+ **Comparison identity**: `comparisonRequestId` is a pure, deterministic
237
+ function of `{beforeObservationId, afterObservationId, normalized
238
+ ComparisonConfig}` - direction-sensitive (`compare(A, B) !==
239
+ compare(B, A)`), and never includes an operational filesystem path.
240
+ `comparisonId` is fresh per execution (same pattern as `observationId`).
241
+
242
+ **Source references**: the comparison artifact retains enough logical
243
+ identity to trace back to its authoritative source observations
244
+ (`observationId`, `requestId`, `producer`, `observationSchemaVersion`, and
245
+ the source `screenshot.path`) without embedding the full
246
+ `ObservationArtifact` or copying screenshot bytes. The persisted comparison
247
+ directory contains `manifest.json` only.
248
+
249
+ The public entry point is `my-frontend-observer compare --before <root>
250
+ --after <root> --output <directory> [--config-file <json-file>]` (see
251
+ `docs/COMMANDS.md`) - comparison itself never launches a browser.
252
+
161
253
  ## Approved v0.1 design inputs
162
254
 
163
255
  The historical greenfield scaffold plan recorded these v0.1 design decisions:
@@ -1,7 +1,8 @@
1
1
  # Current State
2
2
 
3
- The project is published at package version `0.3.0` (roadmap v0.3, Runtime
4
- Scrolling, Overflow, and Visibility Behavior; observation schema `1.2.0`).
3
+ The project is published at package version `0.4.0` (roadmap v0.4, Layout
4
+ Relationships, Dependency Evidence, and Before/After Comparison; observation
5
+ schema `1.2.0`; comparison schema `1.0.0`).
5
6
 
6
7
  ## Greenfield foundation established
7
8
 
@@ -221,15 +222,107 @@ consumer environment on Windows, Linux, and macOS before release.
221
222
  unchanged. Proven via real Chromium (`tests/browser/cliObserve.test.ts`)
222
223
  and the built `dist/cli.js` (`scripts/dev/builtCliScrollScenarioSmoke.mjs`).
223
224
 
225
+ ## v0.4 status (Layout Relationships, Dependency Evidence, and Before/After Comparison) - released as 0.4.0
226
+
227
+ v0.4 is implemented and released as package version `0.4.0`; observation
228
+ schema remains `1.2.0`; comparison schema is `1.0.0`. It was validated as a
229
+ packed npm tarball in a clean consumer environment on Windows, Linux, and
230
+ macOS - covering the legacy CSS-shorthand `--target` path, the structured
231
+ `--targets-file` path, both `--scroll-scenario-file` action kinds, and the
232
+ installed `compare` command (comparable and incomparable cases) - before
233
+ release.
234
+
235
+ - **Batch 1** froze the `my-frontend-observer/comparison` artifact contract
236
+ (schema `1.0.0`, independent of and never reused for the observation
237
+ schema): `ComparisonConfig` (geometry tolerance, default `0.5`px, bounded
238
+ `[0, 10]`px), the bounded layout-relationship vocabulary (horizontal/
239
+ vertical order, area overlap, relative width, geometric fit, vertical
240
+ sequencing, page-width fit, clipping), comparability states, the
241
+ before/after difference vocabulary, and the non-causal explicit
242
+ dependency-evidence contract, plus `comparisonRequestId`/`comparisonId`
243
+ identity (`src/domain/relationships.ts`, `src/domain/comparison.ts`,
244
+ `src/domain/comparisonIdentity.ts`). No derivation, comparison, or
245
+ persistence.
246
+ - **Batch 2** implemented the one canonical pure derivation engine,
247
+ `deriveLayoutRelationships(observation, options?)`
248
+ (`src/domain/relationships.ts`): consumes an existing `ObservationArtifact`
249
+ only (no Chromium, no re-resolution, no DOM access) and derives a bounded,
250
+ traceable `LayoutRelationshipGraph` among configured targets - stable
251
+ target identity, deterministic configured-target ordering, honest
252
+ unresolved-target handling (not-found/ambiguous/unavailable/hidden, never
253
+ a fabricated zero-sized region), and evidence-reference provenance for
254
+ every derived relationship. DOM containment is read directly from the
255
+ existing `TargetContainment` evidence rather than re-derived, and stays
256
+ distinct from geometric fit. A standalone `deriveTargetClipping(record)`
257
+ derives the frozen clipping concept per target from existing layout/style
258
+ evidence.
259
+ - **Batch 3** implemented the pure before/after comparison engine,
260
+ `compareObservations(before, after, config?)`
261
+ (`src/domain/comparisonEngine.ts`): validates both source observations,
262
+ evaluates comparability before any rendered difference is calculated
263
+ (hard page-URL/viewport/browser-engine/scroll-scenario mismatches;
264
+ producer/browser-version and target-configuration warnings), reuses
265
+ `deriveLayoutRelationships` unchanged for both sides, and derives target/
266
+ page differences (appeared/disappeared, moved, resized, visibility,
267
+ clipping, actual overflow, DOM containment, page size, scroll-owner) and
268
+ relationship changes (matched by family + subject/related target, never
269
+ array position) - all without launching Chromium, re-resolving targets, or
270
+ mutating either input observation. Explicit `ComparisonConfig.
271
+ expectedDependencies` are evaluated into non-causal
272
+ consistent/not-observed/contradictory-to-declaration/unavailable outcomes
273
+ only; the observer never infers a dependency from co-change. Comparison
274
+ identity reuses the existing Batch 1 `buildComparisonRequestIdentity`/
275
+ `buildComparisonIdentity` verbatim. Persistence
276
+ (`src/artifacts/comparisonArtifactWriter.ts#writeComparisonArtifact`,
277
+ atomic, `<outputLocation>/<comparisonId>/manifest.json` only, no copied
278
+ screenshots) and the application-level `compareAndPersist` use case
279
+ (`src/application/comparisonService.ts`) are implemented; a narrow
280
+ `readObservationArtifact` reader
281
+ (`src/artifacts/artifactReader.ts`) is established ahead of the Batch 4
282
+ CLI.
283
+ - **Batch 4** exposed the existing comparison workflow through the real
284
+ public CLI: `my-frontend-observer compare --before <observation-artifact-
285
+ root> --after <observation-artifact-root> --output <directory>
286
+ [--config-file <json-file>]` (see `docs/COMMANDS.md`). The CLI stays thin
287
+ - `src/cli.ts` parses arguments, optionally loads a config file (file
288
+ readability/JSON validity/object-root only, exactly like
289
+ `--targets-file`/`--scroll-scenario-file`), and delegates to one new
290
+ thin application-layer orchestration function,
291
+ `compareAndPersistFromArtifactRoots`
292
+ (`src/application/comparisonService.ts`), which reads both observation
293
+ roots through the existing `readObservationArtifact` reader and calls the
294
+ existing `compareAndPersist` exactly once - no comparability/geometry/
295
+ relationship/dependency logic lives in the CLI, and comparison itself
296
+ never launches Chromium (`src/cli.ts` still imports nothing from
297
+ `src/artifacts/` or `src/browser/`, matching the pre-existing observe-CLI
298
+ import-boundary test). `comparable`, `comparable-with-warnings`, and
299
+ `incomparable` all exit `0` - each is a successful comparison outcome;
300
+ only a genuine parse/read/domain/persistence failure exits nonzero.
301
+ Operational paths (`--before`/`--after`/`--config-file`/`--output`) never
302
+ affect `comparisonRequestId` and are never written into the persisted
303
+ manifest. Proven end-to-end via real Chromium
304
+ (`tests/browser/cliCompare.test.ts`) and the built `dist/cli.js`
305
+ (`scripts/dev/builtCliCompareSmoke.mjs`): unchanged/moved/resized/
306
+ appeared/disappeared/configuration-only-change/overlap/geometric-fit/
307
+ page-overflow/clipping/scroll-owner cases, plus an explicit
308
+ `--config-file` dependency-evidence case, all through the public command
309
+ surface.
310
+
311
+ v0.4's canonical relationship derivation, before/after comparison,
312
+ comparability, differences, relationship changes, explicit dependency
313
+ evidence, comparison persistence, and public `compare` CLI are all
314
+ implemented, exercised end-to-end, packed-validated cross-platform, and
315
+ released.
316
+
224
317
  ## Not implemented
225
318
 
226
- - Layout/spatial relationship engine, before/after comparison, frontend
227
- contracts/change scope, source ownership, my-dev-kit runtime/static
228
- integration, orchestrator/lab product integration, viewer, and annotation
229
- all remain unimplemented (v0.4+).
319
+ - v0.5+ frontend contracts/change scope (baseline approval, requested/
320
+ protected/preserved change scope, PASS/FAIL verdicts), source ownership,
321
+ my-dev-kit runtime/static integration, orchestrator/lab product
322
+ integration, viewer, and annotation all remain unimplemented.
230
323
 
231
324
  ## Next target
232
325
 
233
- v0.1, v0.2, and v0.3 are implemented, validated, and released (`0.1.0`,
234
- `0.2.0`, `0.3.0`). v0.4 (Layout Relationships, Dependency Evidence, and
235
- Before/After Comparison) is the next planned version.
326
+ v0.1-v0.4 are implemented, validated, and released (`0.1.0`, `0.2.0`,
327
+ `0.3.0`, `0.4.0`). v0.5 (Executable Frontend Contracts and Explicit Change
328
+ Scope) is next.
@@ -62,10 +62,11 @@ It is what `.github/workflows/pre-release-readiness.yml` runs identically on
62
62
  Windows, Linux, and macOS against one shared candidate tarball (see
63
63
  `docs/CI_CD.md`); it can also be run locally the same way the workflow runs
64
64
  it. It is readiness/CI infrastructure only, not part of the published
65
- package and never imported by production code. It exercises both the
66
- legacy CSS-shorthand `--target` packed-observation shape and the
67
- structured semantic `--targets-file` shape in the same run - see
68
- `docs/CI_CD.md` for the current v0.2 readiness coverage.
65
+ package and never imported by production code. In the same run it
66
+ exercises the legacy CSS-shorthand `--target` packed-observation shape,
67
+ the structured semantic `--targets-file` shape, a `window-scroll-by`
68
+ scroll scenario, and a `target-scroll-by` scroll scenario - see
69
+ `docs/CI_CD.md` for the current readiness coverage.
69
70
 
70
71
  `scripts/dev/builtCliTargetsFileSmoke.mjs` is a separate, narrower v0.2
71
72
  development smoke, added alongside the `--targets-file` implementation: it
@@ -93,11 +94,33 @@ locally after `npm run build`:
93
94
  node scripts/dev/builtCliScrollScenarioSmoke.mjs
94
95
  ```
95
96
 
96
- Unlike `scripts/ci/runPackedObservationSmoke.mjs`, neither of these dev
97
+ `scripts/dev/builtCliCompareSmoke.mjs` is the v0.4 equivalent, added
98
+ alongside the `compare` command implementation (shipped as part of the
99
+ published `0.4.0` package - see `docs/CURRENT_STATE.md`): it runs the built
100
+ `dist/cli.js` twice as
101
+ `observe` against an inline disposable local HTTP fixture whose served
102
+ content changes deterministically between the two runs (a real moved/
103
+ resized target, and a page-width transition from fitting to exceeding the
104
+ viewport), then runs the built `dist/cli.js compare` against the two
105
+ resulting persisted observation artifacts. It validates artifact kind/
106
+ schema `1.0.0`, `comparability: "comparable"`, source observation
107
+ references, at least one real `moved` difference and one real page-width
108
+ relationship change, that the comparison directory contains `manifest.json`
109
+ only, that no operational filesystem path leaked into the persisted
110
+ manifest, and that both source observation manifests are byte-identical
111
+ before and after the comparison ran. Run it locally after `npm run build`:
112
+
113
+ ```powershell
114
+ node scripts/dev/builtCliCompareSmoke.mjs
115
+ ```
116
+
117
+ Unlike `scripts/ci/runPackedObservationSmoke.mjs`, none of these three dev
97
118
  smokes is wired into any CI workflow or is a release gate - they are
98
119
  source-checkout development evidence only, proving the built CLI's
99
- `--targets-file`/`--scroll-scenario-file` behavior without installing a
100
- packed tarball or requiring cross-platform infrastructure. Neither is part
101
- of the published package. Cross-platform packed validation of the v0.3
102
- scroll-scenario behavior is `scripts/ci/runPackedObservationSmoke.mjs`'s
103
- responsibility (see `docs/CI_CD.md`), and has been completed.
120
+ `--targets-file`/`--scroll-scenario-file`/`compare` behavior without
121
+ installing a packed tarball or requiring cross-platform infrastructure.
122
+ None is part of the published package. Cross-platform packed validation of
123
+ both the v0.1-v0.3 observation behavior and the v0.4 `compare` command is
124
+ `scripts/ci/runPackedObservationSmoke.mjs`'s responsibility (see
125
+ `docs/CI_CD.md`) - the same script, against the same single candidate
126
+ tarball per platform.
@@ -16,16 +16,20 @@ The responsibility split is stable:
16
16
  ## Current repository state
17
17
 
18
18
  v0.1, Runtime Observation Foundation; v0.2, Stable Semantic Targets and
19
- Region Identity; and v0.3, Runtime Scrolling, Overflow, and Visibility
20
- Behavior, are released, published to npm (current version `0.3.0`,
21
- observation schema `1.2.0`) and validated as a packed npm tarball in a
22
- clean consumer environment across Windows, Linux, and macOS: a real
23
- `observe` CLI command launches Chromium, enforces loopback-only safety,
24
- captures bounded page/target evidence via legacy CSS-shorthand targets,
25
- structured semantic `--targets-file` targets, or a bounded
26
- `--scroll-scenario-file` runtime scroll scenario (`window-scroll-by` or
27
- `target-scroll-by`), and persists one portable local artifact - see
28
- `docs/CURRENT_STATE.md` for the implementation summary. v0.4–v0.10 remain
19
+ Region Identity; v0.3, Runtime Scrolling, Overflow, and Visibility Behavior;
20
+ and v0.4, Layout Relationships, Dependency Evidence, and Before/After
21
+ Comparison, are released, published to npm (current version `0.4.0`,
22
+ observation schema `1.2.0`, comparison schema `1.0.0`) and validated as a
23
+ packed npm tarball in a clean consumer environment across Windows, Linux,
24
+ and macOS: a real `observe` CLI command launches Chromium, enforces
25
+ loopback-only safety, captures bounded page/target evidence via legacy
26
+ CSS-shorthand targets, structured semantic `--targets-file` targets, or a
27
+ bounded `--scroll-scenario-file` runtime scroll scenario
28
+ (`window-scroll-by` or `target-scroll-by`), and persists one portable local
29
+ artifact; a real `compare` CLI command reads two already-persisted
30
+ observation artifacts and derives before/after layout-relationship and
31
+ difference evidence without launching a browser - see
32
+ `docs/CURRENT_STATE.md` for the implementation summary. v0.5–v0.10 remain
29
33
  future and unimplemented.
30
34
 
31
35
  The revised dependency path reaches practical coding-agent use before graphical
@@ -52,8 +56,8 @@ Repository-local authorities and navigation:
52
56
  capability plan and cross-milestone rules.
53
57
  - [ROADMAP.md](ROADMAP.md) owns version-level direction without prewritten
54
58
  implementation batches.
55
- - [CURRENT_STATE.md](CURRENT_STATE.md) records only current scaffold and release
56
- state.
59
+ - [CURRENT_STATE.md](CURRENT_STATE.md) records current implementation and
60
+ release state.
57
61
 
58
62
  Historical greenfield artifacts and reports are retained as evidence that an
59
63
  earlier run overreached into v0.1; they are not current-state authority.
@@ -25,6 +25,11 @@ See [COMMANDS.md](COMMANDS.md) for the full flag reference, including the
25
25
  `--targets-file` structured semantic-target input and the
26
26
  `--scroll-scenario-file` bounded runtime scroll scenario input.
27
27
 
28
+ Once you have two such artifacts, `node dist/cli.js compare --before
29
+ <root> --after <root> --output comparisons` derives before/after evidence
30
+ between them without launching a browser again - see
31
+ [COMMANDS.md](COMMANDS.md#compare) for details.
32
+
28
33
  To validate the repository itself instead:
29
34
 
30
35
  ```powershell
package/docs/RELEASE.md CHANGED
@@ -1,16 +1,18 @@
1
1
  # Release
2
2
 
3
- `v0.3.0` is published to npm as `my-frontend-observer`, validated on
3
+ `v0.4.0` is published to npm as `my-frontend-observer`, validated on
4
4
  Windows, Linux, and macOS as an installed packed-tarball consumer prior to
5
5
  publication (covering the legacy CSS-shorthand `--target` path, the
6
- structured semantic `--targets-file` path, and the bounded
6
+ structured semantic `--targets-file` path, the bounded
7
7
  `--scroll-scenario-file` `window-scroll-by`/`target-scroll-by` runtime
8
- scroll scenario path). No project license has been declared yet; that
8
+ scroll scenario path, and the installed `compare` command's comparable and
9
+ incomparable cases). No project license has been declared yet; that
9
10
  decision remains open for a later explicit task.
10
11
 
11
- Observation schema version and package version remain separate: package
12
- version is `0.3.0`; observation schema is `1.2.0` and does not change
13
- automatically with the package version.
12
+ Observation, comparison, and package version remain separate: package
13
+ version is `0.4.0`; observation schema is `1.2.0` and comparison schema is
14
+ `1.0.0`, neither of which changes automatically with the package version.
14
15
 
15
- Prior releases: `v0.2.0` (Stable Semantic Targets and Region Identity),
16
- `v0.1.0` (Runtime Observation Foundation) - see `CHANGELOG.md`.
16
+ Prior releases: `v0.3.0` (Runtime Scrolling, Overflow, and Visibility
17
+ Behavior), `v0.2.0` (Stable Semantic Targets and Region Identity), `v0.1.0`
18
+ (Runtime Observation Foundation) - see `CHANGELOG.md`.
package/docs/ROADMAP.md CHANGED
@@ -77,6 +77,10 @@ syntax, stabilization, and visibility thresholds.
77
77
 
78
78
  ## v0.4 — Layout Relationships, Dependency Evidence, and Before/After Comparison
79
79
 
80
+ Current status: released as `0.4.0`, published to npm and validated as a
81
+ packed npm tarball in a clean consumer environment on Windows, Linux, and
82
+ macOS. See `docs/CURRENT_STATE.md` for the implementation summary.
83
+
80
84
  Objective/problem: explain whole-layout consequences rather than isolated
81
85
  numbers. Required capabilities are containment/order/overlap/fit relationships,
82
86
  comparable observation identity, before/after differences, appearance and
package/docs/SECURITY.md CHANGED
@@ -24,12 +24,25 @@ tests:
24
24
  unexpected internal error);
25
25
  - the observed target's own content/source is never modified by observation.
26
26
 
27
+ ## Comparison (`compare`, shipped as part of the published `0.4.0` package)
28
+
29
+ `my-frontend-observer compare` introduces no new network or browser
30
+ surface: it never
31
+ launches Chromium, never navigates, and never re-observes a target - it only
32
+ reads two local, already-persisted observation-artifact `manifest.json`
33
+ files (`src/artifacts/artifactReader.ts`) through the same structural
34
+ validator the observation writer uses, computes a pure in-memory
35
+ comparison, and writes one local comparison `manifest.json`
36
+ (`src/artifacts/comparisonArtifactWriter.ts`). Manifest content is parsed
37
+ as JSON only and is never executed (no `eval`, no dynamic code loading from
38
+ a manifest).
39
+
27
40
  ## Not yet addressed
28
41
 
29
42
  Certificate-failure-specific handling, permission-prompt-specific handling
30
43
  (Chromium's default deny-all applies; no permission is ever explicitly
31
44
  granted), and any non-loopback/remote browsing mode remain unimplemented and
32
- out of scope. `my-frontend-observer@0.3.0` is published to npm, and a
45
+ out of scope. `my-frontend-observer@0.4.0` is published to npm, and a
33
46
  pre-release readiness CI workflow (Windows/Linux/macOS packed-candidate
34
47
  validation) already exists (see `docs/CI_CD.md`); these are no longer future
35
48
  decisions. Those facts do not expand the security scope above: remote