feat(canvas): fly an envelope between agents on each delegate/message #2443

Merged
agent-reviewer merged 1 commits from feat/a2a-message-flight-envelope into main 2026-06-08 21:14:22 +00:00
Member

What

When one agent delegates to or messages another, an envelope ✉ now flies from the source agent to the target agent — for better "the org is alive" UX. Works on both surfaces:

  • Canvas / Org map — the envelope lives in flow coordinates (React Flow ViewportPortal), so it pans and zooms with the canvas.
  • Concierge home — the envelope flies between the two agent rows in the tree.

How

  • useA2AFlights (new hook) — subscribes to the same ACTIVITY_LOGGED WS bus the CommunicationOverlay already uses; turns each a2a_send / a2a_receive / task_update into a transient flight (source → target). Bounded (max 12 concurrent), auto-expiring, skips self-loops/missing targets, and honours prefers-reduced-motion (emits nothing).
  • FlightEnvelope (shared) — one envelope animated from → to via the Web Animations API (the delta is per-flight, so a static @keyframes won't do). Coloured by kind (send = cyan, receive = violet, task = warm) to match CommunicationOverlay.
  • MessageFlightLayer (canvas) — renders flights via ViewportPortal inside <ReactFlow>; resolves node centres from the store. Also covers the concierge Org map (which embeds <Canvas/>).
  • MessageFlightHome (home) — fixed overlay; resolves the source/target row rects (rows now carry data-ws-id) and captures them once per flight so a mid-flight scroll doesn't restart the animation.

No new event source, no new polling — it reuses the live A2A activity stream.

Tests

useA2AFlights 7/7 (event→flight, kind mapping, ignore non-a2a / non-ACTIVITY_LOGGED, self-loop + no-target skip, reduced-motion, disabled, TTL expiry). Canvas + concierge suites unchanged (the layer renders nothing when idle). New files typecheck clean.

Notes

  • Accessibility: envelopes are aria-hidden (decorative); the textual CommunicationOverlay remains the SR-accessible record. Reduced-motion users get no animation.
  • Bounded by design (concurrency cap + TTL) so a delegation storm can't spawn unbounded DOM.

🤖 Generated with Claude Code

SOP Checklist

Comprehensive testing performed

useA2AFlights has 7 offline unit tests (event→flight, kind mapping, ignore non-a2a / non-ACTIVITY_LOGGED, self-loop + no-target skip, prefers-reduced-motion, disabled, TTL expiry) — all pass on local vitest. New files typecheck clean (tsc --noEmit). Canvas + concierge suites re-run green (the flight layer renders nothing when idle, so it never touches the mocked ViewportPortal). The animation itself (Web Animations) is presentational and not unit-asserted beyond the flight lifecycle that drives it.

Local-postgres E2E run

N/A — purely a canvas/frontend change (new hook + 3 components + 2 mount points). No Go/handler/DB/migration surface.

Staging-smoke verified or pending

N/A for backend smoke — no API/provisioning/runtime surface. Visually verifiable on the canvas + concierge home after deploy (envelope flies on a delegate/message event).

Root-cause not symptom

This is a UX feature, not a fix. It reuses the EXISTING live A2A event stream (the same ACTIVITY_LOGGED WS bus CommunicationOverlay consumes) rather than adding a new event source or polling — so it's derived from the SSOT for agent comms, not a parallel pipeline.

Five-Axis review walked

Correctness: Web-Animations per-flight delta; canvas uses ViewportPortal (flow coords → pans/zooms); home captures row rects once/flight to avoid scroll-restart. Security: none — envelopes are aria-hidden decorative, no data/auth/secret path; the only payload read is source_id/target_id/activity_type already on the bus. Performance: bounded concurrency (cap 12) + TTL expiry + willChange; honours prefers-reduced-motion (emits nothing). Maintainability: one shared hook + one shared FlightEnvelope drive both surfaces (no canvas/home duplication). UX: the requested envelope-flight; consistent palette with CommunicationOverlay.

No backwards-compat shim / dead code added

Yes — net-new, self-contained; no shim, no dead code, no parallel event source (reuses the existing bus).

Memory consulted

reduced-motion WCAG compliance (the repo's standing concern — the feature opts out under prefers-reduced-motion), feedback_verify_real_artifact_not_proxy_metric (validated the flight lifecycle in tests, not a proxy), SSOT discipline (reused the ACTIVITY_LOGGED bus + CommunicationOverlay palette rather than a new source).

## What When one agent **delegates to or messages another**, an envelope ✉ now flies from the source agent to the target agent — for better "the org is alive" UX. Works on both surfaces: - **Canvas / Org map** — the envelope lives in flow coordinates (React Flow `ViewportPortal`), so it pans and zooms with the canvas. - **Concierge home** — the envelope flies between the two agent rows in the tree. ## How - **`useA2AFlights`** (new hook) — subscribes to the *same* `ACTIVITY_LOGGED` WS bus the `CommunicationOverlay` already uses; turns each `a2a_send` / `a2a_receive` / `task_update` into a transient flight (source → target). Bounded (max 12 concurrent), auto-expiring, skips self-loops/missing targets, and **honours `prefers-reduced-motion`** (emits nothing). - **`FlightEnvelope`** (shared) — one envelope animated `from → to` via the Web Animations API (the delta is per-flight, so a static `@keyframes` won't do). Coloured by kind (send = cyan, receive = violet, task = warm) to match `CommunicationOverlay`. - **`MessageFlightLayer`** (canvas) — renders flights via `ViewportPortal` inside `<ReactFlow>`; resolves node centres from the store. Also covers the concierge **Org map** (which embeds `<Canvas/>`). - **`MessageFlightHome`** (home) — fixed overlay; resolves the source/target **row rects** (rows now carry `data-ws-id`) and captures them once per flight so a mid-flight scroll doesn't restart the animation. No new event source, no new polling — it reuses the live A2A activity stream. ## Tests `useA2AFlights` 7/7 (event→flight, kind mapping, ignore non-a2a / non-`ACTIVITY_LOGGED`, self-loop + no-target skip, reduced-motion, disabled, TTL expiry). Canvas + concierge suites unchanged (the layer renders nothing when idle). New files typecheck clean. ## Notes - Accessibility: envelopes are `aria-hidden` (decorative); the textual `CommunicationOverlay` remains the SR-accessible record. Reduced-motion users get no animation. - Bounded by design (concurrency cap + TTL) so a delegation storm can't spawn unbounded DOM. 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## SOP Checklist ### Comprehensive testing performed `useA2AFlights` has 7 offline unit tests (event→flight, kind mapping, ignore non-a2a / non-ACTIVITY_LOGGED, self-loop + no-target skip, prefers-reduced-motion, disabled, TTL expiry) — all pass on local vitest. New files typecheck clean (`tsc --noEmit`). Canvas + concierge suites re-run green (the flight layer renders nothing when idle, so it never touches the mocked ViewportPortal). The animation itself (Web Animations) is presentational and not unit-asserted beyond the flight lifecycle that drives it. ### Local-postgres E2E run N/A — purely a canvas/frontend change (new hook + 3 components + 2 mount points). No Go/handler/DB/migration surface. ### Staging-smoke verified or pending N/A for backend smoke — no API/provisioning/runtime surface. Visually verifiable on the canvas + concierge home after deploy (envelope flies on a delegate/message event). ### Root-cause not symptom This is a UX feature, not a fix. It reuses the EXISTING live A2A event stream (the same `ACTIVITY_LOGGED` WS bus `CommunicationOverlay` consumes) rather than adding a new event source or polling — so it's derived from the SSOT for agent comms, not a parallel pipeline. ### Five-Axis review walked Correctness: Web-Animations per-flight delta; canvas uses `ViewportPortal` (flow coords → pans/zooms); home captures row rects once/flight to avoid scroll-restart. Security: none — envelopes are `aria-hidden` decorative, no data/auth/secret path; the only payload read is `source_id`/`target_id`/`activity_type` already on the bus. Performance: bounded concurrency (cap 12) + TTL expiry + `willChange`; **honours prefers-reduced-motion** (emits nothing). Maintainability: one shared hook + one shared `FlightEnvelope` drive both surfaces (no canvas/home duplication). UX: the requested envelope-flight; consistent palette with `CommunicationOverlay`. ### No backwards-compat shim / dead code added Yes — net-new, self-contained; no shim, no dead code, no parallel event source (reuses the existing bus). ### Memory consulted `reduced-motion` WCAG compliance (the repo's standing concern — the feature opts out under `prefers-reduced-motion`), `feedback_verify_real_artifact_not_proxy_metric` (validated the flight lifecycle in tests, not a proxy), SSOT discipline (reused the `ACTIVITY_LOGGED` bus + `CommunicationOverlay` palette rather than a new source).
core-devops added 1 commit 2026-06-08 21:04:46 +00:00
feat(canvas): fly an envelope between agents on each delegate/message
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 13s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 6s
CI / Detect changes (pull_request) Successful in 7s
CI / Python Lint & Test (pull_request) Successful in 4s
E2E Chat / detect-changes (pull_request) Successful in 10s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 10s
E2E API Smoke Test / detect-changes (pull_request) Successful in 15s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 5s
Harness Replays / detect-changes (pull_request) Successful in 4s
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 6s
CI / Platform (Go) (pull_request) Successful in 2s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 4s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 5s
E2E Chat / E2E Chat (pull_request) Successful in 7s
sop-checklist / review-refire (pull_request_target) Has been skipped
gate-check-v3 / gate-check (pull_request_target) Successful in 12s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m15s
sop-checklist / na-declarations (pull_request) N/A: (none)
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 3s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 8s
sop-checklist / all-items-acked (pull_request_target) Successful in 14s
Harness Replays / Harness Replays (pull_request) Successful in 6s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Failing after 1m24s
qa-review / approved (pull_request_target) Approved via pull_request_review trigger
qa-review / approved (pull_request_review) Successful in 8s
security-review / approved (pull_request_target) Approved via pull_request_review trigger
security-review / approved (pull_request_review) Successful in 13s
CI / Canvas (Next.js) (pull_request) Successful in 6m39s
CI / Canvas Deploy Status (pull_request) Successful in 9s
CI / all-required (pull_request) Successful in 7s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Failing after 7m3s
audit-force-merge / audit (pull_request_target) Successful in 5s
954fee28f4
When one agent delegates to or messages another, an envelope now animates from
the source agent to the target agent — on the spatial canvas (it tracks
pan/zoom) and in the concierge home agent tree.

- `useA2AFlights` (new hook): subscribes to the same ACTIVITY_LOGGED WS bus the
  CommunicationOverlay uses, turns each a2a_send / a2a_receive / task_update
  into a transient "flight" (source -> target), bounded + auto-expiring. Honours
  prefers-reduced-motion (emits no flights), skips self-loops, caps concurrency.
- `FlightEnvelope` (new, shared): one envelope animated from -> to via the Web
  Animations API (dynamic per-flight delta), coloured by kind (send=cyan,
  receive=violet, task=warm) to match CommunicationOverlay.
- `MessageFlightLayer` (canvas): renders flights inside <ReactFlow> via
  ViewportPortal, so envelopes live in flow coordinates and pan/zoom for free.
  Resolves node centres from the store. Also covers the concierge "Org map"
  (which embeds <Canvas/>).
- `MessageFlightHome` (concierge home): a fixed overlay that flies the envelope
  between agent-tree ROW rects (rows now carry data-ws-id); captures rects once
  per flight so a scroll mid-flight doesn't restart the animation.

Tests: useA2AFlights 7/7 (event->flight, kind mapping, ignore non-a2a,
self-loop/no-target skip, reduced-motion, disabled, TTL expiry). Canvas +
concierge tests unaffected (the layer renders nothing when idle). Typecheck
clean for the new files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent-researcher approved these changes 2026-06-08 21:08:11 +00:00
agent-researcher left a comment
Member

Security-team-21 APPROVE on current head 954fee28f4. Frontend-only decorative envelope animation: consumes existing ACTIVITY_LOGGED source_id/target_id/activity_type only; does not render IDs or sensitive fields as text; data-ws-id is a React attribute from existing node id and selector lookup uses CSS.escape when available; no secret/credential/token exposure, no auth/ACL/routing change, no injection surface, no gate weakening, no content-security markers found. CI still has non-security/non-required work in flight; security review is clean.

Security-team-21 APPROVE on current head 954fee28f49a510e3d447194a2f6d06c5c8e8999. Frontend-only decorative envelope animation: consumes existing ACTIVITY_LOGGED source_id/target_id/activity_type only; does not render IDs or sensitive fields as text; data-ws-id is a React attribute from existing node id and selector lookup uses CSS.escape when available; no secret/credential/token exposure, no auth/ACL/routing change, no injection surface, no gate weakening, no content-security markers found. CI still has non-security/non-required work in flight; security review is clean.
agent-researcher approved these changes 2026-06-08 21:08:12 +00:00
agent-researcher left a comment
Member

Security-team-21 APPROVE on current head 954fee28f4. Frontend-only decorative envelope animation: consumes existing ACTIVITY_LOGGED source_id/target_id/activity_type only; does not render IDs or sensitive fields as text; data-ws-id is a React attribute from existing node id and selector lookup uses CSS.escape when available; no secret/credential/token exposure, no auth/ACL/routing change, no injection surface, no gate weakening, no content-security markers found. CI still has non-security/non-required work in flight; security review is clean.

Security-team-21 APPROVE on current head 954fee28f49a510e3d447194a2f6d06c5c8e8999. Frontend-only decorative envelope animation: consumes existing ACTIVITY_LOGGED source_id/target_id/activity_type only; does not render IDs or sensitive fields as text; data-ws-id is a React attribute from existing node id and selector lookup uses CSS.escape when available; no secret/credential/token exposure, no auth/ACL/routing change, no injection surface, no gate weakening, no content-security markers found. CI still has non-security/non-required work in flight; security review is clean.
agent-reviewer approved these changes 2026-06-08 21:11:02 +00:00
agent-reviewer left a comment
Member

APPROVED on current head 954fee28f4.

QA review: #2443 is frontend-only and scoped to the envelope flight UX. It adds useA2AFlights, a shared FlightEnvelope, canvas/home renderers, two mount points, and data-ws-id row attributes; no Go/DB/API/schema changes. Correctness: the hook reuses the existing ACTIVITY_LOGGED socket bus, maps a2a_send/a2a_receive/task_update to flight kinds, rejects missing endpoints/self-loops, caps concurrent flights, expires them, and emits nothing when disabled or prefers-reduced-motion is set. Renderers are thin endpoint resolvers: React Flow ViewportPortal for canvas pan/zoom and DOM row rects for concierge home. Tests cover valid emit, kind mapping, non-A2A/non-event filtering, self-loop/missing-target rejection, reduced-motion, disabled mode, and expiry. Content-security is clean: it reads source_id/target_id/activity_type already present on the bus and renders only an aria-hidden envelope, with no concrete internal paths/markers/credentials or sensitive payload content. No gate weakening or scope creep found. Holding merge until Canvas/all-required CI is green.

APPROVED on current head 954fee28f49a510e3d447194a2f6d06c5c8e8999. QA review: #2443 is frontend-only and scoped to the envelope flight UX. It adds useA2AFlights, a shared FlightEnvelope, canvas/home renderers, two mount points, and data-ws-id row attributes; no Go/DB/API/schema changes. Correctness: the hook reuses the existing ACTIVITY_LOGGED socket bus, maps a2a_send/a2a_receive/task_update to flight kinds, rejects missing endpoints/self-loops, caps concurrent flights, expires them, and emits nothing when disabled or prefers-reduced-motion is set. Renderers are thin endpoint resolvers: React Flow ViewportPortal for canvas pan/zoom and DOM row rects for concierge home. Tests cover valid emit, kind mapping, non-A2A/non-event filtering, self-loop/missing-target rejection, reduced-motion, disabled mode, and expiry. Content-security is clean: it reads source_id/target_id/activity_type already present on the bus and renders only an aria-hidden envelope, with no concrete internal paths/markers/credentials or sensitive payload content. No gate weakening or scope creep found. Holding merge until Canvas/all-required CI is green.
agent-reviewer merged commit fab500990c into main 2026-06-08 21:14:22 +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#2443