@asrunjs/asrun 0.2.0 → 0.5.3
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 +18 -15
- package/.claude/commands/gen-spec.md +16 -13
- package/.claude/commands/heal-spec.md +26 -23
- package/.claude/commands/make-case.md +11 -8
- package/.claude/skills/exploring-cases/SKILL.md +146 -132
- package/.claude/skills/exploring-cases/references/open-questions.md +116 -112
- package/.claude/skills/exploring-cases/references/readiness.md +146 -137
- package/.claude/skills/exploring-cases/references/user-handoff.md +157 -147
- package/.claude/skills/generating-specs/SKILL.md +219 -207
- package/.claude/skills/generating-specs/references/conventions.md +148 -148
- package/.claude/skills/making-cases/SKILL.md +72 -64
- package/.claude/skills/making-cases/references/normalizing.md +39 -38
- package/.claude/skills/making-cases/references/writes-and-email.md +37 -36
- package/AGENTS.md +169 -154
- package/CLAUDE.md +2 -1
- package/README.md +221 -410
- package/dist/lib/build-artifacts.d.ts +8 -0
- package/dist/lib/build-artifacts.js +10 -0
- package/dist/lib/case-doc.d.ts +311 -0
- package/dist/lib/case-doc.js +1117 -0
- package/dist/lib/cases.d.ts +2 -15
- package/dist/lib/cases.js +5 -78
- package/dist/lib/command.d.ts +24 -0
- package/dist/lib/command.js +90 -0
- package/dist/lib/fixtures.js +2 -2
- package/dist/lib/login-card.d.ts +22 -0
- package/dist/lib/login-card.js +183 -0
- package/dist/lib/node-cli.d.ts +6 -2
- package/dist/lib/node-cli.js +16 -6
- package/dist/lib/profiles.d.ts +25 -1
- package/dist/lib/profiles.js +54 -1
- package/dist/lib/run-filters.js +10 -2
- package/dist/lib/session.d.ts +13 -1
- package/dist/lib/session.js +73 -7
- package/dist/lib/targets.d.ts +5 -13
- package/dist/lib/targets.js +4 -29
- package/dist/lib/values.js +2 -2
- package/dist/scripts/build.js +2 -1
- package/dist/scripts/check-cases.js +74 -6
- package/dist/scripts/doctor.js +115 -4
- package/dist/scripts/explore.js +22 -1
- package/dist/scripts/go.mjs +188 -188
- package/dist/scripts/init.d.ts +7 -1
- package/dist/scripts/init.js +62 -14
- package/dist/scripts/lint-specs.js +4 -1
- package/dist/scripts/login.js +30 -2
- package/dist/ui/server/actions.d.ts +4 -0
- package/dist/ui/server/actions.js +25 -12
- package/dist/ui/server/ai-models.d.ts +3 -0
- package/dist/ui/server/ai-models.js +347 -0
- package/dist/ui/server/ai-stream.d.ts +34 -9
- package/dist/ui/server/ai-stream.js +283 -77
- package/dist/ui/server/app.js +74 -12
- package/dist/ui/server/jobs.d.ts +7 -1
- package/dist/ui/server/jobs.js +69 -15
- package/dist/ui/server/profiles.d.ts +20 -1
- package/dist/ui/server/profiles.js +214 -38
- package/dist/ui/shared/ai-commands.d.ts +16 -6
- package/dist/ui/shared/ai-commands.js +35 -12
- package/dist/ui/shared/types.d.ts +114 -0
- package/docs/agents/case-format.md +193 -0
- package/docs/agents/framework-dev.md +167 -0
- package/docs/ai-workflow.md +235 -0
- package/docs/cases.md +189 -0
- package/docs/commands.md +175 -0
- package/docs/install.md +174 -0
- package/docs/profiles.md +139 -0
- package/docs/theme-guide.html +922 -692
- package/docs/troubleshooting.md +101 -0
- package/docs/web-ui.md +139 -0
- package/package.json +20 -1
- package/templates/.claude/commands/explore-case.md +22 -21
- package/templates/.claude/commands/gen-spec.md +21 -20
- package/templates/.claude/commands/heal-spec.md +31 -30
- package/templates/.claude/commands/make-case.md +13 -12
- package/templates/.mcp.json +8 -8
- package/templates/AGENTS.md +66 -45
- package/templates/cases/_template.md +57 -63
- package/templates/opencode.jsonc +16 -11
- package/templates/profiles.yaml +42 -29
- package/ui/dist/assets/{dist-D_I45xgJ.js → dist-BudNAjOv.js} +1 -1
- package/ui/dist/assets/{dist-CBV7_vDN.js → dist-C-eCSFja.js} +1 -1
- package/ui/dist/assets/{dist-gF2bFn-5.js → dist-CO4heSzh.js} +1 -1
- package/ui/dist/assets/{dist-DX8knLVr.js → dist-CPLhRzom.js} +1 -1
- package/ui/dist/assets/{dist-BqAROxzI.js → dist-DEPJZ3Me.js} +1 -1
- package/ui/dist/assets/{dist-BwYRbe5s.js → dist-DZ7RiqmA.js} +1 -1
- package/ui/dist/assets/{dist-BHaIOZdW.js → dist-LixzGniF.js} +1 -1
- package/ui/dist/assets/{dist-DHCY9KpV.js → dist-O_RVi4tP.js} +1 -1
- package/ui/dist/assets/{dist-BiE4suo9.js → dist-jPS6HCJ5.js} +1 -1
- package/ui/dist/assets/{dist-BSJMM_jp.js → dist-vmf3fnkM.js} +1 -1
- package/ui/dist/assets/index-BIGt8Hfz.js +338 -0
- package/ui/dist/assets/index-CTmnF0Wp.css +2 -0
- package/ui/dist/help/ai-tools.png +0 -0
- package/ui/dist/help/case-explore.png +0 -0
- package/ui/dist/help/case-generate.png +0 -0
- package/ui/dist/help/cases-memo.png +0 -0
- package/ui/dist/help/profile-form.png +0 -0
- package/ui/dist/help/profiles-login.png +0 -0
- package/ui/dist/help/reports.png +0 -0
- package/ui/dist/help/run-tests.png +0 -0
- package/ui/dist/index.html +22 -16
- package/ui/dist/assets/index-DmasQ6Rq.css +0 -2
- package/ui/dist/assets/index-I7uU93kk.js +0 -294
|
@@ -1,147 +1,157 @@
|
|
|
1
|
-
# User handoff: a person works in the browser, the agent waits
|
|
2
|
-
|
|
3
|
-
Used by `exploring-cases` (and by `making-cases` never: it does not open a browser). `generating-specs` never hands
|
|
4
|
-
off; it replays the
|
|
5
|
-
|
|
6
|
-
## The rule
|
|
7
|
-
**An agent never writes data.** Not in staging, not in production. Every step that creates, edits, publishes, shares,
|
|
8
|
-
deletes or otherwise changes data, and every step that needs a human's choice (an existing document, items, a contact
|
|
9
|
-
name), is done by the user in the browser window that Playwright opened. Writing is rare (only while preparing a
|
|
10
|
-
case) and a person succeeds where an agent guesses. The agent drives only what is read-only: open, look, read,
|
|
11
|
-
hover, switch tabs, open and close dialogs and menus.
|
|
12
|
-
|
|
13
|
-
The runtime permission is a different thing and stays as it is: `writes: [<env>, ...]` in the case front matter says
|
|
14
|
-
where the finished spec may write, and a human confirms a run in any environment except staging.
|
|
15
|
-
|
|
16
|
-
## When a handoff happens
|
|
17
|
-
Only in an attended run (`--attended`, a person is at the machine, the browser window is visible). A step is a
|
|
18
|
-
handoff when it is marked `[input]` or `[writes]` in the case, or when the agent finds out while exploring that the
|
|
19
|
-
next action would write data or needs a choice.
|
|
20
|
-
|
|
21
|
-
Without `--attended` the agent does not wait. It writes a `TODO [blocking]` under that step ("a person has to
|
|
22
|
-
perform this step; run /explore-case with --attended") and goes on with the rest. Never wait for a person in a run
|
|
23
|
-
that nobody watches.
|
|
24
|
-
|
|
25
|
-
## Before the handoff
|
|
26
|
-
1. Say what the user has to do and when it is finished, in one or two sentences ("Fill in the form, pick two
|
|
27
|
-
items, then press Done"). Name the finish condition first (below).
|
|
28
|
-
2. Put every text the user has to type into `copy` (the `[asrun] ...` name of a document, a title), so it can be
|
|
29
|
-
copied with one click.
|
|
30
|
-
3. Never ask the user to send email (production: never; other environments: only when `email` is `true` for the
|
|
31
|
-
profile). Never ask for login or 2FA. Name everything the user creates `[asrun] <something>`.
|
|
32
|
-
4. Start recording with `browser_start_recording` (see "Recording").
|
|
33
|
-
|
|
34
|
-
## The wait loop
|
|
35
|
-
Run it with one `browser_run_code_unsafe` call. A single call may wait for minutes (verified: 150 s without a
|
|
36
|
-
timeout), so no polling from outside is needed. The loop:
|
|
37
|
-
|
|
38
|
-
- **Shows a small floating card, not a bar.** It sits in the bottom-left corner and only the card takes clicks, so
|
|
39
|
-
nothing of the page is covered or blocked. The user can **drag** it by its title bar and **minimize** it to a small
|
|
40
|
-
pill that still has a Done button. Position and minimized state survive a page reload (kept in `sessionStorage`).
|
|
41
|
-
- **Click to copy.** Every text in `copy` (for example the `[asrun] ...` name the user has to type) is shown on its
|
|
42
|
-
own line with a copy icon; one click puts it on the clipboard and the icon shows "Copied". Pass only text that the
|
|
43
|
-
case says to type; leave `copy` empty when there is none.
|
|
44
|
-
- **Resets the flag first**: `window.__handoff = null` on every page it paints. A flag left over from an earlier
|
|
45
|
-
handoff ends the wait at once.
|
|
46
|
-
- **Paints the card on every open tab** and repaints after navigation (a new page has no card). The document
|
|
47
|
-
editor opens in a new tab, so the loop looks at `context.pages()`, not only at the first page.
|
|
48
|
-
- **Stops** when one of these happens, whichever is first: the user presses Done or "Cannot do this" on the card
|
|
49
|
-
(`window.__handoff` is `'done'` or `'skip'`), or the finish condition holds, or the time is up (default 10 minutes).
|
|
50
|
-
- **Ends visibly**: the card turns green and says control is back for two seconds, then it is removed, and the tab
|
|
51
|
-
titles are restored.
|
|
52
|
-
- The card lives in a Shadow DOM (the site's CSS cannot change it), does not take keyboard focus (the user can keep
|
|
53
|
-
typing in the page) and works even when the page locks all clicks behind a modal. The icons are inline SVG because
|
|
54
|
-
the card is injected into the page under test; the web UI's react-feather rule does not apply to it.
|
|
55
|
-
|
|
56
|
-
**Never write this code yourself and never shorten it.** It lives in `references/handoff-card.js` (next to this
|
|
57
|
-
file) and a rewritten, simplified card has already gone wrong once: it had no drag handle, no minimize button and
|
|
58
|
-
no copy icon.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
a
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
-
|
|
146
|
-
-
|
|
147
|
-
|
|
1
|
+
# User handoff: a person works in the browser, the agent waits
|
|
2
|
+
|
|
3
|
+
Used by `exploring-cases` (and by `making-cases` never: it does not open a browser). `generating-specs` never hands
|
|
4
|
+
off; it replays the step recipes that an exploration recorded.
|
|
5
|
+
|
|
6
|
+
## The rule
|
|
7
|
+
**An agent never writes data.** Not in staging, not in production. Every step that creates, edits, publishes, shares,
|
|
8
|
+
deletes or otherwise changes data, and every step that needs a human's choice (an existing document, items, a contact
|
|
9
|
+
name), is done by the user in the browser window that Playwright opened. Writing is rare (only while preparing a
|
|
10
|
+
case) and a person succeeds where an agent guesses. The agent drives only what is read-only: open, look, read,
|
|
11
|
+
hover, switch tabs, open and close dialogs and menus.
|
|
12
|
+
|
|
13
|
+
The runtime permission is a different thing and stays as it is: `writes: [<env>, ...]` in the case front matter says
|
|
14
|
+
where the finished spec may write, and a human confirms a run in any environment except staging.
|
|
15
|
+
|
|
16
|
+
## When a handoff happens
|
|
17
|
+
Only in an attended run (`--attended`, a person is at the machine, the browser window is visible). A step is a
|
|
18
|
+
handoff when it is marked `[input]` or `[writes]` in the case, or when the agent finds out while exploring that the
|
|
19
|
+
next action would write data or needs a choice.
|
|
20
|
+
|
|
21
|
+
Without `--attended` the agent does not wait. It writes a `TODO [blocking]` under that step ("a person has to
|
|
22
|
+
perform this step; run /explore-case with --attended") and goes on with the rest. Never wait for a person in a run
|
|
23
|
+
that nobody watches.
|
|
24
|
+
|
|
25
|
+
## Before the handoff
|
|
26
|
+
1. Say what the user has to do and when it is finished, in one or two sentences ("Fill in the form, pick two
|
|
27
|
+
items, then press Done"). Name the finish condition first (below).
|
|
28
|
+
2. Put every text the user has to type into `copy` (the `[asrun] ...` name of a document, a title), so it can be
|
|
29
|
+
copied with one click.
|
|
30
|
+
3. Never ask the user to send email (production: never; other environments: only when `email` is `true` for the
|
|
31
|
+
profile). Never ask for login or 2FA. Name everything the user creates `[asrun] <something>`.
|
|
32
|
+
4. Start recording with `browser_start_recording` (see "Recording").
|
|
33
|
+
|
|
34
|
+
## The wait loop
|
|
35
|
+
Run it with one `browser_run_code_unsafe` call. A single call may wait for minutes (verified: 150 s without a
|
|
36
|
+
timeout), so no polling from outside is needed. The loop:
|
|
37
|
+
|
|
38
|
+
- **Shows a small floating card, not a bar.** It sits in the bottom-left corner and only the card takes clicks, so
|
|
39
|
+
nothing of the page is covered or blocked. The user can **drag** it by its title bar and **minimize** it to a small
|
|
40
|
+
pill that still has a Done button. Position and minimized state survive a page reload (kept in `sessionStorage`).
|
|
41
|
+
- **Click to copy.** Every text in `copy` (for example the `[asrun] ...` name the user has to type) is shown on its
|
|
42
|
+
own line with a copy icon; one click puts it on the clipboard and the icon shows "Copied". Pass only text that the
|
|
43
|
+
case says to type; leave `copy` empty when there is none.
|
|
44
|
+
- **Resets the flag first**: `window.__handoff = null` on every page it paints. A flag left over from an earlier
|
|
45
|
+
handoff ends the wait at once.
|
|
46
|
+
- **Paints the card on every open tab** and repaints after navigation (a new page has no card). The document
|
|
47
|
+
editor opens in a new tab, so the loop looks at `context.pages()`, not only at the first page.
|
|
48
|
+
- **Stops** when one of these happens, whichever is first: the user presses Done or "Cannot do this" on the card
|
|
49
|
+
(`window.__handoff` is `'done'` or `'skip'`), or the finish condition holds, or the time is up (default 10 minutes).
|
|
50
|
+
- **Ends visibly**: the card turns green and says control is back for two seconds, then it is removed, and the tab
|
|
51
|
+
titles are restored.
|
|
52
|
+
- The card lives in a Shadow DOM (the site's CSS cannot change it), does not take keyboard focus (the user can keep
|
|
53
|
+
typing in the page) and works even when the page locks all clicks behind a modal. The icons are inline SVG because
|
|
54
|
+
the card is injected into the page under test; the web UI's react-feather rule does not apply to it.
|
|
55
|
+
|
|
56
|
+
**Never write this code yourself and never shorten it.** It lives in `references/handoff-card.js` (next to this
|
|
57
|
+
file) and a rewritten, simplified card has already gone wrong once: it had no drag handle, no minimize button and
|
|
58
|
+
no copy icon. Load that file in two calls:
|
|
59
|
+
|
|
60
|
+
**Two calls, every time.** Set the options with their own call and only then run the card, for every handoff,
|
|
61
|
+
including a second one later in the same run. Never reuse the options of an earlier handoff and never change them
|
|
62
|
+
inside the call that runs the card: OpenCode reports a tool call only when it ends, so the options call is the only
|
|
63
|
+
way the web UI can see that a person is needed while the card waits. With the card alone there is no "Your turn"
|
|
64
|
+
badge, no count in the tab title and no notification (a HINT in the job log says so).
|
|
65
|
+
|
|
66
|
+
1. Set the options on the browser context (this call only sets data):
|
|
67
|
+
```js
|
|
68
|
+
async (page) => {
|
|
69
|
+
page.context().__handoffCfg = {
|
|
70
|
+
message: '<what the user does, one sentence>',
|
|
71
|
+
copy: [], // texts to type, e.g. ['[asrun] published document']
|
|
72
|
+
doneText: null, // text that appears when finished, or null
|
|
73
|
+
maxMs: 600000,
|
|
74
|
+
};
|
|
75
|
+
return 'cfg set';
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
2. Run the card and wait: `browser_run_code_unsafe` with `filename` set to the absolute path of
|
|
79
|
+
`<framework>/.claude/skills/exploring-cases/references/handoff-card.js` (use the absolute path of the repository, a
|
|
80
|
+
relative one is resolved against the workspace root, which may be the parent folder). It returns `{outcome: 'done' | 'skip' | 'condition' | 'timeout', waitedMs}`.
|
|
81
|
+
|
|
82
|
+
Check once, after the card shows, that it looks right: take a screenshot and see a title bar with a move icon, a
|
|
83
|
+
chevron button at its right and, when `copy` is not empty, a line per text with a copy icon. If not, stop and report
|
|
84
|
+
it; do not hand off with a broken card.
|
|
85
|
+
|
|
86
|
+
Tell the user in the chat (the terminal or the UI job log) as well: "Your turn in the browser window: <task>. Press
|
|
87
|
+
Done on the card (bottom-left; drag it if it is in the way) when you finish." When the run was started from the web
|
|
88
|
+
UI, the UI notices the handoff by itself (it sees the `__handoffCfg` call and the `handoff-card.js` call, whether the
|
|
89
|
+
browser tool is called directly or through the CLI's code mode, as OpenCode's `execute` tool does) and shows the
|
|
90
|
+
"Your turn" badge, a count in the tab title and, if the person switched notifications on, a browser notification;
|
|
91
|
+
this is why the message in `__handoffCfg` must be a plain string literal. A macOS notification is a bonus and may
|
|
92
|
+
fail in a sandbox: `osascript -e 'display notification "<task>" with title "AsRun" sound name "Glass"'`. If it
|
|
93
|
+
fails, go on.
|
|
94
|
+
|
|
95
|
+
## Finish condition
|
|
96
|
+
Pick one that the page can show, before the handoff, and write it into the message of the card:
|
|
97
|
+
- a text that appears (a "Saved" toast, the title of the next step) or one that goes away;
|
|
98
|
+
- a URL that the page reaches;
|
|
99
|
+
- an element that appears or disappears (an editor that closes).
|
|
100
|
+
|
|
101
|
+
The Done button is always there (also on the minimized card) as the fallback, and "Cannot do this" lets the user give up a step.
|
|
102
|
+
|
|
103
|
+
## After the handoff
|
|
104
|
+
- The card turns green and says control is back ("Done: control is back with Playwright. Do not touch the page.")
|
|
105
|
+
for two seconds before it is removed, so the user knows when they may let go.
|
|
106
|
+
- `outcome: 'timeout'` or `'skip'`: do not guess. Write a `TODO [blocking]` under the step and go on with what does
|
|
107
|
+
not depend on it.
|
|
108
|
+
- Take a snapshot and write down what the user did (see "Recording"), then continue read-only.
|
|
109
|
+
- At the end of the exploration hand off once more when the user created data: "Delete the [asrun] items you
|
|
110
|
+
created, then press Done". The case must clean up after itself, and so must the exploration.
|
|
111
|
+
|
|
112
|
+
## Recording
|
|
113
|
+
Between the start and the end of a handoff the agent records what the user does (`browser_start_recording`,
|
|
114
|
+
`browser_stop_recording`). The recorded Playwright code is **raw material, never saved as it is**. It is turned into
|
|
115
|
+
a general recipe and written under the step as `- Recipe (phase): ...` lines (format below). The recipe holds what the
|
|
116
|
+
user did in words, plus the **labels and roles of the controls** they used ("the textbox 'Title'", "the button
|
|
117
|
+
'Next'"), because `/gen-spec` cannot write data and so cannot see those controls itself. It never holds selectors,
|
|
118
|
+
ids or the names of data that can change.
|
|
119
|
+
|
|
120
|
+
Make the recipe as general as possible, because lists and data change:
|
|
121
|
+
- **A choice from a list that can change** (items, search results, a contact list): record the position, never the
|
|
122
|
+
name or id. "Select items #1 to #3 from the list."
|
|
123
|
+
- **Random is allowed only when the user asks for it** ("pick any 3"). The default is the position, because it can be
|
|
124
|
+
repeated. A random pick must be written into the test's annotations when the spec runs.
|
|
125
|
+
- **Text the case creates**: `[asrun] <something>`.
|
|
126
|
+
- **A value that has to exist** (an existing name, a search term): write what it must be like ("a name that
|
|
127
|
+
returns a result") and the observed value as `(observed "<value>", 🔍 to be confirmed by QA)` plus a
|
|
128
|
+
`[non-blocking]` TODO block. Do not put a brittle literal in as the only truth.
|
|
129
|
+
- **Nothing that depends on the pick** may become an assertion (a total changes with the items). Say so in a
|
|
130
|
+
TODO when a check would.
|
|
131
|
+
- Settings that the user changed on purpose (a toggle, a template) are recorded as they were set, by label.
|
|
132
|
+
|
|
133
|
+
If the recording tool fails or returns nothing, describe what the user did from before/after snapshots instead.
|
|
134
|
+
|
|
135
|
+
## Recipe lines under a step
|
|
136
|
+
One or more `- Recipe (phase): ...` lines directly under the `[input]` or `[writes]` step they belong to, indented by
|
|
137
|
+
four spaces. The phase is optional (`start`, `items`, `finish`, ...). The step is the key; there is no step number to
|
|
138
|
+
keep in sync.
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
3. Select an existing document and pick 3 items. [input]
|
|
142
|
+
- Recipe (start): search for an existing document and pick result #1 (observed search term "...", 🔍 to be confirmed by QA).
|
|
143
|
+
- ❓ TODO [non-blocking]: Is any result that opens fine as the starting point? (seen on example-staging)
|
|
144
|
+
- ✍️ Answer:
|
|
145
|
+
- Recipe (items): select 3 items by position (#1 to #3) from the list.
|
|
146
|
+
- Recipe (finish): press "Next" until the "Publish" button shows, then publish.
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
A step that is marked `[input]` or `[writes]` and has no `- Recipe:` line has never been explored. `generating-specs`
|
|
150
|
+
stops on it, and `pnpm case:check` warns about it.
|
|
151
|
+
|
|
152
|
+
## Hard rules
|
|
153
|
+
- Never write data yourself, never press a button that writes. In production the same, with no exception.
|
|
154
|
+
- Never wait in an unattended run.
|
|
155
|
+
- Never ask a person to log in, pass 2FA or send email through the handoff.
|
|
156
|
+
- Never save selectors, ids or the names of changing data into a case. Control labels and roles are fine.
|
|
157
|
+
- Never read or print anything under `.auth/`.
|