Skip to content

fix(doctor): report every migration history serve would refuse - #144

Merged
TusanHomichi merged 3 commits into
mainfrom
claude/138-doctor-checksums
Oct 15, 2026
Merged

TusanHomichi merged 3 commits into
mainfrom
claude/138-doctor-checksums

Conversation

@TusanHomichi

Copy link
Copy Markdown
Member

Primary Issue

Closes #138

Problem And Outcome

doctor compared migrations by version only. A database whose stored checksum had changed, or whose migration was recorded as unsuccessful, read ok, while serve refused to start on it: migration 16 was previously applied but has been modified. The reverse mismatch also existed: doctor reported fail on pending migrations, which serve applies by itself, so running doctor between installing a new version and restarting looked like a failure.

After merge, doctor's migration verdict matches serve in both directions:

  • A refusal is a fail. That covers a version this build does not know, a row recorded as unsuccessful, or a checksum that differs from this build's. The finding names the version and says what to do.
  • Pending migrations, and a database with no history yet, are a warn that says what the service will do on its next start.

Changes

  • storage.rs: one owning judgment of an applied history, RefusedHistory with Newer, Unfinished and Changed, plus migration_history(). The refusal list was derived from sqlx-core 0.9's Migrator::run_direct and validate_applied_migrations. Startup's existing newer-database check reads through it, with byte-identical wording.
  • doctor.rs: check_migrations reports each refusal as a fail, and pending or no-history as a warn. It runs SELECTs only, on the existing read-only connection, as ADR 0016 requires. Warnings do not change the exit status; only a fail does.
  • Docs: README, docs/operations.md (only named-migration lines mean the service refuses), docs/install.md, and a CHANGELOG Fixed entry.

Scope

Verification

  • Candidate revision: cab75e787f1a4c9d2559dd011756f1272568d5a4 (tree 71bf58df).
  • Local full proof (verifier role): scripts/proof.py passed all 7 gates in 501 s.
    • 302 Rust tests passed, 0 failed.
    • Browser: 62 expected, 0 unexpected, 0 flaky, 0 skipped, on system Chrome 155.
    • Receipt sha256 99d8216b…, archived on the maintainer machine.
  • New tests/doctor_migrations.rs runs the real binary for both doctor and serve on each case. Every case failed against the pre-change code.
    • Refusals, where doctor fails and serve refuses the same database:
      • changed checksum;
      • success = 0;
      • unknown version;
      • two problems at once.
    • Warnings, where doctor warns and exits 0 and serve starts:
      • one migration behind: serve also takes the pre-migration backup, after which doctor reports ok;
      • no history.
    • Positive control: an intact database.
    • A settings pin covers the sqlx assumptions this diagnosis relies on.
  • tests/doctor_read_only.rs: with a changed checksum in a live writer's WAL, the database and WAL stay byte-identical. That test caught a deliberately injected doctor write in review. A separate test covers diagnosis in a read-only directory.
  • Listed the exact verification commands run below
  • Added or updated tests when behavior changed
  • Added or updated an ADR when a durable decision changed (ADR 0016's contract unchanged)
  • All fixtures and examples are invented; no real agency data
- scripts/check-guidance-names.sh
- web/: npm ci, npm run check, npm run build
- cargo fmt --check
- cargo clippy --workspace --all-targets -- -D warnings
- cargo test --workspace
- cargo build -p consolebook-server
- web/: npm run e2e (system Google Chrome 155)

Review And Merge Notes

  • Independent review (reviewer role, frozen worktree at 249b2a3): 0 blocking.
    • It confirmed against the sqlx source that no history makes doctor say ok while serve refuses.
    • It confirmed startup decisions and wording are unchanged.
    • Its should-fix was the inverse mismatch: pending and no-history reported as fail. The integrator decided on parity in both directions, implemented in cab75e7 with parity tests, along with the nits: message wording, a test's stated claim, an ordering comment, a zombie process, and a README wrap.
  • Delta 249b2a3..cab75e7: self-reviewed by the integrator.
  • Authority: the maintainer selected doctor: compare stored migration checksums, not just versions #138 on 2026-10-15; standing PR permission.
  • Operator impact:
    • doctor now catches a database serve would refuse.
    • Pending migrations warn instead of failing, so the exit code is 0.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T22:34:08.742366Z 8d403e5 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cab75e787f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/consolebook-server/src/doctor.rs
Comment thread crates/consolebook-server/src/doctor.rs
TusanHomichi and others added 3 commits October 15, 2026 15:26
doctor compared only migration versions, so a changed checksum or a
migration recorded as failed read "ok" while serve refused to start. One
storage function now judges an applied history the way startup does (a
version this build does not know, a row recorded as unfinished, a checksum
that differs from this build's), in sqlx 0.9's order, and doctor reports
each refusal as a fail naming the version and what to do, read-only as ADR
0016 requires. Startup's own newer-database check reads through the same
function, so the wording is defined once.

doctor_migrations runs the real binary: for each condition doctor fails
and serve refuses the same database, with an intact database as the
positive control; doctor_read_only proves the database and its sidecars
stay byte-identical while doctor reports a changed checksum.

Closes #138

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
doctor now matches serve in both directions: a refusal is a fail, while
pending migrations and a database with no migration history yet are a
warning that says what the service does on its next start (take a
validated backup, then migrate), so running doctor between installing a
new version and restarting no longer exits non-zero. Parity tests run the
real binary: one migration behind warns, serve starts, takes the
pre-migration backup, and doctor then reports ok.

Review follow-ups: the Changed and Unfinished messages say what is known
and where to go (docs/install.md, Upgrading); the read-only-directory test
claims what it proves; the ordering comment is accurate; a timed-out serve
is reaped; the operations guide says only named-migration lines mean the
service will refuse.

Refs #138

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ord ADR 0029

A database that holds tables but has no migration history (the table
dropped or emptied) now reads as a refusal: doctor fails and startup refuses
it before sqlx tries migration 1 over the existing tables, both through the
same storage judgment (MissingHistory). Only a pristine database, with no
schema objects of its own, keeps the "no migration history yet" warning.
Parity tests run the real binary for the dropped and emptied cases and for
the pristine empty-table case.

ADR 0029 records the verdict contract operators and monitoring read from
doctor's exit status: fail means serve will refuse, warn means the service
acts on its next start, ok means nothing is pending or refused. ADR 0016
and the task index link it.

Refs #138

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TusanHomichi
TusanHomichi force-pushed the claude/138-doctor-checksums branch from cab75e7 to 8d403e5 Compare October 15, 2026 22:31
@TusanHomichi

Copy link
Copy Markdown
Member Author

Rebased onto main 1dfb945 (#145). Codex P1: ADR 0029. Codex P2: MissingHistory refusal. Both are in 8d403e5.

Local full proof on 8d403e5c3f9298a21baf0cc00628c5511d7a857f (tree 6a642bc8):

  • 7/7 gates passed;
  • 309 Rust tests passed, 0 failed;
  • browser suite: 62 expected, 0 unexpected, 0 flaky, 0 skipped, on system Chrome 155;
  • receipt sha256 4916711e….

The earlier receipt for cab75e7 covers the pre-rebase head only.

@TusanHomichi
TusanHomichi merged commit 296a81a into main Oct 15, 2026
9 checks passed
@TusanHomichi
TusanHomichi deleted the claude/138-doctor-checksums branch October 15, 2026 22:44
TusanHomichi added a commit that referenced this pull request Oct 15, 2026
A minor release under ADR 0022: the complete installation export (#130), the
web stack on SvelteKit 3 and Vite 8 (#140) with the browser floor it brings
(Chrome/Edge 111, Firefox 114, Safari 16.4), Rust 1.99 and SQLite 3.51
(#139), and doctor's migration verdict matching serve (#144, ADR 0029).
Upgrading from 0.2.0 runs no migration. Versions agree across Cargo and web
(tests/release_version.rs); the changelog, README, roadmap, and install guide
name 0.3.0.

Refs #146

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

doctor: compare stored migration checksums, not just versions

1 participant