fix(pi): accept Cursor AgentRunRequest managed receipts
Part of #880
Summary
OMP's Cursor provider sends an AgentRunRequest whose history is content-addressed in conversationState.rootPromptMessagesJson. The managed-dispatch verifier only inspected messages, input, or Google contents, so every Cursor turn failed with missing current receipt signature.
This adds a Cursor adapter that:
- hashes the prepared managed
m[0]/m[1]messages into a receipt and matches those hashes against Cursor's root blob IDs; - derives retry identity from the root blob IDs plus the active user text, excluding Cursor's random
messageId; - skips Cursor's structural row comparison with an explicit diagnostic until its root serializer is modeled. The managed receipt and conversation-identity checks remain enforced.
What this does not change
The separate refusal-path behavior (calling ctx.abort() while OMP still sends the original payload) is not changed here. #880 should keep tracking that issue independently.
Validation
bun test packages/pi-plugin/src/issue-880-cursor-receipt.test.ts packages/pi-plugin/src/issue-880-provider-fence.test.ts packages/pi-plugin/src/pi-dispatch-identity.test.ts packages/pi-plugin/src/issue-683-provider-fence.test.ts— 50 passed.bun run --cwd packages/pi-plugin typecheck— passed.bunx biome check --write ...on the four touched files — passed.- Verified the source receipt hashes against a real OMP 18.18.0
buildGrpcRequestCursor payload; both managed m0/m1 hashes matched the emitted root blob IDs. - No live Cursor account request was run from this source branch.
Harness coverage (required)
- OpenCode 1: not applicable — this is the Pi/OMP extension and the Cursor
AgentRunRequestsurface does not exist there. - OpenCode 2: not applicable — same reason.
- Pi: not applicable — Pi does not emit Cursor
AgentRunRequest; existing standard message paths are covered by the identity and provider-fence tests. - OMP: covered — Cursor receipt, identity, structure-skip, admitted-dispatch, and missing-receipt refusal tests.
- Rust module: not applicable — no Rust surface is involved.
Opened as draft because #880 does not yet carry design-approved.
Summary by cubic
Makes Pi accept Cursor's AgentRunRequest in OMP, fixing the managed-dispatch verifier that previously rejected every Cursor turn because it only inspected messages, input, or Google contents.
- Hashes the prepared managed m0/m1 messages and matches them against the root blob IDs in
conversationState.rootPromptMessagesJson, rejecting payloads missing the receipt. - Derives retry identity from the root blob IDs plus active user text, excluding Cursor's random
messageIdso retries don't appear as new turns. - Skips Cursor's structural row comparison with an explicit diagnostic until its root serializer is modeled; the receipt and conversation-identity checks stay enforced.
The separate refusal-path behavior (calling ctx.abort() while OMP still sends the original payload) is unchanged and remains tracked in #880.