wiki_lint Transaction Isolation
Lint() in api/internal/storage/postgres.go wraps both SQL queries in a REPEATABLE READ, READ ONLY transaction.
Why
Without this, a page deleted between the orphan query and the dead-link query silently vanishes from both result sets — the lint report looks clean when it shouldn't.
- Orphan query: finds pages with no inbound links
- Dead-link query: finds links pointing to non-existent pages
A page deleted mid-flight no longer appears in wiki_pages, so it's excluded from both checks. Result: false-clean report.
Implementation
tx, err := s.pool.BeginTx(ctx, pgx.TxOptions{
IsoLevel: pgx.RepeatableRead,
AccessMode: pgx.ReadOnly,
})
defer tx.Rollback(ctx) // safe — read-only tx, no commit needed
Both pool.Query() calls replaced with tx.Query(). The transaction's consistent snapshot guarantees both queries see the same DB state.
Race frequency
Rare in practice. The fix prevents false-clean reports during concurrent bulk edits or deletes running alongside a lint check.
Related
- lint-index — composite index for query performance
- lint-cooldown — cooldown to limit lint call frequency