# Upgrade Guide — vNEXT

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

## What Changed

Added `src/core/PrincipalGuard.ts` — the pure-logic brain of the "Know Your
Principal" cross-principal coherence guard (constitution standard ratified in
#898). It establishes a topic's operator only from the authenticated sender,
detects operator-role-decision attributions in agent-authored text ("X
approved", "Mandate (X)", "locked with X", "X dropped a token"), and flags any
credited to a principal who is neither the bound operator nor a known user —
blocking authority/credential misattributions, warning on prose. No runtime
consumers yet (the wiring is a later increment).

Fixes #866: `POST /projects/:id/advance` building→merged always failed
`GH_PR_VIEW_UNAVAILABLE` because `StageTransitionValidator` has no internal
default for `ghPrView`/`gitMergeBaseIsAncestor` and the route never injected
them — so no project item could ever reach `merged` through the live API.
The route now injects both as read-only helpers (`gh pr view` and
`merge-base --is-ancestor` via SafeGitExecutor.readSync) against the
project's target repo. A wiring-integrity test asserts the helper-absent
error can never recur.

macOS Spotlight (`mds_stores`) was a top constant CPU consumer on busy fleet
boxes because it re-indexed the Claude Code session transcripts on every turn —
~18 GB of JSONL that grows with every message. Instar already excluded
`.worktrees/` and `node_modules/` from Spotlight; this extends the same
`.metadata_never_index` exclusion to the agent's Claude transcript directory
(`~/.claude/projects/<encoded-agent-home>`), the largest churning set.

New `ensureClaudeTranscriptSpotlightExclusion()` helper + a `PostUpdateMigrator`
backfill so existing agents get the relief on their next update.

## What to Tell Your User

Nothing user-facing changes. This is foundation code (experimental) for the
security fix behind the Caroline identity-bleed incident — it does not alter any
current behavior.

If you drive a multi-spec initiative through the projects pipeline, its
items can now actually reach the "merged" stage — the system verifies the
work's pull request really merged (merge state, commit reachable on the
main branch, CI green) instead of always erroring out. Project status
finally tracks reality through the whole pipeline.

Nothing required — this is silent OS-level resource hygiene. If they've noticed
the Mac running hot, part of the cause was Spotlight endlessly re-indexing
session transcripts; this stops that going forward.

## Summary of New Capabilities

- `PrincipalGuard` (experimental, no runtime consumers yet): `establishOperator`,
  `detectAttributions`, `evaluatePrincipalCoherence`.

- `POST /projects/:id/advance` with `targetStage: "merged"` now works end to
  end (was structurally impossible): it verifies the PR via `gh pr view` and
  confirms the merge commit is reachable on `origin/main` before recording
  the item as merged.

- `ensureClaudeTranscriptSpotlightExclusion()` — drops a `.metadata_never_index`
  marker at the agent's Claude transcript dir so macOS Spotlight stops
  re-indexing the constantly-appended JSONL session transcripts (~18GB churn).
- `PostUpdateMigrator` backfill — existing agents get the exclusion on their next
  update; new agents get it once they have transcripts. Internal OS hygiene; no
  agent-facing API or config surface.

## Evidence

Net-new capability. Verified by 13 unit tests including the incident-replay
regression test (the three real Caroline doc lines all caught with the topic
bound to the operator; the same lines crediting the operator all pass) and a
clean `tsc --noEmit`.

- tests/integration/projects-api.test.ts: building→merged now returns
  GH_PR_VIEW_FAILED (not UNAVAILABLE), deterministic regardless of whether
  gh is installed/authed. Full projects-api (45) + StageTransitionValidator
  (26) green; tsc + destructive lint clean.

Unit + migration tests (both sides of every boundary: marker dropped when
transcripts exist, correct encoding, graceful no-op for a new agent, idempotent;
migration backfills/skips/idempotent). 15/15 green. `tsc --noEmit` clean.
Mirrors the existing node_modules/worktree exclusion pattern.

## Scope (honest)

This prevents FUTURE re-indexing. It does not instantly drop `mds_stores` —
Spotlight releases already-indexed content on its own schedule; forcing
immediate eviction needs a one-time `sudo mdutil -E ~/.claude/projects` the
operator runs. One of several resource-efficiency fixes (2026-06-06).
