Skip to content

fix(messages.send): body_received is dict not flat string (empirical wire-shape)#40

Merged
mikemolinet merged 1 commit into
mainfrom
fix/body-verify-echo-wire-shape
May 11, 2026
Merged

fix(messages.send): body_received is dict not flat string (empirical wire-shape)#40
mikemolinet merged 1 commit into
mainfrom
fix/body-verify-echo-wire-shape

Conversation

@mikemolinet
Copy link
Copy Markdown
Collaborator

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-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.

Bug

PR #39 compared response["body_received"] (dict) against body (str) — type mismatch caused EVERY default-auto-verify send to raise BodyVerifyMismatchError with a degenerate divergence position.

Fix

Defensive shape-handling via isinstance check:

  • If body_received is dict: extract body_received["body"] (current empirical shape)
  • If body_received is str: use as-is (future shape per substrate fix requested by cue-pm)
  • If neither: no-op (backward-compat with pre-Layer-1 substrate)

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

  • 23 of 23 messages_resource tests pass
  • Tests updated to use the empirical dict shape
  • 1 new defensive test pins the backward-flat-string path

Urgency

This hotfix is unblocking — every auto-verify send was broken in main until this lands. Recommend admin-merge ASAP.

🤖 Generated with Claude Code

…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>
@govindkavaturi-art govindkavaturi-art enabled auto-merge (squash) May 11, 2026 23:21
@mikemolinet mikemolinet merged commit aae27eb into main May 11, 2026
3 checks passed
@mikemolinet mikemolinet deleted the fix/body-verify-echo-wire-shape branch May 11, 2026 23:21
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant