# Upgrade Guide — vNEXT

<!-- assembled-by: assemble-next-md -->
<!-- bump: patch -->

## What Changed

The **knowledge base is now the FOURTH concrete consumer of the HLC replicated-store foundation and the THIRD memory-family kind** (after WS2.3 relationships and WS2.2 learnings) — `knowledge-record` rides the foundation primitives (envelope / union-reader / conflict-store / rollback-unmerge / bounds) so a knowledge source the agent ingested on one machine is known on the others. It REUSES the WS2.2 PII machinery rather than reinventing it. Per `docs/specs/multi-machine-replicated-store-foundation.md`.

- **The `knowledge-record` replicated kind** (`src/core/KnowledgeReplicatedStore.ts`) — a STRICT typed schema that is a **discriminated union on `op`** (a value schema AND a delete-tombstone schema coexist under one kind) and **type-clamps every known field on receive** (`ingestedAt` is ISO-8601-only, `type` is one of {article, transcript, doc}, `wordCount` is a finite number, `tags[]`/`summary` are length-clamped, a path-shaped `url` is jailed out — so a foreign, attacker-controlled record can't smuggle markup through a render slot). The **disclosure-minimized, metadata-only projection** emits ONLY the catalog metadata (title, url, type, tags, summary, word count) — never the markdown file BODY, never the local generated `id`, and never the local `filePath` (a per-machine artifact path is meaningless + a mild info-leak on a peer). The cross-machine `recordKey` is a **content fingerprint** — `sha256(normalize(url || title) + normalize(type))` — so the SAME article ingested on two machines collapses to ONE record instead of duplicating (the generated id is the cross-machine-unstable id, exactly the relationship-UUID / LRN-id trap solved with a stable identity surface). The per-entry cap is **raised to 64KB** so a fat summary replicates instead of wedging the stream; a record still over-cap after projection is a NAMED rejection, never a silent truncate. HIGH impact tier at the **replication** layer (append-both-and-flag, never a silent clobber) but **advisory** at the **read** layer (both variants of an open conflict surface as guidance hints — a knowledge source is reference, not authority — the read never blocks).
- **DUAL REGISTRY** — `knowledge-record` is registered in BOTH `JOURNAL_KINDS` (`CoherenceJournal.ts` — the static serve/apply/advert half, with a `DEFAULT_RETENTION` entry that is never `rotateKeep:0` for compliance) AND `ReplicatedKindRegistry` (the dynamic half). A kind in only one silently replicates nothing; the coupling test asserts it.
- **Emit-on-write funnel + tombstones** — `KnowledgeManager` gains an injected (dark-by-default) `KnowledgeReplicationEmitter` seam; `ingest()` emits a `put` for the ingested source and — CRITICALLY — `remove()` emits an `op:'delete'` **tombstone** keyed on the removed source's fingerprint (else a peer re-replicates a locally-removed source forever — resurrection). The emit is best-effort: a throwing emitter never breaks the local write.
- **Read-only neutralized union** — the merged read resolves THROUGH the bypass-proof `ReplicatedStoreReader` and renders each foreign source inside a `<replicated-untrusted-data origin="…">` envelope (quoted advisory reference, never an instruction). A replicated record never clobbers a divergent local one.
- **Config + advert + awareness + migration** — `multiMachine.stateSync.knowledge { enabled:false, dryRun:true }` added to ConfigDefaults (classified in `DARK_GATE_EXCLUSIONS`; the dark-gate line-map recomputed by hand; `applyDefaults` backfills existing agents); the `stateSyncReceive` advert self-reports `knowledge` from the registry; the "One Memory" CLAUDE.md section gains a WS2.4 line in both `generateClaudeMd` and an idempotent `migrateClaudeMd` splicer.
- **Slice** — this PR builds `knowledge-record` ONLY, and replicates the catalog METADATA only (not the file body). Full-content-body sync, plus the evolution-queue / playbook memory-family kinds, reduce to "add schema + projection + flag" on this proven machinery and are a tracked follow-up (CMT-1416).

Pure MECHANISM, dark by default. A single-machine / flag-off agent is a strict no-op (no knowledge source ever crosses a machine boundary while dark).

## What to Tell Your User

None while dark — internal substrate. The user-visible capability — a source I ingested on one machine follows you to your others, collapsing the same source by content fingerprint instead of duplicating it — becomes real only when an operator turns on cross-machine knowledge replication. Only the catalog summary and pointer travel between machines, never the full ingested file body. That awareness ships in the CLAUDE.md One Memory section so the agent can honestly answer whether your ingested sources and knowledge base follow you across machines.

## Summary of New Capabilities

None user-facing while dark. New internal module `KnowledgeReplicatedStore.ts`; `KnowledgeManager` gains an injected (dark) knowledge-replication emit seam. No new routes (the foundation `/state/conflicts` · `/state/resolve-conflict` · `/state/quarantine` surface is reused).

## Evidence

- `tests/unit/KnowledgeReplicatedStore.test.ts` — dual-registry coupling; recordKey identity derivation (content fingerprint over url||title + type, NEVER the local id; same source collapses across machines/formatting; url-anchored collapse; collision-resistant across different sources + a `\x1f` field-straddle guard + type disambiguation); metadata-only projection (no local id, no filePath, no file body, filePath-leak guard); `fat-record-replicates` + `fat-record-does-not-wedge-stream`; `foreign-record-type-clamped` (ISO-8601 / enum / number clamps + url-jail reject smuggled markup); `tombstone-coexists-with-value` + delete-resurrection guard; the advisory append-both union merge; foreign-record render safety. Green.
- `tests/unit/knowledge-manager-replication.test.ts` — dark no-op; emit-on-ingest; **REMOVE EMITS TOMBSTONE** (no resurrection); remove-of-nonexistent emits nothing; a throwing emitter never breaks the local write; detach returns to no-op. Green.
- `tests/unit/ws24-knowledge-wiring.test.ts` — dual-registry + server.ts registration/union-reader wiring + KnowledgeManager emit seam + ConfigDefaults dark default + dev-gate exclusion + the awareness section + §12 union-reader-cannot-be-bypassed. Green.
- `tests/integration/ws24-knowledge-emit.test.ts` — the emit-on-mutation contract with a real AgentServer (ingest fires the put funnel keyed on the fingerprint; remove fires the tombstone; the shared /state/conflicts substrate is alive). Green.
- `tests/e2e/ws24-knowledge-alive.test.ts` — the Phase-1 "feature is alive" E2E: enabled = a knowledge-record conflict is open + readable + resolvable over HTTP (200); disabled = 503; routes require Bearer auth. Green.
