@astrosheep/square 0.3.93 → 0.3.95
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.
- package/dist/activity-feed.d.ts +3 -5
- package/dist/activity-feed.js +16 -14
- package/dist/artifact.js +3 -3
- package/dist/attention.d.ts +19 -0
- package/dist/attention.js +30 -0
- package/dist/boundary-presentation.d.ts +2 -2
- package/dist/boundary-presentation.js +33 -40
- package/dist/catch-decisions.d.ts +5 -8
- package/dist/catch-decisions.js +45 -25
- package/dist/claude-delivery-status.js +10 -4
- package/dist/claude-delivery.js +19 -11
- package/dist/claude-mod.js +24 -53
- package/dist/cli/context.d.ts +9 -4
- package/dist/cli/context.js +30 -27
- package/dist/cli/express-presentation.d.ts +3 -1
- package/dist/cli/express-presentation.js +28 -16
- package/dist/cli/json.d.ts +3 -0
- package/dist/cli/json.js +14 -0
- package/dist/cli/mcp-server-command.js +2 -2
- package/dist/cli/observation-commands.d.ts +1 -3
- package/dist/cli/observation-commands.js +43 -56
- package/dist/cli/program.js +3 -3
- package/dist/cli/registry.js +7 -6
- package/dist/cli/square-commands.d.ts +0 -2
- package/dist/cli/square-commands.js +30 -44
- package/dist/codex-hook.d.ts +3 -2
- package/dist/codex-hook.js +13 -4
- package/dist/codex-queue.js +4 -4
- package/dist/decisions.d.ts +5 -16
- package/dist/decisions.js +9 -33
- package/dist/delivery-attempts.d.ts +52 -0
- package/dist/delivery-attempts.js +73 -0
- package/dist/delivery-deferral.js +2 -2
- package/dist/delivery-effects.d.ts +139 -0
- package/dist/delivery-effects.js +163 -0
- package/dist/delivery-health.d.ts +0 -1
- package/dist/delivery-health.js +1 -3
- package/dist/delivery-operations.d.ts +2 -2
- package/dist/delivery-operations.js +76 -101
- package/dist/delivery-primitives.d.ts +5 -0
- package/dist/delivery-primitives.js +3 -0
- package/dist/delivery.d.ts +1 -1
- package/dist/delivery.js +7 -6
- package/dist/help.js +14 -14
- package/dist/http-delivery.d.ts +16 -0
- package/dist/http-delivery.js +101 -0
- package/dist/inbox.d.ts +9 -22
- package/dist/inbox.js +23 -27
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.js +23 -24
- package/dist/model.d.ts +12 -21
- package/dist/model.js +5 -8
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +8 -5
- package/dist/operation-presentation.d.ts +6 -6
- package/dist/operation-presentation.js +55 -58
- package/dist/owner.d.ts +11 -0
- package/dist/owner.js +32 -0
- package/dist/paseo-delivery.d.ts +4 -1
- package/dist/paseo-delivery.js +7 -12
- package/dist/paseo-state.d.ts +2 -2
- package/dist/paseo-state.js +6 -4
- package/dist/plugins/opencode/delivery.js +27 -15
- package/dist/ports.d.ts +18 -47
- package/dist/presentation-operations.d.ts +14 -19
- package/dist/presentation-operations.js +51 -61
- package/dist/presentation.d.ts +7 -17
- package/dist/presentation.js +46 -91
- package/dist/receive.d.ts +66 -0
- package/dist/receive.js +54 -0
- package/dist/runtime.d.ts +1 -8
- package/dist/runtime.js +2 -17
- package/dist/seats.d.ts +2 -3
- package/dist/seats.js +7 -15
- package/dist/session-lifecycle.d.ts +6 -2
- package/dist/session-lifecycle.js +39 -11
- package/dist/sqlite-square.d.ts +36 -23
- package/dist/sqlite-square.js +162 -211
- package/dist/square-api.d.ts +16 -11
- package/dist/square-api.js +27 -23
- package/dist/square-core.d.ts +0 -14
- package/dist/square-core.js +0 -9
- package/dist/square-domain.d.ts +4 -2
- package/dist/square-domain.js +65 -52
- package/dist/square-facade.d.ts +47 -105
- package/dist/square-index.d.ts +5 -13
- package/dist/square-index.js +13 -38
- package/dist/square-legacy-framing.d.ts +2 -0
- package/dist/square-legacy-framing.js +8 -0
- package/dist/square-location.d.ts +1 -14
- package/dist/square-location.js +4 -70
- package/dist/square-migration-host-ledger.d.ts +2 -2
- package/dist/square-migration-host-ledger.js +6 -5
- package/dist/square-migration.d.ts +4 -1
- package/dist/square-migration.js +93 -38
- package/dist/square-receive.d.ts +6 -0
- package/dist/square-receive.js +18 -0
- package/dist/square-sqlite.d.ts +9 -3
- package/dist/square-sqlite.js +139 -114
- package/dist/square-tools.d.ts +7 -10
- package/dist/square-tools.js +21 -61
- package/dist/stream.js +4 -5
- package/dist/views.d.ts +23 -13
- package/dist/views.js +47 -53
- package/dist/wakes.d.ts +1 -5
- package/dist/wakes.js +4 -6
- package/examples/symmetric-domains.mjs +250 -0
- package/guides/application-facade-delivery-evidence.md +6 -6
- package/guides/attention-primitive.md +32 -0
- package/guides/change-waits.md +2 -2
- package/guides/claude-native.md +18 -9
- package/guides/codex-delivery.md +17 -6
- package/guides/delivery-primitives.md +180 -0
- package/guides/mcp-connection-lifetime.md +1 -1
- package/guides/mcp.md +3 -3
- package/guides/migration.md +148 -151
- package/guides/operation-cancellation.md +1 -1
- package/guides/participant-ownership.md +78 -47
- package/guides/pi-tools.md +34 -5
- package/guides/primitive-catch-consolidation.md +5 -5
- package/guides/primitive-history-consolidation.md +2 -2
- package/guides/primitive-status-consolidation.md +3 -3
- package/guides/primitive-storage-consolidation.md +1 -1
- package/guides/receive-primitive.md +90 -0
- package/guides/row-runtime-delivery-evidence.md +1 -1
- package/guides/row-storage-design.md +22 -28
- package/guides/square-api.md +314 -91
- package/guides/symmetric-domains.md +92 -0
- package/package.json +14 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/skills/square/SKILL.md +2 -6
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +27 -17
- package/plugins/paseo/client/palette.ts +18 -18
- package/plugins/paseo/client/square-message.tsx +17 -23
- package/plugins/pi/square-pi.js +17 -17
- package/skills/square/SKILL.md +2 -6
- package/dist/square-backend.d.ts +0 -13
- package/dist/square-backend.js +0 -1
- package/dist/square-stdio.d.ts +0 -22
- package/dist/square-stdio.js +0 -235
- package/dist/stdio-server.d.ts +0 -3
- package/dist/stdio-server.js +0 -212
- package/guides/backends.md +0 -193
package/guides/pi-tools.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pi native tools
|
|
2
2
|
|
|
3
|
-
The existing Square Pi extension registers `square_join`, `square_express`, `square_catch`, `square_history`, `square_attention`, `
|
|
3
|
+
The existing Square Pi extension registers `square_join`, `square_express`, `square_catch`, `square_history`, `square_attention`, `square_done`, and `square_status`. `square_attention` covers listen, unlisten and ignore; `square_status` also shows who you listen to. No additional MCP server or subprocess is needed.
|
|
4
4
|
|
|
5
5
|
Tools use the `square` namespace with codemode exposure. Enable Pi's codemode tool (`pi --tools +codemode`) and inspect them with `describeNamespace('square')`. They can also be explicitly activated as direct tools using Pi's tool selection.
|
|
6
6
|
|
|
@@ -11,11 +11,40 @@ const result = await tools.square_express({
|
|
|
11
11
|
body: 'A different angle on this.',
|
|
12
12
|
mentions: ['aoi'],
|
|
13
13
|
});
|
|
14
|
-
text(result);
|
|
14
|
+
text(result); // CLI text: confirmation and bounded unread previews
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
`location` defaults to `SQUARE_LOCATION`; relative paths use the current call's cwd.
|
|
17
|
+
`location` defaults to `SQUARE_LOCATION`; relative paths use the current call's cwd. Join requires
|
|
18
|
+
an explicit `as`. For later participant operations, an explicit `as` must name a current attached
|
|
19
|
+
seat of the live Pi owner; without it, exactly one such seat is required. Status checks an explicit
|
|
20
|
+
`as` the same way, but without `as` uses the sole attached seat as viewer or gives an unfiltered
|
|
21
|
+
overview if there are zero or multiple. The extension encodes the live Pi session with
|
|
22
|
+
`harnessOwner({channel: 'pi', session})`, never a model-provided session id, without mutating
|
|
23
|
+
the process environment.
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
All seven tools return the CLI's human-readable text, without an `outputSchema` or
|
|
26
|
+
`structuredContent`. In Pi codemode, a successful call resolves to a `string`:
|
|
27
|
+
use `text(result)`, not `text(result.text)`. Failures are marked as failed tool results;
|
|
28
|
+
codemode rejects with the readable error and recovery commands rather than returning
|
|
29
|
+
an error object. For machine-readable domain results, use the [SDK](square-api.md).
|
|
20
30
|
|
|
21
|
-
|
|
31
|
+
`express` confirms landing and reach warnings without echoing the sent body. Unread
|
|
32
|
+
context shows at most the latest five directed activities, in chronological order,
|
|
33
|
+
with at most 400 Unicode characters per preview. Already consumed activities are
|
|
34
|
+
excluded, including those beyond an earlier unread hole. Previews never consume
|
|
35
|
+
activity; the text supplies a `catch` command and the count of other unread activities.
|
|
36
|
+
Use `catch` for consumption or `history` for archives. Exact parameters and semantics
|
|
37
|
+
come from the tool descriptions, shared with MCP through `square-tools.ts`.
|
|
38
|
+
|
|
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).
|
|
48
|
+
|
|
49
|
+
Notification rendering remains independent of tool calls. Reload the extension after installing
|
|
50
|
+
an updated package to register the tools in an existing Pi session.
|
|
@@ -20,7 +20,7 @@ Deliverer evidence only, **not independent review or acceptance**.
|
|
|
20
20
|
|
|
21
21
|
| Removed | Canonical owner / retained boundary |
|
|
22
22
|
| --- | --- |
|
|
23
|
-
| `CatchDecision`, its unused `changed`, and its all-full perception map | `CatchSelection` contains raw selected activities, participant, cursor/remaining, say ordinals, clock, count/
|
|
23
|
+
| `CatchDecision`, its unused `changed`, and its all-full perception map | `CatchSelection` contains raw selected activities, participant, cursor/remaining, say ordinals, clock, count/cap/terminal facts. Pure `decideCatch` selects and writes receipts through `SquareWrite`, then captures these facts in that transaction. |
|
|
24
24
|
| `CatchSelectionResult` combining public activities with a second raw observation | `catchUp` admits the owner, checks the lease ID and invokes `decideCatch` in one receipt transaction, publishes presence best effort, and returns that exact selection. It no longer performs public conversion. |
|
|
25
25
|
| `CatchSelectionObservation` and `WatchPresentation` | `catchOwned` carries the same selection through completion, alongside actual lifecycle stop, waitStarted and replaced facts. No second selected-record wrapper or public page is built inside the lifecycle. |
|
|
26
26
|
| Completion's separate empty-result construction | `observeCatchSelection` captures the same concrete contract using `SquareRead` without marking seen. Only a completion without a committed selection calls it; it does not reopen or rehydrate a committed page. Empty ordinals are `{}` without an unnecessary selector call. |
|
|
@@ -34,7 +34,7 @@ Necessary abstractions remain: typed transaction capabilities, pure selection, o
|
|
|
34
34
|
## Preserved lifecycle and observation timing
|
|
35
35
|
|
|
36
36
|
- Lease acquisition retains its own transaction. Lease-ID validation, selection, markSeen, cursor, remaining and selected-page facts share the `catchUp` receipt transaction. A replaced waiter cannot insert a receipt in the gap after its heartbeat.
|
|
37
|
-
- Revision is still captured before evaluation. Heartbeats,
|
|
37
|
+
- Revision is still captured before evaluation. Heartbeats, lease-paused quiet expiry, replacement and ID-fenced signal-free cleanup remain unchanged. Already-active/replaced/capped/quorum remain distinct from empty-now/stale.
|
|
38
38
|
- Successful selection never falls back to a postcommit page/context read. Presence publication, lease release and notification enrichment remain best effort after authoritative consumption. Optional nearby presence can be unavailable without erasing the selected page.
|
|
39
39
|
- Empty terminal/quiet completion reads authoritative cursor and filtered remaining without markSeen. It never invents a null cursor after consumption. Seen holes, continuous cursor, historical catch and notification latest-join semantics remain unchanged.
|
|
40
40
|
- Public conversion now occurs later, at each API exit, rather than in the action/lifecycle. Selection facts still reflect the receipt transaction, not optional presence time. Empty completion's clock is captured when constructing that read-only selection; no selected body is hydrated. No SDK default or wire result changes are intended.
|
|
@@ -80,9 +80,9 @@ The first full run exposed an unnecessary `sayOrdinals([])` read on empty SDK co
|
|
|
80
80
|
|
|
81
81
|
Boundary evidence:
|
|
82
82
|
|
|
83
|
-
- `performance`: real raw selection hydrates only its bounded page; remaining uses directedCount; presence/rendering never rehydrates it. A new postcommit mutation fixture changes own count
|
|
84
|
-
- `application-boundary`: a real delivered receipt triggers failing host publication and a failing postcommit clock/presence read; catch still returns the consumed public page and its original projection facts, with enrichmentUnavailable and no raw activities projection. A later catch is empty. Existing real leased replacement, cancellation cleanup
|
|
85
|
-
- `presentation`: public/raw rendering parity checks multiline body, activity ID, reply ID, mention metadata, done and listen; presence omits bodies. Raw read remains empty
|
|
83
|
+
- `performance`: real raw selection hydrates only its bounded page; remaining uses directedCount; presence/rendering never rehydrates it. A new postcommit mutation fixture changes own count and pending rows after selection and rejects any action-level read: returned ordinals/cursor/remaining/count/clock still match the receipt transaction. A mismatched lease ID returns null without revision/receipt change.
|
|
84
|
+
- `application-boundary`: a real delivered receipt triggers failing host publication and a failing postcommit clock/presence read; catch still returns the consumed public page and its original projection facts, with enrichmentUnavailable and no raw activities projection. A later catch is empty. Existing real leased replacement, cancellation cleanup and quiet expiry fixtures pass, including the preserved consumed cursor after an actual say.
|
|
85
|
+
- `presentation`: public/raw rendering parity checks multiline body, activity ID, reply ID, mention metadata, done and listen; presence omits bodies. Raw read remains empty.
|
|
86
86
|
- `row-domain`, `core`, `delivery`, `perception-projection`: filter-before-limit, exact repeat, original receipt timestamp, gap/cursor and latest-join differences remain tested. Obsolete changed assertions were replaced by actual receipts, or removed only where the immediately adjacent unchanged receiptAssignments equality already proves no write. No boundary assertion was weakened to preserve a retired mechanism.
|
|
87
87
|
- `operation-cancellation`, `square-facade`: commit survives response abort; SDK returns only its established CatchResult, no application body projections. CLI process coverage retains filtered continuation, mention/body visibility, stable IDs and lifecycle feedback. MCP continues serializing data only.
|
|
88
88
|
- Production reference search for `CatchDecision|CatchSelectionResult|CatchSelectionObservation|WatchPresentation|exposeCaught` returned no matches (excluding dist/node_modules); `git diff --check` passed. CLI has no `projection.activities.find` or raw reconstruction.
|
|
@@ -57,9 +57,9 @@ Entry still uses the actual selector with explicit `['say', 'done']` kinds and i
|
|
|
57
57
|
## Necessary distinctions retained
|
|
58
58
|
|
|
59
59
|
- **Defaults:** SDK `Square.history` is unbounded. SDK `Participant.history` defaults to ten. Application/CLI/MCP default to ten, cap explicit limits at 100, and reject an implicit merged context larger than 100 with the original `operation.historyBounds` detail. Supplying a limit bounds that context. Application's stricter grep/fixed, non-empty search, finite since and safe nonnegative context validation is unchanged; SDK search remains intentionally looser.
|
|
60
|
-
- **Three subsets:** raw selected records can contain reads and historical actorless lifecycle records; public `Activity` omits read/actorless records but retains listen/ignore; ordinary terminal visibility contains join/say/done
|
|
60
|
+
- **Three subsets:** raw selected records can contain reads and historical actorless lifecycle records; public `Activity` omits read/actorless records but retains listen/ignore; ordinary terminal visibility contains join/say/done. Hidden listener events still occupy page positions. Since/context windows still select raw bookkeeping; ordinary history excludes reads. Field formatting uses raw records; CLI JSON now serializes the public SDK result and omits bookkeeping records. No third event model was introduced.
|
|
61
61
|
- **Paging:** cursor bounds remain exclusive stable IDs, sparse context counts existing positions, and from/mention/search intersect before applying the limit. An after cursor selects the oldest eligible page; otherwise the newest eligible page is selected. `order` only reverses the selected page. Continuation uses the terminal-visible subset and the same filtered candidate universe; a listener-only page has no invented terminal anchor. Audience paging continues through empty intersections.
|
|
62
|
-
- **Projection:** ordinals, presence anchors,
|
|
62
|
+
- **Projection:** ordinals, presence anchors, roster facts and final data come from the same read callback. The projection clock is now sampled within that callback instead of after the intermediate async presentation completed. It is still an observation-only operation with no receipt, presence or lease writes. Overflow is rejected before unnecessary anchor/ordinal enrichment.
|
|
63
63
|
- CLI and MCP require no policy changes: CLI continues formatting raw/terminal records and owner-produced continuation; MCP serializes public data only. Catch's renderer-accessor changes are owned by its separate lane.
|
|
64
64
|
|
|
65
65
|
## Verification
|
|
@@ -63,14 +63,14 @@ For completeness, **whole integrated source** against fixed `501ddc2` is 110 fil
|
|
|
63
63
|
|
|
64
64
|
Full versus filtered roster is a real distinction: status data omits never-joined historical actor names, while participants data retains them. `knownParticipantCount` separately preserves the complete-roster continuation count; it is not `status.data.participants.length` or the standing count.
|
|
65
65
|
|
|
66
|
-
The amended guidance's reachable-latest clause is applied: the selector remains newest `say`/`done`. Both require an actor in valid storage, whereas
|
|
66
|
+
The amended guidance's reachable-latest clause is applied: the selector remains newest `say`/`done`. Both require an actor in valid storage, whereas `read` is not selected. Therefore status has no reachable raw/public latest distinction. The conversion guard remains conservative, but no hypothetical duplicate projection is retained. History and other operations' genuine raw/public distinctions are untouched by this lane.
|
|
67
67
|
|
|
68
68
|
## Behavior and timing evidence
|
|
69
69
|
|
|
70
|
-
- `test/projections.test.js`: exact canonical status data, full versus filtered roster, absent duplicate projections,
|
|
70
|
+
- `test/projections.test.js`: exact canonical status data, full versus filtered roster, absent duplicate projections, cap/throttle fields, and read exclusion from latest selection. Existing viewer perception, exact-spelling rejoin and bounded hydration assertions remain. Shared watching/recent/lingering policy remains read-only.
|
|
71
71
|
- `test/application-boundary.test.js`: configured named, discovered (including blank environment name), explicit blank, explicit override and ambient viewer; body perception and attention names; unchanged artifact state and ownership/presence ledger after status.
|
|
72
72
|
- `test/core.test.js`: status and participants continue sharing actual authored and receipt times, including a fresh rejoin and watcher.
|
|
73
|
-
- `test/process/square-cli-render.test.js`: the compact ten-person preview now includes a valid historical never-joined actor in the artifact. Status still hides that actor but its executable continuation uses the full count 14 rather than filtered count 13; participants prints the complete roster. Existing
|
|
73
|
+
- `test/process/square-cli-render.test.js`: the compact ten-person preview now includes a valid historical never-joined actor in the artifact. Status still hides that actor but its executable continuation uses the full count 14 rather than filtered count 13; participants prints the complete roster. Existing exact rejoin, attention, clipping/public-id continuation and presence feedback remain covered.
|
|
74
74
|
|
|
75
75
|
No observation timing change is intended: optional viewer discovery still precedes status's resource read; the clock is sampled once inside the transaction, and all domain data, classification, perception and rendering annotations are assembled in that read. Queries perform no I/O or mutations themselves. SDK participant/snapshot shapes and MCP serialization of data remain unchanged. No join/claim is introduced.
|
|
76
76
|
|
|
@@ -25,7 +25,7 @@ Deliverer evidence, not independent review or acceptance.
|
|
|
25
25
|
| `square-state.ts` legacy SQLite framing | `square-sqlite.ts`: read-only owned-v1 recognition beside row framing/codecs |
|
|
26
26
|
| `square-state.ts` legacy payload validation | `square-migration.ts`: explicit legacy envelope, order/gap and assigned-reference checks, permissive finite route data and path-specific nonfinite rejection |
|
|
27
27
|
| General-model snapshot/runtime DTOs | `square-sqlite.ts`: explicit import/export DTOs, not runtime transaction state |
|
|
28
|
-
| Dead `StoredActHead`, `
|
|
28
|
+
| Dead `StoredActHead`, `findParticipantName`, empty `ReceiverRoute` alias | Deleted; interchange routes use the existing `WakeRoute` type |
|
|
29
29
|
|
|
30
30
|
There are no forwarding stubs. The renamed build preparation is the actual implementation, not an alias. File SDK build, synchronous memory build and application build share it. Application build returns the normalized configuration from canonical creation rather than reconstructing it. Ordinary storage/resource imports perform no guide reads; the first build reads only its selected guides and caches them.
|
|
31
31
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Transaction-local receive and consumption
|
|
2
|
+
|
|
3
|
+
`@astrosheep/square/receive` admits items and their settled audience, selects
|
|
4
|
+
received heads without consumption, and records sparse first-write-wins receipts.
|
|
5
|
+
It has no runtime dependencies, Square membership, SQLite or transport requirement.
|
|
6
|
+
For computing an audience before admission, see [attention](attention-primitive.md).
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { receive, consumeReceived } from '@astrosheep/square/receive';
|
|
10
|
+
|
|
11
|
+
// Both callbacks belong to your storage implementation, not this package.
|
|
12
|
+
store.transaction(tx => receive(tx, {
|
|
13
|
+
item: { key: 'opaque:west/7?hello', data: { text: 'Hello' } },
|
|
14
|
+
audience: [{ recipient: 'east:bob', via: 'link' }],
|
|
15
|
+
}));
|
|
16
|
+
const page = store.transaction(tx => consumeReceived(tx, 'east:bob', {
|
|
17
|
+
kind: 'page', query: { sender: 'west:alice' }, limit: 10,
|
|
18
|
+
}, Date.now()));
|
|
19
|
+
// { items: [{ key, data, via }], newlyConsumed, remaining }
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`store` and `tx` above are caller-owned storage, not exports. Implement
|
|
23
|
+
`ReceiveRead<K,D,V,Q>` / `ReceiveWrite<K,D,V,Q>` structurally; each function only
|
|
24
|
+
requires the `Pick` of methods it uses. `K extends string | number` is an opaque
|
|
25
|
+
equality identity: no ordering, parsing, numeric sequence, or `act/N` convention
|
|
26
|
+
is imposed. The storage defines head order and query semantics. `D`, route `V`,
|
|
27
|
+
and query `Q` are caller data. Recipients are strings; the caller owns canonical
|
|
28
|
+
identity and eligibility. Item and address keys must be unique in storage.
|
|
29
|
+
|
|
30
|
+
## Capabilities and ownership
|
|
31
|
+
|
|
32
|
+
- `insertItem({key,data})` and `insertAddress(key,{recipient,via},order)` admit an
|
|
33
|
+
item and its audience in supplied order. `receive` permits an empty audience.
|
|
34
|
+
Supply unique recipient keys; duplicate items/addresses must throw, never
|
|
35
|
+
overwrite or silently deduplicate. Roll back the whole admission on failure.
|
|
36
|
+
- `heads(recipient,query,{unconsumed,limit})` applies the query and consumption
|
|
37
|
+
predicate **before** limiting, returning ordered `{key,via}` heads.
|
|
38
|
+
`addressed(recipient,key)` ignores receipt state, but checks addressedness.
|
|
39
|
+
- `load(keys)` hydrates the selected keys once as a `ReadonlyMap<K,D>`.
|
|
40
|
+
Missing keys are errors; an explicitly stored `undefined` value is not missing.
|
|
41
|
+
`count(recipient,query,unconsumed)` counts the same selection without a limit.
|
|
42
|
+
- `receipt({recipient,item})` reads `{at}` or `undefined`.
|
|
43
|
+
`insertReceipt(ref,at)` returns true only for a new coordinate and preserves the
|
|
44
|
+
first timestamp. The identity is `(recipient,item)`, not a cursor or generation.
|
|
45
|
+
|
|
46
|
+
All functions are synchronous. Supply capabilities from **one isolated,
|
|
47
|
+
caller-owned transaction**, with storage uniqueness constraints and rollback on
|
|
48
|
+
any thrown error, including failures during hydration, receipt insertion or the
|
|
49
|
+
final count. No capability or selected page should escape that transaction for
|
|
50
|
+
later consumption. The leaf does not start, commit, retry or emulate transactions.
|
|
51
|
+
Its atomicity depends on this caller obligation.
|
|
52
|
+
|
|
53
|
+
## Selection and receipts
|
|
54
|
+
|
|
55
|
+
`selectReceivedHeads(tx,recipient,selection)` never hydrates or writes. A page is
|
|
56
|
+
`{kind:'page',query,limit}` and always selects unconsumed heads; `limit` must be a
|
|
57
|
+
positive safe integer, with no policy maximum. An exact selection is
|
|
58
|
+
`{kind:'exact',key,remainingQuery}` and remains repeatable after consumption.
|
|
59
|
+
|
|
60
|
+
`consumeReceived` selects inside the supplied transaction, hydrates all selected
|
|
61
|
+
keys before any receipt insertion, preserves head order, records the captured
|
|
62
|
+
coordinates and counts matching unconsumed items. Exact remaining uses
|
|
63
|
+
`remainingQuery`; page remaining uses `query`. Repeating exact consumption returns
|
|
64
|
+
the same item with `newlyConsumed: 0`, not a second receipt.
|
|
65
|
+
|
|
66
|
+
`recordConsumed(tx,refs,at)` only needs `insertReceipt`. It records captured
|
|
67
|
+
coordinates without reselecting, loading or checking eligibility. Duplicate refs
|
|
68
|
+
are idempotent through storage and cannot change the first timestamp. Timestamps
|
|
69
|
+
must be finite numbers (negative/fractional timestamps are allowed). Nonnumber
|
|
70
|
+
limits/timestamps throw `TypeError`; out-of-range numbers throw `RangeError`.
|
|
71
|
+
`ReceiveError` exposes `code: 'not_addressed' | 'missing_item'` and the opaque `key`.
|
|
72
|
+
Storage errors propagate unchanged; they still require caller rollback.
|
|
73
|
+
|
|
74
|
+
This is not a remote message protocol, replay envelope, permission system,
|
|
75
|
+
ordering service, billing ledger or exactly-once external effect guarantee.
|
|
76
|
+
Delivery attempts and presentation are separate from consumption. The
|
|
77
|
+
[symmetric domains example](symmetric-domains.md) composes all three public
|
|
78
|
+
primitive entrypoints without constructing Square.
|
|
79
|
+
|
|
80
|
+
## Square composition
|
|
81
|
+
|
|
82
|
+
Square uses these functions for production landing, catch and `markSeen` against
|
|
83
|
+
its existing activity, audience and receipt tables. Numeric activity indexes stay
|
|
84
|
+
internal keys; the primitive does not know Square IDs. Square retains validation,
|
|
85
|
+
limits, filtering, perception, ownership, leases, hints and error mapping. The
|
|
86
|
+
empty-catch read probe does not hydrate or acquire a writer; a nonempty probe is
|
|
87
|
+
reselected inside the writer. Ordinary catch sees historical receipt holes,
|
|
88
|
+
including before rejoin; proactive pending still starts after the latest join.
|
|
89
|
+
The artifact schema/format and receipt identity are unchanged. See the
|
|
90
|
+
[Square API](square-api.md) for product operations.
|
|
@@ -10,7 +10,7 @@ Candidate implementation: `833d6f15c9071767eb49a9562a4c42a93c6f4000` plus post-r
|
|
|
10
10
|
| Whole-history fold on normal operations; replay delivery/perception closures | `square-domain.ts::deriveLanding` maintains participant, attention and ordered audience indices once at landing; `runtime.ts` computes cursor/presence/terminal from narrow domain facts. |
|
|
11
11
|
| `FromState`/delta bridges and old core append/observation update helpers | Removed. `SquareWrite.land/markSeen/putLease/removeLease/replaceRoutes` are the finite domain mutations. Memory uses the same SQLite driver in `:memory:`, not a second selector/policy implementation. |
|
|
12
12
|
| Renderer `.state` inputs and replay-based ordinal/perception lookup | `views.ts`, `perception-projection.ts` and presentation operations settle selected bodies, ordinals, counts and perceptions inside the transaction; renderers receive detached values. |
|
|
13
|
-
| Join/status/
|
|
13
|
+
| Join/status/done snapshot loads for counts | `joinFacts`, standing counts, roster/status aggregates and header reads. Public SDK snapshot is no longer used by these production callers. |
|
|
14
14
|
| Global whole-history notification/wake enumeration | Bodyless `pendingAudience` groups with a captured activity upper bound and recipient join coordinates; receivers use their own `directed` relation. Scans advance past withheld groups and do not restart on unrelated writes. |
|
|
15
15
|
| Whole-history native/Claude currentness and cancellation | Exact pending facts, ordered routes, lease and captured host fences; cancellation selects activity heads by descending coordinate and tests timestamp. Host/network work stays outside artifact transactions. |
|
|
16
16
|
| Preliminary full load before file-backed open/probe/wait | Validated header/schema boundary, revision-only observer; selected row validation on access. Full doctor is explicit. |
|
|
@@ -27,7 +27,7 @@ Replace AGENTS.md's `All behavior operates on SquareState ...` sentence, with th
|
|
|
27
27
|
|
|
28
28
|
> Behavior operates on typed Square domain facts obtained through transaction-scoped reads and domain transitions. SQLite schema, SQL, and storage framing remain private to the artifact boundary. Partial fact reads must not masquerade as a complete SquareState.
|
|
29
29
|
|
|
30
|
-
One typed domain representation: activities, sparse seen receipts, catch leases, and ordered published routes, plus small configuration facts. Current participants/attention and historical landed audience are reconstructible indices. No inbox, continuous cursor, pending flag, eligibility, persisted ordinal, or receiver acknowledgement watermark.
|
|
30
|
+
One typed domain representation: activities, sparse seen receipts, catch leases, and ordered published routes, plus small configuration facts. Current participants/attention and historical landed audience are reconstructible indices. No inbox, continuous cursor, pending flag, eligibility, persisted ordinal, or receiver acknowledgement watermark.
|
|
31
31
|
|
|
32
32
|
Three layers:
|
|
33
33
|
- Domain actions validate admission and produce `Act` values; domain projections combine the read capabilities below. Host/network work is outside artifact transactions.
|
|
@@ -82,7 +82,6 @@ interface ActivityFilter {
|
|
|
82
82
|
readonly kinds?: readonly StoredAct['kind'][];
|
|
83
83
|
readonly actors?: readonly string[];
|
|
84
84
|
readonly actorMatch?: 'identity' | 'exact'; // default identity
|
|
85
|
-
readonly actorRequired?: true;
|
|
86
85
|
readonly afterAt?: number; // exclusive; no implicit upper-time bound
|
|
87
86
|
}
|
|
88
87
|
interface IndexPage {
|
|
@@ -144,9 +143,6 @@ interface SquareRead {
|
|
|
144
143
|
attention(listener: string): readonly AttentionFact[]; // sinceIndex ascending
|
|
145
144
|
incomingAttention(sender: string): readonly AttentionFact[];
|
|
146
145
|
// incoming matches nameKey(target); includes listen and ignore, not only joined actors
|
|
147
|
-
hold(): { readonly active: boolean; readonly at?: number;
|
|
148
|
-
readonly reason?: string; readonly actor?: string };
|
|
149
|
-
|
|
150
146
|
activity(index: ActivityIndex): StoredAct | undefined;
|
|
151
147
|
activityHeads(filter: ActivityFilter, page: IndexPage): FactPage<ActivityHead>;
|
|
152
148
|
activities(indexes: readonly ActivityIndex[]): readonly StoredAct[];
|
|
@@ -232,7 +228,7 @@ interface LandingFacts {
|
|
|
232
228
|
function deriveLanding(activity: StoredAct, facts: LandingFacts): LandingEffect;
|
|
233
229
|
```
|
|
234
230
|
|
|
235
|
-
`deriveLanding` is pure and shared by runtime and rebuild. `land()` reads the necessary narrow facts, validates structural invariants (not action admission again), allocates **header.nextActIndex**, calls this transition, and applies the effect plus nextActIndex increment atomically. Migration supplies the preserved assigned indices; it never calls the allocator or admission validation. Earlier reply author lookup uses the existing activity row
|
|
231
|
+
`deriveLanding` is pure and shared by runtime and rebuild. `land()` reads the necessary narrow facts, validates structural invariants (not action admission again), allocates **header.nextActIndex**, calls this transition, and applies the effect plus nextActIndex increment atomically. Migration supplies the preserved assigned indices; it never calls the allocator or admission validation. Earlier reply author lookup uses the existing activity row; missing earlier coordinate means no author. Valid replay never requires a future author because reply < own index.
|
|
236
232
|
|
|
237
233
|
`markSeen` accepts any nonnegative index below nextActIndex, even if no activity/participant exists. It refuses unassigned coordinates and non-finite timestamps; it inserts only missing exact-owner receipts. Actions—not a receipt FK—ensure catch/native writes concern the intended activities. Lease writers similarly retain unknown/raw owner fallback. Only receipt insertion marks seen; presentation outcome, cancellation, and wake evidence do not.
|
|
238
234
|
|
|
@@ -257,14 +253,12 @@ CREATE TABLE square_meta (
|
|
|
257
253
|
CREATE TABLE activities (
|
|
258
254
|
act_index INTEGER PRIMARY KEY CHECK (act_index BETWEEN 0 AND 9007199254740991),
|
|
259
255
|
at REAL NOT NULL,
|
|
260
|
-
kind TEXT NOT NULL CHECK (kind IN ('join','done','say','
|
|
261
|
-
actor_json TEXT COLLATE BINARY,
|
|
262
|
-
actor_key_json TEXT COLLATE BINARY,
|
|
256
|
+
kind TEXT NOT NULL CHECK (kind IN ('join','done','say','read','listen','ignore')),
|
|
257
|
+
actor_json TEXT COLLATE BINARY NOT NULL,
|
|
258
|
+
actor_key_json TEXT COLLATE BINARY NOT NULL,
|
|
263
259
|
reach TEXT CHECK (reach = 'bell'),
|
|
264
260
|
reply_index INTEGER CHECK (reply_index >= 0 AND reply_index < act_index),
|
|
265
261
|
payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),
|
|
266
|
-
CHECK ((actor_json IS NULL) = (actor_key_json IS NULL)),
|
|
267
|
-
CHECK (kind IN ('hold','resume') OR actor_json IS NOT NULL),
|
|
268
262
|
CHECK (kind = 'say' OR (reach IS NULL AND reply_index IS NULL))
|
|
269
263
|
);
|
|
270
264
|
CREATE INDEX activity_kind_index ON activities(kind, act_index);
|
|
@@ -333,9 +327,9 @@ CREATE INDEX audience_recipient ON landed_audience(recipient_key_json, act_index
|
|
|
333
327
|
No foreign keys. In particular receipts must not reference activities or participants; replies/through must not require existing rows; leases/routes must not require known names. Derived tables are maintained and checked against authority, not used to reinterpret permissible v1 authority as invalid. `next_act_index > greatest existing activity index` and receipts < next_act_index are checked by the boundary (all receipts only on full integrity/import; inserted receipts on writes). No contiguous-index constraint. Finite fractional activity/receipt/lease times remain REAL, not INTEGER. Number-safe limits are enforced in the codec and allocator.
|
|
334
328
|
|
|
335
329
|
Activity payload shapes, with optional-property presence preserved:
|
|
336
|
-
- join
|
|
330
|
+
- join: `{}`.
|
|
337
331
|
- say: `{body: string, mentions?: string[]}`; reach/reply live only in their columns.
|
|
338
|
-
- done
|
|
332
|
+
- done: `{body?: string}`.
|
|
339
333
|
- read: `{through: number}`; no reference check on through.
|
|
340
334
|
- listen/ignore: `{target: string}`; no participant reference check on target.
|
|
341
335
|
Actor's original spelling lives in actor_json; actor_key_json is its indexed identity derivative. Neither is repeated in payload. Indices store coordinates/keys, never duplicate bodies.
|
|
@@ -344,7 +338,7 @@ Route payload contains location, original participant spelling, channel, address
|
|
|
344
338
|
|
|
345
339
|
Preserve finite route epoch/extra JSON values and empty strings; do not otherwise tighten their legacy shapes. Use ordinary JSON encoding, not a bespoke numeric codec. Migration explicitly refuses non-finite numbers anywhere in a route (updatedAt, epoch, or nested extras) before DDL/inserts and leaves the artifact unchanged; never silently coerce them to null. These exponent-overflow values can pass the old permissive validator on manually authored JSON, but are not non-finite values normally persisted by the v1 JSON.stringify writer. Runtime codecs likewise require finite route numeric values. Raw schema equality is not receipt or participant equality.
|
|
346
340
|
|
|
347
|
-
No receipt `state` column: all receipts are seen. No
|
|
341
|
+
No receipt `state` column: all receipts are seen. No additional name registry: a participant is first touched by ANY actor-bearing activity, not necessarily join.
|
|
348
342
|
|
|
349
343
|
## 4. Exact derived transitions and routes
|
|
350
344
|
|
|
@@ -352,7 +346,7 @@ Landing uses pre-activity participant/attention facts:
|
|
|
352
346
|
1. Compute a say audience first. Resolve deduplicated mentions against standing roster (bell: all standing); then standing reply author; then active listeners in roster order. Skip sender and duplicate recipients. Ignore blocks all non-bell reach; bell bypasses ignore. Store ordered unique recipients and priority **bell > mention > reply > attention**. Explicit self mention remains in activity metadata but creates no self audience edge. Missing/departed reply author creates no edge; action result retains existing replyAuthorNotHere semantics.
|
|
353
347
|
2. Touch actor if new: name is first actor spelling, joined=false, done=false, sayCount=0. Update lastActiveAt with max(existing, activity.at), not latest-by-index time.
|
|
354
348
|
3. join sets joined=true/done=false and lastJoinIndex=index. done sets joined=false/done=true and clears OUTGOING listen only. Ignore survives departure/rejoin; incoming attention is not cleared. Say increments lifetime count, even for unusual imported prejoin/postdone sequences.
|
|
355
|
-
4. listen inserts listen only when not already listening; removes matching ignore. ignore removes matching listen and inserts ignore only when absent. Preserve target's first retained spelling and relation order, including unknown/self targets. A no-op legacy activity still touches actor time; replay never applies the current ten-name admission cap.
|
|
349
|
+
4. listen inserts listen only when not already listening; removes matching ignore. ignore removes matching listen and inserts ignore only when absent. Preserve target's first retained spelling and relation order, including unknown/self targets. A no-op legacy activity still touches actor time; replay never applies the current ten-name admission cap. Read does not acknowledge receipts or advance a persisted cursor.
|
|
356
350
|
|
|
357
351
|
There is one production transition, no SQL triggers and no separate migration fold. Test-only frozen old fold/replay supplies differential evidence. Index integrity checking can rebuild through the production transition but cannot replace differential tests with self-comparison.
|
|
358
352
|
|
|
@@ -370,9 +364,9 @@ Let P be resolved participant, K=P.name (or requested raw spelling if unknown),
|
|
|
370
364
|
|
|
371
365
|
### Continuous cursor
|
|
372
366
|
|
|
373
|
-
Find B = smallest landed-audience index > J without receipt (K,index). Then find C = greatest EXISTING activity index > J and < B (no upper bound if no B), with
|
|
367
|
+
Find B = smallest landed-audience index > J without receipt (K,index). Then find C = greatest EXISTING activity index > J and < B (no upper bound if no B), with kind != read. Every persisted activity has an actor. Return max(J,C), with missing C treated as J. Implementation uses `directed(... unseenOnly, oldest limit=1)` and `activityHeads(... kinds excluding read, newest limit=1)` in the SAME transaction. It does not read every intervening activity body.
|
|
374
368
|
|
|
375
|
-
Why this is exact: audience edges only exist on peer says. Before the first unseen addressed say, own and nonaddressed
|
|
369
|
+
Why this is exact: audience edges only exist on peer says. Before the first unseen addressed say, own and nonaddressed non-read events all advance readCursor. Reads do not. No cursor at B-1 is invented: if J=4, act/7 exists, act/9 is a read, and unseen addressed act/12 blocks, cursor is 7, not 11 or 9. Seen act/13 beyond that hole does not advance it.
|
|
376
370
|
|
|
377
371
|
### Evidence and presence
|
|
378
372
|
|
|
@@ -385,7 +379,7 @@ Presence anchor: if no join, return -1. E=max(J, largest own actor-bearing activ
|
|
|
385
379
|
- Suffix/behind/unreadActivityCount use directed rows > continuous cursor, **including individually seen rows beyond a hole**. Notification pending instead requires joined, >latest join, individually unseen. Do not substitute one count for the other.
|
|
386
380
|
- Hard cap uses lifetime sayCount. Quorum uses all known peers' done booleans (there must be at least one peer), not only currently standing peers.
|
|
387
381
|
- Throttle: request newest `limit` global say times with at > now-THROTTLE_WINDOW_MS; if that many exist, releaseAt is the oldest returned + window, retry=max(1, releaseAt-now). Bell: newest 1 actor bell timestamp > now-1h; that timestamp +1h is nextAt. Neither query excludes future timestamps.
|
|
388
|
-
- Behind summaries retain
|
|
382
|
+
- Behind summaries retain per-sender counts, latest timestamp and one greatest-index suffix preview. The latest timestamp need not belong to that preview. Lifetime sayOrdinals are retained for history field formatting, not recovery previews. Block only when !force, suffix nonempty, and freshest summary age > UNREAD_BLOCK_GRACE_MS; max(0,now-at) remains the age. force bypasses behind only.
|
|
389
383
|
|
|
390
384
|
### Catch transaction
|
|
391
385
|
|
|
@@ -411,22 +405,22 @@ Keep filesystem hints plus the existing 2-second authoritative revision reconcil
|
|
|
411
405
|
|
|
412
406
|
## 7. Complete caller replacement map (including render dependencies)
|
|
413
407
|
|
|
414
|
-
No production structure below carries `.state`, all `.activities`, or a deferred DB query. Renderers receive settled perceptions
|
|
408
|
+
No production structure below carries `.state`, all `.activities`, or a deferred DB query. Renderers receive settled perceptions, never recompute audience from a partial SquareState; history field formatting also receives selected ordinals.
|
|
415
409
|
|
|
416
410
|
| Current callers | Exact facts/replacement |
|
|
417
411
|
|---|---|
|
|
418
412
|
| openSquare/openSquareArtifact, wait baselines, watch headers, cli/program | header/revision only; remove preliminary whole-state validation/load. Every normal selected-row decode remains validated. |
|
|
419
413
|
| square-actions join/implicitJoin/takeover/done/endOwnedSession, registry-associated route cleanup | participant/roster as needed, routes, land/replaceRoutes; same host claim lock scopes and cleanup sequences. Takeover done+join is one txn. No full SDK snapshot. |
|
|
420
|
-
| Join
|
|
421
|
-
| express/decideAct and behind rendering
|
|
422
|
-
| listen/ignore/listening, watch leases and terminal checks | actor fact, outgoing attention; roster only for quorum; land or lease methods. Unknown valid attention target still allowed.
|
|
414
|
+
| Join/status/done count calls | `Square.join` returns a Participant handle and committed activity; optional observations use transaction-captured counts and time. Listener/lifecycle commit facts likewise come from the mutation transaction; join's extra entry history is best-effort. See [Square/Participant API](square-api.md). |
|
|
415
|
+
| express/decideAct and behind rendering | header, actor fact, roster for longest standing-body mention resolution, reply head/existence, recentSayTimes, continuous cursor, directed suffix. Admission normalization/error order unchanged. A valid reply coordinate is <nextActIndex, even if a gap: preserve current acceptance of assigned-but-missing reply. Recovery supplies own count/cap and behind summaries with one full preview per sender. |
|
|
416
|
+
| listen/ignore/listening, watch leases and terminal checks | actor fact, outgoing attention; roster only for quorum; land or lease methods. Unknown valid attention target still allowed. |
|
|
423
417
|
| catch / native seen | directed selectors/activity exact, markSeen, cursor/counts in txn; native `current` becomes synchronous `(facts: SquareRead)=>boolean`, evaluated ONLY within reads/receipt txn. It cannot escape or call host I/O. |
|
|
424
|
-
| entryPresentation / cli/square-commands join | bounded newest say/done heads then
|
|
425
|
-
| statusPresentation / cli/observation-commands status | roster+attention,
|
|
418
|
+
| entryPresentation / cli/square-commands join | bounded newest say/done heads then public activities with settled perceptions for the selected viewer; header context/scene; actor's join count from activityCount(kind join, actor identity). Supply `joinedBefore` rather than replaying `.state.acts`. `lastN=null` remains an explicit complete history request, not normal join's default. |
|
|
419
|
+
| statusPresentation / cli/observation-commands status | roster+attention, receiptFacts, continuous cursors and directed counts, fresh lease status; latest say/done. Supply last THREE public join events after latest public index, total number of such joins, and each `rejoined` boolean from existence of earlier done with EXACT actor spelling (current CLI equality). Latest line carries settled perception for context.name (including '' ambient viewer), not a SquareState. No receipts/history map hydrated. |
|
|
426
420
|
| participants/participantsPresentation/listPresentation | roster-derived status sorted by existing compareParticipantActivity; receipts/leases aggregates for participant statuses; list requires only active names, header preamble and say count. Change probeSquare to create a validated file-backed port, not full read then memory clone. |
|
|
427
421
|
| history / participantHistory / historyPresentation | relational head filter + contextIndexes; hydrate filtered candidate bodies for JS search, otherwise page only; count before final limit; selected ordinals + detached presence anchors/perceptions. Retain CLI lifecycle archive/raw coordinate windows and facade non-read inclusion. See algorithm below. |
|
|
428
|
-
|
|
|
429
|
-
| streamProjection/streamTailProjection |
|
|
422
|
+
| catch selection and rendering | hydrate ONLY selected rows, capture caught perceptions, participant status/clock, count/cap/terminal in the receipt transaction. Empty completion does not hydrate bodies. No all-history lookup of caught ids. |
|
|
423
|
+
| streamProjection/streamTailProjection | stream pages canonical activity heads before recipient filtering, advances its cursor even on empty recipient output, and returns public Activity or viewer-relative PerceivedActivity. Recipient filtering uses the historical landed audience, not pending/seen/latest-join. Tail selects last N matching activities and advances to the artifact head. |
|
|
430
424
|
| sessionInbox/located seats/boundary | exact-body seats + establishing join time, recipient directed unseen pages + live lease; complete result using §6. Boundary's stale-activity fallback uses activity(index) existence, not `.acts.every`. |
|
|
431
425
|
| deliverPending/sweep/delivery-health/notifications | pendingAudience groups or audience(activity)+joined/latestJoin+receipt checks for exact activity, ordered routes and detached host ledger evidence. Eligibility projection takes these typed facts instead of state. Sweep scans past suppressed candidates. Health can explicitly collect its complete pending summaries without bodies; renderer's existing detail cap stays. |
|
|
432
426
|
| Claude cancellation/resume/route discovery | cancellation=max existing activity index with at<=cutoff (not assumed chronological time); use newest activity-head pages in one read txn, testing timestamps from greatest index downward and stopping at the first match. If none matches, cutoff is -1. Resume last join/done by EXACT actor spelling; no full snapshot. Routes keep first-match order. |
|
|
@@ -444,7 +438,7 @@ Keep synchronous arbitrary `delivered(name,id)`. `snapshot()` intentionally copi
|
|
|
444
438
|
Execution is fixed: with an audience filter, enumerate historical `directed` pages without unseenOnly or a join cutoff; intersect each page's indices with the context union and other index/time/actor/kind filters through `activityHeads`. Without an audience filter, enumerate `activityHeads` directly. Continue the source traversal even when an intersection is empty. Public limiting follows the remaining filters/search; storage page exhaustion is distinct from a filtered empty page. This composition needs no new audience selector or query framework.
|
|
445
439
|
2. Nonempty regex/fixed search additionally restricts to say/done. Compile existing JS case-insensitive search once and test id/actor/body, not SQL LIKE/SQLite regexp. Iterate all relationally matching candidate body pages in the txn to count matches; maintain only the requested edge's selected page plus the needed existence/count metadata. Regex remains potentially expensive exactly as current engine; no new safety claim. Empty supplied pattern keeps current no-search semantics for facade.
|
|
446
440
|
3. Default/before selects LAST N filtered matches; after selects FIRST N. Select chronological edge first; desc reverses ONLY selected page. A complete request remains explicit and follows existing CLI maximum refusal. Continuation availability is computed over the current archive-visible kind set and current public page min/max, preserving current text/JSON differences; it is not simply a raw-head hasMore flag. Return total search matches, selected rows, public-before/public-after existence, selected ordinals and all anchor names landing on selected coordinates.
|
|
447
|
-
4. Presence anchors are the §5 evidence algorithm for all roster names; compute without full hydration and attach only selected-coordinate annotations in roster order. Context positions include
|
|
441
|
+
4. Presence anchors are the §5 evidence algorithm for all roster names; compute without full hydration and attach only selected-coordinate annotations in roster order. Context positions include reads; coordinate arithmetic must not replace position selection. History across separate calls promises stable activity-id coordinates, not frozen mutable receipt/presence annotations.
|
|
448
442
|
|
|
449
443
|
## 8. Error/transaction lifecycle (fixed)
|
|
450
444
|
|
|
@@ -473,7 +467,7 @@ These terms apply together with the domain specification above.
|
|
|
473
467
|
- Open existing canonical path create-disabled. A read-only preflight establishes owned known schema/version before any persistent pragma or DDL. Require existing DELETE journal mode, refuse another mode without changing it; the shipped v1 creator/writer already establishes DELETE. Set connection busy_timeout=0 and synchronous=FULL. Acquire BEGIN IMMEDIATE, re-check format/schema under the lock, and validate the full v1 snapshot inside it. If v2 is already present and has valid framing/header, return already-format-2 without changing revision. A second migrator follows this same in-lock check.
|
|
474
468
|
- Use v1 validation retained ONLY in migration (test oracle may also retain it), plus one explicit restriction: non-finite numbers anywhere in a route (including nested extras) are unsupported input, refused before DDL/inserts with the artifact untouched. They are not normally persisted as non-finite values by the v1 JSON.stringify writer; do not add a bespoke overflow-number codec or silently coerce to null. Copy normally persisted authoritative facts losslessly, preserving revision and nextActIndex, activity indices/gaps and optional field distinctions, raw receipt/lease owner keys, route order/duplicates, strings and finite fractional timestamps. Absent routes and [] both become zero rows; empty receipt-owner maps are behaviorless and may become zero receipt rows. Do not canonicalize receipts or add foreign keys that reject accepted v1 facts.
|
|
475
469
|
- Actual receipt lookup is exact canonical roster spelling, not lowercase nameKey: preserve the raw owner-key relation and resolve lookup via the domain. Free-form JS strings must survive SQLite binding; JSON string encoding (including for key strings where necessary) preserves lone surrogates. All normalized lookup keys come from domain nameKey, never SQLite LOWER.
|
|
476
|
-
- Create v2 tables and insert authority. Build derived participant/
|
|
470
|
+
- Create v2 tables and insert authority. Build derived participant/attention/audience facts with the SAME single-step domain transition used by runtime landing (admission checks are NOT replayed). Check insert/constraint failures normally; do not add a second full replay or a second in-memory copy just to validate the function against itself. Lossless authority equality and old-replay equivalence are migration tests; doctor can explicitly recompute indices for integrity checking. Drop square_snapshot. Set user_version=2 inside the same transaction. Commit once; nothing is published piecemeal.
|
|
477
471
|
- Busy acquisition/read retries yield using existing 25ms retry and operation cancellation. Busy COMMIT retries the same transaction; never rerun copy or domain callback. Error/abort before successful COMMIT rolls back. Process death before commit recovers v1 through SQLite journal; after commit leaves complete v2. Preserve path/inode/registry identity. No host-ledger mutation and no synthetic activity.
|
|
478
472
|
- Storage exclusion is guaranteed for the shipped SQLite v1 runtime because it validates again after BEGIN IMMEDIATE: its write commits before migration, or it sees v2 and refuses afterward. A pre-migration read can finish with its old snapshot. Migration does not revoke in-flight remote delivery or stop processes; recommend stopping/upgrading attached runtimes for an operationally quiet migration. Arbitrary external path replacement and pre-SQLite binaries are outside the artifact update protocol. Do not claim a distributed transaction or exactly-once remote delivery.
|
|
479
473
|
|