mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-26 22:37:03 +00:00
dab3acd1f1
* feat(store): a read-only diagnostic counts version tie groups whose order breaks history (BUG-3751) Postgres migration 054 backfilled item_versions.version_seq ordering same-second ties by ctid, a physical location rather than chronology. No column records finer chronology (created_at is second-precision, id a random UUIDv4), so whether a tie group was numbered out of order shows only in whether its reverse patches apply in the order history reads them. DiagnoseVersionTies walks each item with a tie group from its current content and classifies every group: current order only, ambiguous, misordered (another order applies, the current one does not), unresolvable, skipped (over 5 rows), plus items whose chain broke outside any tie. Counts only, no ids or content, inside a read-only transaction. `pad db diagnose-version-ties --pg URL | --sqlite PATH` runs it without the store's migrate-on-open and prints JSON. It is measurement first, by the lead's ruling, before any corrective rewrite of history. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * refactor(store): the version tie diagnostic is a standalone script, read-only by construction (BUG-3751) Per the lead, for running against production Postgres: - No product surface: `pad db diagnose-version-ties` is removed. The operator runs `go run ./scripts/diagnose-version-ties -pg DSN`. - Read-only by construction: one transaction opened READ ONLY through TxOptions and again with SET TRANSACTION READ ONLY. A test shows a write inside it refused (SQLSTATE 25006); with both removed (mutant on test-pg) the write goes through and the test fails. SQLite opens query_only. - Bounded: SET LOCAL statement_timeout (-timeout, default 30s), one item at a time, progress on stderr. - Counts only as JSON on stdout: no ids, titles or content. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(store): the tie diagnostic bounds its whole run and does not judge groups a snapshot masks (BUG-3751) Codex round 1: - Per-statement timeouts did not bound the run, or the read-only snapshot it holds on a production database. -max-duration (default 15m) stops the run and reports what it scanned, with truncated: true. - A full-content row in a tie group resets the content whatever the order, so such groups are counted as with_snapshot and never as ordered or misordered. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(store): the tie diagnostic's deadline is a context from the first statement, and permutations are checked against the rest of the chain (BUG-3751) Codex round 2: - The whole-run bound was checked only between items, after the first scan. It is now a context deadline set before the first statement, so it cancels any query (SQLite included) and ends the snapshot. Reaching it, wherever, returns a partial report with truncated set. - An order was judged against only the next older version. It is now checked against every older version in stored order, up to the next tie group or full snapshot. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(store): the tie diagnostic's deadline bounds classification too, and a sub-millisecond timeout is never 0 (BUG-3751) Codex on the diagnostic: the run deadline was checked only between items, so one item with many tie groups could run past -max-duration and still report a complete result; and a positive -timeout under 1ms truncated to statement_timeout = 0, which PostgreSQL reads as no limit. Classification now checks the context per group, inside the permutation search and before judging, and each item is folded into the report only when it finishes. The timeout rounds up to whole milliseconds. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(store): the tie diagnostic's deadline bounds every version it applies (BUG-3751) Codex on the diagnostic: applyOrder walked and applied versions with no deadline check, and the singleton, snapshot and oversized paths could cross the deadline on their last step and still report the item complete. applyOrder now checks the context before each version, and every successful return of classifyTieGroups re-checks it. The checks in the permutation search and before judging a group are removed: once the deadline passes applyOrder applies nothing, and the return re-check keeps the item out of the counts, so no mutant of them can be observed. The test now ties the deadline to the work: it expires during the n-th version application, for every n, across histories that take every path. An earlier form tripped on the n-th Err call and could not see a removed check. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(store): the tie diagnostic sets its statement timeout first and requires a run deadline (BUG-3751) Codex on the diagnostic: BEGIN and SET TRANSACTION READ ONLY ran before statement_timeout was set. The timeout is now the first statement in the transaction. BEGIN and that SET cannot be capped by statement_timeout; they are bounded by the run deadline, which the operator entry point now requires (a max duration of zero or less is refused). On Postgres the test reads back statement_timeout and transaction_read_only from inside the transaction. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS * fix(store): a deadline that closes the tie diagnostic's rows before a scan is a truncated report (BUG-3751) Codex on the diagnostic: database/sql closes the rows when the deadline passes, and if that lands between Next and Scan the scan fails. Both row loops returned that as an error; they now report it as truncated, like every other deadline path. A test hook runs before each scan so a test can put the deadline there. Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS