fix(purge): #886 name every store purge leaves deleted, with its own restore cost - #894
Merged
Merged
Conversation
…restore cost `purge` deletes five derived stores and rebuilds two, so three are left deleted -- and the warning named one. `findings.db` and `insight_questions.db` were destroyed in silence. In the reported session that cost 11 persisted contradiction verdicts, 9 edge suggestions and 7 identity adjudications, minutes after `contradictions` reported "11 of 11 candidate(s) served from persisted findings; 0 judged fresh". The three restore costs are genuinely different, so one shared "run `openkos reindex`" line would misprice two of them: a reindex restores no findings verdict at all, and the question-embedding cache needs nothing run. - One structure pairs each dropped store with its own cost. The sidecar sweep, the count and the notice all walk it, so a fourth store cannot reach the delete set while missing from the disclosure. - A store is reported only when this purge actually DESTROYED it: it existed before and is verifiably gone after. Absence alone is not loss -- a workspace that never ran `curate` has no `findings.db` to lose -- and a failed `unlink` must not be announced as a drop. - The existence probe cannot raise. `Path.exists()` re-raises EACCES, and these probes run after the irreversible rewrite, so an unguarded one would crash away the entire success report. It fails CLOSED: a store whose absence cannot be verified is not claimed as destroyed. - Orphan `-wal`/`-shm` sidecars are swept, but only for stores that actually went. Sweeping the sidecars of a live database is worse than litter: a `-wal` holds committed pages not yet checkpointed back. - The disclosure is emitted from a `finally`, so post-erasure bookkeeping failing cannot swallow the only record of what was destroyed. CORRECTION to the issue: it states purge destroyed "the operator's own recorded rulings (two declined identity merges)". It does not. All three `findings.db` tenants hold MACHINE-computed verdicts, while a `--decline` or `--keep-distinct` ruling is written under the bundle's decision subtree and committed with the bundle. The notice says so, qualified -- a ruling naming a purged concept IS expunged in the same rewrite pass, which is the erasure working, not a gap. Review receipt review-34230384f7c253bf, four lenses, APPROVED with zero corrections consumed, over six candidates all fixed pre-capture. Closes #886
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The defect
openkos purgedeletes five derived stores and rebuilds two, so three are left deleted — and the warning named one.findings.dbandinsight_questions.dbwere destroyed in silence. In the reported session that cost 11 persisted contradiction verdicts, 9 edge suggestions and 7 identity adjudications, minutes aftercontradictionsreported11 of 11 candidate(s) served from persisted findings; 0 judged fresh.#142's own justification for the vectors warning — "warn every time so an operator is never left assuming dense retrieval is still intact" — was never applied to the other two.
Why one line would not do
The three restore costs are genuinely different, so a shared "run
openkos reindex" would misprice two of them:vectors.dbopenkos reindex(#698 wording preserved)findings.dbcontradictions/adjudicate/suggest-relations.reindexrestores none of them.insight_questions.dbWhat changed
curatehas nofindings.dbto lose), and a failedunlinkmust not be announced as a drop.Path.exists()re-raisesEACCES, and these probes run after the irreversible rewrite, so an unguarded one would crash away the entire success report. It fails closed: a store whose absence cannot be verified is not claimed as destroyed.-wal/-shmsidecars are swept — but only for stores that actually went. Sweeping the sidecars of a live database is worse than litter: a-walholds committed pages not yet checkpointed back.finally, so post-erasure bookkeeping failing cannot swallow the only record of what was destroyed.Correction to the issue
The issue states purge destroyed "the operator's own recorded rulings (two declined identity merges)". It does not, and a test now pins that. All three
findings.dbtenants hold MACHINE-computed verdicts, while a--declineor--keep-distinctruling is written under the bundle's decision subtree and committed with the bundle.The notice says so — qualified. A ruling naming a purged concept is expunged in the same rewrite pass, which is the erasure working, not a gap. An unqualified promise would read as the erasure having missed something.
Review
Receipt
review-34230384f7c253bf, four lenses, APPROVED with zero corrections consumed, over six candidates all fixed pre-capture. The rounds found, among others:unlinkhad failed;Declared, not fixed
A TOCTOU between the delete and the sweep's re-check was raised as CRITICAL and rejected: this is a single-process CLI operating on a local workspace during an already-irreversible operation, with no concurrent writer to race. The fail-closed probe means an unverifiable state is treated as "still present" either way.
Verification
5761 passed, 1 skipped · coverage 96.80% (gate 90) ·
ruff check,ruff format --check,mypy .clean over 275 files · 36/36 harness self-tests.Closes #886