@onlooker-community/ecosystem 0.33.1 → 0.34.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 (67) hide show
  1. package/.agents/skills/beads/SKILL.md +80 -0
  2. package/.agents/skills/beads/agents/openai.yaml +4 -0
  3. package/.claude/settings.json +13 -0
  4. package/.claude/skills/writing-tests/SKILL.md +27 -0
  5. package/.claude-plugin/plugin.json +1 -1
  6. package/.codex/config.toml +2 -0
  7. package/.codex/hooks.json +51 -0
  8. package/.markdownlint.json +3 -0
  9. package/.release-please-manifest.json +6 -6
  10. package/AGENTS.md +246 -0
  11. package/CHANGELOG.md +14 -0
  12. package/CLAUDE.md +56 -1
  13. package/docs/lesson-promotion-pipeline.md +210 -0
  14. package/docs/superpowers/plans/2026-08-09-lesson-transform.md +1537 -0
  15. package/docs/superpowers/specs/2026-08-09-lesson-transform-design.md +261 -0
  16. package/package.json +3 -2
  17. package/plugins/assayer/.claude-plugin/plugin.json +1 -1
  18. package/plugins/assayer/CHANGELOG.md +7 -0
  19. package/plugins/assayer/scripts/lib/assayer-config.sh +6 -0
  20. package/plugins/curator/.claude-plugin/plugin.json +1 -1
  21. package/plugins/curator/CHANGELOG.md +7 -0
  22. package/plugins/curator/scripts/lib/curator-emit.sh +2 -1
  23. package/plugins/historian/.claude-plugin/plugin.json +1 -1
  24. package/plugins/historian/CHANGELOG.md +7 -0
  25. package/plugins/historian/scripts/lib/historian-emit.sh +2 -1
  26. package/plugins/librarian/.claude-plugin/plugin.json +1 -1
  27. package/plugins/librarian/CHANGELOG.md +14 -0
  28. package/plugins/librarian/config.json +4 -0
  29. package/plugins/librarian/schema/PROVENANCE.json +7 -0
  30. package/plugins/librarian/schema/lesson-applies-to.subschema.json +74 -0
  31. package/plugins/librarian/schema/lesson-evidence.subschema.json +36 -0
  32. package/plugins/librarian/scripts/hooks/librarian-session-end.sh +26 -0
  33. package/plugins/librarian/scripts/lib/librarian-cli.sh +2 -1
  34. package/plugins/librarian/scripts/lib/librarian-emit.sh +2 -1
  35. package/plugins/librarian/scripts/lib/librarian-lesson-storage.sh +135 -0
  36. package/plugins/librarian/scripts/lib/librarian-lesson-transform.sh +311 -0
  37. package/plugins/librarian/scripts/lib/librarian-lesson-validate.sh +140 -0
  38. package/plugins/tribunal/.claude-plugin/plugin.json +1 -1
  39. package/plugins/tribunal/CHANGELOG.md +7 -0
  40. package/plugins/tribunal/scripts/lib/tribunal-aggregate.sh +3 -1
  41. package/plugins/tribunal/scripts/lib/tribunal-gate.sh +2 -1
  42. package/scripts/lib/prompt-rules.sh +6 -1
  43. package/scripts/lint/check-lesson-schema-drift.mjs +36 -0
  44. package/test/bats/archivist-inject.bats +1 -1
  45. package/test/bats/assayer-extract.bats +2 -2
  46. package/test/bats/bursar-session-start.bats +3 -3
  47. package/test/bats/cartographer-lock.bats +3 -3
  48. package/test/bats/compass-sanitizer.bats +11 -11
  49. package/test/bats/compass-transcript.bats +2 -2
  50. package/test/bats/config.bats +15 -15
  51. package/test/bats/curator-session-start.bats +10 -3
  52. package/test/bats/emit-payload-default.bats +52 -0
  53. package/test/bats/governor-ledger.bats +1 -1
  54. package/test/bats/historian-prompt-submit.bats +1 -1
  55. package/test/bats/inspector-post-write-hook.bats +4 -4
  56. package/test/bats/librarian-cli.bats +16 -16
  57. package/test/bats/librarian-lesson-transform.bats +609 -0
  58. package/test/bats/librarian-session-start.bats +2 -2
  59. package/test/bats/lineage-config.bats +1 -1
  60. package/test/bats/lineage-redact.bats +5 -5
  61. package/test/bats/session-tracker.bats +4 -4
  62. package/test/bats/tribunal-jury.bats +1 -1
  63. package/test/bats/turn-tracker.bats +1 -1
  64. package/test/bats/warden-sanitizer.bats +3 -3
  65. package/test/bats/worktree-tracker.bats +2 -2
  66. package/test/node/lesson-schema-drift.test.mjs +28 -0
  67. package/test/node/lesson-validate-agreement.test.mjs +154 -0
@@ -0,0 +1,210 @@
1
+ # Lesson Promotion Pipeline
2
+
3
+ **Status:** Not started. Design is settled; implementation lives in this repo.
4
+ **Tracked by:** `onlooker-97e` in the onlooker beads tracker.
5
+ **Authoritative design:** `docs/superpowers/specs/2026-08-08-promotion-pipeline-design.md`
6
+ in the [onlooker](https://github.com/onlooker-community/onlooker) repo, Sections 2 and 3.
7
+ Read that before making design decisions — this document is orientation, not the spec.
8
+
9
+ ---
10
+
11
+ ## What we are building
12
+
13
+ A fourth destination for archivist artifacts: a **shared** pool of lessons that
14
+ can cross machines and people, rather than the local, per-machine typed memory
15
+ store librarian writes to today.
16
+
17
+ This is easy to misread as "another memory type." It is not. Compare with
18
+ [memory-architecture.md](memory-architecture.md):
19
+
20
+ | | destination | scope | who sees it |
21
+ |---|---|---|---|
22
+ | librarian → typed memory store | `~/.claude/projects/<encoded>/memory/` | one machine | you |
23
+ | **librarian → lesson pool** | `~/.onlooker/librarian/<project-key>/lessons/` | shared, eventually cross-person | you, your org, or the public |
24
+
25
+ Everything upstream is unchanged. Artifacts are still captured by archivist,
26
+ still filtered for durability, still classified, still deduped. The new work
27
+ hangs off the end of that existing chain.
28
+
29
+ ## The shape
30
+
31
+ ```
32
+ archivist artifacts EXISTS session-scoped facts
33
+ └→ durability filter EXISTS cheap, pre-LLM
34
+ └→ type classifier (Haiku) EXISTS user/feedback/project/reference
35
+ └→ conflict/dup detect (Jaccard) EXISTS keeps the queue high-signal
36
+ ══════════════════════════════════════
37
+ └→ lesson transform (Haiku) NEW claim, rationale, applies_to
38
+ └→ human picks + visibility NEW propose-only, per librarian ADR-001
39
+ └→ tribunal gate NEW one-shot, visibility-scoped
40
+ └→ approved pool NEW local; the sync service drains it later
41
+ ```
42
+
43
+ Three new steps, in two existing plugins. **No new plugin.** Librarian already
44
+ owns the artifact reader, the durability filter, the classifier, the dedup pass
45
+ and the proposal queue — the transform is a fifth stage on a chain that exists,
46
+ and its `last_scan.json` watermark already tracks which artifacts have been
47
+ considered. A separate plugin would need a second copy of that state, free to
48
+ drift.
49
+
50
+ Tribunal contributes a rubric and reuses `tribunal-judge-security`, which it
51
+ already ships disabled by default.
52
+
53
+ ## Why lessons rot, and what the contract does about it
54
+
55
+ The design exists because of a real artifact in this repo's own storage: a
56
+ vitest/vite version-mismatch decision that was true when captured and is false
57
+ now. Shared and auto-injected, it would send someone else down a dead end.
58
+
59
+ So staleness is **structural**, not procedural. A lesson carries version ranges,
60
+ and a session outside those ranges simply never matches it. No review queue, no
61
+ expiry job, nothing to forget to run. The contract enforces this by construction:
62
+ `applies_to.scope` is a tagged union, and the branch that claims version
63
+ independence must carry a written justification the tribunal scores. A transform
64
+ that failed to infer versions has nothing to put there, so it cannot silently
65
+ mint a lesson that never expires.
66
+
67
+ ## The contract
68
+
69
+ Defined in `packages/lesson-contract` in the onlooker repo and **published as
70
+ JSON Schema**:
71
+
72
+ - `packages/lesson-contract/schema/lesson.schema.json`
73
+ - `packages/lesson-contract/schema/counter-observation.schema.json`
74
+
75
+ Currently `schema_version: 2`.
76
+
77
+ **The producing side cannot import the definition.** Plugins here are
78
+ bash-based and live in a different repo; the zod source is not available to
79
+ them. Validate against the published JSON Schema, or simply conform to it. The
80
+ sync endpoint in `apps/api` is the real enforcement boundary and validates
81
+ regardless, so client-side validation is a convenience, not a trust boundary.
82
+
83
+ Fields worth knowing before you start:
84
+
85
+ | Field | Note |
86
+ |---|---|
87
+ | `claim` / `rationale` | what is asserted, and why it follows |
88
+ | `evidence.resolution` | **required.** "this breaks" without "and this fixed it" is a warning, not a lesson |
89
+ | `evidence.project_key` | the opaque hash, never the repo name |
90
+ | `applies_to.scope` | `{kind: "versioned", versions}` or `{kind: "version_independent", justification}` |
91
+ | `applies_to.stack` | every key of `scope.versions` must name an entry here — see cross-field rules below |
92
+ | `author_key` | 32 lowercase hex, `HMAC(user_secret, scope)`, derived **per visibility scope** so org and public identities are unlinkable |
93
+ | `visibility` | `private` / `org` / `public` |
94
+ | `status` | `active` / `refuted` / `superseded` / `retracted`. There is deliberately no `expired` |
95
+
96
+ **Cross-field rules the schema cannot express**, documented in the contract's
97
+ `.describe()` text and enforced at ingest. Worth self-checking before emitting:
98
+
99
+ - `consensus.agreed <= consensus.judges`
100
+ - every key of `applies_to.scope.versions` names an entry in `applies_to.stack`
101
+
102
+ ## What is already decided
103
+
104
+ Do not re-litigate these; they came out of a full design cycle and are recorded
105
+ with reasoning in the spec.
106
+
107
+ **The gate is one-shot.** `max_iterations: 1`. Below threshold, a candidate is
108
+ dropped rather than repaired. Refutation should be cheaper to trigger than
109
+ promotion — a wrong lesson actively misleads, a missing one merely fails to
110
+ help. Fail toward removal. This also bounds token cost per promotion and stops
111
+ the transform learning to satisfy judges rather than the evidence.
112
+
113
+ **The human confirms before judging, not after.** The transform is Haiku and
114
+ cheap; the jury is Opus and not. Splitting the filters this way means the human
115
+ judges *intent* ("do I want to share anything about this?"), which only they can
116
+ do and which costs nothing, and the jury judges *quality*, which only it can do
117
+ and which costs real money. Opus tokens are then only ever spent on candidates
118
+ someone already wants shared.
119
+
120
+ **Gating is scoped by visibility.** Not every lesson passes a jury:
121
+
122
+ | visibility | gate | why |
123
+ |---|---|---|
124
+ | `private` | none | you are the only consumer |
125
+ | `org` | `lesson-promotion` rubric | the org boundary already implies trust |
126
+ | `public` | rubric + disclosure lens | self-reported consensus is gameable by a modified client |
127
+
128
+ **The rubric**, in tribunal's existing `config.json` shape:
129
+
130
+ | criterion | weight | `min_pass` | asks |
131
+ |---|---|---|---|
132
+ | `grounding` | 0.45 | 0.7 | does the claim follow from `evidence` and `resolution`? |
133
+ | `scope_accuracy` | 0.35 | 0.7 | does `applies_to` correctly bound the claim? |
134
+ | `generality` | 0.20 | 0.6 | is this a lesson, or a session-scoped fact? |
135
+
136
+ `score_threshold: 0.75`, `gate_policy: majority`, `aggregation_method:
137
+ weighted_mean`, `judge_types: ["standard", "adversarial"]` — all tribunal
138
+ defaults. The only override is `max_iterations: 1`.
139
+
140
+ For `public`, add the disclosure lens using the already-shipped
141
+ `tribunal-judge-security`:
142
+
143
+ | criterion | weight | `min_pass` | asks |
144
+ |---|---|---|---|
145
+ | `disclosure` | 0.30 | **0.9** | leaks a secret or identity, or advocates a harmful practice? |
146
+
147
+ The high floor is deliberate. Correctness rots and `applies_to` retires it;
148
+ harm does not. A leaked credential never expires on its own, so disclosure gets
149
+ a floor a strong weighted mean cannot average away.
150
+
151
+ **State layout**, under librarian's existing project key:
152
+
153
+ ```
154
+ ~/.onlooker/librarian/<project-key>/
155
+ lessons/approved/<ulid>.json jury passed; awaiting sync
156
+ lessons/declined.jsonl artifact_id + verdict + reason
157
+ ```
158
+
159
+ The declined ledger matters more than it looks. The watermark advances past a
160
+ rejected artifact, so without a record a drop is either silently permanent or —
161
+ on a rescan — re-pays Opus tokens to re-judge the same failures every session.
162
+ Append-only, never re-judged automatically.
163
+
164
+ **"Judged and failed" is not "could not judge."** Only real verdicts go in
165
+ `declined.jsonl`. A tribunal API error, or a jury below quorum, leaves the
166
+ candidate in proposals untouched. Conflating them lets one transient outage
167
+ permanently bury good lessons behind a watermark that has already moved.
168
+
169
+ ## Conventions this repo imposes
170
+
171
+ From [CLAUDE.md](../CLAUDE.md) — these differ from the onlooker repo:
172
+
173
+ - **Hooks are bash.** No Python or Node entry points in hook scripts, though they
174
+ may shell out to `node` for event emission or heavy lifting.
175
+ - **Event names** follow `<plugin>.<noun>.<verb>`. Likely additions here:
176
+ `librarian.lesson.proposed`, `librarian.lesson.approved`,
177
+ `librarian.lesson.declined`, `tribunal.lesson.judged`.
178
+ - **ULIDs, not UUIDs**, and each plugin ships its own helper. Librarian will need
179
+ one for lesson ids if it does not have one — copy
180
+ `plugins/tribunal/scripts/lib/tribunal-ulid.sh` and rename the prefix.
181
+ - **Config defaults** live in the plugin's `config.json`; user overrides go under
182
+ the plugin's namespace key in settings. See ADR-004.
183
+
184
+ ## Out of scope
185
+
186
+ **Counter-observations and re-judgment.** They need consumers of shared
187
+ lessons, which needs the sync service and retrieval. The contract already
188
+ defines `ZCounterObservation`, and the counter-observation threshold is
189
+ explicitly still an open number — do not invent one.
190
+
191
+ **Publishing anywhere.** The pipeline stops at the local approved pool. Nothing
192
+ crosses the network. The sync service drains that queue later, and does not
193
+ exist yet.
194
+
195
+ **The server-side re-judge for public lessons.** Local consensus for public
196
+ lessons runs here; the pool records the intended visibility so the server knows
197
+ what still needs independent judging.
198
+
199
+ ## Open questions
200
+
201
+ - **Where the human confirmation surfaces.** Librarian already has a proposal
202
+ queue and a SessionStart surfacer for memory promotions. Reuse it, or keep
203
+ lesson proposals separate so the two kinds of confirmation are not confused?
204
+ - **`author_key` derivation.** The contract pins the format — 32 hex,
205
+ `HMAC(user_secret, scope)` — but nothing derives it yet. Where does
206
+ `user_secret` live, and how is it created on first use?
207
+ - **Whether the transform self-validates** against the published JSON Schema
208
+ before writing to the pool, or leaves all validation to ingest. Validating
209
+ locally catches a bad transform earlier; it also means fetching and caching
210
+ a schema from another repo.