plan(#31,#32): fork-impossibility fix — design + failing test#125
Closed
hyperpolymath wants to merge 1 commit into
Closed
plan(#31,#32): fork-impossibility fix — design + failing test#125hyperpolymath wants to merge 1 commit into
hyperpolymath wants to merge 1 commit into
Conversation
#31 (per-entity write lock) and #32 (UNIQUE INDEX(entity_id, previous_hash)) together design the provenance chain so that a forked history *cannot be represented*. Issues #31/#32 frame forks as purely adversarial; that is incomplete. Network-partitioned/replicated honest writers and simulation branches (ADR-0006) are legitimate divergence. A UNIQUE INDEX on (entity_id, previous_hash) does not *detect* a fork — it *rejects the second row at insert time*, discarding honest history. A fork that cannot be written cannot be detected or audited. That is the integrity defect. This is a planning skeleton — design doc + a failing-by-design test. No implementation; the parent session controls merges. Contents: * docs/decisions/0010-provenance-forks-are-first-class.adoc — ADR (estate .adoc default). Decision: forks are first-class. Concretely: - #32: do NOT add UNIQUE INDEX(entity_id, previous_hash). The `hash` PRIMARY KEY (preimage is domain-tagged + covers every field, per ADR-0002) already rejects exact-duplicate rows — that is the correct duplicate guard. Add a NON-unique idx_provenance_predecessor(entity_id, previous_hash) for O(log n) fork detection. - #31: verisimdb_provenance_chain_head (entity_id PK, one head) becomes verisimdb_provenance_chain_heads (PK(entity_id, head_hash), a SET of tips). `append_provenance` keeps BEGIN IMMEDIATE (still serialises racing *duplicate* appends from one node) but removes parent-tip + adds new-tip on linear append; a new `append_provenance_fork(... from_hash ...)` adds a head without removing one. - Detection surface: `fork_points(conn, entity)`; `verify_chain` becomes per-branch (each head -> genesis walk hash-consistent), so divergence is never conflated with tampering. - Data migration: idempotent CREATE-IF-NOT-EXISTS + INSERT..SELECT copy of the head table guarded by a sqlite_master check; old table left for one release (no destructive step ships). The log table is unchanged. Because the unique index is never created, an existing sidecar that already contains a legitimate fork cannot fail to open — a hazard that WOULD exist had #32 shipped first (flagged in the #32 thread). * tests/provenance_fork_test.rs — failing-by-design test. Writes genesis + branch A (supported linear path) + branch B (a second legitimate child of genesis). Asserts both children persist AND the entity records two heads. Compiles against the current public surface; the assertions, not the compile, fail. Verified red on this branch: child_count==2 passes (log keeps both rows) but head_count is 1 not 2 — the single-head table collapses branch B. Exactly the #31 defect, in executable form. (With #32's unique index applied, the branch-B insert would additionally fail with a constraint violation — also encoded in the ADR test plan.) Build/test: lib builds clean (only the pre-existing unrelated gc.rs RetentionConfig warning). New test compiles and FAILS as intended (1 failed, by design). Unblocked by #26 / PR #103 — there is now one ProvenanceEntry and one compute_hash for the fork-aware append/verify to evolve. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Owner
Author
|
Superseded — this plan/test pair already landed via PR #104 ( |
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.
#31 (per-entity write lock) and #32 (UNIQUE INDEX(entity_id, previous_hash)) together design the provenance chain so that a forked history cannot be represented. Issues #31/#32 frame forks as purely adversarial; that is incomplete. Network-partitioned/replicated honest writers and simulation branches (ADR-0006) are legitimate divergence. A UNIQUE INDEX on (entity_id, previous_hash) does not detect a fork — it rejects the second row at insert time, discarding honest history. A fork that cannot be written cannot be detected or audited. That is the integrity defect.
This is a planning skeleton — design doc + a failing-by-design test. No implementation; the parent session controls merges.
Contents:
docs/decisions/0010-provenance-forks-are-first-class.adoc — ADR (estate .adoc default). Decision: forks are first-class. Concretely:
hashPRIMARY KEY (preimage is domain-tagged + covers every field, per ADR-0002) already rejects exact-duplicate rows — that is the correct duplicate guard. Add a NON-unique idx_provenance_predecessor(entity_id, previous_hash) for O(log n) fork detection.append_provenancekeeps BEGIN IMMEDIATE (still serialises racing duplicate appends from one node) but removes parent-tip + adds new-tip on linear append; a newappend_provenance_fork(... from_hash ...)adds a head without removing one.fork_points(conn, entity);verify_chainbecomes per-branch (each head -> genesis walk hash-consistent), so divergence is never conflated with tampering.tests/provenance_fork_test.rs — failing-by-design test. Writes genesis + branch A (supported linear path) + branch B (a second legitimate child of genesis). Asserts both children persist AND the entity records two heads. Compiles against the current public surface; the assertions, not the compile, fail. Verified red on this branch: child_count==2 passes (log keeps both rows) but head_count is 1 not 2 — the single-head table collapses branch B. Exactly the V-L2-L1: per-entity serialisation prevents chain forks (write-path lock) #31 defect, in executable form. (With V-L2-L2: UNIQUE INDEX(entity_id, previous_hash) makes forks structurally impossible #32's unique index applied, the branch-B insert would additionally fail with a constraint violation — also encoded in the ADR test plan.)
Build/test: lib builds clean (only the pre-existing unrelated gc.rs RetentionConfig warning). New test compiles and FAILS as intended (1 failed, by design).
Unblocked by #26 / PR #103 — there is now one ProvenanceEntry and one compute_hash for the fork-aware append/verify to evolve.
Summary
Changes
RSR Quality Checklist
Required
just testor equivalent)just fmtor equivalent)unsafeblocks without// SAFETY:commentsbelieve_me,unsafeCoerce,Obj.magic,Admitted,sorry).envfiles includedAs Applicable
.machine_readable/STATE.a2mlupdated (if project state changed).machine_readable/ECOSYSTEM.a2mlupdated (if integrations changed).machine_readable/META.a2mlupdated (if architectural decisions changed)TOPOLOGY.mdupdated (if architecture changed)CHANGELOGor release notes updatedsrc/interface/abi/andsrc/interface/ffi/consistent)Testing
Screenshots