v0.2.5 — Brain M4: Claim Identity
Brain M4 — Claim Identity. Claims acquire a stable identity: lexical slot keys backed by a curated per-workspace vocabulary, an alias proposal/decision flow with permanent rejection memory, typed object_cmp and subject_cmp comparison columns, and a tier guard preventing a draft from superseding a published warehouse-derived fact.
⚠️ Before you upgrade a multi-region deployment
Region export bundles move to v3. Importers accept 1 | 2 | 3, so old-bundle → new-destination is safe, but a source region on v0.2.5 exporting into a destination still on v0.2.4 fails the whole bundle with Unsupported bundle version: 3.
Every destination region must be on v0.2.5 before any source region is. Avoid triggering a cross-region residency migration during the rollout window.
Changed — /api/v1/admin/*
These are behavior changes on documented admin endpoints. Per the stability contract, /api/v1/admin/* is the Admin Console's backing API: additive by default, but a validation rule or refusal condition may tighten where the previous behavior was defective. If you automate against these routes, read this section.
POST /admin/brain-facts/{id}/correct— the identical-replacement guard now compares slot keys instead of raw bytes, soBobandbobare one slot. A supersede that previously succeeded may now return400 REPLACEMENT_IDENTICAL. Note this is vocabulary-dependent: the same request can change verdict after an alias approval.POST /admin/brain-facts/{id}/correct— new400 REPLACEMENT_MALFORMED. Previously these requests returned200and installed a successor that nothing could ever corroborate, contradict, or supersede.POST /admin/migrate/import— new409, refusing the entire bundle when a fact has no identity key at a position whose surface normalizes to a real one. Nothing is written. On the v1/v2 legacy arm the cause is destination-side vocabulary, so re-exporting will not fix it — repairbrain_vocabulary_targeton the destination.POST /admin/migrate/import— facts whose surface normalizes away (-,___) now land tombstoned (invalidated_atset, placeholder key) rather than live. ChecktombstonedFactsin the import response first: tombstoned facts are invisible tosearchBrainand the review queue, their surfaces are retained verbatim, and only clearinginvalidated_atby hand restores them.
Migrations
Ships 8 migrations (0187–0194), including a NOT NULL tightening on brain_facts slot keys with backfill. 0194 tombstones any row it cannot key. Measured at 86 ms total against a production-representative corpus; the dominant cost is AccessExclusiveLock on brain_facts held for the duration of 0187 and 0194, which scales linearly with corpus size (~7 s each at 200k rows).
What's Changed
- docs(research): T1 — the semantic glossary is not the brain's vocabulary (#5005) by @msywulak in #5014
- docs(adr): ADR-0037 — claim identity in the brain (#5004) by @msywulak in #5018
- feat(brain): identity key columns, lexicalNorm, and the day-one backfill (#5019) by @msywulak in #5045
- docs(roadmap): record Brain M4 slice A's first issue shipping (#5019) by @msywulak in #5046
- feat(brain): materialize claim identity keys and repoint the three slot consumers (#5020) by @msywulak in #5048
- test(brain): strip FakeBrainStore of identity answers; one -pg corpus, three verdicts (#5021) by @msywulak in #5049
- docs(roadmap): record Brain M4 slice A's third issue shipping (#5021) by @msywulak in #5050
- feat(brain): the vocabulary — approved edges plus a derived effective-target closure, position-scoped (#5022) by @msywulak in #5051
- docs(roadmap): record Brain M4 slice B shipping (#5022) by @msywulak in #5052
- feat(brain): the alias decision seam — auto-approve split, direction, and permanent rejection memory (#5023) by @msywulak in #5053
- docs(roadmap): record Brain M4 slice C shipping (#5023) by @msywulak in #5054
- fix(brain): the drift re-key, an identity-mutation lock namespace, and a collision re-check in SUPERSEDE_STAMP_SQL (#5024) by @msywulak in #5055
- feat(brain): object_cmp, the fail-closed typed parser, and three-valued agreement (#5030) by @msywulak in #5057
- feat(brain): the tier guard — a draft may not stamp a published warehouse-derived fact (#5033) by @msywulak in #5058
- docs(roadmap): record Brain M4 slice D shipping (#5033) by @msywulak in #5059
- chore(test): delete counts-in-prose, and move the comment sweep to the final round by @msywulak in #5063
- docs(roadmap): record Brain M4 slice D shipping (#5024) by @msywulak in #5056
- chore(test): the mutation runner — generated tables, not hand-typed ones (#5060) by @msywulak in #5062
- fix(brain): cardinality becomes a property of the canonical predicate; delete the both-sides clause (#5027) by @msywulak in #5064
- docs(agents): fill #5027's merge refs, and add /review-panel Step 6 by @msywulak in #5065
- refactor(web/admin): the Company Brain is a nav group, not a table name (#5066) by @msywulak in #5067
- docs(roadmap): fill #5066's merge refs, and record its prose-accuracy lesson by @msywulak in #5070
- test(e2e): delete the connection-groups spec, dead since the 0096 cutover by @msywulak in #5071
- fix(web/admin): the feature gate speaks the server's words, and carries the request id (#5068) by @msywulak in #5072
- docs(roadmap): mark #5068 shipped, and record its four-round panel non-convergence by @msywulak in #5073
- refactor(brain): the batched, role-less entity resolver (#5031) by @msywulak in #5074
- docs(roadmap): mark #5031 shipped, and record its four-round panel by @msywulak in #5075
- feat(brain): subject_cmp with inverted polarity, and the review-gate widening disclosure (#5032) by @msywulak in #5076
- docs(adr): amend ADR-0037 §6 from #5025's design pass, and correct T11 §5(b) by @msywulak in #5079
- feat(brain): the alias-proposal query — structural evidence, repeat-gated (#5034) by @msywulak in #5080
- feat(brain): bundle v3 — keys travel verbatim, both _cmp columns are nulled at import (#5035) by @msywulak in #5081
- The Company Atlas — a destination for the arc, ADR-0038, and the Layer 1 rename by @msywulak in #5084
- docs(context): pin the Claim Vocabulary, its two panes, and surface/norm/key by @msywulak in #5085
- feat(brain): the blast-radius counterfactual — collision slot expressions as a parameter, not a fork by @msywulak in #5089
- feat(web/admin): direct alias authoring and the In-force pane (#5087) by @msywulak in #5090
- feat(web/admin): the Pending proposal queue, and the object-position blast radius by @msywulak in #5091
- docs(agents): close the review panel's sibling blind spot by @msywulak in #5092
- docs(roadmap): record the Claim Vocabulary surface, its open AC, and the panel fix by @msywulak in #5094
- feat(brain): an alias preview SAYS its target predicate is curated single (#5093) by @msywulak in #5095
- docs(agents): name a falsifier every round, build it in the closing one by @msywulak in #5096
- ci: gate the generated mutation tables, and refuse a baseline that lies (#5077) by @msywulak in #5098
- docs(agents): check a fix against its own finding, in fresh context, in the round by @msywulak in #5099
- docs(agents): split the yield metric, and make a STOP a closing round by @msywulak in #5100
- docs(agents): promote a twice-violated principle to a check; default late machinery to a follow-up by @msywulak in #5101
- fix(brain): correction inherits the slot keys from its target instead of re-deriving them by @msywulak in #5102
- fix(mutations): repair the cardinality anchor #5102 killed, and remeasure by @msywulak in #5103
- feat(brain): make the slot keys total — tighten MALFORMED_CLAIM, then SET NOT NULL by @msywulak in #5104
- fix(brain): close the five #5047 follow-ups — the leak falsifier, the import 500, 0194's per-column scoping, the computed arm, the re-key's lost distinction by @msywulak in #5110
- docs(agents): close the seven gaps #5110 found in /ship-issue by @msywulak in #5111
- feat(residency): merge two vocabularies on import — union approved edges, refuse cycles (#5036) by @msywulak in #5114
- ci: take the two heavy gates off every PR's critical path by @msywulak in #5115
- feat(brain): admin-triggered bounded tension sweep over existing rows (#5029) by @msywulak in #5116
- docs(agents): fold #5029's loop findings back into /ship-issue and /review-panel by @msywulak in #5117
- chore(ci): a skipped eval job fails the gate, by default (#5040) by @msywulak in #5118
- chore(brain): drop the deferred unique index on the live slot (#5038) by @msywulak in #5119
- ci(eval): run the real-model eval through the gateway, not a direct Anthropic key by @msywulak in #5120
- fix(eval): the MCP eval auth fixture depended on the runner's NODE_ENV by @msywulak in #5121
- ci(eval): split the paid LLM eval into its own workflow, on a weekly schedule by @msywulak in #5124
- docs(roadmap): record the eval lane's three findings and the workflow split by @msywulak in #5125
- fix(eval,mcp): adjudicate the 1/20 eval — two surface, three grader, one harness defect (#5122) by @msywulak in #5127
- docs(agents): open the PR as a draft first, so remote CI runs alongside the panel by @msywulak in #5132
- fix(eval): a successful
explorecall no longer fails its question — apply the tool's output contract at the recording seam by @msywulak in #5133 - fix(eval): route every canonical-eval path through one process.exit by @msywulak in #5134
- fix(brain): regenerate the stale bundle-identity mutation table by @msywulak in #5142
- fix(eval): make stdout under
--jsoncarry the JSON payload and nothing else by @msywulak in #5141 - fix(eval): grade a keyed answer on its substance, not its group labels by @msywulak in #5140
- docs(roadmap): record #5126 — the eval artifact had never parsed by @msywulak in #5144
- docs(roadmap): record #5128 — the keyed comparison graded a display label, and the obvious fix was the fourth false negative by @msywulak in #5145
- fix(eval): close the six residual eval-lane defects — tool contract, keyed comparison, throttle scoring, token usage, --json stdout by @msywulak in #5148
- docs(stability): scope the v1 additive-only promise out of /api/v1/admin/* by @msywulak in #5149
Full Changelog: v0.2.4...v0.2.5