23. Org-brain graduation: cross-brain recurrence → org-brain, opt-in and manual by default¶
- Status: Accepted
- Date: 2026-07-06
- Deciders: kristof (owner); Claude (orchestrator)
- Relates: ADR-0007 (curation/review gate),
ADR-0008 (staging is per-user, local),
ADR-0014 (auto-promote default),
ADR-0015 (note
sourceprovenance), ADR-0019 (clone-on-demand), ADR-0021 (embeddings/semantic dedup), issues #110 (this feature), #167 (org-brain wiring), #168 (graduation-control primitive)
Context¶
Teams accumulate the same fact or decision independently across several project brains
(conventions, shared infra rules, client rules). The roadmap and architecture doc name
cross-brain graduation as a standing open thread: promote knowledge recurring across ≥2
project brains up to an org-brain where everyone can find it, without silently crossing a trust
boundary.
Graduation is fundamentally an audience-widening operation, and Commonwealth's note schema has
no visibility field — source (ADR-0015) is advisory only. The naive design (auto-detect
recurrence, stage into the org-brain) has one acute failure mode: the "recurs across ≥2 brains"
trigger is exactly the case where a fact shared between two different client brains would be
pushed into an org-brain that both clients' teams can read. For the multi-client agency that is our
first candidate user, cross-client leakage is the headline risk, not a corner case.
Two capabilities are missing in code and are split out as prerequisites: there is no way to designate or enumerate an org-brain (#167), and no primitive to say a note may leave its repo (#168).
Decision¶
Implement graduation as an on-demand, single-writer batch pass (graduateToOrgBrain() in
packages/curate, modeled on the existing consolidateCanon()), gated by four safety choices:
-
Opt-in, never opt-out (#168). A note is eligible only if it explicitly carries
graduate: true. Untagged notes never leave their repo. This honors the "never promote notes that shouldn't leave their repo" bar literally, and needs no schema-version bump (the field is passthrough, honored by anisGraduatable()policy). We accept lower recall (the feature starts quiet until authors/curators opt notes in) as the price of safe-by-default. -
Surface provenance at review, don't model audience (yet). Rather than build a visibility/ audience model and enforce an audience-superset check now, the pass stages the candidate with
sources:back-links to the ≥2 originating notes and shows the reviewer which brains it recurs in. A human makes the "is the org-brain a readable superset of these sources?" call at the manual promote gate. A first-class audience model may supersede this later. -
On-demand pull, not a background batch. Graduation runs when a human invokes
commonwealth graduate --suggest; detection is automatic, invocation is manual. This avoids a scheduled slot silently filling the org-brain queue and sidesteps cadence / review-fatigue / per-run-cap questions until there is evidence they are needed. -
Manual review by default, structurally. Candidates are created via
curate(orgBrainDir, …)— which routes through the org-brain's localstaging/queue — and never viacaptureCandidates(the only path that can auto-promote). So graduated candidates wait for/commonwealth:promoteregardless of any brain'sautoPromoteflag;autoPromotedoes not compose across the trust boundary.curate()also re-runs the secret + dedup + validation gate on the synthesized candidate.
Detection reuses the existing embeddings toolkit (ADR-0021): loadVectors + cosineSimilarity
over each brain's cached vectors, clustering same-kind notes across brains with a dedicated,
conservative RECURRENCE_THRESHOLD (0.90, distinct from the 0.85 within-brain dedup threshold),
plus a lexical corroboration floor, plus a hard "spans ≥2 distinct brains" bar (counted by
brain dir, since source is advisory and may be absent). The pass holds each mutated brain's
sync lock (org-brain for staging; a project brain's lock around any re-index), per ADR-0008.
Federated cross-brain search is not required. The minimal version is a local O(n·m) scan over already-registered brains — honest and sufficient for the acceptance bar. An ANN/federated index is future work for large N, not a blocker.
Consequences¶
- Positive. No leak-by-default; the acceptance bar is met literally. No schema-version bump. No new audience model or scheduler to build now. Reuses the embeddings, clustering, locking, and curation machinery wholesale rather than adding parallel systems. Small, reviewable PRs (#167 → #168 → #110).
- Negative / accepted. Low initial recall — nothing graduates until notes are marked
graduate: true. Cross-client safety rests on the human reviewer plus opt-in, not on an enforced audience check; if that proves insufficient we add a first-classvisibility/audiencefield and supersede decision (2). Org-brain identity is a local per-machine pointer (#167), so each teammate wires their own — slightly off the multiplayer thesis; a syncedrole: 'org'config can upgrade it later. Detection is a naive linear scan; fine at team scale, needs an index later. - Follow-ups. A rejected candidate must be tombstoned so the next pass does not re-propose the same cluster (tracked in #110). Threshold values (0.90 cosine + lexical floor + ≥2 brains) are conservative guesses pending calibration against a real multi-brain corpus.
Alternatives considered¶
- Opt-out tag (
no-graduate). Highest recall, simplest, but leaks by default — rejected because it contradicts the "Never" acceptance criterion and is dangerous for multi-client teams. - First-class
visibilityschema field + enforced audience-superset check. The most correct long-term design, but requires a schema-version bump and an audience model for every brain now. Deferred; opt-in + surfaced provenance gets the safety guarantee at a fraction of the cost. - Proactive background batch. "It just works," but reintroduces cadence, review-fatigue, and candidate-cap decisions with no evidence they are wanted yet. Deferred behind on-demand pull.
- Per-brain
role: 'org'config as the org-brain locator. Source-of-truth-in-repo and team- shared, but requires loading every brain's config to find the org-brain. Deferred in favor of the cheap local registry pointer (#167).