Skip to content

feat: add reconcile mode for declarative database seeding#31

Merged
mikkeldamsgaard merged 1 commit intomainfrom
feature/reconcile-seeding
Mar 11, 2026
Merged

feat: add reconcile mode for declarative database seeding#31
mikkeldamsgaard merged 1 commit intomainfrom
feature/reconcile-seeding

Conversation

@mikkeldamsgaard
Copy link
Contributor

Summary

  • Add mode: reconcile to seed sets for declarative seeding where the spec is the source of truth
  • On each run, initium detects changes via per-row tracking and content hashing, then converges the database: inserts new rows, updates changed rows, deletes removed rows
  • Add --dry-run flag to preview changes without modifying the database
  • Add --reconcile-all CLI flag to override all seed sets to reconcile mode for a single run
  • Auto-migrate existing tracking tables (adds content_hash column transparently)
  • Supports auto_id + @ref: resolution during reconciliation and across phases

Test plan

  • All 146 existing unit tests pass (backward compatibility)
  • 12 new reconciliation tests: initial apply, skip unchanged, update changed, add new, delete removed, auto_id+refs, cross-phase refs, dry-run, reconcile-all, mode validation, tracking table migration
  • cargo clippy — no warnings
  • cargo fmt -- --check — clean
  • Integration tests against real Postgres/MySQL (docker-compose)

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings March 11, 2026 22:28
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new declarative “reconcile” seeding mode to initium’s database seeder, enabling per-row change detection (via tracking + hashing), plus CLI flags to preview and override reconciliation behavior.

Changes:

  • Add mode: reconcile to seed set schema and validation, including tracking table migration for content_hash.
  • Implement reconciliation execution: compute seed-set hash, reconcile inserts/updates/deletes using per-row tracking, and support --dry-run + --reconcile-all.
  • Add hashing module + documentation/changelog updates for the new behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/seed/schema.rs Adds seed-set mode with validation for reconcile mode.
src/seed/mod.rs Extends seeding entrypoint to accept dry_run and reconcile_all.
src/seed/hash.rs Introduces deterministic seed-set content hashing for reconciliation.
src/seed/executor.rs Implements reconciliation execution logic, row tracking, dry-run behavior, and reconcile-all override.
src/seed/db.rs Extends DB trait + SQLite/Postgres/MySQL implementations for tracking migrations and row-level CRUD needed by reconciliation.
src/main.rs Adds CLI flags --dry-run and --reconcile-all and wires them into seeding.
docs/seeding.md Documents reconcile mode, row tracking, and new CLI flags.
CHANGELOG.md Adds an Unreleased entry describing reconcile mode and related features.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

mikkeldamsgaard added a commit that referenced this pull request Mar 11, 2026
1. hash.rs: Sort tables by (order, table_name) for deterministic hashing
   when multiple tables share the same order value.

2. db.rs (MySQL): Use SHA-256 generated column (row_key_hash) for the
   row tracking table primary key instead of row_key(255) prefix index,
   preventing key collisions for JSON keys exceeding 255 bytes.

3. docs/seeding.md: Clarify that reconcile mode only reconciles when the
   rendered spec changes (hash mismatch), and that out-of-band DB changes
   are not corrected until a spec change triggers reconciliation.

4. executor.rs: Add runtime guard for --reconcile-all — rejects seed sets
   where any table lacks unique_key, preventing wrong-row updates/deletes
   from identical row keys.

5. executor.rs: Skip hash-based fast path for seed sets containing @ref:
   expressions, since resolved reference targets can change without
   affecting the hash (e.g., upstream auto_id row reinserted).

6. executor.rs: Dry-run mode now treats @ref: as literals via
   resolve_value_dry_run(), preventing failures when refs haven't been
   populated (auto_id + refs within same seed set).

7. schema.rs: Reconcile validation now rejects empty/whitespace unique_key
   entries, reserved column names (_ref) in unique_key, and rows missing
   required unique_key columns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add reconcile mode (`mode: reconcile`) for seed sets, making seeding
declarative: the rendered spec becomes the source of truth, and initium
reconciles the database to match it whenever the spec changes. New rows
are inserted, changed rows are updated, and removed rows are deleted.

Key changes:
- Per-row tracking table (`initium_seed_rows`) for change detection
- Content hash on seed tracking table for fast skip optimization
- `--reconcile-all` CLI flag to override all seed sets to reconcile mode
- `--dry-run` CLI flag to preview changes without modifying the database
- Schema validation: reconcile requires unique_key on every table,
  validates rows contain all key columns, rejects reserved keys
- Runtime guard: --reconcile-all rejects tables missing unique_key
- Hash-skip disabled for seed sets with @ref: expressions to prevent
  stale foreign keys when upstream auto-generated IDs shift
- Dry-run treats @ref: as literals to avoid resolution failures
- MySQL row tracking uses SHA-256 generated column for PK (no collisions)
- CI summary job (`ci`) for branch ruleset status check
- Backward compatible: existing seed sets default to mode: once

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mikkeldamsgaard mikkeldamsgaard force-pushed the feature/reconcile-seeding branch from 72eccba to 2487164 Compare March 11, 2026 22:48
@mikkeldamsgaard mikkeldamsgaard merged commit 8e999b8 into main Mar 11, 2026
6 checks passed
@mikkeldamsgaard mikkeldamsgaard deleted the feature/reconcile-seeding branch March 11, 2026 22:50
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.

2 participants