task-pipeline-skill 1.39.0 → 1.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/CONTRIBUTING.md +1 -1
- package/SKILL-CARD.md +1 -1
- package/package.json +1 -1
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/pipeline.example.json +7 -2
- package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +19 -3
- package/plugins/task-pipeline/skills/task-pipeline/references/continuity.md +73 -4
- package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.40.0 — the loop had a cadence and no queue
|
|
4
|
+
|
|
5
|
+
`run.loop` said how **often** to continue. It never said **what the next item is**, so an
|
|
6
|
+
armed mode still left the run choosing its next move by recollection — `learned.md` rule
|
|
7
|
+
16, once per fire. And nothing scheduled the next turn at all: on 2026-08-10 a run of
|
|
8
|
+
this pipeline wrote *«продолжаю без остановки»* and the turn ended, because a sentence
|
|
9
|
+
about future behaviour is not a wakeup. That run is this release's occasion and its
|
|
10
|
+
evidence.
|
|
11
|
+
|
|
12
|
+
### The queue is stage 2's
|
|
13
|
+
|
|
14
|
+
The **module map** when the brief was a platform, the plan's task list otherwise. Both
|
|
15
|
+
already existed, both were already ordered, and neither had ever been named as the thing
|
|
16
|
+
the loop walks. `run.loop.queue` names it; `run.loop.arm` says where the mode is armed,
|
|
17
|
+
and the default for a queue-bearing run is **after decomposition** — arming at preflight
|
|
18
|
+
arms a loop with nothing to walk.
|
|
19
|
+
|
|
20
|
+
Arming is a consequence, not a request, for the same reason the mode is recorded rather
|
|
21
|
+
than asked for: a capability the operator must remember to switch on is one they forget
|
|
22
|
+
on exactly the run that needed it.
|
|
23
|
+
|
|
24
|
+
**What arming does not change is stated where it could be missed.** The four stops are
|
|
25
|
+
the four stops; a `manual` gate still waits; an outward act still needs its own specific
|
|
26
|
+
authorization. *A generic flag is not a specific authorization*, and arming a queue is
|
|
27
|
+
the most generic flag there is — guarded, because that sentence is what the deploy floor
|
|
28
|
+
rests on.
|
|
29
|
+
|
|
30
|
+
### `mode: dynamic`
|
|
31
|
+
|
|
32
|
+
`interval` was the only mode while a fixed tick was the only primitive. A harness that
|
|
33
|
+
can schedule its own next turn picks each delay from what it is waiting for, and **prints
|
|
34
|
+
the delay it chose** — the disclosure that replaces an interval run's job id. A run
|
|
35
|
+
silent about its pacing cannot be told apart from one that quietly stopped, which is the
|
|
36
|
+
claim this file already forbade for harnesses with no primitive at all.
|
|
37
|
+
|
|
38
|
+
### The goal is re-read between items, not only the board
|
|
39
|
+
|
|
40
|
+
Each iteration already re-measured the work-list, which answers *what is open*. It did
|
|
41
|
+
not answer *whether the open thing still serves what this run was for*. A queue built at
|
|
42
|
+
stage 2 outlives the reason it was built, because the operator learns things between
|
|
43
|
+
items and says so. So the bottom of an iteration now quotes the goal, states whether the
|
|
44
|
+
next item still serves it, and re-orders or re-scopes when it does not — a row that stops
|
|
45
|
+
serving the goal leaves for the board with its reason.
|
|
46
|
+
|
|
47
|
+
A queue re-derived only by `age` and `sev` is honest about priority and silent about
|
|
48
|
+
purpose. Both numbers can be right while the run finishes something the operator stopped
|
|
49
|
+
wanting two items ago.
|
|
50
|
+
|
|
51
|
+
### The reader found the contradiction, not the bug
|
|
52
|
+
|
|
53
|
+
R-005's reader defeated all five guards and then read the doctrine as a reader rather
|
|
54
|
+
than its author. Part 1a said *"arming is a consequence, not a request"* and stated its
|
|
55
|
+
trigger as a fact about the **work** — a queue with more than one item — with no
|
|
56
|
+
antecedent about configuration. Two sections above, the same file says **Default off.
|
|
57
|
+
Silence arms nothing, exactly as silence authorizes no deploy**, and `grill.md`'s deploy
|
|
58
|
+
floor is explicitly said to rest on that distinction. Read cold, Part 1a arms a loop in a
|
|
59
|
+
project with no `pipeline.json` at all.
|
|
60
|
+
|
|
61
|
+
The contradiction was in the phrasing, not the intent — `stages.md` had already restated
|
|
62
|
+
the rule with the antecedent intact. **Part 1a gave way**, and a guard now requires it to
|
|
63
|
+
state its precondition, because five guards checked for the presence of strings and not
|
|
64
|
+
one would have noticed either reading.
|
|
65
|
+
|
|
66
|
+
What the reader took apart in the guards, all verified by planting the defect and
|
|
67
|
+
watching `PASS`:
|
|
68
|
+
|
|
69
|
+
- **a deleted contract was a skip, not a failure.** Removing the whole `run.loop` block
|
|
70
|
+
left CI green with two tidy `unlooked` lines — and `run` allows additional properties,
|
|
71
|
+
so the example still conformed while meaning nothing;
|
|
72
|
+
- **`_loop_block` searched instead of addressing.** A deprecated top-level `loop` earlier
|
|
73
|
+
in file order answered for the real contract;
|
|
74
|
+
- **presence tests let the release's own thesis be reverted.** `arm` existed, so setting
|
|
75
|
+
the example back to `preflight` passed;
|
|
76
|
+
- **`if _qv and …` short-circuited itself** — an open string in place of the queue enum
|
|
77
|
+
passed, which is precisely the failure the guard was written for;
|
|
78
|
+
- **the floor guard had never tested its own rule.** Its phrase entered the file in
|
|
79
|
+
v1.11.0, twenty-nine releases earlier; both doctrinal statements could be deleted and a
|
|
80
|
+
Rationalizations row kept it green;
|
|
81
|
+
- **the dynamic-disclosure regex was content-blind** — a sentence keeping the words and
|
|
82
|
+
inverting the obligation passed — and it triggered off the prose word, so renaming the
|
|
83
|
+
mode switched the guard off;
|
|
84
|
+
- **`arm the mode` matched a bullet forbidding arming**, and `"loop"` matched any
|
|
85
|
+
sentence about any loop. Both now key on the schema's own tokens.
|
|
86
|
+
|
|
87
|
+
Guards 233 → **248**: seven more probes than the first pass shipped with, six of them for
|
|
88
|
+
fail sites that did not exist until the reader's findings were fixed.
|
|
89
|
+
|
|
90
|
+
### Also
|
|
91
|
+
|
|
92
|
+
- **A guard was listing the legal modes instead of reading them.** Adding `dynamic`
|
|
93
|
+
failed the guard on a correct example — a check enforcing its own staleness. It now
|
|
94
|
+
reads the enum out of the schema.
|
|
95
|
+
- Guards: 233 → **248**, one per new fail site, each with its planted defect.
|
|
96
|
+
|
|
3
97
|
## v1.39.0 — the skill could not be reached by the word "audit"
|
|
4
98
|
|
|
5
99
|
`references/audit.md` has said since v0.1.0 that an audit may be **the whole task** —
|
package/CONTRIBUTING.md
CHANGED
|
@@ -191,7 +191,7 @@ reads those files, and a partial read shows whichever sections come first.
|
|
|
191
191
|
`run` block in `pipeline.schema.json` carries the loop mode; the shipped example
|
|
192
192
|
sets `run.loop.mode` explicitly rather than omitting it, because the example is
|
|
193
193
|
what gets copied and an absent field reads as an oversight instead of a decision.
|
|
194
|
-
*(guard: `
|
|
194
|
+
*(guard: `run.loop.mode is` … `and the schema's legal set is`)*
|
|
195
195
|
|
|
196
196
|
**25. The run-wide mode is named by every stage that could be misled by it.**
|
|
197
197
|
`SKILL.md`, `references/grill.md`, `references/build.md`, `references/stages.md`
|
package/SKILL-CARD.md
CHANGED
|
@@ -12,7 +12,7 @@ harmless.
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| **Purpose** | Runs a substantial task through ten gated delivery stages — intake grill, docs study, brainstorm, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs+registers, acceptance — refusing to advance until each gate passes |
|
|
14
14
|
| **Owner** | ssheleg ([github.com/ssheleg/task-pipeline](https://github.com/ssheleg/task-pipeline)) |
|
|
15
|
-
| **Version** | 1.
|
|
15
|
+
| **Version** | 1.40.0 |
|
|
16
16
|
| **Surface** | Claude Code (filesystem skill + plugin) and the vercel `skills` CLI. **Not** uploaded to the Skills API; custom Skills do not sync across surfaces |
|
|
17
17
|
| **Dependencies** | None required. Optional: `context7` (MCP), `figma` (MCP), super-ux, agent-sync, graphify, obsidian-wiki. Every stage's doctrine ships in-repo; the one conditional requirement is super-ux for the stage-3 UX track on a user-facing task |
|
|
18
18
|
| **Evaluation status** | Suite authored, 5 categories. One recorded run, **self-observed by the author**; **zero blind runs on zero of three models** — the split, and the numbers, live in [`evals/RESULTS.md`](evals/RESULTS.md) and are computed by `evals/run.py` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "task-pipeline-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.40.0",
|
|
4
4
|
"description": "Full-cycle delivery pipeline for coding agents: a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine ships inside the skill — no companion plugin required. This package is the installer CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"task-pipeline": "bin/task-pipeline.js"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "task-pipeline",
|
|
3
3
|
"displayName": "Task Pipeline",
|
|
4
4
|
"description": "Runs a substantial task through a mandatory built-in intake grill, then 10 gated stages (docs, brainstorm+decompose, spec, plan, subagent build, tests, lint/deploy, post-deploy, docs/wiki, acceptance). Every stage's doctrine is built into the skill — no companion plugin required — with typed auto/manual gates, a frozen requirement spine that closes with evidence, a work board and a verification ledger that outlive a run, an exposure line naming what shipped unconfirmed, a progress rail computed from the project's own config, a loop guard whose review ceiling measures rather than stops, and stage-3 tracks for what a product does, how it sounds and how it looks. Two modes need no task: `checkup` (what is unverified) and `setup` (audit existing docs). Retro insights can publish upstream as issues, opt-in and redacted.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.40.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
],
|
|
47
47
|
"gate": {
|
|
48
48
|
"type": "manual",
|
|
49
|
-
"check": "the user approves the design AND the UI verdict is recorded (does the task touch a user-facing surface — web/mobile/CLI/TUI? this arms the stage-3 UX track). Every REQ is answered by the design, or explicitly dropped by the operator into the carry-over ledger. For a platform (several independent capabilities or shippable surfaces): the module map specs/<topic>-modules.md is committed and approved — brick criteria met or excepted in writing, dependency graph acyclic, build order topological with the walking skeleton first, every REQ mapped to exactly one module, cross-module contracts named with their owner. Single-module work records 'single module: <name>' instead — a skipped decomposition is a recorded decision, never an omission"
|
|
49
|
+
"check": "the user approves the design AND the UI verdict is recorded (does the task touch a user-facing surface — web/mobile/CLI/TUI? this arms the stage-3 UX track). Every REQ is answered by the design, or explicitly dropped by the operator into the carry-over ledger. For a platform (several independent capabilities or shippable surfaces): the module map specs/<topic>-modules.md is committed and approved — brick criteria met or excepted in writing, dependency graph acyclic, build order topological with the walking skeleton first, every REQ mapped to exactly one module, cross-module contracts named with their owner. Single-module work records 'single module: <name>' instead — a skipped decomposition is a recorded decision, never an omission. THE LOOP'S ARMING STATE IS PRINTED — armed with its queue and pacing, or not armed with the reason; the queue exists at this stage and a loop armed earlier has nothing to walk."
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
52
|
{
|
|
@@ -172,7 +172,12 @@
|
|
|
172
172
|
],
|
|
173
173
|
"_run_note": "Run-wide pacing. Shipped explicitly OFF so this example DEMONSTRATES the default rather than relying on its absence — see references/continuity.md. Set mode to 'interval' and a project stops being asked whether to run item-by-item; it still stops at every manual gate. There is no context-budget field here on purpose: the threshold is not measurable, so it is unconditional doctrine, not config.",
|
|
174
174
|
"run": {
|
|
175
|
-
"loop": {
|
|
175
|
+
"loop": {
|
|
176
|
+
"mode": "dynamic",
|
|
177
|
+
"queue": "module-map",
|
|
178
|
+
"arm": "after-decomposition",
|
|
179
|
+
"command": "/loop"
|
|
180
|
+
}
|
|
176
181
|
},
|
|
177
182
|
"release": {
|
|
178
183
|
"enabled": true,
|
|
@@ -48,18 +48,34 @@
|
|
|
48
48
|
"mode": {
|
|
49
49
|
"enum": [
|
|
50
50
|
"off",
|
|
51
|
-
"interval"
|
|
51
|
+
"interval",
|
|
52
|
+
"dynamic"
|
|
52
53
|
],
|
|
53
|
-
"description": "off (the default when absent) = the run pauses between items as it always did. interval =
|
|
54
|
+
"description": "off (the default when absent) = the run pauses between items as it always did. interval = armed with the harness's fixed-tick primitive, one item per fire. dynamic = the harness schedules its own next turn and the run picks each delay from what it is waiting for; a wait on nothing is minutes, not a tick nobody chose. interval and dynamic stop at the same four things — a manual gate, an unresolvable block, a genuine ambiguity, completion — and neither collapses an outward act: a generic flag is not a specific authorization."
|
|
54
55
|
},
|
|
55
56
|
"interval": {
|
|
56
57
|
"type": "string",
|
|
57
58
|
"pattern": "^[0-9]+[smhd]$",
|
|
58
|
-
"description": "Required when mode is 'interval'. Must divide its unit cleanly (5m, 10m, 2h — not 7m or 90m); a value that does not is rounded to the nearest that does, and the rounding is stated out loud. Pick the shortest interval that is longer than a typical item."
|
|
59
|
+
"description": "Required when mode is 'interval', and meaningless when it is 'dynamic' — a self-pacing run chooses each delay. Must divide its unit cleanly (5m, 10m, 2h — not 7m or 90m); a value that does not is rounded to the nearest that does, and the rounding is stated out loud. Pick the shortest interval that is longer than a typical item."
|
|
59
60
|
},
|
|
60
61
|
"command": {
|
|
61
62
|
"type": "string",
|
|
62
63
|
"description": "How this harness arms it, e.g. '/loop'. Harness-specific and therefore project-recorded rather than assumed: on a harness with no loop primitive, omit it — the mode then degrades to prose discipline plus the build ledger, and the run says so instead of implying it is armed."
|
|
64
|
+
},
|
|
65
|
+
"queue": {
|
|
66
|
+
"enum": [
|
|
67
|
+
"module-map",
|
|
68
|
+
"plan-tasks",
|
|
69
|
+
"none"
|
|
70
|
+
],
|
|
71
|
+
"description": "What the loop walks. A loop with no queue is a timer: it says how often to continue and never what the next item is, so the run picks its next move by recollection. module-map = stage 2's decomposition (a platform); plan-tasks = stage 4's task list; none = the mode is armed for the stage boundaries only. Doctrine: references/continuity.md -> Part 1a."
|
|
72
|
+
},
|
|
73
|
+
"arm": {
|
|
74
|
+
"enum": [
|
|
75
|
+
"preflight",
|
|
76
|
+
"after-decomposition"
|
|
77
|
+
],
|
|
78
|
+
"description": "When the mode is armed. preflight = at the top of the run, the original behaviour. after-decomposition = at the close of stage 2, once the queue exists and has more than one item — the default for a queue-bearing run, because a capability the operator must remember to switch on is one they forget on the run that needed it. Arming never collapses a manual gate or an outward action."
|
|
63
79
|
}
|
|
64
80
|
}
|
|
65
81
|
},
|
|
@@ -11,6 +11,7 @@ almost no window left, loses the middle of it, and re-derives what it already di
|
|
|
11
11
|
|
|
12
12
|
- The limit, before the capability
|
|
13
13
|
- Part 1 — the loop
|
|
14
|
+
- Part 1a — the queue is stage 2's, and the loop arms on it
|
|
14
15
|
- Arming it on Claude Code
|
|
15
16
|
- Other harnesses, and honest degradation
|
|
16
17
|
- What one iteration means
|
|
@@ -62,6 +63,62 @@ the boundary between one agent turn and the next. This file is that reach.
|
|
|
62
63
|
is never asked again — which is the entire point. A mode that has to be requested
|
|
63
64
|
every run is not a mode, it is a habit the operator maintains by hand.
|
|
64
65
|
|
|
66
|
+
## Part 1a — the queue is stage 2's, and the loop arms on it
|
|
67
|
+
|
|
68
|
+
**A loop with no queue is a timer.** Until this section existed, `run.loop` said *how
|
|
69
|
+
often* to continue and never said *what the next item is*, so the mode could be armed
|
|
70
|
+
and still leave the run picking its next move by recollection — which is the failure
|
|
71
|
+
[`learned.md`](learned.md) rule 16 is about, running once per fire.
|
|
72
|
+
|
|
73
|
+
**The queue is the module map** ([`decomposition.md`](decomposition.md)) when the brief
|
|
74
|
+
was a platform, and the plan's task list otherwise. Both already exist and both are
|
|
75
|
+
already ordered; neither was ever named as the thing the loop walks.
|
|
76
|
+
|
|
77
|
+
**Arming is the execution of a recorded decision, not a fresh request.** Where the mode
|
|
78
|
+
is **recorded** and the queue has more than one item, the loop arms **at the close of
|
|
79
|
+
stage 2** and the run says so in one line. It is not asked for at that point, for the
|
|
80
|
+
same reason the mode is recorded rather than requested: re-asking would rebuild the habit
|
|
81
|
+
the config exists to retire.
|
|
82
|
+
|
|
83
|
+
**Where nothing is recorded, nothing arms.** Silence arms nothing here too — this section
|
|
84
|
+
moves *where* a recorded mode is armed, from preflight to the close of stage 2. It does
|
|
85
|
+
not make arming unconditional, and a reader who takes it that way would arm a loop in a
|
|
86
|
+
project with no `pipeline.json` at all. That reading was in this section's first draft;
|
|
87
|
+
an independent reader found it before it shipped.
|
|
88
|
+
|
|
89
|
+
**What arming does NOT change, and this is load-bearing:** the four stops are the four
|
|
90
|
+
stops. A `manual` gate still waits. An outward or irreversible act still needs its own
|
|
91
|
+
specific authorization — *a generic flag is not a specific authorization*, and arming a
|
|
92
|
+
queue is the most generic flag there is. Arming decides only that the run does not stop
|
|
93
|
+
to ask *"shall I take the next one?"*.
|
|
94
|
+
|
|
95
|
+
**`mode: dynamic` — when the harness paces itself.** `interval` was the only mode while
|
|
96
|
+
the only primitive was a fixed tick. A harness that can schedule its own next turn
|
|
97
|
+
should: the run picks the delay from what it is waiting for, and a wait on nothing is a
|
|
98
|
+
wait of minutes rather than a fixed tick nobody chose. On a harness with neither
|
|
99
|
+
primitive the mode degrades to prose discipline plus the build ledger, and **the run
|
|
100
|
+
says which one it is running** — the rule below about claiming a capability you do not
|
|
101
|
+
have is unchanged and applies to `dynamic` first.
|
|
102
|
+
|
|
103
|
+
### The goal is re-read between items, not only the board
|
|
104
|
+
|
|
105
|
+
Each iteration already re-measures the work-list. That answers *what is open*. It does
|
|
106
|
+
not answer *whether the open thing still serves what this run was for* — and a queue
|
|
107
|
+
built at stage 2 outlives the reason it was built, because the operator learns things
|
|
108
|
+
between items and says so.
|
|
109
|
+
|
|
110
|
+
So at the bottom of an iteration, beside the re-derived `prio`:
|
|
111
|
+
|
|
112
|
+
1. re-read the brief's goal — one line, quoted, not recalled;
|
|
113
|
+
2. state whether the next item still serves it;
|
|
114
|
+
3. if it does not, **re-order or re-scope the queue and say what moved and why.** A row
|
|
115
|
+
that stops serving the goal leaves for the board with its reason
|
|
116
|
+
([`backlog.md`](backlog.md)), it does not get worked because it was next.
|
|
117
|
+
|
|
118
|
+
A queue re-derived only by `age` and `sev` is a queue that is honest about priority and
|
|
119
|
+
silent about purpose. Both numbers can be right while the run is finishing something the
|
|
120
|
+
operator stopped wanting two items ago.
|
|
121
|
+
|
|
65
122
|
## Arming it on Claude Code
|
|
66
123
|
|
|
67
124
|
```
|
|
@@ -85,10 +142,22 @@ silent failures otherwise:
|
|
|
85
142
|
stops on day eight is worse than one that was never armed, because the operator
|
|
86
143
|
believes work is still moving.
|
|
87
144
|
|
|
88
|
-
Where `run.loop.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
145
|
+
**Where it arms is `run.loop.arm`,** and there are two points because there are two
|
|
146
|
+
kinds of run:
|
|
147
|
+
|
|
148
|
+
- `preflight` — the top of the run. Right when the loop walks stage boundaries rather
|
|
149
|
+
than a list, and the only option before Part 1a existed.
|
|
150
|
+
- `after-decomposition` — the close of stage 2, once the queue exists and holds more
|
|
151
|
+
than one item. Arming earlier would arm a loop with nothing to walk.
|
|
152
|
+
|
|
153
|
+
Either way the run **prints the job id and the cancel command**, and arming is not a new
|
|
154
|
+
decision at that point — the config is the recorded authorization, and re-asking would
|
|
155
|
+
rebuild the habit the config exists to retire.
|
|
156
|
+
|
|
157
|
+
Under `mode: dynamic` there is no job id: the run schedules its own next turn each time
|
|
158
|
+
and prints **the delay it chose and why**, which is the same disclosure in the form that
|
|
159
|
+
mode has. A dynamic run that says nothing about its pacing is indistinguishable from a
|
|
160
|
+
run that quietly stopped.
|
|
92
161
|
|
|
93
162
|
## Other harnesses, and honest degradation
|
|
94
163
|
|
|
@@ -258,13 +258,21 @@ never that the work was skipped quietly.
|
|
|
258
258
|
its status, in build order with the walking skeleton first. Single-module work
|
|
259
259
|
records `single module: <name>` in the design and moves on — a skipped
|
|
260
260
|
decomposition is a decision, never an omission.
|
|
261
|
+
- **The queue exists here, so the loop arms here** ([`continuity.md`](continuity.md) →
|
|
262
|
+
*Part 1a*). Where `run.loop.arm` is `after-decomposition` and the map holds more than
|
|
263
|
+
one module, arm the mode at the close of this stage and print one line: the mode, and
|
|
264
|
+
either the job id and its cancel command (`interval`) or the delay chosen and why
|
|
265
|
+
(`dynamic`). Arming collapses no gate and authorizes no outward act; it decides only
|
|
266
|
+
that the run does not stop to ask *"shall I take the next one?"*. Single-module work
|
|
267
|
+
arms nothing and says so — a loop with one item is a timer.
|
|
261
268
|
- **GATE (manual):** the user approves the design, the UI verdict is recorded,
|
|
262
269
|
**every REQ is answered by the design** — a requirement the design doesn't
|
|
263
270
|
address is either covered now or explicitly dropped by the operator, with the
|
|
264
271
|
drop recorded in the carry-over ledger — **and, for a platform, the module map is
|
|
265
272
|
approved**: brick criteria met or excepted in writing, dependency graph acyclic,
|
|
266
273
|
build order topological, every REQ mapped to exactly one module, cross-module
|
|
267
|
-
contracts named with their owner
|
|
274
|
+
contracts named with their owner — **and the loop's arming state is printed**:
|
|
275
|
+
armed with its queue and pacing, or not armed with the reason.
|
|
268
276
|
|
|
269
277
|
## 3 — Spec — with UX track for user-facing tasks
|
|
270
278
|
- **Freedom: medium** — what the contract says is judgement; which contracts must be locked is a list ([`gates.md`](gates.md) → *Axis C*).
|