From 185f2462a37e333cfcfeca6cabd1087c43bbcdfa Mon Sep 17 00:00:00 2001 From: mikemolinet Date: Mon, 11 May 2026 16:23:17 -0700 Subject: [PATCH] fix(messages): body_received is dict not flat string (defensive isinstance) --- cueapi/cli.py | 14 +++++++++++--- tests/test_cli.py | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/cueapi/cli.py b/cueapi/cli.py index 637d666..e2bf51d 100644 --- a/cueapi/cli.py +++ b/cueapi/cli.py @@ -2228,10 +2228,18 @@ def messages_send( resp = client.post("/messages", json=body, headers=headers) if resp.status_code in (200, 201): m = resp.json() - # Phase 2 body-verify check. Substrate echoes body_received - # when header set; missing field = pre-Layer-1 substrate, no-op. + # Phase 2 body-verify check. Empirically-locked wire shape + # (probed 2026-05-11 ~23:17Z): substrate echoes body_received + # as PARSED request dict, NOT flat string. Extract the body + # field for comparison. Defensive isinstance check handles + # future substrate rev that flattens echo back to a string. if not no_verify and isinstance(m, dict): - received = m.get("body_received") + received_raw = m.get("body_received") + received: Optional[str] = None + if isinstance(received_raw, dict): + received = received_raw.get("body") + elif isinstance(received_raw, str): + received = received_raw if received is not None and received != resolved_body: _emit_body_verify_mismatch_diagnostic( sent=resolved_body, received=received, diff --git a/tests/test_cli.py b/tests/test_cli.py index 9a615ac..840dbc3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2093,7 +2093,11 @@ def test_messages_send_no_verify_omits_header(monkeypatch): def test_messages_send_verify_passes_byte_identical(monkeypatch): - """Substrate echoes back same body → success.""" + """Substrate echoes back same body in body_received.body → success. + + Empirically-locked wire shape 2026-05-11: body_received is the + PARSED request dict, not a flat string. CLI extracts .body for diff. + """ holder: dict = {} _patch_messages_client( monkeypatch, @@ -2101,7 +2105,7 @@ def test_messages_send_verify_passes_byte_identical(monkeypatch): responses={ ("POST", "/messages"): lambda: _FakeResp( 201, {"id": "msg_x", "delivery_state": "queued", - "body_received": "plain"}, + "body_received": {"to": "b@y", "body": "plain", "subject": None, "priority": 3}}, ) }, ) @@ -2113,7 +2117,7 @@ def test_messages_send_verify_passes_byte_identical(monkeypatch): def test_messages_send_verify_fails_loud_on_mismatch(monkeypatch): - """Substrate echoes back DIFFERENT body → exit 7 + diff diagnostic.""" + """body_received.body differs from sent body → exit 7 + diff diagnostic.""" holder: dict = {} _patch_messages_client( monkeypatch, @@ -2121,7 +2125,8 @@ def test_messages_send_verify_fails_loud_on_mismatch(monkeypatch): responses={ ("POST", "/messages"): lambda: _FakeResp( 201, {"id": "msg_mutated", "delivery_state": "queued", - "body_received": "body received by substrate (mutated)"}, + "body_received": {"to": "b@y", "body": "body received by substrate (mutated)", + "subject": None, "priority": 3}}, ) }, ) @@ -2135,6 +2140,30 @@ def test_messages_send_verify_fails_loud_on_mismatch(monkeypatch): assert "MISMATCH" in r.output +def test_messages_send_verify_handles_flat_string_body_received(monkeypatch): + """Defensive: future substrate rev flattens body_received → CLI still verifies. + + Belt-and-suspenders for spec drift; cue-pm fired primary to fix + substrate to flat-string post-Phase-1-bug-headsup ~23:20Z. + """ + holder: dict = {} + _patch_messages_client( + monkeypatch, + holder, + responses={ + ("POST", "/messages"): lambda: _FakeResp( + 201, {"id": "msg_x", "delivery_state": "queued", + "body_received": "plain"}, # flat-string variant + ) + }, + ) + r = runner.invoke( + main, + ["messages", "send", "--from", "a@x", "--to", "b@y", "--body", "plain"], + ) + assert r.exit_code == 0, r.output + + def test_messages_send_verify_noop_when_substrate_omits_echo(monkeypatch): """Backward-compat: pre-Layer-1 substrate omits body_received → no raise.""" holder: dict = {}