Skip to content

feat(cues): opt-in auto_verify on cueapi_fire_cue (cueapi-cli #55 + cueapi-python #41 parity)#36

Merged
mikemolinet merged 1 commit into
mainfrom
feat/fire-cue-verify-optin
May 12, 2026
Merged

feat(cues): opt-in auto_verify on cueapi_fire_cue (cueapi-cli #55 + cueapi-python #41 parity)#36
mikemolinet merged 1 commit into
mainfrom
feat/fire-cue-verify-optin

Conversation

@mikemolinet
Copy link
Copy Markdown
Collaborator

Summary

Parity port of cueapi-cli #55 and cueapi-python #41 — body-verify Phase 2 on cueapi_fire_cue tool, OPT-IN (default false).

Design rationale (verbatim from primary's #41)

Substrate /v1/cues/{id}/fire echoes a pydantic-after-parse body that may include server-side default-population, causing spurious diff vs the tool's JSON.stringify(body). So auto_verify is opt-in — caller flips it on when they know substrate echo semantics match their serialization.

Diverges from cueapi_send_message (cueapi-mcp #35) which is default-on: that endpoint echoes the raw STRING body field per the #798 spec-lock — no parsed-defaulted concern.

Wire shape

Args X-CueAPI-Verify-Echo header Verify check runs
(no auto_verify) omitted no
auto_verify: true "true" yes (string compare; defensive isinstance for both wire shapes)
auto_verify: false omitted no

Notable trade-off vs python/cli

Skips the SHA256 constant-cost fast-path that python #41 and cli #55 both have. Reason: Web Crypto SubtleCrypto.digest() is async; embedding it here would force the whole tool async-contortion. The string-compare-only trade-off is reliable since JSON.stringify is deterministic on Node for non-trivial payloads. If MCP ever needs hash-based verify, the helper can move to a separate async path.

Tests (7 new)

  • default (no auto_verify) omits header — preserves wire format for non-opted callers
  • auto_verify: true sends header
  • matching body_received (STRING shape post-#798) passes silently
  • matching body_received (dict shape pre-#798) passes via JSON.stringify-equivalence
  • mismatched body_received throws with byte-divergence diagnostic
  • mismatch error includes execution id from response
  • missing body_received in response (substrate didn't echo) is silently OK

Full suite: 149/149 passing (was 142 + 7 new).

Parity-impact checklist

  • Server contract (cueapi #795 + #798 + python #41 + cli #55) reviewed
  • Default OFF mirrors python/cli design (opt-in for substrate echo-shape drift)
  • Defensive isinstance for both body_received shapes
  • Throws on confirmed mismatch with byte-divergence + exec id

Backlog row: cmp1wj2a6.

🤖 Generated with Claude Code

…ueapi-python #41 parity)

Parity port of cueapi-cli #55 and cueapi-python #41 — body-verify
Phase 2 on cueapi_fire_cue tool, OPT-IN (default false).

## Design rationale (verbatim from primary's #41)

Substrate /v1/cues/{id}/fire echoes a pydantic-after-parse body that
may include server-side default-population, causing spurious diff vs
the tool's JSON.stringify(body). So auto_verify is opt-in — caller
flips it on when they know substrate echo semantics match their
serialization.

Diverges from cueapi_send_message (cueapi-mcp #35) which is default-
on: that endpoint echoes the raw STRING body field per the #798 spec-
lock — no parsed-defaulted shape concern.

## Implementation

- Schema: auto_verify: optional<boolean> (default false). Help text
  documents the opt-in rationale + the substrate-echo-shape concern.
- Handler: when auto_verify=true, sends X-CueAPI-Verify-Echo: true
  header + captures sentBodyStr = JSON.stringify(body). After response,
  compares against body_received (defensive isinstance: STRING per
  spec-lock OR dict pre-#798 wire shape → JSON.stringify for compare).
- Throws on mismatch with byte-divergence index + execution id +
  diagnostic pointing to caller-side payload mutation as typical cause.

## Notable trade-off vs cueapi-cli/python

Skips the SHA256 constant-cost fast-path that python #41 and cli #55
both have. Reason: Web Crypto SubtleCrypto.digest() is async; embedding
it in this synchronous-shape handler would force the whole tool async-
contortion. Accepts the trade-off of string-compare-only for the MCP
TS port. JSON.stringify deterministic serialization on Node makes the
string compare reliable for non-trivial payloads.

## Tests (7 new)

- default (no auto_verify) omits X-CueAPI-Verify-Echo header
- auto_verify=true sends the header
- matching body_received (STRING shape post-#798) passes silently
- matching body_received (dict shape pre-#798) passes via
  JSON.stringify-equivalence
- mismatched body_received throws with byte-divergence diagnostic
- mismatch error includes execution id from response
- missing body_received (substrate didn't echo) is silently OK

Full suite: 149/149 passing (was 142 + 7 new).

Backlog row: cmp1wj2a6.
@mikemolinet mikemolinet merged commit 92fa463 into main May 12, 2026
1 of 2 checks passed
@mikemolinet mikemolinet deleted the feat/fire-cue-verify-optin branch May 12, 2026 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant