fix(pi): accept Cursor AgentRunRequest managed receipts

Draft
ZI
1d ago
+405-8

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 buildGrpcRequest Cursor 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 AgentRunRequest surface 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 messageId so 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.