Skip to content

docs: the chain guide, migrating from alembic, and a README that shows the whole tool - #7

Merged
juanmicl merged 11 commits into
mainfrom
docs/b1-release
Sep 2, 2026
Merged

docs: the chain guide, migrating from alembic, and a README that shows the whole tool#7
juanmicl merged 11 commits into
mainfrom
docs/b1-release

Conversation

@juanmicl

@juanmicl juanmicl commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

The documentation release: the front page now represents the whole tool, and the two workflows have complete guides. Docs-only — zero src/tests changes (git diff main..HEAD --stat touches README.md, CHANGELOG.md, docs/ only).

New: docs/the-chain.md

The chain guide — the three verbs (revision / migrate / stamp), the file format with a real generated example, migrate's gates (destructive header gate, checksum gate with the stamp --force escape, strict order, shared bounded advisory lock, per-file budgets), CONCURRENTLY replay semantics (whole-text fast path dollar-quote safe; label-delimited plain-first hybrid for CONCURRENTLY files), the data-backfill workflow (append a -- op N [raw_sql] UPDATE before first apply: schema change and data change ship as one reviewable file), the hand-authored 0000_extensions.sql pattern (fresh environments get PostGIS/TimescaleDB before any generated file; existing ones adopt with stamp; IF NOT EXISTS keeps re-runs safe) — the pattern was derived and verified live against scratch databases (migrate applies, stamp never executes, next revision numbers 0001, end-to-end revision→migrate→check clean), the registry, and an honest-limitations list.

New: docs/migrating-from-alembic.md

The refugee recipe, no automated conversion stated up front: command map (autogenerate→revision, upgrade→migrate, stamp→stamp, downgrade→none, forward-only), then four phases — observe parity (alembic_version pruned from every diff, exit 0/2/3, --exclude acceptance for legacy objects), baseline the empty chain (+ 0000_extensions), run both then switch (coexistence forever, the old chain becomes an archive), and a scratch-DB equivalence proof (baseline dump → migrate head-to-toe → check exit 0).

README rewrite

All six verbs on the front page: a "When you want files: the chain" section after the push-style pitch, the full exit-codes table (per cli.py), a per-verb flags reference, the inherited-database story (first check drift, exit 3, --exclude/--allow-destructive escape hatches), schema-scoping facts (search_path default, extension-owned schemas, registry always in public, pruned), the asyncpg translation note, an honest comparison row ("migration files: optional"), and the stale roadmap lines removed.

CHANGELOG

New [Unreleased] Added bullet for the docs; the 0.5.0 limitation wording made self-contained — "(pinned chain spec §7)" replaced with plain wording (no references to untracked specs anywhere in public surface).

Verification

  • 166 passed, 1 xfailed unchanged (docs-only confirmed); ruff / ty clean
  • 0000_extensions pattern verified live on scratch DBs (evidence in 8cfb9ca's commit body)
  • Humanizer pass over all new prose (zero em/en-dashes, house style matched to the migra guide)
  • Full accuracy review against the code (every command, flag, default, exit code, format claim, semantic claim vs cli.py/api.py/chain/) — verdict approve; both nits folded in as 3441822

Release plan

On merge, cut v0.5.1 (docs-only patch) so the PyPI description picks up the new README.

New docs/the-chain.md: the two-workflow model (push vs chain), the
three verbs (revision/migrate/stamp), the file format with a real
generated example, migrate's gates, CONCURRENTLY replay semantics,
the backfill workflow, the hand-authored 0000_extensions.sql pattern,
the public.sqlpush_versions registry, and an honest-limitations
section.

The 0000_extensions pattern was verified live against a scratch DB on
the dev server (localhost:5433, timescaledb-ha:pg17), never against
sqlpush_test:

- migrate on an empty scratch DB applied a hand-authored
  0000_extensions.sql (header `-- sqlpush: revision=0000 risk=SAFE`,
  one labeled op, CREATE EXTENSION IF NOT EXISTS postgis +
  timescaledb): applied: 1, exit 0; both extensions present in
  pg_extension afterwards; registry row ('0000_extensions.sql',
  sha256) recorded. This also proves parse accepts the hand-authored
  header/op-label form.
- Idempotency: with the registry row deleted, migrate re-EXECUTED the
  file cleanly (IF NOT EXISTS); with the row present, it skipped.
- stamp on a second fresh scratch DB: applied: 0, skipped
  (registered): 1, registry row present, postgis NOT installed ->
  nothing was executed. (timescaledb appears on every new DB on this
  image via template1 preload; postgis does not, so it is the clean
  indicator.)
- Numbering after 0000: next_revision_id on a dir containing only
  0000 returns 0001; a real `sqlpush revision` run against the
  scratch DB (at chain head) generated 0001_create_users.sql with
  header revision=0001.
- End to end: migrate applied 0001 (0000 skipped), then `sqlpush
  check` against the same DB exited 0.
The refugee recipe, honest about what does not exist: no automated
conversion of alembic revisions, the old chain stays untouched
(alembic_version is pruned from every diff forever). Four phases:
observe parity first (check + --exclude for legacy objects), baseline
the empty chain (0000_extensions link), run both then switch, and a
scratch-DB equivalence replay. Command map included; downgrade is
none, forward-only, stated plainly.
…-DB story

Surface the whole tool: a "When you want files: the chain" section
after the push-style pitch (three chain verbs + link to the guide),
the comparison row now honest (files optional), and guides links for
the chain, alembic and migra. Exit codes table covers all six verbs;
a compact per-verb flags table folds in the lock/timeout/concurrency
knobs. New "An inherited database" section explains first-check drift
and the --exclude / --allow-destructive escape hatches. Scoping
paragraph under How it works (extension schemas, public registry,
alembic_version pruning). asyncpg translation note in the lifespan
section. Roadmap heading de-versioned; pitch softened to "no
migration files required".
Replace the internal spec reference in the released 0.5.0 Known
limitations section with wording that stands alone (the trade-off is
named, not cited). Add the [Unreleased] entry for the two guides and
the README's six-verb documentation surface.
@juanmicl
juanmicl merged commit 19fef66 into main Sep 2, 2026
7 checks passed
@juanmicl
juanmicl deleted the docs/b1-release branch September 2, 2026 21:29
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.

1 participant