# Upgrade Guide — vNEXT

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

## What Changed

The Instar CLI now rejects unknown top-level commands before the bare setup flow can run. A typo such as `instar dev:claim-checkk` prints a clear unknown-command error and exits with status 1 instead of falling into the interactive setup wizard.

Bare `instar` remains unchanged: it still opens the setup flow for new or interrupted setup sessions. `instar help` now prints CLI help instead of entering setup.

Audit fix #2 under "No Unbounded Loops" (P19): the lease transport — the
machine-to-machine "who is awake" wire — gains its missing brakes. (1) Per-peer
failure logging is now state-change-based via the new pure `PeerFailureLogGate`
(first failure / every-360th reminder / recovery-once): a down peer at the
deliberate ~5s anti-blinding pull cadence now produces ~49 log lines per day
instead of ~17,000, and previously-SILENT non-ok responses (a peer actively
rejecting us) are now visibly logged under the same bound. (2) Both transport
fetches carry `AbortSignal.timeout` — the pull loop's re-entrancy guard meant a
single hung socket would have wedged every future pull forever. The timeout
defaults to 30s and is derived from `leaseTtlMs` at the server construction
site (`min(ttl/2, 30s)`) — sized ABOVE the fleet's documented 5–40s
receiver-stall envelope after the adversarial second-pass reviewer showed a
10s default could convert a slow-but-alive peer into "no medium" and falsely
self-suspend a healthy lease holder via the renewal path. Cadence, lease, and
anti-blinding semantics unchanged.

The ServerSupervisor's slow-retry mode (respawn a dead server every 2h, forever)
is a sanctioned Eternal Sentinel under the new "No Unbounded Loops" standard —
but it violated condition 4: it never told anyone. A multi-day crash-revive loop
was indistinguishable from silence. Now a pure one-shot latch
(`SlowRetrySentinelEscalation`, the AgeKillBackoff suppressor shape) fires
exactly once per outage episode after a sustained-failure threshold (default
12h ≈ 6 failed cycles): the supervisor emits `sentinelStalled` and the lifeline
sends ONE operator message with the two useful levers (`/lifeline doctor`,
`/lifeline reset`), then the sentinel keeps quietly retrying. The message goes
directly to the Telegram Bot API from the lifeline process — no dependency on
the (down) agent server. Recovery re-arms the latch via the single
`resetCircuitBreaker()` funnel; retry/kill/spawn decisions are unchanged.

## What to Tell Your User

- **Clearer command typos**: "When I mistype an Instar command, I now fail fast with a clear message instead of opening setup and looking stuck."

If you run me on more than one machine: my logs no longer flood with thousands
of identical "can't reach the other machine" lines when a machine is down (you
get one line when it goes, a brief reminder every half hour, one when it's
back), and a single stuck network connection can no longer silently break the
machines' ability to notice each other — without any risk of a healthy machine
wrongly stepping down.

If your agent's server ever gets stuck in a crash loop, you'll now get one
clear heads-up after ~12 hours — "still down, here's how to diagnose or force a
retry, I'll keep trying" — instead of discovering the outage by noticing your
agent went quiet for days. One message per outage, never a stream.

## Summary of New Capabilities

| Capability | How to Use |
|-----------|-----------|
| Unknown command rejection | Automatic for mistyped top-level Instar commands |
| Bare setup preservation | Automatic when running Instar without a command |
| Help command preservation | Automatic when asking Instar for help |

- Bounded mesh failure logging (state-change + capped reminders, recovery
  notices, rejecting-peer visibility) via `PeerFailureLogGate` — reusable for
  other fixed-cadence transports.
- Hung-socket protection on all lease-transport HTTP calls (config-derived
  abort timeout).

- Slow-retry escalation: a sustained server outage (default 12h in slow-retry)
  produces exactly one operator notification per episode; the never-give-up
  revival behavior is unchanged. In-code default; no config required.

## Evidence

Reproduced the typo path locally with the built CLI. Before this change, a typoed command could enter the interactive setup path and hang an agent shell. After the change, `node dist/cli.js dev:claim-checkk` exits 1 with `error: unknown command 'dev:claim-checkk'` and the help hint. A separate `node dist/cli.js help` probe exits 0 and prints CLI help. A separate bare invocation probe, `timeout 3 node dist/cli.js`, still enters setup and times out at status 124, confirming the default setup behavior remains intact.

Loop-safety audit (CMT-1109) verified at source: `pullPeer` per-attempt logging
(~17k lines/day per down peer at 5s cadence — the reaper-flood signature) and
no abort signal on either fetch while `leasePulling` blocks re-entry. Reviewer
finding applied pre-commit (timeout 10s→30s + config derivation; the
false-self-suspend trace is documented in `docs/specs/mesh-pull-brakes.md`).
Tests: 22 green across `PeerFailureLogGate.test.ts` (incl. the P19
sustained-failure bound: 17,280 failures → 49 lines) and
`HttpLeaseTransport.test.ts` (AbortSignal presence pin, gated pull/broadcast
logging, recovery-once, server.ts derivation wiring pin); all pre-existing
lease suites green; tsc clean.

Loop-safety audit finding (CMT-1109), verified at source: the slow-retry block
in `src/lifeline/ServerSupervisor.ts` was annotated "never truly give up" with
no operator signal. Fix is the first PR under constitution P19 ("No Unbounded
Loops", incl. Justin's Eternal Sentinel caveat — this loop is its namesake
case). Tests: 10 green in `tests/unit/SlowRetrySentinelEscalation.test.ts`
including the P19 sustained-failure bound (week-long never-recovering episode →
exactly 1 escalation) and source-shape wiring pins. Independent adversarial
second-pass: CONCUR (all probes safe — per-tick reachability, no double-fire,
server-independent delivery, emit-before-spawn ordering). tsc clean.
