Skip to content

fix(store): surface SQLITE_CORRUPT from row scans instead of truncating#1018

Merged
DeusData merged 1 commit into
mainfrom
fix/surface-sqlite-corrupt
Jul 11, 2026
Merged

fix(store): surface SQLITE_CORRUPT from row scans instead of truncating#1018
DeusData merged 1 commit into
mainfrom
fix/surface-sqlite-corrupt

Conversation

@DeusData

Copy link
Copy Markdown
Owner

Closes #896.

Every store row-scan loop had the shape while (sqlite3_step(stmt) == SQLITE_ROW) with the terminal code discarded — SQLITE_CORRUPT mid-scan was indistinguishable from a clean end of results. Index-covered counts stayed correct while row fetches died at the first corrupt page, producing the report's contradictory error-free output (total: 379, results: [], Cypher vs schema count divergence, BM25 total: 0, empty schema/architecture sections).

Fix: all 31 scan loops capture the terminal code and fail loudly (CBM_STORE_ERR + store error) with per-site cleanup — partial results freed, or assigned to the out-params so the caller's existing free path owns them. Two enrichment-only soft spots are documented inline (include_connected neighbor names, cluster adjacency), and best-effort/capped helpers keep by-design semantics.

Reproduce-first (the issue's dd recipe): zero a 40-page mid-file band, scan. RED showed the exact reported bug live — CBM_STORE_OK with 264 of 2,000 rows silently truncated; GREEN returns CBM_STORE_ERR. Two independent scan surfaces asserted; fixture-health guards prevent a vacuous pass (a healthy full scan fails the test as a broken fixture, not as a fixed bug).

Full suite 5,990/0, lint-ci clean.

Thanks @kriswill — the field-confusion framing ("symptoms read as extraction bugs") is exactly why this class mattered.

@DeusData DeusData added this to the 0.9.1-rc milestone Jul 11, 2026
@DeusData DeusData enabled auto-merge July 11, 2026 01:13
Every row-scan loop discarded the terminal sqlite3_step code, so
SQLITE_CORRUPT mid-scan was indistinguishable from a clean end of
results: against a page-corrupted DB, counts answered from covering
indexes stayed correct while row fetches died at the first corrupt
table page — every query surface returned plausible truncated/empty
answers with no error (search total=379 with results=[], Cypher counts
diverging from schema counts, BM25 total=0, empty schema sections).

All 31 scan loops now capture the terminal code and fail loudly with
CBM_STORE_ERR + a store error message when a scan aborts, with
per-site cleanup (partial results freed or handed to the caller's
normal free path). Two deliberate soft spots, both enrichment-only and
documented inline: include_connected neighbor names (no store handle)
and the cluster adjacency scan (partial adjacency; primary surfaces
already fail loudly). Best-effort schema property-name discovery and
two capped helper scans keep their by-design early-exit semantics.

Reproduce-first: corrupt_page_scan_returns_error_not_truncation
zeroes a 40-page mid-file band per the issue's dd recipe and asserts
scans return CBM_STORE_ERR. RED on the old code with the exact
reported symptom (OK with 264 of 2000 rows silently truncated); GREEN
now. Fixture-health guards make a healthy-scan pass impossible to
mistake for a fix.

Closes #896

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData DeusData merged commit 4ac5bb6 into main Jul 11, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Row-scan loops swallow SQLITE_CORRUPT — queries return plausible truncated/empty results with no error

1 participant