@reqvire-org/ads 0.3.11 → 0.3.13

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/README.md +20 -1
  2. package/dist/capture/worker.mjs +38 -0
  3. package/dist/capture-store.mjs +123 -0
  4. package/dist/capture.mjs +117 -0
  5. package/dist/config.mjs +6 -1
  6. package/dist/mcp/catalog.mjs +3 -3
  7. package/dist/mcp/context.mjs +1 -1
  8. package/dist/mcp/mutations.mjs +26 -6
  9. package/dist/mcp/server.mjs +64 -17
  10. package/dist/project-documents.mjs +29 -6
  11. package/dist/scenarios.mjs +9 -3
  12. package/dist/showcase/client.bundle.js +18 -18
  13. package/dist/showcase/style.css +2 -0
  14. package/dist/skills/ads-break-ui/SKILL.md +12 -5
  15. package/dist/skills/ads-break-ui/references/captures.md +147 -0
  16. package/dist/skills/ads-break-ui/references/guarded-editing.md +68 -0
  17. package/dist/skills/ads-break-ui/references/scenarios.md +22 -0
  18. package/dist/skills/ads-designer/SKILL.md +13 -6
  19. package/dist/skills/ads-designer/references/captures.md +147 -0
  20. package/dist/skills/ads-designer/references/guarded-editing.md +68 -0
  21. package/dist/skills/ads-designer/references/scenarios.md +22 -0
  22. package/dist/skills/ads-import/SKILL.md +13 -6
  23. package/dist/skills/ads-import/references/captures.md +147 -0
  24. package/dist/skills/ads-import/references/guarded-editing.md +68 -0
  25. package/dist/skills/ads-import/references/implementation.md +3 -1
  26. package/dist/skills/ads-import/references/scenarios.md +22 -0
  27. package/dist/skills/ads-migrate/SKILL.md +12 -5
  28. package/dist/skills/ads-migrate/references/captures.md +147 -0
  29. package/dist/skills/ads-migrate/references/guarded-editing.md +68 -0
  30. package/dist/skills/ads-migrate/references/scenarios.md +22 -0
  31. package/dist/skills/ads-migrate/references/testing.md +5 -0
  32. package/dist/skills/ads-motion/SKILL.md +12 -5
  33. package/dist/skills/ads-motion/references/captures.md +147 -0
  34. package/dist/skills/ads-motion/references/guarded-editing.md +68 -0
  35. package/dist/skills/ads-motion/references/scenarios.md +22 -0
  36. package/dist/units.mjs +7 -6
  37. package/dist/verification/browser.mjs +8 -3
  38. package/dist/verification/playwright-reporter.cjs +23 -8
  39. package/dist/verification.mjs +137 -33
  40. package/docs/ADS.md +9 -0
  41. package/docs/ARCHITECTURE.md +44 -3
  42. package/docs/BEHAVIORS.md +57 -3
  43. package/docs/CHANGELOG.md +28 -0
  44. package/docs/GUIDE.md +48 -1
  45. package/docs/MCP.md +63 -2
  46. package/package.json +1 -1
@@ -0,0 +1,147 @@
1
+ # On-demand visual captures
2
+
3
+ Use captures when reviewing appearance or a proposed visual change. Discover exact
4
+ scenario IDs with `ads_scenarios`; these are project-owned independently mountable
5
+ token, component, pattern and composition views. A component export alone is not
6
+ a renderable fixture. Controllers/hooks need a scenario demonstrating their visible
7
+ effects. ADS never supplies library-specific renderers, fixtures or capture targets.
8
+
9
+ ## Capture current source
10
+
11
+ ```js
12
+ ads_capture({
13
+ scenario: "components/Example",
14
+ theme: "dark",
15
+ viewport: { width: 1280, height: 800 }
16
+ })
17
+ ```
18
+
19
+ The ID above is illustrative; use one returned by discovery. The default is light
20
+ theme at 1280 × 800 CSS pixels. Capture uses the real sandboxed MCP App with the
21
+ requested viewport and excludes showcase navigation. The default image records
22
+ the complete widget viewport, including its current scroll/state; it does not
23
+ automatically stitch every scroll position into one image.
24
+
25
+ ADS starts an isolated showcase/compiler and an owned browser process, using the
26
+ connected project's installed `@playwright/test` or `playwright`. It installs no
27
+ dependency/browser. Chromium is the default; optional project configuration is:
28
+
29
+ ```json
30
+ {
31
+ "mcp": {
32
+ "capture": {
33
+ "browser": "chromium",
34
+ "channel": "chrome",
35
+ "timeoutMs": 60000
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ Omit `channel` to use Playwright's installed Chromium. Firefox and WebKit are also
42
+ accepted browser choices; channel is Chromium-only. The registered browser must
43
+ be installed locally. This budget bounds the capture runner, including preview
44
+ readiness. Capture does not run the project's entire Playwright suite or require a
45
+ behavior manifest. Readiness uses the App bridge, fonts and settled image loads,
46
+ not `networkidle` (MCP maintains live connections).
47
+
48
+ ## Capture a named element
49
+
50
+ Declare selectors in the scenario's static metadata:
51
+
52
+ ```tsx
53
+ export const scenario = {
54
+ title: "Example",
55
+ covers: ["Example"],
56
+ captureTargets: {
57
+ control: '[data-testid="example-control"]'
58
+ }
59
+ };
60
+ ```
61
+
62
+ Use attributes/selectors already owned by the real UI or its public review pattern.
63
+ Scenarios keep their existing styling/control rules. A target is not permission
64
+ to add demo-only product props, custom CSS or synthetic native controls. Each
65
+ selector is scoped to the App iframe and must match exactly one visible element.
66
+ Select it with `ads_capture({scenario:"<discovered ID>",target:"control"})`.
67
+ `captureTargets` allows up to 20 named CSS selectors. Unknown, hidden, ambiguous
68
+ or unrenderable targets fail explicitly; ADS does not guess a substitute element.
69
+ Arrange a specific interaction state through the scenario's real fixture/adapter;
70
+ capture itself accepts no arbitrary browser script or click sequence.
71
+
72
+ Screenshots hide the text caret and disable animations by default. Set
73
+ `animations:"allow"` when motion must remain active, and account for nondeterminism.
74
+ The same capture settings are used for both sides of a candidate comparison.
75
+
76
+ ## Review a patch without applying it
77
+
78
+ Prepare/diff an owner draft normally, then request screenshots during its guarded
79
+ dry run:
80
+
81
+ ```js
82
+ ads_apply_patch({
83
+ unit: "components/Example",
84
+ patchFile: ".ds/patches/<returned-name>.patch",
85
+ dryRun: true,
86
+ screenshot: true,
87
+ captures: [{ scenario: "components/Example", target: "control", theme: "light" }]
88
+ })
89
+ ```
90
+
91
+ The placeholder owner/ID/path must come from discovery/preparation. Transactions
92
+ accept the same `screenshot`/`captures` fields. Select 1–8 distinct scenario/target
93
+ pairs explicitly; do not capture every affected scenario by default. Ordinary dry
94
+ runs and patches create no screenshots. `screenshot:true` requires `dryRun:true`.
95
+
96
+ Core, registered lint/project and affected behavior gates pass first. ADS then
97
+ captures current source and the isolated candidate under matching theme, viewport,
98
+ animation and browser settings. Candidate screenshots survive candidate-directory
99
+ cleanup. Final source/conflict checks still run before the pair is published. A
100
+ failed/cancelled capture does not replace existing image slots or apply source.
101
+ If a scenario/target is newly introduced, `current` is null with an explicit
102
+ `currentAbsent` explanation; only the real candidate image exists.
103
+
104
+ Review the returned images and diagnostics, fix the draft if necessary, then apply
105
+ with `dryRun:false`. Apply reruns all gates. An image is promoted only when the
106
+ accepted source revision matches the captured candidate; other proposals remain
107
+ stale. Images do not approve a patch or certify interaction/accessibility/parity.
108
+
109
+ ## Two slots, no automatic history
110
+
111
+ The stable capture key identifies the scenario and optional named target. Theme,
112
+ viewport and revision are metadata, not additional resource identities.
113
+
114
+ | Successful operation | Result for that target |
115
+ | --- | --- |
116
+ | Standalone `ads_capture` | Fresh current; any earlier candidate removed |
117
+ | Screenshot-enabled dry run | Fresh current + candidate; replaces the old pair |
118
+ | Apply matching proposed source | Candidate becomes current; candidate slot cleared |
119
+ | `ads_capture_clear({scenario,target?,candidateOnly:true})` | Discard candidate, retain current when present |
120
+ | `ads_capture_clear({scenario,target?})` | Remove both slots |
121
+ | Remove scenario/target | Orphan images collected on resource refresh/discovery |
122
+
123
+ No previous slot, revision history or TTL is kept. Later source changes mark
124
+ images stale rather than silently recapturing them. New proposals replace the
125
+ candidate. Three limits keep storage bounded: at most 4 MiB per PNG, 8 megapixels
126
+ per image and 256 MiB total capture storage. Clear unneeded targets if the store
127
+ reaches its limit. Viewport dimensions range from 100 to 4096 pixels per axis,
128
+ subject to the pixel limit.
129
+
130
+ ## Read resources and freshness
131
+
132
+ `ads://project/captures` lists existing slots and metadata. Each returned image URI
133
+ uses the template `ads://captures/{key}/{slot}`, with `slot` current or candidate.
134
+ Read the exact returned URI through MCP `resources/read` (or the host's resource
135
+ tool). The result is `image/png` with binary `blob`, not a filesystem or browser
136
+ URL. Use the client's image/resource viewer; do not paste base64 into model text.
137
+
138
+ Capture metadata records source/build revision, fixture owner file, settings,
139
+ capture time, PNG dimensions/digest and candidate proposal identity. Current is
140
+ stale when its source revision differs; a candidate becomes stale when its base
141
+ source changes. Static freshness does not prove external/live fixture data stayed
142
+ identical. Subscribe to the index and image URIs for `resources/updated`, including
143
+ candidate removal; explicitly reread when the host does not deliver notifications.
144
+ Absent/cleared slots return a resource-not-found diagnostic, not an old image.
145
+ The resource catalogue exposes one index and an image URI template, avoiding a
146
+ resource-list entry for every new revision. Images stay as generated development
147
+ data under `.ds/captures/`; none belongs in product bundles or source patches.
@@ -6,6 +6,74 @@ tools, request `action:"diff"`, then apply the returned patchFile. Discard the
6
6
  draft afterward. Remote clients can keep sending inline Git diffs. Neither draft
7
7
  preparation nor diff generation validates or changes live source.
8
8
 
9
+ To verify a draft before applying it, diff it and dry-run the returned patch:
10
+
11
+ ```js
12
+ ads_prepare_patch({"unit":"components/Example","action":"diff","draft":"<returned draft ID>"})
13
+ ads_apply_patch({"unit":"components/Example","patchFile":"<returned patchFile>","dryRun":true})
14
+ ```
15
+
16
+ The dry run validates the full candidate, including affected registered behavior
17
+ checks in an isolated project copy. Configured browser checks use that candidate's
18
+ managed preview, not the live showcase. Inspect the returned `behavior` failures
19
+ or the registered behavior-check results in `checks`, fix the draft and diff again.
20
+ Keep behavior.json/specs with their owner and use registered checks; a scratchpad
21
+ run against live source cannot verify unapplied changes. After validation, apply
22
+ with `dryRun:false`; ADS revalidates before writing. Dry-run evidence is not saved
23
+ as passing evidence for the live project.
24
+
25
+ `ads_verify({unit,checks?})` selects checks for current project source; it has no
26
+ draft argument. There is no dedicated selected-check runner for drafts yet.
27
+ Use a dry-run transaction for genuinely coupled draft patches.
28
+
29
+ Behavior-run performance belongs to both orchestration and project checks. ADS
30
+ selects affected owners, filters registered Playwright case tags and shares one
31
+ candidate host per run. The project owns assertions, browser setup, worker count,
32
+ per-test timeouts and its profile's whole-run `timeoutMs`. The latter covers the
33
+ entire runner process, not each test. Do not rewrite APIs, drop guarantees or
34
+ disable checks to fit the budget. Inspect measured durations before tuning it.
35
+
36
+ During verification, inspect `ads_status.behaviors.progress`; during candidate
37
+ validation, inspect `ads_status.mutations.progress`. These show completed/active/
38
+ pending checks and timings. MCP clients requesting progress also receive updates.
39
+ A timeout retains reported case outcomes and identifies active/unstarted checks;
40
+ it still blocks the mutation. `reportedStatus:"passed"` within an incomplete run
41
+ is diagnostic information, not a passing guarantee. Reports/artifacts under the
42
+ live project's `.ds/verification/` survive candidate cleanup. Uninstrumented custom
43
+ runners may report an unknown execution state instead of claiming a case started.
44
+
45
+ For independent browser specs, consider a small parallel worker count and measure
46
+ on the target machine. Use separate contexts/pages, independent state and the
47
+ candidate URLs provided by `openBehaviorScenario`; avoid fixed live-server URLs,
48
+ shared mutable fixtures and test-order assumptions. Files can run in parallel;
49
+ tests in one file remain sequential by default. Prefer readiness assertions over
50
+ blanket sleeps. Fake clocks suit timer-only guarantees; keep real time for actual
51
+ gesture/motion/layout guarantees. Project settings belong in guarded configuration
52
+ changes; ADS does not silently raise budgets or override the worker count.
53
+
54
+ Named barrel imports can narrow affected checks when the project accurately
55
+ declares package `sideEffects`; retain CSS/global effects in that policy. Missing
56
+ or unsupported policies and dynamic/wildcard dependencies stay conservative.
57
+ Do not change the policy merely to suppress verification of real side effects.
58
+
59
+ For registered measured-geometry style writes, use direct `element.style.transform =
60
+ value` or `element.style.setProperty("--ds-measured-value", value)` with the exact
61
+ file/property boundary. The current guard rejects a style-object alias such as
62
+ `const style = element.style` as an escape; it does not trace the alias to later
63
+ writes. Keep writes explicit when adapting local controller code. This syntax
64
+ constraint is separate from deciding which measured properties belong to the
65
+ controller; it does not authorize unregistered visual writes.
66
+
67
+ Shared provenance uses the existing `documentation` unit. Read its `filePolicy`
68
+ from `ads_units`: one patch can create `CREDITS.md`, shared `licenses/*.txt` and
69
+ README links together. Conventional root credits/license/notice names support
70
+ UTF-8 `.md`/`.txt` or extensionless notices; `licenses/` may also sit under
71
+ `docs/`, `doc/` or the ADS root. Preserve upstream notice text exactly. Keep
72
+ component/asset-local notices with their owner; reference shared notices instead
73
+ of duplicating them across units. Do not create an asset group or bypass a guard
74
+ to add these documents. Code/configuration and hidden/generated paths remain
75
+ outside documentation ownership.
76
+
9
77
  For genuinely coupled changes, `ads_apply_transaction` accepts 2–8 distinct owner
10
78
  patches (32 distinct files and 16 MiB combined). Each patch keeps its ownership and
11
79
  companion restrictions. Patches apply in order; later shared-entry hunks match the
@@ -92,7 +92,9 @@ imports, setup/providers, and scope/mounting across routes where relevant.
92
92
 
93
93
  Compare the imported component or pattern with the actual source implementation
94
94
  at the recorded revision. Align content, configuration, themes, viewport, and
95
- input modality. For implementation comparisons, use matching token values when
95
+ input modality. Preserve the original comparison baseline; see the
96
+ [verification pitfalls](scenarios.md#verification-pitfalls) before changing
97
+ reference sizing or API visibility to make checks pass. For implementation comparisons, use matching token values when
96
98
  possible; also verify the item under its actual destination theme. For
97
99
  stateful/motion-heavy items, check lifecycle, focus, keyboard,
98
100
  pointer and touch, natural dimensions, transitions, interruption, reduced motion,
@@ -18,6 +18,11 @@ recovers missed atomic replacements. Do not touch source to force freshness;
18
18
  inspect build diagnostics. Upgrade the project's compiler dependency together
19
19
  with MCP when an older reporter lacks source evidence.
20
20
 
21
+ Optional static `captureTargets` names CSS selectors within the scenario's App for
22
+ on-demand element screenshots. It grants no render/behavior coverage and no extra
23
+ styling permission. Use [captures.md](captures.md) for current/candidate review,
24
+ target selection, resource reads and storage lifecycle.
25
+
21
26
  ## Owner-local token previews load their own definitions
22
27
 
23
28
  Keep the registered token sheet imported by its runtime owner for product use.
@@ -68,6 +73,23 @@ just to satisfy a guard. Static evidence does not establish successful mounting,
68
73
  visibility, interaction, every state or visual parity. Verify those in the built
69
74
  App and registered browser checks.
70
75
 
76
+ ## Verification pitfalls
77
+
78
+ Preserve the intended API and the reference baseline when resolving a diagnostic.
79
+ These examples describe verification mistakes, not component-specific rules:
80
+
81
+ | Situation | Do not | Do instead |
82
+ |-----------|--------|------------|
83
+ | A reference example sets `width: 15rem`, while the native popup uses its default width. | Remove the reference width and claim the original example now matches. | Keep the baseline intact. Reproduce demo sizing through the project's public review/layout pattern or supported style helper. If a different native size is intentional, document it. Label any additional normalized comparison separately. |
84
+ | Static tracing cannot prove that a public clear control renders when a value is selected. | Remove its export, drop its required coverage, or change runtime behavior merely to pass the gate. | Preserve the intended public API. Try a meaningful selected-state fixture or another real scenario. If valid rendering remains untraceable, report the tooling limitation with a small reproduction. |
85
+ | A screenshot shows the clear control in a selected state. | Treat its presence as evidence that clearing works. | Add a browser check: start selected, activate Clear, assert the value and selection are empty, verify the control's resulting visibility and documented focus behavior, then select again. |
86
+
87
+ A private helper exposed through its parent's public prop can legitimately stay
88
+ private when that is the intended API. Verify the behavior through the parent;
89
+ do not export the helper solely for a test. Public/private ownership is a product
90
+ decision, not a coverage workaround. Browser checks verify transitions but do not
91
+ replace the current static `covers` requirement; `exercises` does not waive it.
92
+
71
93
  ## Scenarios may consume verified public style helpers
72
94
 
73
95
  A deliberately public helper can expose its owner's Linaria treatment:
@@ -32,7 +32,10 @@ also list a `ds.config.json` companion: change only that owner's `inlineStyleFil
32
32
  and `boundaries.styleWrites` entries together with its source. Unused permissions
33
33
  fail the core checks; do not pre-register a boundary without its implementation.
34
34
  Use `dryRun: true` to
35
- inspect validation; applying re-runs the gates. Fix rejected patches in their
35
+ inspect validation, including affected registered behavior checks on the isolated
36
+ candidate. For a prepared draft, request its diff and dry-run the returned
37
+ `patchFile`; `ads_verify` checks current source and accepts no draft argument.
38
+ Applying re-runs the gates. Fix rejected patches in their
36
39
  owner. Use `ads_apply_transaction` for genuinely coupled owner patches;
37
40
  never bypass a rejection with direct source writes. Shared styles/helpers use `foundation`, root guides use
38
41
  `documentation`, and branding/fonts use their discovered `assets/*` unit.
@@ -44,12 +47,16 @@ stay out of model context. Binary changes require Git. When editing is disabled,
44
47
  use the client's normal source-editing tools.
45
48
  For owner drafts, token-sample reconciliation, coupled transactions and local
46
49
  constant namespaces, read [guarded-editing.md](references/guarded-editing.md).
50
+ For on-demand current/candidate screenshots and visual dry-run review, read
51
+ [captures.md](references/captures.md).
47
52
 
48
53
 
49
- For parent/child `covers`, public style-helper use in scenarios, or
50
- `scenario-render` / `showcase-class` findings, read
51
- [scenario contracts](references/scenarios.md). Traced parents can cover declared
52
- public children; verified public Linaria helpers do not grant custom scenario CSS.
54
+ For parent/child `covers`, conditional-control review, reference comparisons,
55
+ public style-helper use in scenarios, or `scenario-render` / `showcase-class`
56
+ findings, read [scenario contracts](references/scenarios.md). Its verification
57
+ examples explain API visibility, reference baselines and state-transition checks.
58
+ Traced parents can cover declared public children; verified public Linaria
59
+ helpers do not grant custom scenario CSS.
53
60
 
54
61
  For atomic base/variant styling, helper/wrapper class composition, extracted
55
62
  custom-property arithmetic, or an
@@ -0,0 +1,147 @@
1
+ # On-demand visual captures
2
+
3
+ Use captures when reviewing appearance or a proposed visual change. Discover exact
4
+ scenario IDs with `ads_scenarios`; these are project-owned independently mountable
5
+ token, component, pattern and composition views. A component export alone is not
6
+ a renderable fixture. Controllers/hooks need a scenario demonstrating their visible
7
+ effects. ADS never supplies library-specific renderers, fixtures or capture targets.
8
+
9
+ ## Capture current source
10
+
11
+ ```js
12
+ ads_capture({
13
+ scenario: "components/Example",
14
+ theme: "dark",
15
+ viewport: { width: 1280, height: 800 }
16
+ })
17
+ ```
18
+
19
+ The ID above is illustrative; use one returned by discovery. The default is light
20
+ theme at 1280 × 800 CSS pixels. Capture uses the real sandboxed MCP App with the
21
+ requested viewport and excludes showcase navigation. The default image records
22
+ the complete widget viewport, including its current scroll/state; it does not
23
+ automatically stitch every scroll position into one image.
24
+
25
+ ADS starts an isolated showcase/compiler and an owned browser process, using the
26
+ connected project's installed `@playwright/test` or `playwright`. It installs no
27
+ dependency/browser. Chromium is the default; optional project configuration is:
28
+
29
+ ```json
30
+ {
31
+ "mcp": {
32
+ "capture": {
33
+ "browser": "chromium",
34
+ "channel": "chrome",
35
+ "timeoutMs": 60000
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ Omit `channel` to use Playwright's installed Chromium. Firefox and WebKit are also
42
+ accepted browser choices; channel is Chromium-only. The registered browser must
43
+ be installed locally. This budget bounds the capture runner, including preview
44
+ readiness. Capture does not run the project's entire Playwright suite or require a
45
+ behavior manifest. Readiness uses the App bridge, fonts and settled image loads,
46
+ not `networkidle` (MCP maintains live connections).
47
+
48
+ ## Capture a named element
49
+
50
+ Declare selectors in the scenario's static metadata:
51
+
52
+ ```tsx
53
+ export const scenario = {
54
+ title: "Example",
55
+ covers: ["Example"],
56
+ captureTargets: {
57
+ control: '[data-testid="example-control"]'
58
+ }
59
+ };
60
+ ```
61
+
62
+ Use attributes/selectors already owned by the real UI or its public review pattern.
63
+ Scenarios keep their existing styling/control rules. A target is not permission
64
+ to add demo-only product props, custom CSS or synthetic native controls. Each
65
+ selector is scoped to the App iframe and must match exactly one visible element.
66
+ Select it with `ads_capture({scenario:"<discovered ID>",target:"control"})`.
67
+ `captureTargets` allows up to 20 named CSS selectors. Unknown, hidden, ambiguous
68
+ or unrenderable targets fail explicitly; ADS does not guess a substitute element.
69
+ Arrange a specific interaction state through the scenario's real fixture/adapter;
70
+ capture itself accepts no arbitrary browser script or click sequence.
71
+
72
+ Screenshots hide the text caret and disable animations by default. Set
73
+ `animations:"allow"` when motion must remain active, and account for nondeterminism.
74
+ The same capture settings are used for both sides of a candidate comparison.
75
+
76
+ ## Review a patch without applying it
77
+
78
+ Prepare/diff an owner draft normally, then request screenshots during its guarded
79
+ dry run:
80
+
81
+ ```js
82
+ ads_apply_patch({
83
+ unit: "components/Example",
84
+ patchFile: ".ds/patches/<returned-name>.patch",
85
+ dryRun: true,
86
+ screenshot: true,
87
+ captures: [{ scenario: "components/Example", target: "control", theme: "light" }]
88
+ })
89
+ ```
90
+
91
+ The placeholder owner/ID/path must come from discovery/preparation. Transactions
92
+ accept the same `screenshot`/`captures` fields. Select 1–8 distinct scenario/target
93
+ pairs explicitly; do not capture every affected scenario by default. Ordinary dry
94
+ runs and patches create no screenshots. `screenshot:true` requires `dryRun:true`.
95
+
96
+ Core, registered lint/project and affected behavior gates pass first. ADS then
97
+ captures current source and the isolated candidate under matching theme, viewport,
98
+ animation and browser settings. Candidate screenshots survive candidate-directory
99
+ cleanup. Final source/conflict checks still run before the pair is published. A
100
+ failed/cancelled capture does not replace existing image slots or apply source.
101
+ If a scenario/target is newly introduced, `current` is null with an explicit
102
+ `currentAbsent` explanation; only the real candidate image exists.
103
+
104
+ Review the returned images and diagnostics, fix the draft if necessary, then apply
105
+ with `dryRun:false`. Apply reruns all gates. An image is promoted only when the
106
+ accepted source revision matches the captured candidate; other proposals remain
107
+ stale. Images do not approve a patch or certify interaction/accessibility/parity.
108
+
109
+ ## Two slots, no automatic history
110
+
111
+ The stable capture key identifies the scenario and optional named target. Theme,
112
+ viewport and revision are metadata, not additional resource identities.
113
+
114
+ | Successful operation | Result for that target |
115
+ | --- | --- |
116
+ | Standalone `ads_capture` | Fresh current; any earlier candidate removed |
117
+ | Screenshot-enabled dry run | Fresh current + candidate; replaces the old pair |
118
+ | Apply matching proposed source | Candidate becomes current; candidate slot cleared |
119
+ | `ads_capture_clear({scenario,target?,candidateOnly:true})` | Discard candidate, retain current when present |
120
+ | `ads_capture_clear({scenario,target?})` | Remove both slots |
121
+ | Remove scenario/target | Orphan images collected on resource refresh/discovery |
122
+
123
+ No previous slot, revision history or TTL is kept. Later source changes mark
124
+ images stale rather than silently recapturing them. New proposals replace the
125
+ candidate. Three limits keep storage bounded: at most 4 MiB per PNG, 8 megapixels
126
+ per image and 256 MiB total capture storage. Clear unneeded targets if the store
127
+ reaches its limit. Viewport dimensions range from 100 to 4096 pixels per axis,
128
+ subject to the pixel limit.
129
+
130
+ ## Read resources and freshness
131
+
132
+ `ads://project/captures` lists existing slots and metadata. Each returned image URI
133
+ uses the template `ads://captures/{key}/{slot}`, with `slot` current or candidate.
134
+ Read the exact returned URI through MCP `resources/read` (or the host's resource
135
+ tool). The result is `image/png` with binary `blob`, not a filesystem or browser
136
+ URL. Use the client's image/resource viewer; do not paste base64 into model text.
137
+
138
+ Capture metadata records source/build revision, fixture owner file, settings,
139
+ capture time, PNG dimensions/digest and candidate proposal identity. Current is
140
+ stale when its source revision differs; a candidate becomes stale when its base
141
+ source changes. Static freshness does not prove external/live fixture data stayed
142
+ identical. Subscribe to the index and image URIs for `resources/updated`, including
143
+ candidate removal; explicitly reread when the host does not deliver notifications.
144
+ Absent/cleared slots return a resource-not-found diagnostic, not an old image.
145
+ The resource catalogue exposes one index and an image URI template, avoiding a
146
+ resource-list entry for every new revision. Images stay as generated development
147
+ data under `.ds/captures/`; none belongs in product bundles or source patches.
@@ -6,6 +6,74 @@ tools, request `action:"diff"`, then apply the returned patchFile. Discard the
6
6
  draft afterward. Remote clients can keep sending inline Git diffs. Neither draft
7
7
  preparation nor diff generation validates or changes live source.
8
8
 
9
+ To verify a draft before applying it, diff it and dry-run the returned patch:
10
+
11
+ ```js
12
+ ads_prepare_patch({"unit":"components/Example","action":"diff","draft":"<returned draft ID>"})
13
+ ads_apply_patch({"unit":"components/Example","patchFile":"<returned patchFile>","dryRun":true})
14
+ ```
15
+
16
+ The dry run validates the full candidate, including affected registered behavior
17
+ checks in an isolated project copy. Configured browser checks use that candidate's
18
+ managed preview, not the live showcase. Inspect the returned `behavior` failures
19
+ or the registered behavior-check results in `checks`, fix the draft and diff again.
20
+ Keep behavior.json/specs with their owner and use registered checks; a scratchpad
21
+ run against live source cannot verify unapplied changes. After validation, apply
22
+ with `dryRun:false`; ADS revalidates before writing. Dry-run evidence is not saved
23
+ as passing evidence for the live project.
24
+
25
+ `ads_verify({unit,checks?})` selects checks for current project source; it has no
26
+ draft argument. There is no dedicated selected-check runner for drafts yet.
27
+ Use a dry-run transaction for genuinely coupled draft patches.
28
+
29
+ Behavior-run performance belongs to both orchestration and project checks. ADS
30
+ selects affected owners, filters registered Playwright case tags and shares one
31
+ candidate host per run. The project owns assertions, browser setup, worker count,
32
+ per-test timeouts and its profile's whole-run `timeoutMs`. The latter covers the
33
+ entire runner process, not each test. Do not rewrite APIs, drop guarantees or
34
+ disable checks to fit the budget. Inspect measured durations before tuning it.
35
+
36
+ During verification, inspect `ads_status.behaviors.progress`; during candidate
37
+ validation, inspect `ads_status.mutations.progress`. These show completed/active/
38
+ pending checks and timings. MCP clients requesting progress also receive updates.
39
+ A timeout retains reported case outcomes and identifies active/unstarted checks;
40
+ it still blocks the mutation. `reportedStatus:"passed"` within an incomplete run
41
+ is diagnostic information, not a passing guarantee. Reports/artifacts under the
42
+ live project's `.ds/verification/` survive candidate cleanup. Uninstrumented custom
43
+ runners may report an unknown execution state instead of claiming a case started.
44
+
45
+ For independent browser specs, consider a small parallel worker count and measure
46
+ on the target machine. Use separate contexts/pages, independent state and the
47
+ candidate URLs provided by `openBehaviorScenario`; avoid fixed live-server URLs,
48
+ shared mutable fixtures and test-order assumptions. Files can run in parallel;
49
+ tests in one file remain sequential by default. Prefer readiness assertions over
50
+ blanket sleeps. Fake clocks suit timer-only guarantees; keep real time for actual
51
+ gesture/motion/layout guarantees. Project settings belong in guarded configuration
52
+ changes; ADS does not silently raise budgets or override the worker count.
53
+
54
+ Named barrel imports can narrow affected checks when the project accurately
55
+ declares package `sideEffects`; retain CSS/global effects in that policy. Missing
56
+ or unsupported policies and dynamic/wildcard dependencies stay conservative.
57
+ Do not change the policy merely to suppress verification of real side effects.
58
+
59
+ For registered measured-geometry style writes, use direct `element.style.transform =
60
+ value` or `element.style.setProperty("--ds-measured-value", value)` with the exact
61
+ file/property boundary. The current guard rejects a style-object alias such as
62
+ `const style = element.style` as an escape; it does not trace the alias to later
63
+ writes. Keep writes explicit when adapting local controller code. This syntax
64
+ constraint is separate from deciding which measured properties belong to the
65
+ controller; it does not authorize unregistered visual writes.
66
+
67
+ Shared provenance uses the existing `documentation` unit. Read its `filePolicy`
68
+ from `ads_units`: one patch can create `CREDITS.md`, shared `licenses/*.txt` and
69
+ README links together. Conventional root credits/license/notice names support
70
+ UTF-8 `.md`/`.txt` or extensionless notices; `licenses/` may also sit under
71
+ `docs/`, `doc/` or the ADS root. Preserve upstream notice text exactly. Keep
72
+ component/asset-local notices with their owner; reference shared notices instead
73
+ of duplicating them across units. Do not create an asset group or bypass a guard
74
+ to add these documents. Code/configuration and hidden/generated paths remain
75
+ outside documentation ownership.
76
+
9
77
  For genuinely coupled changes, `ads_apply_transaction` accepts 2–8 distinct owner
10
78
  patches (32 distinct files and 16 MiB combined). Each patch keeps its ownership and
11
79
  companion restrictions. Patches apply in order; later shared-entry hunks match the
@@ -18,6 +18,11 @@ recovers missed atomic replacements. Do not touch source to force freshness;
18
18
  inspect build diagnostics. Upgrade the project's compiler dependency together
19
19
  with MCP when an older reporter lacks source evidence.
20
20
 
21
+ Optional static `captureTargets` names CSS selectors within the scenario's App for
22
+ on-demand element screenshots. It grants no render/behavior coverage and no extra
23
+ styling permission. Use [captures.md](captures.md) for current/candidate review,
24
+ target selection, resource reads and storage lifecycle.
25
+
21
26
  ## Owner-local token previews load their own definitions
22
27
 
23
28
  Keep the registered token sheet imported by its runtime owner for product use.
@@ -68,6 +73,23 @@ just to satisfy a guard. Static evidence does not establish successful mounting,
68
73
  visibility, interaction, every state or visual parity. Verify those in the built
69
74
  App and registered browser checks.
70
75
 
76
+ ## Verification pitfalls
77
+
78
+ Preserve the intended API and the reference baseline when resolving a diagnostic.
79
+ These examples describe verification mistakes, not component-specific rules:
80
+
81
+ | Situation | Do not | Do instead |
82
+ |-----------|--------|------------|
83
+ | A reference example sets `width: 15rem`, while the native popup uses its default width. | Remove the reference width and claim the original example now matches. | Keep the baseline intact. Reproduce demo sizing through the project's public review/layout pattern or supported style helper. If a different native size is intentional, document it. Label any additional normalized comparison separately. |
84
+ | Static tracing cannot prove that a public clear control renders when a value is selected. | Remove its export, drop its required coverage, or change runtime behavior merely to pass the gate. | Preserve the intended public API. Try a meaningful selected-state fixture or another real scenario. If valid rendering remains untraceable, report the tooling limitation with a small reproduction. |
85
+ | A screenshot shows the clear control in a selected state. | Treat its presence as evidence that clearing works. | Add a browser check: start selected, activate Clear, assert the value and selection are empty, verify the control's resulting visibility and documented focus behavior, then select again. |
86
+
87
+ A private helper exposed through its parent's public prop can legitimately stay
88
+ private when that is the intended API. Verify the behavior through the parent;
89
+ do not export the helper solely for a test. Public/private ownership is a product
90
+ decision, not a coverage workaround. Browser checks verify transitions but do not
91
+ replace the current static `covers` requirement; `exercises` does not waive it.
92
+
71
93
  ## Scenarios may consume verified public style helpers
72
94
 
73
95
  A deliberately public helper can expose its owner's Linaria treatment:
@@ -8,6 +8,11 @@ the baseline. The page frame may use native controls, but those controls must
8
8
  trigger the original component and store. Two pages importing the native component
9
9
  cannot establish upstream parity.
10
10
 
11
+ Keep example-level sizing and configuration intact too. Changing a reference to
12
+ match the native result weakens the comparison even when its component CSS is
13
+ untouched. Use the [verification pitfalls](scenarios.md#verification-pitfalls)
14
+ for concrete baseline, API-visibility and conditional-control examples.
15
+
11
16
  Use identical messages, options, counts, async delays/outcomes, action payloads,
12
17
  and viewport/input settings. Align configuration explicitly rather than relying
13
18
  on two different defaults. Compare brand/token differences separately from UX
@@ -52,7 +52,10 @@ also list a `ds.config.json` companion: change only that owner's `inlineStyleFil
52
52
  and `boundaries.styleWrites` entries together with its source. Unused permissions
53
53
  fail the core checks; do not pre-register a boundary without its implementation.
54
54
  Use `dryRun: true` to
55
- inspect validation; applying re-runs the gates. Fix rejected patches in their
55
+ inspect validation, including affected registered behavior checks on the isolated
56
+ candidate. For a prepared draft, request its diff and dry-run the returned
57
+ `patchFile`; `ads_verify` checks current source and accepts no draft argument.
58
+ Applying re-runs the gates. Fix rejected patches in their
56
59
  owner. Use `ads_apply_transaction` for genuinely coupled owner patches;
57
60
  never bypass a rejection with direct source writes. Shared styles/helpers use `foundation`, root guides use
58
61
  `documentation`, and branding/fonts use their discovered `assets/*` unit.
@@ -64,12 +67,16 @@ stay out of model context. Binary changes require Git. When editing is disabled,
64
67
  use the client's normal source-editing tools.
65
68
  For owner drafts, token-sample reconciliation, coupled transactions and local
66
69
  constant namespaces, read [guarded-editing.md](references/guarded-editing.md).
70
+ For on-demand current/candidate screenshots and visual dry-run review, read
71
+ [captures.md](references/captures.md).
67
72
 
68
73
 
69
- For parent/child `covers`, public style-helper use in scenarios, or
70
- `scenario-render` / `showcase-class` findings, read
71
- [scenario contracts](references/scenarios.md). Traced parents can cover declared
72
- public children; verified public Linaria helpers do not grant custom scenario CSS.
74
+ For parent/child `covers`, conditional-control review, reference comparisons,
75
+ public style-helper use in scenarios, or `scenario-render` / `showcase-class`
76
+ findings, read [scenario contracts](references/scenarios.md). Its verification
77
+ examples explain API visibility, reference baselines and state-transition checks.
78
+ Traced parents can cover declared public children; verified public Linaria
79
+ helpers do not grant custom scenario CSS.
73
80
 
74
81
  For atomic base/variant styling, helper/wrapper class composition, extracted
75
82
  custom-property arithmetic, or an