090416f05e
Move subsystem mechanics (migrations, thesis gate, redaction, ingest, email, packaging) out of AGENTS.md into docs/guides/<topic>.md, each scoped by paths: frontmatter and symlinked from .claude/rules/ so Claude Code lazy-loads them. AGENTS.md keeps whole-repo facts and universal guardrails plus a one-line index per guide. Fix the inaccurate ".claude/ is gitignored" note — it is tracked.
1.6 KiB
1.6 KiB
paths
| paths | |||
|---|---|---|---|
|
Migrations & seeders
Read this before adding or editing a schema migration or a one-time seed/backfill.
How they run
- Migrations apply automatically at startup via
backend/core_migrations.py, readingbackend/migrations/NNNN_*.sqlin order and tracking applied files in aschema_migrationsledger. - One-time seeds/backfills live in
backend/thesis_seed.py(theensure_*functions), wired intoserver.init_db()and run on every boot.
Rules
- Additive + reversible only. Numbered
NNNN_*.sqlwith a pairedNNNN_*.down.sql— ship the.down.sqlwith every new migration. SQLiteALTERis add-column / rename only; no drop-column, no type change. - Seeds/backfills must be idempotent via
interaction_logsentinels (theensure_*pattern) — safe to re-run on every boot. - Make migrations/seeders deployment-state-invariant. Target rows structurally, not by transient text the same change mutates; capture prior state so a revert is exact.
- Learned the hard way: matching old nodes by a body string the same changeset deleted broke fresh DBs. A migration must produce the same end state whether the box is empty, mid-version, or fully seeded.
- Soft-delete only —
deleted_atand/orstatus='retired'; never hard-delete CRM records or thesis history.
Verify before shipping
python3 -m py_compilethe edited Python.- For any DB logic, run the change against a copy of
data/crm.db, never production. Confirm the paired.down.sqlcleanly reverts.