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.
- package/CHANGELOG.md +105 -0
- package/README.md +42 -9
- package/SKILL-CARD.md +1 -1
- package/bin/task-pipeline.js +64 -33
- package/cursor/rules/task-pipeline.mdc +10 -5
- package/evals/RESULTS.md +1 -1
- package/evals/task-pipeline.evals.json +16 -0
- package/package.json +3 -3
- package/plugins/task-pipeline/.claude-plugin/plugin.json +1 -1
- package/plugins/task-pipeline/agents/verifier.md +4 -1
- package/plugins/task-pipeline/commands/task-pipeline.md +22 -8
- package/plugins/task-pipeline/hooks/memory-nudge.sh +45 -3
- package/plugins/task-pipeline/skills/evidence-docs/references/gates.md +6 -3
- package/plugins/task-pipeline/skills/evidence-docs/references/hooks.md +2 -1
- package/plugins/task-pipeline/skills/evidence-docs/references/retrospective.md +26 -1
- package/plugins/task-pipeline/skills/task-pipeline/SKILL.md +13 -11
- package/plugins/task-pipeline/skills/task-pipeline/graph.schema.json +89 -4
- package/plugins/task-pipeline/skills/task-pipeline/pipeline.schema.json +7 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/backlog.md +25 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/certification.md +45 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/continuity.md +94 -25
- package/plugins/task-pipeline/skills/task-pipeline/references/deploy-targets.md +30 -4
- package/plugins/task-pipeline/skills/task-pipeline/references/doctrine-map.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/gates.md +6 -3
- package/plugins/task-pipeline/skills/task-pipeline/references/grill.md +1 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/hooks.md +2 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/iteration.md +387 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/knowledge-sources.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/loop-guard.md +4 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/portability.md +1 -0
- package/plugins/task-pipeline/skills/task-pipeline/references/retrospective.md +26 -1
- package/plugins/task-pipeline/skills/task-pipeline/references/stages.md +35 -11
- package/plugins/task-pipeline/skills/task-pipeline/references/waves.md +76 -36
- package/plugins/task-pipeline/skills/task-pipeline/references/work-graph.md +54 -5
- package/plugins/task-pipeline/skills/task-pipeline/scripts/backlog_sources.py +54 -13
- package/plugins/task-pipeline/skills/task-pipeline/scripts/context_packets.py +3 -3
- package/plugins/task-pipeline/skills/task-pipeline/scripts/graph.py +205 -22
- package/plugins/task-pipeline/skills/task-pipeline/scripts/lessons.py +1137 -0
- package/plugins/task-pipeline/skills/task-pipeline/scripts/stage_checkpoint.py +108 -11
- package/plugins/task-pipeline/skills/task-pipeline/scripts/waves.py +546 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/README.md +6 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/backlog-sources.schema.json +96 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/canvas.md +97 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/dossier.md +82 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/inventory.schema.json +94 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/lesson.schema.json +221 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/questions.md +45 -0
- package/plugins/task-pipeline/skills/task-pipeline/templates/retro.md +4 -0
- 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
|
|
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
|
|
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
|