@earendil-works/pi-durable 0.99.2 → 1.0.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 (129) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +196 -74
  3. package/dist/env/index.d.ts +5 -0
  4. package/dist/env/index.d.ts.map +1 -1
  5. package/dist/env/index.js.map +1 -1
  6. package/dist/env/node.d.ts +2 -0
  7. package/dist/env/node.d.ts.map +1 -1
  8. package/dist/env/node.js +2 -0
  9. package/dist/env/node.js.map +1 -1
  10. package/dist/harness/agent.d.ts +31 -0
  11. package/dist/harness/agent.d.ts.map +1 -0
  12. package/dist/harness/agent.js +209 -0
  13. package/dist/harness/agent.js.map +1 -0
  14. package/dist/harness/compaction.d.ts.map +1 -1
  15. package/dist/harness/compaction.js +8 -11
  16. package/dist/harness/compaction.js.map +1 -1
  17. package/dist/harness/define.d.ts +18 -0
  18. package/dist/harness/define.d.ts.map +1 -0
  19. package/dist/harness/define.js +25 -0
  20. package/dist/harness/define.js.map +1 -0
  21. package/dist/harness/events.d.ts +5 -5
  22. package/dist/harness/events.d.ts.map +1 -1
  23. package/dist/harness/events.js +6 -6
  24. package/dist/harness/events.js.map +1 -1
  25. package/dist/harness/generation.d.ts +2 -4
  26. package/dist/harness/generation.d.ts.map +1 -1
  27. package/dist/harness/generation.js +39 -43
  28. package/dist/harness/generation.js.map +1 -1
  29. package/dist/harness/harness.d.ts.map +1 -1
  30. package/dist/harness/harness.js +68 -154
  31. package/dist/harness/harness.js.map +1 -1
  32. package/dist/harness/inbox.d.ts +4 -2
  33. package/dist/harness/inbox.d.ts.map +1 -1
  34. package/dist/harness/inbox.js +3 -5
  35. package/dist/harness/inbox.js.map +1 -1
  36. package/dist/harness/prompt.d.ts +1 -3
  37. package/dist/harness/prompt.d.ts.map +1 -1
  38. package/dist/harness/prompt.js +1 -11
  39. package/dist/harness/prompt.js.map +1 -1
  40. package/dist/harness/registry.d.ts +2 -3
  41. package/dist/harness/registry.d.ts.map +1 -1
  42. package/dist/harness/registry.js +66 -283
  43. package/dist/harness/registry.js.map +1 -1
  44. package/dist/harness/scheduler.d.ts +7 -2
  45. package/dist/harness/scheduler.d.ts.map +1 -1
  46. package/dist/harness/scheduler.js +41 -27
  47. package/dist/harness/scheduler.js.map +1 -1
  48. package/dist/harness/submissions.d.ts +4 -4
  49. package/dist/harness/submissions.d.ts.map +1 -1
  50. package/dist/harness/submissions.js +7 -4
  51. package/dist/harness/submissions.js.map +1 -1
  52. package/dist/harness/task-graph.d.ts +49 -0
  53. package/dist/harness/task-graph.d.ts.map +1 -0
  54. package/dist/harness/task-graph.js +163 -0
  55. package/dist/harness/task-graph.js.map +1 -0
  56. package/dist/harness/tool.d.ts +1 -1
  57. package/dist/harness/tool.d.ts.map +1 -1
  58. package/dist/harness/tool.js +9 -6
  59. package/dist/harness/tool.js.map +1 -1
  60. package/dist/harness/types.d.ts +171 -140
  61. package/dist/harness/types.d.ts.map +1 -1
  62. package/dist/harness/types.js.map +1 -1
  63. package/dist/harness/view.d.ts +1 -1
  64. package/dist/harness/view.d.ts.map +1 -1
  65. package/dist/harness/view.js +2 -7
  66. package/dist/harness/view.js.map +1 -1
  67. package/dist/index.d.ts +4 -2
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +2 -1
  70. package/dist/index.js.map +1 -1
  71. package/dist/session/session.d.ts.map +1 -1
  72. package/dist/session/session.js +5 -1
  73. package/dist/session/session.js.map +1 -1
  74. package/dist/session/transaction.d.ts +2 -2
  75. package/dist/session/transaction.d.ts.map +1 -1
  76. package/dist/session/transaction.js +7 -4
  77. package/dist/session/transaction.js.map +1 -1
  78. package/dist/storage/sqlite/database.d.ts +26 -19
  79. package/dist/storage/sqlite/database.d.ts.map +1 -1
  80. package/dist/storage/sqlite/database.js.map +1 -1
  81. package/dist/storage/sqlite/index.d.ts +1 -1
  82. package/dist/storage/sqlite/index.d.ts.map +1 -1
  83. package/dist/storage/sqlite/index.js.map +1 -1
  84. package/dist/storage/sqlite/migrations.js +6 -6
  85. package/dist/storage/sqlite/migrations.js.map +1 -1
  86. package/dist/storage/sqlite/node.d.ts +23 -7
  87. package/dist/storage/sqlite/node.d.ts.map +1 -1
  88. package/dist/storage/sqlite/node.js +129 -47
  89. package/dist/storage/sqlite/node.js.map +1 -1
  90. package/dist/storage/sqlite/storage.d.ts +12 -0
  91. package/dist/storage/sqlite/storage.d.ts.map +1 -1
  92. package/dist/storage/sqlite/storage.js +121 -129
  93. package/dist/storage/sqlite/storage.js.map +1 -1
  94. package/dist/tools/bash.d.ts +1 -1
  95. package/dist/tools/bash.d.ts.map +1 -1
  96. package/dist/tools/bash.js +3 -2
  97. package/dist/tools/bash.js.map +1 -1
  98. package/dist/tools/edit.d.ts +3 -3
  99. package/dist/tools/edit.d.ts.map +1 -1
  100. package/dist/tools/edit.js +5 -4
  101. package/dist/tools/edit.js.map +1 -1
  102. package/dist/tools/file-mutation-queue.d.ts +5 -1
  103. package/dist/tools/file-mutation-queue.d.ts.map +1 -1
  104. package/dist/tools/file-mutation-queue.js +39 -33
  105. package/dist/tools/file-mutation-queue.js.map +1 -1
  106. package/dist/tools/index.d.ts +18 -0
  107. package/dist/tools/index.d.ts.map +1 -1
  108. package/dist/tools/index.js +10 -0
  109. package/dist/tools/index.js.map +1 -1
  110. package/dist/tools/read.d.ts +3 -3
  111. package/dist/tools/read.d.ts.map +1 -1
  112. package/dist/tools/read.js +4 -3
  113. package/dist/tools/read.js.map +1 -1
  114. package/dist/tools/write.d.ts +1 -1
  115. package/dist/tools/write.d.ts.map +1 -1
  116. package/dist/tools/write.js +3 -2
  117. package/dist/tools/write.js.map +1 -1
  118. package/dist/types.d.ts +15 -4
  119. package/dist/types.d.ts.map +1 -1
  120. package/dist/types.js.map +1 -1
  121. package/package.json +25 -15
  122. package/dist/harness/config.d.ts +0 -29
  123. package/dist/harness/config.d.ts.map +0 -1
  124. package/dist/harness/config.js +0 -24
  125. package/dist/harness/config.js.map +0 -1
  126. package/docs/chord-delta-findings.md +0 -358
  127. package/docs/pico-v5-chord-usage.md +0 -373
  128. package/docs/pico-v5-handoff.md +0 -861
  129. package/docs/pico-v5.md +0 -4174
@@ -1,373 +0,0 @@
1
- # Pico5 documents through Chord
2
-
3
- This guide uses the contracts in the [Pico5 specification](pico-v5.md).
4
-
5
- - **Session:** a durable container for conversations, entries, tasks, and documents;
6
- it serializes mutations on one commit line.
7
- - **Facet:** a feature's setup unit in a Chord host. Setup declares services and
8
- dependencies synchronously; `onActivate` runs after dependencies are ready.
9
- - **Context:** explicitly passed cancellation and invocation values. Forward the caller's context.
10
- - **Service:** a typed token and implementation acquired with `env.use`. Remote
11
- services contain replicated state and async methods with JSON arguments plus a trailing `Context`.
12
- - **Durable document:** JSON persisted as a complete base, Chord operations, and
13
- checkpoints. Its definition token declares schema, version, scope, and initialization;
14
- conversation scope also declares history and fork behavior.
15
- - **Transaction draft:** the revocable copy-on-write object from `await tx.doc`,
16
- valid only inside that commit callback, including all nested objects.
17
- - **DocumentState:** a disposable read-only Chord state bound to one document incarnation.
18
- - **ReplicatedState:** Chord's immutable complete values through `value` and
19
- `subscribe(listener)`. `value` is `undefined` before hydration or while disconnected.
20
- The listener receives `(value, context, delivery)`; delivery contains `kind`
21
- (`hydrate` or `update`) and a stream `sequence`, not a Session commit number.
22
-
23
- Documents are scoped directly to a Session, conversation, or task. A task is
24
- durable work attached to a conversation; its documents retire when it becomes
25
- terminal and never participate in conversation forks.
26
-
27
- ## Imports and the adapter boundary
28
-
29
- Examples build on one another. Pico5 names (`defineDoc`, `defineDocFamily`,
30
- `Session`, `DocumentState`, `Id`, `TaskRuntime`, `DocumentObserver`)
31
- refer to normative contracts, without a specified import path or runnable Pico5
32
- package. In those contracts, `ConversationRecord`, `EntryRecord`, and
33
- `TaskRecord` are persisted records, while `Conversation` is the public
34
- conversation object and `Entry`/`Task` are typed definitions. The Chord imports
35
- below are the concrete APIs used by the examples:
36
-
37
- ```ts
38
- import {
39
- createFacetHost, createRemoteServiceBinding, defineFacet, defineService,
40
- type Context, type Facet, type JsonValue, type RemoteServiceTransport,
41
- type ReplicatedState,
42
- } from "@earendil-works/chord";
43
- import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
44
- // The Pico specification calls this object-root constraint JsonObject.
45
- type JsonObject = { [key: string]: JsonValue };
46
- ```
47
-
48
- `documentState()` performs Chord adoption internally: it atomically captures a
49
- committed snapshot, registers for every later exact frame, and returns an already
50
- hydrated read-only state. Operations covered by the snapshot are never
51
- redelivered. Disposing the state releases observation, not the document. Pico
52
- remains the sole mutator.
53
-
54
- ## 1. A Session-wide canvas
55
-
56
- All conversations in this Session share one canvas. Session documents are
57
- current-only and have no history or fork settings.
58
-
59
- ```ts
60
- type Stroke = { color: string; points: { x: number; y: number }[] };
61
- type CanvasState = { strokes: Stroke[] };
62
-
63
- const CanvasDoc = defineDoc<CanvasState>({
64
- kind: "app.canvas", version: 1, scope: "session",
65
- initial: () => ({ strokes: [] }),
66
- // Store a complete base after at most 99 replayed deltas.
67
- checkpointWhen: (_value, _ops, info) => info.deltasSinceBase >= 99,
68
- });
69
-
70
- interface CanvasService {
71
- readonly state: ReplicatedState<CanvasState | null>;
72
- addStroke(stroke: Stroke, context: Context): Promise<void>;
73
- }
74
- const Canvas = defineService<CanvasService>("app.canvas");
75
-
76
- async function createCanvasFacet(session: Session, context: Context): Promise<Facet> {
77
- // Creation is explicit; observation never writes.
78
- await session.commit(async tx => {
79
- await tx.doc(CanvasDoc);
80
- }, context);
81
- const state = await session.documentState(CanvasDoc, context);
82
- if (state === undefined) throw new Error("canvas was retired during setup");
83
- return defineFacet({
84
- id: "app.canvas/session",
85
- setup(env) {
86
- env.own(() => state.dispose());
87
- env.provide(Canvas, {
88
- state,
89
- async addStroke(stroke, context) {
90
- await session.commit(async tx => {
91
- const draft = await tx.doc(CanvasDoc);
92
- draft.strokes.push(stroke); // Chord copies the assigned stroke by value.
93
- }, context);
94
- },
95
- });
96
- },
97
- });
98
- }
99
-
100
- const CanvasConsumer = defineFacet({
101
- id: "app.canvas/consumer",
102
- setup(env) {
103
- const canvas = env.use(Canvas); // Declare now; access only after activation.
104
- env.onActivate(() => {
105
- env.own(canvas.state.subscribe((value, _context, delivery) => {
106
- console.log(delivery.kind, delivery.sequence, value?.strokes.length ?? "retired");
107
- })); // subscribe delivers the current hydrated value, then updates.
108
- });
109
- },
110
- });
111
-
112
- async function runCanvasExample(session: Session): Promise<void> {
113
- const context = BACKGROUND_CONTEXT;
114
- const provider = await createCanvasFacet(session, context);
115
- const host = await createFacetHost({ facets: [provider, CanvasConsumer] });
116
- try {
117
- await host.services.use(Canvas).addStroke({
118
- color: "black", points: [{ x: 10, y: 20 }, { x: 30, y: 40 }],
119
- }, context);
120
- } finally {
121
- await host.dispose(); // Unsubscribes; does not delete the canvas or close Session.
122
- }
123
- }
124
- ```
125
-
126
- The application owns the open Session. Acquire the document state asynchronously
127
- before synchronous `setup`, then transfer its disposal to the facet;
128
- `env.provide` cannot run in `onActivate`. Install one provider per
129
- Session host. Chord may reload presentation facets independently. Session-side
130
- tools, hooks, tasks, and prompt sections reload through the Harness
131
- registry: publish the replacement in one `batch()`. Work already running keeps
132
- the old code, so the facet manages its old resources' lifetime itself.
133
-
134
- Remote clients supply a `RemoteServiceTransport` connected to the host's `services`
135
- provider; Chord prescribes no socket protocol. `CanvasConsumer` also works unchanged
136
- in a UI host configured with a remote service source.
137
-
138
- ```ts
139
- async function connectCanvas(transport: RemoteServiceTransport, context: Context) {
140
- const services = createRemoteServiceBinding({ services: [Canvas], transport });
141
- const canvas = services.use(Canvas);
142
- const stop = canvas.state.subscribe((value, _context, delivery) => {
143
- console.log(delivery.kind, delivery.sequence, value?.strokes ?? "retired");
144
- });
145
- try {
146
- await services.ready(context); // Initial snapshot installed; not all future updates.
147
- } catch (error) {
148
- stop();
149
- await services.dispose(BACKGROUND_CONTEXT);
150
- throw error;
151
- }
152
- return async () => {
153
- stop();
154
- await services.dispose(BACKGROUND_CONTEXT);
155
- };
156
- }
157
- ```
158
-
159
- ```text
160
- explicit first tx.doc -> commit base { strokes: [] }
161
- addStroke(A) -> commit A -> local and remote subscribers see A
162
- worker restarts -> open same durable storage; install canvas facet again
163
- acquire source -> load base + committed deltas, without rerunning initial()
164
- late client -> hydrate complete canvas including A, then ordered updates
165
- conversation fork -> still uses this same Session canvas
166
- ```
167
-
168
- Use persistent storage for restart survival. The memory backend is not persistent.
169
- A method's successful commit does not promise every remote callback has run yet.
170
-
171
- ## 2. Conversation-scoped diff reviews
172
-
173
- A **document family** uses one definition for many instances. The logical key is
174
- `(kind, conversationId, key)`; the persisted numeric document ID identifies an
175
- incarnation and is never reused. The creation seed is not part of the key.
176
-
177
- ```ts
178
- type ReviewInput = { path: string; patch: string };
179
- type ReviewComment = { id: string; line: number; text: string };
180
- type ReviewState = ReviewInput & { comments: ReviewComment[] };
181
- const ReviewDoc = defineDocFamily<ReviewState, ReviewInput>({
182
- kind: "app.diff-review", version: 1, family: true, scope: "conversation",
183
- history: "latest", fork: "current",
184
- initial: seed => ({ path: seed.path, patch: seed.patch, comments: [] }),
185
- checkpointWhen: (_value, _ops, info) => info.deltasSinceBase >= 49,
186
- });
187
- interface DiffReviewService {
188
- readonly state: ReplicatedState<ReviewState | null>;
189
- identity(context: Context): Promise<{ conversationId: Id; key: string }>;
190
- addComment(comment: ReviewComment, context: Context): Promise<void>;
191
- }
192
- const DiffReviews = defineService<DiffReviewService>("app.diff-reviews");
193
-
194
- function reviewFacet(
195
- session: Session, conversationId: Id,
196
- reviews: readonly { key: string; seed: ReviewInput }[], context: Context,
197
- ): Facet {
198
- return defineFacet({
199
- id: "app.diff-reviews/session",
200
- setup(env) {
201
- const instances = env.provideMany(DiffReviews);
202
- env.onActivate(async () => {
203
- for (const review of reviews) {
204
- await session.commit(async tx => {
205
- await tx.doc(ReviewDoc, conversationId, review.key, review.seed);
206
- }, context);
207
- const state = await session.documentState(ReviewDoc, conversationId, review.key, context);
208
- if (state === undefined) throw new Error("review was retired during setup");
209
- env.own(() => state.dispose());
210
- // Chord instance keys route services; they are not numeric document incarnation IDs.
211
- instances.spawn(JSON.stringify([conversationId, review.key]), {
212
- state,
213
- async identity() { return { conversationId, key: review.key }; },
214
- async addComment(comment, context) {
215
- await session.commit(async tx => {
216
- const draft = await tx.doc(ReviewDoc, conversationId, review.key, review.seed);
217
- draft.comments.push(comment); // Chord copies the assigned comment by value.
218
- }, context);
219
- },
220
- }); // The facet owns spawned service lifetimes automatically.
221
- }
222
- });
223
- },
224
- });
225
- }
226
- ```
227
-
228
- Example input: `[{ key: "review-7", seed: { path: "a.ts", patch: "-old\n+new" } }]`.
229
- Pass distinct family keys and a real conversation ID; install the facet as above.
230
- Keyed consumers use `env.observe(DiffReviews, handler)`, not `env.use`. The handler
231
- receives `(review, context)`; call `review.identity(context)` to identify it and
232
- `review.state.subscribe` to observe comments.
233
-
234
- These comments are conversation-scoped: ending the generating task or unloading
235
- the facet does not retire them. `current` copies every logically
236
- present review at fork-commit time into independent child instances with new
237
- numeric IDs, retaining family keys. Parent and child then diverge.
238
-
239
- ```text
240
- parent review-7: comment A -> transcript entry E -> comment B
241
- fork at E with current: child review-7 contains A and B
242
- child adds C: parent still contains only A and B
243
- ```
244
-
245
- With `fork: "initial"`, no instance copies; the first child `tx.doc()` uses its supplied seed.
246
- `latest` cannot read history or fork `asOf`; use `history: "rewindable"` with `asOf`
247
- to reflect E's commit. Reaccess ignores later seeds; updating the patch requires
248
- an explicit mutation or a distinct review key.
249
-
250
- ## 3. Task-scoped output and a tool/task watch
251
-
252
- This is a bounded progress window, not the permanent result. Scope itself gives
253
- it task lifetime; no history, fork, owner, or conversation setting is needed.
254
-
255
- ```ts
256
- type JobInput = { command: string };
257
- type JobOutput = { stdout: string; chunks: number };
258
- const JobOutputDoc = defineDoc<JobOutput>({
259
- kind: "app.job-output", version: 1, scope: "task",
260
- initial: () => ({ stdout: "", chunks: 0 }),
261
- checkpointWhen: (_value, _ops, info) => info.deltasSinceBase >= 99,
262
- });
263
- async function appendJobOutput(
264
- runtime: TaskRuntime<JobInput, { phase: "running" }, null, {}>,
265
- chunk: string, context: Context,
266
- ): Promise<void> {
267
- // Read process output outside this callback. The runtime gates the live task.
268
- await runtime.commit(async tx => {
269
- const draft = await tx.doc(JobOutputDoc, runtime.taskId);
270
- draft.stdout = (draft.stdout + chunk).slice(-50_000);
271
- draft.chunks += 1;
272
- }, context);
273
- }
274
- async function observeJob(
275
- api: DocumentObserver, producerTaskId: Id,
276
- finished: Promise<void>, context: Context,
277
- ): Promise<void> {
278
- const watch = await api.watchDoc(JobOutputDoc, producerTaskId, context);
279
- if (watch === undefined) return;
280
- console.log(watch.value === null ? "retired" : watch.value.stdout);
281
- try {
282
- watch.start(async (value, ops, _context) => {
283
- await sendCommittedFrame(value, ops);
284
- await render(value === null ? "retired" : value.stdout);
285
- }); // Serialized callbacks never overlap.
286
- await finished; // Caller-supplied observation lifetime; outside any commit.
287
- } finally {
288
- await watch.stop(); // Idempotent; prevents another callback from starting.
289
- }
290
- }
291
- ```
292
-
293
- The running phase calls `appendJobOutput` and must also commit its next checkpoint
294
- or terminal outcome. `api` is the invocation's `DocumentObserver`; `TaskRuntime`
295
- includes that interface. `tx.doc()` creation validates that the target task is live and derives its
296
- conversation from the task record. A later non-creating watch lookup returns
297
- `undefined` after the task is terminal and its document has retired.
298
-
299
- ```text
300
- watchDoc: capture immutable V0 + register for later exact committed frames
301
- producer commits D1 and D2 before start: buffer (V1, D1), (V2, D2)
302
- start: caller has initialized from V0; deliver D1, then D2 serially
303
- producer commits D3 while listener awaits: buffer D3; never overlap callbacks
304
- 101 pending frames: replace the pending suffix with [["r", newestValue]]
305
- producer becomes terminal: deliver [["r", null]], then close as retired
306
- ```
307
-
308
- Watches automatically stop when their invocation ends. A Session-acquired watch
309
- is caller-owned and stops on Session close. Previously delivered snapshots never
310
- mutate. Slow or unstarted delivery retains up to 100 exact frames, then replaces
311
- the undelivered suffix with a full-value root replacement. A watch is convergent
312
- state observation rather than a transition journal. Retirement ends the
313
- incarnation's stream; a service exposing that state must withdraw or remain
314
- terminal at `null`. Recreation requires a new watch/state and numeric document ID. A terminal task cannot
315
- create more output. Task-scoped documents
316
- never copy into forks. Preserve required output in result entries or Session- or
317
- conversation-scoped documents in the terminal commit before retirement. Use a
318
- task-scoped family only when one task needs several independently keyed documents.
319
-
320
- ## 4. Built-in conversation views and commit delivery
321
-
322
- `ConversationView` contains `conversation`, raw transcript `entries`, and
323
- `docs: Readonly<Record<string, JsonObject>>`. Selected built-in singletons mount
324
- under `docs` by stable document kind, not numeric incarnation ID. The spec's
325
- illustrative path mapping is:
326
-
327
- ```text
328
- document ["s", ["generation", "message"], value]
329
- -> view ["s", ["docs", "pi.live", "generation", "message"], value]
330
- ```
331
-
332
- `pi.live` is specified in `pico-v5.md` section 8.2.
333
- The mount publishes one batch per complete Session commit: entry/head changes and
334
- changed mounted documents together, without a tracker or semantic projection.
335
- Third-party documents are **not automatically mounted**; use their own Chord
336
- services or trusted invocation watches. A retired source publishes `null`; a
337
- dynamic service should then withdraw its instance rather than expose stale data.
338
-
339
- ```text
340
- addStroke -> hold Session mutation line -> await tx.doc -> mutate tracker change draft
341
- callback succeeds -> tracker prepare: immutable candidate + immutable ops
342
- Session checkpoint predicate selects a base or delta exactly once
343
- atomic storage commit: persist selected document and record writes
344
- storage succeeds -> adopt candidate + enqueue candidate/ops, still on line
345
- release line -> deliver committed source ops -> adapter -> local/remote Chord consumers
346
- late subscriber -> atomically capture committed value + adapter sequence + subscription
347
- ```
348
-
349
- No visible-undurable path exists. Callback, tracker preparation, and checkpoint
350
- failure abort normally before Storage admission. An uncertain Storage failure
351
- publishes nothing and poisons the open Session; close and reopen it instead of
352
- continuing.
353
-
354
- ## Footguns
355
-
356
- - Never retain drafts, nested proxies, or bound array methods across commits;
357
- they are revoked. Assigned containers are copied by value.
358
- - Async commit holds the line through storage settlement and baseline adoption.
359
- Await document access there, not models, processes, network calls, or humans.
360
- - Only `tx.doc()` creates. `snapshot`, `documentState`, and `watchDoc` return
361
- `undefined` when absent and never write. Family seeds are used only when the
362
- first `tx.doc()` creates an incarnation; later seeds are ignored.
363
- - Initialize from the fixed `watch.value` before `start()`. Slow or unstarted
364
- delivery retains up to 100 exact frames, then replaces the pending suffix with
365
- one full-value root replacement. No serialized-byte accounting is performed.
366
- Do not use a watch as an audit log.
367
- - `stop()` prevents future callbacks but does not abort or join one already running.
368
- - Definitions own checkpoints, not storage heuristics. Keep document kinds, versions, fork policies, and
369
- public paths stable; schema changes require migration, not a source-only rename.
370
-
371
- Chord sources: [types](../../chord/src/types.ts), [facet examples](../../chord/test/facets.test.ts),
372
- [state](../../chord/src/services/state.ts), [provider](../../chord/src/services/provider.ts),
373
- [Context](../../chord/src/context/index.ts), [Delta](../../chord/src/delta/README.md).