@orkestrel/scaffold 0.0.59 → 0.0.60

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 (23) hide show
  1. package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +91 -82
  2. package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +5 -5
  3. package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +10 -10
  4. package/dist/host/agents/skills/enterprise-bootstrap/references/inputs.md +501 -0
  5. package/dist/host/agents/skills/enterprise-bootstrap/references/inspection.md +167 -0
  6. package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +2 -2
  7. package/dist/host/agents/skills/orkestrel-polish-surface/SKILL.md +4 -1
  8. package/dist/host/agents/skills/orkestrel-polish-surface/references/capture-harness.md +71 -50
  9. package/dist/host/agents/skills/orkestrel-prove-journey/SKILL.md +93 -29
  10. package/dist/host/agents/skills/orkestrel-prove-journey/agents/openai.yaml +1 -1
  11. package/dist/host/agents/skills/orkestrel-prove-journey/references/captures.md +62 -38
  12. package/dist/host/agents/skills/orkestrel-prove-journey/references/decide.md +68 -0
  13. package/dist/host/agents/skills/orkestrel-prove-journey/references/layer.md +107 -79
  14. package/dist/host/agents/skills/orkestrel-prove-journey/references/statechart.md +84 -0
  15. package/dist/host/agents/skills/orkestrel-prove-journey/references/styles.md +87 -0
  16. package/dist/host/claude/agents/orkestrel.md +11 -10
  17. package/dist/host/claude/skills/orkestrel-prove-journey/SKILL.md +1 -1
  18. package/dist/host/manifest.json +43 -13
  19. package/dist/src/core/index.cjs +5 -5
  20. package/dist/src/core/index.cjs.map +1 -1
  21. package/dist/src/core/index.js +5 -5
  22. package/dist/src/core/index.js.map +1 -1
  23. package/package.json +5 -5
@@ -39,7 +39,7 @@ Prefer `bg-body-*` and `*-subtle` over `bg-white`/`bg-light` — they track `dat
39
39
  .rounded-0, .rounded-1, .rounded-2, .rounded-3, .rounded-4, .rounded-5
40
40
  ```
41
41
 
42
- For borders that must stay visible in both color modes, prefer `border-*-subtle` variants (theme-adaptive) over raw color borders.
42
+ For borders that must stay visible in both color modes, prefer the `border-*-subtle` classes (theme-adaptive) over raw color borders.
43
43
 
44
44
  ### Colors (Text)
45
45
 
@@ -246,7 +246,7 @@ The composition traps in this group:
246
246
  ### Z-index
247
247
 
248
248
  ```css
249
- .z-n1, .z-0, .z-1, .z-2, .z-3 /* NOT responsive — no breakpoint variants exist */
249
+ .z-n1, .z-0, .z-1, .z-2, .z-3 /* NOT responsive — no breakpoint classes exist */
250
250
  ```
251
251
 
252
252
  ## Spacing Scale
@@ -26,7 +26,10 @@ contract and this skill as the workflow. Preserve dirty and user-owned work.
26
26
  A claim about a rendered surface is proven by capture, never by reading the code that was
27
27
  supposed to produce it. Source-reading review passes a component that renders nothing.
28
28
 
29
- - The portfolio IS the review input: captures at both viewports and both themes, an
29
+ - Generate the portfolio from the journey suite's capture family wherever a Vitest
30
+ browser project can drive the surface, and from a spawned harness only where none
31
+ can ([capture-harness.md](references/capture-harness.md)).
32
+ - The portfolio IS the review input: captures at every viewport and every theme the surface declares, an
30
33
  accessibility snapshot, and an interaction log.
31
34
  - Source is corroboration for a mechanism, never the proof that the surface shows it.
32
35
  - A claim the portfolio cannot show is unproven, not passed. Say so.
@@ -1,82 +1,103 @@
1
1
  # The capture harness
2
2
 
3
- The harness produces the only evidence the verdict lanes are allowed to judge. It is owned
4
- by the campaign owner, not by a review lane, and it is a throwaway instrument: written for
5
- this surface, kept honest, deleted or rebuilt when the surface changes.
3
+ Take the portfolio from the journey suite's capture family wherever a Vitest browser project can
4
+ mount and drive the surface. Build the spawned script this file describes only for a surface no such
5
+ project can host — a served page, a foreign client, a process the runner cannot start inside a test.
6
+ Choose one source per surface, and never judge a round against a portfolio that is part
7
+ journey-generated and part spawned.
8
+
9
+ - Read the `orkestrel-prove-journey` skill for how the journey run generates a portfolio. This file
10
+ adds only what the review requires of a portfolio and how a spawned harness produces one.
11
+ - Own the spawned harness as the campaign owner. Never let a verdict lane write or edit it.
12
+ - Treat the spawned harness as a throwaway instrument: written for this surface, rebuilt or deleted
13
+ when the surface changes.
6
14
 
7
15
  ## One call, one lifecycle
8
16
 
9
- Background processes started inside one tool call die with that call's process group, and a
10
- verdict round spent on a half-dead harness is a wasted round.
17
+ Apply this section to a spawned harness only.
11
18
 
12
- - Write the harness as one self-contained script that spawns its own children, waits for
13
- readiness, does the capture, and kills them before returning.
14
- - Never leave a child running across calls or expect one to survive its parent.
15
- - Give every child a pinned working directory: a process that resolves assets, config, or
19
+ - Write the harness as one self-contained script that spawns its own children, waits for readiness,
20
+ does the capture, and kills them before returning.
21
+ - Never leave a child running across calls or expect one to survive its parent. A process started
22
+ inside one tool call dies with that call's process group.
23
+ - Give every child a pinned working directory. A process that resolves assets, configuration, or
16
24
  fixtures relative to the current directory dies silently when launched from elsewhere.
17
- - Pipe child standard error somewhere readable and print it on failure. A discarded stream
18
- turns a one-line configuration refusal into a debugging round.
19
- - Wait on an observable readiness signal — a served response, a printed line, a health
20
- probe — never on a fixed sleep.
21
- - Tear down on every exit path, including assertion and setup failure, so a failed capture
22
- leaves no orphaned server, browser, or port.
25
+ - Pipe child standard error somewhere readable and print it on failure.
26
+ - Wait on an observable readiness signal — a served response, a printed line, a health probe — never
27
+ on a fixed sleep.
28
+ - Tear down on every exit path, including assertion and setup failure, so a failed capture leaves no
29
+ orphaned server, browser, or port.
23
30
 
24
31
  ## Validate the seed before capturing
25
32
 
26
- Most "the surface is broken" verdicts trace back to a seed the surface legitimately
27
- refused.
33
+ Apply this section to a spawned harness only. In the journey run the acceptance journey is the seed,
34
+ and `orkestrel-prove-journey` fixes how it enters and what it may reach past.
28
35
 
29
- - Build seed payloads from the surface's own published contract, not from memory of it: a
30
- near-miss field name produces an empty screen that looks exactly like a product defect.
31
- - Assert the seeded state is present before shooting: the row exists, the prompt is parked,
32
- the list is non-empty.
33
- - Drive the surface through its real entry path so the captured state is one a user can
34
- actually reach.
35
- - Reset to a known state between scenarios; a capture that inherits the previous scenario's
36
+ - Build seed payloads from the surface's own published contract, never from memory of it; a
37
+ near-miss field name renders an empty screen that reads as a product defect.
38
+ - Assert the seeded state is present before shooting: the row exists, the prompt is parked, the list
39
+ is non-empty.
40
+ - Drive the surface through its real entry path, so the captured state is one a person can reach.
41
+ - Reset to a known state between scenarios. A capture that inherits the previous scenario's
36
42
  selection, focus, or scroll proves nothing about either.
37
43
 
38
44
  ## Capture the full portfolio
39
45
 
40
- Every round produces all of it, for every scenario in scope:
41
-
42
- | Artifact | Requirement |
43
- | ---------------------- | -------------------------------------------------------------------------------------- |
44
- | Viewport captures | The narrow and wide breakpoints the surface actually declares, not one convenient size |
45
- | Theme captures | Every theme the surface ships, each at both viewports |
46
- | Accessibility snapshot | The rendered accessible tree: roles, names, states, and focus order |
47
- | Interaction log | Each scripted interaction, its trigger, and the observed result |
48
- | Console and error log | Anything the page or process emitted during the run |
49
-
50
- - Shoot the whole surface before selecting or focusing anything inside it; a capture taken
51
- after a selection reports a duplicate or highlighted artifact that does not exist.
52
- - Start a keyboard walk from a neutral state, never from an already-focused control, or the
53
- log will "prove" a broken order the user never sees.
54
- - Name artifacts so a verdict can cite one exactly: scenario, viewport, theme, step.
55
- - Keep the artifacts of each round beside its verdicts; a round judged against the previous
56
- round's captures is not a round.
46
+ Produce every artifact in the following table each round, for every scenario in scope. The Source
47
+ column names what produces the artifact in the journey run; a spawned harness produces each one
48
+ itself.
49
+
50
+ | Artifact | Source in the journey run | What the artifact must show |
51
+ | ---------------------- | ------------------------------------ | ------------------------------------------------------------------------------------- |
52
+ | Viewport captures | `place` across the declared variants | Every breakpoint the surface declares, never one convenient size |
53
+ | Theme captures | `place` across the declared variants | Every theme the surface ships, at every declared viewport |
54
+ | Accessibility snapshot | `describeTree` and `describeFocus` | The rendered roles, names, and states, and the focus order the walk took |
55
+ | Interaction log | The journal's `steps` | Each interaction, its trigger, and the result observed after it |
56
+ | Console and error log | The journal's `output` | Everything the page emitted, including an uncaught error |
57
+ | Statechart outcome | The harness after a play-all run | The terminal status, the passed, failed, and total tallies, and each row's own result |
58
+
59
+ - Require the statechart outcome of every surface that declares the statechart family, and omit the
60
+ row only where the surface declares none.
61
+ - Read the journey run's per-variant written artifact for the accessibility snapshot and the logs,
62
+ and cite the statechart harness by its deep link where a lane must watch the widget move rather
63
+ than read a still of it. `orkestrel-prove-journey` fixes what each holds and what each is named
64
+ for.
65
+ - Shoot the whole surface before selecting or focusing anything inside it. A capture taken after a
66
+ selection reports a duplicate or highlighted artifact that does not exist.
67
+ - Start a keyboard walk from a neutral state, never from an already-focused control, or the log will
68
+ report a broken order no person meets.
69
+ - Name a spawned harness's artifacts so a verdict cites one exactly: scenario, viewport, theme,
70
+ step. The journey run's filename law already does this.
71
+ - Keep the artifacts of each round beside its verdicts. A round judged against the previous round's
72
+ captures is not a round.
57
73
 
58
74
  ## Preflight before spending a round
59
75
 
60
- The campaign owner opens every artifact before dispatching a verdict lane:
76
+ Open every artifact yourself before dispatching a verdict lane, whichever source produced it.
77
+ Confirm each of the following:
61
78
 
62
79
  - each capture shows the scenario it claims, in the theme and viewport it claims;
63
80
  - the seeded state is visible;
64
81
  - the accessibility snapshot is non-empty and matches the captured screen;
65
82
  - the interaction log records the interactions the brief asked for;
83
+ - the statechart outcome reads a terminal status, with a zero failed tally and a passed tally equal
84
+ to the total;
66
85
  - nothing in the console log indicates the harness, rather than the surface, failed.
67
86
 
68
- A portfolio that fails preflight is repaired before dispatch. A verdict round is the
69
- most expensive way to discover a harness bug.
87
+ Repair a portfolio that fails preflight before dispatching it. Never spend a verdict round
88
+ discovering a harness defect.
70
89
 
71
90
  ## Triage missing evidence to the harness first
72
91
 
73
- When a verdict returns a not-evidenced item, the harness is the first suspect and the
74
- surface is the second. In order:
92
+ Treat a not-evidenced verdict item as a harness fault before treating it as a product finding. Work
93
+ these in order:
75
94
 
76
- 1. Confirm the artifact that should decide the item exists and is named as the brief said.
95
+ 1. Confirm the artifact that decides the item exists and is named as the brief said.
77
96
  2. Confirm the scenario reached the state the item is about.
78
97
  3. Confirm the seed and the entry path match the surface's real contract.
79
- 4. Only then treat it as a product finding.
98
+ 4. Only then record it as a product finding.
80
99
 
81
- Every harness gap a round exposes is repaired before the recapture, and the repair is
82
- recorded with the round so the next portfolio is strictly better than the last.
100
+ - Repair every harness gap a round exposes before the recapture, and record the repair with the
101
+ round.
102
+ - Route a journey-run gap to the journey suite that owns it, and recapture from the repaired
103
+ journeys.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: orkestrel-prove-journey
3
- description: Prove a browser application the way a person uses it — real keystrokes, clicks, and Tab/Enter against only what is visible and reachable — and generate the capture portfolio from those same journeys. Use when accepting a UI build, proving an application end to end, deciding whether a surface is reachable by keyboard alone, proving what a screen refuses as well as what it does, auditing whether the interface speaks the user's vocabulary rather than the engine's, producing the screenshots a design review judges, or whenever the only evidence a screen works is a test that drove it through JavaScript instead of through the interface.
3
+ description: Prove a browser application the way a person uses it — real keystrokes, clicks, and Tab/Enter against only what is visible and reachable — through the journey layer @orkestrel/test/browser publishes, and generate the capture portfolio, the resolved-style matrix, and the statechart outcome from those same journeys. Use when accepting a UI build, proving an application end to end, deciding whether a surface is reachable by keyboard alone, proving what a screen refuses as well as what it does, proving the styles a browser actually resolved under each theme and viewport, driving a transition table through the interface and watching it run, auditing whether the interface speaks the user's vocabulary rather than the engine's, producing the screenshots a design review judges, routing a rendered question to an artifact a model can read, or whenever the only evidence a screen works is a test that drove it through JavaScript instead of through the interface.
4
4
  ---
5
5
 
6
6
  # Prove an application through human journeys
@@ -12,24 +12,63 @@ Read the current files in this order:
12
12
  1. `AGENTS.md`.
13
13
  2. `.claude/rules/tests.md` for test law, real implementations, and shared test infrastructure;
14
14
  `.claude/rules/browser.md` for browser and Vue usage; `.claude/rules/application.md` for app
15
- composition and entries; `.claude/rules/documentation.md` for parity. Those rules are the
16
- contract; this skill is the workflow.
17
- 3. [layer.md](references/layer.md) before building, extending, or debugging the journey layer.
15
+ composition and entries; `.claude/rules/styles.md` for style centralization;
16
+ `.claude/rules/quality.md` for the instrument and negative-control law;
17
+ `.claude/rules/documentation.md` for parity. Those rules are the contract; this skill is the
18
+ workflow.
19
+ 3. [layer.md](references/layer.md) before importing, extending, or debugging the journey layer.
18
20
  4. [captures.md](references/captures.md) before registering a state or placing a capture.
19
- 5. `guides/README.md`, the governing guide for the surface, and `ROADMAP.md` when present.
20
- 6. The `*/types.ts` of every environment the journeys drive, plus the application's root component,
21
+ 5. [styles.md](references/styles.md) before asserting anything the browser resolved.
22
+ 6. [statechart.md](references/statechart.md) before declaring a transition or building the harness.
23
+ 7. [decide.md](references/decide.md) before routing a question to an instrument.
24
+ 8. `guides/README.md`, the governing guide for the surface, and `ROADMAP.md` when present.
25
+ 9. The `*/types.ts` of every environment the journeys drive, plus the application's root component,
21
26
  route entry, and store contract.
22
27
 
28
+ ## Declare the families
29
+
30
+ Declare in the browser environment's `integration.test.ts` which families that surface carries, and
31
+ assert in the always-on proofs that every declared family is present. A declaration names which
32
+ families a surface owes. It never switches what a declared family proves.
33
+
34
+ | Family | Declared | Proves |
35
+ | ---------- | --------------------------------------------------- | ---------------------------------------------------------------------- |
36
+ | Journey | Always | Each user intent reaches its outcome through the interface |
37
+ | Refusal | Always | Each control the surface withholds, through one exact failure voice |
38
+ | Matrix | Where the surface ships more than one variant | The values the browser resolved under each declared variant |
39
+ | Statechart | Where a journey drives a control that carries state | Each declared transition, driven through the interface where it can be |
40
+ | Transport | Where the surface persists or restarts | Persistence, restart, and storage failure through real implementations |
41
+ | Capture | Under the capture flag | The registry times the variants, each registered file written to disk |
42
+
43
+ - Refuse a declaration that omits a family whose trigger the surface meets. Report the omission as a
44
+ scope finding and stop; never prove the remaining families around it.
45
+ - Assert the declaration itself: a family listed with no proof, and a proof belonging to no listed
46
+ family, each fail the run.
47
+
48
+ ## Read the variant once
49
+
50
+ Read one `variant` value at run start, and let it choose the capture destination, the matrix row,
51
+ and the statechart run together. Never split the theme from the viewport; a split writes a filename
52
+ naming a combination the run did not render.
53
+
54
+ - Declare every variant once as a published `CaptureVariant` — its `name`, its `width`, its
55
+ `height`, and the `apply` that switches the theme — and read that list from the capture family and
56
+ the matrix family alike.
57
+ - Loop every declared variant inside one run for the matrix family
58
+ ([styles.md](references/styles.md) → Run per variant).
59
+ - Render exactly one variant per run for the capture family
60
+ ([captures.md](references/captures.md) → Variants).
61
+
23
62
  ## Apply the journey laws
24
63
 
25
- 1. **Drive only what a person can see and reach.** Target every control by its ARIA role and its
26
- accessible name as rendered. Never reach into a component instance, a store, a transport, a
27
- copied credential, or a test-only hook to make a step succeed. Report a step that cannot be
28
- performed through the interface as a finding about the interface.
64
+ 1. **Drive only what a person can see and reach.** Resolve every interactive target by its ARIA
65
+ role and its accessible name as rendered. Never reach into a component instance, a store, a
66
+ transport, a copied credential, or a test-only hook to make a step succeed. Report a step that
67
+ cannot be performed through the interface as a finding about the interface.
29
68
  2. **Assert what is seen.** Quote the rendered text a person reads, which is `innerText` — a label
30
- under `text-uppercase` asserts as `TRACE` where the source says `Trace`. Never let a state read
31
- replace a perception assertion; it may only corroborate one, and `.claude/rules/tests.md` fixes
32
- which state a test may read at all.
69
+ under `text-uppercase` asserts as `TRACE` where the source says `Trace`. Never let an entity
70
+ state read replace a perception assertion; it may only corroborate one, and
71
+ `.claude/rules/tests.md` fixes which entity state a test may read at all.
33
72
  3. **Assert what the interface withholds.** Assert every refusal through the resolver's exact
34
73
  failure voice, and distinguish an absent control from a present but humanly unreachable one.
35
74
  4. **Keep transport and persistence proofs in their own declared block,** never inside a journey.
@@ -43,17 +82,17 @@ Read the current files in this order:
43
82
  7. **Type only what a person would.** Journeys carry trusted input; adversarial payloads belong to
44
83
  the transport family and the parser suites.
45
84
 
46
- ## Build or verify the journey layer
47
-
48
- - Build the layer as shared browser test infrastructure under `.claude/rules/tests.md`: it lives in
49
- the workspace's browser test setup module, exports every helper from there, and adds a journey
50
- helper only where `@orkestrel/test` publishes none. Never declare a resolver inside a test file.
51
- - Give the layer every capability [layer.md](references/layer.md) fixes: the role-scoped resolver
52
- and its distinct failure voices, region-scoped resolution, the input and traversal verbs, the
53
- perception readers, and the capture hook.
54
- - Drive every step through the browser provider's user-event API, and never dispatch a constructed
55
- event ([layer.md](references/layer.md) → What it drives).
56
- - Re-verify the layer against what the application renders now whenever markup changes
85
+ ## Import the journey layer
86
+
87
+ - Import every journey verb, reader, and fixture builder from `@orkestrel/test/browser`. Write one
88
+ of your own only where that package publishes none for the act
89
+ ([layer.md](references/layer.md) → Import, never implement).
90
+ - Place a helper you must write in the workspace's browser test setup module, name it for the act,
91
+ and export it from there under `.claude/rules/tests.md`. Never declare a resolver inside a test
92
+ file.
93
+ - Drive every step through the published verbs, and never dispatch a constructed event
94
+ ([layer.md](references/layer.md) → What it drives).
95
+ - Re-verify every target against what the application renders now whenever markup changes
57
96
  ([layer.md](references/layer.md) → Role vocabulary).
58
97
 
59
98
  ## Derive journeys from intents
@@ -86,7 +125,7 @@ placement and scope `.claude/rules/tests.md` fixes.
86
125
  - Give every surface a refusal family: the controls a person must not reach in the state the
87
126
  journey has put the surface in.
88
127
  - Assert the exact failure voice the case means. Never write an assertion that accepts more than
89
- one voice.
128
+ one voice ([layer.md](references/layer.md) → The failure voices).
90
129
  - Cover the restrictions the interface imposes on itself: a collapsed panel's field, a verb
91
130
  belonging to another kind of object, a control disabled until its precondition lands.
92
131
  - When a refusal changes voice after a markup change, read it as a role or reachability change
@@ -103,17 +142,34 @@ placement and scope `.claude/rules/tests.md` fixes.
103
142
  that clears it.
104
143
  - Assert restart by starting a second session over the same store and polling the restored value.
105
144
 
145
+ ## Prove the styles
146
+
147
+ Follow [styles.md](references/styles.md) for the resolved-value law, the per-variant run, the
148
+ composited contrast reading and its under-bar negative control, the authored-class census, the
149
+ `extractStyles` reading, and the token comparison.
150
+
151
+ ## Prove the statechart
152
+
153
+ Follow [statechart.md](references/statechart.md) for the transition table, the scenario per
154
+ transition, the runner, the harness a person watches, and the gate that drives the harness through
155
+ the interface.
156
+
106
157
  ## Generate the portfolio
107
158
 
108
159
  Follow [captures.md](references/captures.md) for the state registry and its placement rules, the
109
160
  theme-and-viewport variant matrix, the always-on filename proof, the capture-run membership proof,
110
161
  and how a state that exists only during an activation is captured.
111
162
 
112
- When a capture and a green suite disagree, the capture is the evidence and the fixture is the
163
+ Where a capture and a green suite disagree, take the capture as the evidence and the fixture as the
113
164
  defect.
114
165
 
115
166
  Route review of the portfolio to the `orkestrel-polish-surface` campaign. Do not judge it here.
116
167
 
168
+ ## Route the question
169
+
170
+ Follow [decide.md](references/decide.md) before spending a round on a question. It fixes which
171
+ instrument judges which claim, what `prove` cannot serve, and what the run's written artifact holds.
172
+
117
173
  ## Accept
118
174
 
119
175
  Completion requires all of:
@@ -123,10 +179,18 @@ Completion requires all of:
123
179
  - keyboard-only reachability proven on every surface the journeys cover;
124
180
  - a refusal family per surface, each asserting one exact failure voice;
125
181
  - the transport family declared separately, driven through real implementations, and convergent;
182
+ - the declared families each proven, and the declaration itself asserted;
183
+ - the matrix family read once per declared variant, each style instrument carrying the negative
184
+ control that must read under its bar in the same run;
185
+ - the authored-class census and the `extractStyles` reading taken on the mounted surface, each
186
+ reporting the population it walked;
187
+ - the statechart table driven to a terminal outcome with no failed row, and the harness gate green;
126
188
  - the registry-times-variants filename proof and the state-placement proof green in an ordinary run;
127
- - one capture run per variant writing every registered file, each read back non-empty;
189
+ - one capture run per variant writing every registered file, and the disk-membership proof green;
190
+ - the written artifact produced for every variant the run rendered, named by that variant;
128
191
  - perception assertions quoting rendered text, and the vocabulary sweep green on the whole page;
129
192
  - the repository gates green, under the independent-verification law in `.agents/orchestration.md`.
130
193
 
131
- Report each journey by the intent it proves, the refusals it establishes, the states it placed, and
132
- every surface finding the layer's refusals exposed.
194
+ Report each journey by the intent it proves, the refusals it establishes, the states it placed, the
195
+ variants it read, the statechart outcome it reached, and every surface finding the layer's refusals
196
+ exposed.
@@ -1,4 +1,4 @@
1
1
  interface:
2
2
  display_name: 'Prove Human Journeys'
3
3
  short_description: 'Prove an application through the interface a person uses'
4
- default_prompt: 'Use $orkestrel-prove-journey to prove this application through the interface a person uses, and generate the capture portfolio from those journeys.'
4
+ default_prompt: 'Use $orkestrel-prove-journey to prove this application through the interface a person uses, and generate the capture portfolio, the resolved-style matrix, and the statechart outcome from those journeys.'
@@ -4,64 +4,88 @@ Take every screenshot from an acceptance journey, at the moment that journey is
4
4
  picture names. Never add a test whose only purpose is a screenshot, and never stage a state for the
5
5
  camera that a journey did not reach through the interface.
6
6
 
7
- ## The capture hook
8
-
9
- ```ts
10
- capture(state: string): Promise<string | undefined>
11
- ```
12
-
13
- - Return `undefined` and do nothing when the capture flag is unset, so an ordinary run neither
14
- resizes the viewport nor writes a file.
15
- - Read one variant value that names the theme and the viewport together, and refuse a value that
16
- names no registered variant.
17
- - Apply that variant's theme and viewport inside the hook, so the run's single variant value is the
18
- only source of both.
19
- - Write one file named `<state>--<variant>.png` under the workspace's git-ignored `tmp/` tree, and
20
- return the path it wrote.
7
+ ## The hook
8
+
9
+ `createPortfolio(options)` is the capture door, and `place(state, element?)` is the hook. Build the
10
+ portfolio once per file from a `PortfolioOptions` value carrying the registry as `states`, every
11
+ declared `CaptureVariant` as `variants`, this run's `variant`, the `directory` each file is written
12
+ to, and the flag as `enabled`.
13
+
14
+ - Place a state with `place(state)` for the whole page, and `place(state, element)` where the
15
+ picture is one element.
16
+ - Leave `enabled` unset in an ordinary run. `place` then returns `undefined`, resizes nothing,
17
+ writes nothing, and records nothing.
18
+ - Read `files` for the registry expanded across every variant, `placements` for what this run placed,
19
+ and `paths` for what it wrote. Each hands back a snapshot.
20
+
21
+ The package already refuses these, so assert none of them again:
22
+
23
+ | Refusal | Raised by |
24
+ | -------------------------------------------------------------------- | --------------------- |
25
+ | `Capture variant "<name>" is not registered` | `createPortfolio` |
26
+ | `Capture state "<state>" is not registered` | `place`, when enabled |
27
+ | `Capture state "<state>" is already placed` | `place`, when enabled |
28
+ | `Capture frame at <path> is not the one this run shot` | `captureFrame` |
29
+ | `Capture frame was written to <written> where <asked> was asked for` | `captureFrame` |
21
30
 
22
31
  ## The registry
23
32
 
24
- Declare a frozen list of state names and a frozen list of variants in the journey file.
33
+ Declare the state names and the variants once in the journey file, and build the portfolio from
34
+ that declaration.
25
35
 
26
36
  - Name a state for its surface and its condition — `answer-partial`, `start-storage-failure`,
27
37
  `case-delete-confirmation`.
28
38
  - Register the states the design work actually needs, and place every registered one. Never leave a
29
39
  registered state unplaced.
30
- - Wrap the hook in a placement helper that refuses an unregistered state name, refuses a second
31
- placement of the same state, records each written path, and refuses a filename written twice.
32
- - Place a state from inside the journey that reaches it, immediately after the assertion that
33
- proves the surface is in that state.
40
+ - Place a capture state from inside the journey that reaches it, immediately after the assertion
41
+ that proves the surface is in the condition that state names.
42
+ - Record each placed name in the suite's own set in the same step that calls `place`. That set, not
43
+ `placements`, is what the always-on placement proof reads.
34
44
 
35
45
  ## Variants
36
46
 
37
- - Name a variant as one value carrying both the theme and the viewport, such as `dark-390`. Never
38
- split them into separate selectors: a split lets a run write a filename describing a combination it
39
- did not render.
40
- - Render one variant per run, and produce the portfolio — the registry times the variants — by
41
- repeating the run once per variant.
47
+ The run axis is fixed in [SKILL.md](../SKILL.md) → Read the variant once, and the theme switch each
48
+ variant's `apply` performs is fixed in [styles.md](styles.md) → Run per variant. The capture family
49
+ adds these.
50
+
51
+ - Produce the portfolio — the registry times the variants — by repeating the run once per variant.
52
+ - Name each variant for the theme and the viewport it renders, such as `dark-390`. The name is the
53
+ second half of every filename the run writes, so a variant named for one alone produces a
54
+ portfolio nobody can tell apart.
55
+ - Pass the whole variant list as `variants` and this run's name as `variant`. `createPortfolio`
56
+ refuses a `variant` no declared variant carries, and `files` expands the registry across the whole
57
+ list rather than across the one being rendered.
58
+
59
+ ## The proofs the suite owes
42
60
 
43
- ## The proofs
61
+ The package times the registry and refuses a bad placement. It asserts nothing about either, so the
62
+ suite carries these.
44
63
 
45
- | Proof | Runs | Asserts |
46
- | -------------------- | --------------------------- | ---------------------------------------------------------------------------------------------- |
47
- | Filename expansion | Always | The registry's length and uniqueness, the variant count, and that the expansion is unique |
48
- | Portfolio membership | Always; disk under the flag | Every registered state was placed; under the flag, the files on disk are exactly the expansion |
64
+ | Proof | Runs | Asserts |
65
+ | -------------------- | -------------- | ---------------------------------------------------------------------------------- |
66
+ | Filename expansion | Always | `expandCaptures(states, variants)` has one entry per state and variant, all unique |
67
+ | Placement membership | Always | The suite's placed set equals the registry, as sets |
68
+ | Disk membership | Under the flag | The filenames on disk equal the expansion for this run's variant |
49
69
 
50
70
  - Keep the filename proof always-on, so a registry edit that introduces a duplicate or a collision
51
- fails the ordinary run.
52
- - Assert placement equality as set equality against the registry, in every run. Never assert a
53
- count: a count passes while one state is placed twice and another never.
54
- - Under the capture flag, assert the written filenames equal the registry expanded for the run's
55
- variant, then read each file back and require non-empty contents. Never treat the path a
56
- screenshot call returned as proof that a file exists.
71
+ fails the ordinary run. Compare `expandCaptures(states, variants)` against `files` and against a
72
+ set built from it; a length equal to the set's size is what proves the expansion unique.
73
+ - Assert placement as set equality against the registry, in every run. Never assert a count: a count
74
+ passes while one state is placed twice and another never.
75
+ - Read the placement proof from the suite's own set rather than from `placements`. An ordinary run's
76
+ `place` returns before it reads the registry, so `placements` is empty there and an unregistered name
77
+ reaches no refusal until a capture run. The always-on placement proof is what catches it.
78
+ - Under the flag, assert the written filenames equal the registry expanded for the run's variant.
79
+ `captureFrame` already reads each file back and compares its bytes against the frame it shot, so
80
+ the path `place` returns is proof the file exists and holds that frame.
57
81
  - Put the membership proof last in the file, after every journey that feeds its tally.
58
82
 
59
83
  ## Transient states
60
84
 
61
- Capture a state that exists only while an activation is in flight from inside that activation,
62
- never after the click returns.
85
+ Capture a state that exists only while an activation is in flight from inside that activation, never
86
+ after the click returns.
63
87
 
64
- - Attach a one-shot listener to the resolved control, place the capture from inside it, then click
88
+ - Attach a one-shot listener to the resolved control, call `place` from inside it, then click
65
89
  through the normal verb and await the promise the listener recorded.
66
90
  - Fail the step when the listener never ran.
67
91
 
@@ -0,0 +1,68 @@
1
+ # Routing a question
2
+
3
+ Route a question by what judges the claim, before spending a round on it. Report a question no
4
+ instrument here answers as open, and never answer it with the nearest instrument instead.
5
+
6
+ | The claim is judged by | Route it to |
7
+ | -------------------------------------- | -------------------------------------------- |
8
+ | A compiler, a linter, or a Node runner | The `prove` tool, with its negative control |
9
+ | A person's eye | The run's written artifact, named by variant |
10
+ | A person watching a widget move | A statechart harness deep link |
11
+ | The browser's own resolved value | The matrix family ([styles.md](styles.md)) |
12
+
13
+ Never ask `prove` about pixels, and never ask a screenshot about types.
14
+
15
+ ## The receipt half
16
+
17
+ A claim a compiler, a linter, or a Node runner judges goes to `prove`. Supply its workspace project,
18
+ its case, its negative control, and the stage that negative control must break at.
19
+ `.claude/rules/quality.md` § Instruments owns that rule and the receipt line every report quotes;
20
+ follow it there rather than restating it here.
21
+
22
+ - Route the control-to-affordance table, the declared class allowlist's own declaration, the variant
23
+ expansion, and the glyph registry here. Each supplies a project, a case, and a negative control.
24
+ - Read a `no receipt` line as the claim unproved, and report the stage that refused.
25
+
26
+ ## The limit that decides the split
27
+
28
+ `prove` cannot serve a browser project in `@orkestrel/probe` 0.0.11. The following refusals are each
29
+ reproduced:
30
+
31
+ - The runtime stage looks a project up by the name it infers, and a browser project is instantiated
32
+ under its browser-expanded name, so the lookup finds nothing and the claim is refused as missing.
33
+ - The runtime stage pins the `threads` pool, so a browser project's specification runs in a Node
34
+ worker. `@orkestrel/test/browser` imports `vitest/browser` at module scope, so the browser setup
35
+ file throws before the case runs and the failure reads as the claim's.
36
+
37
+ Never route a rendered question to `prove` while that holds. The pinned-pool refusal arrives as a
38
+ case failure, which reads exactly like a broken claim.
39
+
40
+ ## The rendered artifact
41
+
42
+ Write one text file per variant under the workspace's git-ignored `tmp/` tree, named for the variant,
43
+ so a decision cites the exact file and reads it in one call.
44
+
45
+ Compose each file from what the run already holds:
46
+
47
+ - `describeTree` of the mounted surface, for the roles, names, and states a person meets.
48
+ - `describeFocus` of the mounted surface, for the focus order the keyboard walk took.
49
+ - The resolved-style rows the matrix family read for that variant — the property, the element, and
50
+ the value the browser returned.
51
+ - The journal's `steps` and `output`, for what the run did and what the page said while it did it.
52
+ - The capture filenames this run wrote, so the artifact and the portfolio name the same states.
53
+
54
+ Rules the artifact obeys:
55
+
56
+ - Name each file for the variant that produced it. An artifact that names no variant describes a
57
+ combination nobody can reproduce.
58
+ - Write one file per variant, never one file per journey. A decision is taken per variant, and a
59
+ reader opening one file per journey pays a round trip per journey.
60
+ - Regenerate the whole set after any surface change. Never judge a round against a set that is part
61
+ old and part new.
62
+ - Keep it out of version control.
63
+
64
+ ## The harness link
65
+
66
+ Send a look a person decides on to a statechart harness deep link rather than to a file. Name the
67
+ exact link in the round, and let the person watch the widget move rather than read a still of it
68
+ ([statechart.md](statechart.md) → Build the harness a person watches).