@jaybeeuu/agent-cortex 2.7.0 → 2.9.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +412 -0
  2. package/README.md +87 -8
  3. package/agents/README.md +4 -4
  4. package/agents/guppi/agent.md +162 -0
  5. package/agents/guppi/claude/frontmatter.json +6 -0
  6. package/agents/guppi/pi/frontmatter.json +6 -0
  7. package/agents/plan/agent.md +6 -0
  8. package/agents/ralph/agent.md +17 -16
  9. package/agents/ralph/claude/wake.md +4 -4
  10. package/agents/ralph/pi/wake.md +15 -20
  11. package/agents/ralph-plan/agent.md +6 -0
  12. package/bin/agent-cortex.mjs +20 -1
  13. package/bin/installers/claude.mjs +1 -20
  14. package/bin/installers/pi.mjs +8 -2
  15. package/extensions/interrupt-bookmark/README.md +129 -0
  16. package/extensions/interrupt-bookmark/index.test.ts +717 -0
  17. package/extensions/interrupt-bookmark/index.ts +354 -0
  18. package/extensions/interrupt-bookmark/package.json +20 -0
  19. package/extensions/post-merge-watch/README.md +133 -0
  20. package/extensions/post-merge-watch/index.test.ts +247 -0
  21. package/extensions/post-merge-watch/index.ts +123 -0
  22. package/extensions/post-merge-watch/package.json +16 -0
  23. package/extensions/post-merge-watch/watch.test.ts +469 -0
  24. package/extensions/post-merge-watch/watch.ts +431 -0
  25. package/extensions/session-clear/README.md +74 -0
  26. package/extensions/session-clear/index.test.ts +524 -0
  27. package/extensions/session-clear/index.ts +159 -0
  28. package/extensions/session-clear/package.json +16 -0
  29. package/extensions/skill-stats/README.md +84 -3
  30. package/extensions/skill-stats/index.ts +62 -3
  31. package/extensions/skill-stats/package.json +1 -1
  32. package/extensions/skill-stats/rollup.test.ts +643 -0
  33. package/extensions/skill-stats/rollup.ts +415 -0
  34. package/extensions/skill-stats/timeline.ts +101 -0
  35. package/lib/cli.mjs +42 -1
  36. package/lib/self-update.mjs +553 -0
  37. package/package.json +1 -1
  38. package/scripts/lib/manifest.mjs +29 -0
  39. package/skills/engineering/implement-task/SKILL.md +124 -0
  40. package/skills/engineering/tdd/SKILL.md +2 -0
  41. package/skills/planning/create-task/REFERENCE.md +15 -6
  42. package/skills/planning/create-task/SKILL.md +1 -1
  43. package/skills/planning/create-task/pipeline.json +8 -0
  44. package/skills/planning/create-task/scripts/create-chores.mjs +27 -18
  45. package/skills/planning/create-task/templates/code.md +8 -3
  46. package/skills/planning/create-task/templates/document.md +8 -3
  47. package/skills/planning/create-task/templates/fix.md +8 -3
  48. package/skills/planning/create-task/templates/housekeeping.md +8 -4
  49. package/skills/planning/create-task/templates/post-merge.md +67 -0
  50. package/skills/planning/create-task/templates/review.md +8 -3
  51. package/skills/planning/create-task/templates/verify.md +8 -3
  52. package/skills/productivity/bd-tool/SKILL.md +55 -0
  53. package/skills/review/review-defects/EXAMPLES.md +198 -0
  54. package/skills/review/review-defects/SKILL.md +121 -0
  55. package/skills/review/review-report/EXAMPLES.md +114 -0
  56. package/skills/review/review-report/SKILL.md +138 -0
  57. package/skills/review/review-report/scripts/report.mjs +1032 -0
  58. package/skills/style/style-tests/EXAMPLES.md +30 -0
  59. package/skills/style/style-tests/SKILL.md +10 -6
  60. package/skills/workflow/hitl-queue/SKILL.md +134 -0
  61. package/skills/workflow/hitl-queue/scripts/queue.mjs +626 -0
  62. package/skills/workflow/plan/SKILL.md +27 -3
  63. package/skills/workflow/prioritise-work/CHALLENGE.md +139 -0
  64. package/skills/workflow/prioritise-work/SKILL.md +150 -0
  65. package/skills/workflow/prioritise-work/scripts/challenge.mjs +505 -0
  66. package/skills/workflow/prioritise-work/scripts/strategy.mjs +566 -0
  67. package/skills/workflow/prioritise-work/templates/strategy.md +61 -0
  68. package/skills/workflow/ralph/REFERENCE.md +124 -27
  69. package/skills/workflow/ralph/SKILL.md +24 -15
  70. package/skills/workflow/ralph/scripts/post-merge-check.mjs +651 -0
  71. package/skills/workflow/run-pipeline-stage/SKILL.md +37 -22
  72. package/skills/workflow/run-pipeline-stage/playbooks/code.md +14 -8
  73. package/skills/workflow/run-pipeline-stage/playbooks/document.md +2 -2
  74. package/skills/workflow/run-pipeline-stage/playbooks/fix.md +2 -2
  75. package/skills/workflow/run-pipeline-stage/playbooks/housekeeping.md +1 -1
  76. package/skills/workflow/run-pipeline-stage/playbooks/post-merge.md +54 -0
  77. package/skills/workflow/run-pipeline-stage/playbooks/review.md +37 -3
  78. package/skills/workflow/run-pipeline-stage/playbooks/verify.md +2 -2
  79. package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +55 -11
  80. package/skills/workflow/run-pipeline-stage/scripts/recover-brief.mjs +805 -0
  81. package/skills/workflow/run-pipeline-stage/scripts/trail-entry.mjs +702 -0
  82. package/skills/workflow/score-bead/FORMAT.md +73 -0
  83. package/skills/workflow/score-bead/SKILL.md +112 -0
  84. package/skills/workflow/score-bead/scripts/rice.mjs +664 -0
  85. package/skills/workflow/using-agent-skills/SKILL.md +21 -8
  86. package/token-map.README.md +27 -0
  87. package/token-map.json +16 -4
@@ -0,0 +1,198 @@
1
+ # Review defects — worked examples
2
+
3
+ One case per class. Each shows what was observed, the label, and the rejection text to write. Eleven
4
+ were observed in real review rounds; `scope-creep` is described as a situation, because no recorded
5
+ case exists, so you can match its shape without guessing at history.
6
+
7
+ ## `test-unproven` — the name claims a settle-time cleanup
8
+
9
+ **Observed.** A test named "… removes it when the watch settles" called `stop()` and asserted the
10
+ entry was gone. It never settled the watch, so the settle path had no assertion. The cleanup on
11
+ settle could have been deleted and the test would still pass.
12
+
13
+ **Label.** `defect:test-unproven`
14
+
15
+ **Rejection text.** "Test `…removes it when the watch settles` claims removal at the settle step,
16
+ but the body stops the watch and asserts removal once. Add the settle trigger and assert the entry
17
+ is gone after it. Either the name or the assertion must change."
18
+
19
+ **Why this class.** Not `test-cannot-fail`: the assertion is genuine and would fail for the bug it
20
+ covers. The defect is narrower — the name promises a path the body never takes.
21
+
22
+ ## `test-cannot-fail` — the concurrent case is never exercised
23
+
24
+ **Observed.** A note appended "a double fire appends nothing twice". The test fired twice in
25
+ sequence and asserted one entry. Two concurrent fires were never run, so the claim could not fail.
26
+
27
+ **Label.** `defect:test-cannot-fail`
28
+
29
+ **Rejection text.** "The claim is about concurrent double fires, but the test fires sequentially.
30
+ Await both fires against the same target and assert one entry, or rename the claim. As written no
31
+ implementation can fail it."
32
+
33
+ **Why this class.** Not `test-unproven`: the name and the assertion agree on "two fires produce one
34
+ entry". The gap is that the case the claim is about is never constructed.
35
+
36
+ ## `missing-proof` — a report of a demonstration that was stubbed
37
+
38
+ **Observed.** A stage report stated "end-to-end run verified: the check writes the record and the
39
+ follow-up reads it". The command in the evidence block substituted a stub for the check, so no
40
+ end-to-end path ran.
41
+
42
+ **Label.** `defect:missing-proof`
43
+
44
+ **Rejection text.** "`SUMMARY` claims an end-to-end demonstration; the evidence command replaces the
45
+ check with a stub, so the record is written by the test, not by the code under review. Paste the
46
+ real invocation and its output."
47
+
48
+ **Why this class.** Nothing is missing from the code. The gap is between the claim and the evidence
49
+ for it, which is exactly what this class names.
50
+
51
+ ## `docs-drift` — shipped text that shipped past its change
52
+
53
+ **Observed.** Two shipped text defects in one round: a token map named an exact harness version, so
54
+ the mapping broke on the next release; and a peer-channel section still said one harness only, after
55
+ the fork had made it both.
56
+
57
+ **Label.** `defect:docs-drift`
58
+
59
+ **Rejection text.** "The token map names an exact harness version — it must read the running one or
60
+ a documented default. The peer-channel section says one harness only, but the mapping now covers
61
+ both; update the prose to what ships."
62
+
63
+ **Why this class.** The shipped artefact and the text describing it disagree. A reviewer reading the
64
+ text would predict behaviour the install does not have.
65
+
66
+ ## `criteria-unmet` — the change breaks the criterion it must satisfy
67
+
68
+ **Observed.** A criterion said an install leaves one directory free of the tool's own files. The
69
+ change wrote its state record into that very directory, so the reviewer could not affirm the
70
+ criterion at all.
71
+
72
+ **Label.** `defect:criteria-unmet`
73
+
74
+ **Rejection text.** "The criterion says that directory holds no file of ours; the new record is
75
+ written into it, so the criterion fails. Move the record under the tool's own state directory,
76
+ keyed by the directory it describes, or amend the criterion in the bead and say why."
77
+
78
+ **Why this class.** The work is real and the scope is honest — part of what was asked is absent.
79
+
80
+ ## `scope-creep` — unrelated tidying rides along
81
+
82
+ **Situation.** A change that adds one label also renames three unrelated helpers and reformats a
83
+ neighbouring module.
84
+
85
+ **Label.** `defect:scope-creep`
86
+
87
+ **Rejection text.** "The rename and the reformat are outside the criteria. Split them into their own
88
+ change so this one can be reviewed and reverted on its own."
89
+
90
+ **Why this class.** Every line is defensible in isolation. The defect is that the change is wider
91
+ than its reason, which hides the real diff.
92
+
93
+ ## `style-violation` — a written rule is broken
94
+
95
+ **Observed.** A change added a new skill and declared a `patch` bump in its changeset. The
96
+ versioning rule says a new skill is a `minor` bump and lists "wrong bump type" as a red flag. The
97
+ reviewer rejected the change citing that rule.
98
+
99
+ **Label.** `defect:style-violation`
100
+
101
+ **Rejection text.** "The changeset declares `patch`, but this change adds a skill. The versioning
102
+ rule makes an addition `minor` and calls a wrong bump type a red flag. Bump it to `minor`."
103
+
104
+ **Why this class.** Cite the rule, not a preference. A reviewer who cannot quote a written rule has
105
+ a preference, and preferences are not rejections.
106
+
107
+ ## `regression` — an existing behaviour breaks
108
+
109
+ **Observed.** A code stage added a manifest write that assumed its target directory existed. An
110
+ install from a source holding no agents and no skills had worked before; after the change it threw
111
+ `ENOENT` on that write. The stage found it in its own check of the change, reproduced it, added a
112
+ test that failed, then fixed it.
113
+
114
+ **Label.** `defect:regression`
115
+
116
+ **Rejection text.** "The manifest write assumes its directory exists, so an install from a source
117
+ with no agents and no skills now throws `ENOENT` where it used to succeed. Create the directory
118
+ before writing, and cover the empty-source case with a test."
119
+
120
+ **Why this class.** The change may satisfy its own criteria fully. It also breaks behaviour nobody
121
+ asked to change, which is a separate fact from `criteria-unmet`.
122
+
123
+ ## `unsafe-instruction` — a documented command that ran the reader's text
124
+
125
+ **Observed.** A shipped skill documented `bd note <bead> "<entry>"` and told the reader to embed a
126
+ free-text entry, including text the user had typed. Following it with an entry containing `$(…)`
127
+ ran the substitution when the line was pasted, and an entry containing a `"` ended the quoted
128
+ argument early and corrupted the note. The sentence had shipped for many releases and still
129
+ described the command correctly: the command does record a note.
130
+
131
+ **Label.** `defect:unsafe-instruction`
132
+
133
+ **Rejection text.** "The note command takes free text through a double-quoted shell argument, so a
134
+ `$(…)` in the entry executes and a `"` truncates the note. Write the entry with `--out` and pass it
135
+ with `bd note --file`, and say why. A reader on an arbitrary machine pastes this line as written."
136
+
137
+ **Why this class.** Not `docs-drift`: the text matches the command's behaviour. Not
138
+ `style-violation`: no convention was broken. The defect is the consequence of following the text —
139
+ data loss and code execution on a machine the author never sees.
140
+
141
+ ## `ambiguous-rule` — two plausible readings of one rule
142
+
143
+ **Observed.** Two in one round. A bead described a runtime that supplies "mail, rigs and pane
144
+ conventions" and said the persona behaves the same in every scope, so a reader could take "rigs" as
145
+ true of personal work too; the real rule is that rigs are code-project containers and personal work
146
+ is a town-level scope with no rig. Separately, a shipped doc printed a live substitution token of
147
+ the `TOOL` kind — a full token, colon and key included — to illustrate the token grammar, and the
148
+ token guard necessarily rejects a literal token in a shipped doc: the line read both as an example
149
+ and as a token that must resolve.
150
+
151
+ **Label.** `defect:ambiguous-rule`
152
+
153
+ **Rejection text.** "Two readings are possible and the text picks neither. 'Mail, rigs and pane
154
+ conventions' reads as true of personal work; state that rigs are code-project containers and that
155
+ personal work is a town-level scope with no rig. The doc prints a literal substitution token of the
156
+ `TOOL` kind, which the guard reads as unresolved; show the grammar without a literal token, or mark
157
+ the line as an example the guard must skip."
158
+
159
+ **Why this class.** Not `docs-drift`: nothing was stale — each statement was true of the code
160
+ projects it described. The text can be read two ways, and the reader who takes the wrong one cannot
161
+ tell from the words.
162
+
163
+ ## `silent-degradation` — a guard that reported success on the tree it never read
164
+
165
+ **Observed.** A materialiser check walked one harness's generated tree for leftover substitution
166
+ tokens and reported success, while the other harness's tree shipped a literal token to readers. The
167
+ guard was real and its assertion genuine; it never looked at half the surface, so it reported "no
168
+ offenders" for a tree it had not read. A second instance in the same area: a token row whose
169
+ second-harness column was empty dropped the token silently, leaving a sentence with a hole in it
170
+ and no warning.
171
+
172
+ **Label.** `defect:silent-degradation`
173
+
174
+ **Rejection text.** "The guard reads one harness's tree only; the other tree ships an unsubstituted
175
+ token and the check passes. Walk every generated tree, and fail on an empty token row rather than
176
+ dropping the token. A skipped check must not report success."
177
+
178
+ **Why this class.** Not `test-cannot-fail`: the assertion would fail for a token in the tree it
179
+ reads. The defect is the unread surface, plus a mapping that degrades to prose with no warning — a
180
+ path that fails quietly, which is wider than one test.
181
+
182
+ ## `unclassified` — the escape hatch, before the class existed
183
+
184
+ **Observed.** The unsafe instruction above was rejected before `unsafe-instruction` existed. No
185
+ class fit, so the reviewer forced the nearest one and the finding went out as `defect:docs-drift`.
186
+ Nothing in the text was stale, the fix had nothing to do with documentation, and the aggregate
187
+ counted a documentation defect where the risk was a destructive command. That mislabel is the case
188
+ this section exists to correct.
189
+
190
+ **Label.** `defect:unclassified`
191
+
192
+ **Rejection text.** "No class fits: this is an instruction that can destroy data or run a command,
193
+ not stale text. Applied `defect:unclassified` alone and proposed an `unsafe-instruction` class in a
194
+ bead. Do not read this as a documentation defect."
195
+
196
+ **Why this class.** It is the escape hatch, and the obligation is the point: it was applied with a
197
+ gap bead proposing the missing class. Without that bead it is a miscount with a nicer name, and the
198
+ class is not a pass on the review.
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: review-defects
3
+ description: The closed vocabulary of `defect:<class>` labels a reviewer applies to a rejected bead, so rejections become countable data. Use when rejecting a change, when deciding which class names a finding, or when querying which defects recur.
4
+ ---
5
+
6
+ # Review defects
7
+
8
+ A rejection says what is wrong. The class says *which kind* of wrong, in one word, so rejections can
9
+ be counted, compared and trended across tasks instead of re-read one at a time.
10
+
11
+ ## One closed list, one label per rejection
12
+
13
+ Apply exactly one class from this table. Never invent one.
14
+
15
+ The **Distinct from** column is part of the definition: two classes that sound alike are separated
16
+ there, and a finding that matches the neighbour belongs to the neighbour.
17
+
18
+ | Class | The defect | Distinct from | Evidence the rejection must show |
19
+ |---|---|---|---|
20
+ | `test-unproven` | A test's name claims a requirement its assertions never check. | `test-cannot-fail`: there the assertion is genuine and the case is absent. | The named clause, and the assertion that is missing. |
21
+ | `test-cannot-fail` | An assertion passes against a broken implementation. | `test-unproven`: a name that outruns its body, not an assertion that cannot bite. | The case that should fail and does not. |
22
+ | `criteria-unmet` | A criterion from the bead is not delivered. | `scope-creep`: too little work, not more than was asked. | The criterion, quoted, and what is absent. |
23
+ | `scope-creep` | The change does more than the criteria ask. | `criteria-unmet`: the change is wider than its reason. | The touched behaviour that no criterion names. |
24
+ | `style-violation` | A `style-*` rule is broken. | `unsafe-instruction`: a convention broken, not a machine put at risk. | The rule, quoted, and the line that breaks it. |
25
+ | `missing-proof` | A report claims success with no evidence. | `silent-degradation`: evidence absent, not evidence that cannot be wrong. | The claim, and the command output that is absent. |
26
+ | `regression` | Behaviour that worked before now breaks. | `criteria-unmet`: it breaks something nobody asked to change. | The old behaviour, and the check that now fails. |
27
+ | `docs-drift` | Shipped text no longer matches what ships. | `ambiguous-rule`: drift is **stale**; ambiguity is **readable two ways**. | The text, and the behaviour that contradicts it. |
28
+ | `unsafe-instruction` | Shipped text that, followed on an arbitrary machine, could destroy data or run something dangerous — destructive commands, force-pushes, credential handling, overwriting user config. | `docs-drift`: the text is still true, and the hazard is the point. `style-violation`: a convention, not a consequence. | The text, quoted, the state it endangers, and a safe form to use instead. |
29
+ | `ambiguous-rule` | Wording a reasonable agent reads two ways, especially a phrase true of one context that reads as true of another. | `docs-drift`: true yesterday, false today. `criteria-unmet`: behaviour delivered, not wording. | Both readings, quoted, and the one the author intended. |
30
+ | `silent-degradation` | A path that fails quietly or passes vacuously: a skipped check reported as success, a null mapping silently dropping a token, a guard that cannot fail. | `test-cannot-fail`: one assertion that cannot bite; this is any path that cannot report. | The quiet path, what it should have reported, and the run that shows it. |
31
+ | `unclassified` | The defect matches no class. It exists so a reviewer never force-fits. | Everything: it is the honest answer when none of the others is true. | The finding, the classes considered and why each fails, and the gap bead filed for the missing class. |
32
+
33
+ Two findings of different kinds are two entries in the rejection text and one label: the class of
34
+ the finding that must be fixed first.
35
+
36
+ ## A class is a classification, not a state
37
+
38
+ The bead's own status still answers "where is this work?". The label answers "what kind of defect
39
+ was this?" — so never use it to mean blocked, in progress or done, and never add a parallel state
40
+ label.
41
+
42
+ ## Apply it
43
+
44
+ 1. Name the class in the rejection text, next to the specific reason.
45
+ 2. Apply it to the bead whose work you reject:
46
+
47
+ ```bash
48
+ bd update <id> --add-label defect:test-unproven
49
+ ```
50
+
51
+ That bead is normally already closed — a pipeline closes the chore whose work is rejected before
52
+ the review runs — and the label attaches to it anyway. So the queries below pass `--all`.
53
+
54
+ 3. Write the specific reason — the file, the line, the missing assertion — in the rejection text.
55
+ The label is queryable; it is never the whole message.
56
+
57
+ ## Remove it when the fix closes
58
+
59
+ The review that confirms the fix removes the label, so the vocabulary describes only defects whose
60
+ fix is unconfirmed:
61
+
62
+ ```bash
63
+ bd update <id> --remove-label defect:test-unproven
64
+ ```
65
+
66
+ Record the removal in that review's trail entry ("`defect:test-unproven` cleared"), not as a label.
67
+ A closed defect is a fact in the trail, not a second class.
68
+
69
+ ## No class fits: the escape hatch
70
+
71
+ Apply `defect:unclassified` when none of the classes above describes the finding. It exists so you
72
+ never force-fit, because a forced label corrupts the aggregate the feedback loop reads: the classes
73
+ are counted, so a `docs-drift` label on a dangerous instruction reports a text problem where the
74
+ risk was a machine at risk.
75
+
76
+ Applying it carries an obligation. The class is not a pass:
77
+
78
+ 1. Say in the rejection text that no class fits, and name the classes you considered.
79
+ 2. File a bead proposing the class that should have covered the finding, with this finding as its
80
+ case.
81
+ 3. Name that bead in the rejection text.
82
+
83
+ Without step 2 the label records a defect and teaches nothing — silent degradation of the aggregate,
84
+ which is the exact failure the class exists to prevent. An escape hatch without the bead is a
85
+ miscount with a nicer name.
86
+
87
+ ## A label off this list is not a class
88
+
89
+ Any other `defect:*` label is not a class: the report prints it as vocabulary drift and counts it as
90
+ nothing. Inventing one is a review defect, and the escape hatch is the only honest way to say "no
91
+ class fits".
92
+
93
+ The vocabulary stays closed. A class is added by changing this file with the owner, never invented
94
+ inside a review, and adding one does not licence the next reviewer to add another. Applying a class
95
+ that does not fit is a review defect in itself, whatever the class: a label is never a near-miss.
96
+
97
+ ## Query it
98
+
99
+ ```bash
100
+ bd list -l defect:test-unproven --all # one class, any status
101
+ bd list -l defect:unclassified --all # the escape hatch: each names the gap bead filed
102
+ bd list --label-pattern 'defect:*' --all # every defect, any class
103
+ ```
104
+
105
+ `--all` is not optional. `bd list` hides closed beads by default, defects are historical data, and
106
+ the bead carrying one is usually closed: drop the flag and the query reports "No issues found" on
107
+ a label that is set.
108
+
109
+ Count the pattern output per class to see what recurs, and fix the process that produces it — a
110
+ class that keeps appearing is a gap in the stage before this one.
111
+
112
+ ## Worked examples
113
+
114
+ `EXAMPLES.md` carries one real case per class, with the rejection text a reviewer should write.
115
+
116
+ ## See Also
117
+
118
+ - [review-security](../review-security/SKILL.md) — the security verdict that precedes any rejection.
119
+ - [review-report](../review-report/SKILL.md) — counts these classes across a project and files the recurring ones upstream.
120
+ - [run-pipeline-stage](../../workflow/run-pipeline-stage/SKILL.md) — the stage that applies these labels.
121
+ - [bd-tool](../../productivity/bd-tool/SKILL.md) — labels, notes and statuses.
@@ -0,0 +1,114 @@
1
+ # Review report — worked examples
2
+
3
+ Five real runs. Each prints the same five sections; what changes is what the tracker held, and a
4
+ section with nothing to measure says so instead of printing a zero. The project names and bead ids
5
+ are fixtures, the output is verbatim.
6
+
7
+ ## No label at all
8
+
9
+ Four beads, one change, one review chore, no `defect:` label anywhere:
10
+
11
+ ```
12
+ Defect report — acme/nolabels
13
+ Reported 2026-05-01T10:00:00Z. Read 4 beads from the tracker.
14
+
15
+ Defects by class — `bd list --label-pattern 'defect:*' --all`
16
+ No defect label is set on any bead, closed beads included. There is nothing to count,
17
+ so no zero is printed as if it were a measurement.
18
+
19
+ First-pass review rate
20
+ 1 of 1 review cohorts passed with no fix round — 100%
21
+ A cohort is a parent holding at least one stage:review chore; a rejected review always
22
+ creates a fresh one, so a parent with exactly one passed first time.
23
+
24
+ Fix rounds
25
+ No stage:fix chore is recorded in this tracker.
26
+
27
+ Change since the previous report
28
+ None — no previous report was named. This is a snapshot, not a trend.
29
+ Pass --baseline <path> to compare against one, and --record to keep this one.
30
+
31
+ A defect label is removed when the review that confirms its fix runs, so every count
32
+ above is the unconfirmed defect set at this moment, not the history of defects.
33
+ ```
34
+
35
+ The pipeline numbers are still real. Only the defect section degrades, and it degrades by saying
36
+ so: `0 defects` would have read as a measurement.
37
+
38
+ ## One labelled defect
39
+
40
+ The same tracker after a review rejected the change once:
41
+
42
+ ```
43
+ Defects by class — `bd list --label-pattern 'defect:*' --all`
44
+ 1. criteria-unmet 1 defect in 1 change · owners: implement-task/SKILL.md, create-task/SKILL.md
45
+ example: acme-2q.3
46
+ 1 unconfirmed defect across 1 change.
47
+
48
+ First-pass review rate
49
+ 0 of 1 review cohorts passed with no fix round — 0%
50
+
51
+ Fix rounds
52
+ 1 in total across 1 change — review 1
53
+ ```
54
+
55
+ The report names the owning skill for the class and the bead that carries the label. The trend
56
+ section still reads "None — no previous report was named": one label is a snapshot, and a
57
+ direction needs a second report to compare against.
58
+
59
+ ## No review stage chore yet
60
+
61
+ A project that has fixed something once but never ran a review chore. Only the two affected sections
62
+ are shown:
63
+
64
+ ```
65
+ First-pass review rate
66
+ No review stage chore is recorded in this tracker, so no rate is reported — absent
67
+ is not zero.
68
+
69
+ Fix rounds
70
+ 1 in total across 1 change — code 1
71
+ ```
72
+
73
+ The rate is absent because nothing measured it, not because it is zero. The fix round is still
74
+ counted, because attribution reads the fresh chore's `blocks` dependency rather than the review
75
+ chores.
76
+
77
+ ## The whole vocabulary
78
+
79
+ Twelve labels, one per class, spread over four changes. The defect section prints the top three and
80
+ summarises the rest:
81
+
82
+ ```
83
+ Defects by class — `bd list --label-pattern 'defect:*' --all`
84
+ 1. ambiguous-rule 1 defect in 1 change · owners: write-a-skill/SKILL.md
85
+ example: acme-5q.1
86
+ 2. criteria-unmet 1 defect in 1 change · owners: implement-task/SKILL.md, create-task/SKILL.md
87
+ example: acme-5q.2
88
+ 3. docs-drift 1 defect in 1 change · owners: maintain-agent-docs/SKILL.md, style-documentation/SKILL.md
89
+ example: acme-5q.3
90
+ 12 unconfirmed defects across 4 changes. Top 3 of 12 classes.
91
+ ```
92
+
93
+ This is the owning-skill mapping in use. Each class maps to at least one shipped skill, the report
94
+ names the file to change rather than the symptom, and the suite fails if a mapped skill disappears
95
+ or a vocabulary class has no owner.
96
+
97
+ `--json` prints every class with its count, its changes and its bead ids, for a caller that needs
98
+ the whole table rather than the top three.
99
+
100
+ ## With a previous report
101
+
102
+ The same project, recorded as a baseline one month earlier and re-run after two more rejections:
103
+
104
+ ```
105
+ Change since the previous report
106
+ Against /tmp/rr-example/trend/.agent-cortex-docs/defect-report.json, reported 2026-04-01T09:00:00Z
107
+ criteria-unmet 1 (+1), docs-drift 1 (+1), missing-proof 1 (+1), and 5 more
108
+ First-pass review rate 75% (from 75%, no change)
109
+ ```
110
+
111
+ The comparison reads the report the script wrote at `--baseline`, so it compares like with like.
112
+ A class that did not change is not listed; when no class changed, the section says so. A baseline
113
+ file with an unrecognised schema is refused rather than read as zeros, because a baseline that
114
+ cannot be read must not become an invented trend.
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: review-report
3
+ description: Reports the defect classes a project's reviews recorded, with the pipeline's first-pass review rate, fix rounds per stage and the change since the previous report, and files that report upstream. Use when you ask "what keeps failing", "defect report", "which skill should change", or "file this as package feedback".
4
+ ---
5
+
6
+ # Review report
7
+
8
+ `review-defects` gives every rejection one class, so rejections become countable. This skill counts
9
+ them: one report naming which classes recur, the shipped skill that owns each failing rule, and the
10
+ pipeline's own rate — then, as a separate step, files that report upstream.
11
+
12
+ ## When to use
13
+
14
+ - "What keeps failing?" — which defect class recurs across this project's changes.
15
+ - Deciding which shipped skill to change, because a class keeps appearing.
16
+ - Filing package feedback against the tool the project runs on.
17
+ - Checking whether the review gate is improving, without reading closed beads one at a time.
18
+
19
+ ## When NOT to use
20
+
21
+ - Applying a class to a rejection — that is `review-defects`.
22
+ - Reviewing one change — that is the `review` stage.
23
+ - Reporting work progress — beads and `bd-tool` own that.
24
+
25
+ ## What it measures
26
+
27
+ | Metric | Derived from the tracker |
28
+ |---|---|
29
+ | Defects by class | every `defect:<class>` label on any bead, closed beads included |
30
+ | First-pass review rate | parents holding exactly one `stage:review` chore |
31
+ | Fix rounds per stage | `stage:fix` chores, attributed to the stage the fresh chore re-runs |
32
+ | Change since the previous report | this report against the report kept at `--baseline` |
33
+
34
+ The class vocabulary is not defined here. `review-defects` owns the closed list of classes, and
35
+ the script parses that table at run time, so the words a reviewer applies and the words this report
36
+ counts cannot drift apart. A class that appears as a label but not in the table is printed as
37
+ vocabulary drift and is never counted as a class of its own.
38
+
39
+ A fix round is attributed by chore state, not by prose: a rejected stage always creates a `stage:fix`
40
+ chore plus a fresh instance of that stage, and the fresh instance declares a `blocks` dependency on
41
+ the fix. The stage label it carries is the stage the fix round repaired. A fix chore that no fresh
42
+ chore depends on is printed as `unattributed`, and the trend compares the per-stage counts only —
43
+ so a movement inside `unattributed` shows in the snapshot and never in the trend.
44
+
45
+ The class-to-skill mapping is `DEFECT_OWNERS` in `scripts/report.mjs` — one table, so a mapping edit
46
+ is one edit. The suite fails when a mapped skill does not exist on disk, or when a class in the
47
+ vocabulary has no owner.
48
+
49
+ ## Honest by construction
50
+
51
+ The report never dresses an absent measurement as a number. The four degradation cases are:
52
+
53
+ - **No defect label.** It says no label is set and prints no zeros, because zero labels is an absence,
54
+ not a measurement of zero defects.
55
+ - **One labelled defect.** It prints the snapshot and says there is a single data point, so there is no
56
+ trend yet.
57
+ - **No review chore.** It says no rate is reported, because absent is not zero.
58
+ - **No baseline.** It prints the snapshot and says there is no previous report to compare against.
59
+
60
+ One further rule governs what a count means rather than what it measures. A label is removed when the
61
+ review that confirms its fix runs, so every count describes the unconfirmed defect set at that
62
+ moment, never the whole history. The trend compares snapshots, and the report says so.
63
+
64
+ ## Workflow
65
+
66
+ 1. Run the report against the project:
67
+
68
+ ```bash
69
+ node <review-report-scripts>/report.mjs
70
+ ```
71
+
72
+ It reads two tracker queries, both read-only and both carrying `--all` — the defect query
73
+ `bd list --label-pattern 'defect:*' --all` and the chore tree. Without `--all` a query for a label
74
+ on a closed bead returns nothing.
75
+
76
+ 2. Cross-check two numbers by hand before trusting the report: count one class with
77
+ `bd list -l defect:<class> --all`, and count one parent's review chores with
78
+ `bd children <id> --json`. The report is a summary of queries you can run yourself.
79
+
80
+ 3. Keep a baseline when you want a trend. `--baseline <path>` compares against a report the script
81
+ wrote earlier, and `--record` keeps this report there:
82
+
83
+ ```bash
84
+ node <review-report-scripts>/report.mjs --baseline docs/defect-report.json --record
85
+ ```
86
+
87
+ The path is yours to choose, and a committed one is the only kind that survives. `.agent-cortex/`
88
+ is an ignored directory in a consuming project, and the working-docs directory is per-bead and lost
89
+ with the worktree, so neither can hold a trend across branches or machines. Commit the file if you
90
+ want the comparison to travel; leave it out of version control and the comparison is local.
91
+
92
+ 4. Read the report before it leaves the machine. The default run writes nothing and calls nothing.
93
+
94
+ 5. File it, once you have read it:
95
+
96
+ ```bash
97
+ node <review-report-scripts>/report.mjs --file
98
+ ```
99
+
100
+ `--file` is the only networked step, and it runs `gh issue create` — no push, no pull request, no
101
+ merge, and nothing written to the repository it files against.
102
+
103
+ `--file` with `--json` prints the model and then appends the `Filed: <url>` line, so that stdout is
104
+ no longer parseable JSON. File from a text run, or read the URL from the last line and drop it.
105
+
106
+ ## Choosing the feedback repository
107
+
108
+ The repository is configuration, resolved in this order:
109
+
110
+ 1. `--repo <owner/name>`.
111
+ 2. `AGENT_CORTEX_FEEDBACK_REPO` in the environment.
112
+ 3. The `repository` field of the manifest the running install ships — the `package.json` of the
113
+ package `install pi` stages, or the `.claude-plugin/plugin.json` of the plugin `install claude`
114
+ stages. A manifest is read only when its `name` is one of this package's three shipped identities
115
+ — `PACKAGE_NAME` and `STAGED_PACKAGE_NAME` for the pi manifest, `PLUGIN_NAME` for the claude one,
116
+ all in `scripts/report.mjs` — so a consuming project's own manifest is never filed against.
117
+
118
+ No repository slug is hardcoded, so an install files feedback to the package it was installed from.
119
+ Both installs declare that field, so `--file` needs no further configuration. A copy that carries
120
+ no such manifest — vendored into a project by hand, for example — cannot resolve one: `--file` then
121
+ fails with a message naming `--repo` and the environment variable, and the report is printed first,
122
+ so the measurement is never lost.
123
+
124
+ ## Verification checklist
125
+
126
+ - [ ] The report printed counts that you can reproduce with the same queries by hand.
127
+ - [ ] Every top class named an owning skill, and one example bead id.
128
+ - [ ] The report was read before `--file` ran, and `--file` ran only if filing was wanted.
129
+ - [ ] With no labels or no baseline, the report said so instead of printing a trend.
130
+ - [ ] Nothing was pushed and no pull request was opened against the feedback repository.
131
+
132
+ ## See Also
133
+
134
+ - [review-defects](../review-defects/SKILL.md) — the closed class vocabulary this report counts.
135
+ - [run-pipeline-stage](../../workflow/run-pipeline-stage/SKILL.md) — the stage that applies the labels and builds fix rounds.
136
+ - [style-tests](../../style/style-tests/SKILL.md) — the rule behind the `test-*` classes this report points at.
137
+
138
+ Reports for the four degradation cases are in `EXAMPLES.md`.