Expand description
Migration runner — invoked by agentmux-srv migrate (a CLI subcommand,
and the now-dead agentmux-launcher::srv_spawner::run_migrate subprocess
path) and, separately, in-process at every srv boot via
run_pending_migrations.
Both paths report the SAME per-migration begin/done progress
(ApplyProgress) but over different channels: the CLI path emits
newline-delimited JSON to stdout (read by the dead subprocess path, kept
for that reason); run_pending_migrations emits agentmux_common:: srv_stderr’s AGENTMUXSRV-MIGRATION-BEGIN/-END lines to stderr — the
real, in-process boot path’s own protocol, so the launcher’s splash
screen can show live per-migration sub-rows instead of a silent clock.
Failures are written to <home>/logs/migration-error.log; the
process exits non-zero so the launcher can surface the error rather than
booting with a half-migrated data dir.
Structs§
- Applied
Ids - Which migration ids each tracking store records as applied, read through
a FALLIBLE path.
Errmeans the store exists but its tracking state could not be read (not a database, malformed table, locked): every migration of that scope then reportsVerifyOutcome::Errorinstead of being silently skipped as “unapplied” and letting the pass exit 0 — codex P1 on #3058, whichStore::migration_is_applied’sunwrap_or(false)would have caused. A store file that does not exist, or one predating thedb_migrationstable, has nothing recorded and isOk(empty). - Apply
Outcome 🔒 - What a batch did.
skipped= already applied at the time of the run. - Apply
Progress 🔒 - Per-migration progress hooks. Two real implementations: the CLI’s NDJSON
stdout lines (
run_migrate_command), and — since this PR —run_pending_migrations’sAGENTMUXSRV-MIGRATION-BEGIN/-ENDstderr lines, which the launcher turns into live splash sub-rows. Both also still get the unconditionaltracinglinesapply_pendingemits regardless of whether a progress hook is passed at all. - Doctor
Report - The complete migration doctor report for one data dir.
- Doctor
Row - One registry migration, in registry order.
- Doctor
Summary - Migration
Lock 🔒 - Held for the duration of a migration batch. Dropping it releases the lock.
- Verify
Record - One line of the verify report.
Enums§
- Pending
Count Error - Why a pending count could not be determined. Distinguished from “zero pending” on purpose: a caller deciding whether the schema is current must be able to tell “nothing to do” from “I could not tell”, because the safe reaction to each is opposite.
Constants§
- MIGRATION_
LOCK_ 🔒FILE - File name of the lock database, created beside the shared store.
- MIGRATION_
LOCK_ 🔒WAIT - How long a second runner waits for the first to finish before giving up.
Matches the launcher’s extended ESTART deadline for a long migration
batch (
srv_spawner.rs/sidecar.rs: 30 minutes). - VERIFY_
FAILED_ EXIT_ CODE - Exit code of
migrate --verifywhen at least one applied migration’s post-condition is a mismatch or its check errored. Distinct from 1 (a migration RUN failed) so a caller can tell “your data is inconsistent” from “the migrate command itself broke”, and from 2, which clap uses for a CLI usage error (a typoed flag must not read as a data finding — reagent P2 on #3058). See docs/exe-return-codes.md.
Functions§
- apply_
pending 🔒 - The locked migration batch — the ONE apply path, used by the daemon
(
run_pending_migrations) and byagentmux-srv migrate. Generic over the registry so the concurrency contract can be tested with a fake migration. - backup_
stores 🔒 - build_
doctor_ 🔒report - Assemble the report from an already-run verify pass, so
cmd_verifycan print the per-record NDJSON lines from the samerecordsthe report summarises rather than verifying twice. - cmd_
list 🔒 - cmd_
verify 🔒 - count_
pending_ migrations - Return the number of REGISTRY migrations that have not yet been applied, reporting 0 on any error so startup is never blocked.
- doctor_
inputs 🔒 - Paths and tracking state the doctor works from. Reads both tracking
stores through the fallible read-only path; never opens a
Store. - doctor_
report - The doctor report for
data_dir, against an explicit registry (tests pass fakes; production passesREGISTRY). Read-only. - doctor_
report_ for_ instance doctor_reportfor the running instance’s own registry and resolved shared store / home — whatGET /api/v1/muxspect/migrationsserves.Errwhen the shared root can’t be resolved at all (noAGENTMUX_SHARED_DIR, CI), the same condition under whichrun_migrate_commandtreats migrations as a no-op.- emit 🔒
- emit_
summary 🔒 - open_
readonly 🔒 - Open an existing SQLite file read-only.
Ok(None)when the file is absent — never creates one (the whole point of this path). - open_
stores_ 🔒for_ preview - Open the shared + channel stores the way every writer does (creating the
channel dir/db on a fresh install — see the comment inside). Shared by the
locked batch and the lock-free
--list/--dry-runpreviews. - pending_
of 🔒 - The migrations in
regswhose tracking store does not record them applied. - prune_
old_ 🔒backups - read_
applied_ 🔒ids SELECT id FROM db_migrationsthrough a read-only connection. A missing file or a missing table isOk(empty)— nothing was ever recorded there. Any other failure isErr, whichverify_appliedturns into anErroroutcome for every migration of that scope.- resolve_
home 🔒 - The true, unconditional
~/.agentmuxroot —MigrationContext.home. - run_
migrate_ command - Called from
main.rswhen themigratesubcommand is active. Returns the exit code (0 = success, 1 = failure, 3 =--verifyfound a mismatch — seeVERIFY_FAILED_EXIT_CODE). - run_
pending_ migrations - Apply all pending migrations in-process before srv opens its stores.
- table_
count 🔒 SELECT COUNT(*) FROM <table>on a (read-only) connection, treating a missing table as 0 rows — a store from before the table existed has nothing in it, which is exactly the answer a post-condition wants. Any other SQLite error is surfaced.tablemust be a literal identifier from the calling migration, never user input (it is interpolated, not bound).- tracking_
store 🔒 - Return the store that tracks applied state for a migration of the given scope. Global migrations → shared store; Channel migrations → channel store.
- try_
count_ pending_ migrations - Number of REGISTRY migrations not yet applied, or why that could not be determined.
- verify_
applied - Run
verify()for every migration inregswhose tracking store records it as applied. Generic over the registry slice so the harness can be tested with fakes; production passesREGISTRY. - verify_
event_ 🔒line - One
migration_verifyNDJSON line.detailgoes through serde_json so control characters (a multi-line SQLite error, say) cannot break the line-delimited stream a consumer tails (reagent P2 on #3058). - verify_
exit_ code - Exit code for a verify report: 0 unless any record is a mismatch or an
error.
NotVerifiableis not a failure — it is the honest default. - write_
error_ 🔒log