Skip to content

Tier dispatch on the run ledger + fleet registry & profile verbs (fleet §3.2/§6.3/§9) - #213

Merged
aarontrowbridge merged 3 commits into
mainfrom
wip/dispatch-ledger
Jul 25, 2026
Merged

Tier dispatch on the run ledger + fleet registry & profile verbs (fleet §3.2/§6.3/§9)#213
aarontrowbridge merged 3 commits into
mainfrom
wip/dispatch-ledger

Conversation

@aarontrowbridge

@aarontrowbridge aarontrowbridge commented Jul 25, 2026

Copy link
Copy Markdown
Member

Phase B of the agentic-substrate program (plan-20260724-133637), Tasks 13 + 15. #212 has merged, so this is now rebased onto main and no longer stacked.

What's here

  • dispatch ledger stanza + tier-dispatch aggregator (ledger_dispatch.ts): $m^*(s) = \arg\min_m c_m / p_m(s)$ over first-attempt samples, exposed as amico ledger dispatch.
  • amico profile resolve (profile_verb.ts) — resolves a capability profile to an effective {model, variant, permissions, gates}.
  • Fleet registry state machine + amico fleet verbs (fleet_registry.ts, fleet_verb.ts) — fleet §9 step 2's third verb family.
  • One rubric, not two: K_MIN/N_HIGH/IQR_TIGHT/IQR_WIDE and numericStat are imported from ledger_query.ts, never re-declared.

This work rides the run ledger rather than building a second store. An earlier revision of the design did specify a parallel amico telemetry log|fit; that was caught and deleted in favour of a 7th dispatch ledger kind.

The load-bearing rule: sim and hw never pool

Simulated rows are admissible here (opt-in --include-simulated) — unlike ledger_query.ts, whose source === "user" filter is untouched — because tier dispatch asks a different question: can model $m$ author correct work of type $s$, which a fit-recovery gate against known ground truth does test. What it cannot test is robustness to real noise, drift, and unexpected resonances, so a simulated pass is necessary but not sufficient evidence of hardware competence.

So both matchers are lane-scoped, not just the fallback. An experiment work_id is the same string on a simulator and on a board ("t1-fit" either way), so an unscoped primary key would pool the two difficulty populations before the fallback was ever consulted — the same defect class as structure_hash's goal-blindness that #212's e164855 fixed. Asserted by the "the sim/hw boundary" block in ledger_dispatch.test.ts.

No transfer claim. Whether simulated pass-rate predicts hardware pass-rate is an open empirical question; nothing here assumes it.

Notes for the reviewer

Rebasing onto #212 produced one textual conflict (a usage string, both sides added a clause) and one auto-merge worth a second look: ledger_query.ts, where #212 added goal to primaryMatch/fallbackMatch while this branch widens four constants and numericStat to exports. Verified orthogonal — the export widening carries no semantic change, and goal keying is intact on both matchers.

ba09f35 is a self-contained fix for a raw NUL byte that made ledger_dispatch.ts invisible to grep/rg. Git diffed it as text (its binary sniff covers only the first 8000 bytes; the NUL sat at 17679), so review could not have caught it — only code search could. See that commit message.

Verification

Re-run after the rebase onto merged main, because the tree genuinely changed — main's telemetry work and these ledger changes had not been exercised together before:

Suite Result
amico-run 640 pass
schema 99 pass
extension 771 pass, 5 skipped
tsc --noEmit clean, all 3 packages

One caveat on reading a local run: vault_verb.test.ts fails on a cold dist/ because tests that spawn the built binary race esbuild. Warm the bundle and it is 640/640. CI builds before testing, so CI is immune.

🤖 Generated with Claude Code

aarontrowbridge and others added 3 commits July 25, 2026 16:20
…run): profile resolve

Fleet spec §6.3 Rev 5 + §2/§3.1; agentic-substrate plan Task 13.

Tier dispatch RIDES the shipped run ledger instead of building a second store:
`dispatch` is the 7th LedgerRecord kind, so validate-on-append covers it for free
via the `ledger-record` schema's new stanza. No `amico telemetry` verb exists —
that name is the solve-log classifier.

- ledger.ts: DispatchRecord + the closed TASK_TYPES taxonomy (the sim/hw axis is
  carried there, so a lane-less `experiment` row cannot exist).
- ledger_dispatch.ts: primary key `work_id x model x variant`, fallback key
  `task_type x model x variant` below K_MIN, first-attempt-only p_m(s),
  m*(s) = argmin c_m/p_m(s), escalation ladder with the same-model-id rung skip,
  and the four confidence bands IMPORTED from ledger_query (one rubric, not two).
  Simulated rows are admissible opt-in; ledger_query's source==="user" filter is
  untouched. THE fallback never crosses the sim/hw boundary: a sparse
  experiment-hw cell relaxes within hardware rows only or falls back to the
  ladder, so simulated pass-rates can never route real board time.
- profile_verb.ts: `amico profile resolve` — schema validation ported from the
  profile lint, entitlement-filtered skills, the spool-up composition rule (a
  preset's base is ignored; a chat is always the resident shell), the
  verifiability rule, and the lossy Claude-Code tool-set preview with `device`
  excluded from the path-rw test.
- ledger_verb.ts: `dispatch` subcommand; verbs.ts: `profile` registered.

Tests: amico-run 374 -> 488 passing; @amicode/schema 92 -> 99 passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
….2, §9 step 2)

Agentic-substrate plan Task 15. Lands the pure module + CLI surface that fleet
steps 4-5 consume, satisfying §8's CI requirement ("the §3.2 state machine as a
pure module with exhaustive transition tests; one-file-per-session TOML records
round-trip") without touching the fork or the extension.

DELIBERATE CONTRAST WITH THE LEDGER, kept: ledger.ts is an append-only immutable
JSONL event log; this registry is mutable per-session TOML state. They share only
what the Rev 4.1 delta review scoped — record I/O + the no-null conventions,
single-writer discipline, adoption/rescan, and the pid-liveness probe. The state
models are NOT forced through one function.

- fleet_registry.ts: the Rev 3 transition table as a total, side-effect-free
  function over 6 states x 9 events, with the writer handoff (extension holds a
  `spooling` record; the harness holds everything after `spooling --inject-->
  running`), stop-from-any-live-state, the `blocked --unblock--> running` budget
  re-arm as the ONE re-arming edge, `killed` terminal, and `respooled_to` stamped
  only on a respool-kill (supplying it on any other edge is rejected). Records are
  one TOML file per session at $AMICO_FLEET_DIR (default ~/.amico/ops/fleet),
  written tmp+rename; no nulls anywhere, empty string / 0 for absent, and an
  explicit null is a validation error. USER ACTIONS are mapped to events
  separately (steerEventFor/stopEventFor/retierEventFor) because the same button
  is a different edge in a different state: a stop during triage is `cancel`,
  applied by the extension.
- fleet_verb.ts: `amico fleet list|status` read verbs over a derived view;
  `steer|stop|re-tier` ENQUEUE SIGNAL FILES under <session_id>.signal.d/ and never
  touch a record, which is what lets a CLI operate live sessions without becoming
  a second writer; `sweep` is the one exception that writes and is pid-liveness
  guarded — a live pid, an unknown pid (0), and a foreign-host record are never
  marked crashed. Sweep applies its transition through the same pure machine, so
  an orphaned `blocked` record is reported rather than laundered into a crash.
  re-tier reuses the shipped escalation ladder for its direction test: upward is a
  next-step-boundary stamp change, downward on a plan-walking session is a replan
  costing one replan-budget unit, and a resident re-tier is a respool.
- verbs.ts: `fleet` registered alongside `profile`, so CLI dispatch, the MCP
  facade, and --help come for free.

Found and fixed while testing: signal ordering. An epoch-ms-only filename prefix
ties for a same-millisecond burst and then sorts by ACTION NAME, silently
reordering steer -> re-tier -> stop into re-tier -> steer -> stop. Names now carry
a fixed-width per-directory sequence, with a regression test.

Tests: amico-run 488 -> 638 passing (113 registry incl. all 54 state x event cells
as individual cases, 37 verb); @amicode/schema 99 unchanged; typecheck clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`aggregateDispatch` builds its per-cell Map key as `${model}<NUL>${variant}` to
make a collision-proof composite of two free-form strings. That separator was
written as a RAW 0x00 byte in the source rather than the `\x00` escape, which
made grep/ripgrep classify ledger_dispatch.ts as binary and silently report
zero matches for every pattern in the file — including `laneOf`, in the module
where the sim/hw lane boundary is the load-bearing rule.

Git still diffed it as text (its binary sniff only covers the first 8000 bytes;
the NUL sat at 17679), so the corruption was invisible in review and visible
only to code search — the worse of the two failure modes, since it is agents
and future readers who search.

The escape is behaviourally identical: JS reads `\x00` in a template literal as
U+0000, and the key is write-only (values carry the structured {model, variant},
nothing splits on the separator). Verified: 0 raw NULs remain in the branch, and
`rg laneOf` now returns all 5 sites.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aarontrowbridge
aarontrowbridge changed the base branch from wip/typed-specs-amicode to main July 25, 2026 20:21
@aarontrowbridge
aarontrowbridge marked this pull request as ready for review July 25, 2026 20:21
@aarontrowbridge
aarontrowbridge merged commit c4c9719 into main Jul 25, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant