@onlooker-community/ecosystem 0.34.0 → 0.43.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 (112) hide show
  1. package/.claude/skills/writing-tests/SKILL.md +27 -0
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.github/workflows/release.yml +14 -14
  4. package/.release-please-manifest.json +7 -7
  5. package/AGENTS.md +116 -0
  6. package/CHANGELOG.md +175 -0
  7. package/CLAUDE.md +5 -0
  8. package/docs/lesson-promotion-pipeline.md +6 -6
  9. package/docs/superpowers/plans/2026-08-10-lesson-confirmation.md +1273 -0
  10. package/docs/superpowers/plans/2026-08-11-lesson-judging.md +1232 -0
  11. package/docs/superpowers/plans/2026-08-11-lesson-unconfirm.md +458 -0
  12. package/docs/superpowers/plans/2026-08-12-author-key.md +567 -0
  13. package/docs/superpowers/plans/2026-08-13-approved-pool.md +747 -0
  14. package/docs/superpowers/plans/2026-08-13-librarian-cluster.md +392 -0
  15. package/docs/superpowers/plans/2026-08-14-criterion-scores-consumers.md +1374 -0
  16. package/docs/superpowers/plans/2026-08-14-criterion-scores-schema.md +277 -0
  17. package/docs/superpowers/plans/2026-08-16-cartographer-undocumented-entity.md +741 -0
  18. package/docs/superpowers/specs/2026-08-10-lesson-confirmation-design.md +213 -0
  19. package/docs/superpowers/specs/2026-08-11-lesson-judging-design.md +267 -0
  20. package/docs/superpowers/specs/2026-08-11-lesson-unconfirm-design.md +152 -0
  21. package/docs/superpowers/specs/2026-08-12-author-key-design.md +317 -0
  22. package/docs/superpowers/specs/2026-08-13-approved-pool-design.md +232 -0
  23. package/docs/superpowers/specs/2026-08-14-criterion-scores-design.md +254 -0
  24. package/docs/superpowers/specs/2026-08-16-cartographer-undocumented-entity-design.md +249 -0
  25. package/package.json +2 -2
  26. package/plugins/assayer/.claude-plugin/plugin.json +1 -1
  27. package/plugins/assayer/CHANGELOG.md +7 -0
  28. package/plugins/assayer/scripts/lib/assayer-config.sh +6 -0
  29. package/plugins/cartographer/.claude-plugin/plugin.json +1 -1
  30. package/plugins/cartographer/CHANGELOG.md +54 -0
  31. package/plugins/cartographer/README.md +56 -1
  32. package/plugins/cartographer/config.json +7 -1
  33. package/plugins/cartographer/scripts/hooks/cartographer-post-write.sh +4 -4
  34. package/plugins/cartographer/scripts/hooks/cartographer-session-start.sh +7 -4
  35. package/plugins/cartographer/scripts/lib/cartographer-collect.sh +8 -1
  36. package/plugins/cartographer/scripts/lib/cartographer-config.sh +26 -0
  37. package/plugins/cartographer/scripts/lib/cartographer-events.sh +90 -0
  38. package/plugins/cartographer/scripts/lib/cartographer-filter.sh +105 -0
  39. package/plugins/cartographer/scripts/lib/cartographer-omission.sh +130 -0
  40. package/plugins/cartographer/scripts/lib/cartographer-resolve.sh +132 -0
  41. package/plugins/cartographer/scripts/run-audit.sh +136 -53
  42. package/plugins/cartographer/skills/cartographer/SKILL.md +33 -9
  43. package/plugins/curator/.claude-plugin/plugin.json +1 -1
  44. package/plugins/curator/CHANGELOG.md +7 -0
  45. package/plugins/curator/scripts/lib/curator-emit.sh +2 -1
  46. package/plugins/historian/.claude-plugin/plugin.json +1 -1
  47. package/plugins/historian/CHANGELOG.md +7 -0
  48. package/plugins/historian/scripts/lib/historian-emit.sh +2 -1
  49. package/plugins/librarian/.claude-plugin/plugin.json +1 -1
  50. package/plugins/librarian/CHANGELOG.md +71 -0
  51. package/plugins/librarian/config.json +30 -1
  52. package/plugins/librarian/docs/adr/002-agent-definitions-are-shared-assets.md +82 -0
  53. package/plugins/librarian/scripts/hooks/librarian-session-end.sh +28 -0
  54. package/plugins/librarian/scripts/hooks/librarian-session-start.sh +42 -12
  55. package/plugins/librarian/scripts/lib/librarian-author-key.sh +279 -0
  56. package/plugins/librarian/scripts/lib/librarian-cli.sh +346 -2
  57. package/plugins/librarian/scripts/lib/librarian-emit.sh +2 -1
  58. package/plugins/librarian/scripts/lib/librarian-lesson-judge.sh +349 -0
  59. package/plugins/librarian/scripts/lib/librarian-lesson-promote.sh +225 -0
  60. package/plugins/librarian/scripts/lib/librarian-lesson-review.sh +312 -0
  61. package/plugins/librarian/scripts/lib/librarian-lesson-rubric.sh +56 -0
  62. package/plugins/librarian/scripts/lib/librarian-lesson-storage.sh +82 -13
  63. package/plugins/librarian/scripts/lib/librarian-lesson-transform.sh +6 -1
  64. package/plugins/librarian/scripts/lib/librarian-lesson-validate.sh +131 -62
  65. package/plugins/librarian/skills/librarian/SKILL.md +98 -1
  66. package/plugins/tribunal/.claude-plugin/plugin.json +1 -1
  67. package/plugins/tribunal/CHANGELOG.md +63 -0
  68. package/plugins/tribunal/agents/tribunal-judge-adversarial.md +34 -0
  69. package/plugins/tribunal/agents/tribunal-judge-security.md +33 -0
  70. package/plugins/tribunal/agents/tribunal-judge-standard.md +12 -0
  71. package/plugins/tribunal/config.json +1 -0
  72. package/plugins/tribunal/scripts/lib/tribunal-aggregate.sh +154 -9
  73. package/plugins/tribunal/scripts/lib/tribunal-gate.sh +195 -16
  74. package/plugins/tribunal/skills/tribunal/SKILL.md +5 -3
  75. package/scripts/lib/prompt-rules.sh +6 -1
  76. package/test/bats/archivist-inject.bats +1 -1
  77. package/test/bats/assayer-extract.bats +2 -2
  78. package/test/bats/bursar-session-start.bats +3 -3
  79. package/test/bats/cartographer-config.bats +43 -0
  80. package/test/bats/cartographer-events.bats +267 -0
  81. package/test/bats/cartographer-filter.bats +169 -0
  82. package/test/bats/cartographer-lock.bats +3 -3
  83. package/test/bats/cartographer-omission.bats +202 -0
  84. package/test/bats/cartographer-resolve.bats +287 -0
  85. package/test/bats/cartographer-run-audit.bats +325 -0
  86. package/test/bats/compass-sanitizer.bats +11 -11
  87. package/test/bats/compass-transcript.bats +2 -2
  88. package/test/bats/config.bats +15 -15
  89. package/test/bats/curator-session-start.bats +10 -3
  90. package/test/bats/emit-payload-default.bats +52 -0
  91. package/test/bats/governor-ledger.bats +1 -1
  92. package/test/bats/historian-prompt-submit.bats +1 -1
  93. package/test/bats/inspector-post-write-hook.bats +4 -4
  94. package/test/bats/librarian-author-key.bats +477 -0
  95. package/test/bats/librarian-cli.bats +16 -16
  96. package/test/bats/librarian-lesson-judge.bats +884 -0
  97. package/test/bats/librarian-lesson-promote.bats +552 -0
  98. package/test/bats/librarian-lesson-review.bats +900 -0
  99. package/test/bats/librarian-lesson-transform.bats +17 -3
  100. package/test/bats/librarian-session-end.bats +161 -0
  101. package/test/bats/librarian-session-start.bats +36 -2
  102. package/test/bats/lineage-config.bats +1 -1
  103. package/test/bats/lineage-redact.bats +5 -5
  104. package/test/bats/session-tracker.bats +4 -4
  105. package/test/bats/tribunal-aggregate.bats +354 -1
  106. package/test/bats/tribunal-gate.bats +631 -0
  107. package/test/bats/tribunal-judge-agents.bats +119 -0
  108. package/test/bats/tribunal-jury.bats +1 -1
  109. package/test/bats/turn-tracker.bats +1 -1
  110. package/test/bats/warden-sanitizer.bats +3 -3
  111. package/test/bats/worktree-tracker.bats +2 -2
  112. package/test/node/lesson-validate-agreement.test.mjs +35 -6
@@ -0,0 +1,277 @@
1
+ # Per-Criterion Scores — Schema Half Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Add an optional `criterion_scores` map to `TribunalVerdictPayload` so per-criterion scores can be emitted at all.
6
+
7
+ **Architecture:** One field, in two files that must move together — the JSON Schema is the runtime contract, `src/types.ts` is hand-written and only cross-checked. Plus tests and a conventional commit that release-please turns into a version.
8
+
9
+ **Tech Stack:** JSON Schema (draft 2020-12), TypeScript, vitest, release-please.
10
+
11
+ ## ⚠️ This plan runs in a DIFFERENT repository
12
+
13
+ **Every implementation step below operates in `~/src/github.com/onlooker-community/schema`**, currently `main` at `46a79b4`, version `2.11.0`. That is the package the ecosystem depends on (`^2.11.0`).
14
+
15
+ This plan file lives in the ecosystem repo only because that is where the spec and the tracking bead (`ecosystem-pht`) live. **Do not edit ecosystem files.** The ecosystem half — judges emitting the field, real `weighted_mean`, `min_pass` enforcement, and librarian's disclosure floor — is a separate plan that starts only after this version publishes.
16
+
17
+ ## Global Constraints
18
+
19
+ - **The field is optional.** It must NOT appear in the payload's `required` array. Three shipped plugins emit this payload and the runtime emitter validates whenever the package resolves; requiring it would invalidate every existing producer the moment the version bumps.
20
+ - **The field is a map, not a parallel array.** `{"type": "object", "additionalProperties": {"type": "number", "minimum": 0, "maximum": 1}}`. An array beside `criteria_evaluated` would have to stay index-aligned with nothing enforcing it, and a silent misalignment attributes each score to the wrong criterion — worse than having no scores.
21
+ - **`additionalProperties` for the values, not enumerated criterion names.** Criterion names come from user-extensible rubrics (ADR-004). Librarian's `lesson-promotion` rubric uses `grounding`, `scope_accuracy`, `generality`, `disclosure` — none of which appear in tribunal's default rubric. Enumerating keys would make every new rubric a schema change.
22
+ - **`criteria_evaluated` and `criterion_scores` are deliberately allowed to disagree.** A judge may evaluate a criterion it cannot score. Cross-field consistency belongs at ingest, mirroring the lesson contract's reasoning for leaving `agreed <= judges` out of `ZConsensus`. Do not add a constraint tying them together.
23
+ - **Both files change in step.** `src/types.ts` is hand-written; `schemas/payload/plugins-safety.json` is the runtime contract. `scripts/generate-types.js` cross-checks them but its own header says divergence is a warning, not a hard failure (`TODO(ONL-6 hard fail)`). **Nothing will catch a drift** — that is why this is one task, not two.
24
+ - **Do not hand-edit a version.** Release is via release-please; ship a conventional commit and the release PR follows.
25
+ - American English. Commit per the `/commit` contract: `<type>(<scope>): <subject> :emoji:`, subject ≤72 chars including the emoji, why-focused body.
26
+
27
+ ## Context that shapes the work
28
+
29
+ The verdict payload already sets **`"additionalProperties": false`** (verified: `$defs/tribunal.verdict`, `required: ["task_id","score","passed","judge_type"]`). So today a producer emitting `criterion_scores` is **rejected outright** — which is precisely why the schema must land before any consumer can emit it, and why this addition is strictly safe: adding the property permits it, and its absence from `required` keeps every current producer valid.
30
+
31
+ ## File Structure
32
+
33
+ | File | Responsibility |
34
+ |---|---|
35
+ | `schemas/payload/plugins-safety.json` | **Modify.** The runtime contract — add the property to `$defs/tribunal.verdict`. |
36
+ | `src/types.ts` | **Modify.** The hand-written type at `TribunalVerdictPayload` (line 218). |
37
+ | `src/validate.test.ts` | **Modify.** Fixture-based vitest cases. |
38
+
39
+ ---
40
+
41
+ ### Task 1: Add `criterion_scores` to the verdict payload
42
+
43
+ **Files (all in `~/src/github.com/onlooker-community/schema`):**
44
+ - Modify: `schemas/payload/plugins-safety.json` — `$defs/tribunal.verdict`, after `criteria_evaluated` (~line 180)
45
+ - Modify: `src/types.ts:218` — `TribunalVerdictPayload`
46
+ - Test: `src/validate.test.ts`
47
+
48
+ **Interfaces:**
49
+ - Produces: `criterion_scores?: Record<string, number>` on `TribunalVerdictPayload`, and the matching JSON Schema property. The ecosystem half consumes both.
50
+
51
+ - [ ] **Step 1: Create a branch**
52
+
53
+ ```bash
54
+ cd ~/src/github.com/onlooker-community/schema
55
+ git switch -c feat/criterion-scores
56
+ ```
57
+
58
+ - [ ] **Step 2: Write the failing tests**
59
+
60
+ Add these to `src/validate.test.ts`, inside the existing tribunal `describe` block that defines the `tribunal()` helper (around line 348) and the `TASK_ID` / `ITERATION_ID` constants. The helper's signature is `tribunal<T extends EventType>(event_type, payload)`.
61
+
62
+ Match the file's existing assertion style: `expect(result.valid).toBe(false)` followed by an `if (!result.valid)` guard before touching `result.errors`.
63
+
64
+ ```ts
65
+ it("accepts a verdict carrying per-criterion scores", () => {
66
+ const result = validate(
67
+ tribunal(TRIBUNAL_VERDICT, {
68
+ task_id: TASK_ID,
69
+ score: 0.85,
70
+ passed: true,
71
+ judge_type: "standard",
72
+ criterion_scores: { correctness: 0.9, safety: 0.8 },
73
+ }),
74
+ );
75
+ expect(result.valid).toBe(true);
76
+ });
77
+
78
+ it("accepts a verdict with no criterion_scores at all", () => {
79
+ // Every producer today omits it. Making the field required would
80
+ // invalidate all three shipped plugins on the version bump.
81
+ const result = validate(
82
+ tribunal(TRIBUNAL_VERDICT, {
83
+ task_id: TASK_ID,
84
+ score: 0.85,
85
+ passed: true,
86
+ judge_type: "standard",
87
+ }),
88
+ );
89
+ expect(result.valid).toBe(true);
90
+ });
91
+
92
+ it("accepts an arbitrary criterion name", () => {
93
+ // The point of the map: criterion names come from user-extensible
94
+ // rubrics, so they cannot be enumerated in the schema. These four are
95
+ // librarian's lesson-promotion rubric, none of which tribunal's own
96
+ // default rubric uses.
97
+ const result = validate(
98
+ tribunal(TRIBUNAL_VERDICT, {
99
+ task_id: TASK_ID,
100
+ score: 0.85,
101
+ passed: true,
102
+ judge_type: "standard",
103
+ criterion_scores: {
104
+ grounding: 0.9,
105
+ scope_accuracy: 0.8,
106
+ generality: 0.7,
107
+ disclosure: 0.95,
108
+ },
109
+ }),
110
+ );
111
+ expect(result.valid).toBe(true);
112
+ });
113
+
114
+ it("rejects a criterion score above 1", () => {
115
+ const result = validate(
116
+ tribunal(TRIBUNAL_VERDICT, {
117
+ task_id: TASK_ID,
118
+ score: 0.85,
119
+ passed: true,
120
+ judge_type: "standard",
121
+ criterion_scores: { correctness: 1.5 },
122
+ }),
123
+ );
124
+ expect(result.valid).toBe(false);
125
+ if (!result.valid) {
126
+ expect(
127
+ result.errors.some((e) => e.path.includes("criterion_scores")),
128
+ ).toBe(true);
129
+ }
130
+ });
131
+
132
+ it("rejects a criterion score below 0", () => {
133
+ const result = validate(
134
+ tribunal(TRIBUNAL_VERDICT, {
135
+ task_id: TASK_ID,
136
+ score: 0.85,
137
+ passed: true,
138
+ judge_type: "standard",
139
+ criterion_scores: { correctness: -0.1 },
140
+ }),
141
+ );
142
+ expect(result.valid).toBe(false);
143
+ });
144
+
145
+ it("rejects a non-number criterion score", () => {
146
+ const result = validate(
147
+ tribunal(TRIBUNAL_VERDICT, {
148
+ task_id: TASK_ID,
149
+ score: 0.85,
150
+ passed: true,
151
+ judge_type: "standard",
152
+ criterion_scores: { correctness: "high" },
153
+ } as unknown as Parameters<typeof tribunal>[1]),
154
+ );
155
+ expect(result.valid).toBe(false);
156
+ });
157
+
158
+ it("allows criteria_evaluated and criterion_scores to disagree", () => {
159
+ // Deliberate: a judge may evaluate a criterion it cannot score.
160
+ // Cross-field consistency belongs at ingest, not in a JSON Schema —
161
+ // the same reasoning that keeps `agreed <= judges` out of ZConsensus
162
+ // in the lesson contract.
163
+ const result = validate(
164
+ tribunal(TRIBUNAL_VERDICT, {
165
+ task_id: TASK_ID,
166
+ score: 0.85,
167
+ passed: true,
168
+ judge_type: "standard",
169
+ criteria_evaluated: ["correctness", "safety", "clarity"],
170
+ criterion_scores: { correctness: 0.9 },
171
+ }),
172
+ );
173
+ expect(result.valid).toBe(true);
174
+ });
175
+ ```
176
+
177
+ - [ ] **Step 3: Run the tests to verify they fail**
178
+
179
+ ```bash
180
+ cd ~/src/github.com/onlooker-community/schema
181
+ npm test 2>&1 | tail -20
182
+ ```
183
+
184
+ Expected: the three "accepts" tests that pass `criterion_scores` **FAIL**, because the payload sets `"additionalProperties": false` and the property does not exist yet. "accepts a verdict with no criterion_scores at all" passes already — that is correct, it is the regression guard for existing producers. The three "rejects" tests may pass for the *wrong* reason right now (rejected as an unknown property rather than for their range or type), which is exactly why Step 6 re-checks them.
185
+
186
+ - [ ] **Step 4: Add the property to the JSON Schema**
187
+
188
+ In `schemas/payload/plugins-safety.json`, inside `$defs/tribunal.verdict`'s `properties`, immediately after the `criteria_evaluated` block:
189
+
190
+ ```json
191
+ "criterion_scores": {
192
+ "type": "object",
193
+ "additionalProperties": { "type": "number", "minimum": 0, "maximum": 1 },
194
+ "description": "Per-criterion score keyed by criterion name, in [0,1]. Criterion names come from the active rubric and are not enumerable here. May disagree with criteria_evaluated: a judge can evaluate a criterion it cannot score. Consistency between the two is an ingest concern."
195
+ },
196
+ ```
197
+
198
+ **Do not add it to `required`.** Leave the payload's `additionalProperties: false` as it is — that is what makes the field a contract rather than a convention.
199
+
200
+ - [ ] **Step 5: Add the matching field to the hand-written type**
201
+
202
+ In `src/types.ts`, in `TribunalVerdictPayload` (line 218), after `criteria_evaluated?: string[];`:
203
+
204
+ ```ts
205
+ criterion_scores?: Record<string, number>;
206
+ ```
207
+
208
+ This file is hand-written and only cross-checked by `scripts/generate-types.js`, whose header says divergence is a warning rather than a hard failure. If this step is skipped the JSON Schema and the type silently disagree, and TypeScript consumers cannot set the field even though the runtime accepts it.
209
+
210
+ - [ ] **Step 6: Run the tests to verify they pass — and for the right reason**
211
+
212
+ ```bash
213
+ cd ~/src/github.com/onlooker-community/schema
214
+ npm test 2>&1 | tail -20
215
+ ```
216
+
217
+ Expected: all pass.
218
+
219
+ Then confirm the three "rejects" tests now fail for their *own* reason rather than as unknown properties. In a scratch copy of the schema (not committed), temporarily widen the value constraint to `{"type": "number"}` — dropping `minimum`/`maximum` — and re-run: "rejects a criterion score above 1" and "below 0" must now **fail**, while "rejects a non-number criterion score" still passes. Restore the constraint.
220
+
221
+ **If they still pass with the range removed, they are not testing the range** — say so plainly in your report rather than treating them as proven.
222
+
223
+ - [ ] **Step 7: Run the full checks**
224
+
225
+ ```bash
226
+ cd ~/src/github.com/onlooker-community/schema
227
+ npm run validate-schemas; echo "validate-schemas: $?"
228
+ npm run typecheck; echo "typecheck: $?"
229
+ npm run ci; echo "ci (biome): $?"
230
+ npm run build; echo "build: $?"
231
+ npm run test; echo "test: $?"
232
+ ```
233
+
234
+ Read each exit code directly — **never through a pipe**, which reports the pipe's last command.
235
+
236
+ `npm run build` runs `generate-types` and may print a divergence warning; read it. If it reports a mismatch on `criterion_scores`, the JSON Schema and `src/types.ts` disagree and one of Steps 4–5 is wrong.
237
+
238
+ - [ ] **Step 8: Commit**
239
+
240
+ ```bash
241
+ cd ~/src/github.com/onlooker-community/schema
242
+ git add schemas/payload/plugins-safety.json src/types.ts src/validate.test.ts
243
+ ```
244
+
245
+ Commit subject: `feat(tribunal): carry per-criterion scores on a verdict :straight_ruler:`
246
+
247
+ The body should say why the field is optional (three shipped producers, and the emitter validates whenever the package resolves) and why it is a map rather than a parallel array (index alignment has nothing enforcing it). `feat` matters: release-please cuts a minor version from it, which is what the ecosystem half will depend on.
248
+
249
+ - [ ] **Step 9: Push and open a PR**
250
+
251
+ ```bash
252
+ cd ~/src/github.com/onlooker-community/schema
253
+ git push -u origin feat/criterion-scores
254
+ ```
255
+
256
+ Open the PR against `main`. Note in its body that this is the first half of `ecosystem-pht` and that no consumer changes ship until the release lands.
257
+
258
+ ---
259
+
260
+ ## Spec coverage
261
+
262
+ | Spec requirement | Step |
263
+ |---|---|
264
+ | Optional, absent from `required` | 4 |
265
+ | Map with `additionalProperties` values in `[0,1]` | 4 |
266
+ | Criterion names not enumerated | 4, and pinned by the arbitrary-name test in 2 |
267
+ | `criteria_evaluated` may disagree | 4 (no cross-field constraint) and pinned in 2 |
268
+ | Both files edited in step | 4, 5, and the divergence check in 7 |
269
+ | A verdict with scores validates | 2 |
270
+ | A score outside `[0,1]` does not | 2, re-checked in 6 |
271
+ | A non-number value does not | 2, re-checked in 6 |
272
+ | Omitting the field still validates | 2 |
273
+ | Released via release-please, not a hand-edited version | 8 |
274
+
275
+ ## Out of scope
276
+
277
+ Retiring `criteria_evaluated`. Any judge-agent change, `weighted_mean`, `min_pass` enforcement, or librarian's disclosure floor — all the ecosystem half, which starts after this publishes. And the `TODO(ONL-6)` hard-fail on type/schema divergence, which is the schema repo's own cleanup.