# Upgrade Guide — vNEXT

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

## What Changed

The subscription-path interactive pool's startup empty-prompt canary used to `throw` on
a structured failure, which rejected `start()`'s `Promise.all` and made the **entire
pool refuse to start** — stranding all Anthropic work onto the SDK credit pot and, under
transient CPU starvation (a slow/garbled canary round-trip), re-failing every spawn and
tripping the LLM circuit breaker in a loop (2026-06-07 "server temporarily down on every
message", topic 21816). A canary failure now **degrades gracefully**: it reports the
degradation and brings the session ready anyway, so the pool serves real prompts and
empty-prompt detection runs best-effort for that lifetime. This makes the structured-fail
path consistent with the adjacent canary-infra-error path, which was already non-fatal.

instar now manages Claude Code's transcript retention (`cleanupPeriodDays`), setting it to
14 days for new agents (init) and existing agents (migration, set-if-unset). Claude writes a
transcript per session — including every fleet background `claude -p` one-shot — and the
unset default of 30 days let them accumulate (observed ~322k files / 18 GB on one box). This
caps the pile-up fleet-wide.

## What to Tell Your User

If the cheaper subscription path went dark and everything fell back to metered credits
(with repeated "pausing all LLM work" circuit trips) during a busy period: a failed pool
self-test no longer takes the whole pool down. Nothing for them to do.

Nothing required — internal disk hygiene. Chat transcripts older than 14 days are pruned by
Claude automatically; recent ones (and the ability to resume them) are unaffected. If you set
your own retention period, it is left as-is.

## Summary of New Capabilities

- `InteractivePool.spawnOne` treats a startup empty-prompt canary `status: 'fail'` as
  non-fatal: report the degradation, keep the canary marked as run, bring the session
  ready (no throw, no session kill). A genuinely broken session is still caught by the
  existing per-call retire/replace path.

- `.claude/settings.json` `cleanupPeriodDays` is now instar-managed (default 14; set-if-unset).

## Evidence

`pool-canary-graceful.test.ts`: source guards that the canary-fail branch no longer
throws, no longer kills/deletes the session, still reports a degradation, and that
`spawnOne` reaches the ready transition after the canary block. The existing 53
interactive-pool unit tests pass unchanged; `tsc --noEmit` clean; no-silent-fallbacks
budget unaffected (removes a throw, adds no catch). causalAutopsy: latent — the
structured-fail branch was fatal from the start while the adjacent infra-error branch
was non-fatal; surfaced as a circuit-tripping outage only once a busy box made the canary
round-trip slow enough to "fail."

`tests/unit/PostUpdateMigrator-cleanupPeriodDays.test.ts` 4/4; adjacent migrateSettings suites
27/27; `tsc` clean.

## Scope (honest)

Contained Tier-1 change to one conditional in one file
(`src/providers/adapters/anthropic-interactive-pool/pool.ts`). The pool is opt-in
(subscription-path). Normal (canary-passes) operation is unchanged. No new API/route/
config/migration. Note: Justin already stabilized this live during the incident; this is
the durable code fix so it can't recur.

Pure disk/file-count hygiene, NOT a CPU fix — transcripts were already Spotlight-excluded.
Tunable per-agent; reversible.
