Skip to content

refactor(service-rpc): the idempotency LRU tracks entries, not a joined string#141

Merged
wmadden-electric merged 3 commits into
mainfrom
fix/rpc-lru-nul-separator
Jul 21, 2026
Merged

refactor(service-rpc): the idempotency LRU tracks entries, not a joined string#141
wmadden-electric merged 3 commits into
mainfrom
fix/rpc-lru-nul-separator

Conversation

@wmadden-electric

Copy link
Copy Markdown
Contributor

Why

The idempotency store flattened (method, key) into a delimited string to use as an LRU Map key, and picked a NUL byte as the delimiter ("a method name or a UUID can't contain one, so it can't collide"). That literal NUL made git classify serve.ts as binary — GitHub rendered "Binary file not shown" and hid the whole file in #140's diff. 808a8ce escaped the byte (\0) as a stopgap, but the delimiter itself was the smell: flattening a tuple into a string is what invited a "clever" separator in the first place.

What

Remove the flattening. A completed cache entry now carries its own method and key, and the LRU is a Set<CompletedEntry> in insertion order (a Set preserves it, so delete-then-add moves an entry to the newest end). Eviction reads the oldest entry's own location. No delimiter, no lruKey helper, no composite Map key — and serve.ts is plain text again.

Behavior

Unchanged: dedup, single-flight, replay-within-TTL, and LRU eviction at REPLAY_CACHE_MAX_ENTRIES. All 55 service-rpc tests pass, including the eviction and cross-method-isolation cases. typecheck clean, lint clean.

🤖 Generated with Claude Code

…ed string

The store flattened (method, key) into a delimited string to use it as an
LRU Map key, and picked NUL as the delimiter because neither part can
contain one. That literal NUL is what made git treat serve.ts as binary
(fixed in 808a8ce by escaping it) — but the delimiter was the real smell.

Remove the flattening entirely: a completed entry carries its own method
and key, and the LRU is a Set of entries in insertion order. Eviction reads
the oldest entry's own location. No delimiter, no lruKey helper, no
composite Map key. Same behavior — dedup, single-flight, replay, and LRU
eviction tests all pass unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric
wmadden-electric requested a review from wmadden July 21, 2026 11:47
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@wmadden, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7282c6dc-2e33-4f3b-8652-159f41766744

📥 Commits

Reviewing files that changed from the base of the PR and between 8aa9821 and 4308867.

📒 Files selected for processing (1)
  • .agents/rules/no-control-bytes-in-source.mdc

Walkthrough

Refactors IdempotencyStore replay and deduplication tracking to use a Set-backed LRU of complete entries. Completed entries now retain their method and key, allowing direct removal from per-method buckets. Replay hits refresh LRU order, expired entries are removed from both indexes, successful completions populate both structures, and overflow eviction removes the oldest entry from both. Adds a source rule prohibiting control bytes and documenting safer delimiter alternatives and detection commands.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the refactor of the idempotency LRU from joined-string keys to tracked entries.
Description check ✅ Passed The description accurately explains the refactor and matches the changed behavior and implementation details.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rpc-lru-nul-separator
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/rpc-lru-nul-separator

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 21, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@prisma/composer@141
npm i https://pkg.pr.new/@prisma/composer-prisma-cloud@141

commit: 4308867

wmadden-electric and others added 2 commits July 21, 2026 13:50
A NUL used as an LRU-key separator made a file read as binary and hid its
entire diff on review. Record the rule so no agent reaches for a control
byte again: compose keys with a data structure, not a delimited string;
if a delimiter is unavoidable, use a printable character.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
Rewrite the rule to lead with the actual reason, not the one symptom I hit:
a NUL is the string terminator — a reserved control signal across the whole
stack — so "it can't collide" is exactly backwards. It is collision-free
only because every correct system refuses to put one in data, and it
silently truncates or corrupts in every downstream layer it reaches
(C strings, DB drivers, serializers, logs, transports); the hidden git
diff is one instance, not the reason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric
wmadden-electric merged commit 855f473 into main Jul 21, 2026
13 of 14 checks passed
@wmadden-electric
wmadden-electric deleted the fix/rpc-lru-nul-separator branch July 21, 2026 11:57
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.

2 participants