Skip to content
This repository was archived by the owner on Jul 24, 2026. It is now read-only.

fix(up): a fresh foreground convoy up UN-PARKS its members — restore the FULL fleet after an outage - #106

Merged
myobie merged 1 commit into
mainfrom
parking-recovery-unpark
Jul 22, 2026
Merged

fix(up): a fresh foreground convoy up UN-PARKS its members — restore the FULL fleet after an outage#106
myobie merged 1 commit into
mainfrom
parking-recovery-unpark

Conversation

@myobie

@myobie myobie commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

What & why

Parking-recovery for the 2026-07-22 incident: a supervisor bring-up after a mass outage brought back only part of the fleet — the rest stayed parked from a prior supervisor's give-up and had to be hand-launched.

Root cause

strategy.status=flapping and the fast-fail counter persist to a session's tags (the on-disk supervision contract), so they outlive the supervisor that wrote them. An outage drives the cap to its limit → the agents park → and a fresh convoy up, reading those stale tags, hits classify's isFlapping → skip and never relaunches them.

Fix

A foreground convoy up is a deliberate bring-up — the operator gesture that says "restore the fleet" — so at startup it clears the park AND zeroes the fast-fail counter for permanent members (regardless of prior fail count), giving each a fresh cap budget. The cap still re-accrues tick-to-tick within this supervisor's watch (the real crash-loop protection).

The --once shepherd cron does NOT un-park: it runs every few minutes, so un-parking there would relaunch a genuinely broken agent every tick — parking must stay durable for it.

Changes

  • flapping-cap.ts: clearParkForFreshSupervisor (pure) — the reset decision, unit-tested.
  • up.ts: the FRESH-SUPERVISOR UN-PARK startup pass (foreground only) — clears the on-disk park (removes the status tag, since updateTags merges) and seeds the in-memory classifier state so the first tick relaunches.
  • Tests: pure cases for the reset + a process-level proof — a parked, gone-but-recorded agent is UN-PARKED and RELAUNCHED by a fresh foreground up, while --once leaves it parked.

Full suite green (546 tests).

Part 2 of 4 of the decoupling-hardening task (decisive test #105 → parking fix → convoy restart → self-sever guard).

Note / possible follow-up

The un-park pass keys on isPermanent(s) (the strategy=permanent pty tag). A gone session that has lost that tag (e.g. stripped by a pty kill) would be treated as a worker and skipped by both this pass and the session loop, while the catalog pass defers to the session loop — a distinct "catalog says permanent, pty tag missing" gap. Flagging it separately rather than widening this PR's scope; happy to take it as a follow-up if it's worth closing.

🤖 Generated with Claude Code

https://claude.ai/code/session_014gbfntB6cu21sL4YBp21LF

…e the FULL fleet after an outage

Parking-recovery for the 2026-07-22 incident: a supervisor bring-up after a mass outage brought
back only part of the fleet; the rest stayed PARKED from a prior supervisor's give-up and had to
be hand-launched.

Root cause: `strategy.status=flapping` + the fast-fail counter PERSIST to a session's tags (the
on-disk supervision contract), so they outlive the supervisor that wrote them. An outage drives the
cap to its limit → the agents park → and a fresh `convoy up`, reading those stale tags, hits
classify's `isFlapping → skip` and never relaunches them.

Fix: a foreground `convoy up` is a DELIBERATE bring-up — the operator gesture that says "restore the
fleet" — so at startup it clears the park AND zeroes the fast-fail counter for permanent members
(regardless of prior fail count), giving each a fresh cap budget. The cap still re-accrues
tick-to-tick WITHIN this supervisor's watch (the real crash-loop protection). The `--once` shepherd
cron does NOT un-park: it runs every few minutes, so un-parking there would relaunch a genuinely
broken agent every tick — parking must stay durable for it.

- flapping-cap.ts: `clearParkForFreshSupervisor` (pure) — the reset decision, unit-tested.
- up.ts: the FRESH-SUPERVISOR UN-PARK startup pass (foreground only), which clears the on-disk park
  (removes the status tag — updateTags MERGES) and seeds the in-memory classifier state.
- Tests: pure cases for the reset + a process-level proof (a parked, gone-but-recorded agent is
  UN-PARKED and RELAUNCHED by a fresh foreground up, while `--once` leaves it parked).

Part 2 of 4 of the decoupling-hardening task.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014gbfntB6cu21sL4YBp21LF
@myobie
myobie merged commit 3b8eedd into main Jul 22, 2026
2 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant