my-frontend-observer 0.1.0 → 0.3.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 (46) hide show
  1. package/CHANGELOG.md +82 -1
  2. package/README.md +30 -7
  3. package/dist/application/observationPersistence.js +1 -0
  4. package/dist/application/observationPersistence.js.map +1 -1
  5. package/dist/browser/chromiumAdapter.js +58 -4
  6. package/dist/browser/chromiumAdapter.js.map +1 -1
  7. package/dist/browser/evidenceCapture.d.ts +46 -3
  8. package/dist/browser/evidenceCapture.js +393 -94
  9. package/dist/browser/evidenceCapture.js.map +1 -1
  10. package/dist/browser/scrollCapture.d.ts +32 -0
  11. package/dist/browser/scrollCapture.js +163 -0
  12. package/dist/browser/scrollCapture.js.map +1 -0
  13. package/dist/browser/types.d.ts +3 -1
  14. package/dist/cli.js +165 -7
  15. package/dist/cli.js.map +1 -1
  16. package/dist/domain/diagnostics.d.ts +1 -1
  17. package/dist/domain/diagnostics.js +2 -0
  18. package/dist/domain/diagnostics.js.map +1 -1
  19. package/dist/domain/identity.d.ts +8 -3
  20. package/dist/domain/identity.js +10 -4
  21. package/dist/domain/identity.js.map +1 -1
  22. package/dist/domain/schema.d.ts +164 -6
  23. package/dist/domain/schema.js +314 -4
  24. package/dist/domain/schema.js.map +1 -1
  25. package/dist/domain/scrollEvidence.d.ts +51 -0
  26. package/dist/domain/scrollEvidence.js +134 -0
  27. package/dist/domain/scrollEvidence.js.map +1 -0
  28. package/dist/index.d.ts +4 -4
  29. package/dist/index.js +2 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/request/request.d.ts +57 -1
  32. package/dist/request/request.js +292 -14
  33. package/dist/request/request.js.map +1 -1
  34. package/docs/ARCHITECTURE.md +62 -1
  35. package/docs/CI_CD.md +49 -8
  36. package/docs/COMMANDS.md +184 -9
  37. package/docs/CONTRACTS.md +135 -6
  38. package/docs/CURRENT_STATE.md +128 -6
  39. package/docs/DEVELOPMENT.md +41 -3
  40. package/docs/PROJECT_OVERVIEW.md +12 -6
  41. package/docs/QUICKSTART.md +3 -1
  42. package/docs/RELEASE.md +12 -5
  43. package/docs/ROADMAP.md +9 -0
  44. package/docs/SECURITY.md +6 -2
  45. package/docs/WORKFLOWS.md +41 -14
  46. package/package.json +1 -1
package/docs/COMMANDS.md CHANGED
@@ -21,10 +21,18 @@ Options:
21
21
  - `--viewport <WIDTHxHEIGHT>` — e.g. `1280x720`. Malformed syntax (missing
22
22
  `x`, non-numeric, empty side) is rejected before any browser launches;
23
23
  in-range bounds are enforced by the existing request validator.
24
- - `--target <id=css-selector>` — an explicit observation target. Repeatable;
25
- order is preserved. Parsed on the *first* `=` only, so a selector
26
- containing `=` survives intact, e.g.
27
- `--target action=button[data-state="active"]`.
24
+ - `--target <id=css-selector>` — an explicit CSS-shorthand observation
25
+ target. Repeatable; order is preserved. Parsed on the *first* `=` only, so
26
+ a selector containing `=` survives intact, e.g.
27
+ `--target action=button[data-state="active"]`. Cannot be combined with
28
+ `--targets-file`.
29
+ - `--targets-file <json-file>` — loads structured semantic observation
30
+ targets from a local JSON file instead of `--target`. Cannot be combined
31
+ with `--target`. See "Structured semantic targets" below.
32
+ - `--scroll-scenario-file <json-file>` — loads one bounded runtime scroll
33
+ scenario from a local JSON file. May be combined with either `--target` or
34
+ `--targets-file` (it is independent of target configuration). See "Scroll
35
+ scenario (`--scroll-scenario-file`)" below.
28
36
  - `--output <directory>` — portable, relative output location for the
29
37
  observation artifact (same contract as the request's `outputLocation`; no
30
38
  drive letter, no leading `/`, no `..` segments).
@@ -53,6 +61,170 @@ capture. CLI-syntax errors (e.g. a missing `--url`) print as `error:
53
61
  <message>` followed by `observe` usage; request/capture/persistence
54
62
  diagnostics print one per line as `[code] message`.
55
63
 
64
+ ### Structured semantic targets (`--targets-file`)
65
+
66
+ **Current status: shipped as part of the published `my-frontend-observer@0.3.0`
67
+ package.** `--target` (CSS shorthand) remains fully supported alongside it.
68
+
69
+ `--targets-file <json-file>` is the public entry point to the v0.2 canonical
70
+ target/locator model established in `src/request/request.ts`. It supplies
71
+ the same `targets` collection that `--target` supplies, just in structured
72
+ form; both converge on the same `normalizeRequest()` validation and the same
73
+ downstream browser resolver - there is no separate semantic observation path.
74
+
75
+ File format (the exact, first frozen structure - the root object supports
76
+ only the `targets` field; any other top-level field is rejected):
77
+
78
+ ```json
79
+ {
80
+ "targets": [
81
+ {
82
+ "name": "primary-navigation",
83
+ "locators": [
84
+ { "kind": "role", "role": "navigation", "name": "Primary" },
85
+ { "kind": "id", "value": "nav" }
86
+ ]
87
+ },
88
+ {
89
+ "name": "workspace",
90
+ "locators": [
91
+ { "kind": "data-attribute", "attribute": "data-region", "value": "workspace" }
92
+ ]
93
+ }
94
+ ]
95
+ }
96
+ ```
97
+
98
+ Each target has a stable `name` and an ordered `locators` array (1-5
99
+ entries; order is the fallback order - the first locator that resolves
100
+ uniquely wins, an ambiguous or unevaluable locator stops immediately without
101
+ trying the next one). Each locator is one of the six frozen kinds:
102
+
103
+ - `{ "kind": "role", "role": "<string>", "name"?: "<string>" }`
104
+ - `{ "kind": "id", "value": "<string>" }`
105
+ - `{ "kind": "data-attribute", "attribute": "data-*", "value": "<string>" }`
106
+ - `{ "kind": "semantic-element", "tag": "<one of the frozen structural tags>" }`
107
+ - `{ "kind": "css", "selector": "<string>" }`
108
+ - `{ "kind": "text", "text": "<exact string>" }`
109
+
110
+ `--targets-file` itself only validates that the file is readable, is valid
111
+ JSON, and has an object root containing exactly a `targets` field - every
112
+ target/locator-internal rule (bounds, per-kind required fields, supported
113
+ values) is enforced by the same `normalizeRequest()` validator `--target`
114
+ already goes through, so both input modes produce identical diagnostics for
115
+ equivalent mistakes.
116
+
117
+ The path may be relative (resolved from the current working directory) or
118
+ absolute; it is operational input only - it never affects the observation's
119
+ request identity and is never written into `manifest.json`.
120
+
121
+ Example:
122
+
123
+ ```powershell
124
+ my-frontend-observer observe `
125
+ --url http://localhost:3000/ `
126
+ --viewport 1280x720 `
127
+ --targets-file .\targets.json `
128
+ --output observations
129
+ ```
130
+
131
+ ### Scroll scenario (`--scroll-scenario-file`)
132
+
133
+ **Current status: shipped as part of the published `my-frontend-observer@0.3.0`
134
+ package.** Observation schema is `1.2.0`.
135
+
136
+ `--scroll-scenario-file <json-file>` is the public entry point to the v0.3
137
+ runtime scroll-scenario contract established in `src/request/request.ts`
138
+ (`ScrollScenario`/`ScrollAction`) and executed in `src/browser/`. It supplies
139
+ exactly the value of the normalized request's `scrollScenario` field - the
140
+ file root *is* the scenario object itself, with no wrapper field (unlike
141
+ `--targets-file`'s `{ "targets": [...] }` root).
142
+
143
+ A request supports **zero or one** scroll scenario. There are exactly two
144
+ supported action kinds:
145
+
146
+ Window scrolling:
147
+
148
+ ```json
149
+ {
150
+ "action": {
151
+ "kind": "window-scroll-by",
152
+ "deltaX": 0,
153
+ "deltaY": 600
154
+ }
155
+ }
156
+ ```
157
+
158
+ Target scrolling (the `target` value must be the stable `name` of one of the
159
+ observation's own configured targets - never a CSS selector, DOM id, or
160
+ source symbol):
161
+
162
+ ```json
163
+ {
164
+ "action": {
165
+ "kind": "target-scroll-by",
166
+ "target": "tool-workspace",
167
+ "deltaX": 0,
168
+ "deltaY": 400
169
+ }
170
+ }
171
+ ```
172
+
173
+ `deltaX`/`deltaY` are signed integers bounded to `[-20000, 20000]`; at least
174
+ one must be non-zero (both zero is rejected). Every scroll/action rule -
175
+ supported action kind, required fields, delta types/bounds, the both-zero
176
+ rule, and the stable-target-name reference for `target-scroll-by` - is
177
+ enforced by the same `normalizeRequest()` validator used everywhere else, not
178
+ duplicated in CLI code; `--scroll-scenario-file` itself only validates that
179
+ the file is readable, is valid JSON, and has a non-array object root.
180
+
181
+ The observer performs the requested scroll immediately (no smooth-scroll
182
+ animation), waits exactly two `requestAnimationFrame` cycles, and captures a
183
+ final runtime snapshot - the same final state that the observation's ordinary
184
+ `pageEvidence`, `targetEvidence`, and `screenshot.png` describe. The actual
185
+ resulting scroll position is browser-authoritative and may be clamped by
186
+ document/element boundaries; a scenario that produces no movement (already at
187
+ a boundary, or a non-scrollable target) is still a valid, successfully
188
+ persisted observation, never a fabricated failure.
189
+
190
+ Usable with either target input mode:
191
+
192
+ ```powershell
193
+ my-frontend-observer observe `
194
+ --url http://localhost:3000/ `
195
+ --target workspace=.workspace `
196
+ --scroll-scenario-file .\scroll.json `
197
+ --output observations
198
+ ```
199
+
200
+ ```powershell
201
+ my-frontend-observer observe `
202
+ --url http://localhost:3000/ `
203
+ --targets-file .\targets.json `
204
+ --scroll-scenario-file .\scroll.json `
205
+ --output observations
206
+ ```
207
+
208
+ `--target` and `--targets-file` remain mutually exclusive with each other,
209
+ exactly as before; `--scroll-scenario-file` is independent of both and is
210
+ never itself a third mutually-exclusive target mode. `window-scroll-by`
211
+ requires no configured target at all.
212
+
213
+ The path may be relative (resolved from the current working directory) or
214
+ absolute; it is operational input only - like `--targets-file`'s path, it
215
+ never affects the observation's request identity and is never written into
216
+ `manifest.json`. Two different scenario files with identical content produce
217
+ the same `requestId`; only the requested scenario *configuration*
218
+ participates in identity, never the runtime outcome (actual scroll
219
+ distance, clamping, or scroll-owner result).
220
+
221
+ If a `target-scroll-by` scenario's configured action target cannot be
222
+ uniquely resolved at runtime (missing, ambiguous, or otherwise unavailable),
223
+ the scroll is not performed, no movement is fabricated, and the observation
224
+ persists honestly - typically as `partial` - carrying the same
225
+ `target-missing`/`target-ambiguous`/`browser-evidence-unavailable` diagnostic
226
+ that any other unresolved configured target would produce.
227
+
56
228
  ## Foundation commands
57
229
 
58
230
  - `npm install` — install dependencies (includes the `playwright` runtime
@@ -75,8 +247,11 @@ diagnostics print one per line as `[code] message`.
75
247
  - `npm run build` — clean and compile `src/` (including `src/cli.ts`) to
76
248
  `dist/`.
77
249
  - `npm run check:docs` — validate canonical documents and roadmap structure.
78
- - `npm pack --dry-run` — inspect the private package inventory without
79
- publishing. The real tarball has been installed and exercised in a clean
80
- temporary consumer directory (real Chromium install, real `observe` run,
81
- real artifact) as part of v0.1 validation; this is local package
82
- validation, not a release/publication step.
250
+ - `npm pack --dry-run` — inspect the public package's tarball inventory
251
+ before publishing. The real tarball has been installed and exercised in a
252
+ clean temporary consumer directory (real Chromium install, real `observe`
253
+ run, real artifact) on Windows, Linux, and macOS as part of v0.1
254
+ validation, again for v0.2's packed semantic `--targets-file` behavior,
255
+ and again for v0.3's packed `--scroll-scenario-file` window/target scroll
256
+ behavior (`scripts/ci/runPackedObservationSmoke.mjs`); this is local
257
+ package validation, not a release/publication step.
package/docs/CONTRACTS.md CHANGED
@@ -2,11 +2,13 @@
2
2
 
3
3
  ## Current contracts
4
4
 
5
- The v0.1 observation artifact contract is implemented (`src/domain/schema.ts`)
6
- and proven both from the source checkout and from the packed npm tarball:
5
+ The observation artifact contract is published as `my-frontend-observer@0.3.0`
6
+ and proven both from the source checkout and from the packed npm tarball,
7
+ on Windows, Linux, and macOS. The observation schema is `1.2.0` (see "v0.2
8
+ target contract" and "v0.3 scroll scenario contract" below):
7
9
 
8
- - artifact kind `my-frontend-observer/observation`, schema version `1.0.0`
9
- (independent of the package version, currently `0.1.0`);
10
+ - artifact kind `my-frontend-observer/observation`, schema version `1.2.0`
11
+ (independent of the package version);
10
12
  - one artifact root per observation, `<outputLocation>/<observationId>/`,
11
13
  containing exactly `manifest.json` (the full `ObservationArtifact`, with
12
14
  page/target evidence embedded inline) and `screenshot.png` - there is no
@@ -26,8 +28,135 @@ and proven both from the source checkout and from the packed npm tarball:
26
28
  - observation/request identity, producer/package identity, and browser
27
29
  provenance are all present in every persisted manifest.
28
30
 
29
- This contract is implemented; it is not yet published as a package, and no
30
- public programmatic-API compatibility promise has been made.
31
+ This contract is implemented and published; no public programmatic-API
32
+ compatibility promise has been made.
33
+
34
+ ## v0.2 target contract (shipped as part of this release)
35
+
36
+ v0.2 introduces a canonical target-configuration model: each configured target has a stable
37
+ observer-level `name` plus an ordered array of bounded `locators`
38
+ (`role`, `id`, `data-attribute`, `semantic-element`, `css`, `text`). This
39
+ identity is distinct from both the browser locator definition that resolves
40
+ it and any source-code identity. The legacy `{name, selector}` shape remains
41
+ accepted and normalizes to a one-item `css` locator, so every published
42
+ `0.1.0` CLI invocation continues to work unchanged. Locator precedence is the
43
+ configured array order; resolution stops on the first unique match, on any
44
+ ambiguous match (never falling through to a later locator), or on an
45
+ unevaluable locator - never silently. All six frozen locator kinds are now
46
+ resolved against a real Chromium page (`role` via Playwright's accessibility-
47
+ role/name locator with exact name matching, `id`/`data-attribute` via exact
48
+ CSS attribute-equals matching that never reinterprets the configured value as
49
+ selector syntax, `semantic-element` via the frozen tag set, `css` via the
50
+ existing v0.1 behavior, `text` via exact-text matching only); every kind
51
+ converges on the same measurement path, so locator strategy never changes the
52
+ resulting target evidence shape.
53
+
54
+ Each resolved target's evidence record additionally carries three bounded
55
+ fields: `semanticState` (a first family of `disabled`/`expanded`/
56
+ `checked`/`selected`/`pressed`/`current` values read from the element's own
57
+ native form-control properties and explicit `aria-*` attributes - a key is
58
+ present only when the browser exposes that state as applicable to this
59
+ element, so an explicit `false` is always distinguishable from "not
60
+ applicable"; `not-applicable` when no supported state applies at all);
61
+ `landmark` (derived only from the already-captured browser-exposed
62
+ role - never from locator kind or HTML tag - against the standard landmark
63
+ role set `banner`/`navigation`/`main`/`complementary`/`contentinfo`/`form`/
64
+ `region`/`search`); and `containment` (bounded DOM containment checked only
65
+ among the other explicitly configured targets in the same observation, in
66
+ configured order, never a layout/relationship graph - `available` when every
67
+ other configured target was itself resolved and checked, `partial` when one
68
+ or more could not be, `unavailable` when the target itself never resolved).
69
+ Stable observer target identity is proven, not just declared: the same
70
+ target configuration produces the same `requestId` across repeated
71
+ observations (with a fresh `observationId` each time); changing a target's
72
+ locator strategy while keeping its stable name changes `requestId` but not
73
+ the `targetEvidence` key; and actual runtime disappearance of a
74
+ still-configured target changes only its resolution status, never the
75
+ `requestId`.
76
+
77
+ The full canonical semantic target model above is reachable through the
78
+ real public CLI: `my-frontend-observer observe --targets-file <json-file>`
79
+ supplies the structured `{ "targets": [...] }` collection (see
80
+ `docs/COMMANDS.md` "Structured semantic targets") as an alternative to the
81
+ existing `--target id=css-selector` shorthand - the two are mutually
82
+ exclusive per invocation, and both converge on the same
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.
87
+
88
+ ## v0.3 scroll scenario contract (shipped as part of this release)
89
+
90
+ v0.3 introduces one optional, additive request/evidence concern: a bounded
91
+ runtime scroll scenario, schema `1.2.0`.
92
+
93
+ A normalized request may carry `scrollScenario: { action }` with exactly one
94
+ of two frozen action kinds:
95
+
96
+ - `{ "kind": "window-scroll-by", "deltaX": <int>, "deltaY": <int> }`
97
+ - `{ "kind": "target-scroll-by", "target": "<stable target name>", "deltaX": <int>, "deltaY": <int> }`
98
+
99
+ `deltaX`/`deltaY` are signed integers bounded to `[-20000, 20000]`; at least
100
+ one must be non-zero. `target-scroll-by.target` refers only to an existing
101
+ stable configured target `name` (never a selector) and resolves through the
102
+ same canonical `resolveConfiguredTargets` algorithm every v0.2 locator kind
103
+ already uses - there is no second target-resolution path. A request with no
104
+ scenario normalizes and identifies exactly as it did before v0.3.
105
+
106
+ Execution (both action kinds share one code path): perform the immediate,
107
+ non-smooth scroll (`window.scrollBy`/`element.scrollBy`, `behavior:
108
+ 'instant'`) on the already-navigated, already-ready page; wait exactly two
109
+ `requestAnimationFrame` cycles; capture a final runtime snapshot. No second
110
+ browser, page, or navigation is ever created. The resulting scroll position
111
+ is browser-authoritative and may be clamped by document/element boundaries;
112
+ a scenario producing no movement is still a valid, successfully persisted
113
+ observation.
114
+
115
+ The scenario evidence lives entirely inside the existing `manifest.json` as
116
+ one additional optional `scrollScenarioEvidence` field on `ObservationArtifact`
117
+ - there is no separate `scroll.json`/`scenario.json`. It contains:
118
+
119
+ - `initial`/`final`: bounded `ScrollRuntimeSnapshot`s (window `scrollX`/
120
+ `scrollY`; the browser's own scrolling-root/`documentElement`/`body`
121
+ metrics; per-configured-target `scrollTop`/`scrollLeft`/`scrollWidth`/
122
+ `scrollHeight`/`clientWidth`/`clientHeight`, actual overflow, bounding
123
+ rectangle, and viewport relation);
124
+ - `transition`: bounded before/after change evidence (window scroll deltas;
125
+ per-target `scrollTop`/`scrollLeft`/bounding-position/viewport-relation
126
+ changes; `enteredViewport`/`leftViewport`) - never a generic recursive
127
+ diff, and a target is simply omitted when either side's evidence isn't
128
+ itself usable (e.g. it never resolved);
129
+ - `scrollOwner`: one derived `EvidenceField<ScrollOwnerInterpretation>`
130
+ (`document` | `target:<stable-name>` | `none` | `indeterminate`), always
131
+ `source: "derived"` with non-empty `derivedFrom` naming the exact
132
+ contributing scroll-position measurements. Ownership is derived only from
133
+ observed `scrollTop`/`scrollLeft`/`window.scrollX`/`window.scrollY`
134
+ changes - never from bounding-rectangle movement (which moves for every
135
+ configured target whenever the document scrolls), computed overflow,
136
+ `position: fixed`/`sticky`, or DOM hierarchy.
137
+
138
+ Actual dimensional overflow (`scrollWidth > clientWidth` /
139
+ `scrollHeight > clientHeight`) is always reported separately from the
140
+ computed `overflow-x`/`overflow-y` CSS declaration; a declared
141
+ `overflow: auto` container with content that fits produces
142
+ `horizontalOverflow`/`verticalOverflow: false`. Viewport relation
143
+ (`above`/`intersecting`/`below`, `intersectsViewport`, `fullyWithinViewport`)
144
+ is derived only from bounding geometry plus viewport size, relative to the
145
+ browser viewport; a hidden/non-rendered target's viewport relation is
146
+ `not-applicable`, never a fabricated geometry claim - hidden and offscreen
147
+ remain distinct evidence concepts, and the existing `target-hidden`
148
+ diagnostic is unaffected.
149
+
150
+ The ordinary, already-existing `pageEvidence`/`targetEvidence`/
151
+ `screenshot.png` for a scenario observation always describe this same final
152
+ post-action state, never the pre-action state.
153
+
154
+ The scenario request participates in `requestId`; the runtime result
155
+ (actual scroll distance, clamping, or scroll-owner outcome) never does. The
156
+ public entry point is `my-frontend-observer observe --scroll-scenario-file
157
+ <json-file>` (see `docs/COMMANDS.md`); the file supplies the scenario value
158
+ directly, and its local path is operational input only, exactly like
159
+ `--targets-file`'s path - never persisted, never part of request identity.
31
160
 
32
161
  ## Approved v0.1 design inputs
33
162
 
@@ -1,7 +1,7 @@
1
1
  # Current State
2
2
 
3
- The project is published at package version `0.1.0` (roadmap v0.1, Runtime
4
- Observation Foundation).
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`).
5
5
 
6
6
  ## Greenfield foundation established
7
7
 
@@ -102,12 +102,134 @@ tarball/output fully cleaned up afterward. Documentation across the
102
102
  repository was reconciled to this implemented state as part of the same
103
103
  batch.
104
104
 
105
+ ## v0.1 status
106
+
107
+ `v0.1.0` was the first published release (see `CHANGELOG.md` and
108
+ `docs/RELEASE.md`). Everything above this section describes that released
109
+ state, still present unchanged in `v0.2.0`.
110
+
111
+ ## v0.2 status (Stable Semantic Targets and Region Identity) - released as 0.2.0
112
+
113
+ v0.2 is implemented and released as package version `0.2.0`, observation
114
+ schema `1.1.0`.
115
+
116
+ - **Canonical target/locator model.** Each configured target has a stable
117
+ observer-owned `name` plus an ordered, bounded `locators` array
118
+ (`src/request/request.ts#TargetLocator`, `NamedTarget`). This identity is
119
+ distinct from both the browser locator that resolves it and any
120
+ source-code symbol. The legacy `{name, selector}` shape remains accepted
121
+ and normalizes to a one-item `css` locator, so every v0.1 CLI invocation
122
+ continues to work unchanged. Bounds: 20 targets max, 5 locators per
123
+ target max (unchanged/new respectively from v0.1's target count bound).
124
+ - **Six frozen locator kinds, all resolved against real Chromium**: `role`
125
+ (Playwright's accessibility role/name locator, exact name matching),
126
+ `id` and `data-attribute` (exact CSS attribute-equals matching that never
127
+ reinterprets the configured value as selector syntax), `semantic-element`
128
+ (a frozen structural tag set: `header`, `nav`, `main`, `footer`,
129
+ `article`, `section`, `aside`, `form`, `dialog`), `css` (unchanged v0.1
130
+ behavior), and `text` (exact match only, no substring/fuzzy matching).
131
+ Locator order is the fallback order: 0 matches tries the next locator; 1
132
+ match selects and stops; more than 1 match is ambiguous and stops (never
133
+ falls through); an unevaluable locator is unavailable and stops (never
134
+ falls through). All six kinds converge on one measurement path
135
+ (`src/browser/evidenceCapture.ts#captureResolvedTargetRecord`) - locator
136
+ strategy never changes the resulting evidence shape.
137
+ - **Semantic region evidence**, added to every resolved target alongside
138
+ the existing v0.1 role/name capture: `semanticState` (a first bounded
139
+ family of `disabled`/`expanded`/`checked`/`selected`/`pressed`/`current`,
140
+ read from the element's own native/ARIA properties so an explicit `false`
141
+ is always distinguishable from "not applicable"; `checked`/`pressed` also
142
+ support the browser's `'mixed'` value); `landmark` (derived only from the
143
+ already-captured browser-exposed role - never from locator kind or HTML
144
+ tag - against the standard landmark role set `banner`/`navigation`/
145
+ `main`/`complementary`/`contentinfo`/`form`/`region`/`search`); and
146
+ `containment` (bounded DOM containment checked only among the other
147
+ explicitly configured targets in the same observation, in configured
148
+ order - `available`/`partial`/`unavailable`, never a layout/spatial-
149
+ relationship graph).
150
+ - **Proven identity stability**: the same target configuration produces the
151
+ same `requestId` across repeated observations (with a fresh
152
+ `observationId` every time); changing a target's locator strategy while
153
+ keeping its stable name changes `requestId` but not the `targetEvidence`
154
+ key; actual runtime disappearance of a still-configured target changes
155
+ only its resolution status, never the `requestId`.
156
+ - **Public CLI**: `my-frontend-observer observe --targets-file <json-file>`
157
+ supplies a structured `{ "targets": [...] }` collection as an alternative
158
+ to one or more `--target id=css-selector` flags; the two are mutually
159
+ exclusive per invocation. `--targets-file` only validates its own root
160
+ wrapper (readable file, valid JSON, object root with exactly a `targets`
161
+ field); all target/locator-internal validation stays owned by the
162
+ existing `normalizeRequest()`. The file path is operational input only -
163
+ never part of request identity, never persisted into `manifest.json`.
164
+ - **Observation schema `1.1.0`** (`src/domain/schema.ts#SCHEMA_VERSION`):
165
+ additive over the published `1.0.0` - extends `TargetEvidenceRecord` with
166
+ `semanticState`/`landmark`/`containment` and extends `TargetResolution`
167
+ with `selectedLocatorKind`/`selectedLocatorIndex`/`usedFallback`/
168
+ `confidence`/`attempts`. Artifact kind, directory structure, atomic
169
+ persistence, and evidence-state/source vocabularies are unchanged.
170
+ - **Validation on this branch**: `npm run typecheck`, `npm run lint`,
171
+ `npm test`, `npm run test:browser`, `npm run build`, and
172
+ `npm run check:docs` all pass (106 unit tests, 69 real-Chromium tests as
173
+ of this reconciliation; see `docs/DEVELOPMENT.md` for how to reproduce).
174
+ `scripts/dev/builtCliTargetsFileSmoke.mjs` additionally proves the built
175
+ `dist/cli.js` (not just the imported `runCli()` function) performs a real
176
+ semantic `--targets-file` observation end to end.
177
+
178
+ ## v0.3 status (Runtime Scrolling, Overflow, and Visibility Behavior) - released as 0.3.0
179
+
180
+ v0.3 is implemented and released as package version `0.3.0`, observation
181
+ schema `1.2.0`. It was validated as a packed npm tarball in a clean
182
+ consumer environment on Windows, Linux, and macOS before release.
183
+
184
+ - **Batch 1** froze the `scrollScenario` request/identity/schema contract:
185
+ `ScrollScenario { action }` with exactly two action kinds
186
+ (`window-scroll-by`, `target-scroll-by`), signed-integer deltas bounded to
187
+ `[-20000, 20000]`, `target-scroll-by.target` referencing an existing stable
188
+ configured target name, scenario configuration participating in
189
+ `requestId` (runtime results never do), and the full bounded runtime
190
+ evidence model (`ScrollRuntimeSnapshot`, `ViewportRelationEvidence`,
191
+ `OverflowEvidence`, scenario transitions, `ScrollOwnerInterpretation`) in
192
+ schema `1.2.0` (up from `1.1.0`).
193
+ - **Batch 2** implemented real `window-scroll-by` execution
194
+ (`src/browser/scrollCapture.ts`, `src/domain/scrollEvidence.ts`): initial/
195
+ final runtime snapshots around an immediate `window.scrollBy({behavior:
196
+ 'instant'})` and exactly two `requestAnimationFrame` cycles, real vertical/
197
+ horizontal document scrolling, actual-vs-computed overflow, real viewport
198
+ relation, `enteredViewport`/`leftViewport`, and `document`/`none`
199
+ scroll-owner evidence - with ordinary final `pageEvidence`/`targetEvidence`
200
+ and the screenshot always describing the same final post-action state.
201
+ - **Batch 3** implemented real `target-scroll-by` execution against the same
202
+ canonical `resolveConfiguredTargets` resolution already used by every v0.2
203
+ locator kind: real nested vertical/horizontal element scrolling, boundary
204
+ clamping, non-scrollable/no-movement targets, and the completed
205
+ `document`/`target:<name>`/`none`/`indeterminate` scroll-owner derivation
206
+ (`src/domain/scrollEvidence.ts#deriveScrollOwner`) - proven never to
207
+ attribute ownership from bounding-rectangle movement alone in either
208
+ direction. An unresolved/ambiguous/hidden action target is never scrolled
209
+ and never fabricated as moved; the existing target diagnostics explain it
210
+ honestly and the observation still persists.
211
+ - **Batch 4** exposed the existing contract through the real public CLI:
212
+ `my-frontend-observer observe --scroll-scenario-file <json-file>` (see
213
+ `docs/COMMANDS.md`). The file supplies the `scrollScenario` value directly
214
+ (no wrapper field); the CLI/input layer only validates file readability,
215
+ JSON validity, and a non-array object root - every scenario/action rule
216
+ stays owned by the existing `normalizeRequest()`. Usable with either
217
+ `--target` or `--targets-file` (independent of target configuration, never
218
+ a third mutually-exclusive mode); the scenario-file path is operational
219
+ input only, never persisted and never part of request identity, exactly
220
+ like `--targets-file`'s path. CLI output/exit-code semantics are
221
+ unchanged. Proven via real Chromium (`tests/browser/cliObserve.test.ts`)
222
+ and the built `dist/cli.js` (`scripts/dev/builtCliScrollScenarioSmoke.mjs`).
223
+
105
224
  ## Not implemented
106
225
 
107
- - There is no controlled-scroll behavior, target-source correlation, or
108
- capability beyond the bounded page/target evidence Batches 3-5 established.
109
- - No v0.2–v0.10 capability is implemented.
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+).
110
230
 
111
231
  ## Next target
112
232
 
113
- v0.1.0 is released. The next allowed workflow is v0.2 planning.
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.
@@ -21,9 +21,9 @@ npm run check:docs
21
21
  npm pack --dry-run
22
22
  ```
23
23
 
24
- `npm test` runs the fast unit suite only (`tests/unit/`, currently 70
24
+ `npm test` runs the fast unit suite only (`tests/unit/`, currently 176
25
25
  passing tests). `npm run test:browser` runs the real-Chromium integration
26
- suite (`tests/browser/`, currently 16 passing tests) against deterministic
26
+ suite (`tests/browser/`, currently 88 passing tests) against deterministic
27
27
  local fixtures under `tests/fixtures/` and requires the Chromium binary
28
28
  above to be installed first; it is kept out of `npm test` because it
29
29
  launches a real browser and is slower.
@@ -62,4 +62,42 @@ 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.
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.
69
+
70
+ `scripts/dev/builtCliTargetsFileSmoke.mjs` is a separate, narrower v0.2
71
+ development smoke, added alongside the `--targets-file` implementation: it
72
+ runs the built `dist/cli.js` directly (`node dist/cli.js observe
73
+ --targets-file ...`) against an inline disposable local HTTP fixture and a
74
+ temporary JSON target file, proving a real semantic observation persists a
75
+ valid schema-`1.2.0` artifact with no packed-tarball step involved. Run it
76
+ locally after `npm run build`:
77
+
78
+ ```powershell
79
+ node scripts/dev/builtCliTargetsFileSmoke.mjs
80
+ ```
81
+
82
+ `scripts/dev/builtCliScrollScenarioSmoke.mjs` is the v0.3 equivalent, added
83
+ alongside the `--scroll-scenario-file` implementation: it runs the built
84
+ `dist/cli.js` directly against an inline disposable local HTTP fixture,
85
+ once with a temporary `window-scroll-by` scenario file and once with a
86
+ temporary structured `--targets-file` plus a `target-scroll-by` scenario
87
+ file, proving both real runtime scroll actions persist a valid
88
+ schema-`1.2.0` artifact with populated `scrollScenarioEvidence`,
89
+ scenario-file path privacy, and target-application immutability. Run it
90
+ locally after `npm run build`:
91
+
92
+ ```powershell
93
+ node scripts/dev/builtCliScrollScenarioSmoke.mjs
94
+ ```
95
+
96
+ Unlike `scripts/ci/runPackedObservationSmoke.mjs`, neither of these dev
97
+ smokes is wired into any CI workflow or is a release gate - they are
98
+ 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.
@@ -15,12 +15,18 @@ The responsibility split is stable:
15
15
 
16
16
  ## Current repository state
17
17
 
18
- v0.1, Runtime Observation Foundation, is released as `0.1.0`, published to
19
- npm and validated as a packed npm tarball in a clean consumer environment: a
20
- real `observe` CLI command launches Chromium, enforces loopback-only safety,
21
- captures bounded page/target evidence and a viewport screenshot, and
22
- persists one portable local artifact. v0.2–v0.10 remain future and
23
- unimplemented.
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
29
+ future and unimplemented.
24
30
 
25
31
  The revised dependency path reaches practical coding-agent use before graphical
26
32
  interaction:
@@ -21,7 +21,9 @@ node dist/cli.js observe `
21
21
 
22
22
  This launches Chromium, captures a screenshot plus bounded page/target
23
23
  evidence, and writes one portable artifact under `observations/<observation-id>/`.
24
- See [COMMANDS.md](COMMANDS.md) for the full flag reference.
24
+ See [COMMANDS.md](COMMANDS.md) for the full flag reference, including the
25
+ `--targets-file` structured semantic-target input and the
26
+ `--scroll-scenario-file` bounded runtime scroll scenario input.
25
27
 
26
28
  To validate the repository itself instead:
27
29
 
package/docs/RELEASE.md CHANGED
@@ -1,9 +1,16 @@
1
1
  # Release
2
2
 
3
- `v0.1.0` is published to npm as `my-frontend-observer`, validated on
3
+ `v0.3.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
- publication. No project license has been declared yet; that decision remains
6
- open for a later explicit task.
5
+ publication (covering the legacy CSS-shorthand `--target` path, the
6
+ structured semantic `--targets-file` path, and the bounded
7
+ `--scroll-scenario-file` `window-scroll-by`/`target-scroll-by` runtime
8
+ scroll scenario path). No project license has been declared yet; that
9
+ decision remains open for a later explicit task.
7
10
 
8
- Observation schema version and package version remain separate: schema
9
- `1.0.0` does not change automatically with the package version.
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.
14
+
15
+ Prior releases: `v0.2.0` (Stable Semantic Targets and Region Identity),
16
+ `v0.1.0` (Runtime Observation Foundation) - see `CHANGELOG.md`.
package/docs/ROADMAP.md CHANGED
@@ -43,6 +43,10 @@ and the concrete dependency/version set before implementation.
43
43
 
44
44
  ## v0.2 — Stable Semantic Targets and Region Identity
45
45
 
46
+ Current status: released as `0.2.0`, published to npm and validated as a
47
+ packed npm tarball in a clean consumer environment on Windows, Linux, and
48
+ macOS. See `docs/CURRENT_STATE.md` for the implementation summary.
49
+
46
50
  Objective/problem: let humans and consumers refer reliably to conceptual
47
51
  rendered regions across observations without brittle selector-only identity.
48
52
  Required capabilities include semantic HTML, accessibility role/name, stable
@@ -56,6 +60,11 @@ identity persistence rules from current evidence.
56
60
 
57
61
  ## v0.3 — Runtime Scrolling, Overflow, and Visibility Behavior
58
62
 
63
+ Current status: released as `0.3.0`, published to npm and validated as a
64
+ packed npm tarball in a clean consumer environment on Windows, Linux, and
65
+ macOS (observation schema `1.2.0`). See `docs/CURRENT_STATE.md` for the
66
+ implementation summary.
67
+
59
68
  Objective/problem: show which container actually scrolls and what becomes
60
69
  visible, clipped, or overflowing after controlled actions. Required capabilities
61
70
  are bounded action scenarios, before/after window and target scroll positions,