# Upgrade Guide — vNEXT

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

## What Changed

Adds the **Standards Enforcement-Coverage Audit** (spec #3 of the
cartographer-conformance project) — the constitution's named-but-unbuilt
"registry-wide conformance gate," scoped to the version that is cheap, deterministic,
and useful immediately. Ships **dark** behind `cartographer.conformanceAudit.enabled`.

For each standard in `docs/STANDARDS-REGISTRY.md`, the audit reads the enforcement
mechanism the standard's own prose names (a test, a lint, a gate, a route) and
**verifies that mechanism actually exists on disk**, then classifies each standard's
enforcement strength (a CI ratchet is stronger than a gate, than a lint, than a
design doc, than nothing). It surfaces the GAPS — standards with no verifiable
structural guard — and, louder, **dangling references**: a standard that cites a
guard which no longer exists. It is the founding principle "Structure beats
Willpower" made measurable: which rules are guaranteed, and which are still wishes.

The core is fully deterministic — local file reads only, zero token cost, zero
egress, identical output every run — exposed via two owner-gated read routes
(`GET /conformance/coverage`, `GET /conformance/coverage/health`) and guarded by a CI
ratchet (an enforced-ratio floor that can only rise, plus a hard zero ceiling on
dangling references). An optional language-model enrichment pass for fuzzy cases is a
structural stub, off by default; the deterministic coverage is always the authority.
A slow optional job recomputes and raises ONE aggregated note only when a new gap
appears. Two earlier designs (a per-file language-model audit, then a narrowed
variant) were rejected at review as intractable and then as a no-op respectively.

On its first run against the live constitution it surfaced a genuine dangling
reference — the "Know Your Principal" standard cited a spec path that does not exist
— which this change repairs to cite the real artifacts (a one-line citation
correction, no rule content changed).

The interactive (user-facing) session lane now pins to a subscription-pool account,
mirroring the headless lane. When `subscriptionPool.pinSessionsToPool` is enabled,
`SessionManager.spawnInteractiveSession` consults the same spawn-account resolver
that `spawnSession` uses (unless the caller passed an explicit `configHome`, e.g. the
account-swap path, which still wins). The session launches under the scheduler-picked
pool account's config home and is tagged with `subscriptionAccountId` — making the
user's own conversation directly eligible for proactive and reactive auto-swap,
instead of riding the default login untagged (rescuable only by the
ProactiveSwapMonitor's default-login fallback). The resolver-pinned home is seeded
onboarding-ready first, so a headless-enrolled home can't wedge the launch on the
first-launch wizard. Claude-code only; complete no-op when pinning is off.

## What to Tell Your User

- **Which of your agent's rules are actually guaranteed?**: "I built a check that goes
  through every rule in the agent's constitution and confirms whether a real,
  automatic guard exists for it — a test, a lint, a gate — or whether it's still just
  a sentence someone has to remember. It surfaces the rules that are still only
  wishes, so each one becomes a guard worth building. It's off by default and costs
  nothing to run. On its very first pass it already caught one rule pointing at a
  guard that had been moved."

The conversation you actually chat with is now protected the same first-class way
your background sessions are. When you pool several logins, your own chat session is
tagged to whichever login it is running on, so the moment that login gets close to
full I can move your conversation to a fresh login before it ever stalls — not just
rescue it after the fact. Nothing changes unless you have pooling turned on.

## Summary of New Capabilities

| Capability | How to Use |
|-----------|-----------|
| Per-standard enforcement coverage map | GET /conformance/coverage (opt-in; off by default) |
| Coverage health + gap list + dangling-ref count | GET /conformance/coverage/health |
| Filter coverage | GET /conformance/coverage?family=…&kind=…&status=gap |
| CI enforcement-coverage ratchet | `node scripts/standards-coverage.mjs --check` |

- The interactive session lane pins to a pool account and carries its account tag,
  so the user's conversation is first-class for both proactive and reactive swap.

## Evidence

- `tests/unit/interactive-session-pin.test.ts` — 6 cases: resolver-pin, explicit
  home wins, unwired no-op, empty-pool no-op, codex-not-pinned, onboarding-safe seeding.
- `tests/integration/subscription-pin-sessions.test.ts` — interactive lane pins via
  the real `selectAccount`-wired resolver; empty-pool no-op.
- `tests/e2e/session-management-e2e.test.ts` — real tmux: an interactive session is
  tagged with the resolver-picked account and its home is seeded onboarding-ready.
