feat(cursor): serve-time blob integrity diagnostic for replay corruption - #2656
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
|
✅ Deterministic PR hygiene checks passed. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 963fff2f19
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| export function cursorBlobServeIntegrityOk(blobId: Uint8Array, served: Uint8Array): boolean { | ||
| if (blobId.byteLength !== 32) return true; | ||
| const digest = createHash("sha256").update(served).digest(); | ||
| return digest.equals(Buffer.from(blobId)); |
There was a problem hiding this comment.
Check replay bytes before deriving their content ID
For locally generated replay blobs, storeCursorBlob derives the ID from the same bytes and setBlob stores a clone, so corruption introduced during root assembly or serialization is incorporated into both the payload and its hash and this check returns true. The new test bypasses the store by manually pairing an old digest with mutated bytes, so it does not demonstrate that the actual getBlobArgs path can detect the reported splice. Add the integrity/round-trip check at the assembly boundary, or introduce a real retained-store fault-injection seam and test the emitted diagnostic through handleCursorNativeKv.
AGENTS.md reference: src/AGENTS.md:L24-L26
Useful? React with 👍 / 👎.
| const blobKey = key(kvMsg.message.value.blobId); | ||
| const blobData = getBlob(blobKey); | ||
| // Splice-class corruption guard (devlog 260826 080): diagnostic only, never blocks serving. | ||
| if (blobData && !cursorBlobServeIntegrityOk(kvMsg.message.value.blobId, blobData)) { |
There was a problem hiding this comment.
Avoid hashing blobs when debug diagnostics are off
On every successful getBlobArgs carrying a 32-byte ID, this condition synchronously hashes the entire served payload before debugProviderDiagnostic gets a chance to discard the event when provider debugging is disabled. With blobs permitted up to 16 MiB, ordinary non-debug requests now incur substantial event-loop work per hydration, and repeated gets can delay stream processing and heartbeats. Gate the integrity calculation on the debug setting, or cache validation performed at admission, so opt-in instrumentation does not add this cost to every Cursor request.
Useful? React with 👍 / 👎.
940d829 to
9de0d83
Compare
963fff2 to
611b2cb
Compare
리뷰 · 우선순위 54 / 80설명 이 풀 리퀘스트는 Cursor 루트/턴 블롭이 재생될 때 글자가 끼어 들어가는 문제를, 서빙 순간에 찾아 진단 로그로 남깁니다. 지금 dev의 src/adapters/cursor/native-exec.ts 618-636줄 handleCursorNativeKv는 getBlobArgs가 오면 키로 바이트를 찾아 그대로 돌려줍니다. 내용 주소 블롭은 32바이트 id가 SHA-256입니다. 바이트가 바뀌면 id와 맞지 않게 됩니다. 라이브 서브에이전트가 [tool_result] 봉투 안에 엉뚱한 토큰이 끼는 모습을 보았고, 그 신호를 잡으려는 계측입니다. cursorBlobServeIntegrityOk는 id가 32바이트일 때만 해시를 비교하고, 더 짧거나 긴 id는 통과시킵니다. 불일치여도 서빙을 막지 않고 blob-integrity-mismatch 진단만 남깁니다. 키 앞 18자와 길이만 남겨 본문은 로그에 안 넣습니다. 그 선택은 맞습니다. 파서가 아니라 재생 경로의 계측이고, 잘못된 양성으로 대화를 끊지 않습니다. 하지만 본문이 말하는 것과 실제 변경이 다릅니다. 체크리스트는 진단만 하고 서빙 동작을 바꾸지 않는다고 합니다. 실제 diff는 세 가지를 더 바꿉니다. src/adapters/cursor.ts는 체크포인트 커밋을 거절할 때 이유를 로그합니다. 이것은 진단입니다. src/adapters/cursor/live-transport.ts의 clientToolFinalizeGraceMsForRequest는 병렬 도구가 켜져 있고 도구가 둘 이상이면 드레인 유예 시간을 늘립니다. 이것은 서빙 동작입니다. src/adapters/cursor/tool-definitions.ts 665-667줄 안내는 NEVER attempt로 바뀌어, 거절 뒤 이어가라는 문장을 없앱니다. 이것도 모델이 읽는 프롬프트이므로 동작입니다. 이 PR도 지금 dev 위가 아닙니다. 베이스는 #2654입니다. 스택 규칙상 #2650-#2654가 먼저입니다. 테스트 세 개는 깨끗한 해시, 끼워 넣은 오염, 32바이트가 아닌 id를 고정합니다. getBlobArgs가 진단을 실제로 부르는지는 그 테스트가 아닙니다. 병렬 유예 시간 변경을 되돌리면 도구 개수 데모가 다시 일찍 끝날 수 있어서, 진단 PR에 숨기기에는 큽니다. src/adapters/cursor/native-exec.ts:622 - getBlobArgs가 id와 바이트를 비교하지 않아 오염을 조용히 재생합니다. 메인테이너의 판단이 필요한 지점
너의 추천 블롭 해시 검사는 유지하되, 병렬 유예와 프롬프트 문장 변경은 이 PR에서 빼는 것을 추천합니다. 진단만 남긴 뒤 #2650-#2654 다음에 합치세요. 지금 dev에 직접 합치지 마세요. 미리보기 배포는 계획에 없습니다. 이 댓글은 grok-bot이 작성했습니다 |
9de0d83 to
3b489ca
Compare
611b2cb to
6dce24e
Compare
6dce24e to
f3bd8b3
Compare
3b489ca to
e0b6060
Compare
Summary
[tool_result]envelopes (a stray token spliced into structural markers). Cursor root/turn blobs are content-addressed (SHA-256 id == bytes), so corruption is detectable at serve time:getBlobArgsnow verifies the digest for raw 32-byte ids and emits ablob-integrity-mismatchprovider diagnostic (key prefix + byte length only — no payload, privacy-scan safe). Serving is never blocked; this is instrumentation for the G4 investigation.Stacked on #2654. Design: 080_stall_corruption_diag.md.
Verification
bun test tests/cursor-blob-integrity.test.ts— 3 pass (clean pass, splice fault-injection detection, non-content-addressed pass-through).bun test tests/cursor-native-exec.test.ts tests/cursor-blob.test.ts— 102 pass 0 fail total.bun run privacy:scan— green.bun x tsc --noEmit— clean.Checklist