# Upgrade Guide — vNEXT

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

## What Changed

Second build slice of the Working-Set Handoff spec (P2 of multi-machine
coherence): the chunked `working-set-pull` mesh verb (both sides), the
durable pending-pull ledger, and never-clobber landing. Nothing schedules a
pull yet — the receiver trigger, reflex route, and staggered drain are
P2.2b. Dark by default: the serve side constructs only where
`multiMachine.coherenceJournal.replication.enabled === true`.

- `working-set-pull` verb (three lockstep edits mirroring journal-sync):
  fresh-manifest-as-allowlist serving, O_NOFOLLOW + fd-identity TOCTOU
  defense, 1 MiB chunked responses (the documented event-loop-starvation
  root cause stays dead), offset-0 whole-file sha256 + cheap fstat
  generation anchor so a file rewritten mid-transfer can never assemble
  into a chimera — bounded restart-from-0, then one honest `unstable`.
- `WorkingSetPuller`: sequential offset cursors with per-tick yields,
  busy-is-retry-without-penalty (a just-woke producer's throttle never
  exhausts recovery records), assembled-bytes budget (discarded restart
  chunks don't count), hostile-relPath jail, and never-clobber landing —
  divergent local files keep their place; the incoming copy lands ALONGSIDE
  (hash-suffixed, capped at 2, eviction through SafeFsExecutor).
- `PendingPullLedger`: the durable EXO-case record. Single-writer
  serialized mutate() funnel (the exact lost-update shape that caused
  topic-flood #3, closed at birth), corrupt-parse quarantine that is NEVER
  silently read as empty, TTL sweep with one honest expiry notice,
  supersession clearing ALL lower-epoch records across nominees, and the
  (peer,topic,epoch) attempt-cap breaker.
- Config: `coherenceJournal.workingSet` block (12 bounded-behavior dials,
  no enable flag — the feature rides the explicit replication gate).
- State-Coherence Registry: new `pending-pulls` category (machine-local,
  single-writer).

Final build slice of the Working-Set Handoff spec (P2 of multi-machine
coherence): the transfer machinery from P2.2a now FIRES — on a topic move,
on demand, and on a returning producer. Still dark everywhere except
explicitly replication-enabled pairs.

- `WorkingSetPullCoordinator`: one pipeline behind three triggers — the
  receiver's deliverMessage onAccepted seam (the moment this machine knows
  it owns the topic), the fetch reflex, and the returning-peer staggered
  drain (one pull at a time against a just-woke machine, never a mob).
  Restart-proof (topic,epoch) dedupe; nomination from journal evidence
  (every machine that actually produced artifacts, capped at 3 with the
  excess NAMED); busy responses never burn recovery budget; stale-owner
  and superseded records clear themselves.
- `POST /coherence/fetch-working-set` — the reflex: "who made artifacts
  for this topic? go get them." The EXO failure as a one-call recovery.
  503 while dark, 429 when rate-limited, coalesces into a running pull.
- `PeerVisibilityGuard` (§3.6 rider, earned from the Mini's 10 invisible
  hours): improper revocations (revokedAt with no who-or-why) surface once
  across boots; a machine missing past a 30-min grace produces ONE notice
  naming any topic workspaces stranded on it; flapping collapses to a
  single notice. All through the agent-health attention lane.
- `PeerPresencePuller.onPeerRecorded` — the re-arm rides the existing 30s
  presence cadence; no new polling loop.
- Agent Awareness + Migration Parity: the CLAUDE.md template (and
  `migrateClaudeMd` for existing agents) gains the fetch-reflex entry with
  the proactive trigger: user references files/work not on this machine →
  fire the reflex, answer from the landed files.
- State-Coherence Registry: `pull-opkeys` + `visibility-guard` categories
  (69 total).

## What to Tell Your User

Nothing user-visible yet — this is the transfer machinery for "moving a
conversation between your machines moves its working files too." The piece
that actually fires it on a move (and the on-demand "go fetch that
workspace" reflex) lands in the next slice.

On machine pairs with diary sync enabled: moving a conversation between
your machines now moves its working files too — automatically, with
nothing ever overwritten (a conflicting local copy keeps its place; the
incoming version lands alongside it). If the machine holding the files is
asleep when they're wanted, the request is written down and fires the
moment it returns — and you can always ask me to fetch a topic's workspace
on demand. Everywhere else: nothing changes yet.

## Summary of New Capabilities

- `working-set-pull` MeshCommand — chunked, bounded, fresh-manifest-gated
  file serving between registered same-operator machines (dark until
  replication is explicitly enabled).
- `WorkingSetPullServer` / `WorkingSetPuller` (`src/core/WorkingSetPull.ts`)
  — the serve/receive engine with generation-anchor consistency, busy
  throttling, and never-clobber landing.
- `PendingPullLedger` (`src/core/PendingPullLedger.ts`) — durable,
  single-writer pending-pull records surviving restarts; the offline-
  producer case re-fires instead of dying at a breaker.
- `coherenceJournal.workingSet` config defaults (ConfigDefaults +
  CoherenceJournalUserConfig).

- `POST /coherence/fetch-working-set {topic}` — on-demand workspace fetch
  (Bearer; 503 dark / 429 rate-limited / 200 outcome with per-nominee
  reports).
- `WorkingSetPullCoordinator` (`src/core/WorkingSetPullCoordinator.ts`) —
  move-trigger + reflex + staggered-drain orchestration.
- `PeerVisibilityGuard` / `detectImproperRevocations`
  (`src/core/PeerVisibilityGuard.ts`) — mesh-health hygiene notices.
- CLAUDE.md proactive trigger for cross-machine file references (new
  agents via template, existing agents via migrateClaudeMd).

## Evidence

- `tests/unit/WorkingSetPull.test.ts` — 16 passing (anchor restart lands
  the new content; never-sits-still → `unstable` with nothing landed; busy
  exhaustion re-files without penalty; alongside cap-2 eviction; malicious
  manifest relPaths refused; ownership-recheck abort; assembled-bytes
  budget; serve refusal matrix + TOCTOU symlink swap).
- `tests/unit/PendingPullLedger.test.ts` — 13 passing (concurrent mutate()
  drops no record; corrupt → quarantine + one notice, never silent-empty;
  supersede clears all nominees; breaker + new-epoch reset; TTL once).
- `tests/integration/working-set-pull-roundtrip.test.ts` — 4 passing
  (1.5MB near-cap chunked round-trip through the REAL express.json +
  signed MeshRpcClient path, independent content oracle; full-stack
  refusals; divergent-alongside; mixed-version 501 back-off).
- Adjacent mesh/journal suites unchanged (78 total across 8 suites);
  typecheck + lint chain clean.

- `tests/e2e/working-set-handoff-lifecycle.test.ts` — 2 passing,
  production-shaped (REAL deliverMessage handler + signed dispatcher +
  journal streams): a move lands the file (source-disk oracle; re-delivery
  + op-key dedupe leave it untouched), and THE EXO CASE end-to-end —
  producer offline at move → pending-pull survives a restart → re-fires on
  return → file lands.
- `tests/unit/WorkingSetPullCoordinator.test.ts` (12) +
  `tests/unit/PeerVisibilityGuard.test.ts` (5) +
  `tests/integration/working-set-reflex-route.test.ts` (2).
- Full P2 sweep: 95 tests / 11 suites green; typecheck, lint chain,
  docs-coverage clean.
