بنقرة واحدة
breaking-schema-changes
How to safely plan and execute a breaking schema migration in a Rust SQLite codebase
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
How to safely plan and execute a breaking schema migration in a Rust SQLite codebase
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Resolve knowledge gaps: fetch unresolved gaps, assess sensitivity, generate research queries, ingest findings, and close gaps with a resolution slug.
Interrupt-driven alerts: detect and surface new contradictions, stale pages, resolved gaps, and embedding drift. Priority-classified with deduplication.
Ingest meeting notes, articles, documents, and conversations into Quaid. Handles idempotent ingestion for exact-byte duplicates and vault-backed sync.
Keep the brain healthy: detect and resolve contradictions via the correction / supersede workflow, validate referential integrity, triage knowledge gaps, find orphaned pages, and compact the database.
Answer questions from the brain using FTS5 + semantic search + structured queries. Synthesize across multiple pages. Cite sources.
Agent-guided binary upgrades: version check, channel detection, download via install.sh (or manual asset fetch + SHA-256 verify), and post-upgrade validation.
| name | breaking-schema-changes |
| description | How to safely plan and execute a breaking schema migration in a Rust SQLite codebase |
| domain | architecture, schema migration, execution planning |
| confidence | high |
| source | earned — vault-sync-engine breakdown (2026-04-22) |
Applies when a new OpenSpec change introduces a breaking DDL change (schema version bump, table drops, column type changes, FK changes) in a Rust binary that embeds its schema via include_str!("schema.sql"). GigaBrain uses rusqlite with SCHEMA_VERSION constant in db.rs. The pattern applies to any SQLite-backed Rust project with the same structure.
Never commit a schema DDL change alone. The schema is include_str!() in db.rs — as soon as it changes, every test that calls db::open() or creates a test DB will fail. The only valid commit is one that simultaneously:
src/schema.sql (new DDL)src/core/db.rs SCHEMA_VERSION constantcargo test passes in the same commitImplement db::open() version detection as the very first task. On detecting an older schema version, return an explicit error with re-init instructions. Users must be directed to an escape route (export, then re-init) BEFORE the first PR that bumps SCHEMA_VERSION is merged.
Before writing any new code, enumerate every file that does INSERT/SELECT/UPDATE on tables with breaking changes (pages, links, assertions in the vault-sync case). Use grep to find them. This is the integration collision list. Fix them in the same Wave as the schema change, not afterward.
When a new module replaces an old one (e.g., reconciler.rs replacing migrate.rs::import_dir()), the new module must be complete and tested before the old one is removed. Never merge a PR that removes the only functional ingest/write/sync path while the replacement is still incomplete.
When a schema change tightens a data invariant (e.g., "exactly one is_active=1 row per page"), add a post-ingest assertion in tests (SELECT COUNT(*) WHERE is_active=1 = 1) and do an explicit callsite audit of every existing INSERT path before writing new code. Existing code may not respect the new invariant.
Changing a unique key from UNIQUE(slug) to UNIQUE(collection_id, slug) cascades to every query, index hint, and ORM-style struct that assumes the old uniqueness contract. Map all affected code before starting.
When schema bootstrap and runtime metadata hydration are separate steps, matching the seeded version number is necessary but not sufficient. Add a regression for the exact crash-partial state that can exist between those steps (for Quaid: current embedded DDL + legacy config.version written, but quaid_config still empty) and prove the normal open path succeeds afterward. A preflight-only test can hide a real reopen failure.
Only auto-repair that window when the database is still bootstrap-fresh (default collection only, no user rows in mutable tables). If embedding_models already has an active row, treat that registry row as the authoritative model hint for reconstructing quaid_config; never fall back to the legacy config.embedding_model value once model selection became runtime-configurable.
# Find all files that INSERT into pages:
rg "INSERT.*INTO.*pages" src/ --type rust
# Find all files that reference SCHEMA_VERSION:
rg "SCHEMA_VERSION" src/ --type rust
# Find all files that use page slug as unique identifier:
rg "\.slug" src/ --type rust | head -50