@asrunjs/asrun 0.8.0 → 0.10.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.
- package/.claude/commands/explore-case.md +14 -5
- package/.claude/commands/gen-spec.md +12 -5
- package/.claude/commands/heal-spec.md +23 -8
- package/.claude/commands/make-case.md +1 -1
- package/.claude/skills/exploring-cases/SKILL.md +82 -37
- package/.claude/skills/exploring-cases/references/assertion-targets.md +8 -4
- package/.claude/skills/exploring-cases/references/case-rules.md +110 -0
- package/.claude/skills/exploring-cases/references/handoff-card.js +73 -11
- package/.claude/skills/exploring-cases/references/open-questions.md +60 -8
- package/.claude/skills/exploring-cases/references/readiness.md +4 -3
- package/.claude/skills/exploring-cases/references/tools.md +117 -0
- package/.claude/skills/exploring-cases/references/user-handoff.md +46 -17
- package/.claude/skills/generating-specs/SKILL.md +148 -55
- package/.claude/skills/generating-specs/references/conventions.md +4 -0
- package/.claude/skills/making-cases/SKILL.md +14 -7
- package/.claude/skills/making-cases/references/gaps.md +7 -4
- package/.claude/skills/making-cases/references/normalizing.md +1 -1
- package/AGENTS.md +68 -20
- package/README.md +8 -6
- package/bin/asrun.mjs +1 -0
- package/dist/lib/case-doc.d.ts +41 -4
- package/dist/lib/case-doc.js +109 -17
- package/dist/scripts/check-cases.js +89 -1
- package/dist/scripts/doctor.js +50 -3
- package/dist/scripts/markers-confirm.d.ts +1 -0
- package/dist/scripts/markers-confirm.js +139 -0
- package/dist/ui/server/actions.js +57 -18
- package/dist/ui/server/app.js +7 -2
- package/dist/ui/server/job-store.d.ts +60 -0
- package/dist/ui/server/job-store.js +198 -0
- package/dist/ui/server/jobs.d.ts +46 -4
- package/dist/ui/server/jobs.js +361 -59
- package/dist/ui/server/process-info.d.ts +17 -0
- package/dist/ui/server/process-info.js +126 -0
- package/dist/ui/server/result-state.d.ts +10 -0
- package/dist/ui/server/result-state.js +106 -0
- package/dist/ui/shared/ai-commands.d.ts +9 -3
- package/dist/ui/shared/ai-commands.js +25 -11
- package/dist/ui/shared/types.d.ts +18 -3
- package/docs/agents/case-format.md +39 -5
- package/docs/ai-workflow.md +80 -21
- package/docs/cases.md +28 -4
- package/docs/commands.md +6 -1
- package/docs/theme-guide.html +93 -5
- package/docs/troubleshooting.md +47 -3
- package/docs/web-ui.md +55 -10
- package/package.json +2 -1
- package/templates/.claude/commands/explore-case.md +14 -4
- package/templates/.claude/commands/gen-spec.md +12 -4
- package/templates/.claude/commands/heal-spec.md +27 -13
- package/templates/.claude/commands/make-case.md +1 -1
- package/templates/AGENTS.md +9 -6
- package/templates/cases/_template.md +7 -0
- package/templates/package.json +1 -0
- package/ui/dist/assets/{dist-ChBHX4rh.js → dist-2msWI-5M.js} +1 -1
- package/ui/dist/assets/{dist-DoChb6QQ.js → dist-4U_gPHXf.js} +1 -1
- package/ui/dist/assets/{dist-CJiwxr1r.js → dist-BMfJatHo.js} +1 -1
- package/ui/dist/assets/{dist-N-o4QIaZ.js → dist-BVvHVJ3N.js} +1 -1
- package/ui/dist/assets/{dist-BC_P1Gnf.js → dist-BmWaNjqO.js} +1 -1
- package/ui/dist/assets/{dist-Do_MhHKF.js → dist-BwNz_xW2.js} +1 -1
- package/ui/dist/assets/{dist-D6jmnDr-.js → dist-J36xayOv.js} +1 -1
- package/ui/dist/assets/{dist-CavmZIv7.js → dist-e-KhTWHJ.js} +1 -1
- package/ui/dist/assets/{dist-BpkTvixI.js → dist-sfZKBSMm.js} +1 -1
- package/ui/dist/assets/{dist-BgPbx2GZ.js → dist-wjB7g6OJ.js} +1 -1
- package/ui/dist/assets/index-CGbRJT3b.js +348 -0
- package/ui/dist/assets/index-CI0i0LWc.css +2 -0
- package/ui/dist/help/case-explore.png +0 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-Cy2l91qV.css +0 -2
- package/ui/dist/assets/index-DGQ5logJ.js +0 -338
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: generating-specs
|
|
3
|
-
description: Turns a human-written test case (cases/<id>.md, the id may include a group folder such as documents/landing-page) into a Playwright spec (tests/<id>.spec.ts) for the multi-profile test suite, explores the real pages to learn the locators and values, and completes the case's own "## Values" block. It only generates: it never runs the tests. Use when asked to generate, update, fix or
|
|
3
|
+
description: Turns a human-written test case (cases/<id>.md, the id may include a group folder such as documents/landing-page) into a Playwright spec (tests/<id>.spec.ts) for the multi-profile test suite, explores the real pages to learn the locators and values, and completes the case's own "## Values" block. It only generates: it never runs the tests. Healing (repairing a failing spec, or refining a case and its spec on request) is the exception. Use when asked to generate, update, fix, heal or refine a spec, or for /gen-spec or /heal-spec.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Generating specs from case documents
|
|
@@ -8,31 +8,47 @@ description: Turns a human-written test case (cases/<id>.md, the id may include
|
|
|
8
8
|
Read `references/conventions.md` first. It defines the spec shape, fixtures, assertion layers and
|
|
9
9
|
the read-only rules. Read the workspace `AGENTS.md` for the hard rules and the project rules. Read `../exploring-cases/references/open-questions.md`: it
|
|
10
10
|
defines how open questions are written into the case file, resolved and reported. Also read
|
|
11
|
+
`../exploring-cases/references/case-rules.md` (how a case's `## Rules` are read, applied and maintained),
|
|
11
12
|
`../exploring-cases/references/assertion-targets.md` (the exact thing each check looks at) and
|
|
12
|
-
`../exploring-cases/references/readiness.md` (wait for the content, verify downloads in five parts). All
|
|
13
|
+
`../exploring-cases/references/readiness.md` (wait for the content, verify downloads in five parts). All four are binding here.
|
|
13
14
|
|
|
14
15
|
This skill never stops to ask the user in the chat, because it may run without anybody present (a one-shot
|
|
15
|
-
`claude -p` / `opencode run`).
|
|
16
|
-
|
|
16
|
+
`claude -p` / `opencode run`). This holds whatever mode or agent the run is in: plan mode changes what you may write,
|
|
17
|
+
never how you end. If you are not allowed to write files (plan mode, a read-only sandbox, a refused permission), say
|
|
18
|
+
what blocked you in one sentence and end with `RESULT: needs-input` instead of answering with a plan and a question.
|
|
19
|
+
Questions go into the case file; the final line is `RESULT: ready` or `RESULT: needs-input`.
|
|
17
20
|
|
|
18
21
|
This skill trusts the case. What the pages show, what a person has to enter, and what the open questions are is
|
|
19
22
|
settled by `/explore-case` and recorded in the case (`(observed, ...)` marks, the step recipes). Generating
|
|
20
23
|
only finds locators and writes code: it replays the case and does not judge the case again.
|
|
21
24
|
|
|
25
|
+
The profile scope is the case's, not a selection. It is every profile id that appears in the case — the keys of
|
|
26
|
+
`## Values`, a target card's `Reference <profile-id>:` line, a step observation — plus the `default` entry. There is no
|
|
27
|
+
`--profiles` here: never narrow the scope to the profiles that are logged in, and never ask for a subset. The spec runs
|
|
28
|
+
once per profile in the environment, so it must cover every profile the case says something about. A profile the case
|
|
29
|
+
says nothing about runs on `default` alone; name those in the report. Runs of `/explore-case` add up, so a case explored
|
|
30
|
+
with A and B first and C later generates a spec for all three.
|
|
31
|
+
|
|
22
32
|
Generating a spec and running it are separate processes. This skill only writes files: it does not run
|
|
23
33
|
`pnpm asrun`, does not create screenshot baselines and does not judge whether the spec passes. The user runs the
|
|
24
|
-
spec afterwards (see the report). Healing
|
|
34
|
+
spec afterwards (see the report). Healing (below) is the exception: it reads the last report first, may edit the case
|
|
35
|
+
and the spec, and runs only the profiles that are logged in, and only when the report is not enough.
|
|
25
36
|
|
|
26
37
|
## Before you start
|
|
27
38
|
Read the workspace `AGENTS.md`: its §2 holds the project rules, and it points at the framework baseline. If
|
|
28
39
|
`.claude/skills/generating-specs.md` exists in the workspace, read it and apply it after this skill. Then apply
|
|
29
|
-
`AGENTS.md` §2, which wins over both (the baseline, "Precedence"). F1–F6 always win. This is not a stop
|
|
30
|
-
continue with the procedure below.
|
|
40
|
+
`AGENTS.md` §2, which wins over both (the baseline, "Precedence"). F1–F6 and R2 always win. This is not a stop
|
|
41
|
+
condition: continue with the procedure below.
|
|
31
42
|
|
|
32
43
|
## Inputs
|
|
33
44
|
- The case id and the environment to explore in (`staging` or `production`). There is no default. If the
|
|
34
45
|
environment is missing, stop before exploring and report `RESULT: needs-input` ("pass the environment").
|
|
35
46
|
- Optionally `--force`: regenerate the spec from scratch and overwrite the existing one. See "An existing spec".
|
|
47
|
+
- Optionally `--hints <file>` (or free text after the arguments): what the person knows, or a change they want. Read it
|
|
48
|
+
before validating the case. It guides this run; after the work, a reusable instruction is written into `## Rules`
|
|
49
|
+
by the gate in `../exploring-cases/references/case-rules.md`, and a one-off clue stays in the report.
|
|
50
|
+
- No profile selection: the profile scope is the case's (see above). A case id and an environment are all this command
|
|
51
|
+
takes besides `--force` and `--hints`.
|
|
36
52
|
|
|
37
53
|
A case id is its path below `cases/` without `.md`: `hub-landing`, or `documents/landing-page` when the case is in a
|
|
38
54
|
folder (one level only). The spec is at the same path below `tests/` (`tests/documents/landing-page.spec.ts`); both import
|
|
@@ -68,14 +84,21 @@ Decide this first, before exploring anything. The spec path is `tests/<id>.spec.
|
|
|
68
84
|
2. **Validate the case.** Collect everything that is ambiguous, every check without an expected value and every
|
|
69
85
|
missing per-profile value, including the `TODO` items already in the case. Resolve them in the order of
|
|
70
86
|
`open-questions.md`; do not stop here:
|
|
87
|
+
- **Apply the rule pass (`R1`–`R4`).** Read `## Rules` before the steps. A rule that states an expectation, a
|
|
88
|
+
literal, a target or a real step belongs in that section: move it there (or ask). A rule that conflicts with the
|
|
89
|
+
case or the page is a `[blocking]` question, never an override. A rule that would write, send email or do a
|
|
90
|
+
person's step is never followed. Details: `case-rules.md`.
|
|
71
91
|
- **Steps that write or need a choice (`[input]`, `[writes]`) need a recipe.** Each must have at least one
|
|
72
92
|
`- Recipe (phase): ...` line under it in the case (written by `/explore-case`). An old case may still hold the
|
|
73
93
|
same recipe in `## Inputs`: use that line until it is moved under the step. If one has none, the case was
|
|
74
94
|
never explored with a person: stop before opening a browser, do not write the spec, and report `RESULT:
|
|
75
95
|
needs-input` with exactly this: "step <n> has no recorded input; run `/explore-case <id> <env> --attended`
|
|
76
96
|
first". Nothing else is written.
|
|
77
|
-
- Facts the page can answer and that the case does not hold yet are read in step 4 and written into the case
|
|
78
|
-
`(
|
|
97
|
+
- Facts the page can answer and that the case does not hold yet are read in step 4 and written into the case. Mark
|
|
98
|
+
them by the gate in `open-questions.md` ("Which sentences carry a marker"): a locator, a flow or a request is
|
|
99
|
+
`(seen on <profile>)`; a literal the spec asserts gets
|
|
100
|
+
`(observed on <profile>, 🔍 to be confirmed: <what a person must decide>)`, and that is the only thing a person
|
|
101
|
+
has to settle. A spec is generated from observed values.
|
|
79
102
|
- Safe defaults are applied: the suggestion is the sentence above the TODO block, and the block stays in the case
|
|
80
103
|
as `❓ TODO [non-blocking]` with an empty `✍️ Answer:`. A sentence with no TODO block under it is confirmed text.
|
|
81
104
|
- A non-empty `Answer:` is the user's answer: it wins over the sentence above it. Fold it into the case.
|
|
@@ -94,40 +117,52 @@ Decide this first, before exploring anything. The spec path is `tests/<id>.spec.
|
|
|
94
117
|
- Do not invent expected values. If the case's `## Values` and the spec disagree, the case wins: fix the spec and
|
|
95
118
|
mention the change in the report.
|
|
96
119
|
3. **Check sessions** if `login: required`: run `pnpm status --env <env>`. If a profile needs login, tell the
|
|
97
|
-
user to run `pnpm signin <profile-id>` and continue with the profiles that are ready.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
and
|
|
120
|
+
user to run `pnpm signin <profile-id>` and continue with the profiles that are ready. A profile the case holds
|
|
121
|
+
information for is never dropped because it is not logged in: write its part from the case and mark it
|
|
122
|
+
`not verified on the page` in the report. If `pnpm status` cannot run (a sandbox error such as `listen EPERM` or a
|
|
123
|
+
Chromium start failure), judge by the page instead: a page that lands on the login page means the profile is not
|
|
124
|
+
logged in.
|
|
125
|
+
4. **Replay the case on the real page** with the `playwright-test` MCP. Read `../exploring-cases/references/tools.md`
|
|
126
|
+
first: that MCP lists tools it cannot run, and a call that answers `Tool "<name>" not found` means exactly that (the
|
|
127
|
+
server is up; use the substitute). If its tools are not registered in this session at all (no `browser_*` /
|
|
128
|
+
`generator_*` tool) or it reports that it failed to start, do not fall back to ad-hoc Playwright scripts: stop, tell
|
|
129
|
+
the user which MCP server is missing and to run `pnpm asrun doctor`, write no spec, and end with
|
|
130
|
+
`RESULT: needs-input`.
|
|
104
131
|
Call `generator_setup_page` with
|
|
105
|
-
`project=<profile-id>` (for example `example-staging`)
|
|
132
|
+
`project=<profile-id>` (for example `example-staging`), `seedFile=tests/seed.spec.ts` and `plan=""`, then perform the
|
|
106
133
|
steps in the environment you were given (never ask for it; there is no default) to learn the locators.
|
|
107
|
-
Do the read-only steps as written
|
|
108
|
-
|
|
134
|
+
Do the read-only steps as written, and follow the `## Rules` that say how to prepare, wait or which control to
|
|
135
|
+
avoid. **Never perform a step that writes or needs a choice**: the agent does not write
|
|
136
|
+
data, in staging or in production, and it does not hand off to a person here or wait for one. A rule never
|
|
137
|
+
authorizes one of those steps. Write those steps
|
|
109
138
|
of the spec from the `- Recipe:` lines under the step (positions, `[asrun]` names, control labels and roles that
|
|
110
139
|
`/explore-case` recorded). Pages that only exist after such a step cannot be seen from here: write their locators
|
|
111
140
|
from what the recipe and the exploration notes say, mark them in the report as "not verified on the page", and
|
|
112
|
-
leave the first run of the spec (or `/heal-spec`) to confirm them. Do this for at least one profile
|
|
113
|
-
per domain (example.com and exampleshop.com differ in markup).
|
|
114
|
-
named in the report
|
|
115
|
-
|
|
141
|
+
leave the first run of the spec (or `/heal-spec`) to confirm them. Do this for at least one logged-in profile
|
|
142
|
+
per domain (example.com and exampleshop.com differ in markup). A profile the case holds information for that is
|
|
143
|
+
not logged in is skipped and named in the report; its part is written from the case and marked `not verified` in
|
|
144
|
+
the assertion table. Use this exploration to answer the open points of step 2, and read each profile's value from
|
|
145
|
+
the case's `## Values`: open that profile's page only when a value or a behavior still has to be resolved for it.
|
|
116
146
|
Keep every browser call short (one action, about 60 s at most, a snapshot between steps, `{timeout: 5000}` when
|
|
117
147
|
something may not appear, no third retry): see "Keep every browser call short" in `../exploring-cases/SKILL.md`.
|
|
118
|
-
**Ready before you read, here too** (`readiness.md`):
|
|
119
|
-
(`
|
|
120
|
-
`Ready when` signals of the case are taken from what you see here.
|
|
148
|
+
**Ready before you read, here too** (`readiness.md`): take a marker on `browser_network_requests`
|
|
149
|
+
(`static: false`), act, wait for the key requests above that mark and the content signal, then snapshot. The request
|
|
150
|
+
URL patterns for `actAndWait` and the `Ready when` signals of the case are taken from what you see here.
|
|
121
151
|
**Check every target on the page:** for each target card, find its `Identified by` locator, confirm that it matches
|
|
122
|
-
exactly one element and that this element is what `What` says (
|
|
123
|
-
matches several elements or the wrong one is fixed or becomes a
|
|
152
|
+
exactly one element and that this element is what `What` says (outline it with `locator.highlight()` and look at the
|
|
153
|
+
screenshot, see `tools.md`). A locator that matches several elements or the wrong one is fixed or becomes a
|
|
154
|
+
question, never `.first()`.
|
|
124
155
|
Prefer `getByTestId` (the project uses `data-tn`), then role/label locators. No CSS chains or XPath.
|
|
125
|
-
Update the case file with what you learned: fold observations into the right section marked
|
|
126
|
-
|
|
127
|
-
and narrow the ones that remain. Keep the shape of
|
|
156
|
+
Update the case file with what you learned: fold observations into the right section, marked `(seen on <profile>)`
|
|
157
|
+
or, for a literal the spec asserts, `(observed on <profile>, 🔍 to be confirmed: <what to decide>)`; remove the
|
|
158
|
+
TODO blocks they answer (rewrite the sentence above the block), and narrow the ones that remain. Keep the shape of
|
|
159
|
+
`open-questions.md` for every block, and never put a marker inside one. Edit the case
|
|
128
160
|
with targeted edits; never touch its `## Source` table.
|
|
129
|
-
5. **Complete the case's `## Values`**: for every profile the
|
|
130
|
-
asserts (the same keys as `default`, only what differs)
|
|
161
|
+
5. **Complete the case's `## Values`**: for every profile the case holds information for, add the entry with the
|
|
162
|
+
literals the spec asserts (the same keys as `default`, only what differs); put a literal that holds for every profile
|
|
163
|
+
in `default`. Do not add an entry for a profile the case says nothing about, and never invent a value to fill one: a
|
|
164
|
+
profile without an entry runs on `default` alone, and a literal the case does not hold is a question in the case.
|
|
165
|
+
Do not move values into `profiles.yaml`; it holds connection
|
|
131
166
|
settings only. Mention every value you added or corrected in the report.
|
|
132
167
|
6. **Write `tests/<id>.spec.ts`** (inside the group folder if the id has one, creating it if needed) following the conventions. One `test()` per outcome, and every
|
|
133
168
|
case step wrapped in `test.step()` with the case's step text as the title, and the top-level
|
|
@@ -136,7 +171,10 @@ Decide this first, before exploring anything. The spec path is `tests/<id>.spec.
|
|
|
136
171
|
(`@asrunjs/asrun/values`), which merges `default` with the running profile's entry.
|
|
137
172
|
Every action that loads something goes through `actAndWait` (`@asrunjs/asrun/ready`) with the key requests and the ready
|
|
138
173
|
signal; every download goes through `verifyDownload` (`@asrunjs/asrun/downloads`); every check on a target has
|
|
139
|
-
`// target: T<n>` on the line before it; every absence check has a `// ready: <signal>` before it
|
|
174
|
+
`// target: T<n>` on the line before it; every absence check has a `// ready: <signal>` before it; code that exists
|
|
175
|
+
only because of a `## Rules` bullet carries `// rule: <short quote>` before it; an assertion whose literal comes
|
|
176
|
+
from a `🔍 to be confirmed` line carries `// unconfirmed: <that case sentence>` before it, so
|
|
177
|
+
`pnpm markers:confirm` can settle it from a passing run. Never
|
|
140
178
|
`waitForTimeout`, `networkidle` or `.first()` to pick an image. A confirmation or modal that may or may not appear is
|
|
141
179
|
never decided by one `isVisible()` look (its `timeout` option is ignored): use `clickOptionalUntilHidden`
|
|
142
180
|
(`@asrunjs/asrun/ready`) or a waiting `expect(...).toBeVisible({timeout})`; see `readiness.md`, "Optional confirmations".
|
|
@@ -150,13 +188,18 @@ Decide this first, before exploring anything. The spec path is `tests/<id>.spec.
|
|
|
150
188
|
Do NOT run `pnpm asrun`, do not use
|
|
151
189
|
`--update-snapshots` and do not create baselines: the first run of the spec does that, and a person reviews them.
|
|
152
190
|
8. **Report** in the user's language: spec path, **an assertion table** (step, what is asserted, target card, ready signal, and
|
|
153
|
-
`observed on the page` or `not verified`; no row may be missing), profiles explored, profiles skipped (and why),
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
191
|
+
`observed on the page` or `not verified`; no row may be missing), profiles explored, profiles skipped (and why),
|
|
192
|
+
the profiles of `profiles.yaml` the case holds no information for (they run on `default` alone), whether the case file was
|
|
193
|
+
translated, what was added to the case file as `(seen on <profile>)` and which lines still need a person
|
|
194
|
+
(`🔍 to be confirmed`, with the reason), checks generated from observations, visual checks that need a baseline on
|
|
195
|
+
the first run, and the remaining TODO blocks (`[blocking]` ones with
|
|
196
|
+
the sentence that deleting the block would confirm). Add the rule table of `case-rules.md`: every `## Rules`
|
|
197
|
+
bullet, where it was applied or why it was not, and which rules were added from `--hints`. State that the spec was
|
|
198
|
+
not run and give the command to run it:
|
|
157
199
|
`pnpm asrun --env <env> --profile <ids> --grep <id>` (with `--update-snapshots` once if the spec has visual
|
|
158
200
|
checks, then run `pnpm baselines:review <id> --new` and open every new image: it must show what its target card says). The last line is `RESULT: ready` (no `[blocking]` question left, spec
|
|
159
|
-
written and the checks above pass) or `RESULT: needs-input`, as defined in `open-questions.md
|
|
201
|
+
written and the checks above pass) or `RESULT: needs-input`, as defined in `open-questions.md`: plain text on the
|
|
202
|
+
last line, never inside a code fence or in emphasis.
|
|
160
203
|
|
|
161
204
|
## Cases that write data
|
|
162
205
|
Only when the case front matter lists environments under `writes` (for example `writes: [staging]`). Never add
|
|
@@ -166,34 +209,54 @@ spec does, when a person runs it in an environment that `writes` lists. Elsewher
|
|
|
166
209
|
notice. Never send email in production; in other environments only if `profile.email` is true, otherwise skip that step and say so
|
|
167
210
|
in the report.
|
|
168
211
|
|
|
169
|
-
## Healing a
|
|
212
|
+
## Healing and refining a spec
|
|
170
213
|
Inputs: the case id and the environment (both required, there is no default: without an environment stop and say so),
|
|
171
214
|
optionally `--profiles a,b`, `--report <run-id>` and `--hints <file>` (or free text after the arguments). Healing is
|
|
172
215
|
the one case where this skill runs specs, and only in the environment given.
|
|
173
216
|
|
|
217
|
+
Healing has two jobs, and the same command does both: **repair** a spec that fails, and **refine** a case and its spec
|
|
218
|
+
when the user asks for a change. A passing run is never a reason to refuse a request, and "nothing failed" is never a
|
|
219
|
+
reason to do nothing when the user asked for something.
|
|
220
|
+
|
|
174
221
|
Heal from evidence, not from a habit of rerunning. A report that already exists says what failed.
|
|
175
222
|
|
|
176
|
-
1. **Read the user's
|
|
177
|
-
evidence the report lacks.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
223
|
+
1. **Read the user's request first** (the `--hints` file, or the free text). It says what to repair or improve and may
|
|
224
|
+
hold evidence the report lacks. Read the case's `## Rules` before the steps and apply the rule pass (`R1`–`R4`,
|
|
225
|
+
`../exploring-cases/references/case-rules.md`). Decide which kind of work it is:
|
|
226
|
+
- a failure to repair (the last run failed, or the user names one);
|
|
227
|
+
- an improvement, even when the last run passed: a check that is too loose, a step, expectation, value or target
|
|
228
|
+
that no longer matches the page, wording a person cannot follow;
|
|
229
|
+
- both.
|
|
230
|
+
Quote the request you used, or say that it did not hold up, in the report. It guides the work and nothing else: it
|
|
231
|
+
never lowers the bar for a product finding and never allows an expectation to be changed just to make a test pass.
|
|
232
|
+
- **No report and no request:** do not invent work. Say that nothing asks for a change, list what
|
|
233
|
+
`pnpm spec:lint <case-id>` and the last report call weak (as suggestions, not edits), and end with `RESULT: ready`.
|
|
234
|
+
- **A passing report and no request:** the same. Do not start an improvement of your own.
|
|
235
|
+
2. **Read the existing report** if there is one: run `pnpm heal:evidence --case <case-id> --env <env>` (add `--profile a,b` when `--profiles`
|
|
181
236
|
was given). It reads `reports/*/summary.json` and prints, per profile, the status, the failed step, the error, the call
|
|
182
237
|
log, the screenshots and videos, and ends with `EVIDENCE: fresh | stale | no-failure | none`. With `--report <run-id>`,
|
|
183
238
|
read `reports/<run-id>/summary.json` instead. Look at the screenshot when the error alone does not explain it. A profile
|
|
184
|
-
that failed only because it was not logged in is no evidence about the spec.
|
|
239
|
+
that failed only because it was not logged in is no evidence about the spec. `EVIDENCE: none` or `no-failure` with an
|
|
240
|
+
improvement request is a starting point, not a stop.
|
|
185
241
|
3. **Decide whether to rerun the case**. Do not rerun when the report is `fresh`, names the failing step and the error,
|
|
186
242
|
and that is enough to tell whether the product changed or the test is wrong. Rerun when:
|
|
187
243
|
- there is no report (`none`), or it is `stale` (the spec, the case or `profiles.yaml` changed after it);
|
|
188
244
|
- the report does not explain the failure (a bare timeout with no locator, a failure before any step, a truncated log);
|
|
189
|
-
- a clue
|
|
245
|
+
- a clue or a requested improvement has to be checked against the real page, and no recent report shows it;
|
|
190
246
|
- a profile that must be healed has no result in the report (for example it was not logged in then).
|
|
191
247
|
Rerun with one plain command, as few profiles as possible, and say why in the report:
|
|
192
248
|
`pnpm asrun --env <env> --logged-in --profile <ids> --grep <case-id>` (optionally piped to `tail`; do not chain it
|
|
193
249
|
with other commands, or it runs inside Claude's sandbox and fails with `listen EPERM`). Always add `--logged-in`: it
|
|
194
250
|
leaves out the profiles that are not logged in instead of failing them. A profile that is not logged in is never healed:
|
|
195
251
|
name it in the report with `pnpm signin <profile-id>`.
|
|
196
|
-
4. **
|
|
252
|
+
4. **Look at the pages when the change depends on them.** Reading a page is not a run and is always allowed, also for an
|
|
253
|
+
improvement request with no failure behind it. Use the `playwright-test` MCP exactly as `/gen-spec` step 4 describes
|
|
254
|
+
(`generator_setup_page` with `project=<profile-id>`, one action per call, ready before you read). Do the read-only
|
|
255
|
+
steps only: **never perform a step that writes or needs a choice**, in any environment. What you see goes into the
|
|
256
|
+
case by the gate in `open-questions.md` ("Which sentences carry a marker"): `(seen on <profile>)` for a locator, a
|
|
257
|
+
flow or a request, and `(observed on <profile>, 🔍 to be confirmed: <what a person must decide>)` only for a
|
|
258
|
+
literal the spec asserts, so the person settles that in the review gate below.
|
|
259
|
+
5. **Audit the assertion before you blame anyone.** Read the `assertion-targets.md` and `readiness.md` sections on healing.
|
|
197
260
|
- Is the locator still what the target card says (`What`, `Identified by`)? Open the failure screenshot and the
|
|
198
261
|
baseline (`pnpm baselines:review <case-id>`) and look at each: a baseline that shows something other than the card
|
|
199
262
|
(a content image instead of a logo) is a wrong test, and passing runs on it prove nothing. Delete it and report it; a
|
|
@@ -204,16 +267,46 @@ Heal from evidence, not from a habit of rerunning. A report that already exists
|
|
|
204
267
|
- A download that fails says which stage failed (start, finish, exists, valid): fix the stage, do not loosen the check.
|
|
205
268
|
- Doubt about which element is meant: write the question into the case (a `[blocking]` TODO naming the exact image,
|
|
206
269
|
text, place or UI) instead of choosing; do not rewrite the card quietly.
|
|
207
|
-
|
|
270
|
+
6. **Decide what the change belongs to, and change the case first.**
|
|
208
271
|
- Locator/timing problem: fix the spec.
|
|
209
272
|
- A real product difference (wrong logo, wrong name): do NOT change the expectation to make it
|
|
210
273
|
pass. Report it as a finding with the trace/screenshot path.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
274
|
+
- A request the case can settle: the case is the source of truth, so write the change into `cases/<case-id>.md`
|
|
275
|
+
first, then into the spec. That covers a step, an expectation, a value in `## Values`, a target card, a ready
|
|
276
|
+
signal and a recipe. The spec follows the case (its step titles copy the case's step text). When the case changed
|
|
277
|
+
more than a sentence (a new or removed step, different expected values, another target), regenerate the spec from
|
|
278
|
+
the case as "## Procedure" steps 5–6 describes instead of patching it; otherwise edit it in place. Say in the
|
|
279
|
+
report which of the two you did.
|
|
280
|
+
- A reusable instruction that is method, not an expectation: append it to `## Rules` under the four-question gate
|
|
281
|
+
of `case-rules.md`, in general terms, after checking that it is not already there. An agent-inferred rule
|
|
282
|
+
carries a marker only when it changes what is asserted; a method rule is `(seen on <profile>)` and a rule the
|
|
283
|
+
person stated carries nothing. A one-off request (this failure, this
|
|
284
|
+
account, this run) stays in the report. Never put a write, an email, a person's step, an expectation or a literal
|
|
285
|
+
into `## Rules`.
|
|
286
|
+
7. **Stop at the review gate.** After editing the case, read it back. If **this run** left a `🚫 TODO [blocking]` or
|
|
287
|
+
`❓ TODO [non-blocking]` block, or a `🔍 to be confirmed` or `👁️ not observed` marker, do not edit or
|
|
288
|
+
regenerate the spec any further: a case that still asks something is not a source for a spec. Report exactly what
|
|
289
|
+
to review, that answering or deleting those blocks comes first, and that the next command is
|
|
290
|
+
`/explore-case <case-id> <env>` (with `--attended` when a step writes data), or
|
|
291
|
+
`pnpm markers:confirm --case <case-id> --env <env>` when a passing run already checks those lines. End with
|
|
292
|
+
`RESULT: needs-input`. Blocks and markers that were already in the case before this run and that it did not touch do
|
|
293
|
+
not stop it. A plain `(seen on <profile>)` note never stops it. One exception:
|
|
294
|
+
a `🔍 to be confirmed` marker inside `## Rules` does not stop the spec work unless the rule covers a literal the
|
|
295
|
+
spec asserts (a `🚫`/`❓` TODO block under a rule still does).
|
|
296
|
+
8. **After editing the spec, run it once to confirm** (same command as in step 3, for the profiles you healed). That rerun
|
|
297
|
+
is the only one that is always allowed. Run `pnpm typecheck`, `pnpm spec:lint <case-id>` and `pnpm case:check`, and
|
|
298
|
+
fix every failure of the checks you touched. An improvement may make the run fail on purpose: a tightened check that
|
|
299
|
+
now fails is evidence about the product, so report it as a finding instead of loosening it again.
|
|
300
|
+
9. **Report** in the user's language: which report was read (or that there was none) and whether it was fresh or stale,
|
|
301
|
+
whether the case was run again and why (or why not), what the request asked for and what came of it, what was
|
|
302
|
+
changed in the case and in the spec (and whether the spec was regenerated), what is a product finding (with paths),
|
|
303
|
+
which assertions were wrong or raced the page, which baselines are wrong and were deleted, what the user's request
|
|
304
|
+
contributed, the rule table of `case-rules.md` (every `## Rules` bullet, where it was applied or why it was not,
|
|
305
|
+
and which rules this run added or changed), which profiles were left out because they are not logged in, and the
|
|
306
|
+
result of the confirming run. The last line is `RESULT: ready` (nothing left for a person, the spec changed and its checks pass)
|
|
307
|
+
or `RESULT: needs-input` (the case waits for a review, as in step 7, or a person has to decide something). A run
|
|
308
|
+
that could not write files at all (plan mode, a read-only sandbox, a refused permission) is `needs-input` too:
|
|
309
|
+
never end with a plan and a question instead.
|
|
217
310
|
|
|
218
311
|
A case that writes data in `production` needs a person's confirmation at run time, so the rerun is refused there:
|
|
219
312
|
use the report, or heal in staging, and never add `--allow-writes`.
|
|
@@ -108,6 +108,10 @@ Binding rules are in `../exploring-cases/references/readiness.md` and `.../asser
|
|
|
108
108
|
- A check on a logo, image, file or screenshot has `// target: T<n>` on the line before it (a card in the case's
|
|
109
109
|
`## Targets`). The element is found by the card's `Identified by` (role and name, test id, alt/title), never `.first()` or
|
|
110
110
|
a bare `img`/`svg`. Semantic assertion first (name/alt/src, where it is), pixels second, on that element only.
|
|
111
|
+
- An assertion whose literal comes from a `🔍 to be confirmed` line in the case carries
|
|
112
|
+
`// unconfirmed: <that case sentence>` before it (one line, the sentence without its marker). It is what
|
|
113
|
+
`pnpm markers:confirm --case <id> --env <env>` reads after a passing run to settle the marker, so the line must be
|
|
114
|
+
the case's own wording, not a paraphrase.
|
|
111
115
|
- A check for absence ("no", "missing", "empty", "hidden") has `// ready: <signal>` in front of it and a positive wait
|
|
112
116
|
before it. The page must have loaded before "nothing" means anything.
|
|
113
117
|
- A download is `await verifyDownload(page, () => option.click(), {kind: 'pdf'})`. It checks, and fails the step on
|
|
@@ -10,14 +10,16 @@ Read the workspace `AGENTS.md` (hard rules and project rules) and `cases/_templa
|
|
|
10
10
|
- `references/writes-and-email.md`: how to classify steps that write data or send email, and the data rules.
|
|
11
11
|
- `references/gaps.md`: what to ask, and the default to suggest for each question.
|
|
12
12
|
- `references/splitting.md`: how many cases to make.
|
|
13
|
+
- `../exploring-cases/references/case-rules.md`: what belongs in `## Rules` (a method constraint), and what stays in
|
|
14
|
+
Steps, Expected, Values or Targets.
|
|
13
15
|
|
|
14
16
|
This skill writes `cases/*.md` only. It never writes specs, `profiles.yaml`, or anything under `tests/`.
|
|
15
17
|
|
|
16
18
|
## Before you start
|
|
17
19
|
Read the workspace `AGENTS.md`: its §2 holds the project rules, and it points at the framework baseline. If
|
|
18
20
|
`.claude/skills/making-cases.md` exists in the workspace, read it and apply it after this skill. Then apply `AGENTS.md`
|
|
19
|
-
§2, which wins over both (the baseline, "Precedence"). F1–F6 always win. This is not a stop condition:
|
|
20
|
-
the procedure below.
|
|
21
|
+
§2, which wins over both (the baseline, "Precedence"). F1–F6 and R2 always win. This is not a stop condition:
|
|
22
|
+
continue with the procedure below.
|
|
21
23
|
|
|
22
24
|
## Inputs
|
|
23
25
|
- Raw notes: pasted text or a file path. Any language, any quality.
|
|
@@ -34,10 +36,11 @@ the procedure below.
|
|
|
34
36
|
creates, edits, publishes, shares, deletes or sends is not read-only, even if the notes do not say so.
|
|
35
37
|
4. **Find the gaps** (`references/gaps.md`): missing expected results, unknown values a spec must assert, unclear starting
|
|
36
38
|
state, steps that need data that may not exist, ordering that is not linear. Never invent an expected value.
|
|
37
|
-
Unknown values are written as the suggested default sentence with a `❓ TODO` block under it (see `gaps.md`)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
`
|
|
39
|
+
Unknown values are written as the suggested default sentence with a `❓ TODO` block under it (see `gaps.md`). A fact
|
|
40
|
+
from the notes that nobody questions is a plain note `(seen on <profile>)`; only a literal the spec will assert and
|
|
41
|
+
that would pass while wrong gets `(observed on <profile>, 🔍 to be confirmed: <what to decide>)`. A marker never
|
|
42
|
+
goes inside a TODO block. A literal nobody knows yet goes into the case's `## Values` as `TODO` (the spec then fails
|
|
43
|
+
with a clear message until it is filled), never into `profiles.yaml`.
|
|
41
44
|
5. **Ask before writing.** Show the user a short plan and the open questions in one message: the proposed split
|
|
42
45
|
into cases, the classification (which steps write, which send email), and the gaps with your suggested default
|
|
43
46
|
for each. Wait for answers. Do not write case files before that.
|
|
@@ -48,10 +51,14 @@ the procedure below.
|
|
|
48
51
|
ask in step 5. The group does not repeat in the name: `documents/landing-page`, not `documents/documents-landing-page`.
|
|
49
52
|
- Front matter: `id`, `title`, `login`, `suites`, `writes`, `writes-note` (required when `writes` is not `none`),
|
|
50
53
|
`envs` when a case must not run everywhere. When unsure: `suites: [regression]`, no `writes` (read-only), or `writes: [staging]` when a step writes.
|
|
51
|
-
- Fill the sections that apply (Goal, Steps, Expected, Values, Visual checks, Source, Notes).
|
|
54
|
+
- Fill the sections that apply (Goal, Steps, Expected, Rules, Values, Visual checks, Source, Notes).
|
|
52
55
|
Remove template placeholders you do not use. Use `## Values` only for the literals a spec asserts; `default`
|
|
53
56
|
applies to every profile, and a profile id entry holds only what differs. Do not add `- Recipe:` lines: a person
|
|
54
57
|
records them during `/explore-case --attended`.
|
|
58
|
+
- Put a note in `## Rules` only when it states a **method** constraint (dismiss a banner before step 1, never use
|
|
59
|
+
an entry that needs 2FA). A constraint that is part of the tested flow is a step; one that creates, changes or
|
|
60
|
+
deletes data is a tagged step with a later recipe. Never invent a rule, and never put an expectation or a literal
|
|
61
|
+
there: those go to `## Expected` or `## Values`. The note that became a rule is listed in its `## Source` row.
|
|
55
62
|
- Case ids are lowercase kebab-case and name the thing, not the ticket: `landing-page`.
|
|
56
63
|
- Existing case files: do not overwrite. If a new case overlaps one (for example another case about the same page), say so,
|
|
57
64
|
propose "keep", "merge" or "replace", and wait for the user.
|
|
@@ -17,7 +17,7 @@ single lines. Never ask a question whose answer is already in the notes, `AGENTS
|
|
|
17
17
|
| Environments | Must this case run in production, or only staging? | All environments; production writes need the usual confirmation |
|
|
18
18
|
| Suites | Smoke, regression, or both? | A read-only landing check: `[smoke, regression]`; a flow that writes: `[regression]` |
|
|
19
19
|
| Profiles | Do all profiles see the same UI? | Yes; the exact literals that differ go in `## Values`, never in the steps |
|
|
20
|
-
| Unclear words | What does "collaborator button" / "..." button open? | Describe
|
|
20
|
+
| Unclear words | What does "collaborator button" / "..." button open? | Describe the safest reading and hang a TODO under it; a detail nobody questions is a plain note `(seen on <profile>)` |
|
|
21
21
|
| Unused lines | A statement that fits no case | Ask where it belongs; never drop it silently |
|
|
22
22
|
|
|
23
23
|
## Marking unknowns in a case
|
|
@@ -26,11 +26,14 @@ single lines. Never ask a question whose answer is already in the notes, `AGENTS
|
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
- The preview header shows the product logo, visible and not empty.
|
|
29
|
-
- ❓ TODO [non-blocking]: Which logo must it be? (
|
|
29
|
+
- ❓ TODO [non-blocking]: Which logo must it be? (the notes say only "the logo")
|
|
30
30
|
- ✍️ Answer:
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
The user accepts the default by deleting the block, or types an answer. Never write a bare `TODO: ...` line, a
|
|
34
|
-
question as the only text, or `Suggested:`.
|
|
35
|
-
- Seen on a page during exploration but not stated in the notes: `- <observation> (
|
|
34
|
+
question as the only text, or `Suggested:`. Never put a marker word inside the block: one claim carries one signal.
|
|
35
|
+
- Seen on a page during exploration but not stated in the notes: `- <observation> (seen on <profile>)`. A literal the
|
|
36
|
+
spec will assert is different: `(observed on <profile>, 🔍 to be confirmed: <what a person must decide>)`, and only
|
|
37
|
+
when a wrong reading would still pass. The gate is "Which sentences carry a marker" in
|
|
38
|
+
`exploring-cases/references/open-questions.md`.
|
|
36
39
|
- Never turn an observation into a hard requirement on your own.
|
|
@@ -34,6 +34,6 @@ Original notes, verbatim. Do not edit this table; it only exists so a reviewer c
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
- The original text is copied character by character, in a code span, in its original language.
|
|
37
|
-
- "Became" points at step numbers, or says "Expected", "Visual checks", "Not used: <reason>".
|
|
37
|
+
- "Became" points at step numbers, or says "Expected", "Rules", "Visual checks", "Not used: <reason>".
|
|
38
38
|
- A statement used by two cases appears in both tables.
|
|
39
39
|
- A statement that is not used anywhere is a gap: ask about it, do not silently drop it.
|
package/AGENTS.md
CHANGED
|
@@ -11,7 +11,7 @@ project that uses asrun, the framework files are in `node_modules/@asrunjs/asrun
|
|
|
11
11
|
## Precedence
|
|
12
12
|
|
|
13
13
|
Rules are applied in this order; a later layer wins where they conflict.
|
|
14
|
-
1. **F1–F6: safety.** Nothing overrides them, in any project. They are enforced in code as well
|
|
14
|
+
1. **F1–F6 and R2: safety.** Nothing overrides them, in any project. They are enforced in code as well
|
|
15
15
|
(`lib/write-gate.ts`, `lib/session.ts`, the run filters), so a rule file cannot weaken them.
|
|
16
16
|
2. **This file.** The generic facts and defaults.
|
|
17
17
|
3. **The framework skills** (`<framework>/.claude/skills/**`).
|
|
@@ -20,8 +20,11 @@ Rules are applied in this order; a later layer wins where they conflict.
|
|
|
20
20
|
5. **The project's `AGENTS.md` §2 (Project rules).** It states the project's intent and wins over layers 2–4.
|
|
21
21
|
|
|
22
22
|
A project writes §2 only for what differs from the defaults here, names the rule id, and says whether it `narrows` or
|
|
23
|
-
`replaces` the rule. `replaces` is refused for F1–F6; `pnpm asrun doctor` checks the table. A rule file never
|
|
24
|
-
the structural tokens under "Fixed tokens".
|
|
23
|
+
`replaces` the rule. `replaces` is refused for F1–F6 and R2; `pnpm asrun doctor` checks the table. A rule file never
|
|
24
|
+
renames the structural tokens under "Fixed tokens".
|
|
25
|
+
|
|
26
|
+
Inside a case, `## Rules` is a case-local layer below this file and the project's §2: it says how to run that case,
|
|
27
|
+
never what is true (`R1`), and a rule that conflicts with the rest of the case is a question, not an override.
|
|
25
28
|
|
|
26
29
|
## Hard rules
|
|
27
30
|
- **F1 — Read-only by default.** [non-negotiable] Tests never create, edit, delete, submit forms that change data,
|
|
@@ -62,8 +65,12 @@ These apply to every agent that drives a browser to explore pages for cases or s
|
|
|
62
65
|
Everything that writes is the person's (see F3).
|
|
63
66
|
- **B2 — Waiting for a person.** Only in an attended run. Announce the task in the browser window (a small draggable
|
|
64
67
|
card with a Done button and click-to-copy for texts to type), name the finish condition, wait, and tell the person
|
|
65
|
-
when control is back.
|
|
66
|
-
|
|
68
|
+
when control is back. The card starts and stops the recording itself and returns `recorded`; never call
|
|
69
|
+
`browser_start_recording` or `browser_stop_recording`: the `playwright-test` MCP lists many browser tools it cannot
|
|
70
|
+
run (`devtools`, `storage`, `network`, `pdf`, `vision`, and the `skillOnly` ones such as `browser_network_clear`),
|
|
71
|
+
and the substitutes for each are in `<framework>/.claude/skills/exploring-cases/references/tools.md`. Record what
|
|
72
|
+
they did as a general recipe under the step (`- Recipe (phase): ...`): positions instead of names of data that can
|
|
73
|
+
change.
|
|
67
74
|
- **B3 — Closing an email composer.** When closing an email composer makes a confirm dialog appear (for example
|
|
68
75
|
"Discard draft?"), choose "Discard" and continue. Never choose "Save" or "Send"; closing the composer must not keep
|
|
69
76
|
or send anything. The dialog can show up late: in a spec, clicking "Discard" and checking that the composer is
|
|
@@ -104,27 +111,60 @@ Details: `<framework>/.claude/skills/exploring-cases/references/assertion-target
|
|
|
104
111
|
- **A6 — Observe first, delete last.** Everything that needs the data (preview, share menus, composers, downloads) is
|
|
105
112
|
observed before the person deletes it.
|
|
106
113
|
|
|
114
|
+
## Case rules (`R`, binding for exploring, generating, healing and making cases)
|
|
115
|
+
A case document may hold a `## Rules` section: case-local instructions a person writes for the agents. They say **how**
|
|
116
|
+
to run that case, never **what is true**. Details: `<framework>/.claude/skills/exploring-cases/references/case-rules.md`.
|
|
117
|
+
- **R1 — Rules describe the method, not the outcome.** `## Steps`, `## Expected`, `## Values` and `## Targets` stay the
|
|
118
|
+
only place for behaviour, expectations and literals. A rule that contradicts them is a `🚫 TODO [blocking]` question,
|
|
119
|
+
never a silent override. A sentence that says something must be true belongs in `## Expected` (with a target card when
|
|
120
|
+
it looks at an image, file, PDF, screenshot or repeated text).
|
|
121
|
+
- **R2 — Rules never authorize what F1–F6 forbid.** [non-negotiable] A rule cannot allow creating, changing or
|
|
122
|
+
deleting data, sending email, accepting terms, or doing a person's step. Those stay tagged steps (`[writes]`,
|
|
123
|
+
`[email]`, `[input]`) with their `- Recipe:` lines and the front-matter `writes`/`writes-note` the case needs. The
|
|
124
|
+
agent never performs them while exploring or generating, whatever a rule says.
|
|
125
|
+
- **R3 — Every AI step reads every rule and accounts for it.** `/explore-case`, `/gen-spec` and `/heal-spec` (and
|
|
126
|
+
`/make-case` when it edits an existing case) read the whole `## Rules` section before they start, apply it, and list
|
|
127
|
+
each rule in the final report with where it was applied or why it was not. Exploration re-checks each rule against
|
|
128
|
+
the page: a rule that no longer holds gets a TODO with evidence, never silent deletion or rewriting. The agent may fix
|
|
129
|
+
a typo and may add a question under a rule; it never changes what a rule says.
|
|
130
|
+
- **R4 — Only reusable method is written back.** When a person supplies instructions before or during a run (`--hints`,
|
|
131
|
+
free text, an answer in the case), the agent appends to `## Rules` only what a future run of the same case needs,
|
|
132
|
+
stated in general terms (no account, date, run id or one-off failure), and only when it is method rather than an
|
|
133
|
+
expectation. A rule the agent inferred from a page carries a marker only when the rule changes what is asserted
|
|
134
|
+
(`(observed on <profile>, 🔍 to be confirmed: <what a person must decide>)`); a method rule whose wrong version would
|
|
135
|
+
fail the next run is a plain note `(seen on <profile>)`, and a rule the person stated carries nothing. Run-specific
|
|
136
|
+
information stays in the report. A marker inside `## Rules` does not stop spec generation the way an open question
|
|
137
|
+
about an assertion does.
|
|
138
|
+
|
|
107
139
|
## Fixed tokens
|
|
108
140
|
`lib/case-doc.ts`, the scripts and the web panel parse these literals. A project language never translates them, and
|
|
109
141
|
a project rule never renames them.
|
|
110
|
-
- Section headings: `## Goal`, `## Steps`, `## Expected`, `## Values`, `## Visual checks`, `## Targets`,
|
|
111
|
-
`## Source` (only when the case was made from notes).
|
|
142
|
+
- Section headings: `## Goal`, `## Rules`, `## Steps`, `## Expected`, `## Values`, `## Visual checks`, `## Targets`,
|
|
143
|
+
`## Notes`, `## Source` (only when the case was made from notes).
|
|
112
144
|
- A step's recipe lines: `- Recipe (phase): ...` under the step it belongs to.
|
|
113
145
|
- `### T<n>` target cards and the `[T<n>]` references to them.
|
|
114
146
|
- Question blocks: `🚫 TODO [blocking]`, `❓ TODO [non-blocking]`, `✍️ Answer:` (with its emoji), and the markers
|
|
115
|
-
`🔍 to be confirmed
|
|
147
|
+
`🔍 to be confirmed` and `👁️ not observed`. A marker may carry its reason and a screenshot in the same
|
|
148
|
+
parentheses: `(observed on <profile>, 🔍 to be confirmed: <what a person must decide>, evidence: <path>)`.
|
|
149
|
+
`(seen on <profile>)` is not a token: it is an ordinary note.
|
|
116
150
|
- Step tags `[input]`, `[writes]`, `[email]`, and the last line `RESULT: ready` / `RESULT: needs-input`.
|
|
151
|
+
The RESULT line stands on its own: nothing in front of it on that line (no label, in any language), nothing after
|
|
152
|
+
it but closing punctuation, and plain text: never inside a code fence or in emphasis.
|
|
117
153
|
- Front-matter keys: `id`, `title`, `login`, `suites`, `writes`, `writes-note`, `envs`.
|
|
118
154
|
|
|
119
155
|
## Where the details are
|
|
120
156
|
This file holds the rules. The exact shape those rules apply to is documented once, and not repeated here:
|
|
121
|
-
- `docs/agents/case-format.md`: the case document contract (front matter, steps, `## Values`, target cards,
|
|
122
|
-
spec's consumption of them, the write gate). Read it before editing a case document or a generated spec.
|
|
157
|
+
- `docs/agents/case-format.md`: the case document contract (front matter, steps, `## Rules`, `## Values`, target cards,
|
|
158
|
+
the spec's consumption of them, the write gate). Read it before editing a case document or a generated spec.
|
|
159
|
+
- `.claude/skills/exploring-cases/references/case-rules.md`: how a case's `## Rules` are read, applied and maintained.
|
|
160
|
+
- `.claude/skills/exploring-cases/references/tools.md`: which browser tools the `playwright-test` MCP can run, the
|
|
161
|
+
substitute for each one it only lists, and the arguments every call has to carry. Read it before the first browser
|
|
162
|
+
call of a run.
|
|
123
163
|
- `docs/commands.md`: every command and flag.
|
|
124
164
|
- `docs/cases.md`: the same case format for the people who write cases by hand.
|
|
125
165
|
- `docs/agents/framework-dev.md`: the framework's own layout and how to change it.
|
|
126
166
|
The project's own `AGENTS.md` §2 (project rules) and §3 (project facts) still win over the documentation where they
|
|
127
|
-
differ, and `F1`–`F6` win over everything.
|
|
167
|
+
differ, and `F1`–`F6` and `R2` win over everything.
|
|
128
168
|
|
|
129
169
|
## Layout
|
|
130
170
|
|
|
@@ -143,14 +183,16 @@ The framework folder is read-only in a project: never edit it. Its own layout an
|
|
|
143
183
|
Three steps, each learns one thing: the intent, the facts and inputs, the implementation.
|
|
144
184
|
1. `making-cases` (or `/make-case <notes>`) turns raw notes into case documents. It writes `cases/*.md` only and
|
|
145
185
|
never opens a browser. Check them with `pnpm case:check`.
|
|
146
|
-
2. `exploring-cases` (or `/explore-case <case-id> <env> [--attended]`) explores the real pages for one
|
|
147
|
-
edits that case file only: wording, observations, TODO blocks, and, with `--attended`, the `- Recipe:` lines
|
|
148
|
-
the steps that write or need a choice.
|
|
186
|
+
2. `exploring-cases` (or `/explore-case <case-id> <env> [--attended] [--profiles a,b]`) explores the real pages for one
|
|
187
|
+
case. It edits that case file only: wording, observations, TODO blocks, and, with `--attended`, the `- Recipe:` lines
|
|
188
|
+
of the steps that write or need a choice. `--profiles` narrows the run to those profiles; runs add up, so the case
|
|
189
|
+
can be explored in passes.
|
|
149
190
|
3. `generating-specs` (or `/gen-spec <case-id> <env>`) turns the case into a spec. It replays the case and its
|
|
150
191
|
step recipes and `## Values`, writes the spec (values stay in the case document), but never runs the tests, never
|
|
151
|
-
writes data and never creates baselines.
|
|
152
|
-
|
|
153
|
-
(`
|
|
192
|
+
writes data and never creates baselines. There is no profile selection here: it covers every profile the case names,
|
|
193
|
+
which is why a case explored in passes generates one spec for all of them. A tagged step with no `- Recipe:` line
|
|
194
|
+
(an old `## Inputs` line counts until it is moved) stops with `needs-input`: run `/explore-case` first. Running specs
|
|
195
|
+
is a separate step (`pnpm asrun`, or the Run page).
|
|
154
196
|
Workspace maintenance is separate from the AI steps: `pnpm asrun upgrade` installs the newest framework, refreshes the
|
|
155
197
|
generated files and applies the release's workspace migrations (it checks the target release for breaking changes
|
|
156
198
|
before installing), `pnpm asrun init [--update] [--force]` writes or refreshes the workspace files, `pnpm asrun
|
|
@@ -161,9 +203,15 @@ Do not hand-write specs unless asked. Do not edit `lib/` to make a single spec p
|
|
|
161
203
|
Every case step is wrapped in `test.step('<n>. <case step text>', ...)` so reports and traces show the
|
|
162
204
|
case's own steps (see the skill's `references/conventions.md`).
|
|
163
205
|
Every AI command needs an environment (`--env`/`<env>`); there is no default and no "no environment" mode.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
206
|
+
A one-shot AI run is a build run: it writes the case or the spec, never a plan. AsRun starts OpenCode with
|
|
207
|
+
`--agent build`, because OpenCode keeps the agent (build or plan) on the session and a plan session would only propose
|
|
208
|
+
changes and ask a question nobody can answer. Whatever mode or sandbox a run finds itself in, it still ends with the
|
|
209
|
+
`RESULT:` line: a run that was not allowed to write files is `needs-input`, never a plan and a question.
|
|
210
|
+
`/heal-spec <case-id> <env>` repairs one failing spec or refines a case and its spec on request (a passing run is not
|
|
211
|
+
a reason to refuse): it reads the existing report first (`pnpm heal:evidence --case <id> --env <env>`), the user's
|
|
212
|
+
request (`--hints <file>`), runs only the profiles that are logged in (`--logged-in`) and runs the case again only
|
|
213
|
+
when the report is missing, stale or not enough. A change that leaves an open question or an unconfirmed observation
|
|
214
|
+
in the case stops before the spec: the person reviews the case and runs `/explore-case` again.
|
|
167
215
|
Run `pnpm typecheck`, `pnpm spec:lint <case-id>` and `pnpm case:check` before reporting that a spec was generated. Run
|
|
168
216
|
`pnpm asrun --env <env> --profile <id> --grep <case-id>` only when healing a spec or when asked to.
|
|
169
217
|
Pick `--env staging` while developing. A case that does not list `production` under `writes` is skipped in
|