brainclaw 1.9.0 → 1.9.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 (91) hide show
  1. package/README.md +585 -499
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/commands/harvest.js +1 -1
  4. package/dist/commands/hooks.js +73 -73
  5. package/dist/commands/init.js +1 -1
  6. package/dist/commands/install-hooks.js +78 -78
  7. package/dist/commands/mcp-read-handlers.js +57 -14
  8. package/dist/commands/mcp.js +79 -13
  9. package/dist/commands/switch.js +26 -5
  10. package/dist/commands/version.js +1 -1
  11. package/dist/core/agent-capability.js +19 -4
  12. package/dist/core/agent-files.js +119 -119
  13. package/dist/core/codev-prompts.js +38 -38
  14. package/dist/core/default-profiles/doctor.yaml +11 -11
  15. package/dist/core/default-profiles/janitor.yaml +11 -11
  16. package/dist/core/default-profiles/onboarder.yaml +11 -11
  17. package/dist/core/default-profiles/reviewer.yaml +13 -13
  18. package/dist/core/dispatcher.js +1 -1
  19. package/dist/core/entity-operations.js +29 -3
  20. package/dist/core/execution.js +1 -1
  21. package/dist/core/loops/verbs.js +0 -1
  22. package/dist/core/messaging.js +2 -2
  23. package/dist/core/protocol-skills.js +164 -164
  24. package/dist/core/runtime-signals.js +1 -1
  25. package/dist/core/search.js +19 -2
  26. package/dist/core/security-guard.js +207 -207
  27. package/dist/core/spawn-check.js +16 -2
  28. package/dist/core/staleness.js +1 -1
  29. package/dist/core/store-resolution.js +26 -7
  30. package/dist/core/worktree.js +18 -18
  31. package/dist/facts.js +3 -3
  32. package/dist/facts.json +2 -2
  33. package/docs/PROTOCOL.md +1 -1
  34. package/docs/adapters/openclaw.md +43 -43
  35. package/docs/architecture/project-refs.md +328 -328
  36. package/docs/cli.md +2093 -2093
  37. package/docs/concepts/coordination.md +52 -52
  38. package/docs/concepts/coordinator-runbook.md +129 -129
  39. package/docs/concepts/dispatch-lifecycle.md +245 -245
  40. package/docs/concepts/event-log-store.md +928 -928
  41. package/docs/concepts/ideation-loop.md +317 -317
  42. package/docs/concepts/loop-engine.md +520 -511
  43. package/docs/concepts/mcp-governance.md +268 -268
  44. package/docs/concepts/memory.md +84 -84
  45. package/docs/concepts/multi-agent-workflows.md +167 -167
  46. package/docs/concepts/observer-protocol.md +361 -361
  47. package/docs/concepts/plans-and-claims.md +217 -217
  48. package/docs/concepts/project-md-convention.md +35 -35
  49. package/docs/concepts/runtime-notes.md +38 -38
  50. package/docs/concepts/troubleshooting.md +254 -254
  51. package/docs/concepts/workspace-bootstrapping.md +142 -142
  52. package/docs/context-format-changelog.md +35 -35
  53. package/docs/context-format.md +48 -48
  54. package/docs/index.md +65 -65
  55. package/docs/integrations/agents.md +158 -158
  56. package/docs/integrations/claude-code.md +23 -23
  57. package/docs/integrations/cline.md +77 -77
  58. package/docs/integrations/continue.md +55 -55
  59. package/docs/integrations/copilot.md +68 -68
  60. package/docs/integrations/cursor.md +23 -23
  61. package/docs/integrations/kilocode.md +72 -72
  62. package/docs/integrations/mcp.md +377 -377
  63. package/docs/integrations/mistral-vibe.md +122 -122
  64. package/docs/integrations/openclaw.md +92 -92
  65. package/docs/integrations/opencode.md +84 -84
  66. package/docs/integrations/overview.md +115 -115
  67. package/docs/integrations/roo.md +71 -71
  68. package/docs/integrations/windsurf.md +77 -77
  69. package/docs/mcp-schema-changelog.md +360 -356
  70. package/docs/playbooks/integration/index.md +121 -121
  71. package/docs/playbooks/orchestration.md +37 -0
  72. package/docs/playbooks/productivity/index.md +99 -99
  73. package/docs/playbooks/team/index.md +117 -117
  74. package/docs/product/agent-first-model.md +184 -184
  75. package/docs/product/entity-model-audit.md +462 -462
  76. package/docs/product/positioning.md +86 -86
  77. package/docs/quickstart-existing-project.md +107 -107
  78. package/docs/quickstart.md +183 -183
  79. package/docs/release-maintenance.md +79 -79
  80. package/docs/reputation.md +52 -52
  81. package/docs/review.md +45 -45
  82. package/docs/security.md +212 -212
  83. package/docs/server-operations.md +118 -118
  84. package/docs/storage.md +106 -106
  85. package/package.json +80 -65
  86. package/docs/concepts/event-log-store-critique-A.md +0 -333
  87. package/docs/concepts/event-log-store-critique-B.md +0 -353
  88. package/docs/concepts/event-log-store-phase0-measurements.md +0 -58
  89. package/docs/concepts/event-log-store-proposal-A.md +0 -365
  90. package/docs/concepts/event-log-store-proposal-B.md +0 -404
  91. package/docs/concepts/identity-model-proposal.md +0 -371
@@ -1,365 +0,0 @@
1
- # Event-Log Store — Proposal A (slot A, round 1)
2
-
3
- > Ideation artifact for lop_3bf55b9492e0d96c (pln_2290bc70 / pln#543 step 1).
4
- > Independent proposal — not yet cross-critiqued. Status: DRAFT.
5
-
6
- ## 0. Position summary
7
-
8
- Evolve `src/core/event-log.ts` from a best-effort notification stream into a
9
- **write-ahead journal of full-entity snapshots**, organized as **immutable
10
- sealed segments + checkpoint records**, with the existing per-entity JSON
11
- directories demoted to **lazily reconciled projections** (pln#496 pattern).
12
- Ordering comes from a **store-global sequence number assigned under the
13
- existing store lock** — never from timestamps. Migration is a four-phase,
14
- flag-gated dual-write with a backfill genesis and a park-don't-delete rollback.
15
-
16
- The three deliberate "boring" choices, argued below:
17
-
18
- 1. **Full snapshot payloads, not diffs** (§2) — correctness over bytes.
19
- 2. **The store lock is the concurrency primitive, O_APPEND is the seatbelt**
20
- (§3) — no new locking protocol.
21
- 3. **One journal per store, not per entity** (§5) — global order for free.
22
-
23
- ## 1. Seed analysis — what exists and the exact gap
24
-
25
- What `src/core/event-log.ts` + call sites give us today:
26
-
27
- | Capability | State today | Gap to source-of-truth |
28
- |---|---|---|
29
- | Append on every mutation | `appendEvent` wired into `persistStateUnlocked` (state.ts:200) and ~30 verb sites | Events carry no payload — state NOT reconstructible |
30
- | Envelope | `{ts, agent, agent_id?, user?, action, item_type, item_id?, summary?}` | No seq, no writer identity, no payload, no schema version |
31
- | Durability | `appendFileSync` inside try/catch that **swallows all errors** (event-log.ts:94-96) | A journal that may silently drop writes cannot be authoritative |
32
- | Rotation | At 10MB: rename file away, **delete all cursors** (event-log.ts:211-236) | History unreachable by readers; cursor reset re-notifies nothing (offset semantics gone) |
33
- | Readers | `readAllEvents` (full parse), `readUnseenEvents` (byte-offset cursors), `buildNotificationSummary` | Cursors are bare byte offsets into a file that rotation deletes |
34
- | Concurrency | All mutations serialize via `mutate()` → store-wide lock with token ownership + refresh (lock.ts, hardened sprint 1.5) | appendEvent itself is also called outside any documented invariant; lock-expiry break creates a 2-writer window |
35
-
36
- Adjacent precedent worth noting: **loops already run a payload-carrying
37
- per-loop journal** (`src/core/loops/store.ts` `appendEvent` →
38
- `loops/<id>/events.jsonl`, zod-validated `LoopEventSchema`, thread file as
39
- projection). The store journal should converge on the same shape; unifying
40
- the loop journals into it is explicitly a **non-goal** of this spec (future
41
- work, §10).
42
-
43
- ## 2. Event payload format: full entity snapshot
44
-
45
- ### Decision
46
-
47
- Every state-changing event carries the **complete post-image of the entity**
48
- (`payload` = the same zod-validated document that today lands in
49
- `<entity>/<id>.json`). Deletions are explicit tombstones (`payload: null`,
50
- `action: "delete"`). No JSON-patch, no field-deltas.
51
-
52
- ```jsonc
53
- {
54
- "v": 2, // envelope schema version
55
- "seq": 18204, // store-global, assigned under lock (§4)
56
- "ts": "2026-06-10T14:02:11.318Z",// informational ONLY, never ordering
57
- "writer": "w_1a2b3c", // writer instance id: pid + start-nonce
58
- "agent": "claude-code",
59
- "agent_id": "agt_...",
60
- "user": "jberdah",
61
- "action": "update", // existing EventAction union
62
- "item_type": "plan",
63
- "item_id": "pln_2290bc70",
64
- "entity_rev": 7, // per-entity monotonic revision (§6)
65
- "payload": { /* full post-image, schema-versioned doc */ },
66
- "summary": "step 1 completed" // kept for notification consumers
67
- }
68
- ```
69
-
70
- ### Why snapshots win
71
-
72
- - **Replay is a trivially correct reducer.** Rebuild = single pass, last
73
- event per `item_id` wins, tombstones remove. No patch-base tracking, no
74
- op-ordering semantics, no "patch against missing base" failure class.
75
- - **Zero-dep constraint.** JSON-patch (RFC 6902) means either a new runtime
76
- dep or a hand-rolled implementation — hand-rolled patch appliers are
77
- exactly the kind of subtle code that produced trp_d5595086 (silent data
78
- loss via load-swallow). Snapshots reuse the existing zod schemas as the
79
- only validation layer.
80
- - **Partial history loss is survivable.** With diffs, one torn/lost event
81
- poisons every later diff for that entity. With snapshots, the next event
82
- for that entity self-heals the projection.
83
- - **Size is bounded by compaction, not by the payload format.** Entities are
84
- 1–10KB. The worst case (a plan updated 50× in a session) costs ~500KB of
85
- journal — and §5's checkpointing makes old fat segments irrelevant to
86
- replay cost. Optimizing bytes here buys nothing measurable and sells
87
- correctness.
88
-
89
- ### Trade-off acknowledged
90
-
91
- Snapshot payloads make the journal **chatty in git diffs** (every event line
92
- embeds the whole doc). Mitigation: the journal lives under
93
- `.brainclaw/journal/` and the *projections* stay git-diffable as today —
94
- store identity for human review remains the per-entity JSON files +
95
- PROJECT.md. The journal is diffable too (append-only = pure line additions),
96
- just verbose. OPEN QUESTION Q1 (§11) flags whether `payload` should be
97
- elided for `summary`-only event kinds (session_start, run_* lifecycle) —
98
- proposed: yes, payload is required only for actions that mutate a persisted
99
- entity.
100
-
101
- ## 3. Atomicity & append guarantees
102
-
103
- ### Append protocol (replaces the swallow)
104
-
105
- 1. All journal appends happen **inside the store mutation lock** — the
106
- journal becomes part of the `mutate()` critical section, ordered
107
- **journal-first** (write-ahead): append event(s) → apply projections →
108
- release lock. Crash between append and projection write = projection is
109
- stale-but-rebuildable; the lazy reconciler (§6) converges it on next read.
110
- 2. One event = **one `fs.writeSync` call** on a fd opened with flag `'a'`
111
- (O_APPEND on POSIX; FILE_APPEND_DATA on Windows). Single-syscall writes
112
- of a full line ≤ a few KB do not interleave on local filesystems on
113
- either platform. This is the **seatbelt**, not the primary guarantee —
114
- the lock is. It matters precisely in the lock-expiry race (lock.ts O2
115
- residual: a breaker can briefly coexist with a stale-but-alive owner):
116
- two appenders may both write, but neither corrupts the other's line, and
117
- `(writer, seq)` lets the reader detect the overlap (§4).
118
- 3. **Failures are loud.** If the journal is source of truth, a failed append
119
- is a failed mutation: `appendEvent` throws inside `mutate()`, the
120
- mutation reports failure to the caller, projections are not written.
121
- The current `logger.debug` swallow is removed in journal-mode. (During
122
- the dual-write phase the legacy stream keeps best-effort semantics; the
123
- new journal is strict from day one — see §8.)
124
-
125
- ### fsync policy
126
-
127
- Default: **no fsync per event.** Node's `writeSync` hands data to the OS;
128
- on OS crash / power loss we may lose the tail. That is acceptable because
129
- (a) projections exist on disk as a second copy, (b) the store also commits
130
- to git (`commitMemoryChange`), and (c) the recovery rule below makes a torn
131
- tail non-fatal. Config escape hatch: `journal.fsync: always | rotate | off`
132
- (default `rotate` — fsync on segment seal and checkpoint write only).
133
- Per-event fsync on Windows is brutal (~ms each) and would violate the
134
- "MCP worker-per-call stays cheap" constraint.
135
-
136
- ### Torn-tail recovery (read side)
137
-
138
- A reader hitting the active segment applies one rule: **a final line not
139
- terminated by `\n`, or that fails `JSON.parse`, is a torn write — ignore
140
- it and treat the previous line as head.** The next writer, before
141
- appending, checks the last byte of the file; if it is not `\n`, it moves
142
- the torn bytes into `journal/quarantine/<segment>-<ts>.torn` and appends a
143
- `journal_repair` event recording what was quarantined. Torn data is parked,
144
- never deleted (house rule). Mid-file malformed lines (should be impossible
145
- under the lock) are surfaced via `logger.warn` + `brainclaw doctor`, never
146
- silently skipped — that is the trp_d5595086 lesson applied to the journal.
147
-
148
- ### Windows/POSIX divergence note
149
-
150
- All of the above must land with tests run on both families — the sprint-1
151
- release-gate trap (trp_e85e9fbe) showed `shell:true` spawn and path-
152
- normalization behaviors diverge between local Windows, CI Windows, and
153
- Linux. The append-atomicity seatbelt specifically needs a two-process
154
- stress test (spawn N children appending K events; assert no interleaved
155
- bytes, no lost `(writer, seq)` pairs) on both platforms.
156
-
157
- ## 4. Ordering: store-global seq under the lock; ts is decoration
158
-
159
- - `seq` is a **store-global monotonic integer**, persisted in
160
- `journal/meta.json` (`next_seq`), incremented under the mutation lock.
161
- Since every legitimate append already holds the lock, this is trivially
162
- total-ordered. File order and seq order coincide in the normal case.
163
- - `writer` (pid + random start nonce) disambiguates the abnormal case: the
164
- lock-expiry break window can produce two writers that both read the same
165
- `next_seq`. Readers treat `(seq, writer)` as the identity; a duplicate
166
- `seq` from different writers is a **detected anomaly** — the reducer
167
- applies both in file order and emits a doctor warning. Snapshot payloads
168
- (§2) make this safe: the later file line wins wholesale, no diff
169
- corruption.
170
- - **Timestamps never order anything.** Clock skew across agent shells,
171
- WSL, and containers is real; `ts` is for humans and notification
172
- summaries only.
173
- - **Federation hook (informative, not normative here):** the journal is the
174
- Pull-and-Materialize substrate. Remote events are imported preserving
175
- `origin: {store_id, seq}` and assigned fresh local seqs; per-entity
176
- conflict detection uses `entity_rev` (§6). Cross-store merge semantics
177
- (entity-level LWW vs. manual conflict surfacing) is OPEN QUESTION Q2 —
178
- it needs the federation architecture's owner, not this spec.
179
-
180
- ## 5. Segments + checkpoints replace lossy rotation
181
-
182
- ### Layout
183
-
184
- ```
185
- .brainclaw/journal/
186
- meta.json # next_seq, active segment id, checkpoint ref
187
- active.jsonl # current segment, append-only
188
- segments/
189
- seg-000001-000812.jsonl # sealed, IMMUTABLE (seq range in name)
190
- seg-000813-001650.jsonl
191
- checkpoints/
192
- ckpt-001650.json # full-state snapshot manifest at seq 1650
193
- quarantine/ # torn tails, unparseable lines (parked)
194
- ```
195
-
196
- ### Seal & checkpoint protocol (under the lock)
197
-
198
- When `active.jsonl` crosses the size threshold (keep 10MB):
199
-
200
- 1. Write `ckpt-<seq>.json`: a manifest containing the full materialized
201
- state at head seq (entity id → post-image, or — cheaper — entity id →
202
- `{file hash, entity_rev}` referencing the projection files; OPEN
203
- QUESTION Q3 picks between self-contained vs. referencing checkpoints).
204
- 2. fsync checkpoint, then rename `active.jsonl` →
205
- `segments/seg-<first>-<last>.jsonl` (sealed segments are immutable
206
- forever after).
207
- 3. Create fresh `active.jsonl` whose first record is a `checkpoint_ref`
208
- event pointing at the checkpoint.
209
- 4. Update `meta.json` last (atomic write via existing `writeFileAtomic`).
210
-
211
- **Rebuild cost is bounded:** latest checkpoint + replay of `active.jsonl`
212
- only (≤10MB ⇒ ~5–15k events ⇒ well under the 1s cold-read target on the
213
- hardware we run). A 100k-event store replays the same ≤10MB tail; the other
214
- 90k events sit in sealed segments that only `doctor --verify-journal`,
215
- backfill audits, or federation ever read.
216
-
217
- ### Cursors survive rotation
218
-
219
- `AgentCursor` becomes `{segment_id, offset, last_read}`. Sealing does not
220
- touch cursors: a cursor pointing into a now-sealed segment is still valid
221
- (the file still exists, immutable). `readUnseenEvents` walks: remainder of
222
- cursor's segment → subsequent sealed segments → active. The current
223
- "rotation deletes all cursors" behavior — and its silent re-notification
224
- loss — disappears entirely.
225
-
226
- ### Retention
227
-
228
- Sealed segments and checkpoints are **never auto-deleted**. `brainclaw gc`
229
- may archive segments older than the N-th checkpoint into
230
- `.brainclaw/gc-backups/` (existing park location). Rationale: house rule
231
- park-don't-delete, plus federation may need deep history.
232
-
233
- ## 6. Projections: entity dirs become lazily reconciled caches
234
-
235
- ### Mechanics
236
-
237
- - Each projection family (constraints, decisions, traps, handoffs, plans,
238
- and later assignments/runs/claims) tracks `last_applied_seq` in
239
- `journal/meta.json` (single file, one stat to check everything).
240
- - **Read path** (`loadState`, entity getters): stat-compare
241
- `meta.next_seq - 1` vs `last_applied_seq`. Equal → serve projection files
242
- as today (zero added cost beyond one small JSON read — keeps the MCP
243
- worker-per-call re-import model cheap). Behind → acquire lock, replay the
244
- delta events into the projection files, bump `last_applied_seq`, serve.
245
- This is exactly the pln#496 lazy-reconcile pattern; **no daemon**.
246
- - **Write path migration** is the key ergonomic question. Today
247
- `mutateState(fn)` lets callers imperatively poke a full `State`. End
248
- state: writers emit **events**, and projections are a pure
249
- `apply(state, event)` reducer. Transition without rewriting ~all call
250
- sites: `persistStateUnlocked` computes an **id-level diff** (loaded state
251
- vs. mutated state per entity collection: created / content-changed /
252
- removed) and synthesizes the corresponding snapshot events automatically.
253
- Callers keep their API; the journal gets correct per-entity events.
254
- Verb-level code (assignments.ts, agentruns.ts, loops) migrates to
255
- explicit event emission opportunistically afterwards.
256
- - `syncDirectory(deleteMissing)` keeps its trp_d5595086 guard during dual-
257
- write. In journal-primary mode, deletion authority moves to tombstone
258
- events: a projection file is only unlinked when a tombstone for its id is
259
- applied — "absent from in-memory state" stops being a deletion signal at
260
- all, which closes that bug class structurally rather than defensively.
261
-
262
- ### entity_rev
263
-
264
- Each entity carries a monotonic `entity_rev` bumped on every event for that
265
- id. Uses: cheap "did it change" checks for projections, optimistic-
266
- concurrency guard for future API writes, and the conflict-detection
267
- primitive federation needs. Stored in the event envelope, not inside the
268
- document (keeps entity schemas untouched during migration).
269
-
270
- ## 7. Crash-matrix (invariants self-attack, round-1 honesty)
271
-
272
- | Scenario | Outcome under this design |
273
- |---|---|
274
- | Crash mid-append | Torn tail quarantined on next read/write (§3); at most the in-flight mutation lost; projections untouched (journal-first means they were never written) |
275
- | Crash between append and projection write | Journal ahead of projection; lazy reconcile converges on next read |
276
- | Crash during seal (steps 1–4) | Ordered writes + meta-last: worst case is a checkpoint file with no meta ref (orphan, harmless) or active not yet renamed (retry seal next time); each step idempotent-checkable |
277
- | Two writers (lock-expiry break, O2 residual) | O_APPEND prevents byte interleaving; duplicate seq detected via `(seq, writer)`; snapshot payloads make double-apply convergent; doctor warning emitted |
278
- | Rotation during concurrent read | Sealed segments immutable; reader holding an fd on the just-sealed file still reads valid data (POSIX) — **Windows caveat:** rename of an open file can fail (EPERM/EBUSY); seal must retry/defer if the rename fails, never copy-then-delete. Flagged for test coverage |
279
- | Clock skew | Irrelevant — ts never orders (§4) |
280
- | 100k-event store | Replay bounded to active segment by checkpoints (§5); cold read target <1s holds |
281
- | Journal disabled/absent (worktree without .brainclaw, trp_26e9634b) | Same failure mode as today's store access — out of scope here, but the spec must not make CLI hang harder on missing journal; ENOENT → clear error |
282
-
283
- ## 8. Migration plan (flag: `journal.mode = off | dual | primary`)
284
-
285
- - **Phase 0 — substrate (no reader change):** envelope v2, loud appends,
286
- seq/meta, segments+checkpoints, cursor format migration. Journal still
287
- consumed only by notifications. Old `events.jsonl` (17k events) and any
288
- `events.<ts>.jsonl` archives are **parked** under
289
- `journal/legacy/` — they carry no payloads and cannot be upgraded; they
290
- remain audit history, not replayable state.
291
- - **Phase 1 — dual-write (`dual`):** genesis backfill emits one
292
- `backfill`-action snapshot event per existing entity (current state =
293
- seq 1..N), then `persistStateUnlocked` diff-emission (§6) runs alongside
294
- the unchanged file writes. State dirs remain authoritative. Rollback =
295
- set `off`; nothing depended on the journal yet.
296
- - **Phase 2 — verification:** `brainclaw doctor --verify-journal` rebuilds
297
- state from checkpoint+journal in a temp dir and diffs against the live
298
- projections; runs in CI on both OS families and in dogfooding for a full
299
- sprint. Exit criterion: zero divergence across a sprint of real
300
- multi-agent traffic, including dispatch worktree churn.
301
- - **Phase 3 — primary (`primary`):** reads serve projections via lazy
302
- reconcile; deletion authority moves to tombstones; `mutateState` callers
303
- unchanged. **Rollback path:** projections are at all times a full
304
- materialized state in the exact legacy format — flipping back to `dual`
305
- or `off` requires no data transformation, only re-arming the legacy
306
- delete semantics. Backup of `.brainclaw/` taken at each phase flip
307
- (upgrade-style, park-don't-delete).
308
- - **Perf gates (measured, not asserted):** `bclaw_work` cold read < 1s;
309
- single-entity op cost independent of store size (O(1) append + O(1)
310
- projection write + O(delta) reconcile); MCP per-call overhead delta
311
- < 50ms vs. today.
312
-
313
- ## 9. Hard-constraint compliance check
314
-
315
- - Zero new runtime deps: JSONL + zod + node:fs only. ✓
316
- - Windows + POSIX: O_APPEND/FILE_APPEND_DATA seatbelt, rename-of-open-file
317
- caveat handled, dual-platform CI mandated (trp_e85e9fbe). ✓
318
- - File-based, git-diffable identity: projections unchanged; journal is
319
- append-only text. ✓
320
- - No daemon: reconciliation only at read paths under lock. ✓ (dec'd in
321
- federation architecture)
322
- - MCP worker-per-call cheap: clean-state read path adds one small meta read. ✓
323
- - Does not regress sprint-1 lock hardening: journal lives *inside* the
324
- existing `mutate()` critical section; no new lock protocol introduced. ✓
325
-
326
- ## 10. Non-goals (this spec)
327
-
328
- - Unifying per-loop journals (`loops/<id>/events.jsonl`) into the store
329
- journal — convergence candidate after primary mode stabilizes.
330
- - Federation merge semantics (consumes this journal; owned by federation
331
- spec).
332
- - Audit-log (`audit.ts`) consolidation.
333
- - Query/index layer over the journal (projections are the query surface).
334
-
335
- ## 11. OPEN QUESTIONS (for cross-critique, Codex schema review, Juan)
336
-
337
- - **Q1 (schema):** which `EventAction`s are exempt from carrying `payload`?
338
- Proposal: payload required iff the action mutates a persisted entity;
339
- lifecycle/notification actions stay payload-free. Codex: please attack
340
- the action-union → payload-requirement mapping for holes.
341
- - **Q2 (product/federation):** cross-store conflict policy when two stores
342
- edited the same entity between pulls — entity-level LWW by pull order,
343
- or surface a conflict artifact for the operator? Affects whether
344
- `entity_rev` needs a vector component. **Juan's call.**
345
- - **Q3 (schema/perf):** checkpoints self-contained (full post-images,
346
- bigger but standalone) vs. referencing (hashes of projection files,
347
- small but couples checkpoint validity to projection integrity)?
348
- Proposal leans self-contained; needs a size estimate at 20-agent scale.
349
- - **Q4 (scope):** do assignments/agent_runs/claims (currently written via
350
- their own stores, not `State`) enter the journal in Phase 1 or in a
351
- Phase 1.5? They are the highest-churn entities — biggest win, biggest
352
- blast radius.
353
- - **Q5 (ops):** exact threshold/policy for `gc` archiving of sealed
354
- segments — count-based, age-based, or never until federation needs
355
- defining?
356
-
357
- ## 12. Memory citations (per loop protocol)
358
-
359
- Relied on: trp_d5595086 (silent-data-loss via load-swallow — drove §3 loud
360
- failures, §6 tombstone deletion authority), feedback_lazy_reconcile_pattern
361
- / pln#496 (drove §6 read-path reconciliation, no daemon), trp_e85e9fbe
362
- (dual-platform CI gates in §3/§7), trp_26e9634b (worktree-without-store
363
- failure mode noted in §7), feedback_no_init_force / park-don't-delete house
364
- rule (§5 retention, §8 rollback), architecture decisions: federation
365
- Pull-and-Materialize + no-daemon (§4 federation hook, §9 compliance).