@astrosheep/square 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/dist/artifact.d.ts +1 -3
  2. package/dist/artifact.js +12 -36
  3. package/dist/attention-presentation.d.ts +2 -22
  4. package/dist/attention-presentation.js +9 -12
  5. package/dist/boundary-presentation.d.ts +3 -14
  6. package/dist/boundary-presentation.js +29 -104
  7. package/dist/card-presentation.d.ts +1 -0
  8. package/dist/card-presentation.js +2 -0
  9. package/dist/catch-decisions.js +1 -7
  10. package/dist/claude-delivery.d.ts +13 -8
  11. package/dist/claude-delivery.js +40 -93
  12. package/dist/claude-mcp-context.js +2 -2
  13. package/dist/claude-mod.js +28 -140
  14. package/dist/claude-transport.d.ts +3 -3
  15. package/dist/claude-transport.js +20 -44
  16. package/dist/cli/context.js +7 -9
  17. package/dist/cli/observation-commands.d.ts +2 -0
  18. package/dist/cli/observation-commands.js +12 -2
  19. package/dist/cli/registry.js +3 -1
  20. package/dist/codex-address.d.ts +2 -2
  21. package/dist/codex-boundary-state.d.ts +1 -5
  22. package/dist/codex-boundary-state.js +0 -4
  23. package/dist/codex-hook.d.ts +7 -10
  24. package/dist/codex-hook.js +69 -33
  25. package/dist/codex-queue.d.ts +10 -11
  26. package/dist/codex-queue.js +32 -32
  27. package/dist/codex-watch.d.ts +2 -0
  28. package/dist/codex-watch.js +100 -0
  29. package/dist/decisions.js +2 -2
  30. package/dist/delivery-deferral.d.ts +8 -17
  31. package/dist/delivery-deferral.js +0 -28
  32. package/dist/delivery-frame.d.ts +7 -0
  33. package/dist/delivery-frame.js +11 -0
  34. package/dist/delivery-ledger-sqlite.d.ts +97 -0
  35. package/dist/delivery-ledger-sqlite.js +496 -0
  36. package/dist/delivery-ledger.d.ts +196 -0
  37. package/dist/delivery-ledger.js +268 -0
  38. package/dist/delivery-lifetime.d.ts +6 -0
  39. package/dist/delivery-lifetime.js +45 -0
  40. package/dist/harness-links.js +61 -7
  41. package/dist/harness.js +12 -17
  42. package/dist/help.js +2 -0
  43. package/dist/http-delivery.d.ts +5 -9
  44. package/dist/http-delivery.js +20 -77
  45. package/dist/inbox.d.ts +6 -49
  46. package/dist/inbox.js +24 -371
  47. package/dist/index.d.ts +6 -3
  48. package/dist/index.js +4 -1
  49. package/dist/mcp.js +1 -1
  50. package/dist/model.d.ts +7 -47
  51. package/dist/model.js +1 -7
  52. package/dist/notifications.d.ts +24 -20
  53. package/dist/notifications.js +39 -108
  54. package/dist/operation-control.d.ts +4 -0
  55. package/dist/operation-control.js +20 -0
  56. package/dist/packages/agent-delivery/src/claude-native.d.ts +2 -0
  57. package/dist/packages/agent-delivery/src/claude-native.js +5 -0
  58. package/dist/packages/agent-delivery/src/codex-boundary.d.ts +11 -6
  59. package/dist/packages/agent-delivery/src/codex-boundary.js +31 -40
  60. package/dist/packages/agent-delivery/src/codex-hook.d.ts +17 -12
  61. package/dist/packages/agent-delivery/src/codex-hook.js +26 -39
  62. package/dist/packages/agent-delivery/src/codex.d.ts +3 -0
  63. package/dist/packages/agent-delivery/src/codex.js +41 -4
  64. package/dist/packages/agent-delivery/src/index.d.ts +3 -1
  65. package/dist/packages/agent-delivery/src/index.js +1 -1
  66. package/dist/packages/agent-delivery/src/paseo.js +11 -2
  67. package/dist/packages/agent-delivery/src/types.d.ts +1 -0
  68. package/dist/paseo-delivery.d.ts +5 -5
  69. package/dist/paseo-delivery.js +19 -97
  70. package/dist/paseo.d.ts +1 -1
  71. package/dist/paseo.js +1 -1
  72. package/dist/plugins/opencode/index.d.ts +5 -3
  73. package/dist/plugins/opencode/index.js +99 -21
  74. package/dist/plugins/opencode-shared/delivery.d.ts +23 -0
  75. package/dist/plugins/opencode-shared/delivery.js +109 -0
  76. package/dist/plugins/opencode-v1/index.d.ts +28 -0
  77. package/dist/plugins/opencode-v1/index.js +41 -0
  78. package/dist/plugins/opencode-v1/runtime.d.ts +56 -0
  79. package/dist/plugins/opencode-v1/runtime.js +152 -0
  80. package/dist/plugins/opencode-v1/transport.d.ts +13 -0
  81. package/dist/plugins/opencode-v1/transport.js +50 -0
  82. package/dist/plugins/paseo/shared/card-presentation.d.ts +10 -0
  83. package/dist/plugins/paseo/shared/card-presentation.js +7 -0
  84. package/dist/ports.d.ts +31 -90
  85. package/dist/session-lifecycle.d.ts +8 -7
  86. package/dist/session-lifecycle.js +40 -42
  87. package/dist/sqlite-square.d.ts +14 -23
  88. package/dist/sqlite-square.js +132 -139
  89. package/dist/square-api.js +4 -7
  90. package/dist/square-core.d.ts +0 -1
  91. package/dist/square-domain.d.ts +5 -17
  92. package/dist/square-domain.js +104 -221
  93. package/dist/square-facade.d.ts +18 -15
  94. package/dist/square-post.d.ts +53 -0
  95. package/dist/square-post.js +4 -0
  96. package/dist/square-posting.d.ts +13 -0
  97. package/dist/square-posting.js +174 -0
  98. package/dist/square-producer-sqlite.d.ts +11 -0
  99. package/dist/square-producer-sqlite.js +210 -0
  100. package/dist/square-sqlite.d.ts +15 -25
  101. package/dist/square-sqlite.js +150 -226
  102. package/dist/views.d.ts +2 -2
  103. package/dist/views.js +0 -1
  104. package/dist/wake-sink.d.ts +4 -11
  105. package/dist/wake-sink.js +8 -32
  106. package/dist/wake-transports.d.ts +4 -7
  107. package/dist/wake-transports.js +8 -39
  108. package/examples/symmetric-domains.mjs +29 -249
  109. package/guides/change-waits.md +13 -53
  110. package/guides/claude-native.md +19 -175
  111. package/guides/codex-delivery.md +55 -80
  112. package/guides/delivery-primitives.md +48 -207
  113. package/guides/operation-cancellation.md +2 -5
  114. package/guides/participant-ownership.md +25 -89
  115. package/guides/pi-native-delivery.md +19 -56
  116. package/guides/pi-tools.md +6 -8
  117. package/guides/square-api.md +113 -615
  118. package/package.json +8 -8
  119. package/plugins/claude/.claude-plugin/plugin.json +1 -1
  120. package/plugins/claude/hooks/hooks.json +1 -1
  121. package/plugins/claude/{hooks/register.js → mods/square.js} +4 -7
  122. package/plugins/codex/.codex-plugin/plugin.json +1 -1
  123. package/plugins/codex/hooks/hooks.json +11 -23
  124. package/plugins/opencode/index.ts +91 -23
  125. package/plugins/opencode-shared/delivery.ts +91 -0
  126. package/plugins/opencode-v1/index.ts +36 -0
  127. package/plugins/opencode-v1/runtime.ts +134 -0
  128. package/plugins/opencode-v1/transport.ts +41 -0
  129. package/plugins/paseo/OVERVIEW.md +5 -5
  130. package/plugins/paseo/README.md +7 -6
  131. package/plugins/paseo/client/markdown.tsx +5 -5
  132. package/plugins/paseo/client/square-message.tsx +28 -24
  133. package/plugins/paseo/client/transform.ts +8 -5
  134. package/plugins/paseo/shared/card-presentation.ts +16 -0
  135. package/plugins/paseo/shared/message.ts +6 -11
  136. package/plugins/pi/square-pi.js +156 -417
  137. package/dist/channel-artifact.d.ts +0 -10
  138. package/dist/channel-artifact.js +0 -55
  139. package/dist/channel-delivery.d.ts +0 -11
  140. package/dist/channel-delivery.js +0 -51
  141. package/dist/channel-domain.d.ts +0 -3
  142. package/dist/channel-domain.js +0 -83
  143. package/dist/channel-facade.d.ts +0 -76
  144. package/dist/channel-facade.js +0 -1
  145. package/dist/channel-internal.d.ts +0 -126
  146. package/dist/channel-internal.js +0 -440
  147. package/dist/channel-metadata.d.ts +0 -11
  148. package/dist/channel-metadata.js +0 -1
  149. package/dist/channel-ports.d.ts +0 -241
  150. package/dist/channel-ports.js +0 -1
  151. package/dist/channel-presentation.d.ts +0 -17
  152. package/dist/channel-presentation.js +0 -22
  153. package/dist/channel-sqlite-schema.d.ts +0 -13
  154. package/dist/channel-sqlite-schema.js +0 -81
  155. package/dist/channel-transport.d.ts +0 -62
  156. package/dist/channel-transport.js +0 -1
  157. package/dist/channel.d.ts +0 -84
  158. package/dist/channel.js +0 -60
  159. package/dist/claude-delivery-status.d.ts +0 -13
  160. package/dist/claude-delivery-status.js +0 -46
  161. package/dist/cmd/notify-once.d.ts +0 -2
  162. package/dist/cmd/notify-once.js +0 -29
  163. package/dist/delivery-attempts.d.ts +0 -52
  164. package/dist/delivery-attempts.js +0 -73
  165. package/dist/delivery-effects.d.ts +0 -139
  166. package/dist/delivery-effects.js +0 -163
  167. package/dist/delivery-health.d.ts +0 -51
  168. package/dist/delivery-health.js +0 -173
  169. package/dist/delivery-operations.d.ts +0 -22
  170. package/dist/delivery-operations.js +0 -198
  171. package/dist/delivery-primitives.d.ts +0 -5
  172. package/dist/delivery-primitives.js +0 -3
  173. package/dist/delivery.d.ts +0 -56
  174. package/dist/delivery.js +0 -80
  175. package/dist/plugins/opencode/delivery.d.ts +0 -19
  176. package/dist/plugins/opencode/delivery.js +0 -223
  177. package/dist/presentation-operations.d.ts +0 -5
  178. package/dist/presentation-operations.js +0 -86
  179. package/dist/sqlite-channel.d.ts +0 -15
  180. package/dist/sqlite-channel.js +0 -600
  181. package/dist/square-index.d.ts +0 -16
  182. package/dist/square-index.js +0 -106
  183. package/dist/wake-preview.d.ts +0 -7
  184. package/dist/wake-preview.js +0 -15
  185. package/plugins/opencode/delivery.ts +0 -198
  186. /package/dist/{channel-values.d.ts → square-values.d.ts} +0 -0
  187. /package/dist/{channel-values.js → square-values.js} +0 -0
@@ -1,207 +1,48 @@
1
- # Delivery custody primitives
2
-
3
- `@astrosheep/square/delivery` provides storage-independent attempt transitions, suppression predicates,
4
- and four bound effect functions: `dispatchEffect`, `preparePresentation`, `presentPrepared`, and
5
- `presentPreparedBatch`. It does not open a square, interpret identities, own transactions, or schedule
6
- retries. Square's actual dispatch, single presentation and boundary batch adapters compose these same
7
- lifecycles; its SQLite adapter uses the attempt transitions with existing tables. Ownership, membership,
8
- cancellation and delivery-deferral policy remain in the bound application capability.
9
-
10
- ## Bind a series inside a transaction
11
-
12
- `AttemptRows<D>` is a capability for **one logical item / recipient / authority / purpose series**.
13
- The caller chooses those coordinates, including arbitrary opaque strings, and binds the store to them.
14
- No Square name, seat, generation, activity-id codec or composite-key format is required.
15
-
16
- - `list()` returns that series newest ordinal first.
17
- - `byToken(token)` returns only a matching attempt in that series.
18
- - `insert(attempt)` and `replace(attempt)` write within the caller's current transaction.
19
- - Replacements preserve purpose, token, ordinal and the caller's external series coordinates.
20
-
21
- The caller guarantees isolation against competing claims, token uniqueness within its token lookup
22
- scope, atomic commit/rollback, and durable storage where needed. Run each operation and its reads and
23
- writes inside that boundary; an asynchronous read followed later by an unguarded write is not custody.
24
- Stores must not retain mutable references that allow a caller to change durable rows without a write.
25
- `D` belongs entirely to the caller. The primitive does not merge, serialize or interpret it.
26
-
27
- ```ts
28
- import { claimAttempt, prepareAttempt, settleAttempt, type AttemptRows } from '@astrosheep/square/delivery';
29
-
30
- type Payload = { route?: string; nativeToken?: string; ack?: string };
31
- // Supplied by the application, already scoped and transaction-bound:
32
- declare const rows: AttemptRows<Payload>;
33
-
34
- const claim = claimAttempt(rows, {
35
- purpose: 'dispatch', token: 'application-generated-unique-token',
36
- at: 1000, leaseMs: 30_000, data: { route: 'opaque endpoint' },
37
- });
38
- if (claim.status === 'acquired') {
39
- prepareAttempt(rows, { token: claim.token, data: { route: 'opaque endpoint', nativeToken: 'correlation' } });
40
- }
41
- // In a later transaction, only after external proof of acceptance:
42
- settleAttempt(rows, {
43
- token: 'application-generated-unique-token', outcome: 'accepted', at: 1100,
44
- data: { route: 'opaque endpoint', nativeToken: 'correlation', ack: 'external proof' },
45
- });
46
- ```
47
-
48
- The example shows only transaction-scoped transitions. Commit a successful claim before external I/O;
49
- settle its exact token in a new transaction after observing the result. The bound effect capability
50
- below connects those operations without introducing a generic transaction runtime. Authority fencing,
51
- currentness policy and the meaning of external proof remain the application's responsibility.
52
- An `accepted` dispatch is not proof of presentation or consumption. Only the responsible presentation
53
- boundary may assert `presented`; consuming an item is a separate application operation.
54
-
55
- ## Square content custody
56
-
57
- Dispatch and presentation remain separate evidence series, but they are not independent permission
58
- to inject content. Square's transaction-scoped domain gate checks both series for the same artifact,
59
- recipient, seat generation and activity before admitting a new injection. A claim in either series
60
- blocks the other; accepted, presented, clipped and unknown evidence also block it. Only failed or
61
- released evidence permits another injection. An expired opposing claim is normalized to unknown in
62
- that transaction rather than stolen. No lock is held over host or network I/O.
63
-
64
- A native receiver that has verified the exact existing wake may pass its claim token as
65
- `observationOf` to the presentation adapter. The gate verifies the wake belongs to the same captured
66
- recipient/generation/activity and remains dispatching, accepted or unknown. This records observation
67
- of that message; its sink must not inject another message. Claude and OpenCode retain their exact
68
- native correlation/content checks. A successful wake alone never creates a consumption receipt.
69
- Paseo currently has no corresponding native Pi observation correlation: its accepted/unknown attempt
70
- stays unconsumed, available to explicit catch, without automatic native reinjection.
71
-
72
- Session pending projections used for automatic injection suppress claimed, accepted and uncertain
73
- items as well as presented ones. Failed/released attempts make them eligible again through delivery
74
- revision observation. Native payload construction and exact-token observation read their captured
75
- activity directly, not this injection queue. Cancellation and seat replacement retain their existing
76
- fences. Uncertainty deliberately favors no automatic duplicate over automatic recovery; no
77
- exactly-once processing or guaranteed eventual delivery is claimed.
78
-
79
- These checks use the existing artifact evidence and transactions; no new registry or artifact format
80
- is introduced. All running injectors must load the updated code before the guarantee applies.
81
-
82
- ## Transitions
83
-
84
- An `Attempt<D>` has `purpose: 'dispatch' | 'presentation'`, `token`, zero-based `ordinal`, `outcome`,
85
- finite `at`, optional `expiresAt`, and `data`.
86
-
87
- - `claimAttempt` first returns terminal evidence: dispatch `accepted`/`unknown`, presentation
88
- `presented`/`unknown`. Otherwise a live `dispatching` attempt is `busy`; missing expiry is live.
89
- - At exact expiry or later, an interrupted `dispatching` attempt becomes `unknown`, keeps its original
90
- payload, loses expiry, and returns `terminal` with `interrupted: true`. There is no new attempt and
91
- **no automatic replay of uncertainty**. Square maps that flag to its interruption diagnostic.
92
- - With neither terminal nor dispatching evidence, claim inserts `dispatching` at the next ordinal.
93
- Failed/released attempts can therefore be retried. Purpose-specific terminal meanings are not
94
- inferred from other completion labels.
95
- - `prepareAttempt` replaces only the data of the exact `dispatching` token. Pass the complete merged
96
- payload. It returns false for an absent or no-longer-dispatching token. Callers that already know
97
- the payload is unchanged may skip the replacement; core performs no JSON equality checks.
98
- - `settleAttempt` allows `dispatching` to any defined completion, and late `unknown` to `accepted`.
99
- It clears expiry and sets time/outcome/data. `accepted` to `accepted` returns true **without any
100
- write or payload/time mutation**. All other transitions return false, including `unknown` to
101
- `presented`. Missing or foreign tokens cannot settle another series.
102
-
103
- Invalid purpose/completion/token/time, non-positive or unsafe lease durations, non-finite expiry, and
104
- unsafe next ordinals reject before mutation with `TypeError` or `RangeError`, not `SquareError`.
105
- The caller supplies valid stored attempts and consistently scoped, ordered rows.
106
-
107
- ## Suppression without payloads
108
-
109
- `presentationBlocksDispatch(attempts, now)` and `automaticDispatchEligible(attempts, now)` accept only
110
- `purpose`, `outcome`, and optional `expiresAt`; no dummy payload or identity is needed. These predicates
111
- may see both purposes for the same logical delivery.
112
-
113
- Presentation `presented`, `clipped`, `unknown`, or `dispatching` blocks dispatch, including an
114
- expired presentation claim: loss of its lease is uncertainty, not permission to send again. Automatic dispatch additionally requires no dispatch
115
- `accepted`, `unknown`, or `dispatching`; even expired dispatch custody blocks automatic replay.
116
- These are preselection predicates, not substitutes for a transactional claim or application gates.
117
-
118
-
119
- ## Bound effects: one captured capability, four functions
120
-
121
- `EffectPort<C>` is bound by the caller to **one captured work item / recipient / authority / purpose**.
122
- It exposes only:
123
-
124
- - `claim(signal?)`: the application's existing atomic claim, returning `{ token, ordinal }` or
125
- `undefined` when busy, terminal, stale or deferred. The runner does not claim the attempt twice.
126
- - `current(signal?)`: pre-effect policy; a rejected check is unverifiable and treated as false.
127
- - `settle(claim, completion)`: one captured settlement operation, with no request signal. Return true
128
- only when it commits, false when not recorded (not necessarily stale), or throw on persistence error.
129
-
130
- The application owns tokens, leases, semantic timestamps, authority, proof/diagnostic payloads and
131
- resource lifetimes. There is no public transaction type, series-key codec or extra persisted lifecycle.
132
- `Settlement<C>` keeps the selected completion separate from persistence: `recorded`, `not-recorded`,
133
- or `error` with the original error. Observations are never erased by persistence refusal/error.
134
-
135
- ### Dispatch
136
-
137
- ```ts
138
- import { dispatchEffect, type EffectPort, type DispatchCompletion } from '@astrosheep/square/delivery';
139
-
140
- declare const port: EffectPort<DispatchCompletion>; // bound claim/current/settle
141
- // A sender must check its absolute deadline/cancellation immediately before external mutation.
142
- const report = await dispatchEffect(port, async context => {
143
- if (!await context.beforeSend()) return { outcome: 'not-capable' };
144
- if (context.signal?.aborted || Date.now() >= context.deadline) return { outcome: 'unknown' };
145
- // Call the application's transport here, passing the remaining budget and captured claim.
146
- return { outcome: 'accepted', data: { proof: 'application acknowledgement' } };
147
- }, { timeoutMs: 5000 });
148
- ```
149
-
150
- `dispatchEffect` owns claim → initial currentness → send → settlement. Cancellation suppresses
151
- pre-effect work. It starts its timer immediately before invoking the sender, not during claim,
152
- initial policy reads or persistence. Exactly one returned/thrown/timeout decision is frozen before
153
- settlement. A sender exception defaults to `unknown`, not failed; returned `not-capable` releases
154
- custody. A denied final gate releases with `not-current / final` under the sender's obligation to
155
- obey it. No automatic retry occurs.
156
-
157
- `beforeSend()` is **policy currentness, not an elapsed-budget gate**. A stalled policy check may
158
- return true after the outer timeout. The sender must recheck `deadline` and `signal` after that await
159
- and immediately before I/O; true does not authorize a late send. Outer timeout stays unknown even
160
- when no I/O is known to have started. Late gates and late promise results cannot rewrite the frozen
161
- settlement. Separately correlated native proof may still use the attempt transition's permitted late
162
- unknown → accepted path; the timed-out runner does not reconcile itself.
163
-
164
- ### Prepared presentation
165
-
166
- `preparePresentation({ payload, coverage, port }, { signal? })` acquires custody without running a
167
- sink. A returned `PreparedPresentation<P>` exposes `payload`, pre-effect `eligible(signal?)`, and
168
- promise-cached `release()` for abandonment. It is a local one-shot capability, not a durable row and
169
- not a public success writer.
170
-
171
- `presentPrepared(handle, sink, control?)` specializes the batch lifecycle to one item.
172
- `presentPreparedBatch(handles, render, sink, control?)` takes all supplied custody before its first
173
- await. It rejects duplicate, foreign or used handles before any effect, checks eligibility, then calls
174
- synchronous side-effect-free `render(eligible)` returning `{ payload, included }`. Included handles
175
- must be a unique exact subset of those eligible handles; invalid rendering releases custody and
176
- rejects without presentation evidence. No included items means no sink call.
177
-
178
- Cancellation is checked immediately before the one sink invocation. There is **no presentation timer**
179
- and no post-effect cancellation, deferral or currentness veto. The runner awaits the sink and marks
180
- **all included handles** effect-observed before starting asynchronous settlements. Full coverage
181
- settles `presented`; clipped coverage settles `clipped`. A thrown sink defaults to `unknown`;
182
- `classifyError` may explicitly return `failed` (classifier failure stays unknown). Unused handles are
183
- released, all sibling settlements and cleanup drain even on persistence failure, and later cleanup
184
- cannot overwrite success or uncertainty.
185
-
186
- ### Mandatory atomic full-consumption settlement
187
-
188
- The presentation binding's single `settle` operation must enforce:
189
-
190
- | Completion | Atomic persistence |
191
- | --- | --- |
192
- | `presented` | Complete the captured attempt **and all captured full-consumption receipts in the same transaction**. Return true only when the combined operation commits. |
193
- | `clipped` | Complete the attempt; no full-consumption receipt. |
194
- | `failed`, `unknown`, `released` | Complete the attempt; no success consumption receipt. |
195
-
196
- If receipt writing throws, both receipt writes and attempt completion must roll back. Do not reselect
197
- items or split `complete` and `recordConsumed` into separately awaited callbacks. Captured ownership
198
- still fences settlement; request cancellation and new delivery deferrals do not. TypeScript cannot
199
- supply isolation for a caller, so this is a mandatory port contract, tested in Square's real transaction.
200
-
201
- Presentation reports distinguish observed sink behavior from durable persistence. A returned sink
202
- with `not-recorded` or `error` still returned successfully; that alone proves only the supplied sink's
203
- documented effect, not model consumption or human display. Square retains throwing sinks as unknown and rethrows the original exception after draining.
204
- A missing native landing event or a canceled wait cannot prove the message never entered the host. Its single result stays
205
- `{ presented: true, activity }` only on recorded success, false on ownership refusal; unexpected
206
- success-settlement errors propagate. Batch returns its original sink value after all settlements,
207
- with the same error propagation. No schema, storage format or public Square result changes are needed.
1
+ # Delivery ledger
2
+
3
+ `@astrosheep/square/delivery-ledger` exports `DeliveryLedger` and its types, also available from the
4
+ package root. The per-user ledger defaults to `~/.square/delivery.v3.sqlite` and stores producer-neutral,
5
+ finished text cards, session attachment, routes, attempts and receipts. Producers own content and
6
+ recipient selection; adapters own transport behavior. Routes contain only `{kind, address}`.
7
+ A card may also carry producer-neutral presentation `details`:
8
+ `{kind: 'presentation', origin, author?, ref?, badge?, body}`. `text` remains the bounded model-facing
9
+ card; `body` holds the full Markdown for display. Receivers validate these details and render them
10
+ without opening producer storage. Cards without valid presentation details remain plain text.
11
+
12
+ Posting is idempotent by owner and key. Producer-push handoff and receiver-pull presentation have
13
+ separate attempt tracks, with cross-track exclusion based on ledger attempt state. Accepted or unknown
14
+ handoff does not establish presentation; uncertain effects must not be blindly replayed. Presentation
15
+ receipts record only the cards confirmed by the receiving boundary. A receipt means observed at that
16
+ boundary, not model comprehension. An observer may not detect a later plugin removing a card.
17
+ Receipt retention is finite: once evidence expires, Square retains unproved local unread until catch
18
+ or ACK, rather than inventing consumption or reinserting an uncertain old card.
19
+
20
+ The ledger is an outbox. Accepted and unknown attempts drop card text and details in the same
21
+ transaction, retaining only custody so an exact late observation can still write a receipt. A presented
22
+ presentation attempt deletes its card and attempts once no attempt is dispatching; a permanent exact
23
+ suppression prevents reposting the key. Unconfirmed accepted/unknown custody expires only after
24
+ 30 days from its latest settlement. Failed and released attempts keep content for retry. Receipts and
25
+ permanent suppressions expire in bounded batches after 30 days. Deleted sessions lose cards, attempts
26
+ and suppressions; sessions detached longer than 30 days lose cards and attempts. Session rows remain:
27
+ a deleted row is the authority for producer reconciliation and cannot be registered again.
28
+
29
+ Square folds receipts lazily into its own read state only for full activity cards; a shortened activity
30
+ card points to `square_catch` and cannot consume the full activity. Catch permanently suppresses the
31
+ corresponding ledger card where possible. Cancellation suppresses outstanding work without claiming it was seen and cannot
32
+ recall an external send already past its final check. Producers can call
33
+ `ledger.suppress({owner, key, scope: 'exact' | 'prefix', expiresAt?})` to suppress one key or a key
34
+ prefix. Omit `expiresAt` for permanent suppression within ledger retention, or supply an expiry for
35
+ temporary suppression. This does not consume Square activity; producer-owned exact ACK is described
36
+ in [square-api.md](square-api.md). The ledger does not match producer metadata.
37
+
38
+ Square posting, the Codex Stop watcher and OpenCode receivers retain their original ledger connection while
39
+ an already-invoked handoff has a pending `lateSettlement`. Timeout or cancellation returns promptly;
40
+ the connection closes after the last captured effect settles. It holds no open SQLite transaction and
41
+ grants no further send authority after the caller stops. An effect that never settles may retain an
42
+ idle connection until process exit. Late persistence failures produce redacted diagnostics rather than
43
+ reopening the ledger or retrying the effect. Pi presentation and Claude's independent exact-reference
44
+ confirmation callbacks retain their existing lifetimes.
45
+
46
+ Codex producers only post. Its native async Stop receiver observes the ledger without holding claims
47
+ while waiting; active UserPromptSubmit, PreToolUse and PostToolUse boundaries present synchronously.
48
+ See [Codex delivery](codex-delivery.md) for exact idle-epoch fencing, cancellation and recovery limits.
@@ -14,11 +14,8 @@ but the committed activity remains recoverable through `history` or a later `cat
14
14
  require a second acknowledgement. The separate `pending` query never consumes; its optional
15
15
  follow-up `ack(ids)` commits exact receipts with the same cancellation boundary.
16
16
 
17
- The single catch lease and independent delivery-deferral leases have distinct lifetimes. Cancelling
18
- an active catch releases only that catch's lease. Cancelling a deferral operation before commit
19
- prevents its mutation; once creation or renewal commits, the lease survives caller cancellation
20
- until explicit release, expiry or retirement of its captured seat. A committed release is likewise
21
- not undone. There is no automatic rollback lease or per-message cancellation timer.
17
+ Cancelling an active catch releases its catch lease, permitting still-unconsumed activity to proceed
18
+ at the next ordinary posting opportunity. It cannot recall export ownership already committed.
22
19
 
23
20
  Ownership and delivery have the same limitation: cancellation can stop work that has not entered the boundary, but it cannot withdraw an ownership effect or a transport send that already happened. The returned committed result and existing degradation classification remain authoritative.
24
21
 
@@ -1,91 +1,27 @@
1
1
  # Participant ownership
2
2
 
3
- Membership and host attachment are different facts. Membership says a participant is in the
4
- square; it owns their join history, read horizon and outgoing listens. Attachment says whether
5
- an exact opaque owner is executing for that participant now.
6
- A standing seat may be attached or detached. The artifact transaction is the sole custody
7
- authority; display spelling, wake addresses and the rebuildable HOME discovery index never
8
- grant ownership. There is no writable HostLedger ownership layer.
9
-
10
- Owners are opaque non-secret strings, not harness coordinates or authentication. Harness adapters
11
- encode their own identity; terminal owners use `user:<OS user>@<host>` and are never automatically
12
- detached or ended by a harness. A seat's optional wake route is self-contained transport readiness,
13
- not an owner or an alternative custody fact.
14
-
15
- ## Three endings
16
-
17
- - **The participant leaves:** `Participant.done()` ends membership, removes its seat, catch
18
- lease and delivery deferrals, and removes outgoing listens. A later explicit `join` establishes
19
- a fresh generation and read horizon. No host start or resume brings a voluntary leave back.
20
- - **The host session ends:** `detach(name, {owner, generation})` detaches only that exact owner and
21
- join generation. It clears wake readiness, catch ownership and delivery deferrals, without landing
22
- an activity or changing membership, listens or the read horizon. A detached participant is
23
- **away**, still receives normal landed audience and accumulates unread activity, but cannot write
24
- or receive proactive delivery. Away has no timeout; a session that never returns simply stays away.
25
- - **The host confirms permanent deletion:** `endHeld(name, {owner, generation})` ends membership
26
- with a fenced `done`, including for a detached seat. OpenCode's `session.deleted` uses this path.
27
- Pi shutdown, Codex SessionEnd and Claude session end do not prove permanent deletion and therefore
28
- detach.
29
-
30
- An explicit takeover remains `done -> join` in one transaction, whether the old seat is attached
31
- or detached. It transfers the name to the new owner with a fresh generation; old cleanup and
32
- recovery cannot reclaim it.
33
-
34
- ## Captured handles and restoration
35
-
36
- A `Square` captures no participant identity. `participant(name, {owner})` selects an attached,
37
- standing seat held by that exact owner without joining; never-joined, done, foreign and detached
38
- seats refuse with join recovery facts, not ghost handles. `seatsOf(owner)` is a read-only discovery
39
- surface for the owner's standing seats as `{name, generation, attachment}`. It includes attached and
40
- detached seats, but does not join or return done participants. See [square-api.md](square-api.md)
41
- for resource lifetimes and adapter selection.
42
-
43
- - `join(name, {owner, wakeAddress?})` atomically establishes membership and its seat when absent.
44
- A same-owner reconnect preserves the establishing generation. On a detached seat it also
45
- reattaches, using the operation's supplied wake address, and returns `reconnected`, with no
46
- activity, new read horizon or listening changes. A foreign owner gets `already_joined`; takeover
47
- must be explicit.
48
- - `reattach(name, {owner, wakeAddress?})` returns a handle for an exact-owner standing seat, or
49
- `null` for absent, foreign or done custody; it never creates membership. A foreign takeover racing
50
- the transaction can instead refuse. It can also refresh an attached seat's wake address subject to
51
- native-route preference. Host start/resume restores only detached seats found through
52
- `seatsOf(owner)` before arming delivery. One unavailable location or
53
- failed reattachment does not block the others. A new or forked session has a different owner and
54
- restores nothing. Hosts never infer restoration from a historical departure.
55
- - Participant mutations require both the captured generation and an attached current seat.
56
- Detach suspends existing handles; they cannot express, catch, listen, leave or change
57
- deferrals until reattachment. Rejoin/takeover fences old handles permanently, even if the same
58
- owner later reacquires the name. Host cleanup checks owner and generation inside its transaction;
59
- stale, foreign, done or already-detached detach changes nothing. Host `cancelDeliveries` also
60
- requires the captured owner/generation and an attached current seat; it does not consume activity.
61
-
62
- The HOME index supplies candidate paths only. Successful file-backed joins and non-null
63
- reattachments attempt best-effort publication; opening or expressing does not publish. Losing the
64
- index may delay restoration or delivery but cannot transfer a seat, erase delivery evidence or
65
- consume unread activity. A wake address is transport readiness for an attached seat, not an
66
- alternative ownership fact.
67
-
68
- ## Independent delivery deferrals
69
-
70
- `deferDelivery`, `renewDeliveryDeferral`, and `releaseDeliveryDeferral` require the same captured,
71
- attached current seat. Independent artifact-owned leases belong to one participant and generation,
72
- separately from catch ownership, delivery claims and receipts. Each has a fresh opaque ID, validated
73
- metadata match and expiry. It is not an acknowledgement intent or an activity.
74
-
75
- Each lease's nested own-property scalar equalities combine with AND; matching active leases combine
76
- with OR. Renewal cannot revive an expired lease. Release touches only its named live lease and
77
- returns false for an absent/expired ID. A current owner cannot use another participant's ID.
78
- Expiry is checked live. Detach, done, takeover and rejoin clear deferrals in the same transaction;
79
- reattachment never revives an old lease.
80
-
81
- Deferrals change only proactive eligibility. They preserve audience, history, unread counts and
82
- explicit catch. A caught record is not replayed after release. Producers, observers, claims and
83
- final send/presentation gates all require attached current custody and apply the same deferral
84
- policy. Neither detach nor a deferral can recall an already-dispatched external message.
85
-
86
- ## Acceptance boundaries
87
-
88
- Tests exercise foreign/stale/detached handles, same-owner restoration with unread activity intact,
89
- voluntary leave, explicit takeover, permanent deletion, exact-owner adapter lifecycle, generation
90
- fences and delivery eligibility. Assertions belong to authoritative facts, not helper ordering or
91
- display copy.
3
+ Membership and host attachment are distinct. Square owns the standing participant, opaque owner,
4
+ join generation, listens and read horizon. The host delivery ledger owns session attachment and
5
+ routes; it does not own membership. An owner is not an authentication credential.
6
+
7
+ `done` ends membership and outgoing listens. After the leave commits, Square best-effort withdraws
8
+ matching posted cards for that captured participant and join generation when they are not already in
9
+ ledger custody. It does not consume producer history or recall an in-custody effect. Cleanup failure
10
+ does not undo the leave or make it retry. A later join establishes a fresh generation; explicit takeover fences the
11
+ previous owner and generation. Host end only detaches the ledger session:
12
+ the participant remains away without a timeout, retains audience and unread activity, and cannot
13
+ write or receive proactive delivery. Start/resume attaches the ledger session, not individual seats;
14
+ there are no seat restore or detach hooks. A voluntary departure or takeover is never resurrected.
15
+ Host-confirmed deletion marks the ledger session deleted; the next privileged mutating Square
16
+ operation reconciles it and lands a generation-fenced `done`. Read-only history, status and
17
+ participants do not perform that mutation.
18
+
19
+ Participant handles capture owner and join generation; stale, departed or replaced custody refuses.
20
+ Sandbox selection and exact ACK authorize against locally known World custody alone,
21
+ without requiring access to the user ledger. This is not proof of current host attachment: a ledger-only
22
+ detach or deletion is learned at the next privileged producer reconciliation. A local control never
23
+ grants host delivery authority or revives a deleted session; export checks the actual ledger state.
24
+
25
+ Exact future ACK is producer-owned and recipient-scoped; see [square-api.md](square-api.md).
26
+ Proactive delivery suppression belongs in the host delivery ledger; see
27
+ [delivery-primitives.md](delivery-primitives.md).
@@ -1,58 +1,21 @@
1
1
  # Pi shared native delivery
2
2
 
3
- The shipped `plugins/pi/square-pi.js` remains the **only Square Pi extension**.
4
- Both its activity steer and advisory `nextTurn` send call the SDK-free shared
5
- `sendPiMessage` leaf compiled from `packages/agent-delivery/src`. Square keeps
6
- framing, custom type, display, preview/UI, observation/presentation evidence,
7
- uncertain-landing and canceled-batch suppression; the leaf neither schedules nor tracks.
8
-
9
- Pi injection and external wake injection acquire mutually exclusive artifact-owned content custody.
10
- An accepted or uncertain Paseo wake suppresses native Pi reinjection without asserting presentation
11
- or consumption. Only proven failed/released attempts can return to the automatic queue. Missing
12
- landing events, thrown sinks and expired claims do not authorize replay. Renderer details describe
13
- only the batch that won custody, not the earlier observed inbox. Budget-omitted activities belong to
14
- that same delivered batch: the omission line settles their presentation as `clipped`, without a
15
- full-consumption receipt. They stay available to explicit catch, but never get paged into later
16
- model completions or replayed on extension reload. See `delivery-primitives.md`.
17
-
18
- For independent existing-session delivery, opt into its local receiver:
19
-
20
- ```sh
21
- mkdir -m 700 /private/path/delivery
22
- pi --agent-delivery-socket /private/path/delivery/p.sock
23
- ```
24
-
25
- The parent must already be private and caller-owned. Explicit macOS Unix endpoint
26
- only; no discovery, registry, daemon or second extension. The flag is read lazily
27
- at session start. Missing flag creates no socket. Occupied paths fail closed.
28
- Session replacement closes outstanding connections and rebinds the same endpoint
29
- to the new identity; old targets reject.
30
-
31
- `observed` / `message_end` means only the matching native extension event was seen.
32
- Pi 1.1.0 emits that event before final append. It is **not durable admission,
33
- final append, model processing, completion or display**. No branch polling or
34
- cross-extension transform compatibility is promised.
35
-
36
- Standalone extensions can register `createPiReceiver` from the package's `./pi`
37
- subpath and use `sendPiMessage` directly. Factory registration creates no
38
- resources; start/shutdown own them. Session replacement and shutdown await the
39
- pending observer's retirement, including cleanup already begun by run cancellation.
40
- Cancellation releases native landing waits; it does not leave the observer running
41
- behind a completed lifecycle hook. Restart after cancellation waits for the old
42
- observer before opening its successor. Shutdown waits for in-flight automatic
43
- startup before ending that session, and awaits the session-end work. Raw SDK hosts
44
- must emit and await `session_shutdown` before `dispose()`;
45
- disposal alone does not retire extension-owned observers or receivers.
46
-
47
- Transport frame/key constraints, client
48
- `connectExisting`/`sendText` usage, receipt states, bounds and the exact validated
49
- runtime evidence live in `@astrosheep/agent-delivery` `README.md` and
50
- `VALIDATION.md`. Reproducer:
51
-
52
- ```sh
53
- npm run build
54
- node --import ./test/sandbox-env.js packages/agent-delivery/test/pi-runtime.mjs /absolute/installed/pi-1.1.0-package-root
55
- ```
56
-
57
- No real accounts/settings/sessions are used. Terminal keystrokes/rendering, other
58
- Pi builds and platforms are not dynamically validated.
3
+ `plugins/pi/square-pi.js` is the Square Pi extension. It watches the host delivery ledger and uses
4
+ the shared Pi send leaf for native injection. A receiver-pull presentation and producer-push handoff
5
+ compete through ledger attempt state, not route declarations. Accepted or uncertain handoff is not a
6
+ presentation receipt and must not be blindly replayed. The boundary's bounded batch renderer records
7
+ receipts only for presented cards. Square folds a receipt into read state only when its activity card
8
+ contained the full body; shortened cards point to catch.
9
+
10
+ Display items come directly from validated producer-neutral card details (`origin`, optional `author`,
11
+ `ref` and `badge`, and full Markdown `body`). Display never opens Square history. Missing or invalid
12
+ details fall back to card text. Model-facing reminder text is unchanged, and a full display body does
13
+ not make a shortened model-facing card eligible to consume producer unread activity.
14
+
15
+ Pi session start and shutdown attach and detach the ledger session, not Square seats. Interactive
16
+ cancellation suppresses outstanding local deliveries without marking activity seen; activity after
17
+ cancellation can notify normally. A send already past its final check cannot be recalled.
18
+
19
+ The `message_end` event is a native observation, not proof of model comprehension or final durable
20
+ append. Independent existing-session Pi delivery, socket constraints and runtime evidence are in
21
+ [agent-delivery's README](../packages/agent-delivery/README.md) and `VALIDATION.md`.
@@ -37,14 +37,12 @@ Use `catch` for consumption or `history` for archives. Exact parameters and sema
37
37
  come from the tool descriptions, shared with MCP through `square-tools.ts`.
38
38
 
39
39
  Each operation owns and closes its connection through the facade, including cancellation cleanup.
40
- Pi `session_shutdown` detaches that exact owner's seats, not membership: no `done` lands, listens
41
- and the read horizon remain, and mentions received while away stay unread. Catch ownership,
42
- deferrals and wake readiness are cleared. Detached participants cannot write or receive proactive
43
- delivery. On `session_start`, before watching, the extension uses `seatsOf(owner)` to discover only
44
- that exact owner's detached standing seats and `reattach(name, {owner, wakeAddress?})` to restore them.
45
- One failed seat/location does not block the others. New/forked harness owners restore nothing, voluntary
46
- `done` is never revived, and away has no timeout. Permanent deletion is a separate host-confirmed
47
- membership ending; Pi shutdown is not such proof. See [participant-ownership.md](participant-ownership.md).
40
+ Pi `session_shutdown` detaches that exact owner's ledger session without ending membership: no `done`
41
+ lands, listens and the read horizon remain, and mentions received while away stay unread. Detached
42
+ participants cannot write or receive proactive delivery. `session_start` attaches the same owner in the
43
+ ledger before watching; it does not restore individual seats. New/forked harness owners do not inherit
44
+ another owner's membership, voluntary `done` is never revived, and away has no timeout. Permanent
45
+ deletion is a separate host-confirmed membership ending; Pi shutdown is not such proof. See [participant-ownership.md](participant-ownership.md).
48
46
 
49
47
  Notification rendering remains independent of tool calls. Reload the extension after installing
50
48
  an updated package to register the tools in an existing Pi session.