You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A route can publish a notice but never learn what became of it. (await agent()).notices.read() returns only the deliveries attempted on the current invocation, and inbox() returns only pending notices addressed to the current principal. Neither shows the publisher the state of the notices it published (pending / attempted / acknowledged / expired), and no route-level surface shows the ledger as a whole. AgentNoticeLedger.read() does exist, but only the generated wiring holds a ledger — routes get the request-bound handle.
Concretely, examples/worktree-proximity's coordinator/status tool cannot report "N notices still pending for actor X"; it reports topology facts only.
This is deliberately how #264 landed ("cross-recipient reads are structurally impossible"), so this issue is a design question, not a bug: is there a scope narrower than "whole ledger" that a coordinator legitimately needs?
packages/rsc-runtime/src/notices/ledger.ts:393-396, 471-476 — read() returns deliveries computed at admission for this invocation only; :284-296 — inboxProgram filters state === 'pending' && recipientMatchesPrincipal(...).
packages/rsc-runtime/src/notices/ledger.ts:487-490 — AgentNoticeLedger.read() returns the full snapshot, but is not reachable from a route.
examples/worktree-proximity/src/mcp/coordinator/tools/status.tsx:36-64 — result carries actors, activeActivities, refusals, revision; no notice counts.
examples/worktree-proximity/README.md:103-105: "(await agent()).notices.read() exposes only deliveries attempted for the current invocation. The coordinator status therefore reports topology facts only and does not claim a whole-ledger pending count."
A. Publisher-scoped read (preferred). Record the publishing principal on the notice at publish() (identity axes + lineage.conversation, no content duplication) and add
interfaceAgentNoticesHandle{/** Notices this principal published, with their current state and receipts; never other publishers' or other recipients' notices. */published(): Promise<readonlyAgentNotice[]>;}
Authorization gets a new phase: 'published' so the authorizer can still refuse. This gives a publisher "was my warning attempted / acknowledged?" without any cross-recipient exposure.
B. Aggregate counts only.notices.summary() → { pending, attempted, acknowledged, expired } for notices whose recipient is under the caller's lineage root. Coarser, no content, but depends on the lineage-addressed recipient axis (sibling issue).
Explicitly not proposed: exposing AgentNoticeLedger.read() on the request handle.
coordinator/status in examples/worktree-proximity reports, for the publishing actor, how many of its proximity notices are pending vs attempted vs acknowledged; a route-unit test in tests/route-unit/routes.test.ts publishes from actor A, admits on actor B's next event, and asserts A's published() shows attempted while B's inbox() is empty and A's inbox() never showed the notice.
Problem (design question)
A route can publish a notice but never learn what became of it.
(await agent()).notices.read()returns only the deliveries attempted on the current invocation, andinbox()returns only pending notices addressed to the current principal. Neither shows the publisher the state of the notices it published (pending / attempted / acknowledged / expired), and no route-level surface shows the ledger as a whole.AgentNoticeLedger.read()does exist, but only the generated wiring holds a ledger — routes get the request-bound handle.Concretely,
examples/worktree-proximity'scoordinator/statustool cannot report "N notices still pending for actor X"; it reports topology facts only.This is deliberately how #264 landed ("cross-recipient reads are structurally impossible"), so this issue is a design question, not a bug: is there a scope narrower than "whole ledger" that a coordinator legitimately needs?
Evidence (
main@284141958)packages/rsc-runtime/src/notices/contract.ts:179-185—AgentNoticesHandle = { acknowledge, inbox, publish, read }.packages/rsc-runtime/src/notices/ledger.ts:393-396, 471-476—read()returnsdeliveriescomputed at admission for this invocation only;:284-296—inboxProgramfiltersstate === 'pending' && recipientMatchesPrincipal(...).packages/rsc-runtime/src/notices/ledger.ts:487-490—AgentNoticeLedger.read()returns the full snapshot, but is not reachable from a route.examples/worktree-proximity/src/mcp/coordinator/tools/status.tsx:36-64— result carriesactors,activeActivities,refusals,revision; no notice counts.examples/worktree-proximity/README.md:103-105: "(await agent()).notices.read()exposes only deliveries attempted for the current invocation. The coordinator status therefore reports topology facts only and does not claim a whole-ledger pending count."Proposed shape (pick one; both are small)
A. Publisher-scoped read (preferred). Record the publishing principal on the notice at
publish()(identity axes +lineage.conversation, no content duplication) and addAuthorization gets a new
phase: 'published'so the authorizer can still refuse. This gives a publisher "was my warning attempted / acknowledged?" without any cross-recipient exposure.B. Aggregate counts only.
notices.summary()→{ pending, attempted, acknowledged, expired }for notices whose recipient is under the caller's lineage root. Coarser, no content, but depends on the lineage-addressed recipient axis (sibling issue).Explicitly not proposed: exposing
AgentNoticeLedger.read()on the request handle.Out of scope / related
published()view would need to honour whatever redaction lands there.attemptedremains the strongest cross-actor state (Add recipient-aware notices and capability-gated delivery #99 survey).Acceptance
coordinator/statusinexamples/worktree-proximityreports, for the publishing actor, how many of its proximity notices arependingvsattemptedvsacknowledged; a route-unit test intests/route-unit/routes.test.tspublishes from actor A, admits on actor B's next event, and asserts A'spublished()showsattemptedwhile B'sinbox()is empty and A'sinbox()never showed the notice.