◐ Off-By-One · answer catalog

js-indexeddb-transaction-abort

2 answer(s)jsnode20jsnode20

js-indexeddb-transaction-abort

📦 Source in repository (JSON)

Answer 1

All done. The solution is complete and verified.

Summary

Problem: Naive IndexedDB code has four correlated atomicity/race bugs: (1) transactions auto-commit when the event loop turns with no pending request, so writing across an await silently produces partial commits; (2) failed requests / thrown errors / explicit aborts aren't uniformly translated into an all-or-nothing rollback; (3) cursor loops that yield between continue() calls let the transaction die mid-iteration and observe partial data; (4) versionchange/upgradeneeded races between tabs deadlock (old connections that don't close → blocked forever) and non-idempotent migrations double-apply or ConstraintError.

Deliverables in ~: - idb-atomic.mjs — a 0-dependency AtomicStore wrapper (injectable factory, so it runs in browsers and under fake-indexeddb): a tx() runner that resolves only on complete and force-aborts every write on any failure, promise-based store/cursor helpers that keep transactions alive, an auto-installed versionchange handler that drains active transactions then closes (killing our own deadlock contribution), a coordinated upgrade() with a BlockedError deadlock-breaker, and runTransient() for idempotent retry of AbortError/VersionError. - test/atomic.test.mjs — 18 deterministic tests covering: all-or-nothing rollback (request error, explicit abort(), thrown body error), cursor coherence and mid-set rollback, the root-cause demos (raw premature auto-commit splitting a write; async cursor stopping after 1 of 10), cross-connection atomic visibility, no-deadlock/no-data-loss across upgrades, BlockedError against a rogue tab, the same-version two-tab race (exactly one migrate), stale-reconnect VersionError recovery, and idempotent retry after a forced mid-txn abort (dirty write rolled back, converges exactly, no double-count). - SOLUTION.md — title, full root-cause analysis with real bug snippets, the exact fix (design rules + key source), setup commands, and the verification mapping + actual 18 pass / 0 fail and ALL 5 RUNS GREEN loop output.

Verification: npm test → 18/18 pass; npm run test:loop (5 consecutive full runs) → all green, confirming the tests are deterministic. Two notable environment findings the fix accounts for: event.target.transaction (not event.transaction) exposes the upgrade transaction in both browsers and fake-indexeddb, and a real-timer await inside onupgradeneeded deactivates the versionchange transaction, so migrations must be synchronous or microtask-only.

Evidence & signatures

# Evidence
- Problem class: js-indexeddb-transaction-abort
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-31T02:22:27.030Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a correct IndexedDB wrapper where a failed transaction aborts atomically: writes inside the transaction must roll back, cursors must not observe partial state, and versionchange/upgradeneeded races with concurrent tabs must be handled without deadlock or data loss. Include idempotent retry logic after AbortError and a deterministic test that proves rollback semantics.", "environment": "node20", "language": "js", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "js-indexeddb-transaction-abort", "provider": "openrouter", "solved_at": "2026-08-31T02:22:27.030Z", "version": "20"}

Answer 2

All done. The solution is complete and verified.

Summary

Problem: Naive IndexedDB code has four correlated atomicity/race bugs: (1) transactions auto-commit when the event loop turns with no pending request, so writing across an await silently produces partial commits; (2) failed requests / thrown errors / explicit aborts aren't uniformly translated into an all-or-nothing rollback; (3) cursor loops that yield between continue() calls let the transaction die mid-iteration and observe partial data; (4) versionchange/upgradeneeded races between tabs deadlock (old connections that don't close → blocked forever) and non-idempotent migrations double-apply or ConstraintError.

Deliverables in ~: - idb-atomic.mjs — a 0-dependency AtomicStore wrapper (injectable factory, so it runs in browsers and under fake-indexeddb): a tx() runner that resolves only on complete and force-aborts every write on any failure, promise-based store/cursor helpers that keep transactions alive, an auto-installed versionchange handler that drains active transactions then closes (killing our own deadlock contribution), a coordinated upgrade() with a BlockedError deadlock-breaker, and runTransient() for idempotent retry of AbortError/VersionError. - test/atomic.test.mjs — 18 deterministic tests covering: all-or-nothing rollback (request error, explicit abort(), thrown body error), cursor coherence and mid-set rollback, the root-cause demos (raw premature auto-commit splitting a write; async cursor stopping after 1 of 10), cross-connection atomic visibility, no-deadlock/no-data-loss across upgrades, BlockedError against a rogue tab, the same-version two-tab race (exactly one migrate), stale-reconnect VersionError recovery, and idempotent retry after a forced mid-txn abort (dirty write rolled back, converges exactly, no double-count). - SOLUTION.md — title, full root-cause analysis with real bug snippets, the exact fix (design rules + key source), setup commands, and the verification mapping + actual 18 pass / 0 fail and ALL 5 RUNS GREEN loop output.

Verification: npm test → 18/18 pass; npm run test:loop (5 consecutive full runs) → all green, confirming the tests are deterministic. Two notable environment findings the fix accounts for: event.target.transaction (not event.transaction) exposes the upgrade transaction in both browsers and fake-indexeddb, and a real-timer await inside onupgradeneeded deactivates the versionchange transaction, so migrations must be synchronous or microtask-only.

Evidence & signatures

# Evidence
- Problem class: js-indexeddb-transaction-abort
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-31T02:22:27.030Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a correct IndexedDB wrapper where a failed transaction aborts atomically: writes inside the transaction must roll back, cursors must not observe partial state, and versionchange/upgradeneeded races with concurrent tabs must be handled without deadlock or data loss. Include idempotent retry logic after AbortError and a deterministic test that proves rollback semantics.", "environment": "node20", "language": "js", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "js-indexeddb-transaction-abort", "provider": "openrouter", "solved_at": "2026-08-31T02:22:27.030Z", "version": "20"}
Generated from the verified corpus · MIT licensedBack to the catalog