docs(design): messaging primitives — counter-proposal to the sendMessage rework - #551
docs(design): messaging primitives — counter-proposal to the sendMessage rework#551Poytr1 wants to merge 2 commits into
Conversation
…ter-proposal Five orthogonal primitives (Conversation, Post, Activation, Provenance, Budget) replacing the target union, the activation rendezvous, the platform metadata promotion chain, and depth-based loop protection, with the four routing acceptance cases traced end to end and a staged migration path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Fast review: docs-only counter-proposal, no runtime/protocol changes. Spot-checked all cross-references into send-message-routing-rework.md (§3.2, §4, §7, §8.5, §8.6) and they match the cited content; all linked docs (session-concept.md, agent-collaboration-implementation.md, collaboration-arena.md, daemon-centric-architecture.md, send-message-routing-rework.md) exist. Internally consistent (Post/Activation/Provenance/Budget composition table, migration phases, acceptance-case traces). No blocking issues found.
sent by review-bot-fast (Claude Agent · sonnet) · open in session
There was a problem hiding this comment.
The decomposition into Conversation/Post/Activation/Provenance/Visibility is a useful direction, and keeping AgentConnect-authored activation on the trusted data plane is appealing. I’m requesting changes because four issues currently break the proposal’s stated routing and loop-safety invariants; these are design-correctness issues, not migration or compatibility concerns:
- A Conversation-scoped budget resets whenever a hand-off creates a new Conversation. Both postless calls and channel-root calls are mapped to
Post(new …), so an A→B→A loop can continually mint fresh budgets. The safety resource needs a trusted causal/interaction root that survives Conversation creation, or the hop guard must remain underneath it. - A Conversation can span multiple daemons, but the document defines no atomic authority for spending or replenishing its budget. Per-daemon ledgers permit concurrent double-spend and multiply the quota; the CP cannot synchronously arbitrate without entering the hot path, and the relay is not currently a durable ledger. This needs an explicit distributed authority/protocol before Budget can replace
MAX_AGENT_CALL_HOPS. - The parent-session example cannot activate under the proposed
Activateladder: the mapping creates an unaddressed agent-authored Post, and the ladder says that activates nobody. The parent owner must be represented structurally or the activation rule must cover this case. - An idempotency key prevents duplicate admission but does not close the crash window between a successful platform post and durable activation delivery. Because the echo is forbidden from activating and carries only display provenance, a source crash can leave a visible hand-off with neither activation nor a component able to detect the missing envelope. Define the durable outbox/pending-marker and correlation protocol, or retain the rendezvous behavior.
Non-blocking type issue: AgentRef[] | UserRef[] cannot represent a finalized reply that mentions both an agent and a human, even though the lift is described as collecting all mention tokens into this field; (AgentRef | UserRef)[] (or an equivalent structured shape) would.
git diff --check passes. The repository’s Prettier command could not be rerun in this isolated review environment because pnpm attempted to open a read-only cache database; the PR reports that exact check as passing.
sent by review-bot (Codex · gpt-5.6-sol) · open in session
| Post( | ||
| conversation: ConversationRef, // existing, or "new in channel C" | ||
| body: Content, | ||
| addresses?: AgentRef[] | UserRef[], // structured; never parsed from model text |
There was a problem hiding this comment.
Non-blocking: this union only permits a homogeneous list. A normal finalized reply can mention an agent and a human together, while the text below says the lift puts both kinds into this same structured field. Should this be Array<AgentRef | UserRef> (with activation selecting only agent refs), or a pair of typed address collections?
|
|
||
| Consequences: | ||
|
|
||
| - The rendezvous state machine disappears. Exactly-once is an idempotency key — |
There was a problem hiding this comment.
Blocking: idempotency prevents duplicate admission, but it does not make the platform send and trusted activation delivery atomic. If the provider accepts the post and the source daemon dies before durably enqueueing/sending the envelope, the echo is forbidden from activating and the target has no pending expectation to expire—the only echo metadata described below is display provenance. Please define a crash-safe source outbox/pending marker plus the platform-ID↔postId correlation/reconciliation path, or retain a rendezvous that can detect this half-delivery.
|
|
||
| ### 2.5 Budget — loop protection as a resource, not a depth | ||
|
|
||
| Each Conversation carries an activation budget: |
There was a problem hiding this comment.
Blocking: scoping the safety resource to the destination Conversation creates a reset path. The table maps postless calls to Post(new private conversation, …) and visible hand-offs to Post(new in C, …), so A and B can alternate hand-offs that each receive a fresh budget instead of draining one shared resource. A trusted interaction/origin budget must propagate across newly created Conversations (or the end-to-end hop guard must remain); otherwise the stated runaway-loop guarantee does not hold.
| keep complete (this dissolves the §7 chrome-scope ambiguity the suite had to | ||
| assume around: the child's own visible speech is simply a different Post with | ||
| its own visibility). | ||
| - The Post lands in the parent Conversation's transcript and activates agent1. |
There was a problem hiding this comment.
Blocking: this does not follow from the Activate function as written. The table/example creates Post(parent conversation, body, 'session-only') with no address, while line 122 says an unaddressed agent-authored Post activates nobody. Visibility only controls projection. Please encode the parent session owner as a structural addressee or add an explicit session-binding activation rule, and update the primitive/table so Case 1b actually wakes agent1.
|
|
||
| ## 5. Cross-daemon delivery | ||
|
|
||
| The trusted plane is in-process for a same-daemon target and a relay envelope |
There was a problem hiding this comment.
Blocking: where is a cross-daemon Conversation’s budget spent atomically? If each daemon charges its local copy, concurrent fan-out double-spends and an A↔B chain can receive roughly one quota per daemon. The CP cannot arbitrate each activation without joining the message hot path, and the relay is currently non-durable. loop-breaker-design.md §8.4 already identifies this exact constraint (a carried remaining-budget token is insufficient). Please choose an authority/protocol or keep the existing hop guard as the cross-daemon backstop.
…tives proposal Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Fast review of this revision: only change vs. the previously-approved revision is two new diagrams (messaging-primitives-mechanism.svg, messaging-primitives-games.svg) plus their alt-text image references in the doc — the prose is unchanged. Both diagrams are diffable SVG (per CLAUDE.md's preference over raster), all visible text is English, and the labeled boxes/legend/colors (trusted plane, platform projection, budget) match the surrounding §2 and §3 prose accurately. No blocking issues.
sent by review-bot-fast (Claude Agent · sonnet) · open in session
There was a problem hiding this comment.
This revision adds two English, diffable SVG diagrams and links them from the proposal. The assets accurately visualize the proposal and introduce no separate diagram-specific blocker. However, the mechanism text is unchanged from the prior revision, so the core design-correctness issues remain and the new claims in the diagrams (“exactly once,” “Conversation budget,” and “no depth ceiling”) are not yet supported end to end:
- The budget resets across Conversations. Postless and channel-root hand-offs are explicitly mapped to
Post(new …), so an A→B→A chain can continually create fresh Conversation budgets instead of draining one causal resource. A trusted interaction/origin budget must survive Conversation creation, or the hop guard must remain as a backstop. - There is no atomic cross-daemon budget authority. A Conversation may span daemons; per-daemon counters allow concurrent double-spend and effectively multiply the quota. The CP cannot synchronously arbitrate without entering the hot path, and the current relay is not a durable ledger. This needs a defined authority/protocol before retiring
MAX_AGENT_CALL_HOPS. - Case 1b contradicts the Activation ladder.
Post(parent conversation, body, 'session-only')has no address, while the ladder says an unaddressed agent-authored Post activates nobody. The parent owner must be structurally addressed or covered by an explicit session-binding routing rule. - Idempotency does not close the dual-side-effect crash window. If the platform accepts a visible post and the source daemon fails before durably delivering the activation envelope, the echo is forbidden from activating and the target has no pending expectation from which to raise the promised alarm. The proposal needs a crash-safe outbox/pending-marker and platform-ID↔
postIdreconciliation protocol, or equivalent rendezvous behavior.
Non-blocking: AgentRef[] | UserRef[] cannot represent one finalized reply that mentions both an agent and a human, despite the lift collecting both kinds into the same addresses field; use a mixed-element array or separate typed collections.
Validation: the checkout is exactly 93b4c997204431f1db9189e5e355b6780ad3c0df; both SVGs are recognized as SVG files, their visible/source text is English, and git diff --check passes for both the revision delta and the full PR. The repository’s Prettier command could not be rerun in this isolated environment because pnpm attempts to open a read-only cache database.
sent by review-bot (Codex · gpt-5.6-sol) · open in session
Summary
Counter-proposal to the sendMessage routing rework (#503), for discussion — not a replacement PR. It keeps every product goal and invariant of the rework and proposes a different shape: five orthogonal primitives (Conversation, Post, Activation, Provenance, Budget) composed instead of per-feature mechanisms.
Post(conversation, body, addresses?, visibility)primitive replaces the target union and its invalid-combination tableMAX_AGENT_CALL_HOPS— distinguishes a long leaderless game from a runaway loop, which a hop counter cannot§3 traces all four routing acceptance cases (#520) end to end under the primitives; §8 gives a staged migration where each phase flips the suite's expected-failures. The acceptance suite itself needs no changes under either design — it pins invariants, not mechanisms.
Why
The rework's rendezvous state machine, metadata promotion chains, forbidden-combination table, three addressing mechanisms, and hop cap are argued (§1) to be accidental complexity from patching the current dual-plane architecture; the essential complexity (streaming vs final, identity verification, mention-safe splitting, relay envelopes) is kept and delineated (§7).
Validation
pnpm exec prettier --check docs/designs/messaging-primitives.md🤖 Generated with Claude Code