Module def_migrate

Module def_migrate 

Source
Expand description

Global migration: backfill user-agent DEFINITIONS (with their content + skills) from every channel’s per-version objects.db — and every dev/ branch DB — into the GLOBAL definition store, so EXISTING agents become cross-channel without waiting for the next edit. Read-only on every scanned SQLite.

Version-gated, re-runnable marker (not strictly one-shot): the .migrated_definitions marker in the store root records the MIGRATION_VERSION that last ran. A marker older than the current version — including the legacy migrated text, which parses as version 0 — re-runs the scan ONCE, so users whose earlier pass was incomplete recover automatically on the next launch. Bump MIGRATION_VERSION whenever the scan logic changes to trigger a one-time re-run for everyone.

On a re-run, an agent already in the global store is refreshed only when the scanned copy is strictly fresher than the global record (so a broken earlier pass’s stale/content-less copy is corrected) — never downgraded below what the live write-mirror has since advanced, and never resurrected if tombstoned. (codex P1 / reagent P2 #1391.)

Cross-channel agent persistence, P0.2d (docs/specs/SPEC_CROSS_CHANNEL_AGENT_PERSISTENCE_2026-06-13.md).

Resilience mirrors scripts/import-agents.sh: a single unreadable / locked / old-schema objects.db is skipped with a warning, never aborting the pass. The marker is written after a pass even if some DBs were skipped — a transiently-skipped DB’s agents still go global on their next edit via the live write-mirror (P0.2b), and a future MIGRATION_VERSION bump re-scans everything — so nothing is permanently lost and the migration never loops forever on a permanent old-schema failure.

Structs§

DefMigrateStats
Outcome stats — surfaced in the srv log.

Constants§

DEF_COLUMNS 🔒
db_agent_definitions columns in the order the row mapper expects, paired with a default SQL literal used when a column is absent on an older DB. Substituting <default> AS <col> keeps the SELECT’s column count + order fixed (so index-based row.get stays valid) while tolerating schema drift.
MARKER 🔒
MIGRATION_VERSION 🔒
Migration-logic version. Bump whenever the scan changes (new roots, schema handling, etc.) so existing users re-run the migration ONCE: the marker stores this number; a marker older than this re-runs. The pre-v2 marker held the literal text migrated, which parses as version 0 → re-runs, recovering everyone whose first pass was incomplete.

Functions§

collect_scan_dbs 🔒
Every …/data/db/objects.db under home/channels/*/versions/* AND home/dev/<branch>[/<sub>]. The instance migration scans both (migrate.rs::enumerate_sources); the definition migration must too, or dev-branch agents (e.g. agents created via task dev) never go global.
dir_subdirs 🔒
is_missing_table 🔒
True iff the error is SQLite “no such table” (a pre-v2 DB missing db_agent_content / db_agent_skills) — the only failure we treat as “no rows” rather than a reason to skip the DB.
marker_version 🔒
Migration version recorded in the marker; 0 when absent or unparseable (the legacy migrated text → 0 → re-run).
max_ts 🔒
MAX(col) over a per-agent table; 0 when the table is missing (pre-v2) or there are no rows. Other errors propagate (→ DB skipped).
migrate_definitions_global_once
Scan every channel AND dev-branch objects.db under home for user agents and backfill them into the global definition store. Re-runs once per MIGRATION_VERSION bump (marker in store.root()); read-only on every scanned SQLite, and tolerant of older schemas (missing columns).
present_columns 🔒
Column names present in table (empty set if the table doesn’t exist — PRAGMA table_info on a missing table yields no rows, not an error).
read_content 🔒
read_skills 🔒
read_user_definitions 🔒
Read all is_seeded=0 definitions from db with their content + skills, each paired with a freshness timestamp for cross-copy winner selection.
tolerate_missing_table 🔒
write_marker 🔒