task-pipeline-skill 1.85.2 → 1.86.1
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 +49 -0
- package/CONTRIBUTING.md +2 -2
- package/README.md +2 -1
- package/SKILL-CARD.md +1 -1
- package/bin/task-pipeline.js +70 -9
- package/evals/cases/evidence-docs.json +188 -0
- package/evals/cases/project-audit.json +188 -0
- package/evals/cases/task-pipeline.json +191 -0
- package/package.json +5 -4
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/skills/evidence-docs/SKILL.md +16 -11
- package/plugins/task-pipeline/skills/evidence-docs/references/GENERATED.md +8 -0
- package/plugins/task-pipeline/skills/evidence-docs/references/documentation.md +472 -0
- package/plugins/task-pipeline/skills/evidence-docs/references/gates.md +645 -0
- package/plugins/task-pipeline/skills/evidence-docs/references/hooks.md +274 -0
- package/plugins/task-pipeline/skills/evidence-docs/references/learned.md +292 -0
- package/plugins/task-pipeline/skills/evidence-docs/references/retrospective.md +551 -0
- package/plugins/task-pipeline/skills/evidence-docs/references/setup.md +149 -0
- package/plugins/task-pipeline/skills/evidence-docs/templates/decisions.md +50 -0
- package/plugins/task-pipeline/skills/evidence-docs/templates/docgate.sh +537 -0
- package/plugins/task-pipeline/skills/project-audit/SKILL.md +66 -25
- package/plugins/task-pipeline/skills/project-audit/scripts/audit.py +11 -0
- package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +71 -54
- package/plugins/task-pipeline/skills/task-pipeline/execution-attempt.schema.json +68 -0
- package/plugins/task-pipeline/skills/task-pipeline/execution-packet.example.json +42 -0
- package/plugins/task-pipeline/skills/task-pipeline/execution-packet.schema.json +217 -0
- package/plugins/task-pipeline/skills/task-pipeline/execution-result.example.json +49 -0
- package/plugins/task-pipeline/skills/task-pipeline/execution-result.schema.json +261 -0
- package/plugins/task-pipeline/skills/task-pipeline/graph.example.json +10 -1
- package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +172 -2
- package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +50 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/acceptance.md +7 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/artifacts.md +23 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/audit.md +6 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/backlog.md +8 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/browser.md +8 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/build.md +32 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/companion-skills.md +14 -3
- package/plugins/task-pipeline/skills/task-pipeline/references/decomposition.md +83 -2
- package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +53 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/documentation.md +3 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/grill.md +27 -8
- package/plugins/task-pipeline/skills/task-pipeline/references/model-tiering.md +19 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/planning.md +203 -26
- package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +26 -8
- package/plugins/task-pipeline/skills/task-pipeline/references/work-graph.md +7 -1
- package/plugins/task-pipeline/skills/task-pipeline/scripts/context_packets.py +686 -0
- package/plugins/task-pipeline/skills/task-pipeline/scripts/execution_authority.py +271 -0
- package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +415 -18
- package/plugins/task-pipeline/skills/task-pipeline/scripts/packet.py +400 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/README.md +2 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/browser-claims.json +54 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/finding-evidence.json +42 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +2 -2
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
# Documentation — the system, not the by-product
|
|
2
|
+
|
|
3
|
+
**One job: make documentation a deliverable with an address, an obligation and a
|
|
4
|
+
gate.** Not "write docs at the end" — a *system*: every settled thing has an id,
|
|
5
|
+
every fact has one home, every kind of change names the documents it owes, and a
|
|
6
|
+
script can say no.
|
|
7
|
+
|
|
8
|
+
This file is the **what and why**. [`gates.md`](gates.md) is how the script that
|
|
9
|
+
enforces it gets written; [`stages.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/stages.md) says where each piece binds.
|
|
10
|
+
|
|
11
|
+
**Governance is a by-product here, never a separate step.** The run already
|
|
12
|
+
produces decisions — the brief's *Decisions locked*, the spec's locked contracts,
|
|
13
|
+
the ADRs the grill writes. Recording one is **transcription plus a stable id**, not
|
|
14
|
+
new thinking. Anything below that feels like ceremony is a sign the register is
|
|
15
|
+
being written twice; write it once, here.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Contents
|
|
20
|
+
|
|
21
|
+
- The canons — what makes a document evidence
|
|
22
|
+
- The inventory — four questions, answered before the first line of work
|
|
23
|
+
- Registers and ids
|
|
24
|
+
- Single source of truth
|
|
25
|
+
- A hand-corrected document drifts back within one run
|
|
26
|
+
- The Doc Loop
|
|
27
|
+
- Changing your mind
|
|
28
|
+
- The propagation matrix
|
|
29
|
+
- Navigation
|
|
30
|
+
- Intent and as-built
|
|
31
|
+
- Registers are shared state
|
|
32
|
+
- Where this binds in the pipeline
|
|
33
|
+
- Rationalizations
|
|
34
|
+
|
|
35
|
+
## The canons — what makes a document evidence
|
|
36
|
+
|
|
37
|
+
Ten laws. Everything else in this file, and the mechanisms in [`gates.md`](gates.md),
|
|
38
|
+
[`learned.md`](learned.md) and [`retrospective.md`](retrospective.md), exist to serve
|
|
39
|
+
them. Where a canon is already enforced by something, the enforcement is **named, not
|
|
40
|
+
restated** — a canon that repeats its own mechanism is the second home this system
|
|
41
|
+
exists to prevent.
|
|
42
|
+
|
|
43
|
+
**1. A claim carries its address.** Every fact that lands in a document names where it
|
|
44
|
+
can be checked: `file:line`, a command with its output, a test name. A lesson names the
|
|
45
|
+
commit that earned it. *"We verified it" is the sentence that passes every review and
|
|
46
|
+
proves nothing.* Where the subject is non-deterministic — an agent, a model call — the
|
|
47
|
+
address is **a trace id and the assertion that ran against it**, because a rerun is not
|
|
48
|
+
the same run and a description of the behaviour is not the behaviour. → the retro's
|
|
49
|
+
SHA-resolution guard; the finding shape in [`setup.md`](setup.md); [`tdd.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/tdd.md) →
|
|
50
|
+
*When the thing under test is an agent*.
|
|
51
|
+
|
|
52
|
+
**2. Numbers are computed, never restated — and an example that instantiates a number
|
|
53
|
+
IS one.** A count in prose is a number that was true once. Derive it at check time and
|
|
54
|
+
compare the stated one against the computed one as the same object. → [`learned.md`](learned.md)
|
|
55
|
+
rule 8.
|
|
56
|
+
|
|
57
|
+
The half that costs more, because it is written by the person who understands the rule:
|
|
58
|
+
**a document quoting a form as an example is indistinguishable from the form.** A release
|
|
59
|
+
note explaining *"the count was written wrongly as `Guards: 412 → 412`"* has just placed a
|
|
60
|
+
second readable count in a section whose count a gate reads — so when the probe removes the
|
|
61
|
+
real one, the narrative still matches and the guard reports green over a section that states
|
|
62
|
+
nothing. Measured three times in one hour on 2026-08-22, each time inside prose *about* this
|
|
63
|
+
very failure: the release note, the board row filed against it, and the repair to the probe.
|
|
64
|
+
|
|
65
|
+
The rule the umbrella already states for commands — **name a dead command, never claim it**
|
|
66
|
+
— holds for a number, a version and a shape. Describe the wrong form; do not write it.
|
|
67
|
+
*"the bold sat around the whole phrase instead of around the second number"* is checkable by
|
|
68
|
+
a reader and invisible to a pattern; the same sentence with the digits in it is a live claim.
|
|
69
|
+
|
|
70
|
+
**3. Every fact has exactly one home.** Other documents link to it; they never restate
|
|
71
|
+
it. Two homes do not disagree on the day they are written — they disagree on the day one
|
|
72
|
+
of them is updated. → *Single source of truth*, below.
|
|
73
|
+
|
|
74
|
+
**4. A reference resolves from where the document is read.** Not from where it lives. A
|
|
75
|
+
link correct in `templates/` and broken everywhere the template is seeded stays green
|
|
76
|
+
under every link checker, because the checker resolves from the file's home. → invariant
|
|
77
|
+
27; the seeded-template guard.
|
|
78
|
+
|
|
79
|
+
**5. Green nobody watched turn red is not evidence.** A check must be seen rejecting a
|
|
80
|
+
planted defect before its pass means anything — and the plant must be proven to have
|
|
81
|
+
landed in the text the check actually parses. **A model used as a judge is the same
|
|
82
|
+
object**: until it has been seen disagreeing with a human label on a case known to be
|
|
83
|
+
bad, its pass is an opinion with a number attached. → [`probing.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/probing.md) →
|
|
84
|
+
*Probing — plant, run, restore*; [`learned.md`](learned.md) rules 4 and 5; [`tdd.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/tdd.md) → *When the
|
|
85
|
+
thing under test is an agent*.
|
|
86
|
+
|
|
87
|
+
**6. A check proves its scope and nothing beyond it.** Every gate carries what it does
|
|
88
|
+
**not** cover, and quoting it wider is how "the gate is green" becomes a false statement
|
|
89
|
+
made in good faith. "The docs are in sync" is a command with an exit code, never a
|
|
90
|
+
sentence at the end of a report. → [`gates.md`](gates.md) → *Before you run a check*.
|
|
91
|
+
|
|
92
|
+
**7. Silence is not a pass.** Ask of any mechanism: what does it print when it did not
|
|
93
|
+
look? If that is indistinguishable from what it prints when it looked and found nothing
|
|
94
|
+
wrong, it is not evidence. → [`gates.md`](gates.md) → *False success*.
|
|
95
|
+
|
|
96
|
+
**8. An estimate is never announced as a measurement.** A rule that fires on a judgement
|
|
97
|
+
states its **evidence condition** — the observable signal that licenses it. A false
|
|
98
|
+
alarm does not cost one interruption; it costs the alarm. A score produced by a model
|
|
99
|
+
is an estimate and stays one in every report that quotes it, however many decimal places
|
|
100
|
+
it carries. → [`continuity.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/continuity.md) → *The context budget*.
|
|
101
|
+
|
|
102
|
+
**9. What was not checked is printed beside what was.** Absence is a finding with one
|
|
103
|
+
side, so it never surfaces by comparison. Carry it as a named, counted set next to every
|
|
104
|
+
verdict — a ratchet, never a TODO — so `PASS` reads as *"green, and here is what nobody
|
|
105
|
+
looked at"*. → [`learned.md`](learned.md) rule 7; [`gates.md`](gates.md) → *Ratchets*.
|
|
106
|
+
|
|
107
|
+
**9a. A measured zero and an unmeasured quantity may not print the same.** Canon 9 says
|
|
108
|
+
carry the absence; this says **refuse the number** when nothing measured it. `0 of 34
|
|
109
|
+
files read` and *the recorder was never installed* are opposite facts, and a `0` claims
|
|
110
|
+
the first while meaning the second — the most reassuring answer available, derived from
|
|
111
|
+
an instrument nobody switched on. So the unmeasured case prints a word, and the word says
|
|
112
|
+
why it cannot be a number.
|
|
113
|
+
The same refusal covers findings: a defect proven by reproduction records
|
|
114
|
+
incidence UNKNOWN — a word, never a zero — and stays a defect;
|
|
115
|
+
`templates/finding-evidence.json` is the minimal schema that keeps the axes apart.
|
|
116
|
+
|
|
117
|
+
The rule is written down because it arrived three times under three names before anyone
|
|
118
|
+
named it: `references/knowledge-graph.md` → *State zero out loud* (a fresh graph must
|
|
119
|
+
still print `current, 0 commits behind`, or freshness is indistinguishable from a harvest
|
|
120
|
+
that never looked); `references/verification.md` → *Staleness* (`unanchored` and
|
|
121
|
+
`unresolvable` are states, not zeroes); and `scripts/graph.py` → `doctrine`, which prints
|
|
122
|
+
`unmeasured` and its reason rather than `0 of 34`, and `next`, which reports how many
|
|
123
|
+
runnable nodes declared no `touches` so that no collision is not read as no collision
|
|
124
|
+
found. Three sites, one rule, and the fourth will be written from this line rather than
|
|
125
|
+
from the same mistake.
|
|
126
|
+
|
|
127
|
+
**10. The document ships in the change that made it true.** Not in the next ticket —
|
|
128
|
+
documentation deferred is documentation that describes a system nobody is running. A
|
|
129
|
+
correction is **appended**, never edited over: a register that is rewritten loses the
|
|
130
|
+
fact that it was ever wrong, which is usually the useful part. → *The Doc Loop*, below.
|
|
131
|
+
|
|
132
|
+
### What these are not
|
|
133
|
+
|
|
134
|
+
They are **epistemic**, not operational: they say what makes a claim documentation, not
|
|
135
|
+
what to do at a trigger. The operational layer is [`learned.md`](learned.md) — each rule
|
|
136
|
+
there carries a trigger, a check and an exit criterion. When the two seem to say the same
|
|
137
|
+
thing, the canon is the *why* and the rule is the *how*; edit the rule, cite the canon.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## The inventory — four questions, answered before the first line of work
|
|
142
|
+
|
|
143
|
+
Stage 0 answers these before the interview, and writes the answers to
|
|
144
|
+
`docs/DOCMAP.md` (seeded from [`../templates/docmap.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/templates/docmap.md),
|
|
145
|
+
**only when absent** — never overwritten):
|
|
146
|
+
|
|
147
|
+
1. **Where do settled things live?** The decision home, and its id scheme.
|
|
148
|
+
2. **What is each fact's single home?** One place per fact; everything else links.
|
|
149
|
+
3. **What does a change of type X oblige?** The propagation matrix.
|
|
150
|
+
4. **What proves it?** The gate command, and what it does *not* cover.
|
|
151
|
+
|
|
152
|
+
A project with no answers gets them seeded. The seeding is itself recorded as the
|
|
153
|
+
first entry in the register, which is the cheapest possible demonstration that the
|
|
154
|
+
register works.
|
|
155
|
+
|
|
156
|
+
**There is no "we don't document" answer.** The four questions have answers in every
|
|
157
|
+
repository — the smallest one still decides *somewhere* that a thing is true — and
|
|
158
|
+
the only choice is whether that answer is written down or re-derived by each new
|
|
159
|
+
reader. What scales down is **volume**, never the rules: a register with three
|
|
160
|
+
entries is a register, and the seeded gate is green on exactly those three
|
|
161
|
+
([`gates.md`](gates.md) → *Progressive arming*).
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Registers and ids
|
|
166
|
+
|
|
167
|
+
**One decision home per project. The doc map names it. Never create a second.**
|
|
168
|
+
|
|
169
|
+
Two shapes satisfy the contract; the difference is physical, not semantic:
|
|
170
|
+
|
|
171
|
+
| Shape | Home | Id | Use when |
|
|
172
|
+
|---|---|---|---|
|
|
173
|
+
| **Register** | `docs/DECISIONS.md`, append-only | `DEC-####` | default; many small decisions, read as a list |
|
|
174
|
+
| **ADR set** | `docs/adr/NNNN-<slug>.md` | `ADR-NNNN` | the project already has `docs/adr/`; decisions are long and each wants a page |
|
|
175
|
+
|
|
176
|
+
**Detect, don't assume:** `docs/adr/` holds at least one `NNNN-*.md` → that is the
|
|
177
|
+
register, record it in the doc map and use it. Otherwise seed
|
|
178
|
+
[`../templates/decisions.md`](../templates/decisions.md). An existing ADR set is
|
|
179
|
+
**never migrated** as a side effect of some other task — migrating is its own
|
|
180
|
+
decision, with its own entry.
|
|
181
|
+
|
|
182
|
+
Both shapes owe the same six things: a **stable id**, an **append-only** history, a
|
|
183
|
+
**status line** with the supersede semantics below, a **`Consequences / affects:`**
|
|
184
|
+
line, a **`Source:`** line carrying the run and the **commit**, and the **edge
|
|
185
|
+
markers**.
|
|
186
|
+
|
|
187
|
+
Open questions get their own register (`docs/OPEN_QUESTIONS.md`, `OQ-####`) with a
|
|
188
|
+
closed status vocabulary: `Open` · `Resolved→DEC-####` · `Dropped (<why>)`.
|
|
189
|
+
|
|
190
|
+
**Two rules that look like formatting and are not:**
|
|
191
|
+
|
|
192
|
+
- **Reference facts by id, never by copying the text.** A copy is a second source
|
|
193
|
+
that nobody will update, and the reader cannot tell which one is current.
|
|
194
|
+
- **Ids are never renumbered and resolved questions are never deleted.** The
|
|
195
|
+
question is the history of the answer; without it the next reader re-litigates a
|
|
196
|
+
settled thing from scratch.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Single source of truth
|
|
201
|
+
|
|
202
|
+
**Every fact has exactly one home. Everything else links to it.**
|
|
203
|
+
|
|
204
|
+
If the same fact is stated in two places, that is a **bug** — collapse it to one
|
|
205
|
+
home and link from the other. Not because duplication is untidy: because the two
|
|
206
|
+
copies will disagree, and at that moment both become unusable, since nobody can
|
|
207
|
+
tell which one moved.
|
|
208
|
+
|
|
209
|
+
- The *decision* lives in the register. Topic docs describe the *current design*
|
|
210
|
+
and cite the id.
|
|
211
|
+
- Each topic (architecture, data model, security, …) has one canonical document.
|
|
212
|
+
- Indexes and summaries **link**; they never restate a rule.
|
|
213
|
+
|
|
214
|
+
### Across repositories
|
|
215
|
+
|
|
216
|
+
**The owning repository decides; a consumer repository describes.** Where a
|
|
217
|
+
consumer document disagrees with the owner, the consumer is wrong — stated rather
|
|
218
|
+
than adjudicated case by case, because case-by-case is how a consumer repo starts
|
|
219
|
+
legislating.
|
|
220
|
+
|
|
221
|
+
The boundary is worth writing out, because an unqualified "the owner always wins"
|
|
222
|
+
is false in one direction: **build state and task status belong to the repository
|
|
223
|
+
doing the work**. A submodule is cloned alone, and a status update must not require
|
|
224
|
+
two repositories.
|
|
225
|
+
|
|
226
|
+
Changing a consumer repo's documentation: compare against the owner's canonical
|
|
227
|
+
doc → look for a contradiction with it *and* with any accepted decision → if the
|
|
228
|
+
consumer document is wrong, fix it in place; if the **owner** is wrong or stale, it
|
|
229
|
+
is corrected there, by a decision entry, through a pull request — and the consumer
|
|
230
|
+
document stays divergent and marked until that lands. Quietly aligning a consumer
|
|
231
|
+
doc to its own view is the failure this paragraph exists to prevent.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## A hand-corrected document drifts back within one run
|
|
236
|
+
|
|
237
|
+
A board, backlog or status document gets corrected during an audit; the same
|
|
238
|
+
contradictions are back inside a day. **Correcting it again is the same
|
|
239
|
+
intervention at the same cost, not a fix.**
|
|
240
|
+
|
|
241
|
+
Measured: four contradictory boards were consolidated into one, every row
|
|
242
|
+
re-checked against its source. Within 24 hours a row settled in code that morning
|
|
243
|
+
read `open` again — in **two** places, because a row listed in a section table and
|
|
244
|
+
again in a summary has to be closed twice. Another called two files missing while
|
|
245
|
+
one had been written five hours earlier. A count quoted from a generated ledger had
|
|
246
|
+
moved and the row had not.
|
|
247
|
+
|
|
248
|
+
**Why the manual pass cannot hold.** A document's claims are never executed. Nothing
|
|
249
|
+
distinguishes a row that **is** true from one that **was** true, so the audit that
|
|
250
|
+
corrects it is the only reader that checks — and it runs once. Between audits the
|
|
251
|
+
document is a set of assertions with no mechanism behind any of them, ageing at the
|
|
252
|
+
speed of the work it describes.
|
|
253
|
+
|
|
254
|
+
So a correction is not done when the rows are right. It is done when **something
|
|
255
|
+
other than the next audit** will notice them going wrong:
|
|
256
|
+
|
|
257
|
+
| The claim | What makes it self-checking |
|
|
258
|
+
|---|---|
|
|
259
|
+
| a row's status | derived from the artefact that settles it, or a gate that fails when the two disagree |
|
|
260
|
+
| a count | computed at check time and printed beside its command — never transcribed |
|
|
261
|
+
| "these files are missing" | resolved against the filesystem by the check that prints it |
|
|
262
|
+
| a row in two tables | one table, or a guard asserting the pair agrees |
|
|
263
|
+
|
|
264
|
+
Where a claim genuinely cannot be derived, **say that in the row** — an assertion
|
|
265
|
+
marked as unverifiable is honest, and the next reader stops treating it as measured.
|
|
266
|
+
Silently correcting it a second time is how a document teaches its readers that
|
|
267
|
+
somebody else is checking.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## The Doc Loop
|
|
272
|
+
|
|
273
|
+
**Fires whenever something is settled — at any stage.** Scope, a contract, a name,
|
|
274
|
+
a policy, a status vocabulary, a price, a retention window. Not only at stage 9.
|
|
275
|
+
|
|
276
|
+
1. **Orient and reconcile.** Read the register and the topic doc. Run the
|
|
277
|
+
intent/as-built reconcile (below). Do not contradict an accepted decision
|
|
278
|
+
without superseding it. *Skipping this is how a run spends a day building
|
|
279
|
+
against a system that does not exist.*
|
|
280
|
+
2. **Reserve the id, then record.** Reading "Next free ID" is **not** reserving it
|
|
281
|
+
(see *Registers are shared state*). Then write the entry: date, status, context,
|
|
282
|
+
decision, consequences, source with the commit.
|
|
283
|
+
3. **Resolve.** Flip every answered question to `Resolved→<id>`. Never delete it.
|
|
284
|
+
4. **Propagate.** Walk the matrix row for this change type and update every
|
|
285
|
+
document it names, **in the same change**. Keep SSOT: the detail in one home,
|
|
286
|
+
links from the rest.
|
|
287
|
+
5. **Adjust scope.** Roadmap, MVP, module map — if scope moved.
|
|
288
|
+
6. **Record as-built.** What was actually built, with the ids and the files. Then
|
|
289
|
+
reconcile again.
|
|
290
|
+
7. **Commit.** One focused commit, conventional message, **the ids in the subject**.
|
|
291
|
+
|
|
292
|
+
**Finishing the chat answer is not finishing the task.** Closing the loop is. A
|
|
293
|
+
decision that lives only in a spec dies with that spec; one that lives only in the
|
|
294
|
+
conversation was never made.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Changing your mind
|
|
299
|
+
|
|
300
|
+
The register is **append-only**. To reverse or replace:
|
|
301
|
+
|
|
302
|
+
- add a **new** entry stating the new decision and naming what it replaces;
|
|
303
|
+
- edit **only the status line** of the old entry;
|
|
304
|
+
- leave the old body intact as history.
|
|
305
|
+
|
|
306
|
+
**A partial supersede annotates both sides.** Most reversals are partial — a later
|
|
307
|
+
decision replaces one clause and leaves the rest standing. If the old entry keeps a
|
|
308
|
+
bare `Accepted`, a reader who opens only that entry gets an answer that is no longer
|
|
309
|
+
true. So the new entry names which clause it replaces, and the old entry's status
|
|
310
|
+
line gains `· **Partially superseded by <id>** — <one line>`.
|
|
311
|
+
|
|
312
|
+
**Three markers, and they mean different things:**
|
|
313
|
+
|
|
314
|
+
| Marker | Meaning | Target's status line annotated? |
|
|
315
|
+
|---|---|---|
|
|
316
|
+
| `Refines:` | **additive only** — every clause of the target still holds | no |
|
|
317
|
+
| `Contradicts:` | a **named clause** of the target no longer holds | **yes** |
|
|
318
|
+
| `Supersedes:` | the whole target is retired | **yes** |
|
|
319
|
+
|
|
320
|
+
One word for "adds to" and "replaces a clause of" is unenforceable. Measured on the
|
|
321
|
+
project this practice comes from: across **275** refine/supersede edges, **204**
|
|
322
|
+
pointed at a target with no annotation — which is not 204 violations, because most
|
|
323
|
+
were additive. *That ambiguity is the defect*: neither a reader nor a script could
|
|
324
|
+
tell which of the 204 should have been annotated, so the rule could not be gated at
|
|
325
|
+
all.
|
|
326
|
+
|
|
327
|
+
**Existing edges are not retro-classified.** Each needs a judgement about what its
|
|
328
|
+
author meant, and a bulk pass would guess. An edge is reclassified when someone
|
|
329
|
+
touches it for another reason.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## The propagation matrix
|
|
334
|
+
|
|
335
|
+
The harvest ledger ([`knowledge-sources.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md)) names the
|
|
336
|
+
documents you **read**. The matrix names the documents you **owe**. They are not
|
|
337
|
+
the same list, and the gap between them is where documentation rots: the document
|
|
338
|
+
nobody read is exactly the document nobody updated.
|
|
339
|
+
|
|
340
|
+
**Build it in five steps** (stage 0; extend it whenever a new doc class appears):
|
|
341
|
+
|
|
342
|
+
0. **Write the meta-row first: *a new document or rule*.** The most frequent change
|
|
343
|
+
in any documented project is adding a document, and it is the row nobody writes —
|
|
344
|
+
so the matrix ends up unable to catch the class it will meet most often. Its
|
|
345
|
+
*Update these* column is every surface that must **learn the thing exists**: the
|
|
346
|
+
index a reader opens, the map, any manifest, the agent-facing rules file.
|
|
347
|
+
Measured on the project this practice comes from: **nine findings across five
|
|
348
|
+
audits were that one missing row**, and the checks were green throughout, because
|
|
349
|
+
a check can only walk the list it was given.
|
|
350
|
+
1. List the project's doc classes — one line each: what is this the home of?
|
|
351
|
+
2. For each **change type** the project can undergo, name every document that must
|
|
352
|
+
move.
|
|
353
|
+
3. For each row, name the **check** that would notice if it did not — or write
|
|
354
|
+
`review` *with a one-line reason why no check can decide it*.
|
|
355
|
+
4. Write the rows into `docs/DOCMAP.md` → *Propagation matrix*.
|
|
356
|
+
5. Arm the mechanical half in the gate: **a document named in an entry's
|
|
357
|
+
`Consequences / affects:` line must cite that entry.**
|
|
358
|
+
|
|
359
|
+
A row with an empty third column is a **finding**, not a blank. Either a check
|
|
360
|
+
exists, or somebody has said out loud that none can.
|
|
361
|
+
|
|
362
|
+
**The backlog is ratcheted, and that is the design.** Turning this check on in an
|
|
363
|
+
existing repository finds a lot: **162** missing propagations across **73**
|
|
364
|
+
decisions, on the project this comes from — not the four the audit had reported.
|
|
365
|
+
Failing on all of them makes the gate something people switch off, and bulk-fixing
|
|
366
|
+
them blind adds 162 citations nobody verified. So: entries from a **floor** id
|
|
367
|
+
onward fail; everything older is a counted backlog that may only shrink, printed on
|
|
368
|
+
every run. Raising the floor is a decision, and it belongs in the register.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Navigation
|
|
373
|
+
|
|
374
|
+
**One definition per entity, and a mention links to the definition.**
|
|
375
|
+
|
|
376
|
+
- Every definition carries an explicit anchor.
|
|
377
|
+
- A mention links to the **anchor**, not the file. A file link makes the reader
|
|
378
|
+
search; a deep link that rots is caught by the gate.
|
|
379
|
+
- **Indexes never restate a rule.** They fall behind and then they lie with
|
|
380
|
+
authority — a navigation aid that omits an entry is worse than none, because a
|
|
381
|
+
reader concludes the entry does not exist.
|
|
382
|
+
|
|
383
|
+
A deep link is worth more than a file link *and* fails harder, so it only pays with
|
|
384
|
+
a check behind it. Land the anchor check with the first rewritten link, not after
|
|
385
|
+
the sweep.
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Intent and as-built
|
|
390
|
+
|
|
391
|
+
Two records, deliberately not merged:
|
|
392
|
+
|
|
393
|
+
| Record | Says | Written by |
|
|
394
|
+
|---|---|---|
|
|
395
|
+
| **Intent** — the registers, the spec, the plan | how it *should* be | the Doc Loop |
|
|
396
|
+
| **As-built** — the run record | how it *turned out* | step 6, at the end |
|
|
397
|
+
|
|
398
|
+
**Reconcile both before starting and after finishing.** Every divergence has one of
|
|
399
|
+
three resolutions: the document is stale, the record is wrong, or they genuinely
|
|
400
|
+
disagree and that is a decision to make. There is no fourth, and "I'll keep it in
|
|
401
|
+
mind" is not one of them.
|
|
402
|
+
|
|
403
|
+
Where a coordination tool is installed it does this for you. Where it is not, the
|
|
404
|
+
as-built record is a section of the carry-over ledger and the reconcile is a read
|
|
405
|
+
of it — **the tool is optional, the discipline is not**.
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## Registers are shared state
|
|
410
|
+
|
|
411
|
+
A register is the one file two agents will write in the same minute.
|
|
412
|
+
|
|
413
|
+
- **Reserve the id before minting it.** "Next free ID" is a *reading*; a second
|
|
414
|
+
agent reading it in the same minute gets the same answer, and now two entries
|
|
415
|
+
carry one number.
|
|
416
|
+
- **Take a lease before writing a guarded register**, where a lease mechanism
|
|
417
|
+
exists. [`hooks.md`](hooks.md) is how such a guard blocks the edit;
|
|
418
|
+
[`companion-skills.md`](https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/references/companion-skills.md) names the optional companion that
|
|
419
|
+
implements one.
|
|
420
|
+
- **Ask what two instances with the same identity would do**, and make the tool
|
|
421
|
+
answer it. This is [`learned.md`](learned.md) rule 15, and it is in that table
|
|
422
|
+
because it cost an entire day of work performed under another session's identity.
|
|
423
|
+
- **When nothing can arbitrate, the run is `ungated` — say so out loud.** That is
|
|
424
|
+
a real state, not a formality. Describing a project as protected while nothing
|
|
425
|
+
enforces it is worse than having no protection, because everyone downstream
|
|
426
|
+
believes the guarantee.
|
|
427
|
+
- **A register declared against a backend that cannot reserve is a register in name
|
|
428
|
+
only, and its presence is what stops the manual procedure being written.** Measured
|
|
429
|
+
2026-08-15: a project declared three id registers over a local-filesystem backend
|
|
430
|
+
whose `reserve` correctly refuses — *pretending would hand two agents the same id* —
|
|
431
|
+
and two sessions filed a different `B-073` on the same afternoon. The tool was honest;
|
|
432
|
+
the *declaration* was the problem, because a capability that appears to exist is one
|
|
433
|
+
nobody replaces. Where reservation is not available, write the three-step manual
|
|
434
|
+
allocation down where an agent reads it, and make it follow the lease:
|
|
435
|
+
1. take the lease on the register's file **first**;
|
|
436
|
+
2. compute the next id from the **committed** file — `git show HEAD:<file>` — never
|
|
437
|
+
from a working copy, which holds your own unpushed row and hides somebody else's;
|
|
438
|
+
3. write and **commit** before releasing the lease. An id held only in an uncommitted
|
|
439
|
+
file is an id nobody else can see you took.
|
|
440
|
+
- **A version number is the same class with no register at all.** Two branches both
|
|
441
|
+
claimed one version on that same afternoon because each incremented from what its own
|
|
442
|
+
checkout knew. Read the remote — `git ls-remote --tags` — because that list is the only
|
|
443
|
+
place the answer lives.
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Where this binds in the pipeline
|
|
448
|
+
|
|
449
|
+
| Point | What happens | Gate |
|
|
450
|
+
|---|---|---|
|
|
451
|
+
| **Stage 0**, phase 1b | the inventory — the four questions, into `docs/DOCMAP.md`; the regime recorded | manual |
|
|
452
|
+
| **Stage 0**, phase 1c | intent vs as-built reconciled; every divergence resolved | manual |
|
|
453
|
+
| **Any stage** | something is settled → the Doc Loop, all seven steps | the stage's own |
|
|
454
|
+
| **Stage 9** | the propagation sweep, the registers, the gate green with its ratchets printed | auto |
|
|
455
|
+
| **Stage 10** | the gate itself proven — every check seen failing once against a planted defect | manual |
|
|
456
|
+
|
|
457
|
+
---
|
|
458
|
+
|
|
459
|
+
## Rationalizations
|
|
460
|
+
|
|
461
|
+
| Excuse | Reality |
|
|
462
|
+
|---|---|
|
|
463
|
+
| "It's a small project, a register is overkill" | A register with three entries costs three minutes and is the only reason the fourth decision can be found. What people mean by overhead is *ceremony*, and none is required here — the entries are transcribed from artefacts the run already produced. |
|
|
464
|
+
| "I'll write the decision up at the end" | At the end you remember the outcome and not the alternatives you rejected, which is the only part with any value later. |
|
|
465
|
+
| "The spec already says it" | A spec is per-run and the next one supersedes it. A decision outlives every artefact that mentions it. |
|
|
466
|
+
| "I updated the docs I touched" | The matrix names the documents you did **not** touch. That is the entire reason it exists. |
|
|
467
|
+
| "Two docs saying the same thing is harmless" | Until they disagree — and then both are unusable, because nobody can tell which one moved. |
|
|
468
|
+
| "I'll just fix the old decision's text" | Then the reason someone chose it is gone and the next person re-litigates it from scratch. Supersede; never edit the body. |
|
|
469
|
+
| "It's obviously additive, no need to mark it" | 204 of 275 edges were left unmarked on exactly that reasoning, and afterwards nobody could tell which of them should have been. The marker costs one word. |
|
|
470
|
+
| "Nobody else is working in this repo right now" | You cannot know that from inside your session, and being wrong means two entries with one id. |
|
|
471
|
+
| "The gate is green, so the docs are fine" | The gate proves what it checks. Read its scope header before quoting it as evidence. |
|
|
472
|
+
| "The doc is stale but that's not this task" | Then it is a row in the carry-over ledger with the exact edit, right now. A staleness noticed and unrecorded is the next run's false premise. |
|