ADR-090: Periodic Housekeeping — Naming as a Recurring Operational Task

Field Value
Decision ID ADR-090
Initiative unsorry — keeping the model→Pokémon registry complete as the distribution grows
Proposed By unsorry maintainers
Date 2026-06-23
Status Proposed

Context

ADR-083 made model→Pokémon naming the swarm’s first operational task: swarm/housekeeping.sh is the first thing run.sh runs, and it blocks — no proving/dispatch/sourcing starts until every model in the leaderboard distribution (docs/metrics/leaderboard-ui.jsonmodels[]) has a Pokémon in docs/metrics/model-registry.json.

That guarantee is enforced only at launcher startup. The model distribution is dynamic — a new provider/model cohort can appear at any time (a new provider, a new model, or a newly-split deterministic-tactic label). A long-lived run.sh:

  1. clears housekeeping once, then drops into the foreground prover loop (supervise.sh --prove), which never returns to housekeeping; and
  2. re-execs only when swarm/run.sh’s own blob changes on main (self_update_to_latestrun_harness_stale). The constant stream of prove(...) merges advances main but leaves the launcher blob unchanged, so there is no re-exec and no second housekeeping pass.

The scheduled queue-dispatcher backstop does no naming. So a cohort that first appears after a node has started proving stays unnamed indefinitely on that node.

Observed (2026-06-23): lean / ring (the deterministic Lean ring-tactic class, 391 proofs) first entered the distribution on 23 Jun (54b811e2), one day after the 22 Jun naming batch that named the other 13 models (and after swarm/run.sh/housekeeping.sh themselves last changed, 22 Jun). Running nodes never re-ran housekeeping, so lean / ring is the sole entry on python3 -m tools.model_registry unassigned, with no in-flight PR. The ADR-083 promise — “every model that appears in the distribution is assigned a Pokémon” — silently degraded from an invariant to a startup snapshot.

WH(Y) Decision Statement

In the context of model→Pokémon naming being a startup-only gate (ADR-083) over a dynamic model distribution,

facing new cohorts that appear mid-run never being named until a launcher restart or a change to swarm/run.sh itself (observed: lean / ring, unnamed for a day on running nodes),

we decided for making housekeeping a recurring operational task — a fourth run.sh arm that re-invokes swarm/housekeeping.sh on an interval, mirroring the demand-driven dispatcher and sourcer loops, default-on whenever the startup gate is on and excluded in fork mode,

and neglected (a) the status quo of relying on run.sh re-exec/restart — leaves an unbounded-in-time window where a model is unnamed and depends on an unrelated launcher edit; (b) a scheduled GitHub Actions naming job — the naming agent is a local claude -p with WebSearch/WebFetch, so it would need an Anthropic key and tool access in CI, a trust/secret surface we deliberately keep out of Actions; (c) triggering naming from the leaderboard-refresh job — couples two subsystems and still leaves locally-run nodes dependent on a server job,

to achieve the ADR-083 completeness guarantee continuously — a new model is named within one interval, with no restart — while reusing the already-idempotent, concurrency-safe housekeeping.sh drain loop unchanged,

accepting that the arm spends a periodic tools.model_registry unassigned check (cheap; it no-ops in well under a second when nothing is unassigned) and, only when a genuinely new model appears, one claude -p research call — and that, like the sourcer (ADR-085), it must run in an isolated worktree because it mutates the checkout.

Decision

Implementation: SPEC-090-A. Tracking issue: filed on agenticsnz/unsorry (companion to this ADR).

Consequences