[Windows App] Request to submit deferred migration line-ending checksum fix

Open 💬 2 comments Opened Aug 14, 2026 by jamespud

Hello,

I have a reviewed and tested fix for the SQL migration CRLF/LF checksum issue tracked in #32643.

Root cause:

SQLx checksums the exact migration bytes embedded at compile time. Migration files checked out with CRLF (for example, on Windows with core.autocrlf=true) therefore produce different checksums than LF checkouts. Databases created by one build fail to open in another with:

migration N was previously applied but has been modified

This also breaks the Windows + WSL shared-Codex-home scenario tracked in #25216 (see #23777, #23841, #23848, #23863), where a WSL runtime must open a database created by a Windows build and vice versa.

Fix:

  • Canonicalizes runtime migrations to LF line endings on all platforms in runtime_migrator(), so embedded checksums no longer depend on checkout line-ending policy.
  • Adds repair_migration_line_ending_checksums(): when opening any runtime SQLite database, _sqlx_migrations rows whose checksum was computed from CRLF migration files are rewritten to the canonical LF checksum, so histories created by either build are accepted interchangeably.
  • Applies to all six runtime migrators (state, logs, goals, memories, queue, thread history).
  • Genuine migration drift is still rejected: the repair only rewrites rows that exactly match the CRLF form of the current migration.

Validation:

  • codex-state: 174/174 tests passed, including 4 new tests (LF invariant across all runtime migrators, CRLF→LF canonicalization, CRLF-applied history accepted after repair, LF-applied history unchanged)
  • scoped Clippy (just fix -p codex-state): clean
  • cargo fmt --check: clean
  • Change is limited to codex-rs/state (+205/-1 across 3 files)

Prepared branch:

  • Fork: jamespud/codex
  • Branch: fix/32643-state-migration-line-endings
  • Commit: 6247dabb4

GitHub currently blocks PR creation because only collaborators may open pull requests in this repository.

Could you please either:

  • invite jamespud as a collaborator with permission to open the PR, or
  • open the PR from the prepared fork branch?

Thank you.

View original on GitHub ↗

2 Comments

jdcodes1 · 9 days ago

Independent verification of the root cause against main (1f41cc5d92): the six runtime DBs all embed their .sql files via sqlx's compile-time migrator (state/src/sqlite.rs, migration dirs like state/migrations/, state/queue_migrations/), and the repo's .gitattributes contains no *.sql text eol=lf rule — only two linguist entries. So on a core.autocrlf=true checkout the embedded bytes really are CRLF, the checksum diverges from LF builds, and migration N was previously applied but has been modified follows exactly as described. The Windows↔WSL shared-home case (#25216) is the worst hit because two differently-built binaries open the same database file.

One addition to the proposed fix: alongside runtime canonicalization + checksum repair, add *.sql text eol=lf to .gitattributes so future checkouts can't reintroduce the divergence at the source. The repair pass is still needed for databases already stamped with CRLF checksums, and restricting it to rows matching the CRLF form of the current migration keeps genuine-drift detection intact — that design looks right.

jamespud · 9 days ago
Independent verification of the root cause against main (1f41cc5): the six runtime DBs all embed their .sql files via sqlx's compile-time migrator (state/src/sqlite.rs, migration dirs like state/migrations/, state/queue_migrations/), and the repo's .gitattributes contains no *.sql text eol=lf rule — only two linguist entries. So on a core.autocrlf=true checkout the embedded bytes really are CRLF, the checksum diverges from LF builds, and migration N was previously applied but has been modified follows exactly as described. The Windows↔WSL shared-home case (#25216) is the worst hit because two differently-built binaries open the same database file. One addition to the proposed fix: alongside runtime canonicalization + checksum repair, add *.sql text eol=lf to .gitattributes so future checkouts can't reintroduce the divergence at the source. The repair pass is still needed for databases already stamped with CRLF checksums, and restricting it to rows matching the CRLF form of the current migration keeps genuine-drift detection intact — that design looks right.

Thanks for the independent verification — glad the root-cause analysis and the checksum-repair design hold up against main.

I've incorporated your suggestion. The branch now adds a *.sql text eol=lf rule to .gitattributes (commit c291fa484) so every checkout embeds LF regardless of core.autocrlf, closing the source-side gap. For the record, git add --renormalize was a no-op on the existing .sql blobs (they're already stored as LF), so the change stays minimal — the runtime canonicalization + checksum repair in 6247dabb4 remains the part that heals databases already stamped with CRLF checksums.

Updated branch: jamespud:fix/32643-state-migration-line-endings (commits 6247dabb4 + c291fa484).