task-pipeline-skill 1.51.0 → 1.52.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 +47 -0
- 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/hooks/build-gate.sh +107 -0
- package/plugins/task-pipeline/hooks/hooks.json +48 -1
- package/plugins/task-pipeline/hooks/run-lifecycle.sh +89 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/progress.md +15 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.52.0 — the three moments the run's own record could not show
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`hooks/run-lifecycle.sh`** — one line shape for three events the ledger was
|
|
8
|
+
blind to:
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
event: <compact|session-end|subagent> — <detail> — <ISO-8601>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- `compact` marks the boundary **the ledger exists because of** —
|
|
15
|
+
`templates/run.md` says so in its own header, and until now that boundary was
|
|
16
|
+
the one thing the file could not show. A resumed run could not tell "the
|
|
17
|
+
context was compacted here" from "nothing happened".
|
|
18
|
+
- `session-end` marks a run whose session ended without reaching acceptance.
|
|
19
|
+
That is precisely what `/task-pipeline checkup` looks for, and it was
|
|
20
|
+
invisible: the ledger simply stopped, which is indistinguishable from a run
|
|
21
|
+
still in progress. A run that *did* reach acceptance is not filed as
|
|
22
|
+
abandoned, or the report fills with runs that closed exactly as intended.
|
|
23
|
+
- `subagent` records one finishing, so the `hand:` count has something to be
|
|
24
|
+
checked against other than itself.
|
|
25
|
+
|
|
26
|
+
**It never writes a `hand:` line, and that is not a shortcut.** That shape
|
|
27
|
+
carries `done`, `surfaced`, `decisions` and `amb` — judgements only the agent
|
|
28
|
+
holds. A hook filling them in would fabricate the evidence the line exists to
|
|
29
|
+
provide. It records what it can see and leaves the accounting to whoever can
|
|
30
|
+
account.
|
|
31
|
+
|
|
32
|
+
One shape rather than three: a ledger grammar is read by four documents and
|
|
33
|
+
several hooks, and every shape added is a shape each of them must learn.
|
|
34
|
+
|
|
35
|
+
- **`hooks/build-gate.sh`** — editing the product before the plan is agreed now
|
|
36
|
+
asks. Stage 5 is where code is written; editing during intake, docs, brainstorm,
|
|
37
|
+
spec or plan is the pipeline's discipline being skipped, and it is the skip
|
|
38
|
+
nobody notices because the work looks like progress.
|
|
39
|
+
|
|
40
|
+
`ask`, never `deny`: the routing boundary says a typo, a one-line fix or a
|
|
41
|
+
mechanical rename never went through the pipeline anyway, and no hook can tell a
|
|
42
|
+
typo from a feature. **The build stage is resolved by role, never by number** —
|
|
43
|
+
the same lesson v1.51.0 learned from the release gate, applied before it could
|
|
44
|
+
be repeated. **The pipeline's own artefacts are never gated**: `docs/`,
|
|
45
|
+
`.task-pipeline/`, README and CHANGELOG are what stages 0-4 are *for*.
|
|
46
|
+
|
|
47
|
+
Guards: 311 → **312**. Property checks: 9 → 9. The release-gate suite is 29 → 43
|
|
48
|
+
fixtures, all run as processes.
|
|
49
|
+
|
|
3
50
|
## v1.51.0 — the gate stopped being keyed to a number, and stopped believing the agent
|
|
4
51
|
|
|
5
52
|
### Fixed
|
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.52.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.52.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.52.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "ssheleg",
|
|
8
8
|
"url": "https://x.com/sshlg93"
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreToolUse — editing the product before the plan is agreed.
|
|
3
|
+
#
|
|
4
|
+
# `stages.md` says no stage advances until its gate passes, and stage 5 is where
|
|
5
|
+
# code gets written. Editing the product during intake, docs, brainstorm, spec or
|
|
6
|
+
# plan is the pipeline's own discipline being skipped — and it is the skip nobody
|
|
7
|
+
# notices, because the work looks like progress.
|
|
8
|
+
#
|
|
9
|
+
# **`ask`, never `deny`, and the reason is this file's own doctrine.** The routing
|
|
10
|
+
# boundary says a typo, a one-line edit or a mechanical rename does not go through
|
|
11
|
+
# the pipeline, and no hook can tell a typo from a feature. A refusal here would
|
|
12
|
+
# fight the honest cases daily and be removed inside a week; a question answered
|
|
13
|
+
# once costs a keystroke.
|
|
14
|
+
#
|
|
15
|
+
# **The build stage is resolved by ROLE, never by number.** v1.50.0 matched
|
|
16
|
+
# `stage: 6` literally and blocked every release in a six-stage project; the same
|
|
17
|
+
# mistake here would put a prompt in front of every edit in any project whose flow
|
|
18
|
+
# is numbered differently. `pipeline.json` → a stage whose `state` is `build`, else
|
|
19
|
+
# one whose name says build. Unresolvable → silence, because a question nobody can
|
|
20
|
+
# act on is worse than none.
|
|
21
|
+
#
|
|
22
|
+
# **The pipeline's own artefacts are never gated.** Stages 0-4 exist to WRITE
|
|
23
|
+
# things — the brief, the spec, the plan, the ledger. A gate that asked about those
|
|
24
|
+
# would fire on the very work it is protecting.
|
|
25
|
+
set -uo pipefail
|
|
26
|
+
|
|
27
|
+
input=$(cat 2>/dev/null || true)
|
|
28
|
+
project="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
29
|
+
ledger="$project/.task-pipeline/run.md"
|
|
30
|
+
[ -f "$ledger" ] || exit 0
|
|
31
|
+
|
|
32
|
+
HOOK_INPUT="$input" python3 - "$ledger" "$project" <<'PY' 2>/dev/null || exit 0
|
|
33
|
+
import json, os, re, sys
|
|
34
|
+
|
|
35
|
+
ledger, project = sys.argv[1], sys.argv[2]
|
|
36
|
+
try:
|
|
37
|
+
data = json.loads(os.environ.get("HOOK_INPUT", ""))
|
|
38
|
+
except Exception:
|
|
39
|
+
raise SystemExit(0)
|
|
40
|
+
|
|
41
|
+
ti = data.get("tool_input") or {}
|
|
42
|
+
path = ti.get("file_path") or ti.get("notebook_path") or ""
|
|
43
|
+
if not path:
|
|
44
|
+
raise SystemExit(0)
|
|
45
|
+
|
|
46
|
+
rel = os.path.relpath(path, project) if os.path.isabs(path) else path
|
|
47
|
+
rel = rel.replace(os.sep, "/")
|
|
48
|
+
# The run writes these; gating them would fire on the work stages 0-4 are for.
|
|
49
|
+
if rel.startswith("..") or re.match(r"^(docs/|\.task-pipeline/|\.claude/|CHANGELOG\.md|README\.md)", rel):
|
|
50
|
+
raise SystemExit(0)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
text = open(ledger, encoding="utf-8").read()
|
|
54
|
+
except Exception:
|
|
55
|
+
raise SystemExit(0)
|
|
56
|
+
|
|
57
|
+
stage_lines = [l.strip() for l in text.splitlines() if l.strip().startswith("stage:")]
|
|
58
|
+
if not stage_lines:
|
|
59
|
+
raise SystemExit(0)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def build_stage_id():
|
|
63
|
+
"""By role, never by number — the mistake v1.50.0 shipped in the release gate."""
|
|
64
|
+
try:
|
|
65
|
+
cfg = json.load(open(os.path.join(project, "pipeline.json"), encoding="utf-8"))
|
|
66
|
+
for s in cfg.get("stages") or []:
|
|
67
|
+
if isinstance(s, dict) and s.get("state") == "build":
|
|
68
|
+
return str(s.get("id"))
|
|
69
|
+
except Exception:
|
|
70
|
+
pass
|
|
71
|
+
for l in stage_lines:
|
|
72
|
+
m = re.match(r"stage:\s*(\S+)\s+([^—]*)", l)
|
|
73
|
+
if m and re.search(r"build|dev\b", m.group(2), re.I):
|
|
74
|
+
return m.group(1)
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
build_id = build_stage_id()
|
|
79
|
+
if build_id is None:
|
|
80
|
+
raise SystemExit(0) # unresolvable: a question nobody can act on
|
|
81
|
+
|
|
82
|
+
# Has the run entered the build stage at all? Entering is enough — the gate is
|
|
83
|
+
# about editing BEFORE the plan is agreed, not about the build's own verdict.
|
|
84
|
+
entered = any(re.match(r"stage:\s*%s\b" % re.escape(build_id), l) for l in stage_lines)
|
|
85
|
+
if entered:
|
|
86
|
+
raise SystemExit(0)
|
|
87
|
+
|
|
88
|
+
last = stage_lines[-1]
|
|
89
|
+
m = re.match(r"stage:\s*(\S+)\s+([^—]*)", last)
|
|
90
|
+
now = "%s %s" % (m.group(1), m.group(2).strip()) if m else "an early stage"
|
|
91
|
+
|
|
92
|
+
print(json.dumps({"hookSpecificOutput": {
|
|
93
|
+
"hookEventName": "PreToolUse",
|
|
94
|
+
"permissionDecision": "ask",
|
|
95
|
+
"permissionDecisionReason":
|
|
96
|
+
"This run is at stage %s and has not entered the build stage (%s). Editing "
|
|
97
|
+
"the product before the plan is agreed is the pipeline's own discipline "
|
|
98
|
+
"being skipped — and it is the skip nobody notices, because the work looks "
|
|
99
|
+
"like progress.\n\n"
|
|
100
|
+
"Allow if this is a typo, a one-line fix or a mechanical rename, which the "
|
|
101
|
+
"routing boundary says never went through the pipeline anyway. Otherwise "
|
|
102
|
+
"finish the plan and record stage %s in %s.\n\n"
|
|
103
|
+
"The pipeline's own artefacts — docs/, .task-pipeline/, README, CHANGELOG — "
|
|
104
|
+
"are never gated." % (now, build_id, build_id, ledger),
|
|
105
|
+
}}))
|
|
106
|
+
PY
|
|
107
|
+
exit 0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "task-pipeline — the
|
|
2
|
+
"description": "task-pipeline — the gates and the observations they rest on. Every hook exits 0 immediately when the project has no .task-pipeline/run.md, so installing the plugin globally changes nothing in a repository that is not running a pipeline.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"PreToolUse": [
|
|
5
5
|
{
|
|
@@ -13,6 +13,17 @@
|
|
|
13
13
|
"timeout": 20
|
|
14
14
|
}
|
|
15
15
|
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"matcher": "Edit|Write|MultiEdit|NotebookEdit",
|
|
19
|
+
"hooks": [
|
|
20
|
+
{
|
|
21
|
+
"type": "command",
|
|
22
|
+
"shell": "bash",
|
|
23
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/build-gate.sh\"",
|
|
24
|
+
"timeout": 20
|
|
25
|
+
}
|
|
26
|
+
]
|
|
16
27
|
}
|
|
17
28
|
],
|
|
18
29
|
"PostToolUse": [
|
|
@@ -40,6 +51,42 @@
|
|
|
40
51
|
}
|
|
41
52
|
]
|
|
42
53
|
}
|
|
54
|
+
],
|
|
55
|
+
"PreCompact": [
|
|
56
|
+
{
|
|
57
|
+
"hooks": [
|
|
58
|
+
{
|
|
59
|
+
"type": "command",
|
|
60
|
+
"shell": "bash",
|
|
61
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-lifecycle.sh\"",
|
|
62
|
+
"timeout": 15
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"SubagentStop": [
|
|
68
|
+
{
|
|
69
|
+
"hooks": [
|
|
70
|
+
{
|
|
71
|
+
"type": "command",
|
|
72
|
+
"shell": "bash",
|
|
73
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-lifecycle.sh\"",
|
|
74
|
+
"timeout": 15
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"SessionEnd": [
|
|
80
|
+
{
|
|
81
|
+
"hooks": [
|
|
82
|
+
{
|
|
83
|
+
"type": "command",
|
|
84
|
+
"shell": "bash",
|
|
85
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-lifecycle.sh\"",
|
|
86
|
+
"timeout": 10
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
}
|
|
43
90
|
]
|
|
44
91
|
}
|
|
45
92
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PreCompact · SessionEnd · SubagentStop — the three moments the run's own record
|
|
3
|
+
# cannot see, written down as they happen.
|
|
4
|
+
#
|
|
5
|
+
# One line shape for all three:
|
|
6
|
+
#
|
|
7
|
+
# event: <kind> — <detail> — <ISO-8601>
|
|
8
|
+
#
|
|
9
|
+
# **Why one shape and not three.** A ledger grammar is read by four documents and
|
|
10
|
+
# two hooks; every shape added is a shape each of them must learn. These three are
|
|
11
|
+
# the same kind of fact — something happened to the RUN rather than to a stage —
|
|
12
|
+
# and a `kind` field costs one word against three grammars.
|
|
13
|
+
#
|
|
14
|
+
# WHAT EACH ONE IS FOR
|
|
15
|
+
#
|
|
16
|
+
# compact — the ledger exists because compaction happens; `templates/run.md`
|
|
17
|
+
# says so in its own header. Until now the boundary itself was the
|
|
18
|
+
# one event the file could not show, so a resumed run could not
|
|
19
|
+
# tell "the context was compacted here" from "nothing happened".
|
|
20
|
+
# session-end — a run whose session ended without reaching acceptance is
|
|
21
|
+
# ABANDONED, and abandoned runs are exactly what
|
|
22
|
+
# `/task-pipeline checkup` exists to surface. Before this they
|
|
23
|
+
# were invisible: the ledger simply stopped, which looks identical
|
|
24
|
+
# to a run still in progress.
|
|
25
|
+
# subagent — stage 5 dispatches implementers as subagents, and the `hand:`
|
|
26
|
+
# line counts them. Both sides of that count are written by the
|
|
27
|
+
# same agent from the same memory, so the audit comparing them
|
|
28
|
+
# compares a number with itself.
|
|
29
|
+
#
|
|
30
|
+
# **It does NOT write `hand:` lines, and that is not a shortcut.** That shape
|
|
31
|
+
# carries `done`, `surfaced`, `decisions` and `amb` — judgements only the agent
|
|
32
|
+
# holds. A hook filling them in would be fabricating the very evidence the line
|
|
33
|
+
# exists to provide. So it records what it can actually see (a subagent of this
|
|
34
|
+
# type stopped) and leaves the accounting to whoever can account.
|
|
35
|
+
#
|
|
36
|
+
# Silent with no ledger, and never blocking: none of these events should ever cost
|
|
37
|
+
# a session. `SessionEnd` hooks share a 1.5-second budget, so this appends one line
|
|
38
|
+
# and exits.
|
|
39
|
+
set -uo pipefail
|
|
40
|
+
|
|
41
|
+
input=$(cat 2>/dev/null || true)
|
|
42
|
+
project="${CLAUDE_PROJECT_DIR:-$PWD}"
|
|
43
|
+
ledger="$project/.task-pipeline/run.md"
|
|
44
|
+
[ -f "$ledger" ] || exit 0
|
|
45
|
+
|
|
46
|
+
HOOK_INPUT="$input" python3 - "$ledger" <<'PY' 2>/dev/null || true
|
|
47
|
+
import json, os, sys, datetime, re
|
|
48
|
+
|
|
49
|
+
ledger = sys.argv[1]
|
|
50
|
+
try:
|
|
51
|
+
data = json.loads(os.environ.get("HOOK_INPUT", ""))
|
|
52
|
+
except Exception:
|
|
53
|
+
raise SystemExit(0)
|
|
54
|
+
|
|
55
|
+
event = data.get("hook_event_name")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def clean(text, limit=90):
|
|
59
|
+
"""One line, no separators that would break the ledger's own grammar."""
|
|
60
|
+
s = re.sub(r"\s+", " ", str(text or "")).replace("—", "-").strip()
|
|
61
|
+
return s[:limit]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if event == "PreCompact":
|
|
65
|
+
kind, detail = "compact", clean(data.get("trigger") or "unknown")
|
|
66
|
+
elif event == "SessionEnd":
|
|
67
|
+
# A run that reached acceptance is finished, not abandoned. Recording an end
|
|
68
|
+
# for it would fill `checkup` with runs that closed exactly as intended.
|
|
69
|
+
try:
|
|
70
|
+
text = open(ledger, encoding="utf-8").read()
|
|
71
|
+
except Exception:
|
|
72
|
+
raise SystemExit(0)
|
|
73
|
+
stages = [l.strip() for l in text.splitlines() if l.strip().startswith("stage:")]
|
|
74
|
+
closed = any(re.search(r"verdict\s+pass", l) and re.search(r"accept", l, re.I) for l in stages)
|
|
75
|
+
if closed:
|
|
76
|
+
raise SystemExit(0)
|
|
77
|
+
kind = "session-end"
|
|
78
|
+
detail = "%s - run not closed, no acceptance recorded" % clean(data.get("reason") or "other", 40)
|
|
79
|
+
elif event == "SubagentStop":
|
|
80
|
+
kind = "subagent"
|
|
81
|
+
detail = clean(data.get("agent_type") or "unknown", 40)
|
|
82
|
+
else:
|
|
83
|
+
raise SystemExit(0)
|
|
84
|
+
|
|
85
|
+
stamp = datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
|
|
86
|
+
with open(ledger, "a", encoding="utf-8") as fh:
|
|
87
|
+
fh.write('event: %s — %s — %s\n' % (kind, detail, stamp))
|
|
88
|
+
PY
|
|
89
|
+
exit 0
|
|
@@ -31,6 +31,7 @@ maintains them and the next run reads them as current.
|
|
|
31
31
|
- Absent is a word, never a zero
|
|
32
32
|
- The `holds:` line — what the run is still holding
|
|
33
33
|
- The observation beside the claim
|
|
34
|
+
- The run's own lifecycle
|
|
34
35
|
- The run ledger this reads from
|
|
35
36
|
- Rationalizations
|
|
36
37
|
|
|
@@ -336,6 +337,20 @@ written from memory is a summary that is confidently wrong exactly when it matte
|
|
|
336
337
|
a gate that reads a verdict typed by the agent it constrains is the same shape
|
|
337
338
|
again, and it looks like enforcement while being a mirror.
|
|
338
339
|
|
|
340
|
+
## The run's own lifecycle
|
|
341
|
+
|
|
342
|
+
Three moments the rail cannot show, recorded by `hooks/run-lifecycle.sh` as
|
|
343
|
+
|
|
344
|
+
```
|
|
345
|
+
event: <compact|session-end|subagent> — <detail> — <ISO-8601>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The rail reads none of them; `checkup` reads `session-end`, which is how an
|
|
349
|
+
abandoned run stops being invisible. Before this the ledger simply stopped at
|
|
350
|
+
whatever stage the session died on — and a stopped ledger is indistinguishable
|
|
351
|
+
from a run still in progress, which is the exact shape *absent is a word, never a
|
|
352
|
+
zero* exists to refuse.
|
|
353
|
+
|
|
339
354
|
## The run ledger this reads from
|
|
340
355
|
|
|
341
356
|
`.task-pipeline/run.md`, seeded at stage 0 from
|
|
@@ -29,6 +29,7 @@ touch: <file> — pass <N> (<stage|round|module>) — reason: <finding id / gate
|
|
|
29
29
|
hand: <N|10> — task "<quoted>" — done <n> — surfaced <n> — decisions <n> — amb <n> (<ids or "— no register">)
|
|
30
30
|
holds: <stage id> — <n> (<class: what, owner>; … or "none") — enumerated <n>/8 classes, <unlooked: classes not enumerable>
|
|
31
31
|
gate: <stage id> — command "<cmd>" — exit <N> — <ISO-8601>
|
|
32
|
+
event: <compact|session-end|subagent> — <detail> — <ISO-8601>
|
|
32
33
|
```
|
|
33
34
|
|
|
34
35
|
- **`stage:`** — written when a gate **returns**, not when the stage is entered. The
|
|
@@ -42,6 +43,19 @@ gate: <stage id> — command "<cmd>" — exit <N> — <ISO-8601>
|
|
|
42
43
|
constrains and confirms an assertion with itself. Absent where the project
|
|
43
44
|
declares no command, and the release gate then degrades to the claim alone.
|
|
44
45
|
|
|
46
|
+
- **`event:`** — written by `hooks/run-lifecycle.sh`, the three moments this file
|
|
47
|
+
otherwise cannot show. `compact` marks the boundary the ledger exists *because
|
|
48
|
+
of* — without it a resumed run cannot tell a compaction from nothing happening.
|
|
49
|
+
`session-end` marks a run whose session ended without reaching acceptance, which
|
|
50
|
+
is what `/task-pipeline checkup` looks for and what was previously invisible: the
|
|
51
|
+
ledger simply stopped, and a stopped ledger looks exactly like a run still in
|
|
52
|
+
progress. `subagent` records one finishing, so the `hand:` count below has
|
|
53
|
+
something to be checked against other than itself.
|
|
54
|
+
|
|
55
|
+
**It never writes a `hand:` line.** That shape carries `done`, `surfaced`,
|
|
56
|
+
`decisions` and `amb` — judgements only the agent holds, and a hook filling them
|
|
57
|
+
in would fabricate the evidence the line exists to provide.
|
|
58
|
+
|
|
45
59
|
- **`iter:`** — one line per iteration closed. The progress line's counter is
|
|
46
60
|
`grep -c '^iter:'`, never a number anyone remembers.
|
|
47
61
|
- **`hand:`** — one per hand-back, at an iteration's close and at stage 10
|
|
@@ -69,6 +83,8 @@ stage: 1 Docs study — gate auto — verdict pass — 2026-08-10T11:31Z
|
|
|
69
83
|
touch: src/export.ts — pass 1 (stage 5) — reason: TASK-3
|
|
70
84
|
touch: src/export.ts — pass 2 (stage 5) — reason: F-014
|
|
71
85
|
touch: src/export.ts — pass 3 (stage 5) — reason: F-014
|
|
86
|
+
event: compact — auto — 2026-08-10T11:58Z
|
|
87
|
+
event: subagent — general-purpose — 2026-08-10T12:00Z
|
|
72
88
|
gate: 6 — command "npm test" — exit 0 — 2026-08-10T12:02Z
|
|
73
89
|
stage: 6 Tests — gate manual — verdict pass — 2026-08-10T12:03Z
|
|
74
90
|
hand: 3 — task "add CSV export to the orders table" — done 2 — surfaced 1 — decisions 1 — amb 2 (OQ-0007, ledger row 4)
|