task-pipeline-skill 1.55.0 → 1.57.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/CHANGELOG.md +215 -0
- package/CONTRIBUTING.md +26 -0
- package/README.md +3 -2
- package/SKILL-CARD.md +1 -1
- package/package.json +1 -1
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +5 -4
- package/plugins/task-pipeline/skills/task-pipeline/pipeline.example.json +2 -2
- package/plugins/task-pipeline/skills/task-pipeline/references/browser.md +278 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/build.md +48 -2
- package/plugins/task-pipeline/skills/task-pipeline/references/planning.md +64 -9
- package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +19 -6
- package/plugins/task-pipeline/skills/task-pipeline/references/tdd.md +7 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,220 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.57.0 — an arrow that carries nothing is not an arrow, and two green diffs can still contradict each other
|
|
4
|
+
|
|
5
|
+
The pipeline has drawn a dependency graph at stage 4 since it had a stage 4, and grouped
|
|
6
|
+
tasks topologically off it. What it never said was how to tell a **real** edge from one
|
|
7
|
+
that only records the order somebody typed the tasks in. The self-review asked the right
|
|
8
|
+
question in a checklist line — *does this `depends:` point at a task that really produces
|
|
9
|
+
what's consumed* — and no gate read the answer, so a plan could serialise itself entirely
|
|
10
|
+
and pass every check.
|
|
11
|
+
|
|
12
|
+
Audited against *Graph Engineering with Claude*
|
|
13
|
+
(`https://x.com/Mahaximus_/status/2082442856417956173`), findings and both rejections in
|
|
14
|
+
`docs/evidence/specs/2026-08-15-graph-audit.md`. **Nine of the ten macro stage edges carry
|
|
15
|
+
data**, which is the audit's first result and the reason nothing was reordered.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **The fake-edge test, as a numbered procedure** (`references/planning.md`). Six steps
|
|
20
|
+
over the graph you just drew: for each arrow, does output from A actually enter B, and if
|
|
21
|
+
you cannot name what crosses it, delete it. Expect two or three per plan.
|
|
22
|
+
|
|
23
|
+
- **A `Carries` column in the *Execution order* table**, and it is the whole mechanisation:
|
|
24
|
+
a cell you cannot fill **is** the finding. The fake-edge test stops being a thing an agent
|
|
25
|
+
remembers to do and becomes a column a reviewer can see is empty.
|
|
26
|
+
|
|
27
|
+
- **`Edges: <n> declared, <n> carry data, <n> removed`** in the stage-4 self-review, and
|
|
28
|
+
the gate reads it. Computed, like every other line in that block.
|
|
29
|
+
|
|
30
|
+
- **The group convergence check** (`references/build.md` §4.2a). A per-task review reads
|
|
31
|
+
**one diff**; a fanned-out group produces several, and the defect that exists only
|
|
32
|
+
*between* two of them passes both. One check over the group's reports and diffs together,
|
|
33
|
+
after the last task and **before the first worktree is integrated** — the only moment all
|
|
34
|
+
of them exist and none has landed. Five things it looks for, each a real defect invisible
|
|
35
|
+
in a single diff: an empty deliverable, two outputs that cannot both be true, off-brief
|
|
36
|
+
work, one REQ satisfied twice differently, a Global Constraint only one task applied.
|
|
37
|
+
**A clean group logs a line too**, because a check whose silence is indistinguishable from
|
|
38
|
+
not having run is not evidence.
|
|
39
|
+
|
|
40
|
+
- **A statement that this pipeline is a static graph, and why** (`references/planning.md`).
|
|
41
|
+
Auditability: a graph that decides its own shape produces a shape nobody drew, and then
|
|
42
|
+
*"here is the pipeline"* and *"here is what this run did"* stop being the same document.
|
|
43
|
+
The two places the run **does** discover structure — the module map and the carry-over
|
|
44
|
+
ledger — are named, and both land in a committed artifact, which is what separates
|
|
45
|
+
discovery from a dynamic graph.
|
|
46
|
+
|
|
47
|
+
- **A preference for a harness-native fan-out primitive**, on the same reasoning §1 already
|
|
48
|
+
applies to worktrees: the harness owns the concurrency cap, the isolation and the resume.
|
|
49
|
+
Stated **without naming a product** — the keyword for one host's fan-out was renamed six
|
|
50
|
+
weeks after the article documenting it, and doctrine pinned to a vendor's noun rots on
|
|
51
|
+
that schedule.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- **`test/negatives.py` could not restore `.git` in a submodule checkout, so two guards
|
|
56
|
+
silently never fired.** The restore was gated on `os.path.isdir(.git)`. In every checkout
|
|
57
|
+
of this repository **as a submodule** — which is how the `sshlg-skills` umbrella ships it,
|
|
58
|
+
and therefore how most work on it happens — `.git` is a 48-byte file holding a `gitdir:`
|
|
59
|
+
pointer, so the branch was skipped and both git-dependent guards reported `fatal: not a
|
|
60
|
+
git repository` and were counted as *did not fire*. CI clones normally and was green,
|
|
61
|
+
which is why it survived. Measured before: exit `1`, `2 guard(s) did not fire`. After:
|
|
62
|
+
exit `0`, **all 318 guards**, twice consecutively.
|
|
63
|
+
|
|
64
|
+
The copy resolves the `gitdir:` pointer and **copies** the directory rather than pointing
|
|
65
|
+
at it, for two reasons that both bite: a plant that commits would otherwise move the real
|
|
66
|
+
branch, and the module's config carries `core.worktree` aimed back at the live checkout,
|
|
67
|
+
which would make every git command inside the snapshot operate on the tree the snapshot
|
|
68
|
+
exists to protect. That one key is stripped from the copy.
|
|
69
|
+
|
|
70
|
+
- **The fan-out rule was stated with three conditions in `build.md` and one in
|
|
71
|
+
`stages.md`.** The summary kept *own worktree* and dropped *same group* and *exclusive
|
|
72
|
+
file ownership*, so a reader who took the summary as the rule would fan out two tasks that
|
|
73
|
+
share a file, in separate worktrees, and meet the conflict at integration. Both surfaces
|
|
74
|
+
now state all three.
|
|
75
|
+
|
|
76
|
+
- **A property check's plant had gone narrow one column over, and CI is what found it.**
|
|
77
|
+
*The Human column survives a header reorder* rewrites the ledger's header and then swaps
|
|
78
|
+
each row's two last cells — matching on `| <auto> | <human> | — |`, with the `—` a
|
|
79
|
+
literal. Seven rows added by this run carry a finding id in `Note` instead, went
|
|
80
|
+
unmatched, stayed in the old order under a reordered header, and the check reported the
|
|
81
|
+
**doctrine** broken when the **plant** was what had aged. It had already been widened once
|
|
82
|
+
for exactly this reason one column to the left, which is what makes it a class rather than
|
|
83
|
+
an incident: a plant anchored on the CONTENT of a cell describes the table it was written
|
|
84
|
+
against. It now matches any note.
|
|
85
|
+
|
|
86
|
+
Guards: 322 → **339**. Property checks: 9 → 9. Seventeen new plants, because a rule a check
|
|
87
|
+
can decide is written as the check and not as prose somebody remembers: the fake-edge test
|
|
88
|
+
renamed away, the `Carries` column dropped, the stage-4 gate no longer reading it, §4.2a
|
|
89
|
+
deleted outright, §4.2a losing its *before integration*, and `stages.md` dropping the
|
|
90
|
+
convergence check from its stage-5 summary — which is the exact drift F-5 found, now
|
|
91
|
+
guarded in the direction it drifted. The other eleven came from **an independent reviewer
|
|
92
|
+
across five rounds on the PR**, which is the mechanism standing instruction R-005 exists to buy: it found four
|
|
93
|
+
branches of the new guards with no plant behind them, a `_section()` site with no
|
|
94
|
+
`is None` arm (the shape every other site in the file has), a stage-5 guard checking one
|
|
95
|
+
of the three preconditions its own message claims, and an uncached read of a memoised
|
|
96
|
+
document. It also found the two gaps that were not nits — see below. Every plant is
|
|
97
|
+
anchored on a heading or a token, and every one asserts it changed something before the
|
|
98
|
+
validator is asked.
|
|
99
|
+
|
|
100
|
+
**Two of the reviewer's findings were defects, not nits, and both were fixed before
|
|
101
|
+
merge.** First: the convergence check was written into narrative prose and into
|
|
102
|
+
`SKILL.md`'s stage table, and **into neither GATE bullet** — so a fanned-out group could
|
|
103
|
+
reach stage 6 having never run it. `build.md`'s and `stages.md`'s gates now require it,
|
|
104
|
+
and a guard requires the gate to require it. Second: the `.git` restore resolved a
|
|
105
|
+
`gitdir:` pointer by hand, which is right for a submodule and **wrong for a linked
|
|
106
|
+
worktree** — the shape `build.md` itself tells every run to work in, where `objects`,
|
|
107
|
+
`refs` and `config` live wherever `commondir` points. It now asks
|
|
108
|
+
`git rev-parse --git-common-dir`, which answers correctly for all three shapes. A fix that
|
|
109
|
+
covers one of two shapes of the same defect is half a fix.
|
|
110
|
+
|
|
111
|
+
### Not changed, deliberately
|
|
112
|
+
|
|
113
|
+
- **Stage 8 → 9.** The audit's F-4 asked whether docs depend on the post-deploy check or
|
|
114
|
+
only on the version stage 7 produced. Rejected with reasoning rather than left open: a
|
|
115
|
+
single agent session runs serially so removing the edge buys no wall-clock, and a
|
|
116
|
+
post-deploy check can change what stage 9 must write. Weak is not the same as fake.
|
|
117
|
+
- **The stage list, the stage count and every gate type.** Gate *criteria* moved at stage 4
|
|
118
|
+
and stage 5; nothing was renumbered, reordered or retyped.
|
|
119
|
+
|
|
120
|
+
**Released as 1.57.0, not 1.56.0.** This work was branched, reviewed over five rounds and tagged in its own tree while a concurrent session merged a different 1.56.0 — the
|
|
121
|
+
browser-channel release below. Both branches claimed the number; the id register that would have prevented it is declared in `.claude/agent-sync.json` and cannot allocate
|
|
122
|
+
against an `fs` backend, which is the umbrella's open row **B-45**. The same collision took a board id: `B-073` here was renumbered to **B-075**.
|
|
123
|
+
|
|
124
|
+
## v1.56.0 — the stages demanded a look and named no way to take one
|
|
125
|
+
|
|
126
|
+
Since v1.36.0 three stages have required the rendered surface to be checked in a
|
|
127
|
+
browser, and v1.55.0 gave that requirement a second channel. Neither release said
|
|
128
|
+
**how a look is taken**. An agent reading this bundle learned which plugin to install
|
|
129
|
+
and nothing about what to do with it — which is precisely how a run reports *checked in
|
|
130
|
+
a browser* and means *ran the unit tests*.
|
|
131
|
+
|
|
132
|
+
`references/browser.md` is that mechanism, and stages 5, 6 and 8, `tdd.md` and both
|
|
133
|
+
gate rows in `SKILL.md` now point at it.
|
|
134
|
+
|
|
135
|
+
### Added
|
|
136
|
+
|
|
137
|
+
- **The one model both channels share.** A snapshot returns the accessibility tree with
|
|
138
|
+
a **ref** per element, and you act on the ref — not on pixels, not on coordinates. Three
|
|
139
|
+
consequences the doctrine already rested on and had never stated: a look costs a page of
|
|
140
|
+
text and no vision model, a ref is deterministic where a coordinate is not, and **a ref
|
|
141
|
+
that stops resolving is a finding rather than an error to retry past**.
|
|
142
|
+
- **The look as four runnable commands** — `open`, `snapshot`, `console`, `requests` —
|
|
143
|
+
with the MCP and `chrome-devtools` names beside them, because the look is the same look
|
|
144
|
+
and that is why the matrix ranks neither.
|
|
145
|
+
- **Sessions and the daemon.** The browser lives between commands, which is the whole
|
|
146
|
+
reason the four compose; `-s=<session>` isolates, `list` is the evidence the environment
|
|
147
|
+
is clean, `kill-all` is for the zombie left by a crash.
|
|
148
|
+
- **`--json` / `--raw`.** The difference between output a reader reads and output a check
|
|
149
|
+
can gate on. A gate that regexes prose breaks on the release that rewords it.
|
|
150
|
+
- **"Tested in a browser" separated into the three claims it conflates** — the look, the
|
|
151
|
+
spec suite (`playwright test`, the runner) and the **library** (`class Playwright`),
|
|
152
|
+
which is an automation API and not a test framework at all. Choosing the library where a
|
|
153
|
+
runner was wanted is how a project grows a half-runner nobody trusts.
|
|
154
|
+
- **Auth and mocking as solved steps rather than exemptions.** `state-save` / `state-load`
|
|
155
|
+
(`--storage-state` on the MCP) for a surface behind a login — the state file is a
|
|
156
|
+
credential and goes where credentials go; `route` / `route-list` / `unroute` for the
|
|
157
|
+
failure paths a mocked unit test can never show rendering.
|
|
158
|
+
- **The loop that turns a look into a test that keeps it found:** `generate-locator` on
|
|
159
|
+
the element the look caught, then `pause-at` / `step-over` / `resume` to watch the new
|
|
160
|
+
spec see what you saw. A browser finding fixed with no test behind it is a finding
|
|
161
|
+
scheduled to return.
|
|
162
|
+
- **What the channel can reach**, because recommending a real browser is the widest
|
|
163
|
+
capability in the matrix: the MCP confines file access to the workspace roots until
|
|
164
|
+
`--allow-unrestricted-file-access` says otherwise, `--isolated` keeps nothing,
|
|
165
|
+
`--secrets` exists so a password reaches the browser and not the transcript — and
|
|
166
|
+
`--allowed-origins` is **not** a security boundary, which is upstream's own wording.
|
|
167
|
+
|
|
168
|
+
### Measured rather than restated
|
|
169
|
+
|
|
170
|
+
- **The MCP's tool list is capability-gated: 24 tools by default, 42 with
|
|
171
|
+
`--caps vision,pdf,devtools`** — counted by starting the server and calling `tools/list`,
|
|
172
|
+
not read off a page. `browser_start_tracing`, `browser_start_video` and
|
|
173
|
+
`browser_pdf_save` are **absent** from a default server. A doctrine naming them without
|
|
174
|
+
`--caps` sends an agent to a tool that is not there, and the agent concludes the doctrine
|
|
175
|
+
is stale rather than the server narrow. The page current at the time also listed route,
|
|
176
|
+
cookie and localStorage tools this version does not ship at all — which is why the CLI is
|
|
177
|
+
what this file names for state and mocking.
|
|
178
|
+
- Every CLI command and flag in the new file was checked against `playwright-cli --help`
|
|
179
|
+
before it shipped, `--persistent` included, which lives on `open` rather than at the top
|
|
180
|
+
level.
|
|
181
|
+
|
|
182
|
+
### Corrected before merge, by the reader
|
|
183
|
+
|
|
184
|
+
- **`npx playwright-cli --help` — this file's own re-derivation command — did not run.**
|
|
185
|
+
Outside a project that has already installed it, npm resolves the bare `playwright-cli`
|
|
186
|
+
to **somebody else's package**: Microsoft's, deprecated in favour of this one, latest
|
|
187
|
+
`0.262.0` against `@playwright/cli`'s `0.1.18`. The line sat inside the sentence that is
|
|
188
|
+
the whole file's evidentiary warrant. It now says `npx @playwright/cli@latest --help`
|
|
189
|
+
and explains the trap.
|
|
190
|
+
- **`state-save .auth/state.json` fails on a directory that does not exist** — real exit 1,
|
|
191
|
+
`ENOENT`. The recipe gained the `mkdir -p` it always needed.
|
|
192
|
+
- **The prescribed verdict quoted a filtered number as the page's request count.**
|
|
193
|
+
`requests` hides successful static resources by default and says so in its own footer.
|
|
194
|
+
Failures are listed either way, so *no status ≥ 400* survives and *"14 requests"* is
|
|
195
|
+
gone.
|
|
196
|
+
|
|
197
|
+
### Guards
|
|
198
|
+
|
|
199
|
+
Guards: 318 → **322**. Property checks: 9 → 9. Two checks: a stage that asks for a browser
|
|
200
|
+
channel must **link** the mechanism, and the mechanism must keep the whole look in one
|
|
201
|
+
runnable fence inside the section the stages point at.
|
|
202
|
+
|
|
203
|
+
**Both shipped weaker first, and the independent reader `R-005` requires broke both.**
|
|
204
|
+
The pointer check tested the substring `browser.md`, so `<!-- browser.md -->` — invisible
|
|
205
|
+
once rendered — satisfied it while the stage named no reachable mechanism. The recipe
|
|
206
|
+
check searched the whole file, so the four commands could be parked in a fence captioned
|
|
207
|
+
*"the ones this file tells you never to run"*, every needle intact and the recipe deleted;
|
|
208
|
+
it also accepted `open` off an incidental mention in the session table. An earlier draft
|
|
209
|
+
had already been caught by a `\b` that let `console-messages` satisfy `console`, and
|
|
210
|
+
`tdd.md` could drop both its pointers because only `stages.md` was read.
|
|
211
|
+
|
|
212
|
+
**The scope is now written down rather than implied.** An anti-recipe *inside* the right
|
|
213
|
+
section still passes: no text check separates *run these four* from *never run these four*,
|
|
214
|
+
because the difference is the prose. Three drafts were spent proving that; the fourth
|
|
215
|
+
stopped and filed `B-073`. `B-074` carries the other hole the reader found — a stage can
|
|
216
|
+
demand the look while naming no channel, and nothing looks at it.
|
|
217
|
+
|
|
3
218
|
## v1.55.0 — the browser step gets a second channel, and the table that names it stops truncating itself
|
|
4
219
|
|
|
5
220
|
The bundle has told every web project to check the rendered surface since v1.36.0, and
|
package/CONTRIBUTING.md
CHANGED
|
@@ -479,6 +479,32 @@ The two checks share one compiled pattern for that reason — two copies would d
|
|
|
479
479
|
the drift is silent in precisely the direction that hurts.
|
|
480
480
|
*(guard: `pipes where the header has` and `names no stage its second cell`)*
|
|
481
481
|
|
|
482
|
+
**55. A stage that demands a look at the rendered surface LINKS the mechanism, and the
|
|
483
|
+
mechanism keeps the whole look in one runnable block.** From v1.36.0 to v1.55.0 stages 5,
|
|
484
|
+
6 and 8 required the browser and pointed only at which companion to install, so the
|
|
485
|
+
requirement had no *how* anywhere in the bundle — the shape that lets a run report
|
|
486
|
+
*checked in a browser* while meaning *ran the unit tests*. Every stage naming a browser
|
|
487
|
+
channel, and `tdd.md` too, must **link** `references/browser.md`, and that file must keep
|
|
488
|
+
one fenced block showing `open`, `snapshot`, `console` and `requests` together.
|
|
489
|
+
|
|
490
|
+
Both halves are stated that precisely because the first draft of each was weaker and an
|
|
491
|
+
independent reader broke both. The stage check tested the substring `browser.md`, and
|
|
492
|
+
`<!-- browser.md -->` — invisible once rendered — satisfied it. The mechanism check
|
|
493
|
+
searched the whole file, so the four commands could be parked in a fence captioned *"the
|
|
494
|
+
ones this file tells you never to run"* with every needle intact and the recipe deleted;
|
|
495
|
+
it also accepted `open` off an incidental mention in the session table. Requiring *one
|
|
496
|
+
fence with all four* was the second draft and fell to the same reader: a fence captioned
|
|
497
|
+
*"never run these"* holds all four. No text check separates a recipe from an anti-recipe,
|
|
498
|
+
so the check is **scoped to the section** — the recipe must live under *The look, as
|
|
499
|
+
commands you can run*, and renaming that heading fails the build, which is correct: the
|
|
500
|
+
section is the contract. **What it does not claim:** an anti-recipe written inside that
|
|
501
|
+
same section still passes. Three drafts were spent trying to close that with a pattern;
|
|
502
|
+
the fourth wrote the limit down instead (`B-073`), because the difference between *run
|
|
503
|
+
these* and *never run these* is prose, and prose is R-005's job. The move needle allows the `--json`, `--raw` and `-s=` prefixes,
|
|
504
|
+
because this same file recommends them and a check that fails its own advice gets edited
|
|
505
|
+
out rather than satisfied.
|
|
506
|
+
*(guard: `does not LINK references/browser.md` and `has no single fenced block showing the whole`)*
|
|
507
|
+
|
|
482
508
|
**53. Publishing a retro insight is opt-in, enumerated, and its own example obeys its
|
|
483
509
|
own rules.** `retro.publish` is off when absent — opening an issue in another repository
|
|
484
510
|
is an outward act, and a generic flag is not a specific authorization. The redaction
|
package/README.md
CHANGED
|
@@ -68,8 +68,8 @@ Every gate is **typed**: `auto` — the orchestrator verifies it itself, pass/fa
|
|
|
68
68
|
| 1 | Docs study | contracts grounded on current docs | auto |
|
|
69
69
|
| 2 | Brainstorm + decompose | design approved; UI verdict recorded; every REQ answered; platform: module map approved | manual |
|
|
70
70
|
| 3 | Spec | committed + reviewed; UI: super-ux chain validated, linter green | manual |
|
|
71
|
-
| 4 | Plan | parallel-ready, DoD per task | auto |
|
|
72
|
-
| 5 | Dev | tasks DONE (three review verdicts each), TDD green per task | auto |
|
|
71
|
+
| 4 | Plan | parallel-ready, DoD per task; **every edge names what it carries** — an arrow whose payload nobody can fill is a fake edge | auto |
|
|
72
|
+
| 5 | Dev | tasks DONE (three review verdicts each), TDD green per task; **a fanned-out group gets one convergence check over all its diffs together before the first worktree lands** | auto |
|
|
73
73
|
| 6 | Tests | full suite green, new code covered; **on a web front end the surface is checked in a browser, not in the diff** | auto |
|
|
74
74
|
| 7 | Lint + deploy | lint clean + suite green before deploy | manual |
|
|
75
75
|
| 8 | Post-deploy | clean boot / honest degradation, **and the CI verdict read rather than assumed**, and **a deployed web page is opened rather than curled** — a `200` is not a rendered page | auto |
|
|
@@ -131,6 +131,7 @@ until it is installed.
|
|
|
131
131
|
| 4 Plan | [`planning.md`](plugins/task-pipeline/skills/task-pipeline/references/planning.md) — zero-context tasks, parallel groups, no placeholders |
|
|
132
132
|
| 5 Build | [`build.md`](plugins/task-pipeline/skills/task-pipeline/references/build.md) + [`review.md`](plugins/task-pipeline/skills/task-pipeline/references/review.md) — isolation, ledger, subagent loop, review rubric, fix loop |
|
|
133
133
|
| 5–6 TDD | [`tdd.md`](plugins/task-pipeline/skills/task-pipeline/references/tdd.md) — the iron law, red/green/refactor, the suite gate |
|
|
134
|
+
| 5, 6, 8 The browser | [`browser.md`](plugins/task-pipeline/skills/task-pipeline/references/browser.md) — the ref model both channels share, the four commands the look is made of, sessions, and the three different things *"tested in a browser"* means |
|
|
134
135
|
| 10 Acceptance | [`acceptance.md`](plugins/task-pipeline/skills/task-pipeline/references/acceptance.md) — REQ coverage table, evidence rules, the closing question |
|
|
135
136
|
| 10 + any audit | [`audit.md`](plugins/task-pipeline/skills/task-pipeline/references/audit.md) — the L0→L7 ladder and its seams, axis rotation, ratchets, proven checks |
|
|
136
137
|
| any loop | [`loop-guard.md`](plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md) — churn detection, caps, the break protocol |
|
package/SKILL-CARD.md
CHANGED
|
@@ -12,7 +12,7 @@ harmless.
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Purpose** | Runs a substantial task through ten gated delivery stages — intake grill, docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs+registers, acceptance — refusing to advance until each gate passes |
|
|
14
14
|
| **Owner** | ssheleg ([github.com/ssheleg/task-pipeline](https://github.com/ssheleg/task-pipeline)) |
|
|
15
|
-
| **Version** | 1.
|
|
15
|
+
| **Version** | 1.57.0 |
|
|
16
16
|
| **Surface** | Claude Code (filesystem skill + plugin) and the vercel `skills` CLI. **Not** uploaded to the Skills API; custom Skills do not sync across surfaces |
|
|
17
17
|
| **Dependencies** | None required. Optional: `context7` (MCP), `figma` (MCP), super-ux, agent-sync, graphify, obsidian-wiki, and **one of two browser channels** — `playwright` (CLI or MCP) or `chrome-devtools` (MCP); either satisfies the browser step and neither is required. Every stage's doctrine ships in-repo; the one conditional requirement is super-ux for the stage-3 UX track on a user-facing task |
|
|
18
18
|
| **Evaluation status** | Suite authored, 5 categories. One recorded run, **self-observed by the author**; **zero blind runs on zero of three models** — the split, and the numbers, live in [`evals/RESULTS.md`](evals/RESULTS.md) and are computed by `evals/run.py` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-pipeline-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.57.0",
|
|
4
4
|
"description": "Full-cycle delivery pipeline for coding agents: a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine ships inside the skill — no companion plugin required. This package is the installer CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"task-pipeline": "bin/task-pipeline.js"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "task-pipeline",
|
|
3
3
|
"displayName": "Task Pipeline",
|
|
4
4
|
"description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/manual gates, a frozen requirement spine that closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a loop guard whose review ceiling measures rather than stops, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs). Retro insights can publish upstream as issues, opt-in and redacted.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.57.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -60,6 +60,7 @@ gate stops until it is installed.
|
|
|
60
60
|
| 4 Plan | `references/planning.md` |
|
|
61
61
|
| 5 Build (worktree, subagents, fix loop) | `references/build.md` + `references/review.md` |
|
|
62
62
|
| 5–6 TDD + suite gate | `references/tdd.md` |
|
|
63
|
+
| 5, 6, 8 The browser — the look, the spec suite, and the difference | `references/browser.md` |
|
|
63
64
|
| 10 Acceptance (REQ close-out) | `references/acceptance.md` |
|
|
64
65
|
| 10 Retrospective (the run's last act) | `references/retrospective.md` |
|
|
65
66
|
| 10 + any audit (what's *missing*) | `references/audit.md` |
|
|
@@ -251,11 +252,11 @@ capable available — see `references/model-tiering.md`).
|
|
|
251
252
|
| 1 | Docs study | contracts grounded on fetched docs | auto |
|
|
252
253
|
| 2 | Brainstorm + decompose | design approved; UI verdict recorded; every REQ answered; platform: module map approved | manual |
|
|
253
254
|
| 3 | Spec | committed + reviewed; UI: chain validated, linter green, scenarios/`SCR-` traced | manual |
|
|
254
|
-
| 4 | Plan | parallel-ready, DoD per task | auto |
|
|
255
|
-
| 5 | Dev | tasks DONE, TDD green per task, branch integrated per the brief; **anything generated passes its own checks, and local infrastructure does not publish the host's default ports** ([`references/learned.md`](references/learned.md)) | auto |
|
|
256
|
-
| 6 | Tests | full suite green; new/changed code covered; **every new check probed both ways and asserted on its exit code**, and the suite run once against a cold environment ; **on a web front end the surface is checked in a browser, not in the diff** — a green suite cannot see a component that renders under a fixed header, a request that 404s past its mock, or a console error — and a browser **test suite** is the other half of the pair, never a substitute for the look (`playwright` or `chrome-devtools`, either one, [`references/companion-skills.md`](references/companion-skills.md); absent → say *verified by reading the diff* and record it as the weaker claim it is) | auto |
|
|
255
|
+
| 4 | Plan | parallel-ready, DoD per task; **every edge names what it carries** — the fake-edge test run, its `Edges:` count computed, and no arrow left whose payload nobody can name ([`references/planning.md`](references/planning.md)) | auto |
|
|
256
|
+
| 5 | Dev | tasks DONE, TDD green per task, branch integrated per the brief; **a fanned-out group gets one convergence check over all its diffs together before the first worktree lands** — a per-task review cannot see a contradiction that exists only between two of them ([`references/build.md`](references/build.md) §4.2a); **anything generated passes its own checks, and local infrastructure does not publish the host's default ports** ([`references/learned.md`](references/learned.md)) | auto |
|
|
257
|
+
| 6 | Tests | full suite green; new/changed code covered; **every new check probed both ways and asserted on its exit code**, and the suite run once against a cold environment ; **on a web front end the surface is checked in a browser, not in the diff** — a green suite cannot see a component that renders under a fixed header, a request that 404s past its mock, or a console error — and a browser **test suite** is the other half of the pair, never a substitute for the look (`playwright` or `chrome-devtools`, either one — **how**: [`references/browser.md`](references/browser.md), which channel: [`references/companion-skills.md`](references/companion-skills.md); absent → say *verified by reading the diff* and record it as the weaker claim it is) | auto |
|
|
257
258
|
| 7 | Lint + deploy | lint clean + suite green before deploy; deploy needs a go (or the brief's specific standing authorization) | manual |
|
|
258
|
-
| 8 | Post-deploy | clean boot or honest degradation report; **a deployed web target is opened, not curled** — a `200` proves the server answered and says nothing about a 404'd bundle or a console full of errors on load (`playwright` or `chrome-devtools`, either one; absent → call it an HTTP response, which is its honest name) | auto |
|
|
259
|
+
| 8 | Post-deploy | clean boot or honest degradation report; **a deployed web target is opened, not curled** — a `200` proves the server answered and says nothing about a 404'd bundle or a console full of errors on load (`playwright` or `chrome-devtools`, either one, [`references/browser.md`](references/browser.md); absent → call it an HTTP response, which is its honest name) | auto |
|
|
259
260
|
| 9 | Docs + wiki | every stale row of the stage-0 source ledger updated; **the propagation matrix walked for every change type this run produced** — the ledger names what you read, the matrix names what you owe — every settled thing recorded with an id, every answered question resolved, and **the documentation gate green with its ratchet counts printed**; docs synced; wiki synced; **the code graph refreshed where one exists** and checked against the docs (a hub no doc names, a doc naming a node the graph lost); **every number computed rather than restated, every named command or file resolvable** ([`references/learned.md`](references/learned.md)); the carry-over count printed beside the verdict | auto |
|
|
260
261
|
| 10 | **Acceptance** | ladder walk ran, its absences became REQ rows; every REQ accounted for with evidence from a check seen failing once; ledger has no unresolved row; **axis rotation recorded** (new findings vs self-inflicted, rule 1 of [`references/learned.md`](references/learned.md)), **every closure verified against the artefact rather than the document describing it**, **each correction swept across its class**, **every deferral a printed ratchet rather than a TODO**; **in a multi-repository project, every repository is clean, pushed and pointed at** (below); **the hand-back is written** — the request quoted as given, progress against it, what was solved, what surfaced unasked, waiting decisions asked here, and the ambiguity count computed ([`references/progress.md`](references/progress.md)); **the environment is given back** — all eight classes enumerated, what this run started ended and verified by re-enumerating rather than by the teardown's reply, an earlier run of this project ended only when **provably spent**, anything this project does not own reported rather than ended, written as a `holds:` line (`references/residue.md`); operator signs off; **every check this close-out leans on — the documentation gate included — has been seen failing once against a planted defect, and its ratchet counts are printed beside the verdict**; **the retrospective written last, and in order — the run stamped with its commit FIRST (the cold-retirement trigger reads that stamp), then the prune with the list at or under its cap and every deletion logged, then the entry; every deletion and every entry carrying its commit, entries older than five stamps rotated into the archive, counts printed** ; **every disclosure printed beside the verdict** — `abstained` (what the run declined to claim) and `unlooked` (what a check never looked at), neither a ratchet, neither with a floor, neither ever a target ([`references/gates.md`](references/gates.md) → *Disclosures*) | manual |
|
|
261
262
|
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
],
|
|
79
79
|
"gate": {
|
|
80
80
|
"type": "auto",
|
|
81
|
-
"check": "SET EQUALITY: the REQ ids in the brief equal the union of Implements: across plan tasks — a non-empty difference fails the gate and is reported as the explicit list of dropped requirements. Plus: every spec requirement maps to a task; no placeholders; names and types consistent across tasks; every task carries a verifiable DoD; parallel-group tasks share no files; UI tasks name the scenario ID(s) and SCR- screen(s) they implement in their DoD"
|
|
81
|
+
"check": "SET EQUALITY: the REQ ids in the brief equal the union of Implements: across plan tasks — a non-empty difference fails the gate and is reported as the explicit list of dropped requirements. Plus: every spec requirement maps to a task; no placeholders; names and types consistent across tasks; every task carries a verifiable DoD; parallel-group tasks share no files; UI tasks name the scenario ID(s) and SCR- screen(s) they implement in their DoD. Every edge in the plan's Execution order table carries a non-empty Carries cell and the self-review's Edges: line is computed — an arrow whose payload nobody can name is a fake edge and the wait behind it is free to give away."
|
|
82
82
|
}
|
|
83
83
|
},
|
|
84
84
|
{
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
],
|
|
93
93
|
"gate": {
|
|
94
94
|
"type": "auto",
|
|
95
|
-
"check": "all plan tasks DONE — the per-task review returns three verdicts (spec compliance, REQ satisfied, code quality); every finding fixed or parked with a written ruling; no task left BLOCKED; full test suite green; the branch integrated per the brief's branch policy (base synced, suite green on the result, worktree removed) — or the operator's explicit 'leave it unmerged' recorded. Every parked finding and implementer concern is harvested into the carry-over ledger before the scratch workspace is deleted."
|
|
95
|
+
"check": "all plan tasks DONE — the per-task review returns three verdicts (spec compliance, REQ satisfied, code quality); every finding fixed or parked with a written ruling; no task left BLOCKED; full test suite green; the branch integrated per the brief's branch policy (base synced, suite green on the result, worktree removed) — or the operator's explicit 'leave it unmerged' recorded. Every parked finding and implementer concern is harvested into the carry-over ledger before the scratch workspace is deleted. Every group that actually fanned out ran its convergence check over all its diffs together BEFORE its first worktree was integrated, and logged a line either way (findings with their ruling, or 'convergence check clean')."
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
{
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# The browser — how the look is actually taken, and how a suite is run beside it
|
|
2
|
+
|
|
3
|
+
[`companion-skills.md`](companion-skills.md) decides **which** channel a project has
|
|
4
|
+
and how to install it. This file is **how to use one**: the model both channels share,
|
|
5
|
+
the commands the look is made of, and the three different things people mean when they
|
|
6
|
+
say *"tested in a browser"*.
|
|
7
|
+
|
|
8
|
+
Stages 5, 6 and 8 ([`stages.md`](stages.md)) and [`tdd.md`](tdd.md) demand a look at the
|
|
9
|
+
rendered surface. Until this file existed, they demanded it and named no mechanism —
|
|
10
|
+
which is how a run says *I checked the browser* and means *I ran the unit tests*.
|
|
11
|
+
|
|
12
|
+
> **Every command and flag below was read from the tool's own `--help`**, not from a
|
|
13
|
+
> vendor page. Where the two disagreed, `--help` won and the page was wrong — see
|
|
14
|
+
> *Rationalizations*. Re-derive before quoting:
|
|
15
|
+
> `npx @playwright/cli@latest --help` and `npx @playwright/mcp@latest --help`.
|
|
16
|
+
>
|
|
17
|
+
> **Use the scoped name with `npx`.** `npx playwright-cli --help` fails outside a project
|
|
18
|
+
> that has already installed it (`could not determine executable to run`), and the bare
|
|
19
|
+
> `playwright-cli` on npm is **somebody else's package** — Microsoft's, deprecated in
|
|
20
|
+
> favour of this one. The binary is called `playwright-cli`; the package is
|
|
21
|
+
> `@playwright/cli`. Every `playwright-cli …` line below assumes it is installed and on
|
|
22
|
+
> PATH, which is what the matrix's install line does.
|
|
23
|
+
|
|
24
|
+
## Contents
|
|
25
|
+
|
|
26
|
+
- The one model: a tree, and a ref
|
|
27
|
+
- The look, as commands you can run
|
|
28
|
+
- Sessions, and why an agent needs them
|
|
29
|
+
- Reading a look vs gating on one
|
|
30
|
+
- "Tested in a browser" is three different claims
|
|
31
|
+
- Getting past a login, and past a backend
|
|
32
|
+
- When the look finds something: debugging the spec that missed it
|
|
33
|
+
- Evidence a reader can open
|
|
34
|
+
- What the channel can reach — the part a recommendation owes you
|
|
35
|
+
- Rationalizations
|
|
36
|
+
|
|
37
|
+
## The one model: a tree, and a ref
|
|
38
|
+
|
|
39
|
+
**Both channels drive the page through its accessibility tree, not its pixels.** You ask
|
|
40
|
+
for a snapshot, you get structured text — roles, names, and a **ref** per interactive
|
|
41
|
+
element (`e5`, `e12`) — and you act on the ref.
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
snapshot -> button "Checkout" [ref=e12] -> click e12
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Three consequences the doctrine rests on:
|
|
48
|
+
|
|
49
|
+
- **A look costs a page of text and no vision model.** This is why the pipeline can ask
|
|
50
|
+
for one at three stages without the cost being an argument. A `screenshot` exists in
|
|
51
|
+
both channels and *is* pixels — take one for a human to look at, not for you to read.
|
|
52
|
+
- **The ref is a fact about the page as rendered**, so `click e12` after a snapshot is
|
|
53
|
+
deterministic in a way a coordinate never is.
|
|
54
|
+
- **A ref that no longer resolves is a finding, not an error to retry past.** The element
|
|
55
|
+
moved, or never rendered. That is exactly the class stage 6 says a green suite cannot
|
|
56
|
+
see. Re-snapshot, read what changed, and report it — do not hunt for a selector that
|
|
57
|
+
makes the command succeed.
|
|
58
|
+
|
|
59
|
+
Refs come from the **latest** snapshot. Act, then snapshot again before using a ref from
|
|
60
|
+
before the act.
|
|
61
|
+
|
|
62
|
+
## The look, as commands you can run
|
|
63
|
+
|
|
64
|
+
The pipeline asks for the same four things every time: **open it, snapshot it, read the
|
|
65
|
+
console, read the network.** In the CLI that is literally four commands:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
playwright-cli open http://localhost:3000/checkout
|
|
69
|
+
playwright-cli snapshot
|
|
70
|
+
playwright-cli console warning # min-level: only warnings and errors
|
|
71
|
+
playwright-cli requests # then: request <n> for headers, body, response
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The MCP is the same four moves under different names: `browser_navigate`,
|
|
75
|
+
`browser_snapshot`, `browser_console_messages`, `browser_network_requests`.
|
|
76
|
+
|
|
77
|
+
**Quote what you read, not that you looked.** *"Console clean, all requests fine"* is a
|
|
78
|
+
claim. *"`console warning` → empty; `requests` → no status ≥ 400"* is the same claim with
|
|
79
|
+
its command attached, and it is the one that belongs in a gate verdict.
|
|
80
|
+
|
|
81
|
+
**Do not quote the request count as the page's count.** `requests` hides successful static
|
|
82
|
+
resources by default and says so in its own footer (*"N static request(s) not shown"*);
|
|
83
|
+
`requests --static` includes them. Failures are listed either way — a 404'd stylesheet
|
|
84
|
+
appears without the flag — so *no status ≥ 400* is a safe claim and *14 requests* is not.
|
|
85
|
+
|
|
86
|
+
`chrome-devtools` takes the identical four moves — `navigate_page`, `take_snapshot`,
|
|
87
|
+
`list_console_messages`, `list_network_requests` — which is why the matrix ranks neither:
|
|
88
|
+
the look is the same look.
|
|
89
|
+
|
|
90
|
+
## Sessions, and why an agent needs them
|
|
91
|
+
|
|
92
|
+
**The CLI keeps a browser alive between commands.** That is the whole reason the four
|
|
93
|
+
commands above compose: `snapshot` sees the page `open` navigated to, and `click e12`
|
|
94
|
+
acts on the element that snapshot named. A tool that launched a browser per invocation
|
|
95
|
+
would lose the page, and every ref with it.
|
|
96
|
+
|
|
97
|
+
| Need | Command |
|
|
98
|
+
|---|---|
|
|
99
|
+
| Two surfaces at once without shared cookies | `playwright-cli -s=checkout open …` and `-s=admin open …` |
|
|
100
|
+
| See what is still running | `playwright-cli list` |
|
|
101
|
+
| Tidy up at the end of a stage | `playwright-cli close-all` |
|
|
102
|
+
| A stale or zombie process after a crash | `playwright-cli kill-all` |
|
|
103
|
+
|
|
104
|
+
**A run that opened a browser closes it**, the same rule the pipeline applies to every
|
|
105
|
+
other resource it starts ([`residue.md`](residue.md)). `list` before you claim the
|
|
106
|
+
environment is clean — the reply is the evidence, not the `close-all` you typed.
|
|
107
|
+
|
|
108
|
+
## Reading a look vs gating on one
|
|
109
|
+
|
|
110
|
+
Two global flags change what the output is for:
|
|
111
|
+
|
|
112
|
+
- **`--json`** — the full response as JSON. This is what a script parses, and therefore
|
|
113
|
+
what a *check* can be built on.
|
|
114
|
+
- **`--raw`** — the result value alone, no status wrapper. For one value in a shell
|
|
115
|
+
variable.
|
|
116
|
+
|
|
117
|
+
Default output is for a reader. If you find yourself regexing the default output in a
|
|
118
|
+
gate, you wanted `--json`; a check that parses prose breaks on the release that reworded
|
|
119
|
+
it ([`gates.md`](gates.md)).
|
|
120
|
+
|
|
121
|
+
## "Tested in a browser" is three different claims
|
|
122
|
+
|
|
123
|
+
Keeping these apart is the entire point of the stage-6 pair, and conflating them is the
|
|
124
|
+
commonest way a run reports a green it does not have.
|
|
125
|
+
|
|
126
|
+
| | What it is | What it proves | Where it counts |
|
|
127
|
+
|---|---|---|---|
|
|
128
|
+
| **The look** | an agent driving a page: open, snapshot, console, network | that this surface renders, right now, and what the browser said while it did | the **look**, stage 6 — recommended, never a gate |
|
|
129
|
+
| **The spec suite** | `playwright test` — the **test runner** | that the assertions someone wrote still hold, on the paths someone thought to write | the **suite** half of the stage-6 gate, counted with every other test |
|
|
130
|
+
| **The library** | `require('playwright')` — `chromium`/`firefox`/`webkit`, `devices`, `request`, `selectors` | whatever your own script asserts; it is an automation API, not a test framework | wherever the project already runs it |
|
|
131
|
+
|
|
132
|
+
The library and the runner are **separate APIs** — a script built on `chromium.launch()`
|
|
133
|
+
has no `expect`, no fixtures, no reporter, and no retry. Choosing the library where a
|
|
134
|
+
runner was wanted is how a project ends up with a bespoke half-runner nobody trusts.
|
|
135
|
+
|
|
136
|
+
The minimal library shape, for reading a script that already exists:
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
const { chromium } = require('playwright');
|
|
140
|
+
const browser = await chromium.launch();
|
|
141
|
+
const page = await browser.newPage();
|
|
142
|
+
await page.goto('http://example.com');
|
|
143
|
+
await browser.close();
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**A green spec suite never discharges the look.** It asserts what was written down; the
|
|
147
|
+
console error nobody asserted on is precisely what the look is for. This is `DEC-0004`
|
|
148
|
+
and it is the reason both halves exist.
|
|
149
|
+
|
|
150
|
+
## Getting past a login, and past a backend
|
|
151
|
+
|
|
152
|
+
A surface behind auth is the usual reason a run skips the look. Both channels solve it,
|
|
153
|
+
and neither needs a password in a transcript.
|
|
154
|
+
|
|
155
|
+
**Storage state — log in once, replay it.**
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
mkdir -p .auth # state-save does not create it
|
|
159
|
+
playwright-cli open https://app.example.com/login
|
|
160
|
+
# … sign in by hand, or drive the form …
|
|
161
|
+
playwright-cli state-save .auth/state.json # cookies + localStorage
|
|
162
|
+
playwright-cli state-load .auth/state.json # every later look starts signed in
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The MCP takes the same file at startup: `--storage-state <path>`. Point the spec suite
|
|
166
|
+
at it too and the suite and the look agree about who is signed in.
|
|
167
|
+
**The state file is a credential.** It goes where credentials go, never into the
|
|
168
|
+
repository.
|
|
169
|
+
|
|
170
|
+
**Routes — make the backend say what you need it to.**
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
playwright-cli route '**/api/quote' --status 500 # then look at the error state
|
|
174
|
+
playwright-cli route-list
|
|
175
|
+
playwright-cli unroute '**/api/quote'
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
This is how a failure path gets a look at all. `route` is also the honest way to check
|
|
179
|
+
that a 404'd bundle or a 500'd call *renders* as something a user can act on — which no
|
|
180
|
+
unit test with a mocked fetch will ever tell you.
|
|
181
|
+
|
|
182
|
+
Storage families exist per layer when you need to reach past the whole state file:
|
|
183
|
+
`cookie-list|get|set|delete|clear`, and the same verbs for `localstorage-` and
|
|
184
|
+
`sessionstorage-`.
|
|
185
|
+
|
|
186
|
+
## When the look finds something: debugging the spec that missed it
|
|
187
|
+
|
|
188
|
+
The look found a defect the suite did not. Stage 6 says fix it here — and the fix has two
|
|
189
|
+
halves: the code, and the assertion that should have caught it.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
playwright-cli generate-locator e12 # a locator for the element the look found
|
|
193
|
+
playwright-cli highlight e12 # show it on the page (--hide to clear)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Drop that locator into a new spec, then drive the spec itself:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
playwright-cli pause-at src/checkout.spec.ts:42 # run up to this line and stop
|
|
200
|
+
playwright-cli snapshot # the page as the test sees it there
|
|
201
|
+
playwright-cli step-over
|
|
202
|
+
playwright-cli resume
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
That loop is what turns *"the look caught it"* into *"the suite catches it next time"* —
|
|
206
|
+
which is the only reason the look's finding stops recurring. `run-code` and `eval` are
|
|
207
|
+
there for the case a question is faster answered in the page than through a command.
|
|
208
|
+
|
|
209
|
+
## Evidence a reader can open
|
|
210
|
+
|
|
211
|
+
A verdict that says *the surface renders* is worth what its attachment is worth.
|
|
212
|
+
|
|
213
|
+
| Artefact | Command | Use it for |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| Screenshot | `screenshot [ref]` | one state, for a human |
|
|
216
|
+
| Trace | `tracing-start` … `tracing-stop` | a failure someone else has to reproduce |
|
|
217
|
+
| Video | `video-start [file]`, `video-chapter <title>`, `video-stop` | a flow, or a regression that only appears in motion |
|
|
218
|
+
| PDF | `pdf` | a printable surface that is itself the deliverable |
|
|
219
|
+
|
|
220
|
+
`video-show-actions` annotates each action on the page with a callout naming it, which is
|
|
221
|
+
what makes a recording readable by someone who did not run it.
|
|
222
|
+
|
|
223
|
+
The MCP's equivalents are `browser_take_screenshot`, `browser_start_tracing` /
|
|
224
|
+
`browser_stop_tracing`, `browser_start_video` / `browser_stop_video`, `browser_pdf_save`,
|
|
225
|
+
written under `--output-dir` — **and all but the screenshot are behind `--caps`.** See
|
|
226
|
+
below: the tool list you read about is not the tool list you get.
|
|
227
|
+
|
|
228
|
+
**Attach the artefact or drop the claim.** A trace nobody can open is prose.
|
|
229
|
+
|
|
230
|
+
## What the channel can reach — the part a recommendation owes you
|
|
231
|
+
|
|
232
|
+
This bundle recommends handing an agent a real browser. That is a wider capability than
|
|
233
|
+
anything else in the matrix, and the boundary is worth stating rather than discovering.
|
|
234
|
+
|
|
235
|
+
- **The MCP restricts file access to the workspace roots** (cwd when no roots are
|
|
236
|
+
configured) and blocks navigation to `file://` by default. `--allow-unrestricted-file-access`
|
|
237
|
+
removes both. Read that flag as what it says.
|
|
238
|
+
- **`--allowed-origins` / `--blocked-origins` are not a security boundary**, and upstream
|
|
239
|
+
says so in its own help: they do not survive redirects. Do not use them as one.
|
|
240
|
+
- **`--isolated` keeps the profile in memory**, so nothing persists past the session —
|
|
241
|
+
the right default for a look at someone else's site. The opposite is deliberate and
|
|
242
|
+
spelled differently per channel: `--user-data-dir <path>` on the MCP,
|
|
243
|
+
`open --persistent` (or `open --profile <path>`) on the CLI.
|
|
244
|
+
- **`--secrets <path>`** exists so a credential reaches the browser without reaching the
|
|
245
|
+
transcript. Use it rather than typing the password into a `fill`.
|
|
246
|
+
- **`--extension` / `attach`** connect to a browser **you are already using**, with your
|
|
247
|
+
sessions in it. That is occasionally exactly what you want and is never the default
|
|
248
|
+
for an unattended run.
|
|
249
|
+
|
|
250
|
+
**The MCP's tool list is capability-gated, and the default is the small one.** Asking
|
|
251
|
+
the running server rather than a page: **24 tools by default, 42 with
|
|
252
|
+
`--caps vision,pdf,devtools`.** Tracing, video and PDF — `browser_start_tracing`,
|
|
253
|
+
`browser_start_video`, `browser_video_chapter`, `browser_pdf_save` — are **not present**
|
|
254
|
+
until `--caps` names them, and neither are the coordinate-mouse tools. A doctrine that
|
|
255
|
+
sends an agent to `browser_start_tracing` on a default server sends it to a tool that is
|
|
256
|
+
not there, and the agent concludes the doctrine is stale rather than the server narrow.
|
|
257
|
+
Re-derive rather than trust this paragraph: start the server and call `tools/list`.
|
|
258
|
+
|
|
259
|
+
Both counts above were measured on `@playwright/mcp` 0.0.79 by listing the server's own
|
|
260
|
+
tools. The vendor page current at the time listed tool groups this version does not ship
|
|
261
|
+
at all — routes, cookies and localStorage among them — which is why the CLI is what this
|
|
262
|
+
file names for state and mocking.
|
|
263
|
+
|
|
264
|
+
The MCP runs **headed** by default; the CLI is headless unless you pass `open --headed`.
|
|
265
|
+
On a CI box, headed is the failure you will spend an hour on.
|
|
266
|
+
|
|
267
|
+
## Rationalizations
|
|
268
|
+
|
|
269
|
+
| The excuse | Why it fails |
|
|
270
|
+
|---|---|
|
|
271
|
+
| *"`playwright test` is green, the surface is checked."* | The suite asserts what someone wrote down. `DEC-0004`: it is the coverage half, never the look. |
|
|
272
|
+
| *"I took a screenshot, so I looked."* | A screenshot is pixels you did not read. The look is `snapshot` + `console` + `requests`, and the verdict quotes them. |
|
|
273
|
+
| *"The click failed, I'll find a better selector."* | A ref that stopped resolving **is the finding**. Re-snapshot and report what moved. |
|
|
274
|
+
| *"The docs say the CLI has no `tracing`."* | A vendor page is a claim; `--help` is the tool. This file was written against `--help` **because** a page-derived claim shipped here and was wrong. |
|
|
275
|
+
| *"The tool list is in the docs."* | The page listed tools this version does not ship, and omitted that tracing, video and PDF need `--caps`. Ask the server: 24 tools default, 42 with all caps. |
|
|
276
|
+
| *"It's behind a login, so the look isn't possible."* | `state-save` / `state-load`, or `--storage-state`. Auth is a solved step, not an exemption. |
|
|
277
|
+
| *"No browser channel is installed, so the step doesn't apply."* | The step still applies; the claim weakens. Say *verified by reading the diff* and let the close-out record it as the weaker claim it is. |
|
|
278
|
+
| *"I closed the browser."* | `list` is the evidence. The command you typed is not the state you left ([`residue.md`](residue.md)). |
|
|
@@ -275,10 +275,52 @@ physical: **two implementers writing one working tree corrupt each other's state
|
|
|
275
275
|
**each implementer gets its own isolated worktree**. Then dispatch them together,
|
|
276
276
|
review each one against its own diff, and integrate the worktrees back to the
|
|
277
277
|
build branch one at a time, running the suite after each merge.
|
|
278
|
+
- **Prefer a native fan-out primitive where the harness has one**, for the same
|
|
279
|
+
reason `git worktree` defers to a native worktree tool in §1: the harness owns the
|
|
280
|
+
concurrency cap, the per-agent isolation and the resume, and hand-rolling those
|
|
281
|
+
creates state it cannot see or clean up. Where there is none, dispatch by hand
|
|
282
|
+
under the three conditions above. **Never name a specific product here** — the
|
|
283
|
+
keyword for one host's fan-out was renamed six weeks after the article that
|
|
284
|
+
documented it, and doctrine pinned to a vendor's noun rots on that schedule.
|
|
278
285
|
- **Any conflict on integration** means the plan's file ownership was wrong: stop
|
|
279
286
|
fanning out, finish the group sequentially, and record it in the ledger.
|
|
280
287
|
- Never fan out the fix loop — a task under repair belongs to one implementer.
|
|
281
288
|
|
|
289
|
+
### 4.2a The group convergence check — after the group, before integration
|
|
290
|
+
|
|
291
|
+
A per-task review reads **one diff**. A fanned-out group produces several, and the
|
|
292
|
+
defect this stage cannot otherwise see is the one that exists only *between* them:
|
|
293
|
+
each task passes its own review and the group is still incoherent.
|
|
294
|
+
|
|
295
|
+
So after the last task in a fanned-out group reports, and **before** the first
|
|
296
|
+
worktree is integrated, run one check over the group's reports and diffs together.
|
|
297
|
+
It is the only moment all of them exist and none of them has landed.
|
|
298
|
+
|
|
299
|
+
Five things it looks for. Each has been a real defect, and none is visible in a
|
|
300
|
+
single diff:
|
|
301
|
+
|
|
302
|
+
1. **An empty deliverable** — a task that reported DONE and changed nothing that
|
|
303
|
+
satisfies its REQ.
|
|
304
|
+
2. **Two outputs that cannot both be true** — the same helper renamed by one task
|
|
305
|
+
and called by its old name in another; two tasks adding the same config key with
|
|
306
|
+
different defaults; two migrations claiming the same version.
|
|
307
|
+
3. **Off-brief work** — a task that solved a neighbouring problem instead of the one
|
|
308
|
+
its brief named. Its own review passes, because its own diff is coherent.
|
|
309
|
+
4. **A REQ satisfied twice, differently** — two tasks each implementing the same
|
|
310
|
+
requirement in incompatible ways, which the per-task REQ verdict cannot see
|
|
311
|
+
because each is looking at one task.
|
|
312
|
+
5. **A shared assumption that only one task acted on** — a Global Constraint one
|
|
313
|
+
implementer applied and another did not.
|
|
314
|
+
|
|
315
|
+
**A finding here is not a per-task fix loop.** It is a group-level decision: pick
|
|
316
|
+
which task is right, send the other back with the ruling, or park both and escalate.
|
|
317
|
+
Log it once, on the group:
|
|
318
|
+
`Group <G>: convergence check — <n> findings (<one-liners>); ruling: <what governs>`.
|
|
319
|
+
|
|
320
|
+
**A clean group logs a line too** — `Group <G>: convergence check clean (<n> tasks)`.
|
|
321
|
+
A check whose silence is indistinguishable from not having run is not evidence, and
|
|
322
|
+
this is the check most likely to be skipped because every task already went green.
|
|
323
|
+
|
|
282
324
|
### 4.3 Handle the report
|
|
283
325
|
|
|
284
326
|
| Status | Action |
|
|
@@ -520,8 +562,10 @@ stages 7–9 run against an unintegrated branch.
|
|
|
520
562
|
## GATE (auto)
|
|
521
563
|
|
|
522
564
|
All plan tasks DONE with all three review verdicts (spec compliance, REQ satisfied,
|
|
523
|
-
code quality);
|
|
524
|
-
|
|
565
|
+
code quality); **every group that actually fanned out has run its convergence check
|
|
566
|
+
(§4.2a) before its first worktree was integrated, and logged a line either way** —
|
|
567
|
+
findings with their ruling, or `convergence check clean`; the full test suite green;
|
|
568
|
+
every open finding either fixed or parked with a ruling; **every parked finding and implementer concern harvested into the
|
|
525
569
|
carry-over ledger** — the workspace is deleted, so nothing may stay only there;
|
|
526
570
|
no task left BLOCKED; the branch integrated per the brief's policy — or the
|
|
527
571
|
operator explicitly told you to leave it, and that is recorded. **Every decision a
|
|
@@ -541,5 +585,7 @@ a red suite or an unresolved BLOCKED does not advance to stage 6.
|
|
|
541
585
|
| "This finding is obviously wrong, drop it" | You adjudicate at the cap, in writing. Silent discards are forbidden. |
|
|
542
586
|
| "Ledger bookkeeping is overhead" | The ledger is what survives compaction. Without one, controllers re-run entire completed task sequences. |
|
|
543
587
|
| "Two implementers in parallel will be faster" | One working tree, two writers = corrupted state. Parallel needs one worktree each. |
|
|
588
|
+
| "Every task in the group passed its review, so the group is fine" | A per-task review reads one diff. The defect between two diffs — a rename one task made and another calls by its old name — passes both and lands at integration. §4.2a. |
|
|
589
|
+
| "The convergence check found nothing, no need to log it" | A check whose silence looks identical to not having run is not evidence. The clean line is the record that it ran. |
|
|
544
590
|
| "I'll paste the earlier tasks so it has context" | A fresh subagent needs its task, its interfaces and the constraints. Pasted history is pure cost. |
|
|
545
591
|
| "Stage 7 can merge the branch" | Stage 7 lints and deploys what is integrated. An unmerged branch means lint, deploy and docs all ran against something that is not what ships. |
|
|
@@ -52,10 +52,53 @@ what each one owns. This is where decomposition gets locked in:
|
|
|
52
52
|
into **parallel groups** in topological order, and tag each task
|
|
53
53
|
`depends: [task ids]`.
|
|
54
54
|
|
|
55
|
+
**Then run the fake-edge test over what you just drew.** An edge is a dependency
|
|
56
|
+
that carries data — not two tasks that happen to be written one after the other.
|
|
57
|
+
Six steps, five minutes, and it is the difference between a graph and a list:
|
|
58
|
+
|
|
59
|
+
1. Write every task as a box.
|
|
60
|
+
2. Draw an arrow between each pair you were about to order.
|
|
61
|
+
3. For each arrow ask: **does output from A actually enter B?** Not *"does B come
|
|
62
|
+
after A"* — does B consume a file, a signature, a decision or a value that A
|
|
63
|
+
produced?
|
|
64
|
+
4. Yes → keep it, and **write the payload in the `Carries` cell**.
|
|
65
|
+
5. No → delete it. That wait was free to give away, and you were paying for it.
|
|
66
|
+
6. Everything left with no incoming arrow is group A and starts at once.
|
|
67
|
+
|
|
68
|
+
**The payload is the test, not the answer to it.** An arrow whose `Carries` cell
|
|
69
|
+
you cannot fill is a fake edge, and the empty cell is what makes that visible to
|
|
70
|
+
a reviewer instead of leaving an arrow in place because it looked orderly. Expect
|
|
71
|
+
two or three per plan; the classic is *"review file A, then review file B"*,
|
|
72
|
+
which reads as a sequence and never once passes anything between them.
|
|
73
|
+
|
|
55
74
|
**File ownership is exclusive within a group.** No two tasks in the same parallel
|
|
56
75
|
group write the same file — that is the rule that makes stage-5 fan-out safe.
|
|
57
76
|
Sequential integration/glue tasks sit *between* groups.
|
|
58
77
|
|
|
78
|
+
**Distinct is not the same as independent.** Two tasks with different names, in
|
|
79
|
+
different directories, that both write one shared registry — or both take the
|
|
80
|
+
same fixed scratch path — are one task with a race in it. The check is what they
|
|
81
|
+
*touch*, never what they are called.
|
|
82
|
+
|
|
83
|
+
### This pipeline is a static graph, and that is a decision
|
|
84
|
+
|
|
85
|
+
The stage list is fixed before the run starts, and stays fixed. It could have
|
|
86
|
+
been otherwise: a run that reads its own findings and invents its next stage is
|
|
87
|
+
a real design, and it is the one this pipeline refuses.
|
|
88
|
+
|
|
89
|
+
**The reason is auditability.** A graph that decides its own shape while running
|
|
90
|
+
produces a shape nobody drew, so *"here is the pipeline"* and *"here is what this
|
|
91
|
+
run did"* stop being the same document — and every claim stage 10 makes becomes
|
|
92
|
+
unfalsifiable from the outside. That is the same failure the evidence canons name
|
|
93
|
+
when a number is restated rather than computed.
|
|
94
|
+
|
|
95
|
+
Two places the run *does* discover structure, both bounded and both recorded:
|
|
96
|
+
the **module map** cut at stage 2 ([`decomposition.md`](decomposition.md)), which
|
|
97
|
+
is committed as a file before any module is built, and the **carry-over ledger**,
|
|
98
|
+
which grows but never reorders a stage. Discovery that lands in a committed
|
|
99
|
+
artifact is not a dynamic graph; discovery that changes what runs next, silently,
|
|
100
|
+
is.
|
|
101
|
+
|
|
59
102
|
## Task right-sizing
|
|
60
103
|
|
|
61
104
|
A task is the smallest unit that carries its own test cycle and is worth a fresh
|
|
@@ -94,14 +137,19 @@ verbatim from the spec. Every task's requirements implicitly include this sectio
|
|
|
94
137
|
|
|
95
138
|
## Execution order
|
|
96
139
|
|
|
97
|
-
| Group | Tasks | Runs after |
|
|
98
|
-
|
|
99
|
-
| A | 1, 2 | — |
|
|
100
|
-
| B | 3 | A |
|
|
140
|
+
| Group | Tasks | Runs after | Carries |
|
|
141
|
+
|---|---|---|---|
|
|
142
|
+
| A | 1, 2 | — | — |
|
|
143
|
+
| B | 3 | A | <what crosses this edge: the file, signature, decision or value B consumes> |
|
|
101
144
|
|
|
102
145
|
---
|
|
103
146
|
```
|
|
104
147
|
|
|
148
|
+
**The `Carries` cell is required on every edge and empty only on group A.** A cell
|
|
149
|
+
you cannot fill means the arrow carries nothing, which means it is a fake edge:
|
|
150
|
+
delete it and let the task start in the earlier group. This is the fake-edge test
|
|
151
|
+
made a column, so its result is committed rather than remembered.
|
|
152
|
+
|
|
105
153
|
## Task structure — required
|
|
106
154
|
|
|
107
155
|
````markdown
|
|
@@ -190,8 +238,11 @@ A checklist you run yourself, inline. No subagent:
|
|
|
190
238
|
4. **Name and type consistency:** signatures, property names and types used in
|
|
191
239
|
later tasks match what earlier tasks defined. `clearLayers()` in Task 3 and
|
|
192
240
|
`clearFullLayers()` in Task 7 is a bug, not a style difference.
|
|
193
|
-
5. **Parallel safety:** no two tasks in the same group write
|
|
194
|
-
`depends:` points at a
|
|
241
|
+
5. **Parallel safety and the fake-edge test:** no two tasks in the same group write
|
|
242
|
+
the same file **or share any other mutable target**; every `depends:` points at a
|
|
243
|
+
task that really produces what's consumed, and every edge's `Carries` cell is
|
|
244
|
+
filled. Count the edges you deleted — that number is the line below, and a plan
|
|
245
|
+
that deletes none on its first pass has almost certainly not run the test.
|
|
195
246
|
6. **DoD present and verifiable** on every task.
|
|
196
247
|
7. **Every command, path and file a DoD names resolves.** Walk each task's
|
|
197
248
|
*Definition of done* and its steps and check the targets exist — a DoD that says
|
|
@@ -219,6 +270,7 @@ before the gate; every line a **computed number, not a tick**.
|
|
|
219
270
|
- Decisions: checked against <the brief's D-table> and <stage 2's rejected options> — <verdict>
|
|
220
271
|
- Cost: <surfaces>/<guards>/<REQ> now, <…> at stage 2 — <proportionate | grown, and why>
|
|
221
272
|
- Hygiene: <n> checks, <n> findings, <n> open
|
|
273
|
+
- Edges: <n> declared, <n> carry data, <n> removed
|
|
222
274
|
- Placeholders: <n> · Ambiguity: <n> found, <n> resolved inline
|
|
223
275
|
```
|
|
224
276
|
|
|
@@ -243,6 +295,9 @@ the explicit list of dropped (or invented) requirements — this seam is where s
|
|
|
243
295
|
leaks, so the check is mechanical, never a judgement call.
|
|
244
296
|
|
|
245
297
|
Then: every spec requirement maps to a task; no placeholders; names and types
|
|
246
|
-
consistent across tasks; parallel-group tasks share no files
|
|
247
|
-
|
|
248
|
-
|
|
298
|
+
consistent across tasks; parallel-group tasks share no files **or other mutable
|
|
299
|
+
target**; each task has a verifiable DoD. **Every edge in the *Execution order*
|
|
300
|
+
table has a non-empty `Carries` cell, and the `Edges:` line of the self-review is
|
|
301
|
+
computed** — an unfillable cell is a fake edge and the gate does not pass with one
|
|
302
|
+
left in the table. UI tasks carry their scenario IDs and `SCR-` screens. Verify all
|
|
303
|
+
of it yourself and stop on failure — this gate has no operator in it.
|
|
@@ -76,6 +76,7 @@ a row pointing outside the bundle is the defect this file exists to catch.
|
|
|
76
76
|
| **The canons** — what makes a claim documentation, and the index that routes to each | `references/documentation.md`, `../evidence-docs/SKILL.md` |
|
|
77
77
|
| **Effect verification** — the `verified-by:` contract and the rubric item that blocks | `references/build.md`, `references/review.md` |
|
|
78
78
|
| The TDD iron law and the suite gate | `references/tdd.md` |
|
|
79
|
+
| How the browser look is taken, and how a spec suite sits beside it | `references/browser.md` |
|
|
79
80
|
| The REQ coverage table, evidence rules, the closing question | `references/acceptance.md` |
|
|
80
81
|
| How the host project's own conventions are read | `references/conventions.md` |
|
|
81
82
|
| Which companions exist, what is required, self-currency | `references/companion-skills.md` |
|
|
@@ -378,7 +378,11 @@ never that the work was skipped quietly.
|
|
|
378
378
|
scope leaks silently, so the check is mechanical, not a judgement call. Plus:
|
|
379
379
|
every spec requirement maps to a task; no placeholders; names and
|
|
380
380
|
types consistent across tasks; every task carries a verifiable DoD; parallel-group
|
|
381
|
-
tasks share no files
|
|
381
|
+
tasks share no files **or other mutable target**; **every edge in the *Execution
|
|
382
|
+
order* table carries a non-empty `Carries` cell and the self-review's `Edges:`
|
|
383
|
+
line is computed** — an arrow whose payload nobody can name is a fake edge and
|
|
384
|
+
the wait behind it is free to give away ([`planning.md`](planning.md)).
|
|
385
|
+
For UI tasks: every task building user-facing behavior
|
|
382
386
|
names the scenario ID(s) and `SCR-` screen(s) it implements, and its DoD
|
|
383
387
|
includes satisfying them **and** updating the affected super-ux layers in the
|
|
384
388
|
same change (super-ux *same-change* rule).
|
|
@@ -393,10 +397,16 @@ never that the work was skipped quietly.
|
|
|
393
397
|
with an explicit breaker. TDD per task ([`tdd.md`](tdd.md)): failing test →
|
|
394
398
|
watch it fail → minimal impl → watch it pass → commit. Pin subagents to the
|
|
395
399
|
run's confirmed model (`model-tiering.md`). The plan's parallel groups fan out
|
|
396
|
-
**only
|
|
400
|
+
**only when all three hold** — the tasks share no `depends:`, their file ownership
|
|
401
|
+
is exclusive per the plan, and each implementer gets its own worktree; otherwise
|
|
402
|
+
sequential. A group that did fan out gets **one convergence check over all its
|
|
403
|
+
reports and diffs together, before the first worktree is integrated**
|
|
404
|
+
([`build.md`](build.md) §4.2a) — a per-task review reads one diff and cannot see a
|
|
405
|
+
contradiction that exists only between two of them.
|
|
397
406
|
- **Web front end? The task's own surface is checked in a browser, not in the diff.**
|
|
398
407
|
Where a browser channel is connected — `playwright` **or** `chrome-devtools`, either
|
|
399
|
-
one, whichever answers first ([`
|
|
408
|
+
one, whichever answers first (**how**: [`browser.md`](browser.md); which:
|
|
409
|
+
[`companion-skills.md`](companion-skills.md)): after a
|
|
400
410
|
task that changes a rendered surface, load it, take a snapshot and read the
|
|
401
411
|
console and the network log **before the task is marked DONE** — a component can be
|
|
402
412
|
correct and land under a fixed header, and a review of the diff cannot see that.
|
|
@@ -415,7 +425,9 @@ never that the work was skipped quietly.
|
|
|
415
425
|
- **GATE (auto):** **the hygiene gate green in diff mode after every task**
|
|
416
426
|
(`references/build.md`) — six checks over what that task changed, no floor, and a
|
|
417
427
|
finding fixed in-task or carried over with a reason; all plan tasks DONE (three review verdicts per task: spec
|
|
418
|
-
compliance, **REQ satisfied**, code quality); every
|
|
428
|
+
compliance, **REQ satisfied**, code quality); **every group that fanned out ran its
|
|
429
|
+
convergence check before its first worktree was integrated, and logged a line either
|
|
430
|
+
way** ([`build.md`](build.md) §4.2a); every finding fixed or parked with a
|
|
419
431
|
ruling; **every parked finding and implementer concern harvested into the
|
|
420
432
|
carry-over ledger** — nothing stays only in the scratch workspace, which is
|
|
421
433
|
deleted; no task left BLOCKED; full test suite green; branch integrated per the brief's policy (or the operator's
|
|
@@ -443,7 +455,8 @@ never that the work was skipped quietly.
|
|
|
443
455
|
page rendered — a component can be correct and land under a fixed header, a request
|
|
444
456
|
can 404 while every unit test mocks it, and a console error costs nothing at test
|
|
445
457
|
time. Where a browser channel is connected — `playwright` **or** `chrome-devtools`,
|
|
446
|
-
either one ([`
|
|
458
|
+
either one ([`browser.md`](browser.md) is the four commands this sentence means;
|
|
459
|
+
[`companion-skills.md`](companion-skills.md) is which channel):
|
|
447
460
|
load the surface, take a snapshot, and read **the console and the network log**
|
|
448
461
|
before calling it green. Absent, say the surface was verified **by reading the
|
|
449
462
|
diff** — that is a weaker claim and the close-out records it as one, rather than
|
|
@@ -518,7 +531,7 @@ never that the work was skipped quietly.
|
|
|
518
531
|
answered; it says nothing about whether the page rendered, whether a bundle 404'd,
|
|
519
532
|
or whether the console filled with errors on load — all three ship green past a
|
|
520
533
|
health check. Where a browser channel is connected — `playwright` **or**
|
|
521
|
-
`chrome-devtools`, either one — load the deployed URL and read
|
|
534
|
+
`chrome-devtools`, either one ([`browser.md`](browser.md)) — load the deployed URL and read
|
|
522
535
|
the console and the network log; quote what you read, not that you looked
|
|
523
536
|
([`companion-skills.md`](companion-skills.md)). Absent → say the check was an HTTP
|
|
524
537
|
response only, which is the honest name for it.
|
|
@@ -113,7 +113,13 @@ database created ten seconds ago" are different claims, and only the second one
|
|
|
113
113
|
suite whose runner happens to be a browser: it still asserts only what someone wrote
|
|
114
114
|
down. It belongs to the coverage half of the gate, and the sentence above still needs
|
|
115
115
|
a page that was opened and read. The two fail differently, which is the entire reason
|
|
116
|
-
to keep both.
|
|
116
|
+
to keep both — and [`browser.md`](browser.md) separates them from a third thing they
|
|
117
|
+
are both confused with, the Playwright **library**, which is an automation API and not
|
|
118
|
+
a test framework at all.
|
|
119
|
+
- **The look that found it writes the assertion that keeps it found.** `generate-locator`
|
|
120
|
+
on the element the look caught, then a spec around it, then `pause-at` to watch the
|
|
121
|
+
new spec see what you saw ([`browser.md`](browser.md)). A browser finding fixed with
|
|
122
|
+
no test behind it is a finding scheduled to return.
|
|
117
123
|
|
|
118
124
|
## Stage 6 — consolidation and the suite gate
|
|
119
125
|
|