Skip to content

Generate a flattened schema.sql snapshot for humans and agents#94

Merged
mbertschler merged 6 commits into
mainfrom
schema-snapshot
Jun 7, 2026
Merged

Generate a flattened schema.sql snapshot for humans and agents#94
mbertschler merged 6 commits into
mainfrom
schema-snapshot

Conversation

@mbertschler
Copy link
Copy Markdown
Owner

Why

Reading the current shape of the index meant mentally replaying the whole forward-only migration chain in store/migrations.go (the v5 baseline plus eight steps to v13). This adds a generated, checked-in store/schema.sql so humans and agents can see the v13 shape at a glance.

This mirrors the "flattened schema snapshot" pattern from another project (there: SHOW CREATE ALL TABLES on CockroachDB), adapted to squirrel's stack. The SQLite analogue is sqlite_master, generated in Go through squirrel's actual migrate path — no sqlite3 CLI dependency, and the snapshot is provably what the code produces.

What

  • store/schema.go(*Store).DumpSchema reads sqlite_master (tables, indexes, triggers) into a deterministic, table-grouped script; implicit PK/UNIQUE autoindexes are omitted (already implied by their table). canonicalSchemaSQL migrates a throwaway in-memory DB to SchemaVersion and prepends a generated-file header. Pure library — returns strings, no stdout.
  • store/schema.sql — the generated v13 snapshot. Shows the rebuilt files PK (folder_id, name, blake3), the ALTER … ADD COLUMN additions, the files_blake3_immutable trigger, and the uniq_files_live_per_path partial unique index.
  • store/schema_test.goTestSchemaSnapshot golden test; fails on drift, go test ./store -update-schema rewrites the file. Runs in the normal suite, so CI catches a stale snapshot with no extra wiring.
  • squirrel db schema — prints the DDL of a live database (which may sit at an older version), for inspecting a real index without trusting the checked-in file to match.
  • AGENTS.md — new "Schema & migrations" section documenting the source-of-truth chain, the snapshot, and the regenerate command.

Deliberately not changed

The migration engine keeps its current design — the snapshot is documentation only; databases are still created and migrated by applyV5 plus the registry, never from this file. squirrel already has the version-skew guard (store.go rejects a DB newer than the binary) and already exercises the full migration chain on every test Open, so no .sql files, down-migrations, or snapshot-seeded tests were introduced.

Reading the current shape of the index meant replaying the whole
forward-only migration chain in migrations.go (v5 baseline + 8 steps).
Add a generated, checked-in store/schema.sql so humans and agents can see
the v13 shape at a glance without that.

DumpSchema reads sqlite_master (tables, indexes, triggers) into a
deterministic, table-grouped script; canonicalSchemaSQL migrates a
throwaway in-memory DB through the real migrate path to SchemaVersion and
prepends a generated-file header. TestSchemaSnapshot compares the result
against the checked-in file and fails on drift; `go test ./store
-update-schema` rewrites it. The test runs in the normal suite, so CI
catches a stale snapshot with no extra wiring.

The snapshot is documentation only — databases are still created and
migrated by applyV5 plus the migration registry, never from this file.
Dumps the schema (tables, indexes, triggers) of whichever DB the usual
--db/config resolution opens, so an operator or agent can inspect a real
index — including one sitting at an older schema version — without
reading migrations.go or trusting the checked-in store/schema.sql to
match. Joins the existing db backup/check/restore cluster as an
inspection primitive.
Add a Schema & migrations section to AGENTS.md: the Go migration registry
is the source of truth, store/schema.sql is a generated snapshot for
reading the current shape, and `go test ./store -update-schema` refreshes
it after a schema change (the golden test fails on drift).
Copilot AI review requested due to automatic review settings June 7, 2026 12:58
Copy link
Copy Markdown

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 introduces a checked-in, generated SQLite schema snapshot (store/schema.sql) and supporting code so contributors (humans and agents) can quickly inspect the current schema shape without replaying the full forward-only migration chain in store/migrations.go.

Changes:

  • Add (*Store).DumpSchema plus an internal canonical snapshot generator used to produce a deterministic flattened DDL script from sqlite_master.
  • Add a golden test (TestSchemaSnapshot) to detect drift and a -update-schema flag to regenerate store/schema.sql.
  • Add squirrel db schema plus documentation in AGENTS.md describing the schema source-of-truth and regeneration workflow.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
store/schema.sql Generated flattened snapshot of the schema at version 13.
store/schema.go Implements schema dumping from sqlite_master and canonical snapshot generation.
store/schema_test.go Golden test to detect schema snapshot drift + regeneration flag.
cmd/squirrel/db.go Registers the new squirrel db schema subcommand.
cmd/squirrel/db_schema.go Implements squirrel db schema to print DDL for an opened database.
AGENTS.md Documents migrations as source-of-truth and how to regenerate the snapshot.

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

Comment thread store/schema.go Outdated
// (header + DDL) that store/schema.sql must match. It is the single source
// of truth shared by the golden test and its -update-schema rewrite path.
func canonicalSchemaSQL(ctx context.Context) (string, error) {
db, err := openSQLite(":memory:")
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good call. Routed the in-memory generation through buildDSN (925b910) so it carries the same pragmas as a production Open (foreign_keys, _txlock, …). The dumped DDL is unaffected by pragmas, so the snapshot stayed byte-identical and the golden test still passes.

Comment thread cmd/squirrel/db_schema.go Outdated
Comment on lines +11 to +14
// reads the shape of whichever DB the usual --db/config resolution opens,
// so an operator or agent can see what a real index actually looks like —
// including its current schema version — without replaying migrations.go
// or trusting the checked-in store/schema.sql to match an older file.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Correct — I over-claimed. Open runs the migration chain, so the DB is at the binary's SchemaVersion and the output is DDL-only (no version line). Reworded the comment in 7aa4a1c to describe the actual behavior.

Comment thread AGENTS.md Outdated
Comment on lines +30 to +32
`go test ./store -update-schema`; the `TestSchemaSnapshot` golden test fails
on drift, so CI catches a stale snapshot. `squirrel db schema` prints the DDL
of a live database (which may sit at an older version).
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 7aa4a1c — reworded so it no longer implies a pre-migration / older-version inspector; opening runs migrations first.

canonicalSchemaSQL opened the throwaway in-memory DB with a bare
":memory:" DSN, so the snapshot was generated without the pragmas a real
Open applies (foreign_keys, _txlock, …). Route it through buildDSN so
generation happens under the same constraints databases actually migrate
under. The dumped DDL is unchanged (pragmas don't affect sqlite_master),
so the golden snapshot is byte-identical.

Addresses Copilot review feedback on PR #94.
The doc comment and AGENTS.md claimed `db schema` shows a database "at an
older version" and "its current schema version", but openStore runs the
migration chain on open (bringing the DB to the binary's SchemaVersion)
and the output is DDL-only with no version line. Reword both to describe
the actual behavior: DDL of the opened database, after the normal
migration-on-open.

Addresses Copilot review feedback on PR #94.
The other db subcommands (backup/check/restore) have CLI tests; db
schema didn't. Add one that runs it against a fixture DB and asserts the
output carries the schema's core invariants — the volumes table, the
blake3-immutability trigger, and the live-row-per-path unique index.
@mbertschler mbertschler merged commit a37e42b into main Jun 7, 2026
2 checks passed
@mbertschler mbertschler deleted the schema-snapshot branch June 7, 2026 13:18
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