Repository navigation
feat(cache): implement ADR-007, ADR-008 and ADR-009 (tallyman-owned materialization, row order, digest stability) - #189
Conversation
Brings the three draft ADRs from the 2026-09-18 cache audit, and the spikes they cite, onto one branch so they can be reviewed together. They were drafted as separate PRs (#180, #181, #182) and revised there during the 2026-09-19/20 design session; this commit is their state at the end of that session, unchanged. - ADR-007: tallyman owns result materialization (no xorq cache nodes in builds); Buckaroo is a displayer; every diff is built as an entry. - ADR-008: every file carries a visible __row_order column and every page request sorts by it. - ADR-009: materialization runs single-partition, and result_digest is a digest of the snapshot's content. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… ADRs - ADR-009 D6 (new): create runs the query twice and compares digests, so a non-reproducible recipe is known from birth and its file is pinned; a cheap entry gets the same check and is materialized if it fails. Adds a Testing section. The entry's schema is read from the file. - ADR-007 D11 (new): one write at a time per project, by taking the existing project file lock around every write; replaces the per-entry lock. Two tallyman servers on one project is unsupported (#183). - ADR-007 D12 (new): files are deleted only by an explicit user action; the startup warm-up stops rewriting deleted files; no disk budget yet. - ADR-007 D6: tallyman stops remembering Buckaroo sessions and re-posts every time, with a session id derived from project, hash and view kind. - ADR-007 D9: the agreed order of work. Nothing starts before review. - ADR-007 open question 1: whether two kinds of entry survive. Unanswered. - Testing sections for ADR-007 and ADR-008, marking which tests are red on main today. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An adversarial review of the three draft ADRs, and Paddy's decisions on its findings (2026-09-20). Still Proposed; nothing is implemented. - ADR-007 D10 (every diff is built as an entry) moved out to #188, so the set stays about the core structure of the cache. D10 is kept as a stub so that references to D11 and D12 stay valid. The live diff is recorded as the one known exception to the governing rule. - ADR-007 D5: the verify sweep is not a caller of ensure_materialized; it reads and never writes. The ordered-copy gap is recorded as accepted. - ADR-007 D6: the session id is derived from project and content hash (closes #172); the exact condition under which Buckaroo skips a repeat /load_expr; deleting a snapshot ends no session; an unfaithful heal posts force_reload, since evict_session worked by forgetting a record that D6 removes. - ADR-007 D11: three limits of the project lock (per-thread re-entrancy, recalc granularity left open, reads not covered, #118). #186 tracks the waiting it causes. - ADR-007 D12: a file is written only because something is about to read it. The warm-up sentence now states the precise condition. - ADR-007 D2: memoizing the read stops tables piling up, not footer reads. - ADR-008 D2, D7: CSVs do not already work this way. The intermediate is keyed by path and overwritten in place (#168), so D7 cannot land before that fix. CSVs go through source identity and the ordered copy is built from the content-addressed clone. - ADR-008: "repeatable pages" asserts the exact rows; a new test that an edited CSV forks the hash; memory at depth recorded under Consequences as a performance matter, deferred. - ADR-009 D1, D3: single-partition execution does not make an ungrouped float total a function of the rows alone; it depends on the parent file's row-group layout (#187). Row-group size and batch_size are pinned and the manifest records a snapshot format version. - ADR-009 D6: the cheap-entry half moved to #185; the limits of running twice are stated, and the #88 lint is mentioned. - ADR-009: four stale cross-references to ADR-008 fixed. - All three Testing sections: normal TDD. Every test goes in the failing-tests commit; a test of a missing function fails on import. New evidence scripts, each runnable from a clean temp dir: scripts/spike_csv_source_identity.py (ADR-008 D2, D7), scripts/spike_float_layout_digest.py (ADR-009 D1, D3), scripts/spike_deep_page_memory.py (ADR-008 Consequences). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Keep two kinds of entry (ADR-007 open question 1). ADR-007 gains D13 (a file is cache only if ensure_materialized can re-create it) and D14 (a reset leaves compute_cache alone), closes the ordered-copy gap in D5, and adds the klass hot-reload fix to D6. ADR-008 rewrites D4 as a three-part test for cheap, corrects D6's three-way join claim, and adds D10 (natural order on every order_by), D11 (hoist a non-final sort) and D12 (a raw parquet read is a build error). ADR-009 says how a loaded build gets onto the single-partition connection and extends the format version to ordered copies. Adds seven evidence scripts under scripts/. Items not yet confirmed by Paddy are marked as such in the ADR text. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
One commit of failing tests for the whole cache redesign, so every test is seen red on CI before the change lands (ADR-007 D9, step 1): - ADR-007: builds carry no cache nodes, snapshot path from the content hash, chaining as a bare read of the parent's snapshot, one writer (materialize), ensure_materialized, re-creation of each class of file, the Buckaroo hand-off (derived session ids, view build, forced reload, klass reload), one write at a time per project, reset leaves compute_cache alone, the xorq-cache sentinel. - ADR-008: __row_order on every file, the cheap/worthy allow-list, build errors for a dropped or assigned column, joins, sort grafting and hoisting, repeatable pages, CSV roots and #168, raw parquet reads. - ADR-009: the content digest, the pinned snapshot format, the single-partition connection, create runs the query twice, engine versions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…mpute_cache alone ADR-007 D11, D13, D14 and the manifest fields ADR-008 and ADR-009 record: - project_lock is public and re-entrant per thread, so a promote can build and then checkpoint, and a build can materialize, while another thread or process still waits. - Manifest loses snapshot_key and gains reproducible, nonreproducible_columns, snapshot_format, engine_versions and ordered_copies. - reset_to no longer records, prunes or restores compute_cache/ (no compute_cache.jsonl). Source clones no surviving entry refers to move to the bullpen instead of being deleted, and a reset forward copies them back. - ensure_cas_path clones to a unique temp name, so two builders cloning one source do not share one. - paths: entry_view_build_dir for the view build a worthy entry's grid is handed; buckaroo_sessions_path is gone (tallyman keeps no session record). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ADR-007 D1 to D5 and D7, ADR-008 D2 to D4, D6, D7 and D10 to D12, ADR-009 D1 to D4 and D6. - No build holds a xorq cache node. A recipe that calls .cache() is a build error; rewrite_cache_dirs, classify_build, snapshot_key, entry_graph_expr and the source-read injection are gone. - materialize is the one writer of snapshots: a single-partition connection, a pinned layout (zstd, 1,048,576-row groups, page index), a last __row_order column, atomic replace under the project lock. A create runs the query twice; a recipe that is not reproducible is recorded and its file is pinned. - ensure_materialized makes every file an entry reads exist before anything runs: snapshots by recursion, ordered copies of sources from their clone with the reader options in the manifest, clones from the live source while the bytes match. - Every source enters through an ordered copy under compute_cache/, keyed by content digest and reader options; tallyman_read_csv no longer sorts and its column is __row_order. A raw parquet read is a build error. - Cheap or worthy is one allow-list test decided at build and recorded in the manifest. A cheap entry must keep __row_order, assignment to it is an error, every order_by gets the natural order as tie-break and a non-final order_by is hoisted, and a three-way join in one recipe gets an instruction. - result_digest is an arrow-sha256 content digest of the file read back. A heal mismatch is attributed to an engine change when the recorded versions differ, and stays loud and pinned. - Chaining a worthy parent is a bare read of its snapshot, so a child's identity follows its parent's. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… pin what cannot be re-made ADR-007 D6 and D12, ADR-008 D5 and D8, ADR-009 D6. - load_session runs ensure_materialized first, then posts /load_expr with a session id derived from the project and the hash. A worthy entry is handed a view build of its snapshot, a cheap entry its own build. Tallyman keeps no session record; a klass reload posts /reload_expr per entry and treats a 404 as not open; an unfaithful heal forces a reload of the open grid. - Every /load_expr names __row_order as the row-order column. - /api/data pages by ORDER BY __row_order. - The startup warm-up loads cheap entries' builds and writes nothing. - The Cache page lists every snapshot file (a file whose entry is gone is an orphan row), marks a snapshot pinned when it cannot be re-created faithfully, and refuses to delete it with a reason. - A diff drops __row_order from both sides. The MCP tool descriptions explain the column and the build errors around it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The API now marks a snapshot pinned (with a reason) when it cannot be re-created faithfully, and lists a file whose entry is gone as an orphan. The page shows both, disables delete for a pinned file, and shows the reason when the server refuses. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rewrites the sections of docs/system-contract.md that ADR-007, ADR-008 and ADR-009 change: xorq's cache nodes become background, the content hash covers ordered copies and parent snapshots, the manifest table, worthiness as one recorded verdict, row order, materialization and ensure_materialized, the content digest, the write and read paths, chaining, the Buckaroo hand-off, reset, verification (with the engine-change row), and a sixth invariant. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
#90's guard: a half-built or pruned entry passes the build-dir check and has no manifest, and its page must still be served rather than 500ing. cache_worthy now falls back to whether a snapshot is on disk when the manifest is gone, since a snapshot can only have been written for a worthy entry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Most existing tests failed on the redesign for one of two reasons the ADRs chose on purpose: - ADR-008 D3: a cheap recipe whose select list drops __row_order is now a build error, so those recipes keep the column, and exact column and row-key expectations now end in __row_order (about 67 tests). - ADR-008 D12: a raw xo.deferred_read_parquet is a build error, so recipes read the file with read_project_file (about 48 tests). test_connect_shim_matches_xorq_api_connect no longer compares xorq's snapshot keys, which are gone; it checks the shim gives the same backend kind and profile and that a materialization through it writes the same data. compute_cache.jsonl leaves the expected tracked set (ADR-007 D14). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
architecture, caching, expression-lifecycle, mcp-server, reactive-recalc, the README and the explanation doc no longer describe xorq cache nodes, the session map, compute_cache.jsonl or original_row_order as current. They cover worthy and cheap entries, snapshots and the content digest, ordered copies, ensure_materialized, row order, the view build and derived session ids, the project lock, and what a reset does to compute_cache and the source clones. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ADR-007, ADR-008 and ADR-009 are implemented in #189: their status lines say so and an Implementation notes section in each records where the code differs from the text (the ordered-copy key and directory, the manifest's ordered_copies, the explicit three-way join check, hoisting only the author's keys, nested types in the digest). ADR-004, ADR-005 and ADR-006 note what the redesign amends or supersedes. The datafusion scan-split threshold is 10,485,760 bytes, not 1 MiB (ADR-008 D9). scripts/spike_sort_grafting.py uses classify_expr now that _is_worthy_expr is gone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Deleted, because the mechanism they protected is gone: - xorq cache nodes in builds, and the lockstep between classify_build and _is_worthy_expr (ADR-007 D1, ADR-008 D4): test_scalar_udf_is_worthy_in_lockstep, test_worthiness_disagreement_falls_back_to_recompute, test_should_cache_read_treats_json_like_csv_not_exempt, test_self_heal_warning_degrades_to_execution_when_classify_build_raises. - xorq's shared temp file and a peer process winning its rename (ADR-007 D4, D11): test_cross_process_heal_reads_landed_snapshot_else_reraises. - Buckaroo's session record and file (ADR-007 D6): the session file round trip, location and persist tests, test_startup_prunes_entries_for_missing_builds. - compute_cache pruning on reset (ADR-007 D14): the three prune tests. The new rules are in test_reset_keeps_compute_cache.py. - Buckaroo replaying a build cold (ADR-006 D4, ADR-007 D3 and D5): test_chained_child_build_heals_parent_without_preheal. Rewritten against the new mechanism, keeping what they protected: self-heal of a deleted snapshot and its verification against the recorded content digest, lineage-faithful reads, cold compute_cache reads, the loud unfaithful heal, the result-plan memo after a reset, CAS reads after an edit or a deleted source, Buckaroo unit-level open, restart and concurrency behaviour, and the klass reload (one request per entry, a 404 means not open). The other tests changed only for the two deliberate build rules. The 10 MiB scan-split threshold replaces 1 MiB in the digest probe test (ADR-008 D9). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…not record it Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ir the page-load profiler recreate_ordered_copy looked for the copy's record only in the manifest of the entry being opened. An entry that reached a cheap entry's graph by a path that records nothing (a promoted diff, cached_result_expr in a recipe) could not survive the loss of compute_cache/. The record now comes from the owner's manifest, else from any entry in the catalog: the build that first reads a source records its copy, and entries are never deleted. scripts/profile_pageload.py imported the removed result_cache.classify_build, found entries by the retired result.parquet, read the old aliases.json, and paged over the bare build without making its files exist. It now reads the worthiness verdict from the manifest and shares entry discovery, alias lookup and a new _paged_build helper with the Tier-B harness. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review pass (
|
…ow-order-and-membership Resolves the conflict in src/tallyman_xorq/diff.py with #242: full_diff drops the row-order columns first (an expression change, no execution) and runs buckaroo's three diff helpers under execution_lock(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-hardening Resolves the conflict in src/tallyman_mcp/server.py with #241: keeps this branch's _record_import_failure and takes #241's _entry_url, which resolves the companion's URL at call time and gives None when no server holds the data dir. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…implemented Brings in #242, #244, #245 and #241. Resolves docs/installing.md: keeps this branch's environment table (with TALLYMAN_COMPANION_URL now read from the data dir's server.lock) and its troubleshooting list, with #241's two bullets in place of the old port-7860 one, and without the stray tags this branch had already removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs: describe the system as built with ADR-007, ADR-008 and ADR-009
The guard counted every name, attribute and parameter under src/ as defined, so a message naming a tool that does not exist passed whenever a variable was spelled the same way. Its scan moves into _unknown_catalog_names so a test can run it over a small tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…failed build The steps after catalog_import_source's import shared one try, so carrying the entry's config forward failing skipped the new_entry notification and the recalc, and the source's dependents stayed on the old version's rows. The failure was recorded as a build_error with no hash, so the Log showed a failed build for an import that was committed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ot a failed build The notebook append, the config carry-forward and the recalc each run in their own try, so one failing no longer skips the new_entry notification or the recalc. What failed is recorded once, as an after_import_error event rather than build_error, with a message that says the version was imported and with the new entry's hash, so a dependent left stale is tied back to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…as defined A variable, parameter or attribute spelled like a tool is not something a message can send an agent to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…SIGSEGV Opening a worthy entry's grid, a diff's compare grid and the re-hash after an unfaithful heal each call xorq's build_expr in the companion process. The companion never installs the git-state guard, because catalog writes, which install it, run in the MCP process. So xorq forks a bare `git rev-parse HEAD`, and on macOS, once PROJ is loaded, that child can die with SIGSEGV (the #267 crash). The grid open then fails with "Tallyman could not prepare this entry: CalledProcessError ... died with <Signals.SIGSEGV: 11>" until the companion restarts. The tests put a git that kills itself with SIGSEGV on PATH and xorq's unguarded get_git_state in place, create the companion app, and run each of the three builds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… created The companion now calls install_git_state_guard() in create_app, so its own builds (a grid's view build, a diff's compare build, the re-hash after an unfaithful heal) spawn git without forking, and a git that dies degrades to placeholder provenance instead of failing the build. Before, only catalog writes installed the guard, and those usually run in the MCP process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LICENSE is the text of https://www.gnu.org/licenses/agpl-3.0.txt, unchanged. pyproject.toml declares `license = "AGPL-3.0-only"` with `license-files = ["LICENSE"]`, so the wheel carries License-Expression and the license file. Both private JS packages declare the same SPDX id, and the README says where the license is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(companion): the companion installs the git-state guard, so a grid open cannot die on a forked git
chore: license tallyman under the GNU AGPL, version 3 only
Implements the cache redesign that #184 proposes: ADR-007 (tallyman owns result materialization), ADR-008 (every file carries
__row_order, every page sorts by it) and ADR-009 (digest stability).Stacked on #184. The first four commits are that PR's ADRs, so merge it first and this diff shrinks to the implementation. Draft, like #184.
Status — 2026-09-22: the fix PRs stacked on this branch
This branch is the direction I am taking, and it is not ready for
mainyet. Reviewing it turned up 25 follow-up issues (#183–#211). Rather than reopen this PR later, each fix lands as its own PR into this branch, TDD'd red then green on CI — 605a677 changed the workflow so pull requests intofeat/**run it.Open on top of this branch, all four green and none merged:
materialize(..., publish=False)stages the file under a temp name; the build publishes it afterwrite_manifest, so a failure between the two no longer deletes a good file.unfaithful_heal_digest) instead of being inferred fromerrors.jsonl; a corrupt line inerrors.jsonlis skipped instead of hiding the log. The Cache page labels a snapshot a reset retired.BuildError, and the.digestsidecar is written through a temp file so a reader never sees an empty one.docs/architecture.mdrewritten as the overview doc. Docs and plans only.Merge order: #213, #214 and #215 first, in any order, then #216 rebased — it currently describes those bugs as open in about twenty places.
Still open against this branch
full_diffshows__row_orderas a changed column), the snapshot writer drops any column named __row_order_right, including one the author made #206 with assert_joinable refuses semi and anti join chains over entries — they add no right-side columns, so nothing collides #199 (the right side's__row_orderand semi/anti chains), a build on the companion's event loop freezes the whole UI while it waits for the project lock — no way to show a busy indicator #190 with reload_project_sessions posts /reload_expr once per catalog entry, one after another, from async handlers #201 (builds and session reloads run on the companion's event loop), cache_worthy falls back to "a snapshot exists" when the manifest is missing — a worthy entry that has lost both is served as cheap #204 with _ResultPlan keeps the unused loaded build, and its backend objects, alive in a 256-entry LRU #210 (a manifest-less entry is served as cheap; the plan LRU holds unused builds alive), an unfaithful heal of a worthy parent changes its cheap children's rows under their hashes — only the parent is flagged and refreshed #208 with an unfaithful heal runs its checks and the companion's forced Buckaroo reload while holding the project lock #203 (an unfaithful heal changes cheap children under their hashes, and runs under the project lock), every grid open now posts /load_expr — concurrent opens load twice, and a promoted diff re-runs Buckaroo's stats pipeline on each open #202 (every grid open posts/load_expr).source_digests.jsonwith a single entry, so the next build re-hashes every source; a child pinned to a parent by raw hash is permanently stale on the source axis and reports as an UNEXPLAINED orphan; a recipe resolves the project from theactive_projectfile while the MCP tool builds into the session's project; the SPA ignores six SSE events (entry_added,alias_changed,alias_renamed,display_changed,project_reset,unfaithful_heal).reprcarries a memory address, so the entry's hash forks on every build).What changed
Terms, once: an entry is one catalog computation. A worthy entry is one tallyman writes a parquet file for, called its snapshot, because it does expensive work (an aggregate, join, sort, window function, UDF, union). A cheap entry is a row-preserving plan over one file and keeps no file of its own. An ordered copy is the parquet copy of a source that carries
__row_order. A clone is the copy of a source underdata/.cas/, named by the digest of its bytes..cache()is a build error.rewrite_cache_dirs,classify_build,snapshot_key,entry_graph_exprand the source-read injection are deleted, and a test keepsXORQ_CACHE_DIRempty through a build, a chained child, a view, a delete and a reopen.materialize. It runs the entry's frozen build on a single-partition connection, writes the snapshot in a pinned layout (zstd, 1,048,576-row groups, a parquet page index,__row_orderlast) to a temp name and replaces the file atomically, under the project's write lock. A create runs the query twice; a recipe that is not reproducible is recorded and its file is pinned (ADR-007 D4, ADR-009 D1, D3, D6).ensure_materializedmakes every file an entry's plan reads exist before anything runs: a snapshot by recursing on the hash in its name, an ordered copy from its clone with the reader options in the manifest, a clone from the live source while the bytes still match. What it writes is checked against the recorded digest; a mismatch is loud and pinned (ADR-007 D5, D13).__row_orderis anint640..N-1last column on every snapshot and ordered copy./api/datapages byORDER BY __row_order. A cheap entry that drops the column fails to build with the fix shown; assigning to it is an error; everyorder_bygets the natural order as a tie-break and a non-final one is kept; three-way joins get an instruction; the diff drops the column from both sides (ADR-008).expr.yamlis no longer parsed for it (ADR-008 D4, closes Cache classifier parses xorq build YAML with regex — silent misclassification if the format drifts #12).compute_cache/ordered_sources/. Editing a CSV and re-running a recipe now forks the hash (closes tallyman_read_csv bypasses source identity — content-blind intermediate key, in-place re-materialization, no manifest.sources #168). A rawxo.deferred_read_parquetis a build error (ADR-008 D2, D7, D12).result_digestisarrow-sha256:, a digest of the file's Arrow content read back, so it does not move with the codec, row-group size or pyarrow version. An unfaithful heal names an engine change when the recorded versions differ (ADR-009 D2, D4).entry-<project>-<hash>and tallyman keeps no record of them; a klass reload posts one request per entry; an unfaithful heal forces a reload; every/load_exprnamesrow_order_column(ADR-007 D6, ADR-008 D8).compute_cache/alone and moves clones into the bullpen instead of deleting them, which fixes an entry that failed after a reset back and forward. The project lock is re-entrant per thread (ADR-007 D11, D14).A snapshot's name is now the entry's content hash, which is the same on every machine, so this should also fix #77 (an empty grid on a clone of the project at another path). I did not test it on a second machine.
docs/system-contract.mdand the descriptive docs are rewritten to match. Each of ADR-004 to ADR-009 has an updated status line, and ADR-007, ADR-008 and ADR-009 have an "Implementation notes" section that records where the code differs from the text. The differences a reviewer should look at: the ordered-copy key uses the source digest and not the clone's path, the reader options live in a newmanifest.ordered_copies, a three-way join is refused by an explicit check because ibis no longer raises through the new canonical sort, and hoisting a non-finalorder_byuses only the keys the author wrote.How it was built
f9bb94b: 180 failing tests for the three ADRs in one commit. CI ran it: ruff passed and the fast suite failed with 180 failed and 688 passed, which matches the local run.283c483: ruff, the fast suite (861 passed), the integration suite (7) and the perf report all pass.__row_order, and a raw parquet read is refused. Tests of retired mechanisms (xorq cache nodes, the session map, compute-cache pruning) were deleted or rewritten against the new one; the commit message lists each deleted test and the decision that retired it.Checked locally before pushing: the fast suite (860 passed), the integration suite against a real Buckaroo (7), the on-demand
cache_labsuite (11), a scripted create, revise, cascade, live diff, promote and reset back and forward against a real Buckaroo, and the Cache page in Chromium.Not in this PR
tallyman packshippingcompute_cache/(it now ships the ordered copies too), the primary-key search, the over-broad stat-cache wipes. They change no hash.ensure_materialized, which only checks that the file exists.verify_result_faithfulraises on it and the verify sweep reports it undererrors.After merge
Every worthy entry's hash, snapshot path and digest change, so the corpus has to be rebuilt once (ADR-007 D9).
~/.cache/xorq/result_cacheand the older~/.cache/xorq/parquet/can then be deleted by hand.🤖 Generated with Claude Code