task-pipeline-skill 1.32.0 → 1.37.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.
@@ -0,0 +1,190 @@
1
+ # Progress — saying which pipeline this is, and where in it
2
+
3
+ **One job: make the run's position a printed fact instead of something the operator
4
+ reconstructs from the last thing that scrolled past.**
5
+
6
+ A pipeline that never says where it is has one specific failure, and it is not
7
+ confusion — it is that **a stage looks done because nothing printed**.
8
+ [`stages.md`](stages.md) opens with a checklist for exactly that reason and then marks
9
+ it *"copy it, tick it"*: an instruction with no gate behind it, which is rung 1
10
+ behaving like rung 3 ([`gates.md`](gates.md) → *Axis B*). This file is that checklist
11
+ promoted to something the run must emit.
12
+
13
+ **Boundary.** This file decides **what is printed and when**. It decides nothing about
14
+ what is true: every number on the block has a home somewhere else and is read from
15
+ there. A progress line that computes its own counts is the fourth copy of the truth,
16
+ and [`continuity.md`](continuity.md) already says what happens to those — nobody
17
+ maintains them and the next run reads them as current.
18
+
19
+ ---
20
+
21
+ ## Contents
22
+
23
+ - The two boundaries, and only those two
24
+ - The header block
25
+ - The iteration line
26
+ - The rail is computed, never eleven
27
+ - What each glyph means
28
+ - Every number is borrowed
29
+ - Absent is a word, never a zero
30
+ - The run ledger this reads from
31
+ - Rationalizations
32
+
33
+ ## The two boundaries, and only those two
34
+
35
+ **Task start** and **iteration close**. Nothing else.
36
+
37
+ An iteration is already defined — *one item taken to its gate*
38
+ ([`continuity.md`](continuity.md) → *What one iteration means*) — and that definition
39
+ is what makes this cheap. Printing per agent turn would put a bar above every tool
40
+ call, and a block that appears fifty times a run is a block nobody reads, including
41
+ the one time it says something.
42
+
43
+ Between the two boundaries the run prints whatever it normally prints. This file adds
44
+ no narration.
45
+
46
+ ## The header block
47
+
48
+ Emitted **once, before stage 0's first question**, and again whenever the module
49
+ changes:
50
+
51
+ ```
52
+ task-pipeline v1.34.0 · pipeline-audit · module P1 «the progress print» (1 of 4)
53
+ 0 ✓ 1 ✓ 2 ✓ 3 ▶ 4 · 5 · 6 · 7 · 8 · 9 · 10 ·
54
+ ███████░░░░░░░░░░░░░░░░░░░ gates 3/11 · now 3 Spec · manual
55
+ board B-028 · carry-over 0 rows · exposure 99 never · unlooked 0
56
+ ```
57
+
58
+ Four lines, and each one answers a question an operator otherwise has to ask:
59
+
60
+ | Line | Answers |
61
+ |---|---|
62
+ | 1 | *which skill, which version, which programme, which module of how many* |
63
+ | 2 | *which stages are closed, which one is live* |
64
+ | 3 | *how far along, what is running now, will it stop for me* |
65
+ | 4 | *what is queued, what is deferred, what nobody has confirmed* |
66
+
67
+ **The module segment is omitted when there is no module map.** A task that stage 2
68
+ never decomposed has no module, and printing `(1 of 1)` turns an absence into a claim
69
+ — the shape [`audit.md`](audit.md) is built around. Where stage 2 recorded `single
70
+ module: <name>` ([`decomposition.md`](decomposition.md)), print that phrase instead.
71
+
72
+ ## The iteration line
73
+
74
+ Emitted at the **close** of every iteration, one line:
75
+
76
+ ```
77
+ ▶ pipeline-audit · P1 (1/4) · 5 Dev auto · iter 3 · gates 5/11 · next B-025
78
+ ```
79
+
80
+ **`next` cites a `B-NNN`, never a description.** That rule is
81
+ [`continuity.md`](continuity.md)'s and it is the reason this line exists at all:
82
+ *"next up is X"* was already the one sentence in a loop that no gate reads. A board id
83
+ can be checked against `docs/superpowers/backlog.md`; *"next up: the export fix"*
84
+ cannot.
85
+
86
+ **Nothing queued is `next —`, printed.** A loop that reaches an empty board says so;
87
+ omitting the field is indistinguishable from forgetting it.
88
+
89
+ ## The rail is computed, never eleven
90
+
91
+ The stage ids on the rail come from the project's `pipeline.json` → `stages[]`. They
92
+ are **not** the eleven in [`../pipeline.example.json`](../pipeline.example.json), which
93
+ is this plugin's *example* flow — a host project replaces it with its own stages
94
+ (`SKILL.md` → *Bring your own skills*).
95
+
96
+ A bar reading `gates 5/11` in a project with six stages is a false success in the
97
+ purest form the pipeline has: a summary that is confidently wrong about the thing it
98
+ summarises, printed in the place designed to be trusted at a glance.
99
+
100
+ So the rail carries **no stage count of its own**. Read the array, print what is in it.
101
+ Six stages give six positions.
102
+
103
+ ## What each glyph means
104
+
105
+ | Glyph | Means | Written when |
106
+ |---|---|---|
107
+ | `✓` | the stage's **gate passed** | the gate's own verdict was recorded |
108
+ | `▶` | in flight | the stage was entered and its gate has not returned |
109
+ | `·` | not entered | — |
110
+ | `✗` | entered, gate returned a failure | the verdict said so |
111
+ | `⊘` | skipped, **with the reason on the same run's record** | the short path, or a stage the brief excluded |
112
+
113
+ **`✓` means the gate passed — not that the stage was walked.** This is the whole
114
+ integrity of the block. A rail is a summary, and a summary is the easiest artefact in
115
+ a run to write from memory rather than from the record; a glyph set by recollection is
116
+ [`gates.md`](gates.md)'s *false success* with a nicer typeface. Derive each glyph from
117
+ the verdict the gate wrote, in the run ledger, and from nothing else.
118
+
119
+ **`⊘` may never be silent.** A skipped stage with no recorded reason is exactly what a
120
+ `·` looks like from outside, and the two mean opposite things.
121
+
122
+ ## Every number is borrowed
123
+
124
+ | Field | Its home |
125
+ |---|---|
126
+ | `board B-NNN` | `docs/superpowers/backlog.md` ([`backlog.md`](backlog.md)) |
127
+ | `carry-over N rows` | the run's carry-over ledger, as printed beside every gate verdict |
128
+ | `exposure N never` | `docs/superpowers/verification.md` ([`exposure.md`](exposure.md)) |
129
+ | `unlooked N` | the gate's own disclosure ([`gates.md`](gates.md) → *Disclosures*) |
130
+ | `gates N/M` | the run ledger's verdict rows, and `pipeline.json` → `stages[]` |
131
+
132
+ **None of these is recomputed here.** If a number on the block disagrees with the
133
+ number beside a gate verdict, the block is wrong — that direction, always, because the
134
+ gate looked and the block quoted.
135
+
136
+ This also settles what the block is *not*: it is neither a ratchet nor a disclosure of
137
+ its own ([`gates.md`](gates.md) → *Ratchets*, *Disclosures*). It sets no floor and
138
+ carries no target. It is a **restatement with a citation**, and the citation is the
139
+ only reason a restatement is allowed here at all.
140
+
141
+ ## Absent is a word, never a zero
142
+
143
+ Where a value does not exist, print the word:
144
+
145
+ ```
146
+ board — · carry-over 0 rows · exposure — · unlooked 0
147
+ ```
148
+
149
+ `exposure —` says *no verification ledger in this project*. `exposure 0` says *nothing
150
+ is unconfirmed*, which is the opposite claim, and it is the same inversion
151
+ [`exposure.md`](exposure.md) refuses when it prints `never checked` rather than
152
+ `0 days`. A zero standing in for an absence is how a project learns it is safe.
153
+
154
+ `carry-over 0 rows` **is** a real zero and prints as one: the ledger exists and holds
155
+ nothing.
156
+
157
+ ## The run ledger this reads from
158
+
159
+ `.task-pipeline/run.md`, seeded at stage 0 from
160
+ [`../templates/run.md`](../templates/run.md), one file per run.
161
+
162
+ It already had a second owner before this file existed:
163
+ [`loop-guard.md`](loop-guard.md) names it as the record that makes churn detection
164
+ **mechanical**, and calls it the only memory that survives compaction. It was never
165
+ written by any run — the detector had no input, and the guard was doctrine wearing a
166
+ script's clothes. One file serves both readers: the guard reads the `touch:` lines,
167
+ this block reads the verdict rows and the iteration counter.
168
+
169
+ Three kinds of line, appended, never rewritten:
170
+
171
+ ```
172
+ stage: 3 Spec — gate manual — verdict pass — 2026-08-10T14:02Z
173
+ iter: 3 — item B-025 — closed at gate 6
174
+ touch: test/validate.py — pass 2 (stage 7) — reason: F-014
175
+ ```
176
+
177
+ **The counter is a count of `iter:` lines, not a number the agent remembers.** After a
178
+ compaction the agent's memory of "iteration 3" is gone and the file's is not, which is
179
+ the entire argument for keeping it on disk rather than in the reply.
180
+
181
+ ## Rationalizations
182
+
183
+ | The excuse | What is actually true |
184
+ |---|---|
185
+ | "The operator can see the stages scroll by" | They can see that *something* printed. A stage that ended silently and a stage that never started look identical in a transcript, which is the failure `stages.md`'s checklist was written for and never enforced. |
186
+ | "A progress bar is decoration" | Then delete the numbers and keep the bar. The objection is really to the bar; the four borrowed counts are the payload, and they are the ones nobody prints today. |
187
+ | "I know which stage I'm on, I'll write the rail from memory" | Then the rail is a claim about the run rather than a reading of it, and it will be right until the run it most matters on. Derive it from the verdicts. |
188
+ | "There's no module map, I'll put (1 of 1)" | An undecomposed task has no module. `(1 of 1)` is an invented denominator, and a reader cannot tell it from a real one. |
189
+ | "Printing it every iteration is noise" | One line. The block is four, and it appears at task start. If that is noise, the run is emitting far worse elsewhere. |
190
+ | "The ledger is bureaucracy, I'll count iterations in my head" | Your head does not survive compaction. That is not a hypothetical here — it is why `loop-guard.md` asked for this file in the first place. |
@@ -37,6 +37,8 @@ file exists to stop.
37
37
  - The prune — mandatory, and it runs after the stamp
38
38
  - The loop closes at stage 0
39
39
  - Where a lesson goes when it is not about this project
40
+ - Publishing the insight — the skill learns from every project that runs it
41
+ - What may leave the project — the redaction list
40
42
  - Rationalizations
41
43
 
42
44
  ## Write the entry only for a divergence — and name the layer that owned it
@@ -227,9 +229,92 @@ rule that was retired for going cold is exactly the rule about to be re-learned.
227
229
 
228
230
  A lesson that would be true in any repository does not belong in one project's
229
231
  retro — it belongs in the pipeline's own doctrine
230
- ([`learned.md`](learned.md), which is exactly that list, earned the same way). Open
231
- an issue upstream and say so in the entry. A local file that accumulates universal
232
- rules is a fork of the skill that nobody named.
232
+ ([`learned.md`](learned.md), which is exactly that list, earned the same way). A local
233
+ file that accumulates universal rules is a fork of the skill that nobody named.
234
+
235
+ **This said *"open an issue upstream"* for eight releases and named no repository, no
236
+ trigger and no authorization** — an instruction on rung 1 that everybody read as done.
237
+ The rest of this section is the mechanism.
238
+
239
+ ## Publishing the insight — the skill learns from every project that runs it
240
+
241
+ **One job: stop a lesson dying in the repository that learned it.**
242
+
243
+ A retro entry is written per project and read by that project's next stage 0. The
244
+ pipeline itself never sees it. So a defect in the **skill** — a gate that loops, a
245
+ doctrine promising what nothing enforces, a rule firing on the wrong shape — is
246
+ rediscovered independently in every project and fixed in none of them.
247
+
248
+ **Opt-in, per project, off by default** — `pipeline.json` → `retro.publish`:
249
+
250
+ ```json
251
+ "retro": {
252
+ "publish": {
253
+ "repo": "ssheleg/task-pipeline",
254
+ "label": "retro-insight",
255
+ "redact": "strict"
256
+ }
257
+ }
258
+ ```
259
+
260
+ Absent, nothing is published, and nothing is asked. **Silence arms nothing** — the same
261
+ floor deploy authorization uses, and for the same reason: this is an **outward act**,
262
+ and an outward act taken from a generic flag is an outward act nobody authorized
263
+ ([`continuity.md`](continuity.md) → *The limit, before the capability*).
264
+
265
+ **The body is printed in full before the issue is opened, every time.** Not a summary
266
+ of it, not its title — the string that will be sent. The operator standing at stage
267
+ 10's manual gate is already reading; showing them what leaves the machine costs one
268
+ block and is the only moment anyone can stop it.
269
+
270
+ ```
271
+ ── would open issue ──────────────────────────────────────────
272
+ repo: ssheleg/task-pipeline
273
+ label: retro-insight
274
+ title: [retro] a queue is not a diagnosis
275
+ <the whole body, verbatim>
276
+ ──────────────────────────────────────────────────────────────
277
+ opening… → #24
278
+ ```
279
+
280
+ **No `gh`, no network, no permission?** Print the body, say the issue was **not**
281
+ opened, and carry the exact text in the carry-over ledger. That is the honest
282
+ degradation; a second transport is not.
283
+
284
+ ## What may leave the project — the redaction list
285
+
286
+ An issue is a **public artefact in someone else's repository**. What travels is the
287
+ *class*; what stays is everything that identifies where it happened.
288
+
289
+ | Goes | Stays |
290
+ |---|---|
291
+ | the class of failure, stated in the abstract | the file, the function, the line it happened in |
292
+ | which stage owned it and which stage surfaced it | the repository, organisation, branch or commit |
293
+ | the doctrine or guard that missed it, by its name **in this skill** | any host path, absolute or relative |
294
+ | the fix by grade, and the check that would catch it | the code, the config values, the data |
295
+ | whether an existing standing instruction fired | any person, company, customer or product name |
296
+
297
+ Five rules, numbered so a reader can point at one:
298
+
299
+ 1. **No host paths.** Only paths inside task-pipeline itself — `references/…`,
300
+ `templates/…`, `test/validate.py`. An absolute path names a machine.
301
+ 2. **No host identifiers**: repository, organisation, branch, commit, tag, issue or PR
302
+ number belonging to the project the run happened in.
303
+ 3. **No code, no configuration values, no data** — not a snippet, not a redacted
304
+ snippet. A shape can be described in a sentence.
305
+ 4. **No names**: person, company, customer, employer, product.
306
+ 5. **The title states the class, not the incident** — *"a queue is not a diagnosis"*,
307
+ never *"our export job looped"*.
308
+
309
+ **The printed text and the sent text are one string.** Redacting after the print, or
310
+ printing a cleaned-up version of what is actually sent, is the false-success shape this
311
+ bundle names outright ([`gates.md`](gates.md) → *False success*): a mechanism reporting
312
+ on itself rather than on what it did.
313
+
314
+ **When in doubt the rule is subtraction, not judgement.** An insight that survives
315
+ losing a detail is still an insight; a detail that leaks cannot be recalled from an
316
+ index. If removing it makes the entry incomprehensible, the entry was about the project
317
+ and not about the skill — keep it local.
233
318
 
234
319
  ## Rationalizations
235
320
 
@@ -8,12 +8,27 @@ operator's explicit go). These stages (0 intake + 1→10) are the plugin's
8
8
  `pipeline.schema.json`; a host project replaces it with its own
9
9
  stages/agents/types (see SKILL.md → *Bring your own skills*).
10
10
 
11
- ## The run checklist — copy it, tick it
11
+ ## The run checklist — printed, not remembered
12
12
 
13
- Complex workflows lose steps silently. Copy this into your response at the start of
14
- a run and check items off as they close; it is the cheapest guard against the one
15
- failure this pipeline keeps paying for — a stage that *looks* done because nothing
16
- printed.
13
+ Complex workflows lose steps silently. **The run says where it is**, at two boundaries
14
+ and only two — task start and iteration close ([`progress.md`](progress.md)):
15
+
16
+ ```
17
+ task-pipeline vX.Y.Z · <topic> · module <id> «<name>» (N of M)
18
+ 0 ✓ 1 ✓ 2 ✓ 3 ▶ 4 · 5 · 6 · 7 · 8 · 9 · 10 ·
19
+ ███████░░░░░░░░░░░░░░░░░░░ gates 3/11 · now 3 Spec · manual
20
+ board B-NNN · carry-over N rows · exposure N never · unlooked N
21
+ ```
22
+
23
+ The rail's positions come from the project's own `pipeline.json`, never from the count
24
+ below — those eleven are this plugin's example flow. Each glyph is read from the
25
+ verdict its gate wrote to `.task-pipeline/run.md`, and from nothing else: a rail
26
+ written from memory is a summary that is confidently wrong exactly where it is trusted
27
+ at a glance.
28
+
29
+ The checklist below is what that rail summarises. This section said *"copy it, tick
30
+ it"* until 2026-08-10 — an instruction with no gate behind it, which is the same
31
+ failure it was written to prevent, one level up.
17
32
 
18
33
  ```
19
34
  Pipeline progress
@@ -35,7 +50,7 @@ never that the work was skipped quietly.
35
50
 
36
51
  ## Contents
37
52
 
38
- - The run checklist — copy it, tick it
53
+ - The run checklist — printed, not remembered
39
54
  - 0 — Intake grill — MANDATORY
40
55
  - 1 — Docs study
41
56
  - 2 — Brainstorm + decompose
@@ -123,6 +138,27 @@ never that the work was skipped quietly.
123
138
  or they genuinely disagree and that is a decision. There is no fourth option, and
124
139
  starting on an unresolved divergence means building against a system that does
125
140
  not exist.
141
+ - **Phase 1d — the short-path triage: printed, proposed, never taken silently.** This
142
+ pipeline's own boundary exempts a typo, a one-line fix and a mechanical rename — and
143
+ nothing measured that until 2026-08-10, so the exemption depended on an agent
144
+ remembering it while eleven stages and four manual gates stood in front of a
145
+ one-paragraph edit. Three questions, each with something behind it:
146
+
147
+ ```
148
+ 1. files the request names, resolved git ls-files -- <paths> -> N
149
+ 2. any of them a public contract the version-synced surfaces,
150
+ pipeline.schema.json, the
151
+ command, the README -> yes/no
152
+ 3. behaviour a user or a caller observes changes -> yes/no
153
+ ```
154
+
155
+ Few files, no contract, no observable change ⇒ **propose** the short path: stages 1,
156
+ 2, 3 and 4 marked `⊘` with the triage answer as the reason, and 5→10 running
157
+ unchanged. **Propose, never take.** The answer goes in the brief's autonomy sweep and
158
+ silence takes the full flow — the same floor deploy authorization uses. The glyph is
159
+ what makes it safe: a skipped stage is printed on the rail **with its reason**
160
+ ([`progress.md`](progress.md)), and a skip nobody can see is indistinguishable from a
161
+ stage that was never entered.
126
162
  - **How it runs: [`grill.md`](grill.md)** — the full doctrine, built into this
127
163
  skill (nothing to install). In short: one question per turn, a recommended
128
164
  answer with each, explore the codebase before asking, depth-first through the
@@ -170,12 +206,22 @@ never that the work was skipped quietly.
170
206
  is now stale), no open contradictions, **every
171
207
  autonomy-sweep row is answered or explicitly marked "stop and ask here"**, the
172
208
  **REQ table is written and every row names its check**, the carry-over ledger is
173
- seeded, the model decision is recorded, and the operator confirms the brief. Stop when a
209
+ seeded, **`.task-pipeline/run.md` exists and the header block has been printed**
210
+ ([`progress.md`](progress.md)), the model decision is recorded, and the operator
211
+ confirms the brief. Stop when a
174
212
  re-scan surfaces no new branches (don't grill past diminishing returns;
175
213
  reversible calls can be deferred with a note). Only then start stage 1.
176
214
  - **The verification ledger is read.** `docs/superpowers/verification.md` — the harvest
177
215
  quotes **how many rows sit at `never`**, because that is the project's standing
178
216
  exposure and stage 0 is where it is cheapest to look ([`verification.md`](verification.md)).
217
+ - **The run ledger is seeded and the header block is printed** — in that order, before
218
+ the first grill question. `.task-pipeline/run.md` from
219
+ [`../templates/run.md`](../templates/run.md) is the record **two** mechanisms already
220
+ depended on and no run had ever written: [`loop-guard.md`](loop-guard.md) calls its
221
+ own churn detection mechanical and reads the `touch:` lines, and
222
+ [`progress.md`](progress.md) derives the rail and the iteration counter from the
223
+ `stage:` and `iter:` lines. The header goes out before the interview because a run
224
+ that announces its position only at the end announced it to nobody.
179
225
  - **The board is read, or seeded.** `docs/superpowers/backlog.md` ([`backlog.md`](backlog.md)) — its **open count is quoted in the brief**, measured by a command at the top of the run rather than inherited from the last run's report. Absent ⇒ seeded from the template and said so; an empty board and no board are the same thing to work on, and only one of them can be appended to.
180
226
 
181
227
  ## 1 — Docs study
@@ -256,6 +302,32 @@ never that the work was skipped quietly.
256
302
  never rebuild from scratch. If the chain already exists and is validated (e.g.
257
303
  the task entered from super-ux), just verify (linter green) and embed it into
258
304
  the spec; only build the parts that are missing.
305
+ - **COPY track — how it sounds.** Every string a product's user will read is written
306
+ through super-ux's `copywriting`, against the brand pack (`docs/brand/voice.md`,
307
+ `terminology.md`, `facts.md`). No pack ⇒ `/brand-init` **before** the first string,
308
+ not after: a voice reverse-engineered from copy already written is a description of
309
+ what happened, not a decision. In scope: interface strings, errors, empty states,
310
+ the landing, pricing, the user-facing changelog. **Out of scope, and saying so is
311
+ what keeps the track honest:** commit messages, PR descriptions, code comments, a
312
+ developer README, internal docs. Running a brand pack over a line in a contributors'
313
+ changelog is the fastest way to teach an agent to route around the track.
314
+ - **VISUAL track — how it looks.** Where the task has a visual surface, the visual
315
+ layer goes through `sheleg-design` ([`companion-skills.md`](companion-skills.md)):
316
+ tokens and themes, typography and rhythm, motion and how it degrades to rest, the
317
+ boundary with Figma (tokens as variables, never raw values carried across). Not
318
+ through it: a purely structural change — what sits where is the UX track's — text,
319
+ a backend, an internal script.
320
+ - **Each track's refusal is a sentence, never a silence.** *"Без дизайна" / "as is"*
321
+ ends the visual track; *"без бренда" / "draft"* ends the copy track. Either one is
322
+ the operator's to make and costs nothing — but it is **recorded in the brief and
323
+ said out loud in the close-out**, because a track skipped silently and a track that
324
+ ran are the same thing in a transcript. This is the `⊘` rule one layer up: a skip
325
+ nobody can see is indistinguishable from work that happened.
326
+ - **Three tracks, three questions, and they do not substitute for each other.** super-ux
327
+ decides what the interface must **do**; `copywriting` how it **sounds**;
328
+ `sheleg-design` how it **looks**. Until 2026-08-10 this stage named only the first,
329
+ so a run designed a flow, then wrote its strings by taste and picked its values at the
330
+ keyboard — and every gate in the pipeline reported green over both.
259
331
  - **Spec:** write the approved design to
260
332
  `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` and commit it. Lock all
261
333
  shared contracts (types, schemas, signatures, file layout). For UI tasks the
@@ -274,7 +346,11 @@ never that the work was skipped quietly.
274
346
  (or an explicit v1-mode/tiny-project waiver by the operator). **With Figma on:
275
347
  the canonical record names one file, and every `screens.md` frame link carries
276
348
  that same `:fileKey`** — a string match, not a judgement; a differing key means
277
- the run drew in a second file nobody will open. No plan (stage 4)
349
+ the run drew in a second file nobody will open. **Every user-facing string went
350
+ through the COPY track or the refusal is recorded**, and **the visual layer went
351
+ through the VISUAL track or the refusal is recorded** — a recorded refusal passes
352
+ this gate and an unmentioned one does not, which is the only difference that matters.
353
+ No plan (stage 4)
278
354
  starts before this — the chain comes BEFORE interface.
279
355
 
280
356
  ## 4 — Plan
@@ -308,6 +384,16 @@ never that the work was skipped quietly.
308
384
  watch it fail → minimal impl → watch it pass → commit. Pin subagents to the
309
385
  run's confirmed model (`model-tiering.md`). The plan's parallel groups fan out
310
386
  **only** when each implementer gets its own worktree; otherwise sequential.
387
+ - **Web front end? The task's own surface is checked in a browser, not in the diff.**
388
+ Where `chrome-devtools` is connected ([`companion-skills.md`](companion-skills.md)):
389
+ after a task that changes a rendered surface, load it, take a snapshot and read the
390
+ console and the network log **before the task is marked DONE** — a component can be
391
+ correct and land under a fixed header, and a review of the diff cannot see that.
392
+ Absent, say the surface was verified by reading the diff and treat it as the weaker
393
+ claim it is. Stage 6 repeats this over the whole tree; this one catches it while the
394
+ implementer that wrote it is still dispatched. The matrix pointed this companion at
395
+ stages 5–6 from the day it was added and **this stage had never named it** — found by
396
+ the guard comparing the two, not by a reader.
311
397
  - **Integration closes the stage:** sync with the base branch, re-run the full suite
312
398
  on the result, land it the project's way (merge, or a PR — outward, so it needs a
313
399
  go), remove the worktree. Stages 7–9 act on the integrated result, so a branch the
@@ -370,6 +456,14 @@ never that the work was skipped quietly.
370
456
  tagging, the CI verdict for what was just pushed is READ, not assumed**
371
457
  ([`conventions.md`](conventions.md) → *The CI verdict*) — a tag on a commit whose
372
458
  run nobody read is how a red `main` ships.
459
+ - **The review loop that lives here has a cap, and the cap is a measurement**
460
+ ([`loop-guard.md`](loop-guard.md) → *The review loop*). **3 rounds** per artifact by
461
+ default (`pipeline.json` → `run.review.maxRounds`); at the cap the run stops reviewing
462
+ and prints new-versus-self-inflicted per round, and either the numbers end it or the
463
+ operator continues it out loud. This stage's loop was capped by nothing until
464
+ 2026-08-10 and ran ten rounds twice in one programme, against a stated ceiling of two
465
+ re-entries per stage — the ceiling simply did not name a review round. Every finding
466
+ left open at the cap leaves as a board row with its evidence, never as a shrug.
373
467
 
374
468
  ## 8 — Post-deploy
375
469
  - **Freedom: medium** — where the logs live varies; 'clean boot or an honest degradation report' does not ([`gates.md`](gates.md) → *Axis C*).
@@ -545,7 +639,13 @@ never that the work was skipped quietly.
545
639
  list at or under its cap, every deletion logged in the archive with its commit,
546
640
  entries older than five run stamps rotated into `docs/superpowers/retro/`, the run
547
641
  stamped with its commit, every SHA in either file resolvable, and the
548
- counts printed beside this verdict**; **the documentation gate has been seen
642
+ counts printed beside this verdict**; **where `pipeline.json` → `retro.publish` is
643
+ set, the skill-level insight is published as an issue on the skill's repository —
644
+ its body printed in full first, the printed string and the sent string being one
645
+ string, and the five redaction rules applied
646
+ ([`retrospective.md`](retrospective.md) → *What may leave the project*). Absent, the
647
+ step does not exist and is not asked about: publishing to another repository is an
648
+ outward act and silence authorizes none**; **the documentation gate has been seen
549
649
  failing once against a planted defect and its ratchet counts are printed**
550
650
  ([`gates.md`](gates.md)); **every repository is closed — the parent included:
551
651
  `git submodule status` shows no `+`, each repo clean and pushed**; **every check this gate leans on has been seen failing
@@ -13,6 +13,7 @@ from `super-ux`.
13
13
  | `carryover.md` | `docs/superpowers/specs/YYYY-MM-DD-<topic>-carryover.md` | 0 seeds, all stages append, 10 reads |
14
14
  | `verification.md` | `docs/superpowers/verification.md` | 8 writes a row per shipped REQ, 10 requires it, a human fills `Human` |
15
15
  | `backlog.md` | `docs/superpowers/backlog.md` | 0 seeds when absent, any stage appends, 10 resolves and re-derives |
16
+ | `run.md` | `.task-pipeline/run.md` — **git-ignored**, one per run | 0 seeds it, every gate appends a verdict, every repeating pass a `touch:` line |
16
17
  | `context.md` | `CONTEXT.md` at the repo root (or per context) | 0 — grill, domain awareness |
17
18
  | `adr.md` | `docs/adr/NNNN-<slug>.md` | 0 — grill, hard-to-reverse decisions |
18
19
  | `docmap.md` | `docs/DOCMAP.md` — **one per project** | 0 — the documentation inventory |
@@ -0,0 +1,77 @@
1
+ # Run ledger — `.task-pipeline/run.md`
2
+
3
+ > **One file per run.** Seeded at stage 0, appended by every stage, never rewritten.
4
+ > Two readers depend on it and neither can work from the agent's memory: the skill's
5
+ > `references/loop-guard.md` reads the `touch:` lines to detect churn mechanically, and
6
+ > its `references/progress.md` reads the `stage:` verdicts and the `iter:` count to
7
+ > print the rail.
8
+ >
9
+ > **This file is the run's memory after a compaction.** Everything else about the
10
+ > run's position lives in a context window that will not survive one.
11
+
12
+ Run: `<topic>` · started `<YYYY-MM-DD>` · module map: `<path or "none">`
13
+
14
+ ## Lines
15
+
16
+ Append-only. Three shapes, and nothing else belongs here:
17
+
18
+ ```
19
+ stage: <id> <name> — gate <auto|manual> — verdict <pass|fail|skip> — <ISO-8601>
20
+ iter: <N> — item <B-NNN or task id> — closed at gate <stage id>
21
+ touch: <file> — pass <N> (<stage|round|module>) — reason: <finding id / gate item>
22
+ ```
23
+
24
+ - **`stage:`** — written when a gate **returns**, not when the stage is entered. The
25
+ rail's `✓` is derived from this line and from nothing else; a glyph set from memory
26
+ is a summary that is confidently wrong exactly when it matters.
27
+ - **`iter:`** — one line per iteration closed. The progress line's counter is
28
+ `grep -c '^iter:'`, never a number anyone remembers.
29
+ - **`touch:`** — one line per file per pass, and the reason names **what forced the
30
+ edit**: a finding id, a failed gate item, an operator instruction. *"Cleanup"*,
31
+ *"polish"* and *"while I was there"* are not reasons; they are churn with better
32
+ manners.
33
+
34
+ A `skip` verdict carries its reason on the same line — a skipped stage and a stage
35
+ never entered look identical from outside, and they mean opposite things.
36
+
37
+ ## Log
38
+
39
+ ```
40
+ stage: 0 Intake — gate manual — verdict pass — 2026-08-10T11:14Z
41
+ iter: 1 — item B-025 — closed at gate 0
42
+ stage: 1 Docs study — gate auto — verdict pass — 2026-08-10T11:31Z
43
+ touch: src/export.ts — pass 1 (stage 5) — reason: TASK-3
44
+ touch: src/export.ts — pass 2 (stage 5) — reason: F-014
45
+ touch: src/export.ts — pass 3 (stage 5) — reason: F-014
46
+ ```
47
+
48
+ The last two lines are a **trip**: the same file, two consecutive passes, the same
49
+ reason. `references/loop-guard.md` → *Detection* item 2 — the fix did not fix it, or
50
+ the two passes disagree about what *fixed* means. Stop editing and run the break
51
+ protocol; do not dispatch a fourth pass.
52
+
53
+ ## Why it is not the build ledger
54
+
55
+ `.task-pipeline/build/<plan>/progress.md` covers **one stage** — stage 5's tasks, and
56
+ whether a task was already dispatched (`references/build.md`). This file
57
+ covers **the run**: stage verdicts, iterations, and every repeating pass anywhere in
58
+ the pipeline, including the loops between stages that the build ledger cannot see.
59
+
60
+ Keeping them separate is deliberate. A run that has no stage-5 work still loops, still
61
+ re-enters stages and still needs a rail — and it would have no ledger at all if the
62
+ run's memory lived inside the build directory that stage 5 deletes.
63
+
64
+ ## What closes it, and what survives it
65
+
66
+ **This file is git-ignored** — `.task-pipeline/` is, and this lives inside it. It is
67
+ the run's working memory, not its record: it exists to survive a **compaction**, which
68
+ is a different problem from surviving the run.
69
+
70
+ So stage 10 **reads it and copies out what outlives the run** — the pass counts and
71
+ any loop-guard ruling go into the acceptance file and the retro stamp, which are
72
+ committed. What is not carried out is gone when the directory is cleared, and that is
73
+ the correct outcome for a `touch:` line whose finding has been closed.
74
+
75
+ Never treat it as evidence in a later run. A file that is not in git cannot be quoted
76
+ at a commit, and a claim nobody can navigate to is the thing this repository's
77
+ documentation canon exists to refuse.