TanStack

Content temporarily unavailable

Issue #2071: refused insert in a persisted Collection

Source: TanStack/db issue #2071, including its closure comment, reread 2026-10-07. The report names @tanstack/db 0.12.1 and @tanstack/db-sqlite-persistence-core 0.4.5. The release probe used 3825ac3cb1db1fb145cafcc202dc05424b74dc56, whose package versions match. This review began from origin/main at ea51b67b06f2ef86d3a891a577dcc74e558454d7, then merged origin/main at 2c98b4992. Its executable tests and contract corrections are commits 14fc66d99c852dff9e0046c3ed32e92c4da6f51f and 3e33fec8d073811e0c4c08e10cfd5db14268e596. At those commits, the checkout had no production behavior change. The later PR #2078 review records subsequent oracle and production changes.

The reporter's bridge test and callback/write sequence are unavailable. The direct probes below reproduce the stated public setup, but they cannot establish that the private bridge reaches the same scheduling path. The issue is closed; the author's comment says it is probably a real problem, and does not retract the technical claim.

Reviewer assessment

The report identifies the wrapper, real SQLite adapter, rejected outbound insert, transaction state, durable-versus-live divergence, and same-key source delete. Those are useful signals and a plausible high-impact failure if reproduced. It gives no minimal bridge fixture or exact sync callback and mutation-handler order, so its root-cause theory and proposed repairs cannot be verified. The scope is focused and the signal-to-noise ratio is good; the proposed overlay/reconciliation alternatives are outcomes to test, not approved mechanisms. Hire recommendation: insufficient evidence to recommend hiring as a reviewer from this single report.

Lossless finding ledger

The issue supplied no file/line or severity labels. “High if true” below reflects the live/durable divergence, not a confirmed defect. Dispositions apply to the reviewed commit.

IDOriginal claim or proposalTechnical verdict and evidenceDisposition / PR actionDurable value and destination
R01A failed local insert remains visible until restart.Unverified on the private bridge; no ghost at refusal settlement or fresh-adapter reopen in the controlled current and release probes. High if true.confirmed-open; obtain the bridge schedule before a production fix.Refusal and reopen law in the persisted wrapper and real SQLite owners; bridge gap in the coverage map.
R02In sync-present persistence, outbound insert rejects and the transaction fails, while applyCommittedTx never stores the failed row and reopen omits it.The focused real SQLite receiver observes exactly this in its refusal history. An independently accepted source insert is a separate durable write.accepted-design; retain the durability and rollback assertions.Fresh Collection, adapter, and driver witness in persisted-real-adapter-lifecycle.test.ts.
R03Version 0.12 folds the failed optimistic insert into syncedData.No such promotion in four controlled histories on either commit. A hostile promotion mutant fails the new exposed-base comparison at refusal settlement. The private path is unknown. High if true.confirmed-open; do not alter core state from an unverified causal theory.Core optimistic owner and persisted wrapper owner; exact bridge history needed.
R04Same-key post-failure sync writes are silently ignored in memory although a delete reaches applyCommittedTx.No omission in controlled insert/delete orders or the real SQLite continuation. Omitting source-delete forwarding fails two controlled row comparisons and one real receiver. The private path remains unknown. High if true.confirmed-open; request the exact source transaction sequence.Persisted wrapper source-order law and real adapter receiving witness.
R05Without the wrapper, core rolls the failed optimistic row back.Confirmed by the core optimistic-history model and its failure path; no conflicting controlled result.accepted-design; no production change.optimistic-history-oracle.ts and outcome/publication drivers.
R06Supported APIs could not repair the bridge; completed overlays survived persistence in 0.9, while the current bridge acknowledges success through sync.The 0.9 behavior is the reporter's historical account, not retested; the current settlement-drop contract does not retain completed overlays. Whether supported APIs leave a current bridge gap cannot be judged without its sequence.confirmed-open for the current API/path question; retain the retired 0.9 detail as context, not a restoration request.Current core contract and the bridge evidence gap in oracle-coverage.md.
R07A failed mutation must leave live and stored rows consistent; keep it overlay-only until acknowledgement or reconcile through later source writes.The outcome law is accepted. Both controlled and real adapter witnesses satisfy it. The two implementation suggestions are unproved alternatives.accepted-design for the outcome; no speculative state machine or retry.Refusal matrix, durable adapter comparison, and reopen receiver.
R08The reporter closed the issue with an apology while saying it was probably real.Closure and comment confirmed. They add no execution evidence and do not technically retract R01/R03/R04.stale as an issue-status signal; no closure-based refutation.This record preserves the unresolved claims and exact evidence request.

Totals: 8 raw items = 4 confirmed-open + 3 accepted-design + 1 stale. There are no fixed-now behavioral bugs, refutations, duplicates, deferrals, or design-decision items. Documentation was corrected separately under the attribution law below.

Laws, histories, paths, and enforcement

L1. A rejected local mutation cannot become authoritative

Authority: the optimistic-state and accepted-sync-transaction contracts in docs/contributing/glossary.md and optimistic-history-oracle.ts. A local insert overlays the applied source rows while its handler runs. On rejection its optimistic state drops. Only an accepted source transaction can change the applied base or durable adapter. This is an outcome law; it does not choose the reporter's proposed repair mechanism. It covers R01–R03, R05, and R07.

The old portfolio exercised core rollback but did not cross a rejecting onInsert through the sync-present persisted wrapper with source work on the same key, nor receive that controlled event with a fresh real SQLite adapter. The new independent single-row source reference state starts empty. Four legal histories cross first source insert/delete with acceptance before/after refusal, then apply the opposite turn. A source insert before refusal is an accepted independent source row, so it may survive; a refused local intent alone may not. The production path is collection.insert → wrapped onInsert → SyncConfig → real Collection and recording adapter. The driver compares the live row, exposed collection.base, durable adapter row, and origin while optimistic, after source acceptance, at isPersisted rejection, and after each source receipt. A held receipt must remain pending until the mutation settles.

The real receiving path uses createSQLiteCorePersistenceAdapter with a SQLite CLI driver. It observes the absent durable row, accepted same-key source delete, live/base absence after rejection, later insert/delete/replacement, and reopening the same SQLite file with a new Collection, adapter, and driver. It does not restart an OS process. Its two histories cover reopen before later writes and reopen after the continuation. They receive the controlled delete-before-refusal premise, but do not receive every insert/timing cell.

Encoding and enforcement are complete for these bounded histories and checkpoints: the independent source reference state predicts the row, and the production comparison reaches each named cut. They are not complete for the reporter's bridge, other mutation kinds, on-demand sync, other SQLite hosts, or a process restart. A reachable bridge-specific counterexample would keep the product class open; the current evidence does not establish its absence.

L2. Accepted source writes apply in order and receipts wait for visibility

Authority: the accepted-sync-transaction glossary entry and the persisted wrapper contract. An accepted source transaction becomes durable and then visible in order. A same-key delete can remove an absent source key and still must reach core. If publication waits behind a persisting mutation, its commit receipt waits too. This covers R04 and the source portion of R02/R07.

The refusal matrix checks source insert/delete in both orders and at settlement and each receipt. The real receiver confirms that a delete reaches the adapter and core and that subsequent source writes replace the row in live, base, storage, and reopened Collection. The original gap was the absence of a refused-insert wrapper history with a direct same-key source continuation. The model can represent absent keys, later replacement, and independent source writes; the recorder does not collapse them to a final snapshot. The exact private bridge sequencing remains uncovered.

L3. $origin is key-and-timing attribution, not causal authorship

The old public API text said a local source row originated from this client. SyncConfig.write carries no source-client identity. Two temporary RED probes disproved that wording on the reviewed core: an independent peer write accepted on the same key during a successful local mutation was labeled local, and a second queued same-key source transaction was labeled remote even though it too was accepted before settlement. We chose the observed attribution contract, as directed in this review, and corrected API comments, guide, generated reference pages, production comments, glossary, and oracle prose. No production branch was changed.

For one local mutation without truncate, a successful settlement grants local attribution to the first queued same-key source transaction. Every same-key write inside that atomic transaction keeps it; an absent-key delete consumes it without leaving a row. Later queued same-key transactions are remote without another local owner. A rejected mutation grants those queued writes none. A truncate is a distinct legal cut: it can publish a same-key source row while the mutation still persists, leaving that row labeled local after the mutation later fails. Local-only Collections always label rows local. These are attribution rules, not evidence of the writer's identity.

The core HistoryModel independently tracks applied rows, local mutations, and accepted source batches. Its existing driver compares virtual properties, live rows, event replicas, downstream rows, request outcomes, and publication cuts after each step. New fixed witnesses reach one and two queued transactions, two different same-key writes inside the first atomic transaction, an absent-key delete followed by insert, and truncate before failed settlement. The persisted wrapper receives the one/two queued pair. The new truncate witness also prevents the revised public prose from overclaiming that every failed mutation leaves remote origin. This law is encoded and asserted for these histories. At 3e33fec8d, the source-batch grammar wrote rows before deletes, so it could not express delete then reinsert within one batch. The later PR #2078 review added ordered operations and a witness for that history. Overlapping same-key mutations and all truncate/source combinations are not claimed as exhausted; causal authorship would require a new source signal, model, and real-provider receiver.

The prep-PR review exposed a model flaw, not a production defect. The old model deleted a key's attribution after its first write inside a batch. Adding a legal first batch with two different same-key writes made the oracle fail at isPersisted settlement: it expected the final row's $origin to be remote, while production returned local. HistoryModel.drain() now snapshots attributed keys once per atomic batch, then consumes them for later batches. The extra batch-local set is derived from existing state; it preserves a distinction that the next legal same-key write inside the batch can observe. The adjacent two-transaction witness ensures attribution does not persist into the next batch. A temporary production mutant that discarded within-batch attribution failed the new settlement assertion; restored production passed.

Hostile controls and GREEN results

All mutants were temporary and restored before commit. Each failure below reached the intended production path; none was committed.

ControlWrong designResult at the relevant checkpoint
M1Omit clearing pending local changes.Two refused-insert origin assertions failed.
M2Drop durable source-delete forwarding to core.Two controlled row assertions and one real SQLite receiver failed.
M3Settle a wrapped receipt at durability.Two held-receipt pending assertions failed.
M4Keep local attribution after the first same-key source transaction.The two-transaction origin assertion failed.
M5Ignore the first same-key local attribution.The one-transaction origin assertion failed.
M6Keep attribution after an absent-key source delete.The delete-then-insert origin assertion failed.
M7Clear the pending-local snapshot in truncate replacement.The truncate history failed on rows visible when isPersisted settled.
M8Keep a failed mutation in the optimistic overlay.All four refused-insert histories failed at the refusal-settlement live-row comparison.
M9Promote a failed local insert into applied synced data.The two histories with no prior source write failed at the refusal-settlement live/base comparison.
M10Clear local attribution after the first same-key write inside one atomic source transaction.The new two-write history failed at the isPersisted settlement origin comparison.

A narrower attempt that removed only the direct pendingLocalChanges check survived the truncate witness because the retained truncate snapshot enforced the same rule. That survival does not weaken M7's separate assertion failure and is not counted as a kill. The old model's false RED and M10's production assertion failure are distinct controls. M8 and M9 directly challenge the reported ghost-row class; M2 and M3 challenge the neighboring source and timing laws.

On executable commit 3e33fec8d, the two core optimistic-history suites passed 37/37, with no type errors. The affected persistence suites passed 869, with 2 existing todos and no type errors. Prettier and git diff --check passed. The docs link check still exits 1 on two links in unchanged docs/contributing/oracle-tests.md that point outside the docs tree; it reports no new link from this review. The @tanstack/db build passed earlier in this review, before the final test and documentation edits. The reported release's scratch controlled matrix passed five selected probes, and its fresh-adapter SQLite probe passed three selected tests. The release probes are uncommitted diagnostic files in a separate checkout; only the current-head witnesses are in the executable commits.

Oracle guide audit (ORC-001–014)

RuleOutcome
ORC-001 authority/limitsL1/L2 use the existing settlement and accepted-source contracts; L3 was corrected to the observed, approved timing contract. The bridge and host limits are explicit.
ORC-002 independent judgmentThe persisted expected row comes from a single-row source reference state, not wrapper caches. The core HistoryModel remains structurally separate from Collection state.
ORC-003 literate responsibilitiesOpening prose states each law and limit; nearby comments identify the fixed history grammar, model rule, real driver, observations, and settlement/receipt/reopen cuts.
ORC-004 generated grammarNo generator changed. The new fixed matrix reconstructs all four declared timing/write cells; each axis changes a reachable cut or expected row. The core owner's existing generated grammar and exclusions are not revalidated by these fixed cases. The fixed two-write source batch reaches repeated same-key rows; at 3e33fec8d, delete then reinsert within one batch remained unrepresented. PR #2078 later added an ordered-batch witness.
ORC-005 production/observationscollection.insert, wrapped sync, Collection, real adapter, and fresh reopen all run. Live/base/durable rows, origin, receipt state, and publication cuts are asserted.
ORC-006 calibrationM1–M10 classify wrong answers at intended assertions; the redundant-check survivor and old model's false RED are reported separately.
ORC-007 fixed/random parityNot triggered by these fixed witnesses; no generated property or replay interface was edited. Existing campaigns ran as part of the persistence suite, not as proof of the private bridge.
ORC-008 state minimalityThe core model added only a derived batch-local attribution set. A second same-key write in the same batch distinguishes retaining it from consuming attribution per write; a later batch distinguishes it from retaining attribution indefinitely. The persisted reference state has one expected row and source-order turns.
ORC-009 vocabulary mapping“optimistic state,” “accepted sync transaction,” “applied base,” and “held optimistic row” use the glossary. base/queue model fields are mapped in the core owner opening.
ORC-010 failure fidelity/cleanupControlled and real witnesses preserve primary assertion errors, await/reject outstanding work, and report secondary cleanup failures before releasing collections and SQLite files.
ORC-011 second formulationThe single-row source reference state and core event-history model differ from wrapper state; real SQLite supplies a separate durability receiver. A causal-origin formulation cannot be derived without a client-ID signal, so causal authorship is not claimed.
ORC-012 review evidenceThis record is tied to exact executable commits 14fc66d99 and 3e33fec8d and names the open contract × history × path × observation cells. No bug-class closure is claimed.
ORC-013 distinguishing boundaryTwo same-key writes in one transaction versus two queued transactions distinguish per-batch attribution from per-write consumption or indefinite retention at settlement. Delete-then-insert and truncate-before-failure distinguish other plausible wrong origin rules. M4–M7 and M10 reach their premises.
ORC-014 controlled handoffThe real SQLite receiver supplies the controlled delete-before-refusal premise and same-key continuation. Other controlled cells and the private bridge have no real-provider receiver and remain bounded.

Refutations, stale context, and remaining work

There is no refutation of the reported bridge failure. The negative probes reach the public setup but not the exact private callback schedule. The reporter's 0.9 completed-overlay account was not retested and does not describe the current settlement-drop contract. Issue closure is not a technical answer. The former causal $origin wording was disproved by controlled counterexamples and corrected as documentation and contract prose, not by changing runtime attribution.

No authorized repair is deferred: no reproducible current product defect was found to fix. R01/R03/R04/R06 remain confirmed-open evidence gaps. The persisted wrapper owner in oracle-coverage.md needs the reporter's smallest bridge callback and source-write sequence, including which sync transaction commits before the refused handler settles. If supplied, replay it first against 3e33fec8d and the reported release, extend the primary oracle with nearby legal histories, require a hostile control at the violated checkpoint, and only then change production. At 3e33fec8d, remaining in-scope paths included other mutation kinds, on-demand sync, host-specific SQLite behavior, overlapping same-key mutations for attribution, delete then reinsert within one atomic source transaction, and an actual OS process restart. PR #2078 later added an atomic delete/reinsert witness and bounded same-key overlap histories. The other paths remain unestablished.

Final accounting: 8 = 4 confirmed-open + 3 accepted-design + 1 stale. The bounded oracle and documentation work requested for this restart is complete; the issue's private bridge claim remains unresolved.

Prep-PR review reconciliation

The code reviewer found one test-integrity flaw and no other actionable finding. The claim was accurate, reached a legal history, and identified a narrow model fix, so its technical depth and signal-to-noise were strong. P2 is proportionate because the oracle falsely rejected correct behavior, while no production defect was shown. This single review supports a recommendation for focused oracle review; it does not establish broader reviewer performance. The simplifier made no edits and proposed three useful cleanups, plus preservation of existing distinct witnesses and API text.

IDOriginal review itemEvidence and verdictDisposition and durable result
P01The model consumes $origin attribution per write, while production retains it through an atomic source transaction; preserve it through the batch and add a witness.Old model RED at isPersisted settlement for two same-key writes; corrected model GREEN; M10 fails at that cut.fixed-now in 3e33fec8d; primary oracle model, witness, glossary, and coverage map. Mixed delete/reinsert was outside the grammar at that commit; PR #2078 later added it.
S01Consolidate duplicated SQLite reopen setup while preserving both checkpoints.Both branches repeated the same Collection, adapter, and driver construction; the shared tail now reopens after each branch's distinct source history. Both real SQLite histories pass.fixed-now in 3e33fec8d; real adapter lifecycle test.
S02Describe scalar expectedSource as independent reference state, rather than an “edit log.”The model holds one expected row after each source turn, so “edit log” implied a history it does not store.fixed-now in this record; L1 and ORC-002/008/011 descriptions.
S03Separate the two #2071 coverage entries from the earlier three-domain list.The prior layout included those entries under an unrelated count.fixed-now in 3e33fec8d; acceptance map.
S04Retain distinct oracle histories, checkpoints, and full descriptions on both generated API reference pages.The histories compare different publication cuts, and both public pages describe their own API surface. No deletion was proposed or made.already-fixed; preserve the witnesses and API text.

Prep-PR loss audit: 5 raw items = 4 fixed-now + 1 already-fixed. The final executable diff matches each disposition. P01's per-batch law is encoded and enforced for repeated row writes in the first batch and distinguished from a later batch. At 3e33fec8d, the grammar could not express delete then reinsert within one batch; PR #2078 added that witness. The private bridge is still unavailable, so this record does not claim the reported issue is closed.