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
fix(notices): keep wire-successful receipts owed and renew the hold during pending sends
Codex P2 x2 on #376:
- A send that succeeded but whose signalAvailability() commit failed was
deduplicated only in memory, so a restarted signaller could resend it once
the abandoned hold lapsed. Owed receipts are now retried with the same
idempotency key before any later observation spends, and on close().
- A protocol write pending longer than the 30s TTL let another process take
the hold and send too. The holder now renews under its key while send() is
pending; the reducer refuses a foreign key while a hold is live and refuses a
lapsed holder's late renewal once another key has taken over.
Copy file name to clipboardExpand all lines: .changeset/notice-inbox-resource-updated.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,4 +3,4 @@
3
3
"agent-bundle": patch
4
4
---
5
5
6
-
Wire the #99 stage-4 `mcp-resource-updated` delivery route into generated stateful MCP servers. `@agent-bundle/runtime/notices` gains `createNoticeInboxSignaller` — one connection's subscription to the reserved inbox resource (`AGENT_NOTICE_INBOX_URI`) that, after each completed render, sends at most one `notifications/resources/updated` for the subscriber's newly eligible pending notices and records it through `signalAvailability()` as an availability receipt (never delivery), honouring `nextAttemptAt` and bounding signals per notice by `retryBudget` across restarts. The ledger gains `reserveAvailability()` / `releaseAvailability()` (and `AgentNotice.availabilityReservation`, `AGENT_NOTICE_AVAILABILITY_RESERVATION_TTL_MS`): the signaller holds a notice's budget slot by compare-and-swap before the wire write so concurrent processes cannot both send, finalizes the hold into the receipt only when the protocol write succeeds, and releases it when the write fails, so a failed send costs no budget and the receipt always means the write succeeded; `unsubscribe()` resolves only after in-flight observations settle; `@agent-bundle/runtime/mount` gains `createGeneratedNoticeRuntime` and `GeneratedRuntimeState.noticeLedger()` so a server process can hold its own handle on the durable store its worker mounts. Generated workspace-durable MCP entries now register `resources/subscribe`/`resources/unsubscribe` for the inbox URI only, advertise `resources.subscribe` exactly when that wiring is active, fail subscriptions closed when the store is unreadable, and the inbox projection exposes the `availability` receipt alongside `exposure`. Volatile lifetimes keep the store in the worker's heap and advertise no subscription capability.
6
+
Wire the #99 stage-4 `mcp-resource-updated` delivery route into generated stateful MCP servers. `@agent-bundle/runtime/notices` gains `createNoticeInboxSignaller` — one connection's subscription to the reserved inbox resource (`AGENT_NOTICE_INBOX_URI`) that, after each completed render, sends at most one `notifications/resources/updated` for the subscriber's newly eligible pending notices and records it through `signalAvailability()` as an availability receipt (never delivery), honouring `nextAttemptAt` and bounding signals per notice by `retryBudget` across restarts. The ledger gains `reserveAvailability()` / `releaseAvailability()` (and `AgentNotice.availabilityReservation`, `AGENT_NOTICE_AVAILABILITY_RESERVATION_TTL_MS`): the signaller holds a notice's budget slot by compare-and-swap before the wire write so concurrent processes cannot both send, finalizes the hold into the receipt only when the protocol write succeeds, and releases it when the write fails, so a failed send costs no budget and the receipt always means the write succeeded. The hold is renewed while the write is pending (a different key may take it over only after the TTL, and a lapsed holder cannot steal it back), and a receipt whose commit failed after a successful send is retried idempotently before later observations and on `close()`; `unsubscribe()` resolves only after in-flight observations settle; `@agent-bundle/runtime/mount` gains `createGeneratedNoticeRuntime` and `GeneratedRuntimeState.noticeLedger()` so a server process can hold its own handle on the durable store its worker mounts. Generated workspace-durable MCP entries now register `resources/subscribe`/`resources/unsubscribe` for the inbox URI only, advertise `resources.subscribe` exactly when that wiring is active, fail subscriptions closed when the store is unreadable, and the inbox projection exposes the `availability` receipt alongside `exposure`. Volatile lifetimes keep the store in the worker's heap and advertise no subscription capability.
0 commit comments