task-pipeline-skill 1.93.3 → 1.94.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +42 -9
  3. package/SKILL-CARD.md +1 -1
  4. package/bin/task-pipeline.js +64 -33
  5. package/cursor/rules/task-pipeline.mdc +10 -5
  6. package/evals/RESULTS.md +1 -1
  7. package/evals/task-pipeline.evals.json +16 -0
  8. package/package.json +3 -3
  9. package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
  10. package/plugins/task-pipeline/agents/verifier.md +4 -1
  11. package/plugins/task-pipeline/commands/task-pipeline.md +22 -8
  12. package/plugins/task-pipeline/hooks/memory-nudge.sh +45 -3
  13. package/plugins/task-pipeline/skills/evidence-docs/references/gates.md +6 -3
  14. package/plugins/task-pipeline/skills/evidence-docs/references/hooks.md +2 -1
  15. package/plugins/task-pipeline/skills/evidence-docs/references/retrospective.md +26 -1
  16. package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +13 -11
  17. package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +89 -4
  18. package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +7 -0
  19. package/plugins/task-pipeline/skills/task-pipeline/references/backlog.md +25 -0
  20. package/plugins/task-pipeline/skills/task-pipeline/references/certification.md +45 -1
  21. package/plugins/task-pipeline/skills/task-pipeline/references/continuity.md +94 -25
  22. package/plugins/task-pipeline/skills/task-pipeline/references/deploy-targets.md +30 -4
  23. package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +1 -0
  24. package/plugins/task-pipeline/skills/task-pipeline/references/gates.md +6 -3
  25. package/plugins/task-pipeline/skills/task-pipeline/references/grill.md +1 -1
  26. package/plugins/task-pipeline/skills/task-pipeline/references/hooks.md +2 -1
  27. package/plugins/task-pipeline/skills/task-pipeline/references/iteration.md +387 -0
  28. package/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md +1 -0
  29. package/plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md +4 -1
  30. package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
  31. package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +26 -1
  32. package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +35 -11
  33. package/plugins/task-pipeline/skills/task-pipeline/references/waves.md +76 -36
  34. package/plugins/task-pipeline/skills/task-pipeline/references/work-graph.md +54 -5
  35. package/plugins/task-pipeline/skills/task-pipeline/scripts/backlog_sources.py +54 -13
  36. package/plugins/task-pipeline/skills/task-pipeline/scripts/context_packets.py +3 -3
  37. package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +205 -22
  38. package/plugins/task-pipeline/skills/task-pipeline/scripts/lessons.py +1137 -0
  39. package/plugins/task-pipeline/skills/task-pipeline/scripts/stage_checkpoint.py +108 -11
  40. package/plugins/task-pipeline/skills/task-pipeline/scripts/waves.py +546 -0
  41. package/plugins/task-pipeline/skills/task-pipeline/templates/README.md +6 -0
  42. package/plugins/task-pipeline/skills/task-pipeline/templates/backlog-sources.schema.json +96 -0
  43. package/plugins/task-pipeline/skills/task-pipeline/templates/canvas.md +97 -0
  44. package/plugins/task-pipeline/skills/task-pipeline/templates/dossier.md +82 -0
  45. package/plugins/task-pipeline/skills/task-pipeline/templates/inventory.schema.json +94 -0
  46. package/plugins/task-pipeline/skills/task-pipeline/templates/lesson.schema.json +221 -0
  47. package/plugins/task-pipeline/skills/task-pipeline/templates/questions.md +45 -0
  48. package/plugins/task-pipeline/skills/task-pipeline/templates/retro.md +4 -0
  49. package/plugins/task-pipeline/skills/task-pipeline/templates/run.md +2 -2
@@ -0,0 +1,97 @@
1
+ # Canvas — <topic> (YYYY-MM-DD)
2
+
3
+ The target state of the next version, laid over today's logic: wave mode's committed
4
+ target-state spec (`references/waves.md` → *The canvas*), written at step 3 of an iteration
5
+ (`references/iteration.md` → *Integration, until it converges*). The machine-readable plan
6
+ is `<topic>-plan.json` (or the work graph), the inventory is `<topic>-inventory.json`
7
+ (inventory/1), and the question queue is `<topic>-questions.md`. This page cites the
8
+ dossiers by section and does not repeat them.
9
+
10
+ **Read at:** <repository @ commit, one per repository the canvas touches — the state this
11
+ design was laid over>.
12
+
13
+ **Decisions applied without re-opening:** <each recorded decision this canvas rests on, with
14
+ its citation>.
15
+
16
+ ## Contents
17
+
18
+ - 1. As-is → to-be
19
+ - 2. The integration seams
20
+ - 3. Item → module → node → wave
21
+ - 4. Deleted or superseded
22
+ - 5. Remaining conflicts → questions
23
+ - The waves
24
+
25
+ ## 1. As-is → to-be
26
+
27
+ ### Per module
28
+
29
+ | Module | As-is (the facts that matter) | To-be | Dossier |
30
+ |---|---|---|---|
31
+ | A <name> | <today, with file:line> | <the next version> | <dossier § sections> |
32
+
33
+ ### Per contract
34
+
35
+ | Contract | Owner | Change | Nodes |
36
+ |---|---|---|---|
37
+ | <schema, wire format, doc of record, register> | <owning repository or Project on the board> | <additive / breaking / new> | <node ids> |
38
+
39
+ ## 2. The integration seams
40
+
41
+ How each integration happens, who owns each side, and what crosses it. Two dossiers that
42
+ change one seam were designed together; a ★ marks a seam that re-designed a dossier.
43
+
44
+ | Seam | What | Sides | Rule | Nodes |
45
+ |---|---|---|---|---|
46
+ | S1 | <seam> | <module ↔ module> | <the one rule both sides follow> | <node ids> |
47
+
48
+ ## 3. Item → module → node → wave
49
+
50
+ Generated, not hand-written: `scripts/waves.py assign --modules <modules.json> --plan
51
+ <plan.json> --write`, then `waves.py count`. Every inventory item is a row. An item on no
52
+ node is closed with its receipt, carried (`release: program`, with the reason), or a gap in
53
+ this canvas — `waves.py validate` exits 1 on the last.
54
+
55
+ | Item | Module | Node(s) | Wave(s) | Status |
56
+ |---|---|---|---|---|
57
+ | <ID-001> | <A> | <A-1> | <1> | <holds / changed / fixed: receipt / carried: reason> |
58
+
59
+ ## 4. Deleted or superseded
60
+
61
+ What the next version removes — code, screens, contracts, docs, rows — and which node
62
+ removes it. A removal nobody wrote down survives the release.
63
+
64
+ | Node | Removes |
65
+ |---|---|
66
+ | <A-1> | <the old path, the doc sentence, the register row> |
67
+
68
+ ## 5. Remaining conflicts → questions
69
+
70
+ What integration could not settle, each a row in `<topic>-questions.md` with both designs
71
+ attached.
72
+
73
+ 1. <conflict> → <question id>
74
+
75
+ ---
76
+
77
+ ## The waves
78
+
79
+ Cut per `references/waves.md` → *Cutting the waves*: a wave holds only items closable in one
80
+ pass; wave 1 is the walking skeleton; lanes run in parallel inside a wave and respect file
81
+ ownership. Each node carries its own risk class (`references/iteration.md` → *Verification
82
+ starts when a node lands*): R1 one passing round, R2 two, R3 three, one of them recorded adversarial.
83
+
84
+ **Counts:** <from `waves.py count` and the graph: nodes by risk, by wave, out of waves>.
85
+
86
+ ### Wave 1: <name>
87
+
88
+ **Exit criteria, written before the wave starts:**
89
+ - <the tests, the live walk, the gates and the documents that will prove it closed>
90
+
91
+ **Nodes by lane:**
92
+
93
+ | Lane | Nodes |
94
+ |---|---|
95
+ | <lane> | <A-1 R2 → A-2 R1> |
96
+
97
+ **Seam checks:** <{node, node} the seam group checked once its last node lands>.
@@ -0,0 +1,82 @@
1
+ # Dossier <letter> — <module name>
2
+
3
+ One dossier per cluster of inventory items (`references/iteration.md` → *Module dossiers*),
4
+ written in parallel with the others, read-only on every repository: the dossier is the only
5
+ write. **A dossier is a design, not a plan** — it does not cut waves. Evidence for every
6
+ claim: `file:line @commit`, or a command and its output. No secret values, ever.
7
+
8
+ Written <date> against: <repository @ commit, one per repository read>.
9
+
10
+ ## Contents
11
+
12
+ - 1. Items
13
+ - 2. As-is
14
+ - 3. To-be
15
+ - 4. Options considered
16
+ - 5. Contracts touched
17
+ - 6. Nodes
18
+ - 7. Deletes
19
+ - 8. Questions
20
+ - 9. Out of scope / program
21
+
22
+ ## 1. Items
23
+
24
+ Every inventory item the module table assigns here, verified against the code before it is
25
+ trusted. An item that does not reproduce is marked so, with the evidence, and closed in its
26
+ owning register.
27
+
28
+ | id | title (short) | still holds? (yes / no + evidence / changed) | severity |
29
+ |---|---|---|---|
30
+ | <ID-001> | <…> | <…> | <…> |
31
+
32
+ ## 2. As-is
33
+
34
+ How the module works today, in the few facts that matter, each with `file:line`.
35
+
36
+ ## 3. To-be
37
+
38
+ The design of the next version: contracts, data, behaviour, failure handling and logs. One
39
+ coherent design that answers every item; say which items each part answers.
40
+
41
+ ## 4. Options considered
42
+
43
+ | Choice | Options | Chosen | Why |
44
+ |---|---|---|---|
45
+ | <the real choice> | (a) … (b) … | <…> | <the reason, with the measurement where there is one> |
46
+
47
+ ## 5. Contracts touched
48
+
49
+ | Contract | Owner (repository / session) | Change | Owner must agree first? |
50
+ |---|---|---|---|
51
+ | <interface, schema, wire format, doc of record, register> | <…> | <additive / breaking / new> | <yes / no> |
52
+
53
+ ## 6. Nodes
54
+
55
+ The design cut into build nodes. **The risk class is per node**, never one class for the
56
+ whole dossier: one R3 node beside four R1 nodes is five classes, and a dossier-wide class
57
+ either over-checks the four or under-checks the one (`references/iteration.md` →
58
+ *Verification starts when a node lands*). Files owned by one node only, where possible.
59
+
60
+ | id | repo | owns (files) | does | tests (★ = fails today) | risk | deps | one pass? |
61
+ |---|---|---|---|---|---|---|---|
62
+ | <X-1> | <…> | <paths> | <…> | ★ <the test that fails today>; <…> | <R1 / R2 / R3> | <node ids> | <yes / no> |
63
+
64
+ Count by risk: <R1 n · R2 n · R3 n>.
65
+
66
+ ## 7. Deletes
67
+
68
+ What the new version removes — code, docs, rows, files — by node.
69
+
70
+ ## 8. Questions
71
+
72
+ Only what the sources cannot answer: the operator's recorded decisions, ADRs and
73
+ principles, the code and the neighbours' contracts were tried first.
74
+
75
+ | id | question | options → consequence | recommendation | whose (operator / peer: name it) | blocks |
76
+ |---|---|---|---|---|---|
77
+ | Q1 | <…> | (a) … → … (b) … → … | <…> | <…> | <node ids> |
78
+
79
+ ## 9. Out of scope / program
80
+
81
+ Items recommended for a later release, each with its reason (`release: program` in the
82
+ inventory).
@@ -0,0 +1,94 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/templates/inventory.schema.json",
4
+ "title": "inventory/1 — <artifacts>/specs/YYYY-MM-DD-<topic>-inventory.json",
5
+ "description": "Wave 0's single machine-readable inventory: one item per open item of the board, every survey and every harvested source (references/waves.md, Wave 0). scripts/waves.py merges audit outputs into it (`merge`), writes `module`, `node`, `wave` and `release` from two short tables (`assign`), counts it (`count`) and refuses an item that lands nowhere (`validate`). The document is an object carrying `schema` and `items`; a bare array of items is read as the items of one. Fields a project needs beyond these go under an `x-` prefix.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["schema", "items"],
9
+ "properties": {
10
+ "schema": {"const": "inventory/1"},
11
+ "topic": {"type": "string"},
12
+ "items": {"type": "array", "items": {"$ref": "#/$defs/item"}}
13
+ },
14
+ "$defs": {
15
+ "item": {
16
+ "type": "object",
17
+ "additionalProperties": false,
18
+ "patternProperties": {"^x-[a-z0-9-]+$": {}},
19
+ "required": ["id", "title", "area", "kind", "severity", "evidence", "proposed_fix"],
20
+ "properties": {
21
+ "id": {
22
+ "description": "The item's id in its owning register. An item without one gets one there, in the same change. Unique across the inventory.",
23
+ "type": "string",
24
+ "pattern": "^[A-Za-z][A-Za-z0-9._-]{0,63}$"
25
+ },
26
+ "title": {"type": "string", "minLength": 3},
27
+ "area": {"description": "The part of the system it touches.", "type": "string", "minLength": 1},
28
+ "kind": {
29
+ "description": "What sort of item: e.g. bug, gap, weak-impl, contradiction, doc-wrong, doc-missing, plan.",
30
+ "type": "string",
31
+ "pattern": "^[a-z][a-z0-9-]*$"
32
+ },
33
+ "severity": {"enum": ["critical", "high", "medium", "low", "info"]},
34
+ "evidence": {
35
+ "description": "The receipt: file:line at a commit, or a command and its output. A finding is a fact with a receipt, never an impression.",
36
+ "oneOf": [
37
+ {"type": "string", "minLength": 3},
38
+ {"type": "array", "minItems": 1, "items": {"type": "string", "minLength": 3}}
39
+ ]
40
+ },
41
+ "proposed_fix": {"type": "string", "minLength": 1},
42
+ "status": {
43
+ "description": "As measured, not as the register last said. Absent means open. Every value but open and changed is terminal; carried means release program with a reason.",
44
+ "enum": ["open", "changed", "closed", "fixed", "fixed-elsewhere", "duplicate", "moved", "stale", "not-reproduced", "carried"],
45
+ "default": "open"
46
+ },
47
+ "source": {"description": "Where it was found, when that differs from the evidence: a register row as file:line, or the command that surfaced it.", "type": "string"},
48
+ "source_file": {"description": "The survey output it was merged from (written by `waves.py merge`).", "type": "string"},
49
+ "repo": {"type": "string"},
50
+ "module": {"description": "The dossier cluster it belongs to (written by `waves.py assign` from the module table).", "type": "string"},
51
+ "node": {
52
+ "description": "The canvas nodes that close it, in wave order (written by `waves.py assign` from the plan's `closes`).",
53
+ "type": "array",
54
+ "items": {"type": "string"},
55
+ "uniqueItems": true
56
+ },
57
+ "wave": {"description": "The wave that closes it: the last wave among its nodes. Null when it is carried to a later release.", "type": ["integer", "null"], "minimum": 1},
58
+ "release": {"enum": ["this", "program"]},
59
+ "register_id": {"type": ["string", "null"]},
60
+ "blocked_by": {"type": "array", "items": {"type": "string"}},
61
+ "closable_in_one_pass": {"type": "boolean"},
62
+ "needs_operator": {"type": "boolean"},
63
+ "notes": {"type": "string"}
64
+ }
65
+ },
66
+ "modules": {
67
+ "description": "The module table `assign --modules` reads: module name -> the item ids it holds. An id in two modules is refused. Edited as the canvas is cut; a re-cut is a diff to this table.",
68
+ "type": "object",
69
+ "additionalProperties": {"type": "array", "items": {"type": "string"}, "uniqueItems": true}
70
+ },
71
+ "plan": {
72
+ "description": "The wave plan `assign --plan` and `sync-graph` read: any JSON whose `nodes` lists {id, wave, closes}. A work graph that carries `closes` on its nodes is one. A node whose wave is not an integer is carried (`release: program`).",
73
+ "type": "object",
74
+ "required": ["nodes"],
75
+ "properties": {
76
+ "nodes": {
77
+ "type": "array",
78
+ "items": {
79
+ "type": "object",
80
+ "required": ["id"],
81
+ "properties": {
82
+ "id": {"type": "string"},
83
+ "graph_id": {"type": "string", "pattern": "^N-[0-9]{3,}$", "description": "The work-graph node this canvas node is built as, where the two ids differ; `sync-graph` moves that node."},
84
+ "wave": {"type": ["integer", "null"], "minimum": 1},
85
+ "closes": {"type": "array", "items": {"type": "string"}},
86
+ "release": {"enum": ["this", "program"]},
87
+ "risk": {"enum": ["R1", "R2", "R3"], "description": "The node's risk class; `sync-graph` writes it onto the work-graph node (a lowering needs --lower-why), and `graph.py close` enforces the rounds it owes."}
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
@@ -0,0 +1,221 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/ssheleg/task-pipeline/blob/main/plugins/task-pipeline/skills/task-pipeline/templates/lesson.schema.json",
4
+ "title": "lesson/1",
5
+ "description": "One lesson: a retro entry's class, stated so another project's agent can use it at stage 0. The project retro is canonical; a lesson is its projection (references/iteration.md, The learning loop). scripts/lessons.py builds one from a retro entry that carries a `**Lesson:**` line and refuses anything this schema does not allow. It never carries a transcript, a value, a path outside the repository, a URL, a person's or a customer's name, or code. The origin carries the project's pseudonymous key and the evidence commit: both stay on this machine or estate, and retro.publish strips the whole origin before anything leaves (references/retrospective.md, What may leave the project).",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "schema",
10
+ "classKey",
11
+ "title",
12
+ "trigger",
13
+ "check",
14
+ "grade",
15
+ "stages",
16
+ "nouns",
17
+ "origin"
18
+ ],
19
+ "properties": {
20
+ "schema": {
21
+ "const": "lesson/1"
22
+ },
23
+ "classKey": {
24
+ "description": "The class as a slug. The identity across projects: two projects with one classKey hold one lesson, seen twice.",
25
+ "type": "string",
26
+ "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
27
+ "maxLength": 64
28
+ },
29
+ "title": {
30
+ "description": "The class in one sentence. States the class, never the incident (redaction rule 5).",
31
+ "type": "string",
32
+ "minLength": 8,
33
+ "maxLength": 160
34
+ },
35
+ "trigger": {
36
+ "description": "When it applies.",
37
+ "type": "string",
38
+ "minLength": 3,
39
+ "maxLength": 200
40
+ },
41
+ "check": {
42
+ "description": "The check that now catches it, by name.",
43
+ "type": "string",
44
+ "minLength": 3,
45
+ "maxLength": 200
46
+ },
47
+ "grade": {
48
+ "description": "The fix grade, 1-3 (references/retrospective.md, Three grades of fix).",
49
+ "type": "integer",
50
+ "minimum": 1,
51
+ "maximum": 3
52
+ },
53
+ "stages": {
54
+ "description": "The stage that owned the failure and the stage that surfaced it. A profile's stage ids need not be numbers.",
55
+ "type": "object",
56
+ "additionalProperties": false,
57
+ "required": [
58
+ "owned",
59
+ "surfaced"
60
+ ],
61
+ "properties": {
62
+ "owned": {
63
+ "type": [
64
+ "integer",
65
+ "string"
66
+ ]
67
+ },
68
+ "surfaced": {
69
+ "type": [
70
+ "integer",
71
+ "string"
72
+ ]
73
+ }
74
+ }
75
+ },
76
+ "nouns": {
77
+ "description": "3-8 search keys: what stage 0 matches the task's nouns against.",
78
+ "type": "array",
79
+ "minItems": 3,
80
+ "maxItems": 8,
81
+ "uniqueItems": true,
82
+ "items": {
83
+ "type": "string",
84
+ "minLength": 2,
85
+ "maxLength": 32
86
+ }
87
+ },
88
+ "origin": {
89
+ "description": "Where the lesson was learned. Local and estate only: retro.publish strips it.",
90
+ "type": "object",
91
+ "additionalProperties": false,
92
+ "required": [
93
+ "project",
94
+ "commit",
95
+ "retro"
96
+ ],
97
+ "properties": {
98
+ "project": {
99
+ "description": "The project's pseudonymous key: `p-` and the first 12 hex digits of the repository's root commit. Never its name: a repository name can be a customer's or a product's (redaction rule 4). The shared store receives the same key, never a `project:<slug>` id.",
100
+ "type": "string",
101
+ "pattern": "^p-[0-9a-f]{12}$"
102
+ },
103
+ "commit": {
104
+ "description": "The evidence commit, which resolves in the project's own clone.",
105
+ "type": "string",
106
+ "pattern": "^[0-9a-f]{7,40}$"
107
+ },
108
+ "retro": {
109
+ "description": "The retro file, relative to the repository, and the entry's anchor: the heading's letters and digits in any script, lowercased, every other run one hyphen. The pattern is the script's RETRO_REF, read with Unicode word characters as Python's `re` reads it.",
110
+ "type": "string",
111
+ "pattern": "^[A-Za-z0-9_][A-Za-z0-9_./-]*\\.md#[^\\W_]+(?:-[^\\W_]+)*$",
112
+ "maxLength": 200
113
+ }
114
+ }
115
+ }
116
+ },
117
+ "$defs": {
118
+ "indexEntry": {
119
+ "description": "One line of the local index (lesson-index/1): one entry per classKey, a pure function of its origins, so a rebuild from the retros equals the incremental index byte for byte.",
120
+ "type": "object",
121
+ "additionalProperties": false,
122
+ "required": [
123
+ "schema",
124
+ "id",
125
+ "classKey",
126
+ "title",
127
+ "trigger",
128
+ "check",
129
+ "grade",
130
+ "stages",
131
+ "nouns",
132
+ "seen",
133
+ "projects",
134
+ "status",
135
+ "origins"
136
+ ],
137
+ "properties": {
138
+ "schema": {
139
+ "const": "lesson-index/1"
140
+ },
141
+ "id": {
142
+ "type": "string",
143
+ "pattern": "^L-[0-9a-f]{12}$",
144
+ "description": "`L-` and the first 12 hex digits of sha256(classKey)."
145
+ },
146
+ "classKey": {
147
+ "type": "string"
148
+ },
149
+ "title": {
150
+ "type": "string"
151
+ },
152
+ "trigger": {
153
+ "type": "string"
154
+ },
155
+ "check": {
156
+ "type": "string"
157
+ },
158
+ "grade": {
159
+ "type": "integer"
160
+ },
161
+ "stages": {
162
+ "type": "object"
163
+ },
164
+ "nouns": {
165
+ "type": "array",
166
+ "items": {
167
+ "type": "string"
168
+ }
169
+ },
170
+ "seen": {
171
+ "type": "integer",
172
+ "minimum": 1,
173
+ "description": "How many origins hold the class."
174
+ },
175
+ "projects": {
176
+ "type": "integer",
177
+ "minimum": 1,
178
+ "description": "How many distinct projects hold it."
179
+ },
180
+ "status": {
181
+ "enum": [
182
+ "local",
183
+ "candidate"
184
+ ],
185
+ "description": "`candidate` when two or more projects hold it: the retro.publish queue for learned.md."
186
+ },
187
+ "origins": {
188
+ "type": "array",
189
+ "items": {
190
+ "type": "object",
191
+ "description": "Each origin's own lesson fields, its origin, and the shared-store memory id once recorded (`mem:<id>@<revision>`).",
192
+ "required": [
193
+ "project",
194
+ "commit",
195
+ "retro",
196
+ "lesson"
197
+ ],
198
+ "properties": {
199
+ "project": {
200
+ "type": "string"
201
+ },
202
+ "commit": {
203
+ "type": "string"
204
+ },
205
+ "retro": {
206
+ "type": "string"
207
+ },
208
+ "memory": {
209
+ "type": "string",
210
+ "pattern": "^mem:[^@\\s]+@[0-9]+$"
211
+ },
212
+ "lesson": {
213
+ "type": "object"
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
@@ -0,0 +1,45 @@
1
+ # Questions — <topic> (YYYY-MM-DD)
2
+
3
+ The single question queue of an iteration (`references/iteration.md` → *Question rounds —
4
+ asked in batches, never blocking*; `references/waves.md` → *The questions*). Every question
5
+ is first tried against the sources. One the sources answer is recorded under **Closed**, with
6
+ its citation, and never asked. The rest fall into three groups:
7
+ - **Operator** — ordered so prerequisite decisions come first;
8
+ - **Peers** — grouped by the repository or session that owns the answer;
9
+ - **Assumed** — taken on the recommendation because the answer is internal and reversible;
10
+ the nodes resting on each are named, so a different answer re-plans exactly those.
11
+
12
+ An outward or irreversible act is never assumed. A round is called on the first of three
13
+ triggers: the whole frontier is blocked, five questions are open, a wave boundary.
14
+
15
+ **Counts:** <N closed from sources · N operator · N peers · N assumed>.
16
+
17
+ ## Closed from the sources (not asked)
18
+
19
+ | # | Question (raised by) | Answer | Citation |
20
+ |---|---|---|---|
21
+ | C1 | <question> (<dossier or node>) | <answer> | <decision record, ADR, code at file:line, a peer's message> |
22
+
23
+ ## Operator
24
+
25
+ | # | Blocks | Question | Recommended | Consequence of each answer | Reversible? |
26
+ |---|---|---|---|---|---|
27
+ | O1 | <node ids> | <question, answerable without context> | **<answer>** | (a) <…> (b) <…> | <yes / no> |
28
+
29
+ ## Peers
30
+
31
+ | # | Blocks | Peer (repository / session) | Question | Recommended |
32
+ |---|---|---|---|---|
33
+ | P1 | <node ids> | <owner> | <question> | <answer> |
34
+
35
+ ## Assumed
36
+
37
+ | # | Assumption | Taken from | Nodes resting on it |
38
+ |---|---|---|---|
39
+ | A1 | <the recommendation, as taken> | <O1 / P1> | <node ids> |
40
+
41
+ ## Answers received
42
+
43
+ | # | From, when | Answer | Applied to |
44
+ |---|---|---|---|
45
+ | <O1> | <who, date> | <answer as given> | <nodes re-planned, or none> |
@@ -49,6 +49,10 @@ stays short precisely so that reading it in full at stage 0 stays cheap.
49
49
  - **Fix:** grade 1 (mechanical) — … / grade 2 → `R-00N` / grade 3, expires in
50
50
  2 runs
51
51
  - **The check:** … (what catches this the first time, from now on)
52
+ - **Lesson:** `<class-key>` — <the class, one sentence> · **When:** <trigger> · **Nouns:** <a>, <b>, <c>
53
+ (optional, and on ONE line: write it only when the class would be true in another
54
+ project — it makes the entry a lesson for `scripts/lessons.py add`, lesson/1. Without
55
+ it the entry stays private to this project)
52
56
  - **Commit:** `<sha>` — the change that fixed it
53
57
  - **Upstream?** … (a lesson true in any repo belongs in the skill's own
54
58
  `references/learned.md` — open an issue and say so here)
@@ -20,7 +20,7 @@ Run: `<topic>` · started `<YYYY-MM-DD>` · module map: `<path or "none">`
20
20
 
21
21
  ## `read:` — which doctrine this run actually opened
22
22
 
23
- The bundle is 40 reference files and nothing recorded which of them a run read, so **a
23
+ The bundle is 41 reference files and nothing recorded which of them a run read, so **a
24
24
  skipped file and a read one were indistinguishable** — the class every guard in this
25
25
  pipeline exists to catch, left standing over the doctrine itself.
26
26
 
@@ -48,7 +48,7 @@ same claim one level down.
48
48
  |---|---|---|
49
49
  | `unmeasured — no run ledger` | there is no ledger | nothing to read from |
50
50
  | `unmeasured — the ledger carries no read: lines` | the hook is absent, **or** the run opened no doctrine | two opposite facts, and the ledger cannot separate them, so neither is claimed |
51
- | `N of 40 reference files read — unattested`, then each unread one | the hook is installed and fired | the count alone says there is a gap, not where — and `unattested` says the ledger cannot name who wrote the lines |
51
+ | `N of 41 reference files read — unattested`, then each unread one | the hook is installed and fired | the count alone says there is a gap, not where — and `unattested` says the ledger cannot name who wrote the lines |
52
52
 
53
53
  **It is a disclosure: no floor, no direction, never a target.** A run that needs four files
54
54
  and reads four is not worse than one that reads thirty — and the moment the number becomes