Skip to content

fix(sync): apply finds natural-key rows whose uid was never filled (T13273) - #1922

Merged
kryptobaseddev merged 5 commits into
mainfrom
fix/T13273-natural-key-apply
Oct 7, 2026
Merged

kryptobaseddev merged 5 commits into
mainfrom
fix/T13273-natural-key-apply

Conversation

@kryptobaseddev

Copy link
Copy Markdown
Owner

Task: T13273

Stacked on #1921 (R-4a), which carries the closure widening this PR's convergence test needs.

The bug (pre-existing, from the T12344 applier)

A natural-key row (tasks_task_dependencies, tasks_task_relations, …) keeps uid NULL until the open-time identity fill. The sealer journals it under the natural uid, which it derives from the key (the op carries k). The write API looks rows up by uid only, so:

  • The own echo of every such insert voided on its origin: the row looked UNSEEN, the insert hit the UNIQUE key, and a guard conflict was recorded. The echo was never sequenced and kept its undo. Reproduced on real replicas: A inserts the edge TA→TB, syncs its own echo, and the result is void: 1, conflicts: 1.
  • A rebase could not rewind such a row, so the foreign edge was judged against the un-rewound local one. That caused divergence and spurious dangling-ref voids downstream.

The fix

  • New write-API method adoptNaturalRow(table, uid, localKey). It finds the row with no uid whose local key matches and writes the uid. That is the same derived value the identity fill writes, and capture never fires on the identity column.
  • The applier calls adoptNaturalRows with the op's k, with refs resolved to local keys, at two points: before planning each staged txn, and before rewinding each local txn.

Tests

  • A dependency insert's own echo: it applies on its origin with no conflict, is sequenced applied, the uid fill is not journaled, and the replicas match.
  • A dependency cycle closed through edges neither txn names: the replicas converge on real sealed ops with no identity fill. This is the test dropped from feat(sync): rebase footprints widened by guard and check reads (T13193 R-4a) #1921, now restored.
  • Mutation checks: the adoption at the frame and at the rewind are both killed. Wrapping the adoption in a capture suspension proved unnecessary (the mutant survived), so I removed it.

Locally green:

  • 204 targeted tests (apply/, repair, sealer, apply-intent, identity-fill);
  • tsc;
  • biome on every file changed vs main;
  • gates 3, 28, 36, 37, 38 (--base origin/feat/T13193-footprints) and 40.

🤖 Generated with Claude Code

…13273)

A natural-key row (dependencies, relations) has uid NULL until the open-
time identity fill; the sealer journals it under the natural uid. Lookups
by uid missed it: the own echo of every such insert voided on its origin
with a UNIQUE guard conflict (never sequenced), and a rebase could not
rewind it, so replicas diverged.

The apply now adopts the row first: the row with no uid whose local key
matches the op's `k` (refs resolved) gets its uid (the fill's derived
value; capture never fires on the identity column). Done before planning
each staged txn and before rewinding each local one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from feat/T13193-footprints to main October 7, 2026 01:47
@kryptobaseddev

Copy link
Copy Markdown
Owner Author

Merging at the approved head b2c2b94 (review-hotfix APPROVE merge-only b2c2b94 (clean main merge over 308bcc1); CI: 103 checks, all green).

@kryptobaseddev
kryptobaseddev merged commit e16577a into main Oct 7, 2026
103 checks passed
@kryptobaseddev
kryptobaseddev deleted the fix/T13273-natural-key-apply branch October 7, 2026 02:40
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.

1 participant