task-pipeline-skill 1.85.2 → 1.86.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/CONTRIBUTING.md +2 -2
  3. package/README.md +2 -1
  4. package/SKILL-CARD.md +1 -1
  5. package/bin/task-pipeline.js +70 -9
  6. package/evals/cases/evidence-docs.json +188 -0
  7. package/evals/cases/project-audit.json +188 -0
  8. package/evals/cases/task-pipeline.json +191 -0
  9. package/package.json +5 -4
  10. package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
  11. package/plugins/task-pipeline/skills/evidence-docs/SKILL.md +16 -11
  12. package/plugins/task-pipeline/skills/evidence-docs/references/GENERATED.md +8 -0
  13. package/plugins/task-pipeline/skills/evidence-docs/references/documentation.md +472 -0
  14. package/plugins/task-pipeline/skills/evidence-docs/references/gates.md +645 -0
  15. package/plugins/task-pipeline/skills/evidence-docs/references/hooks.md +279 -0
  16. package/plugins/task-pipeline/skills/evidence-docs/references/learned.md +292 -0
  17. package/plugins/task-pipeline/skills/evidence-docs/references/retrospective.md +551 -0
  18. package/plugins/task-pipeline/skills/evidence-docs/references/setup.md +149 -0
  19. package/plugins/task-pipeline/skills/evidence-docs/templates/decisions.md +50 -0
  20. package/plugins/task-pipeline/skills/evidence-docs/templates/docgate.sh +537 -0
  21. package/plugins/task-pipeline/skills/project-audit/SKILL.md +66 -25
  22. package/plugins/task-pipeline/skills/project-audit/scripts/audit.py +11 -0
  23. package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +71 -54
  24. package/plugins/task-pipeline/skills/task-pipeline/execution-attempt.schema.json +68 -0
  25. package/plugins/task-pipeline/skills/task-pipeline/execution-packet.example.json +42 -0
  26. package/plugins/task-pipeline/skills/task-pipeline/execution-packet.schema.json +217 -0
  27. package/plugins/task-pipeline/skills/task-pipeline/execution-result.example.json +49 -0
  28. package/plugins/task-pipeline/skills/task-pipeline/execution-result.schema.json +261 -0
  29. package/plugins/task-pipeline/skills/task-pipeline/graph.example.json +10 -1
  30. package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +172 -2
  31. package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +50 -1
  32. package/plugins/task-pipeline/skills/task-pipeline/references/acceptance.md +7 -0
  33. package/plugins/task-pipeline/skills/task-pipeline/references/artifacts.md +23 -0
  34. package/plugins/task-pipeline/skills/task-pipeline/references/audit.md +6 -0
  35. package/plugins/task-pipeline/skills/task-pipeline/references/backlog.md +8 -1
  36. package/plugins/task-pipeline/skills/task-pipeline/references/browser.md +8 -0
  37. package/plugins/task-pipeline/skills/task-pipeline/references/build.md +32 -0
  38. package/plugins/task-pipeline/skills/task-pipeline/references/companion-skills.md +14 -3
  39. package/plugins/task-pipeline/skills/task-pipeline/references/decomposition.md +83 -2
  40. package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +53 -0
  41. package/plugins/task-pipeline/skills/task-pipeline/references/documentation.md +3 -0
  42. package/plugins/task-pipeline/skills/task-pipeline/references/grill.md +27 -8
  43. package/plugins/task-pipeline/skills/task-pipeline/references/hooks.md +10 -5
  44. package/plugins/task-pipeline/skills/task-pipeline/references/model-tiering.md +19 -0
  45. package/plugins/task-pipeline/skills/task-pipeline/references/planning.md +203 -26
  46. package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
  47. package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +26 -8
  48. package/plugins/task-pipeline/skills/task-pipeline/references/work-graph.md +7 -1
  49. package/plugins/task-pipeline/skills/task-pipeline/scripts/context_packets.py +686 -0
  50. package/plugins/task-pipeline/skills/task-pipeline/scripts/execution_authority.py +271 -0
  51. package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +415 -18
  52. package/plugins/task-pipeline/skills/task-pipeline/scripts/packet.py +400 -0
  53. package/plugins/task-pipeline/skills/task-pipeline/templates/README.md +2 -0
  54. package/plugins/task-pipeline/skills/task-pipeline/templates/browser-claims.json +54 -0
  55. package/plugins/task-pipeline/skills/task-pipeline/templates/finding-evidence.json +42 -0
  56. package/plugins/task-pipeline/skills/task-pipeline/templates/hooks.example.json +2 -2
  57. package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +2 -2
@@ -15,7 +15,7 @@ coming back to the operator.
15
15
  ## Contents
16
16
 
17
17
  - Phase 1 — harvest before you ask
18
- - Phase 2 — the loop
18
+ - Phase 2 — the gap check, then the loop
19
19
  - Domain awareness
20
20
  - The autonomy sweep
21
21
  - The design destination — one file, decided here, never invented later
@@ -42,11 +42,28 @@ Everything below runs against that harvest. An answer you can't check against a
42
42
  source is a recollection, and the whole loop exists to stop the run from building
43
43
  on one.
44
44
 
45
- ## Phase 2 — the loop
46
-
47
- Interview the operator relentlessly about every aspect of the task until you reach
48
- a **shared understanding**. Walk down each branch of the decision tree, resolving
49
- dependencies between decisions one by one.
45
+ ## Phase 2 — the gap check, then the loop
46
+
47
+ **Phase 2 opens with a verdict, not a question.** Walk the decision tree against
48
+ the harvest and the request FIRST and mark every branch: **answered** (the
49
+ request, the code, an ADR, a past brief or the wiki already decides it — record
50
+ the source, do not re-ask), **immaterial** (either answer ships the same work —
51
+ decide it yourself and note it), or **material unknown** (the answer changes
52
+ what gets built, is expensive to reverse, or would stop the run later). Only the
53
+ third kind earns a question. **A complete brief yields zero intake questions**
54
+ — the grill's output is then the brief itself, and going around the loop anyway
55
+ is re-negotiating what is already decided, which costs a human round and buys
56
+ nothing.
57
+
58
+ **A material unknown the operator cannot answer now** does not hold the whole
59
+ intake open: it becomes **one bounded decision task** — a named node in the
60
+ plan with the question, the options, the recommendation and the latest date it
61
+ can be decided without rework — and the run proceeds on the branches that do
62
+ not depend on it.
63
+
64
+ Where material unknowns remain, interview the operator about THOSE until you
65
+ reach a **shared understanding**. Walk down each unresolved branch of the
66
+ decision tree, resolving dependencies between decisions one by one.
50
67
 
51
68
  1. **One question per turn.** Never bundle. Wait for the answer before the next.
52
69
  2. **Recommend an answer with every question** (+ a one-line rationale). "What do
@@ -58,8 +75,10 @@ dependencies between decisions one by one.
58
75
  decisions first, so later answers don't invalidate earlier ones.
59
76
  5. **Reconcile contradictions immediately**, and chase dodges: "we'll decide
60
77
  later" → "what's the latest you can decide and still ship?"
61
- 6. **Cover the autonomy sweep** (below). An unasked question is not neutral — it
62
- is a scheduled interruption at stage 6.
78
+ 6. **Cover the autonomy sweep** (below). An unasked MATERIAL question is not
79
+ neutral — it is a scheduled interruption at stage 6. An answered or
80
+ immaterial one asked anyway is not neutral either — it is a human round
81
+ spent confirming what the sources already said.
63
82
 
64
83
  **Stop** when a re-scan surfaces no new branches. Don't grill past diminishing
65
84
  returns: genuinely reversible calls can be deferred with a note.
@@ -129,8 +129,13 @@ machine, and the first surprising denial is debugged in the wrong project.
129
129
  ```
130
130
 
131
131
  - a tool-name pattern (`Edit|Write|…`), or `"*"` for every call;
132
- - for a specific shell command, add `"if": "Bash(git commit *)"` beside
133
- `"matcher": "Bash"`.
132
+ - for a specific shell command, add `"if": "Bash(git commit *)"` **inside the
133
+ handler object**, beside `"type"` and `"command"` — never beside `"matcher"`.
134
+ A matcher group is only `matcher` + `hooks`; a key Claude Code does not know
135
+ there is ignored, and from 2.1.270 announced at every session start as
136
+ `hooks.json: unknown key "if" … ignored`. This skill's own template carried it
137
+ at group level until v1.86.2, so its gate filtered nothing and ran on every
138
+ Bash call.
134
139
 
135
140
  `if` uses **permission-rule syntax** (`Bash(git *)`, `Edit(*.ts)`) and is evaluated
136
141
  **only on tool events** — `PreToolUse`, `PostToolUse`, `PostToolUseFailure`,
@@ -177,9 +182,9 @@ the project's `.claude/settings.json`.
177
182
 
178
183
  ```json
179
184
  { "hooks": { "PreToolUse": [
180
- { "matcher": "Bash", "if": "Bash(git commit *)",
181
- "hooks": [{ "type": "command", "shell": "bash", "timeout": 60,
182
- "command": "bash scripts/check-docs.sh >&2 || exit 2" }] } ] } }
185
+ { "matcher": "Bash",
186
+ "hooks": [{ "type": "command", "if": "Bash(git commit *)", "shell": "bash",
187
+ "timeout": 60, "command": "bash scripts/check-docs.sh >&2 || exit 2" }] } ] } }
183
188
  ```
184
189
 
185
190
  `|| exit 2` is the contract, not a flourish: without it the gate's own `exit 1`
@@ -30,6 +30,25 @@ even be on the same provider. So:
30
30
  environment has no Opus-class model, the best available one is the right answer —
31
31
  say which one you settled on and keep going.
32
32
 
33
+ ## The operator's explicit choice is inherited, verbatim
34
+
35
+ **Advice and choice are different things, and the second wins.** The
36
+ recommendation above is ADVICE — printed once at preflight. A model or effort
37
+ the operator has set explicitly (`/model`, `/fast`, a config entry, an answer
38
+ at preflight) is the CHOICE, and the plan, every stage and every subagent
39
+ inherit it unchanged. **Task size is not a basis for switching**: a large task
40
+ does not upgrade the model, a mechanical stage does not downgrade it — the only
41
+ thing that changes the model mid-run is an override the operator RECORDED, with
42
+ its basis, in the per-stage map. A switch nobody recorded is a defect, whatever
43
+ it saved.
44
+
45
+ **An unsupported capability is its own line, never a silent swap.** When the
46
+ confirmed model cannot do what a stage needs — vision it lacks, a context
47
+ window the material exceeds, a tool the tier does not offer — the run states
48
+ that limitation by NAME, records it in the brief, and asks (or proceeds with
49
+ the gap named). Substituting a different model to cover the gap without the
50
+ operator's say-so is the same defect as the silent downgrade.
51
+
33
52
  ## Mechanic — confirm at preflight, then stop asking
34
53
 
35
54
  Once, as part of the preflight (before stage 0):
@@ -19,7 +19,11 @@ Built into this skill; nothing to install.
19
19
  - No placeholders
20
20
  - Self-review — before handing off
21
21
  - This stage settles nothing — and that is a rule, not an omission
22
+ - The UI handoff annex — a packet an executor can build without re-deriving
23
+ - Pre-dispatch — the last gate before a claim
24
+ - The leaf compiler — a slice survives a cold reader or it does not dispatch
22
25
  - GATE (auto)
26
+ - Execution packets
23
27
 
24
28
  ## Audience
25
29
 
@@ -28,6 +32,12 @@ this toolset, has questionable taste, and will read **only their own task**.
28
32
  Everything they need is in that task: exact paths, complete code, exact commands,
29
33
  expected output. DRY. YAGNI. TDD. Frequent commits.
30
34
 
35
+ For independently dispatched agents, "that task" includes the resolved context
36
+ packet in [Execution packets](#execution-packets): relevant program/module
37
+ constraints, versioned interfaces, decisions and source digests travel with it.
38
+ Do not assume the executor has read a plan header or inherited the planning chat.
39
+ Planning may hand off at plan-ready without claiming implementation is complete.
40
+
31
41
  Path: `<artifacts>/plans/YYYY-MM-DD-<topic>.md` — same `<topic>` slug as the
32
42
  brief and the spec.
33
43
 
@@ -52,24 +62,26 @@ what each one owns. This is where decomposition gets locked in:
52
62
  into **parallel groups** in topological order, and tag each task
53
63
  `depends: [task ids]`.
54
64
 
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:
65
+ **Then run the fake-edge test over what you just drew.** Keep dependencies that
66
+ carry data, an enforceable control condition, or resource ordering. Mere sequence
67
+ is not enough. Test each edge before assigning a parallel group:
58
68
 
59
69
  1. Write every task as a box.
60
70
  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.
71
+ 3. Ask what fails if B starts before A: missing output, unmet approval/control
72
+ condition, or conflicting ownership of a mutable resource?
73
+ 4. Keep a justified edge and write its kind plus concrete payload/condition in
74
+ the `Carries` cell: `data: schema v2`, `control: review accepted`, or
75
+ `resource: release write lease on shared registry`.
76
+ 5. Remove an edge only if none of those reasons applies. No data payload alone
77
+ does not make an edge fake. Do not remove approval or ownership constraints.
78
+ 6. Nodes without incoming dependencies are candidates for group A; capability
79
+ and resource checks still determine whether they can start together.
80
+
81
+ **The stated dependency is reviewable.** An empty `Carries` cell requests a reason,
82
+ not automatic deletion. Keep a justified dependency, remove accidental ordering,
83
+ and leave an unresolved dependency blocked until its condition is understood.
84
+ There is no target number of edges to remove.
73
85
 
74
86
  **File ownership is exclusive within a group.** No two tasks in the same parallel
75
87
  group write the same file — that is the rule that makes stage-5 fan-out safe.
@@ -140,15 +152,15 @@ verbatim from the spec. Every task's requirements implicitly include this sectio
140
152
  | Group | Tasks | Runs after | Carries |
141
153
  |---|---|---|---|
142
154
  | A | 1, 2 | — | — |
143
- | B | 3 | A | <what crosses this edge: the file, signature, decision or value B consumes> |
155
+ | B | 3 | A | <kind: payload, control condition or resource ordering B requires> |
144
156
 
145
157
  ---
146
158
  ```
147
159
 
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.
160
+ **The `Carries` cell is required on every edge and empty only on group A.**
161
+ Record `data`, `control` or `resource` and its concrete condition. An unexplained
162
+ edge blocks dispatch until justified or removed after review; never delete an
163
+ approval/resource edge merely because it carries no file or value.
152
164
 
153
165
  ## Task structure — required
154
166
 
@@ -240,9 +252,9 @@ A checklist you run yourself, inline. No subagent:
240
252
  `clearFullLayers()` in Task 7 is a bug, not a style difference.
241
253
  5. **Parallel safety and the fake-edge test:** no two tasks in the same group write
242
254
  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.
255
+ task that produces the input or establishes the required condition, and every edge's `Carries` cell is
256
+ filled. Count retained edges by kind and record removed edges with reasons.
257
+ Zero removals is valid when every original dependency is justified.
246
258
  6. **DoD present and verifiable** on every task.
247
259
  7. **Every command, path and file a DoD names resolves.** Walk each task's
248
260
  *Definition of done* and its steps and check the targets exist — a DoD that says
@@ -270,7 +282,7 @@ before the gate; every line a **computed number, not a tick**.
270
282
  - Decisions: checked against <the brief's D-table> and <stage 2's rejected options> — <verdict>
271
283
  - Cost: <surfaces>/<guards>/<REQ> now, <…> at stage 2 — <proportionate | grown, and why>
272
284
  - Hygiene: <n> checks, <n> findings, <n> open
273
- - Edges: <n> declared, <n> carry data, <n> removed
285
+ - Edges: <n> declared, <n> data, <n> control, <n> resource, <n> removed with reasons
274
286
  - Placeholders: <n> · Ambiguity: <n> found, <n> resolved inline
275
287
  ```
276
288
 
@@ -287,6 +299,52 @@ back to stage 3 and is recorded there; a scope question goes back to the operato
287
299
  A decision first made while sequencing tasks is a decision nothing downstream will
288
300
  ever find, because nobody reads a plan after the build.
289
301
 
302
+ ## The UI handoff annex — a packet an executor can build without re-deriving
303
+
304
+ A packet whose work is a screen carries a UI ANNEX beside its context: the
305
+ state IDs it touches, the components it reuses and the props they take, the
306
+ tokens and content strings, the accessibility requirements, and the exact
307
+ asset versions. With it, an executor implements the fixture without going
308
+ back to re-derive the visual spec; without it, the same work is re-decided
309
+ per session and drifts. The annex ADDS to the task context — it never
310
+ replaces the scheduler's claim or fence (that is `agent-sync`'s job, not the
311
+ packet's), and a stale visual spec (an asset version or a token that moved
312
+ under the plan) triggers a packet REVISION exactly as a moved source input
313
+ does, never a silent dispatch against old pixels.
314
+
315
+ The annex is a DOMAIN annex, optional by domain: a screen packet carries it,
316
+ a migration or a CLI packet does not — a non-UI task owes no visual spec,
317
+ and demanding one would be the mirror of the omission it fixes.
318
+
319
+ ## Pre-dispatch — the last gate before a claim
320
+
321
+ Before a compiled leaf is claimed and worked
322
+ (`scripts/context_packets.py predispatch`), it passes one final check: every
323
+ input's digest is re-verified against the bytes on disk NOW (source drift
324
+ blocks — the plan was made against other bytes), each data prerequisite's
325
+ output must be materialized, the PRIMARY context must fit its budget (a
326
+ breach BLOCKS and is never a silent truncation — the budget cuts appendix,
327
+ never primary), and the declared capability and coordination claim must be
328
+ present. Any failure blocks the claim and names itself; nothing is trimmed
329
+ to fit.
330
+
331
+ ## The leaf compiler — a slice survives a cold reader or it does not dispatch
332
+
333
+ Where the plan is compiled into execution packets
334
+ (`scripts/context_packets.py compile-leaf`), each outcome slice carries its
335
+ resolved decisions (bound by address+digest — an unresolved decision
336
+ dispatches NO leaf), its exact scope, its mapping onto the parent's
337
+ acceptance, and its material split into budgeted primary vs appendix — a
338
+ budget cuts appendix only and records the cut, never acceptance. The test of
339
+ a compiled packet is the **cold reader**: with no author history, the packet
340
+ alone answers eight questions — goal, inputs, decisions, scope, outputs,
341
+ acceptance, guards, resume (`readiness`); a missing version or output
342
+ contract fails readiness. Acceptance names at least one positive and one
343
+ negative case. A slice is selected by its explicit id, never by mtime; and
344
+ neither a design flow nor a `.design/TASKS.md` becomes a parallel plan
345
+ authority — leaves come from the plan through the compiler or they are not
346
+ leaves.
347
+
290
348
  ## GATE (auto)
291
349
 
292
350
  **Set equality first:** the REQ ids in the brief equal the union of `Implements:`
@@ -298,6 +356,125 @@ Then: every spec requirement maps to a task; no placeholders; names and types
298
356
  consistent across tasks; parallel-group tasks share no files **or other mutable
299
357
  target**; each task has a verifiable DoD. **Every edge in the *Execution order*
300
358
  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
359
+ computed** — each retained edge names data, control or resource semantics. An
360
+ unexplained edge blocks the gate until justified or safely removed. UI tasks carry their scenario IDs and `SCR-` screens. Verify all
303
361
  of it yourself and stop on failure — this gate has no operator in it.
362
+
363
+ ## Execution packets
364
+
365
+ Size independent-executor tasks with [`decomposition.md`](decomposition.md) →
366
+ Executor-sized tasks and context. Keep parent findings/features as containers;
367
+ dispatch only leaves with resolved material decisions and budgeted primary context.
368
+
369
+
370
+ Use this contract when research, intake, specification and planning happen in one
371
+ agent, while other agents execute individual tasks, or when a host pipeline owns
372
+ dispatch. It is an artifact and workflow contract. It does not claim that the
373
+ bundled graph CLI is a distributed scheduler or that it implements the fields
374
+ below as commands.
375
+
376
+ ### Roles and boundaries
377
+
378
+ The planning agent harvests sources, resolves material decisions, produces the
379
+ program/module model, specifications, task packets and their dependencies. It may
380
+ finish at **plan-ready**. That state means the plan is available for execution;
381
+ it does not mean the requested product is implemented.
382
+
383
+ An executor receives one task and its resolved context. It does not restart
384
+ intake or independently redesign settled interfaces. If the packet conflicts with
385
+ source reality, it returns a change proposal with evidence to the planner rather
386
+ than silently editing a shared plan. A reviewer evaluates the produced artifact;
387
+ an integrator reconciles compatible outputs and owns the final delivery boundary.
388
+ These are roles, not hardcoded models or host-specific subagent names.
389
+
390
+ ### The context closure a task must carry
391
+
392
+ Persist a program brief and decisions, a module/interface map, shared contracts,
393
+ and one task packet per independently reviewable deliverable. Each packet names:
394
+
395
+ - Stable task, program and module IDs; its requirement and finding IDs.
396
+ - The relevant program constraints and module boundaries, as explicit inputs.
397
+ - Decisions with provenance, rationale, rejected alternatives and change triggers.
398
+ - Every consumed/produced interface, including its version and responsible task.
399
+ - Source repository, base revision and digests for the files/inputs it relies on.
400
+ - Files to read, files permitted to change, new files explicitly marked Create,
401
+ and shared mutable resources. A directory name is not a complete ownership claim.
402
+ - Concrete implementation sequence, invariants and edge cases; exact code where
403
+ a signature or algorithm must be settled, without pretending speculative code
404
+ was tested against a future tree.
405
+ - Acceptance checks, required evidence type, scope exclusions and rollback.
406
+ - Output/return format, reviewer/integrator destination and context budget.
407
+
408
+ A linked file is useful only if the receiving agent can fetch it at the recorded
409
+ revision. Resolve required links before dispatch; a missing required contract
410
+ blocks dispatch, while optional context is labelled optional. Do not silently
411
+ truncate required constraints to fit a token budget. Produce a smaller coherent
412
+ task or move background material to retrievable references.
413
+
414
+ Priority, dependency readiness, context completeness and implementation status
415
+ are separate fields. An urgent row can be blocked; a detailed packet can still
416
+ depend on an unfinished contract. Never translate either into "ready" by prose.
417
+
418
+ ### Dispatch, retries and changed inputs
419
+
420
+ Before dispatch, verify the packet's inputs and predecessor outputs against their
421
+ current digests. Changed relevant input makes the packet stale until it is
422
+ reconciled; an unrelated file change need not invalidate the whole program.
423
+ Record a new packet revision rather than rewriting the executor's historical input.
424
+
425
+ The host adapter must establish one execution attempt: task ID, packet revision,
426
+ attempt ID, owner, resource scope, expiry/heartbeat when applicable, and a fencing
427
+ token for takeover. A file lock protecting JSON writes is not an execution lease.
428
+ If the host cannot provide this boundary, serialize execution and state the
429
+ limitation; do not run independent workers that merely read the same ready list.
430
+
431
+ An executor returns output artifacts, changed-file digests, base/produced revisions,
432
+ checks with PASS/FAIL/NOT_RUN/TEST_ERROR, remaining risks and the attempt token.
433
+ Completion is accepted only for the current attempt and expected input revision.
434
+ Duplicate results are idempotent; a late stale worker cannot close a newer attempt.
435
+ Do not equate an agent's final message with an accepted business result.
436
+
437
+ Dependencies may carry data, a control/approval condition, or a resource ordering
438
+ constraint. Name the kind and reason. A dependency cannot be discarded solely
439
+ because it has no data payload. Dispatch a task only after all its declared
440
+ prerequisites are satisfied, and check overlapping write sets separately.
441
+
442
+ ### Portable host integration
443
+
444
+ Keep the packet independent of Claude Code, Codex or any provider's conversation
445
+ format. Each adapter maps dispatch, artifact access, cancellation, progress and
446
+ result receipts to actual host capabilities. Record the capabilities used.
447
+ Fresh agents and resumed agents receive the same required context closure.
448
+
449
+ For an external platform, map both schemas explicitly: a stage list is not a work
450
+ graph, a handoff message is not an execution lease, and an artifact path is not
451
+ proof that a remote worker can read it. Until the adapter and its failure tests
452
+ exist, label integration proposed/manual rather than supported.
453
+
454
+ ### UI task annex
455
+
456
+ For a UI outcome, attach the scenario/screen/state IDs, selected flow and visual
457
+ direction revision, component reuse/modify/create decisions, semantic token roles,
458
+ approved or explicitly provisional content, keyboard/accessibility expectations,
459
+ responsive/native behavior, and local asset provenance. Include only the portion
460
+ needed for this leaf. A non-UI task does not need this annex.
461
+
462
+ Keep behavior, its visual presentation and relevant states together when they
463
+ form one independently verifiable outcome. Do not split every screen into HTML,
464
+ CSS and interaction jobs. A changed flow, component contract or design revision
465
+ refreshes the affected packets; the executor does not guess which screenshot or
466
+ style discussion was authoritative. Preserve the existing family artifact paths.
467
+
468
+ ### Audit to executable backlog
469
+
470
+ Every finding has a disposition and a task or a recorded reason for not acting.
471
+ Separate common enabling contracts from per-finding repairs; link each task to
472
+ the program/module/interface context it consumes. Build the graph, verify its
473
+ closure, and partition runnable tasks by disjoint write sets. Include input drift,
474
+ missing context, duplicate dispatch, late completion, multiple prerequisites,
475
+ cancellation and failure recovery in acceptance. A cold reader must understand
476
+ why the change exists and how its result fits the system without the original chat.
477
+
478
+ Store the packet set with the plan. Planning is complete when the declared scope
479
+ is covered, required inputs resolve, dependencies are acyclic and readiness is
480
+ reported honestly. Delivery remains a separate state with its own evidence.
@@ -41,6 +41,7 @@ a row pointing outside the bundle is the defect this file exists to catch.
41
41
  |---|---|
42
42
  | The stage list, ids, names, gate types | `pipeline.example.json` |
43
43
  | Per-stage criteria, freedom levels, the run checklist | `references/stages.md` |
44
+ | Which reference owns which stage (the doctrine map) | `references/doctrine-map.md` |
44
45
  | What the intake grill asks, and the autonomy sweep | `references/grill.md` |
45
46
  | **The escalation boundary** — what an agent may settle alone | `references/grill.md` |
46
47
  | The knowledge harvest and its source ledger | `references/knowledge-sources.md` |
@@ -269,15 +269,31 @@ printf '%s · %s\n' "$(date +%F)" "$(git rev-parse --short HEAD)" >> docs/eviden
269
269
  A lesson that lands in a cluttered file is a lesson nobody will reach — so the prune still runs
270
270
  before the entry is written. It runs *after* the stamp, because it reads it.
271
271
 
272
- Every row carries its own trigger in a **`Retire when`** column, written at birth —
273
- a rule whose retirement condition is decided later is a rule the prune can only
274
- argue about. Check **every** standing instruction against three triggers:
272
+ Every row carries its own trigger in a **`Retire when`** column AND a **class**,
273
+ both written at birth — a rule whose retirement condition is decided later is a
274
+ rule the prune can only argue about. Three classes, because coldness means
275
+ three different things:
276
+
277
+ - **permanent** — a safety invariant, a contract, a recovery procedure. The
278
+ absence of the rare event it guards is not absence of value: **coldness never
279
+ retires a permanent rule** — only *became a check* or *surface gone* do.
280
+ - **situational** — fires when a named EXPOSURE occurs (a payment run, a
281
+ migration, a release). Its row names the exposure, and the prune counts
282
+ **exposure opportunities, not raw runs**: five runs that never touched
283
+ payments say nothing about a payment rule.
284
+ - **temporary** — a workaround with a **TTL** and the replacing mechanism named
285
+ at birth. TTL only exists on this class.
286
+
287
+ Check **every** standing instruction against three triggers:
275
288
 
276
289
  | Trigger | Test | Then |
277
290
  |---|---|---|
278
291
  | **It became a check** | the rule is now enforced by a test, lint, gate or hook | delete it — the check is the memory, and keeping both means it is read twice and obeyed once |
279
292
  | **Its surface is gone** | resolve every path, command, stage and tool it names; any that no longer exists | delete it — it now describes a system nobody is running |
280
- | **It went cold** | it has not fired in the last **five run stamps** — **or** in the last **sixty days**, whichever comes first | delete it: five runs without firing is the evidence it was situational, and the calendar is the unit that still moves when the stamp counter has stopped |
293
+ | **It went cold** | *situational only*: it fired in none of the last **five exposure opportunities** — or no exposure occurred in **sixty days** | mark **review-needed** and put the question to the operator with the exposure counts — cold is evidence worth reviewing, never an automatic deletion. *temporary*: TTL expired → archive it **once the replacing mechanism is verified present** (its check resolves and runs); an expired workaround whose replacement is absent is a live defect, not a retirement. *permanent*: not applicable |
294
+
295
+ Every removal stays explainable: the archive line names the class, the trigger
296
+ and the evidence (the exposure counts, or the replacing mechanism's check).
281
297
 
282
298
  **Each trigger is a command, not a judgement.** A retirement condition nobody can run is a
283
299
  condition nobody applies, which is how a list reaches ten and stops being read:
@@ -297,10 +313,12 @@ tail -n 200 docs/evidence/retro.md | grep -c "$RULE_ID"
297
313
  git log -1 --format=%cd --date=short -S"$RULE_ID" -- docs/evidence/retro.md
298
314
  ```
299
315
 
300
- Anything the first two print is a deletion; a zero from the third **or** a last-fired date more
301
- than sixty days old is a deletion. What survives all three stays, and the run states the counts
302
- rather than the conclusion (`learned.md` rule 19 an empty result and an unrun command look
303
- identical).
316
+ Anything the first two print is a deletion. A zero from the third counted against
317
+ **exposure opportunities** for a situational rule (`grep -c "$EXPOSURE_MARK"` over the same
318
+ stamps, so the denominator is runs that COULD have fired it) marks **review-needed**, and the
319
+ run states the counts rather than the conclusion (`learned.md` rule 19 — an empty result and an
320
+ unrun command look identical). Only the operator's answer, or a temporary rule's verified
321
+ replacement, turns review-needed into a removal.
304
322
 
305
323
  **Why the cold trigger needs two units, and it is not belt-and-braces.** A run stamp is written by
306
324
  a run *of this pipeline*. Where a project ships some of its work another way, the stamp counter
@@ -38,7 +38,7 @@ turn of every loop.
38
38
  | `goal_clauses` | release work no requirement names. Enumerated, never matched against the goal's prose: substring-matching a sentence produces confidence without correctness |
39
39
  | `nodes[].owner` | which role does it. A node nobody can dispatch never leaves the frontier and nothing says why |
40
40
  | `nodes[].serves` | the REQ or goal clause it exists for. A node serving neither is **parked with that as the reason** |
41
- | `nodes[].blocked_by` | what must close first. This is what the frontier obeys |
41
+ | `nodes[].blocked_by` | what must PRODUCE first. The frontier obeys a satisfaction predicate, and only `done` satisfies — a PARKED producer blocks its consumer, because a park is a decision not to produce, not a production. `next` names each held consumer with the park's reason; a valid alternative producer is an explicit, versioned edge change, never an implicit unblock |
42
42
  | `nodes[].touches` | what it **mutates**. Two runnable nodes writing one file is the false parallelism [`planning.md`](planning.md) refuses — *distinct is not the same as independent, and the check is what they touch, never what they are called* |
43
43
  | `nodes[].check` | **how this node will be closed** — one command, or the named judgement where no command can decide it. Required on every node except a `parked` one. The certification's `unit` tier runs it and reports its output as the evidence row ([`certification.md`](certification.md) — three blind tiers close a node, not one reader); before this field existed that instruction pointed at an absence, leaving a verifier the two things it forbids — invent a check, or run everything (B-080) |
44
44
  | `nodes[].evidence` | required when `status` is `done`. A node called done by assertion is what evidence exists to prevent |
@@ -63,6 +63,12 @@ conditional on the code, never merely sequenced after it.**
63
63
  | `close` | the goal, the new frontier count, and what was not verified | `0` · `1` refused **or the verdict stops the run** |
64
64
  | `producer` | what produced this proof — actor, model, runtime, skill, config, commit, trace | `0` |
65
65
  | `doctrine` | how many of the bundle's reference files this run opened | `0` |
66
+ | `claim` | **external mode** — arbitrate one runnable node to a single owner through the durable coordinator (`scripts/execution_authority.py`); prints the grant. `next` says what COULD run, `claim` says who MAY | `0` won · `5` lost the race · `4` not runnable · `1` authority unavailable — **and `1` means no work starts** (fail-closed) |
67
+ | `release` | give back a hold this run owns, matching its fence; a mismatch is a no-op, never a way to steal a live node | `0` released · `5` not held at that fence · `1` authority unavailable |
68
+ | `recover` | **external mode** — reclaim an EXPIRED node for a new owner, minting a higher fence; a still-live claim is not recoverable (that is stealing a working node) | `0` recovered · `5` still live · `1` authority unavailable |
69
+ | `complete` | **external mode** — record completion from the CURRENT fence-holder only; a late/superseded worker (stale fence) is refused, and the current holder completing twice is idempotent | `0` completed · `5` not the current holder · `1` authority unavailable |
70
+ | `waive` | record an AUTHORIZED EXCEPTION — reason + identity, its own disposition: the node is never marked certified, a failed certification stays visible, and `close` stamps the exception into the evidence | `0` waived · `1` refused (no reason, no identity, unknown node) |
71
+ | `invalidate` | a REQ/interface/brief change supersedes one node: a superseding revision is recorded, and the node plus every `done` DESCENDANT resets to pending with its evidence/proof/certification cleared — a proof certified against a contract that moved is a proof about a tree that no longer exists. Unrelated nodes keep their proofs; invalidation flows downstream only | `0` invalidated · `1` refused (no `--why`, unknown node, or the write would break the graph) |
66
72
 
67
73
  **`next` is ordered by what each node unblocks, transitively, and the number is computed.**
68
74
  A `priority` field is something somebody typed once and nobody revisits; this one moves when