fix(messages.send): body_received is dict not flat string (empirical wire-shape)#40
Merged
Merged
Conversation
…wire-shape) Hotfix for cueapi-python PR #39. Empirically verified 2026-05-11 ~23:17Z via direct curl probe: substrate's X-CueAPI-Verify-Echo response includes ``body_received`` as the PARSED request body (a dict with to/body/subject/priority/etc fields), NOT a flat string per the original spec wording. Before fix: SDK compared ``response["body_received"]`` (dict) against ``body`` (str) — type mismatch → ALWAYS raised BodyVerifyMismatchError on every default-auto-verify send. Regression in PR #39. After fix: SDK extracts ``body_received.body`` (str) and compares against sent body (str). Includes defensive isinstance check that falls through gracefully if a future substrate rev flattens the echo back to a string. Tests updated to use the dict shape; 1 new defensive test pins the backward-flat-string path. 23 of 23 messages tests pass. This hotfix is unblocking — every auto-verify send was broken in main until this lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
mikemolinet
added a commit
that referenced
this pull request
May 11, 2026
… B + bonus) (#41) * cues.fire: auto_verify + sha256 constant-cost path (Phase 2 follow-on B + bonus) Mike body-verify directive 2026-05-11. cue-pm unblocked these follow-ons at ~23:48Z after primary's substrate-fix (body_received flat-string + body_received_sha256 hashing body field bytes) verified on prod. Changes: cueapi/resources/cues.py: - New ``auto_verify=True`` kwarg on ``CuesResource.fire``. Default verify-on (symmetric with MessagesResource.send). When set: - sends X-CueAPI-Verify-Echo: true request header - pre-computes sha256(canonical-JSON-of-body) client-side - on response: extracts body_received (defensive isinstance for both string post-fix shape AND dict pre-fix shape — sibling of PR #40 hotfix pattern) - if body_received_sha256 present: constant-cost hex compare first, fall back to string compare on sha drift (JSON-canonicalization differences could cause spurious sha mismatch) - on confirmed drift: raises BodyVerifyMismatchError with sent_body, received_body, first_divergence_byte, message_id (= execution_id for fire) attributes. tests/test_cues_resource.py: - Existing 3 TestFire tests updated to expect the new headers kwarg in the post call (X-CueAPI-Verify-Echo: true is now default-on). - New TestFireAutoVerify class with 5 tests pinning: - Default adds verify-echo header - --auto_verify=False omits header - Byte-identical sha256 match passes - No-op when substrate omits echo fields (pre-Layer-1 backward-compat) - Opt-out skips verify even if substrate echoes All 39 tests (messages + cues resource units) pass. CHANGELOG entry under [Unreleased]. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cues.fire): default auto_verify=False until substrate echo semantics locked CI revealed: substrate's /v1/cues/{id}/fire echoes a pydantic-after-parse body that includes server-side default-population (e.g. empty {} request gets echoed as 16-byte populated-defaults JSON). Client's canonical-JSON serialization diverges from substrate's defaulted echo → spurious BodyVerifyMismatchError on integration tests. Mitigation: default auto_verify=False on CuesResource.fire. Callers opt- in via auto_verify=True when their serialization aligns with substrate's echo semantic. Once cueapi-primary locks per-field echo semantics for fire (sibling to the body_received semantic locked for /v1/messages), flip default to True. Existing fire tests reverted to expect headers={} (no auto-verify). TestFireAutoVerify class tests updated to explicitly pass auto_verify=True. 39 of 39 messages + cues resource tests pass. Integration tests in test_cues.py no longer raise spurious BodyVerifyMismatchError. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mikemolinet
added a commit
that referenced
this pull request
May 12, 2026
…dy coverage, bump audit to 2026-05-12 (#43) Manifest was dated 2026-05-07 and missing the PR-1b event-emit endpoint coverage (4 endpoints) plus the body-verify Phase 2 + inline_body extensions that shipped 2026-05-09 → 2026-05-12. Brings the manifest back in sync with SDK head. Endpoints added to `endpoints_covered`: - POST /v1/agents/{ref}/subscriptions (subscriptions_create, PR #38; inline_body kwarg in PR #42 / cueapi #791 Item 1) - GET /v1/agents/{ref}/subscriptions (subscriptions_list, PR #38) - DELETE /v1/agents/{ref}/subscriptions/{sub_id} (subscriptions_delete, PR #38) - GET /v1/agents/{ref}/events (events_pull, PR #38) Updates to existing entries: - POST /v1/messages — added auto_verify body-verify Phase 2 (PR #39 + #40, cueapi/cueapi #795 + #798 parity) - POST /v1/cues/{id}/fire — note that #33 shipped (was "in-flight") - GET /v1/agents/roster — note that #35 shipped (was "in-flight") - GET /v1/agents/{ref}/presence — note that #35 shipped (was "in-flight") Replaced `in_flight_ports_2026_05_07` section with `ports_shipped_2026_05_08_to_2026_05_12` (now-resolved entries) plus a near-empty `ports_in_flight_2026_05_12` placeholder for future ports. Backlog row: cmp1vukmc. Out of scope: - `model_drift` section walk-through (Cue/Execution/Worker missing fields) — PR #31 just landed the Execution + Worker + Agent + Message additive models; a fuller `model_drift` refresh deserves a separate audit pass against the now-shipped models to figure out what's still drifting.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Hotfix for PR #39 (Phase 2 auto-verify). Empirically verified 2026-05-11 ~23:17Z via direct curl probe: substrate's
X-CueAPI-Verify-Echoresponse includesbody_receivedas the PARSED request body (a dict with to/body/subject/priority/etc fields), NOT a flat string per the original spec wording.Bug
PR #39 compared
response["body_received"](dict) againstbody(str) — type mismatch caused EVERY default-auto-verify send to raiseBodyVerifyMismatchErrorwith a degenerate divergence position.Fix
Defensive shape-handling via
isinstancecheck:body_receivedisdict: extractbody_received["body"](current empirical shape)body_receivedisstr: use as-is (future shape per substrate fix requested by cue-pm)This means cueapi-python correctly verifies under BOTH the current substrate behavior AND the post-primary-fix shape (cue-pm fired urgent cue to primary at 23:20Z requesting body_received → STRING). Zero re-work needed when fix lands.
Test plan
Urgency
This hotfix is unblocking — every auto-verify send was broken in main until this lands. Recommend admin-merge ASAP.
🤖 Generated with Claude Code