Uuid: make v7 monotonic within a millisecond (de-flake the transcript ordering) - #130
Merged
Conversation
…ake class) Tiger_Uuid::v7() filled the sub-ms bits with pure randomness, so two IDs minted in the same millisecond had no deterministic order. Any v7-keyed append log that sorts by id (or falls back to id as a created_at tiebreak) could therefore re-order two rows written in the same tick — the AgentServiceTest transcript flake (expected 'user', got 'assistant'), which has recurred across #68/#125/#129. Fix at the root (RFC 9562 §6.2 "monotonic random", method 2): rand_a becomes a 12-bit counter that increments for each same-ms mint (seeded randomly per ms so it doesn't leak a mint count; rolls into the next ms if it exhausts 4096). rand_b stays fully random, so uniqueness and index locality are unchanged, and the ID is still a valid v7 whose embedded timestamp timeOf() reads. `ORDER BY id` is now a stable insertion order for same-process appends — the case that matters (a conversation's turns are appended within one request). - UuidTest: assert STRICT full-string monotonicity over 5000 tight-loop mints (forces same-ms collisions) — the direct regression guard, replacing the old "full-string order NOT guaranteed within a ms" assertion. - Verified: the previously ~1/20-flaky transcript test now passes 40/40; full unit (821) + integration (1094) green; v7 still unique over 20k and version/variant-valid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Root cause
The flaky
AgentServiceTest::history_returns_a_transcript_...(expected'user', got'assistant') isn't a test bug — it's the UUID generator.Tiger_Uuid::v7()filled the sub-millisecond bits with pure randomness and explicitly punted on a counter ("isn't worth the complexity here"). So two messages appended in the same millisecond got IDs with random tails, and the transcript'screated_at DESC, message_id DESCsort had a non-deterministic tiebreak → the two rows re-ordered ~1/20 runs. It recurred across #68 / #125 / #129.Fix (at the root, benefits every v7-keyed table)
RFC 9562 §6.2 "monotonic random" (method 2):
rand_abecomes a 12-bit monotonic counter that increments for each same-ms mint (seeded randomly per ms so it doesn't leak a mint count; rolls into the next ms if 4096 are exhausted).rand_bstays fully random → uniqueness + index locality unchanged, still a valid v7,timeOf()still works.ORDER BY idis now a stable insertion order for same-process appends — exactly the transcript case (a conversation's turns are appended in one request).No change to the model or the test's intent — the ordering ambiguity simply no longer exists.
Verification
UuidTestnow asserts strict full-string monotonicity over 5000 tight-loop mints (forces same-ms collisions) — the regression guard, replacing the old "full-string order NOT guaranteed within a ms" assertion.🤖 Generated with Claude Code