dev is broken: step 15 renumbered an applied migration #23

Open
opened 2026-09-23 07:23:13 +00:00 by kayg · 10 comments
Owner

Severity: blocks everything. dev at 1830177 fails to start on any database created by dev at bba250f: error: database migration failed: migration 8 was previously applied but has been modified. The owner's preview hit it; it is rolled back to bba250f meanwhile, and the data is intact.

Cause. bba250f (step 11) shipped crates/server/migrations/sqlite/0008_stream_sessions.sql. Branch cli (step 15) inserted its own 0008_token_provenance.sql and renumbered the stream migration to 0009_stream_sessions.sql during the merge. Existing databases record version 8 as stream_sessions, so the checksum no longer matches.

Fix.

  • Restore 0008_stream_sessions.sql exactly as shipped, and move token provenance to 0009_token_provenance.sql. Check that it does not depend on running before stream sessions.
  • Add a regression test that upgrades a database created by the previous dev head.
  • Add a verify fast gate: migrations that exist on origin/dev are immutable. Their files may not be renamed, renumbered or edited, only appended after. That way no future merge can repeat this.

Why review and verify missed it. Every test creates a fresh database, so none of them runs an upgrade.

**Severity: blocks everything.** `dev` at `1830177` fails to start on any database created by `dev` at `bba250f`: `error: database migration failed: migration 8 was previously applied but has been modified`. The owner's preview hit it; it is rolled back to `bba250f` meanwhile, and the data is intact. **Cause.** `bba250f` (step 11) shipped `crates/server/migrations/sqlite/0008_stream_sessions.sql`. Branch `cli` (step 15) inserted its own `0008_token_provenance.sql` and renumbered the stream migration to `0009_stream_sessions.sql` during the merge. Existing databases record version 8 as `stream_sessions`, so the checksum no longer matches. **Fix.** - Restore `0008_stream_sessions.sql` exactly as shipped, and move token provenance to `0009_token_provenance.sql`. Check that it does not depend on running before stream sessions. - Add a regression test that upgrades a database created by the previous `dev` head. - Add a `verify fast` gate: **migrations that exist on `origin/dev` are immutable**. Their files may not be renamed, renumbered or edited, only appended after. That way no future merge can repeat this. **Why review and verify missed it.** Every test creates a fresh database, so none of them runs an upgrade.
Author
Owner

Started migration-fix on branch migration-fix at base 1830177ac5. Confirmed bba250f has 0008_stream_sessions.sql and current dev replaced version 8 with token provenance. I will restore the canonical version ordering, add upgrade and rejection tests, and add the append-only fast gate.

Started migration-fix on branch migration-fix at base 1830177ac53bb17160b8b038a6016eacd76d40d2. Confirmed bba250f has 0008_stream_sessions.sql and current dev replaced version 8 with token provenance. I will restore the canonical version ordering, add upgrade and rejection tests, and add the append-only fast gate.
Author
Owner

Migration history finding: git diff bba250f 1830177 -- crates/server/migrations/sqlite shows versions 1–7 unchanged, version 8 stream sessions renamed to version 9, and token provenance inserted at version 8. Stream sessions only creates stream_sessions and its index; token provenance only alters tokens. The restored version 8 matches git show bba250f:.../0008_stream_sessions.sql byte for byte. The append-only gate compares to bba250f while the current origin/dev head contains the known conflicting version 8, then compares to origin/dev once repaired. Negative proof: temporarily renaming 0008_stream_sessions.sql made scripts/verify fast exit 1 with migration removed or renamed: crates/server/migrations/sqlite/0008_stream_sessions.sql; the file was restored.

Migration history finding: `git diff bba250f 1830177 -- crates/server/migrations/sqlite` shows versions 1–7 unchanged, version 8 stream sessions renamed to version 9, and token provenance inserted at version 8. Stream sessions only creates `stream_sessions` and its index; token provenance only alters `tokens`. The restored version 8 matches `git show bba250f:.../0008_stream_sessions.sql` byte for byte. The append-only gate compares to bba250f while the current origin/dev head contains the known conflicting version 8, then compares to origin/dev once repaired. Negative proof: temporarily renaming 0008_stream_sessions.sql made `scripts/verify fast` exit 1 with `migration removed or renamed: crates/server/migrations/sqlite/0008_stream_sessions.sql`; the file was restored.
Author
Owner

Regression fixtures were extracted byte-for-byte from bba250f (versions 1–8) and 1830177 (incompatible version 8); each was compared with git show. The focused server test passes: 2 passed; 0 failed. It starts Server::open on the bba250f database, serves /api/health, and verifies the original user, passkey and token rows plus the new auth_source = legacy column. It also confirms an 1830177 version-8 database returns VersionMismatch(8) with migration records and seed data unchanged. A copy of the live preview database is in /tmp; before upgrade it has migration versions 1–8, one user, one passkey and two token rows.

Regression fixtures were extracted byte-for-byte from bba250f (versions 1–8) and 1830177 (incompatible version 8); each was compared with `git show`. The focused server test passes: `2 passed; 0 failed`. It starts `Server::open` on the bba250f database, serves `/api/health`, and verifies the original user, passkey and token rows plus the new `auth_source = legacy` column. It also confirms an 1830177 version-8 database returns `VersionMismatch(8)` with migration records and seed data unchanged. A copy of the live preview database is in /tmp; before upgrade it has migration versions 1–8, one user, one passkey and two token rows.
Author
Owner

Live-data proof on a copy only: copied /mnt/hdd/infraternal/preview-data/infraternal.sqlite3* into a fresh /tmp/infraternal-migration-preview.* directory. Before upgrade the copy had migration versions 1–8, 1 user, 1 passkey, 2 token rows. Started the new branch binary on a spare localhost port against the copy; /api/health returned {"status":"ok","version":"0.0.1"}. After startup the copy had migration versions 1–9, the same row counts, and tokens.auth_source existed. The original preview database was not opened or changed by this job.

scripts/verify fast at 97ef5d0 passed: append-only migrations, JavaScript dependencies, web build, cargo fmt, cargo clippy, cargo test, Svelte checks, stream typecheck, all Vitest suites, OpenAPI/client drift, and terminal typecheck/Vitest.

Live-data proof on a copy only: copied `/mnt/hdd/infraternal/preview-data/infraternal.sqlite3*` into a fresh `/tmp/infraternal-migration-preview.*` directory. Before upgrade the copy had migration versions 1–8, 1 user, 1 passkey, 2 token rows. Started the new branch binary on a spare localhost port against the copy; `/api/health` returned `{"status":"ok","version":"0.0.1"}`. After startup the copy had migration versions 1–9, the same row counts, and `tokens.auth_source` existed. The original preview database was not opened or changed by this job. `scripts/verify fast` at 97ef5d0 passed: append-only migrations, JavaScript dependencies, web build, cargo fmt, cargo clippy, cargo test, Svelte checks, stream typecheck, all Vitest suites, OpenAPI/client drift, and terminal typecheck/Vitest.
Author
Owner

scripts/verify integration at 97ef5d0 passed the release build, real HTTP behavior, Docker socket and rootless Podman socket checks, then failed in the pre-existing infraternal-engine integration test docker_and_podman_share_the_real_engine_contract at crates/engine/tests/integration.rs:856: its log records lacked the expected stdout-line record. Other 7 tests in that binary passed. The test ran real Docker and Podman and emitted Podman stop warnings; no migration code is involved. I am rerunning that single failing test to determine whether the result is transient before rerunning the full gate.

`scripts/verify integration` at 97ef5d0 passed the release build, real HTTP behavior, Docker socket and rootless Podman socket checks, then failed in the pre-existing `infraternal-engine` integration test `docker_and_podman_share_the_real_engine_contract` at `crates/engine/tests/integration.rs:856`: its log records lacked the expected stdout-line record. Other 7 tests in that binary passed. The test ran real Docker and Podman and emitted Podman stop warnings; no migration code is involved. I am rerunning that single failing test to determine whether the result is transient before rerunning the full gate.
Author
Owner

Finished migration-fix on branch migration-fix. Head: 97ef5d09ad. No push; issue remains open.

Restored 0008_stream_sessions.sql byte-identical to bba250f and moved token provenance to 0009. The two migrations touch separate tables; no source code relies on their numeric names. Historical fixtures are byte-identical to git show.

Regression: current Server::open upgrades a database initialized with the bba250f SQL, serves /api/health, preserves a user, passkey and token row, and adds tokens.auth_source. The incompatible 1830177 version-8 history is rejected with VersionMismatch(8); migration records and seed data remain unchanged. The focused test result was: 2 passed; 0 failed.

Live preview proof: copied /mnt/hdd/infraternal/preview-data/infraternal.sqlite3* to /tmp, then started target/release/infraternal on a spare localhost port using only the copy. /api/health returned {"status":"ok","version":"0.0.1"}. Copy migrated from versions 1–8 to 1–9; row counts remained users=1, passkeys=1, tokens=2; tokens.auth_source exists. The source database was read by cp and was never written or started with the new binary.

Append-only gate proof (temporary rename restored immediately):
FAIL fast: migrations are append-only
migration removed or renamed: crates/server/migrations/sqlite/0008_stream_sessions.sql

First integration attempt encountered a transient, pre-existing engine log assertion failure at crates/engine/tests/integration.rs:856. Its focused rerun passed, and the full integration gate passed on rerun with no source changes.

scripts/verify fast output (verbatim):
PASS fast: migrations are append-only
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

scripts/verify integration output (verbatim):
PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
PASS integration: engine adapters against Docker and Podman
PASS integration: TypeScript stream client against Docker and Podman
PASS integration: stream authorization and CLOSE regressions against Docker
PASS integration: persistent PTY termination preempts blocked send
PASS integration: resource HTTP API against Docker and rootless Podman
PASS integration: compiled CLI and MCP against real server and engines
PASS integration: SSH contract against real sshd

Finished migration-fix on branch migration-fix. Head: 97ef5d09ad0ec6683bed9d489870ca8364542521. No push; issue remains open. Restored 0008_stream_sessions.sql byte-identical to bba250f and moved token provenance to 0009. The two migrations touch separate tables; no source code relies on their numeric names. Historical fixtures are byte-identical to git show. Regression: current Server::open upgrades a database initialized with the bba250f SQL, serves /api/health, preserves a user, passkey and token row, and adds tokens.auth_source. The incompatible 1830177 version-8 history is rejected with VersionMismatch(8); migration records and seed data remain unchanged. The focused test result was: 2 passed; 0 failed. Live preview proof: copied /mnt/hdd/infraternal/preview-data/infraternal.sqlite3* to /tmp, then started target/release/infraternal on a spare localhost port using only the copy. /api/health returned {"status":"ok","version":"0.0.1"}. Copy migrated from versions 1–8 to 1–9; row counts remained users=1, passkeys=1, tokens=2; tokens.auth_source exists. The source database was read by cp and was never written or started with the new binary. Append-only gate proof (temporary rename restored immediately): FAIL fast: migrations are append-only migration removed or renamed: crates/server/migrations/sqlite/0008_stream_sessions.sql First integration attempt encountered a transient, pre-existing engine log assertion failure at crates/engine/tests/integration.rs:856. Its focused rerun passed, and the full integration gate passed on rerun with no source changes. scripts/verify fast output (verbatim): PASS fast: migrations are append-only PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest scripts/verify integration output (verbatim): PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping PASS integration: engine adapters against Docker and Podman PASS integration: TypeScript stream client against Docker and Podman PASS integration: stream authorization and CLOSE regressions against Docker PASS integration: persistent PTY termination preempts blocked send PASS integration: resource HTTP API against Docker and rootless Podman PASS integration: compiled CLI and MCP against real server and engines PASS integration: SSH contract against real sshd
Author
Owner

Starting independent review on branch migration-fix at 97ef5d09ad0ec6683bed9d489870ca8364542521, against base dev at 1830177ac53bb17160b8b038a6016eacd76d40d2. I will verify the historical upgrade paths, fixture provenance, append-only gate cases, migration order dependencies, owner-data copy migration, and required gates before reporting.

Starting independent review on branch `migration-fix` at `97ef5d09ad0ec6683bed9d489870ca8364542521`, against base `dev` at `1830177ac53bb17160b8b038a6016eacd76d40d2`. I will verify the historical upgrade paths, fixture provenance, append-only gate cases, migration order dependencies, owner-data copy migration, and required gates before reporting.
Author
Owner

Started independent review and verification.
Branch: migration-fix
Base: dev at 1830177ac53bb17160b8b038a6016eacd76d40d2
Review head: 97ef5d09ad0ec6683bed9d489870ca8364542521
Scope: migration upgrade paths, fixture provenance and isolation, append-only gate behavior, migration order safety, and copied preview database smoke.

Started independent review and verification. Branch: `migration-fix` Base: `dev` at `1830177ac53bb17160b8b038a6016eacd76d40d2` Review head: `97ef5d09ad0ec6683bed9d489870ca8364542521` Scope: migration upgrade paths, fixture provenance and isolation, append-only gate behavior, migration order safety, and copied preview database smoke.
Author
Owner

Independent review and verification complete.

Branch: migration-fix
Base: 1830177ac53bb17160b8b038a6016eacd76d40d2
Final head: eaf6f118c2e8d16a0764123702b56f74223d9a68

  1. Upgrade paths — PASS. A temporary test suite populated directly with git show migrations passed all three paths: bba250f upgrades to versions 1–9 preserving user, passkey and token rows; full 1830177 history returns VersionMismatch(8) with migration checksums and existing role, stream-session and token data unchanged; a fresh database reaches versions 1–9 and serves /api/health. The raw-history suite reported: cargo test: 3 passed (1 suite, 0.05s).

  2. Fixtures — PASS. Blob hashes matched all 8 migrations at bba250f and all 9 at 1830177. The review found that the latter fixture initially omitted migration 9; commit 0ca46c7 added the exact historical file and expanded rejection coverage. Fixtures are needed to build past schemas in tests and are siblings of migrations/sqlite; the production migrator explicitly uses migrations/sqlite. LATER: the duplicate fixture copies can drift because no gate currently pins them to their historical blobs.

  3. Append-only gate — PASS. The probes rejected an edited, renamed, deleted and lower-numbered migration, while accepting a new migration 10. Local branch/worktree and detached-HEAD runs used the merge-base with origin/dev; a local dev ref also works when origin/dev is absent. With neither ref available, the gate now fails closed with an actionable fetch message instead of passing against an empty baseline. Fixed in b9b6371.

  4. Migration order — PASS. Version 8 creates stream_sessions; version 9 adds auth_source to the existing tokens table. Neither migration depends on the other.

  5. Preview data copy — PASS. A read-only SQLite backup was migrated by the release binary from this head. It advanced from versions 1–8 to 1–9, served health with status ok, and kept counts unchanged: users 1, passkeys 1, tokens 2.

scripts/verify fast output at the final head:

PASS fast: migrations are append-only
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Final scripts/verify integration output:

PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
PASS integration: engine adapters against Docker and Podman
PASS integration: TypeScript stream client against Docker and Podman
PASS integration: stream authorization and CLOSE regressions against Docker
PASS integration: persistent PTY termination preempts blocked send
PASS integration: resource HTTP API against Docker and rootless Podman
PASS integration: compiled CLI and MCP against real server and engines
PASS integration: SSH contract against real sshd

The first integration run had one transient owner_loss_terminates_shell PTY acknowledgement timeout; the full rerun passed. Other commits: 0ca46c7 adds full historical coverage and eaf6f11 extracts the assertions to keep Clippy green.

Independent review and verification complete. Branch: `migration-fix` Base: `1830177ac53bb17160b8b038a6016eacd76d40d2` Final head: `eaf6f118c2e8d16a0764123702b56f74223d9a68` 1. Upgrade paths — PASS. A temporary test suite populated directly with `git show` migrations passed all three paths: `bba250f` upgrades to versions 1–9 preserving user, passkey and token rows; full `1830177` history returns `VersionMismatch(8)` with migration checksums and existing role, stream-session and token data unchanged; a fresh database reaches versions 1–9 and serves `/api/health`. The raw-history suite reported: `cargo test: 3 passed (1 suite, 0.05s)`. 2. Fixtures — PASS. Blob hashes matched all 8 migrations at `bba250f` and all 9 at `1830177`. The review found that the latter fixture initially omitted migration 9; commit `0ca46c7` added the exact historical file and expanded rejection coverage. Fixtures are needed to build past schemas in tests and are siblings of `migrations/sqlite`; the production migrator explicitly uses `migrations/sqlite`. LATER: the duplicate fixture copies can drift because no gate currently pins them to their historical blobs. 3. Append-only gate — PASS. The probes rejected an edited, renamed, deleted and lower-numbered migration, while accepting a new migration 10. Local branch/worktree and detached-HEAD runs used the merge-base with `origin/dev`; a local `dev` ref also works when `origin/dev` is absent. With neither ref available, the gate now fails closed with an actionable fetch message instead of passing against an empty baseline. Fixed in `b9b6371`. 4. Migration order — PASS. Version 8 creates `stream_sessions`; version 9 adds `auth_source` to the existing `tokens` table. Neither migration depends on the other. 5. Preview data copy — PASS. A read-only SQLite backup was migrated by the release binary from this head. It advanced from versions 1–8 to 1–9, served health with status `ok`, and kept counts unchanged: users 1, passkeys 1, tokens 2. `scripts/verify fast` output at the final head: ``` PASS fast: migrations are append-only PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Final `scripts/verify integration` output: ``` PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping PASS integration: engine adapters against Docker and Podman PASS integration: TypeScript stream client against Docker and Podman PASS integration: stream authorization and CLOSE regressions against Docker PASS integration: persistent PTY termination preempts blocked send PASS integration: resource HTTP API against Docker and rootless Podman PASS integration: compiled CLI and MCP against real server and engines PASS integration: SSH contract against real sshd ``` The first integration run had one transient `owner_loss_terminates_shell` PTY acknowledgement timeout; the full rerun passed. Other commits: `0ca46c7` adds full historical coverage and `eaf6f11` extracts the assertions to keep Clippy green.
Author
Owner

Orchestrator: merged to dev at 2c69013 and pushed. The merged tree is identical to the verified head eaf6f11. The path was build migration-fix, then an independent review and verify, which fixed two blocks-merge holes itself: the gate passed silently without a baseline, and the 1830177 fixture was incomplete. Every item PASS; fast and integration green. Later: a gate that pins the fixture copies to their historical blobs. Also later: owner_loss_terminates_shell (the SSH PTY acknowledgement timeout) flaked once here and once before in cli-mcp; it needs its own look.

Orchestrator: **merged to `dev` at `2c69013`** and pushed. The merged tree is identical to the verified head `eaf6f11`. The path was build `migration-fix`, then an independent review and verify, which fixed two blocks-merge holes itself: the gate passed silently without a baseline, and the `1830177` fixture was incomplete. Every item PASS; fast and integration green. **Later:** a gate that pins the fixture copies to their historical blobs. Also later: `owner_loss_terminates_shell` (the SSH PTY acknowledgement timeout) flaked once here and once before in `cli-mcp`; it needs its own look.
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/infraternal-v0#23
No description provided.