Skip to content

fix(sync): a row-uid fill never captures a stray K op (T13311) - #1979

Merged
kryptobaseddev merged 2 commits into
mainfrom
fix/T13311-uid-k-capture
Oct 10, 2026
Merged

kryptobaseddev merged 2 commits into
mainfrom
fix/T13311-uid-k-capture

Conversation

@kryptobaseddev

@kryptobaseddev kryptobaseddev commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Summary

T13311. With row uids on by default (#1964, T13305), every insert of a minted row under sync.capture also captured a K (re-key) op: [K,I,U,D] instead of [I,U,D].

Root cause. The per-connection TEMP fill (installRowUidTriggers) sets uid and then birth_fp in two UPDATEs. By the second, OLD.uid is set, and _sync_cap_<t>_k's OLD.birth_fp IS NOT NEW.birth_fp read the birth_fp NULL -> value fill as a re-key.

Decision (journal spec v11.4, §2.3, recorded via cleo docs update). No stray K at all, rather than a K the sealer must recognise and drop. The K trigger counts a birth_fp change only when the old value was set: OLD.uid IS NOT NULL AND (OLD.uid IS NOT NEW.uid OR (OLD.birth_fp IS NOT NULL AND OLD.birth_fp IS NOT NEW.birth_fp)). _f alone patches the filled identity into the I, in both trigger orders. This keeps the S2 rule "identity-fill updates capture nothing". A value -> value or value -> NULL birth_fp change is still a K. Existing stores get the new trigger text at the next open (installCaptureTriggers replaces any trigger that differs).

Changes

  • packages/core/src/store/sync/capture.ts: K trigger condition.
  • capture.test.ts, sealer.test.ts, repair.test.ts (the AC), plus rewriters-capture.test.ts and recursive-triggers-audit.test.ts: the CLEO_ROW_UID_FILL=0 pins are removed. (trigger-suspend.test.ts keeps its single-test pin. That pin is a deliberate rollback-under-kill-switch case.)
  • New __tests__/older-build.ts asOlderBuild(): tests that need NULL-identity rows (sealer step 0, the repair "without uid" reason, the stand-in fill order test, the raw bracket rebuild) drop the connection's TEMP fill triggers and reinstall them afterwards, as an older build would.
  • New test: the real per-connection fill gives exactly one I carrying the live uid and birth_fp with no K, in both orders. A birth_fp value -> value change is still a K.

Verification

  • Run with row uids ON: capture, sealer and repair (103/103); rewriters-capture and recursive-triggers-audit (6/6); display-id-alias, row-identity-heal, apply-intent, identity-fill, remap-pending, trigger-suspend, journal-gate-b and write-actor-e2e (104/104).
  • Mutation checks:
    • Restoring the old K condition fails 7 tests, including [K,I,U,D] and [K,I].
    • Dropping the birth_fp re-key term fails the new test's K assertion.
  • pnpm run typecheck (tsc -b), pnpm run build and biome on the diff set pass.
  • Gates pass: 39 (startup graph), 32 (skill coverage), 38 (sync write invariants), 36 (sync schema).

Notes

🤖 Generated with Claude Code

https://claude.ai/code/session_01VjjTKbQXyCFdkLBSeuyKLt

With row uids on by default (T13305), every minted insert under
sync.capture also captured a K: the per-connection fill sets uid, then
birth_fp, in two UPDATEs, and _sync_cap_<t>_k read the second one
(birth_fp NULL -> value, uid already set) as a re-key. The K trigger now
counts a birth_fp change only when the old value was set; _f alone
patches the filled identity into the I, in both trigger orders.

capture, sealer, repair, rewriters-capture and recursive-triggers-audit
tests run with row uids on (their CLEO_ROW_UID_FILL=0 pins removed).
Tests that need NULL-identity rows write as an older build through the
new asOlderBuild helper. Journal spec v11.4 records the decision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VjjTKbQXyCFdkLBSeuyKLt
Base automatically changed from feat/T13305-row-uid-default-on to main October 10, 2026 04:14
@kryptobaseddev
kryptobaseddev merged commit 2238dc9 into main Oct 10, 2026
110 of 202 checks passed
@kryptobaseddev
kryptobaseddev deleted the fix/T13311-uid-k-capture branch October 10, 2026 04:52
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