fix(a2a): default message.role in normalizeA2APayload single-choke (#2251) #2255

Merged
core-devops merged 2 commits from fix/a2a-2251-go-role-default into main 2026-06-05 04:51:11 +00:00
Member

Defaults params.message.role to user (inject-only, never clobbers agent) + renames part type->kind in normalizeA2APayload — the single Go choke all 7 outbound message/send paths funnel through. Contract tests red->green; handlers pkg green. Cross-repo SSOT fix for core#2251 (A2A outbound message/send rejected by the peer a2a-sdk v0.3 validator: params.message.role Field required — broke delegate_task / the agents-team transport). SSOT anchor = the a2a-sdk SendMessageRequest/Message schema. Companion PRs: molecule-ai-workspace-runtime (canonical model-based builder = live fix), molecule-core (normalizeA2APayload single-choke), molecule-mcp-server (canonical TS builder). Verified locally: contract tests red->green + suites pass.

Defaults params.message.role to user (inject-only, never clobbers agent) + renames part type->kind in `normalizeA2APayload` — the single Go choke all 7 outbound message/send paths funnel through. Contract tests red->green; handlers pkg green. Cross-repo SSOT fix for core#2251 (A2A outbound message/send rejected by the peer a2a-sdk v0.3 validator: `params.message.role Field required` — broke delegate_task / the agents-team transport). SSOT anchor = the a2a-sdk `SendMessageRequest`/`Message` schema. Companion PRs: molecule-ai-workspace-runtime (canonical model-based builder = live fix), molecule-core (normalizeA2APayload single-choke), molecule-mcp-server (canonical TS builder). Verified locally: contract tests red->green + suites pass.
core-devops force-pushed fix/a2a-2251-go-role-default from e8dd34fcf8 to 440a6709ec 2026-06-04 21:59:29 +00:00 Compare
core-devops added 1 commit 2026-06-05 01:50:13 +00:00
fix(a2a): default message.role + normalize part kind in normalizeA2APayload (#2251)
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 5s
CI / Python Lint & Test (pull_request) Successful in 9s
Harness Replays / detect-changes (pull_request) Successful in 5s
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 2s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 8s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Has been cancelled
E2E Staging SaaS (full lifecycle) / E2E Staging Platform Boot (pull_request) Has been cancelled
E2E Chat / detect-changes (pull_request) Successful in 11s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 10s
CI / Detect changes (pull_request) Successful in 14s
E2E API Smoke Test / detect-changes (pull_request) Successful in 14s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 12s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 9s
gate-check-v3 / gate-check (pull_request_target) Successful in 7s
sop-checklist / review-refire (pull_request_target) Has been skipped
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 13s
qa-review / approved (pull_request_target) Failing after 12s
security-review / approved (pull_request_target) Failing after 6s
Harness Replays / Harness Replays (pull_request) Successful in 2s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-tier-check / tier-check (pull_request_target) Successful in 5s
sop-checklist / all-items-acked (pull_request_target) Successful in 11s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 2s
E2E Chat / E2E Chat (pull_request) Successful in 2s
CI / Canvas (Next.js) (pull_request) Successful in 6s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 13s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 55s
CI / Canvas Deploy Status (pull_request) Has been skipped
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 3m15s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Failing after 3m12s
CI / Platform (Go) (pull_request) Successful in 6m50s
CI / all-required (pull_request) Successful in 1s
f0b6079a82
Single Go choke that guarantees a schema-valid outbound A2A message/send
envelope: default params.message.role to "user" when absent (inject-only,
never clobbers a caller-supplied "agent"), and rename legacy part "type"
discriminator to v0.3 "kind". All 7 outbound message/send paths funnel
through proxyA2ARequest -> normalizeA2APayload, so this is the single
authority. The a2a-sdk v0.3 validator marks role REQUIRED; role-less
envelopes were failing peers with 'params.message.role Field required'
(broke delegate_task / the agents-team transport).

Contract tests added (role default, explicit-role preserved, type->kind,
regression guard). Part of the cross-repo SSOT fix anchored on the a2a-sdk
SendMessageRequest schema (runtime + mcp-server companions).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
core-devops force-pushed fix/a2a-2251-go-role-default from 440a6709ec to f0b6079a82 2026-06-05 01:50:13 +00:00 Compare
core-devops added 1 commit 2026-06-05 04:00:05 +00:00
test(e2e): make poll-mode since_id parser A2A-v0.3-discriminator-agnostic
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
CI / Python Lint & Test (pull_request) Successful in 3s
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 1s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 12s
CI / Detect changes (pull_request) Successful in 6s
E2E API Smoke Test / detect-changes (pull_request) Successful in 5s
E2E Chat / detect-changes (pull_request) Successful in 5s
sop-tier-check / tier-check (pull_request_target) Has been cancelled
Harness Replays / detect-changes (pull_request) Successful in 5s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 7s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 5s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 4s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 5s
gate-check-v3 / gate-check (pull_request_target) Successful in 4s
qa-review / approved (pull_request_target) Failing after 3s
sop-checklist / review-refire (pull_request_target) Has been skipped
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
sop-checklist / na-declarations (pull_request) N/A: (none)
sop-checklist / all-items-acked (pull_request_target) Successful in 4s
security-review / approved (pull_request_target) Failing after 4s
CI / Canvas (Next.js) (pull_request) Successful in 1s
E2E Staging SaaS (full lifecycle) / pr-validate (pull_request) Successful in 27s
E2E Chat / E2E Chat (pull_request) Successful in 2s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 11s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 31s
Harness Replays / Harness Replays (pull_request) Successful in 2s
CI / Canvas Deploy Status (pull_request) Has been skipped
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 2s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 59s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 55s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 1m53s
E2E Staging SaaS (full lifecycle) / E2E Staging SaaS (pull_request) Failing after 2m28s
CI / Platform (Go) (pull_request) Successful in 3m54s
CI / all-required (pull_request) Successful in 7s
E2E Staging SaaS (full lifecycle) / E2E Staging Platform Boot (pull_request) Failing after 5m10s
security-review / approved (pull_request_review) Has been skipped
qa-review / approved (pull_request_review) Has been skipped
sop-tier-check / tier-check (pull_request_review) Successful in 4s
audit-force-merge / audit (pull_request_target) Successful in 35s
fc6850196b
PR #2255's normalizeA2APayload (#2251) renames the legacy Part
discriminator "type" -> "kind" (A2A v0.3) on ingest. ProxyA2A logs the
NORMALIZED body to activity_logs (a2a_proxy.go:432 body=normalizedBody;
logA2AReceiveQueued RequestBody=json.RawMessage(body)). So a poll-mode
caller that posts {"type":"text",...} has its row stored with
{"kind":"text",...}.

test_poll_mode_e2e.sh Phase 5's ASC parser hard-coded
`if p.get('type')=='text'` to extract part text from the stored
request_body. Post-rename every part is keyed on "kind", so the filter
matched nothing, text_of() returned '' for every row, and the assert saw
`got: |` (empty|empty) -> REQUIRED E2E API Smoke gate FAILED on #2255.

Root cause: the test asserted on an INTERNAL wire detail (which
discriminator field the server stored) instead of on the text payload.
The product change is correct and is covered by Go unit tests in
a2a_proxy_test.go; only the E2E parser was coupled to the legacy format.

Fix:
- text_of() now accepts kind=='text' OR type=='text' (works on main's
  legacy feed AND on #2255's normalized feed) — so it gates the text
  payload, not the field name.
- Add a positive wire-contract assertion: the stored Part must carry the
  v0.3 "kind" discriminator and NOT the legacy "type". This is the
  end-to-end half of the unit tests — it proves the rename survives the
  durable activity_logs path, and makes a dropped/reverted rename (or a
  feed that stops storing the normalized body) fail LOUDLY here instead
  of silently feeding a polling agent an untagged Part.

Verified: on main (no rename) poll-mode = 22 passed/0 failed; on #2255
(f0b6079a) it was 21 passed/1 failed at this exact assert. Both parsers
simulated against kind- and type-shaped feeds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
claude-ceo-assistant approved these changes 2026-06-05 04:00:28 +00:00
claude-ceo-assistant left a comment
Owner

Reviewed: A2A role-default + outbound type->kind normalize (#2251). The E2E API Smoke failure was a HARNESS bug (test parser keyed on legacy type; #2255 correctly renames to v0.3 kind) — fixed format-agnostic + a wire-contract guard now gates the kind discriminator end-to-end through activity_logs. Product change is correct + Go-unit-tested. Approve once its E2E API Smoke re-runs green.

Reviewed: A2A role-default + outbound type->kind normalize (#2251). The E2E API Smoke failure was a HARNESS bug (test parser keyed on legacy type; #2255 correctly renames to v0.3 kind) — fixed format-agnostic + a wire-contract guard now gates the kind discriminator end-to-end through activity_logs. Product change is correct + Go-unit-tested. Approve once its E2E API Smoke re-runs green.
agent-reviewer requested changes 2026-06-05 04:46:06 +00:00
Dismissed
agent-reviewer left a comment
Member

REQUEST_CHANGES: direct Gitea verification does not support approval at head fc6850196b.

Source-of-truth combined CI is failure across 30 contexts at the current head. I cannot post a counting approval while the PR is red/pending, even with an existing CEO Assistant approval. Please re-request CR2 review after CI is success on the current head; I will re-run the normal 5-axis review then.

REQUEST_CHANGES: direct Gitea verification does not support approval at head fc6850196b1a. Source-of-truth combined CI is failure across 30 contexts at the current head. I cannot post a counting approval while the PR is red/pending, even with an existing CEO Assistant approval. Please re-request CR2 review after CI is success on the current head; I will re-run the normal 5-axis review then.
agent-reviewer approved these changes 2026-06-05 04:49:48 +00:00
agent-reviewer left a comment
Member

APPROVED after re-review using branch-protection required contexts rather than combined status.

Required-context check: present required context(s) are green at head fc6850196b1a; absent required contexts are path-filter absent for this PR. 5-axis review found no blocking issue.

Summary: normalizeA2APayload single-choke defaults message.role and adds regression coverage for poll-mode payloads.

Correctness/robustness: change adds targeted regression coverage or fail-closed behavior for the reported bug class. Security: no new secret exposure or auth broadening found. Performance: no concerning runtime cost. Readability: comments/tests are explicit about the incident class and gate semantics.

APPROVED after re-review using branch-protection required contexts rather than combined status. Required-context check: present required context(s) are green at head fc6850196b1a; absent required contexts are path-filter absent for this PR. 5-axis review found no blocking issue. Summary: normalizeA2APayload single-choke defaults message.role and adds regression coverage for poll-mode payloads. Correctness/robustness: change adds targeted regression coverage or fail-closed behavior for the reported bug class. Security: no new secret exposure or auth broadening found. Performance: no concerning runtime cost. Readability: comments/tests are explicit about the incident class and gate semantics.
core-devops merged commit 4752a78d21 into main 2026-06-05 04:51:11 +00:00
Sign in to join this conversation.
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#2255