Files
alkblobs/tasks/c3-sqlite-busy-timeout.md
T
glm-5.3-flash a5bebc6aa7 feat(sqlite): busy_timeout = 5000 pinned at open — the contention posture contracted (review-002 C-3, wave 13)
- explicit `PRAGMA busy_timeout = 5000` in the open pragma block,
  pinned constant, not a knob: DQ-7's co-tenancy evidence shows no
  contention observable at POC scale, so there is no tuning story;
  the value matches the family contract (alkstore-sqlite pins the
  same 5000 ms) so the first consumer's co-tenant assembly over one
  sqlite file has a visible contention posture, not a rusqlite-
  default coincidence
- module doc carries the contention posture alongside the
  durability posture; the constructor doc records the choice and
  its reason
- pragma posture test extended: busy_timeout asserted 5000 on the
  backend's own connection
- fuzz/Cargo.lock: alkcall 0.10.0 resolution drift from the dep
  bump, refreshed by the corpus-replay gate run

Verification: cargo test (default: 149+54+4+2 passed); clippy
--all-targets -- -D warnings (default + all-features); cargo fmt
--check; cargo test --manifest-path fuzz/shared/Cargo.toml
2026-10-17 23:36:39 +00:00

4.3 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
c3-sqlite-busy-timeout C-3 — sqlite busy_timeout explicit: knob or pinned constant, the contention posture contracted completed
single trivial component implementation
wave-13
review-002
sqlite

Description

Review-002 C-3 (ride-along). The sqlite engine sets its durability posture explicitly — PRAGMA journal_mode = WAL + PRAGMA synchronous = NORMAL (src/sqlite.rs:156-163, WAL engagement verified at open) — but sets no busy_timeout: contention behavior rides rusqlite's implicit 5-second default, which happens to equal alkstore's explicit 5000 ms. The first consumer's deployment shape is a co-tenant assembly on one sqlite file (alkstore machinery + alkblobs kv + consumer-own tables), where this store's writers serialize behind every other co-tenant writer — the durability/contention posture is load-bearing there and should be a visible contract, not a library-default coincident.

Land an explicit busy_timeout:

  • The shape is the task's design point (re-derive; the review offers either): a knob on the engine options alongside the durability posture (the constructor-tunable pattern), or a pinned constant set at open (the ADR-015-style no-knob posture). The co-tenancy evidence (DQ-7: no contention observable at POC scale) argues the value is not performance-tuned yet — a pinned constant matching the family's 5000 ms is the lean default; a knob is justified only if the session finds the co-tenant story wants it. Record the choice and its reason.
  • The pragma set at open next to the durability block; if a pragma's engagement is verifiable (as journal_mode's is), verify it the same way.
  • The module doc line: the contention posture joins the durability posture as stated contract.

Acceptance Criteria

  • busy_timeout set explicitly at open (the knob/constant choice recorded with its reason)
  • The module doc carries the contention posture alongside the durability posture
  • A server-less test asserts the posture (the pragma observable or the knob's effect) — green in the default build
  • Gates green: cargo test (default), clippy --all-targets -- -D warnings, cargo fmt --check

References

  • docs/reviews/002-first-consumer-review.md (C-3)
  • src/sqlite.rs:156-163 (the durability pragma block — the new pragma's home)
  • /workspace/@alkdev/alkgit/docs/research/substrate-recomposition.md (upstream-ask 4; DQ-7's co-tenancy measurement)
  • alkstore's sqlite engine (the explicit 5000 ms — the family contrast)

Notes

Chosen shape: pinned constant set at open (the ADR-015-style no-knob posture). Reason: the co-tenancy evidence (DQ-7, recorded in the substrate-recomposition doc) is that no contention is observable at POC scale — there is no tuning story to hang a knob on, so a tunable surface would be speculative API. The value pinned is 5000 ms, matching the family contrast (alkstore-sqlite pins PRAGMA busy_timeout = 5000 explicitly in substrate/schema.rs::Default_PRAGMAS): the first consumer's co-tenant assembly over one sqlite file now has a visible contract aligned with the alkstore machinery it co-tenants with, rather than riding rusqlite's implicit 5 s default by coincidence.

Implementation (src/sqlite.rs):

  • PRAGMA busy_timeout = 5000; joins the durability block in SqliteBackend::new's execute_batch (verified live via PRAGMA busy_timeout; no separate result check needed — the setting cannot silently fail the way WAL can).
  • The module doc's opening line now states the contention posture alongside the durability posture, with the pinned-constant reason recorded there.
  • The constructor doc comment carries the choice and its reason.

Summary

Landed: explicit busy_timeout = 5000 at open as a pinned constant (src/sqlite.rs), the module doc carrying the contention posture as stated contract, and the pragma posture test extended to assert busy_timeout == 5000 on the backend's own connection (opens_with_wal_synchronous_normal_and_busy_timeout). All gates green: cargo test (default: 149+54+4+2 passed), clippy --all-targets -- -D warnings (default and all-features), cargo fmt --check, and the fuzz corpus-replay gate (fuzz/shared).