@mu-crew/mu 3.11.2 → 3.11.3
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/AGENTS.md +2 -1
- package/dist/{chunk-2FJK6OOZ.js → chunk-3L5KO3PX.js} +3 -3
- package/dist/{chunk-JYZUNPPO.js → chunk-F7ZBF6I7.js} +24 -22
- package/dist/chunk-F7ZBF6I7.js.map +1 -0
- package/dist/{chunk-4PACTXAB.js → chunk-L2ABBTYG.js} +1 -1
- package/dist/chunk-L2ABBTYG.js.map +1 -0
- package/dist/{chunk-DXKJY3NT.js → chunk-LEORAGKV.js} +3 -3
- package/dist/{chunk-WYBOR4FX.js → chunk-R2SVBZAB.js} +20 -4
- package/dist/chunk-R2SVBZAB.js.map +1 -0
- package/dist/{cli-GRAPF5VC.js → cli-GJIO7GWD.js} +9 -8
- package/dist/cli-GJIO7GWD.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/extension/mu-pi.js +122 -32
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/{tui-DGDEH4JX.js → tui-WHCLVCYE.js} +5 -5
- package/dist/tui-sync-worker.js +2 -2
- package/docs/architecture/control-socket.md +1 -1
- package/docs/guide/delegate.md +7 -0
- package/docs/reference/env.md +1 -0
- package/docs/reference/naming.md +7 -0
- package/package.json +1 -1
- package/dist/chunk-4PACTXAB.js.map +0 -1
- package/dist/chunk-JYZUNPPO.js.map +0 -1
- package/dist/chunk-WYBOR4FX.js.map +0 -1
- package/dist/cli-GRAPF5VC.js.map +0 -1
- /package/dist/{chunk-2FJK6OOZ.js.map → chunk-3L5KO3PX.js.map} +0 -0
- /package/dist/{chunk-DXKJY3NT.js.map → chunk-LEORAGKV.js.map} +0 -0
- /package/dist/{tui-DGDEH4JX.js.map → tui-WHCLVCYE.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/capture.ts","../src/tasks/status.ts","../src/db.ts","../src/hlc.ts","../src/op-context.ts","../src/file-lock.ts","../src/legacy-ops.ts","../src/apply.ts","../src/segment-manifest.ts","../src/sha256-resumable.ts","../src/segments.ts","../src/sync.ts"],"sourcesContent":["// mu — op capture: SQLite triggers that record every change to a\n// portable table as an op, inside the SAME TRANSACTION as the mutation.\n//\n// WHY TRIGGERS AND NOT HAND-EMITTED OPS\n// -------------------------------------\n// Capture fires inside the same transaction as the row change, in the\n// same file. So capture is ATOMIC with the change: the two cannot\n// drift, not even on power loss mid-write. Either both landed or\n// neither did.\n//\n// Hand-emitted ops (an `emitOp(...)` next to each mutation) were\n// rejected because they can be FORGOTTEN. A forgotten op is no\n// longer \"sync missed something\" — undo, sync and history are\n// ALL projections of this one log, so one missing op is silent\n// corruption of all four at once. A future SDK function that mutates\n// `tasks` must not be ABLE to skip capture. Triggers make that\n// structural rather than a convention someone has to remember.\n//\n// WHY THE TRIGGERS ARE TEMP TRIGGERS (the load-bearing surprise)\n// -------------------------------------------------------------\n// The triggers need per-invocation context (intent / actor / group /\n// the echo guard) which lives in the `_op_ctx` TEMP table. SQLite\n// REFUSES to let a main-schema trigger reference the temp schema:\n//\n// sqlite> CREATE TRIGGER x AFTER INSERT ON tasks\n// > WHEN (SELECT applying FROM _op_ctx) = 0 ...\n// Error: no such table: main._op_ctx\n// -- and qualifying it explicitly fails differently:\n// Error: trigger x cannot reference objects in database temp\n//\n// So the triggers themselves must live in the TEMP schema, where the\n// temp table IS visible. Verified empirically (see the probe results in\n// this task's note). Consequences, all of them fine:\n//\n// * Triggers are (re)created per connection, by `installCapture`,\n// which `openDb` calls on every open. There is no persistent\n// trigger in the DB file, so no stale-DDL-in-file problem and no\n// schema-version churn when the trigger set changes.\n// * A connection that never runs `installCapture` captures nothing.\n// That is only reachable inside this codebase (readonly opens), not\n// by a normal `mu` invocation.\n// * A TEMP trigger cannot write to a qualified `main.ops` —\n// \"qualified table names are not allowed on INSERT, UPDATE, and\n// DELETE statements within triggers\" — so the INSERTs here are\n// UNQUALIFIED and resolve to `main` because no temp table shadows\n// those names. `_op_ctx` / `_op_clock` / `_op_dying` are prefixed\n// to make that shadowing impossible by accident.\n//\n// SEMANTIC PARTIAL UPDATES — ONLY CHANGED COLUMNS\n// -----------------------------------------------\n// The UPDATE triggers compare `NEW.<col> IS NOT OLD.<col>` per column\n// and build the payload from just the columns that actually changed, so\n// `task.close` carries `{\"status\":\"CLOSED\"}` and nothing else. This is\n// the single detail that makes per-field merge FREE: \"apply in HLC\n// order\" then converges without column version vectors.\n//\n// Dumping the whole row instead would look identical in every\n// single-machine test and silently regress the design from field-level\n// to row-level last-writer-wins. mu runs autonomous agent crews, so a\n// devserver crew closing a task while the operator edits that task's\n// impact on a laptop is concurrent multi-machine writing BY\n// CONSTRUCTION. Field-level merge keeps both edits; row-level LWW\n// discards one at random. `IS NOT` (not `<>`) because `<>` is NULL for\n// a NULL operand, which would drop every set-to-NULL and\n// NULL-to-a-value transition — e.g. releasing a claim\n// (`owner_id -> NULL`) would never be captured.\n\n// TYPE-ONLY import: db.ts imports this module, so a value import would\n// be a runtime cycle (and an import cycle here shows up as `node\n// dist/cli.js` printing nothing at all). `typeof PORTABLE_TABLES` is a\n// type position, so this is erased at compile time.\nimport type { PORTABLE_TABLES } from \"./db.js\";\n\n/** Sentinel key segment for a natural key whose parent row could not be\n * resolved. Should be unreachable — the dying-ancestor stash below\n * exists precisely so cascades can still resolve — but a capture that\n * records a degraded key is strictly better than one that records\n * nothing, so this FAILS SAFE rather than failing silent. */\nconst UNRESOLVED = \"<unresolved>\";\n\n// ─── The op context temp tables ───────────────────────────────────────\n\n/**\n * DDL for the three per-connection temp tables the triggers read.\n * Created by `installCapture` before the triggers that reference them.\n *\n * _op_ctx the **op context** (docs/VOCABULARY.md): group_id /\n * actor / intent / applying. Exactly ONE row, seeded with\n * defaults so a mutation occurring outside any SDK context\n * is still CAPTURED, just with a null intent. Fail safe,\n * never fail silent.\n *\n * _op_clock a one-row scratchpad holding \"now\" for the current\n * trigger firing. The HLC advance needs to compare `now`\n * against `last_wall` and then reuse the SAME `now` to\n * write it; calling unixepoch() twice could straddle a\n * millisecond boundary and mint a non-monotonic pair. So\n * the value is stashed once per op and read from here.\n *\n * _op_dying natural keys of rows that are mid-DELETE — see the\n * DELETE section below. Keyed by (kind, id).\n *\n * Temp tables are per-connection and mu is one connection per\n * short-lived process, so there is no cross-process leakage and no\n * cleanup to schedule.\n */\nexport const OP_CTX_DDL = `\nCREATE TEMP TABLE IF NOT EXISTS _op_ctx (\n group_id TEXT,\n actor TEXT,\n intent TEXT,\n applying INTEGER NOT NULL DEFAULT 0\n);\nCREATE TEMP TABLE IF NOT EXISTS _op_clock (\n now_ms INTEGER NOT NULL DEFAULT 0\n);\nCREATE TEMP TABLE IF NOT EXISTS _op_dying (\n kind TEXT NOT NULL,\n id INTEGER NOT NULL,\n key TEXT NOT NULL,\n PRIMARY KEY (kind, id)\n);\n`;\n\n/** Seed the singleton rows. Separate from the DDL because CREATE TABLE\n * IF NOT EXISTS is idempotent but INSERT is not. */\nconst OP_CTX_SEED = `\nINSERT INTO _op_ctx (group_id, actor, intent, applying)\n SELECT NULL, NULL, NULL, 0 WHERE NOT EXISTS (SELECT 1 FROM _op_ctx);\nINSERT INTO _op_clock (now_ms)\n SELECT 0 WHERE NOT EXISTS (SELECT 1 FROM _op_clock);\n`;\n\n// ─── Shared SQL fragments ─────────────────────────────────────────────\n\n/** Echo guard. Every trigger carries it. `applying = 1` means we are\n * INGESTING a peer's op, where writing a fresh local op would be an\n * echo that propagates back and never terminates. v2-sync sets it. */\nconst NOT_APPLYING = \"(SELECT applying FROM _op_ctx) = 0\";\n\n/** Advance the persisted HLC by one tick, then read it back formatted.\n * Mirrors `nextHlc` in src/hlc.ts EXACTLY — same monotonic rule (if\n * now > last_wall take now with counter 0, else hold the wall and step\n * the counter) and same `%015d.%06d.%s` serialization. It is\n * reimplemented in SQL rather than called from JS because a trigger\n * cannot call back into JS, and the whole point is that capture\n * happens inside the mutation's transaction.\n *\n * Kept honest by test/capture.test.ts, which asserts the SQL-minted\n * HLC parses with `parseHlc` and interleaves monotonically with\n * JS-minted ones. If the format changes in one place the other fails. */\nconst ADVANCE_CLOCK = `\n UPDATE _op_clock SET now_ms = CAST(unixepoch('subsec') * 1000 AS INTEGER);\n UPDATE machine_identity\n SET last_wall = MAX(last_wall, (SELECT now_ms FROM _op_clock)),\n last_counter = CASE WHEN (SELECT now_ms FROM _op_clock) > last_wall\n THEN 0 ELSE last_counter + 1 END\n WHERE id = 1;`;\n\n/** The just-advanced HLC, formatted. Must be read AFTER ADVANCE_CLOCK. */\nconst HLC = `(SELECT printf('%015d.%06d.%s', last_wall, last_counter, machine_id)\n FROM machine_identity WHERE id = 1)`;\n\n/** Column list shared by every op INSERT. */\nconst OP_COLS = \"(hlc, machine_id, group_id, actor, intent, entity, key, op, payload, created_at)\";\n\n/** The context/identity columns, in OP_COLS order after `hlc`.\n * `group_id` falls back to a per-op random hex string so the column is\n * never NULL: an op outside any SDK context is its own group of one,\n * which is exactly right for undo. */\nconst OP_CTX_VALUES = `\n (SELECT machine_id FROM machine_identity WHERE id = 1),\n COALESCE((SELECT group_id FROM _op_ctx), lower(hex(randomblob(8)))),\n (SELECT actor FROM _op_ctx),\n (SELECT intent FROM _op_ctx)`;\n\n/** ISO-8601 wall time, matching what the SDK writes elsewhere.\n * Advisory only — `hlc` is the ordering key, this is for humans. */\nconst CREATED_AT = `strftime('%Y-%m-%dT%H:%M:%fZ', 'now')`;\n\n// ─── Natural keys ─────────────────────────────────────────────────────\n//\n// `ops.key` is ALWAYS the natural key, never a surrogate id. This is\n// exactly why mu's keys don't collide across machines the way an\n// AUTOINCREMENT rowid would: two machines both minting `tasks.id = 7`\n// is inevitable and meaningless, whereas `demo/fix-auth` denotes the\n// same task everywhere.\n//\n// workstream <name> demo\n// task <workstream>/<local_id> demo/fix-auth\n// note <workstream>/<local_id>#<id> demo/fix-auth#12\n// edge <blocker> -> <blocked> demo/a->demo/b\n//\n// Notes keep their surrogate `id` as a suffix because a note has no\n// natural identity of its own — same author and text twice is two\n// notes. Notes are append-only and never edited, so the suffix only\n// needs to be locally unique, and `<task-key>#<id>` is.\n\n/** Workstream name for a workstream id, or the dying-stash value if the\n * workstream row is already gone (FK cascade). */\nconst wsKey = (idExpr: string): string => `COALESCE(\n (SELECT w.name FROM workstreams w WHERE w.id = ${idExpr}),\n (SELECT d.key FROM _op_dying d WHERE d.kind = 'workstream' AND d.id = ${idExpr}),\n '${UNRESOLVED}')`;\n\n/** `<workstream>/<local_id>` for a task id, falling back to the dying\n * stash when the task row itself is already gone. */\nconst taskKey = (idExpr: string): string => `COALESCE(\n (SELECT ${wsKey(\"t.workstream_id\")} || '/' || t.local_id\n FROM tasks t WHERE t.id = ${idExpr}),\n (SELECT d.key FROM _op_dying d WHERE d.kind = 'task' AND d.id = ${idExpr}),\n '${UNRESOLVED}')`;\n\n// ─── Per-table trigger DDL ────────────────────────────────────────────\n\n/** Build the changed-columns-only payload expression for an UPDATE.\n *\n * Nests one CASE per column around a `json_insert` so a column lands\n * in the payload only when it actually changed:\n *\n * CASE WHEN NEW.impact IS NOT OLD.impact\n * THEN json_insert(<inner>, '$.impact', NEW.impact)\n * ELSE <inner> END\n *\n * With six columns and one change that yields a 1-key object. */\nfunction changedPayload(cols: readonly string[]): string {\n let expr = \"'{}'\";\n for (const col of cols) {\n expr = `CASE WHEN NEW.${col} IS NOT OLD.${col}\n THEN json_insert(${expr}, '$.${col}', NEW.${col})\n ELSE ${expr} END`;\n }\n return expr;\n}\n\n/** Whole-row payload for an INSERT: an insert changes every column by\n * definition, so there is nothing to diff against. */\nfunction fullPayload(cols: readonly string[]): string {\n const pairs = cols.map((c) => `'${c}', NEW.${c}`).join(\", \");\n return `json_object(${pairs})`;\n}\n\n/** Whole-row payload for a DELETE, from `OLD.*`.\n *\n * Tombstones are normally EMPTY (`'{}'`): the key identifies the row\n * and the puts before it describe it, so carrying the body again would\n * just bloat the log. Notes are the exception, and the reason is their\n * key.\n *\n * A note's key embeds its rowid (`<ws>/<task>#<id>`), which is NOT\n * portable — a rebuild, a v8/v9 reprojection, or any path that\n * reinserts a note assigns a fresh one (see src/drift.ts, which\n * deliberately matches notes on the task-key PREFIX for exactly this\n * reason). When that happens the historical `put` stays under the old\n * key while a later `del` is emitted under the current one, and\n * nothing joins the two.\n *\n * Undo folds the puts for a key to reconstruct a tombstoned row, so a\n * note in that state reconstructed to `{}` and was silently never\n * restored (drift-641: `mu undo` of a workstream teardown brought back\n * every task and edge but only the notes whose rowid happened to be\n * unchanged). A self-describing note tombstone closes that hole: the\n * op that removed the row also carries what the row WAS, so the\n * inverse never depends on finding a matching put. */\nfunction fullOldPayload(cols: readonly string[]): string {\n const pairs = cols.map((c) => `'${c}', OLD.${c}`).join(\", \");\n return `json_object(${pairs})`;\n}\n\n/** A note tombstone's payload. The full row only when the log holds no\n * put under the same key (a reprojection gave the note a new rowid, so\n * undo could not fold it back: drift-641); otherwise `{}`, because\n * undo's fold and apply's delete both read the content from that put.\n * Without this, every workstream teardown wrote each note a second time. */\nfunction noteTombstonePayload(keyExpr: string, cols: readonly string[]): string {\n return `CASE WHEN EXISTS (\n SELECT 1 FROM ops WHERE entity = 'note' AND key = ${keyExpr} AND op = 'put'\n ) THEN '{}' ELSE ${fullOldPayload(cols)} END`;\n}\n\n/** `WHEN` clause restricting an UPDATE trigger to real changes. A\n * no-op UPDATE (SET x = x, or rewriting identical values) produces NO\n * op at all, which keeps the log free of churn that would otherwise\n * make every `mu log` read noisy and every sync flush bigger. */\nfunction anyChanged(cols: readonly string[]): string {\n return cols.map((c) => `NEW.${c} IS NOT OLD.${c}`).join(\"\\n OR \");\n}\n\n/** Emit one op. `keyExpr`/`payloadExpr` are SQL expressions. */\nfunction emitOp(\n entity: string,\n opKind: \"put\" | \"del\",\n keyExpr: string,\n payloadExpr: string,\n): string {\n return `${ADVANCE_CLOCK}\n INSERT INTO ops ${OP_COLS} VALUES (\n ${HLC},${OP_CTX_VALUES},\n '${entity}',\n ${keyExpr},\n '${opKind}',\n ${payloadExpr},\n ${CREATED_AT}\n );`;\n}\n\n/** Columns captured per portable table. Deliberately EXCLUDES surrogate\n * ids and FK columns that are already encoded in the natural key\n * (`tasks.workstream_id`, `task_notes.task_id`, the edge endpoints),\n * because shipping a peer our local rowids would be worse than\n * useless. Changing one of those would re-key the row, which no op\n * can express, so KEY_COLUMNS below refuses it instead. `tasks.owner_id` IS captured: it is an FK into the\n * machine-local `agents` table, so it never syncs (see\n * MACHINE_LOCAL_TABLES), but it must still be captured for local\n * history and undo of a claim/release. */\nconst CAPTURED_COLUMNS = {\n workstreams: [\"name\", \"created_at\"],\n tasks: [\n \"local_id\",\n \"title\",\n \"status\",\n \"substate\",\n \"impact\",\n \"effort_days\",\n \"owner_id\",\n \"created_at\",\n \"updated_at\",\n ],\n task_notes: [\"author\", \"content\", \"created_at\"],\n task_edges: [\"created_at\"],\n} as const satisfies Record<(typeof PORTABLE_TABLES)[number], readonly string[]>;\n\n/** Columns that make up (or resolve to) each table's natural key.\n *\n * An UPDATE of one of these moves the row to a different `ops.key`\n * (`a/t1` -> `b/t1`), and every op already in the log stays filed under\n * the old key. The UPDATE triggers above diff only CAPTURED_COLUMNS, so\n * such an update used to emit NOTHING: no tombstone for the old key, no\n * put for the new one. Sync, undo, rebuild and `mu doctor` then disagree\n * with the live row. Children re-key with it (a task's notes and edges\n * embed its key), so capturing a move would mean re-emitting a subtree.\n *\n * Natural keys are immutable instead: apply (NEVER_APPLY) and undo\n * (NEVER_RESTORE) already never write these columns, and a raw\n * `mu sql` UPDATE is refused here with an explicit error rather than\n * committing a row the log cannot explain. The guard is NOT gated on\n * the echo guard: no mu path re-keys a row, ingest included. */\nconst KEY_COLUMNS = {\n workstreams: [\"name\"],\n tasks: [\"workstream_id\", \"local_id\"],\n task_notes: [\"id\", \"task_id\"],\n task_edges: [\"from_task_id\", \"to_task_id\"],\n} as const satisfies Record<(typeof PORTABLE_TABLES)[number], readonly string[]>;\n\n/** BEFORE UPDATE trigger refusing a natural-key change on `table`. */\nfunction keyGuard(table: keyof typeof KEY_COLUMNS): string {\n const cols = KEY_COLUMNS[table];\n const msg =\n `mu: ${table}.${cols.join(\"/\")} is part of the natural key that every op is filed under; ` +\n \"changing it would desync the ops log, sync and undo. \" +\n \"Add a new row (mu task add / mu workstream init) instead of moving or renaming one.\";\n return `\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_${table}_key\nBEFORE UPDATE OF ${cols.join(\", \")} ON ${table}\n WHEN ${anyChanged(cols)}\nBEGIN\n SELECT RAISE(ABORT, '${msg.replaceAll(\"'\", \"''\")}');\nEND;`;\n}\n\n/**\n * THE DELETE SUBTLETY\n * -------------------\n * Every other op can resolve its natural key lazily, because the row is\n * still there. DELETE cannot: by the time anything downstream looks,\n * the row is gone. So the key is captured INLINE, in the trigger, while\n * the row still exists.\n *\n * That alone is not enough, because of FK CASCADE. Empirically (this\n * was the thing most worth checking): SQLite FK `ON DELETE CASCADE`\n * DOES fire triggers on the cascaded child rows — and it does so\n * regardless of the `recursive_triggers` pragma, which governs only\n * trigger-initiated recursion, not FK actions. Good: destroying a\n * workstream captures its tasks, notes and edges without any explicit\n * walk in the SDK.\n *\n * The trap is ORDERING. With AFTER DELETE triggers, cascaded children\n * fire after the parent row is already deleted, so joining to the\n * parent to build the child's key yields nothing:\n *\n * DELETE FROM workstreams WHERE id = 1\n * -> edge op key \"<unresolved>-><unresolved>\"\n * -> note op key \"<unresolved>#100\"\n * -> task op key \"<unresolved>/t1\"\n *\n * Two mechanisms fix it together:\n *\n * 1. BEFORE DELETE, not AFTER. The row and its ancestors are all\n * still present when the trigger body runs, so `OLD.*` plus a\n * normal join resolves the key.\n * 2. The `_op_dying` stash. BEFORE DELETE fixes the FIRST level only:\n * cascade children still fire after their parent's row is gone.\n * So each parent's BEFORE DELETE trigger records its own natural\n * key into `_op_dying` before emitting, and the child key\n * resolvers (`wsKey` / `taskKey`) consult the stash when the live\n * join misses. Rows are never removed from the stash: it is a\n * per-connection temp table on a short-lived process, ids are not\n * reused within a transaction, and an INSERT OR REPLACE keyed on\n * (kind, id) keeps it correct even if an id is recycled later.\n *\n * The alternative — having the parent trigger emit ops for its whole\n * subtree and suppressing the cascade triggers — also works and was\n * prototyped, but it duplicates the subtree walk in SQL four times and\n * breaks the moment a new FK is added. The stash is smaller and\n * self-maintaining.\n */\nconst DYING_STASH = (kind: \"workstream\" | \"task\", keyExpr: string): string =>\n `INSERT OR REPLACE INTO _op_dying (kind, id, key) VALUES ('${kind}', OLD.id, ${keyExpr});`;\n\n/** All capture triggers, as one idempotent DDL string. */\nfunction buildTriggerDdl(): string {\n const wsCols = CAPTURED_COLUMNS.workstreams;\n const taskCols = CAPTURED_COLUMNS.tasks;\n const noteCols = CAPTURED_COLUMNS.task_notes;\n const edgeCols = CAPTURED_COLUMNS.task_edges;\n\n const taskKeyNew = `${wsKey(\"NEW.workstream_id\")} || '/' || NEW.local_id`;\n const taskKeyOld = `${wsKey(\"OLD.workstream_id\")} || '/' || OLD.local_id`;\n const edgeKeyNew = `${taskKey(\"NEW.from_task_id\")} || '->' || ${taskKey(\"NEW.to_task_id\")}`;\n const edgeKeyOld = `${taskKey(\"OLD.from_task_id\")} || '->' || ${taskKey(\"OLD.to_task_id\")}`;\n\n return `\n-- ─── natural-key guards (see KEY_COLUMNS) ───────────────────────────\n${keyGuard(\"workstreams\")}\n${keyGuard(\"tasks\")}\n${keyGuard(\"task_notes\")}\n${keyGuard(\"task_edges\")}\n\n-- ─── workstreams ────────────────────────────────────────────────────\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_workstreams_ins\nAFTER INSERT ON workstreams WHEN ${NOT_APPLYING}\nBEGIN\n ${emitOp(\"workstream\", \"put\", \"NEW.name\", fullPayload(wsCols))}\nEND;\n\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_workstreams_upd\nAFTER UPDATE ON workstreams WHEN ${NOT_APPLYING}\n AND (${anyChanged(wsCols)})\nBEGIN\n ${emitOp(\"workstream\", \"put\", \"NEW.name\", changedPayload(wsCols))}\nEND;\n\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_workstreams_del\nBEFORE DELETE ON workstreams WHEN ${NOT_APPLYING}\nBEGIN\n ${DYING_STASH(\"workstream\", \"OLD.name\")}\n ${emitOp(\"workstream\", \"del\", \"OLD.name\", \"'{}'\")}\nEND;\n\n-- ─── tasks ──────────────────────────────────────────────────────────\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_tasks_ins\nAFTER INSERT ON tasks WHEN ${NOT_APPLYING}\nBEGIN\n ${emitOp(\"task\", \"put\", taskKeyNew, fullPayload(taskCols))}\nEND;\n\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_tasks_upd\nAFTER UPDATE ON tasks WHEN ${NOT_APPLYING}\n AND (${anyChanged(taskCols)})\nBEGIN\n ${emitOp(\"task\", \"put\", taskKeyNew, changedPayload(taskCols))}\nEND;\n\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_tasks_del\nBEFORE DELETE ON tasks WHEN ${NOT_APPLYING}\nBEGIN\n ${DYING_STASH(\"task\", taskKeyOld)}\n ${emitOp(\"task\", \"del\", taskKeyOld, \"'{}'\")}\nEND;\n\n-- ─── task_notes ─────────────────────────────────────────────────────\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_task_notes_ins\nAFTER INSERT ON task_notes WHEN ${NOT_APPLYING}\nBEGIN\n ${emitOp(\"note\", \"put\", `${taskKey(\"NEW.task_id\")} || '#' || NEW.id`, fullPayload(noteCols))}\nEND;\n\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_task_notes_upd\nAFTER UPDATE ON task_notes WHEN ${NOT_APPLYING}\n AND (${anyChanged(noteCols)})\nBEGIN\n ${emitOp(\"note\", \"put\", `${taskKey(\"NEW.task_id\")} || '#' || NEW.id`, changedPayload(noteCols))}\nEND;\n\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_task_notes_del\nBEFORE DELETE ON task_notes WHEN ${NOT_APPLYING}\nBEGIN\n ${emitOp(\"note\", \"del\", `${taskKey(\"OLD.task_id\")} || '#' || OLD.id`, noteTombstonePayload(`${taskKey(\"OLD.task_id\")} || '#' || OLD.id`, noteCols))}\nEND;\n\n-- ─── task_edges ─────────────────────────────────────────────────────\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_task_edges_ins\nAFTER INSERT ON task_edges WHEN ${NOT_APPLYING}\nBEGIN\n ${emitOp(\"edge\", \"put\", edgeKeyNew, fullPayload(edgeCols))}\nEND;\n\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_task_edges_upd\nAFTER UPDATE ON task_edges WHEN ${NOT_APPLYING}\n AND (${anyChanged(edgeCols)})\nBEGIN\n ${emitOp(\"edge\", \"put\", edgeKeyNew, changedPayload(edgeCols))}\nEND;\n\nCREATE TEMP TRIGGER IF NOT EXISTS _cap_task_edges_del\nBEFORE DELETE ON task_edges WHEN ${NOT_APPLYING}\nBEGIN\n ${emitOp(\"edge\", \"del\", edgeKeyOld, \"'{}'\")}\nEND;\n`;\n}\n\n/** The capture trigger DDL. Built once at module load; pure string. */\nexport const CAPTURE_TRIGGER_DDL = buildTriggerDdl();\n\n/**\n * How many `total_changes()` the capture triggers themselves added while\n * stamping the ops of `groupId`. `mu sql --confirm-rows` subtracts this\n * from its delta so it can count user rows on the SAME capture-on run it\n * commits (no probe-then-rerun).\n *\n * Mirrors the trigger bodies above: every `emitOp` is exactly 3 changes\n * (the `_op_clock` UPDATE, the `machine_identity` UPDATE, the ops\n * INSERT), and every workstream/task tombstone also writes 1\n * `DYING_STASH` row. Change a trigger body and this must change too;\n * test/sql-capture.test.ts pins it with cascading deletes.\n */\nexport function captureBookkeepingChanges(db: CaptureDb, groupId: string): number {\n const row = db\n .prepare(\n `SELECT COUNT(*) AS ops,\n COALESCE(SUM(op = 'del' AND entity IN ('workstream', 'task')), 0) AS stashed\n FROM ops WHERE group_id = ?`,\n )\n .get(groupId) as { ops: number; stashed: number };\n return 3 * row.ops + row.stashed;\n}\n\n// ─── Installation ─────────────────────────────────────────────────────\n\n/**\n * Create the op-context temp tables and the capture triggers on this\n * connection. Called by `openDb` on every non-readonly open.\n *\n * Everything here is idempotent (CREATE TEMP TABLE / TRIGGER IF NOT\n * EXISTS + guarded seed INSERTs) so calling it twice is harmless.\n *\n * No transaction and no 'already exists' swallow, unlike\n * `applySchema`: the temp schema is PRIVATE to this connection, so the\n * concurrent-openDb race that forced those measures on the main schema\n * cannot occur here. Two processes opening the same file each build\n * their own temp schema without contending.\n */\nexport function installCapture(db: CaptureDb): void {\n db.exec(OP_CTX_DDL);\n db.exec(OP_CTX_SEED);\n db.exec(CAPTURE_TRIGGER_DDL);\n}\n\n/** The slice of better-sqlite3's Database that capture needs. Declared\n * structurally rather than importing `Db` from db.ts, because db.ts\n * imports THIS module — a nominal import would be a cycle, and an\n * import cycle here silently breaks `node dist/cli.js`. */\nexport interface CaptureDb {\n exec(sql: string): unknown;\n prepare(sql: string): {\n run(...params: readonly unknown[]): unknown;\n get(...params: readonly unknown[]): unknown;\n };\n}\n","// mu — TaskStatus enum + helpers.\n//\n// Single source of truth for \"what statuses and substates can a task\n// have\". The schema (db.ts) seeds the task_substates lookup table from\n// TASK_SUBSTATE_ROWS, and a composite FK from tasks (status, substate)\n// into it is the only guard on both columns. Add a status or substate\n// here only.\n//\n// Extracted from src/tasks.ts as part of refactor_split_large_src_files.\n\nexport type TaskStatus = \"OPEN\" | \"IN_PROGRESS\" | \"CLOSED\";\n\n/** Every legal task status, in canonical order (matches the seeded\n * task_substates rows). Exported so CLI surfaces (`--status` validators,\n * --help text, error messages) name them all in one place; missing\n * one used to silently lie about the supported set. */\nexport const TASK_STATUSES: readonly TaskStatus[] = [\"OPEN\", \"IN_PROGRESS\", \"CLOSED\"];\n\nexport function isTaskStatus(s: string): s is TaskStatus {\n return (TASK_STATUSES as readonly string[]).includes(s);\n}\n\n/** Pipe-separated list of every legal status, e.g.\n * 'OPEN | IN_PROGRESS | CLOSED'. Single source of truth for\n * --help text and error messages so adding a new status doesn't\n * leave stale lists rotting in the CLI surface. */\nexport const TASK_STATUS_LIST = TASK_STATUSES.join(\" | \");\n\n/** Legal substates per status. `substate` qualifies `status` and never\n * touches edge semantics: only `status === \"CLOSED\"` satisfies a\n * `blocks` edge. Open: `parked` = set aside on purpose; `triage` = a\n * proposed task (e.g. a review finding) not yet accepted as work. Both\n * stay out of `ready` and `claim`. Closed: `rejected` = the proposal\n * was declined; `wontfix` = valid, but not worth doing. */\nexport const TASK_SUBSTATES = {\n OPEN: [\"todo\", \"parked\", \"triage\"],\n IN_PROGRESS: [\"active\"],\n CLOSED: [\"done\", \"rejected\", \"wontfix\", \"duplicate\", \"superseded\"],\n} as const satisfies Record<TaskStatus, readonly string[]>;\n\nexport type TaskSubstate = (typeof TASK_SUBSTATES)[TaskStatus][number];\n\n/** The substate a status takes when none is given. Never null: an\n * absent value must not carry meaning. */\nexport const DEFAULT_SUBSTATE: {\n readonly [S in TaskStatus]: (typeof TASK_SUBSTATES)[S][number];\n} = { OPEN: \"todo\", IN_PROGRESS: \"active\", CLOSED: \"done\" };\n\nexport interface TaskPair {\n status: TaskStatus;\n substate: TaskSubstate;\n}\n\n/** Rows for seeding task_substates: [status, substate, isDefault]. */\nexport const TASK_SUBSTATE_ROWS: ReadonlyArray<readonly [TaskStatus, TaskSubstate, 0 | 1]> =\n TASK_STATUSES.flatMap((status) =>\n TASK_SUBSTATES[status].map(\n (substate) => [status, substate, substate === DEFAULT_SUBSTATE[status] ? 1 : 0] as const,\n ),\n );\n\nexport function isValidPair(status: string, substate: string): boolean {\n if (!isTaskStatus(status)) return false;\n return (TASK_SUBSTATES[status] as readonly string[]).includes(substate);\n}\n\n/** Retired v9 statuses and the pair each one now means. */\nconst LEGACY_STATUS_PAIRS: Readonly<Record<string, TaskPair>> = {\n REJECTED: { status: \"CLOSED\", substate: \"rejected\" },\n DEFERRED: { status: \"OPEN\", substate: \"parked\" },\n};\n\n/** REJECTED -> {CLOSED, rejected}; DEFERRED -> {OPEN, parked}; else null. */\nexport function mapLegacyStatus(value: string): TaskPair | null {\n const pair = LEGACY_STATUS_PAIRS[value];\n return pair ? { ...pair } : null;\n}\n\n/** Map a stored/remote pair onto a legal one. Legacy status -> mapped pair\n * (ignores substate arg). Unknown status -> null. Known status with\n * unknown/missing/mismatched substate -> {status, DEFAULT_SUBSTATE[status]}. */\nexport function resolvePair(status: string, substate: unknown): TaskPair | null {\n const legacy = mapLegacyStatus(status);\n if (legacy) return legacy;\n if (!isTaskStatus(status)) return null;\n if (typeof substate === \"string\" && isValidPair(status, substate)) {\n return { status, substate: substate as TaskSubstate };\n }\n return { status, substate: DEFAULT_SUBSTATE[status] };\n}\n\n/** OPEN substates that keep a task out of `ready`, `next` and `claim`. */\nexport const UNSCHEDULED_SUBSTATES: readonly TaskSubstate[] = [\"parked\", \"triage\"];\n\nexport function isUnscheduled(pair: { status: string; substate: string }): boolean {\n return (\n pair.status === \"OPEN\" && (UNSCHEDULED_SUBSTATES as readonly string[]).includes(pair.substate)\n );\n}\n\n/** \"OPEN\" for default pairs, \"OPEN/parked\" otherwise. Shared by CLI + TUI. */\nexport function formatPair(pair: TaskPair): string {\n return pair.substate === DEFAULT_SUBSTATE[pair.status]\n ? pair.status\n : `${pair.status}/${pair.substate}`;\n}\n","// mu — DB module.\n//\n// Opens <state-dir>/mu.db (or the MU_DB_PATH override; see defaultDbPath),\n// enables WAL + foreign keys, applies the schema idempotently, and\n// exposes the live Database handle.\n//\n// Schema (v11 — task substates on the v10 three-state lifecycle):\n// - 6 entity tables: workstreams, agents, tasks, task_edges,\n// task_notes, vcs_workspaces\n// - 1 ops log: ops (the single append-only record of\n// every change — VISION.md § 2b)\n// - 2 sync tables: sync_peers (per-peer watermarks),\n// sync_fingerprints (caught-up fingerprints)\n// - 2 meta tables: schema_version, machine_identity\n// - 1 lookup table: task_substates (legal (status, substate) pairs,\n// seeded from code when missing)\n// - 3 views: ready, blocked, goals\n// => EXPECTED_TABLES is exactly 12 entries.\n//\n// v11 adds tasks.substate, which qualifies status (OPEN/parked,\n// CLOSED/wontfix, ...). A composite FK (status, substate) ->\n// task_substates, DEFERRABLE INITIALLY DEFERRED, is the only guard on\n// the pair: it is checked at COMMIT, so apply's one-field-at-a-time\n// UPDATEs pass as long as the pair is valid when the transaction ends.\n//\n// v9 is a BREAKING, migration-free redesign. It DROPS v8's four\n// separate change-recording mechanisms — `agent_logs`, `snapshots`,\n// `workstream_sync`, and the five `archived_*` tables — and replaces\n// all of them with one **ops log**. Sync, undo, and history\n// are queries or replays over that log (docs/VOCABULARY.md § op,\n// ops log, watermark).\n//\n// The surrogate-INTEGER-PK discipline introduced in v5 is unchanged:\n// per docs/architecture/sdk.md § Surrogate-PK and SDK-boundary discipline,\n// every entity table has an INTEGER PK; FKs reference INTEGER ids;\n// the operator-facing TEXT name is per-scope unique via\n// UNIQUE (<scope_id>, <name>). `ops` is the deliberate exception: it\n// holds the NATURAL key (`ws/local_id`) in `ops.key`, never a\n// surrogate id, which is exactly why keys don't collide across\n// machines.\n//\n// IMPORTANT: MIN_ACCEPTED_SCHEMA_VERSION === CURRENT_SCHEMA_VERSION\n// === 11. There is no in-place forward-bump ladder: every pre-v11 DB\n// is rejected at openDb time with SchemaTooOldError (exit 4), and a DB\n// newer than this build with SchemaTooNewError (exit 4). Migration\n// lives only in scripts/migrate.ts.\n\nimport { randomUUID } from \"node:crypto\";\nimport { mkdirSync } from \"node:fs\";\nimport { homedir, hostname } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport Database, { type Database as DatabaseType, type Statement } from \"better-sqlite3\";\nimport { installCapture } from \"./capture.js\";\nimport type { HasNextSteps, NextStep } from \"./output.js\";\nimport { defaultStateDir, xdgStateHome } from \"./state-dir.js\";\nimport { TASK_SUBSTATE_ROWS } from \"./tasks/status.js\";\n\nexport { defaultStateDir };\n\nexport type Db = DatabaseType;\n\nconst statementCache = new WeakMap<Db, Map<string, Statement>>();\n\n/**\n * `db.prepare(sql)`, compiled once per connection and reused.\n *\n * better-sqlite3 has no statement cache, so a hot loop that calls\n * `db.prepare` per row pays SQL compilation every time. Ingest applies\n * thousands of ops and prepared ~10 statements per op, which made SQL\n * compilation most of a large catch-up's cost. Use this on per-op paths;\n * one-off queries keep plain `db.prepare`. `sql` must come from a fixed\n * template (the cache never evicts). Not for a statement a caller\n * `.iterate()`s while re-entering the same SQL: a busy statement throws.\n */\nexport function prepareCached(db: Db, sql: string): Statement {\n let byDb = statementCache.get(db);\n if (byDb === undefined) {\n byDb = new Map();\n statementCache.set(db, byDb);\n }\n let stmt = byDb.get(sql);\n if (stmt === undefined) {\n stmt = db.prepare(sql);\n byDb.set(sql, stmt);\n }\n return stmt;\n}\n\nexport interface OpenDbOptions {\n /**\n * Absolute path to the SQLite file. Defaults to MU_DB_PATH env var or\n * the XDG state path (see `defaultDbPath`). Use a per-test temp path\n * in tests.\n */\n path?: string;\n\n /**\n * If true, opens the DB read-only. Used by `mu sql` and similar read-only\n * surfaces to enforce no-mutation guarantees at the connection level.\n */\n readonly?: boolean;\n}\n\n/**\n * Resolve the canonical DB path:\n * MU_DB_PATH > <state-dir>/mu.db\n */\nexport function defaultDbPath(): string {\n if (process.env.MU_DB_PATH) return process.env.MU_DB_PATH;\n return join(defaultStateDir(), \"mu.db\");\n}\n\n/**\n * Open the mu database. Creates the parent directory and applies the schema\n * idempotently when it is missing or differs from this build (an\n * up-to-date DB opens without a write). Safe to call from many short-lived processes\n * concurrently — WAL mode handles cross-process writes.\n */\nexport function openDb(options: OpenDbOptions = {}): Db {\n const path = options.path ?? defaultDbPath();\n refuseUserDbDuringTests(path);\n mkdirSync(dirname(path), { recursive: true });\n\n const db = new Database(path, { readonly: options.readonly ?? false });\n\n if (!options.readonly) {\n // Wait up to 5s for a competing writer's lock instead of throwing\n // SQLITE_BUSY immediately. Every `mu` invocation is a separate\n // short-lived process and a parallel fan-out (`for n in …; do mu\n // agent spawn … & done`) opens the same DB from N processes at\n // once — without this, the losers of a write-lock race die with\n // 'database is locked' and roll back their agent. WAL handles\n // concurrent readers; busy_timeout handles concurrent writers.\n // busy_timeout only covers a lock taken at BEGIN, so every write\n // transaction runs as `db.transaction(fn).immediate()` (or `BEGIN\n // IMMEDIATE`). A deferred one that reads first and then writes gets\n // SQLITE_BUSY_SNAPSHOT at once if another process committed in\n // between, and busy_timeout does not retry that.\n db.pragma(\"busy_timeout = 5000\");\n // Detect schema version BEFORE applySchema so a real v<11 DB is not\n // silently stamped as v11 by the CREATE-IF-NOT-EXISTS in applySchema,\n // and before `journal_mode = WAL`, which rewrites the file header:\n // a refused DB must be left byte-for-byte untouched.\n // One read transaction: a process creating this DB can commit\n // between two bare reads, and \"no schema_version table, then a\n // workstreams table\" read as a pre-versioning v1 DB.\n const detectedVersion = db.transaction(() => detectExistingSchemaVersion(db))();\n if (detectedVersion !== null && detectedVersion > CURRENT_SCHEMA_VERSION) {\n // A newer mu wrote this DB. Its writes would fail here in\n // confusing ways (unknown columns, constraints this build does not\n // know), so refuse before applySchema touches anything.\n try {\n db.close();\n } catch {\n // best effort\n }\n throw new SchemaTooNewError(detectedVersion, CURRENT_SCHEMA_VERSION);\n }\n if (detectedVersion !== null && detectedVersion < MIN_ACCEPTED_SCHEMA_VERSION) {\n // Loud-fail: refuse to touch a pre-v11 DB. There is no in-place\n // migration to run, so leave the old file untouched and tell the\n // operator how to preserve it (see SchemaTooOldError.errorNextSteps).\n try {\n db.close();\n } catch {\n // best effort\n }\n throw new SchemaTooOldError(detectedVersion, MIN_ACCEPTED_SCHEMA_VERSION);\n }\n setWalMode(db);\n db.pragma(\"foreign_keys = ON\");\n // Skip the DDL write transaction when the DB already matches this\n // build. applySchema takes the write lock and rewrites the views,\n // which bumps the schema cookie on every open: every `mu` call,\n // reads included, queued behind any writer and forced every other\n // connection to re-parse the schema (f_opendb_schema_write).\n if (detectedVersion !== CURRENT_SCHEMA_VERSION || !schemaIsCurrent(db)) applySchema(db);\n seedMachineIdentity(db);\n // Install the op-capture triggers + the _op_ctx temp tables they\n // read. Per-connection, because SQLite forbids a main-schema\n // trigger from referencing the temp schema, so the triggers must\n // themselves be TEMP triggers (see src/capture.ts for the full\n // reasoning and the exact error messages). Must run AFTER\n // seedMachineIdentity: the triggers mint HLCs from that row.\n installCapture(db);\n } else {\n db.pragma(\"foreign_keys = ON\");\n }\n\n return db;\n}\n\n/**\n * Hard guard (Layer \"db\" of bug_test_flake_round_2): refuse to open\n * the user's REAL default mu.db when running under vitest. Tests\n * MUST point at a per-test temp DB (via MU_DB_PATH or the explicit\n * `{ path }` option). A test that forgets to override either one\n * silently mutated the dev box's live state — we observed a stray\n * 'demo' workstream row replicated from test/tui-acceptance.integration.test.ts\n * into ~/.local/state/mu/mu.db. The guard throws a useful diagnostic\n * the moment the offending openDb() call is made; the failing test's\n * stack trace then names the leak source directly.\n *\n * Test mode = `process.env.VITEST` is defined OR `NODE_ENV === \"test\"`.\n * vitest sets VITEST=\"true\" in every fork; the NODE_ENV branch is for\n * other runners that may invoke openDb during tests.\n *\n * The user's REAL DB path is computed from HOME / XDG_STATE_HOME\n * directly (NOT from defaultDbPath() — which would honour MU_DB_PATH\n * and produce the temp path the test set, defeating the check).\n * MU_STATE_DIR is deliberately not consulted: test/_setup.ts deletes\n * the user's MU_* vars in every fork, so any MU_STATE_DIR seen here was\n * set by a test to a temp dir (test/disk-recon.test.ts opens\n * <MU_STATE_DIR>/mu.db), and guarding it would refuse that temp DB.\n * Production code paths (the `mu` CLI binary) never set VITEST, so\n * the guard is a complete no-op outside the test runner.\n */\nfunction refuseUserDbDuringTests(path: string): void {\n const inTest = process.env.VITEST !== undefined || process.env.NODE_ENV === \"test\";\n if (!inTest) return;\n const home = process.env.HOME ?? homedir();\n const realDb = resolve(join(xdgStateHome(home), \"mu\", \"mu.db\"));\n if (resolve(path) === realDb) {\n throw new Error(\n `openDb refused: tests must NEVER write to the user DB (${realDb}). Set MU_DB_PATH to a per-test temp path (test/_runCli.ts does this automatically) or pass an explicit { path } argument. The leak source is the call site of openDb in this stack frame.`,\n );\n }\n}\n\n// ─── Resolve helpers (operator-facing name -> surrogate id) ───────────\n//\n// docs/architecture/sdk.md § Surrogate-PK and SDK-boundary discipline:\n//\n// PUBLIC SDK functions take operator-facing names (workstream + local\n// id + agent name). Internal helpers take surrogate ids. Resolution\n// happens at the public-function entry, exactly once.\n//\n// `resolveWorkstreamId` is the only resolve helper that throws a typed\n// error from this leaf module — `WorkstreamNotFoundError` is defined\n// here, so there is no cycle. The task / agent resolvers RETURN\n// `number | null` (`tryResolveTaskId` / `tryResolveAgentId`) and let\n// SDK callers in `src/tasks/*.ts` / `src/agents.ts` throw the typed\n// `TaskNotFoundError` / `AgentNotFoundError` they own. That keeps\n// `cli/handle.ts`'s `instanceof`-based exit-code map (3 = not-found)\n// honest: a leaf throwing a plain `Error` whose `.name` was monkey-\n// patched to `\"TaskNotFoundError\"` flunks `instanceof TaskNotFoundError`\n// and falls through to the generic exit 1\n// (review_substrate_resolve_id_anonymous_errors).\n\nexport class WorkstreamNotFoundError extends Error implements HasNextSteps {\n override readonly name = \"WorkstreamNotFoundError\";\n constructor(public readonly workstream: string) {\n super(`no such workstream: ${workstream}`);\n }\n errorNextSteps(): NextStep[] {\n return [\n { intent: \"List workstreams\", command: \"mu workstream list\" },\n {\n intent: \"Initialise this workstream\",\n command: `mu workstream init ${this.workstream}`,\n },\n ];\n }\n}\n\n/** Resolve a workstream name to its INTEGER surrogate id. Throws\n * WorkstreamNotFoundError on miss. Pure: no auto-create — callers\n * that want the auto-create-or-resolve semantics use\n * `ensureWorkstream` from src/workstream.ts (which returns void;\n * follow up with `resolveWorkstreamId` if the id is needed).\n */\nexport function resolveWorkstreamId(db: Db, workstream: string): number {\n const row = db.prepare(\"SELECT id FROM workstreams WHERE name = ?\").get(workstream) as\n | { id: number }\n | undefined;\n if (!row) throw new WorkstreamNotFoundError(workstream);\n return row.id;\n}\n\n/** Resolve a workstream name to its id, returning null on miss instead\n * of throwing. Useful for read paths that want to early-return [] on\n * a non-existent workstream (e.g. listTasks). */\nexport function tryResolveWorkstreamId(db: Db, workstream: string): number | null {\n const row = db.prepare(\"SELECT id FROM workstreams WHERE name = ?\").get(workstream) as\n | { id: number }\n | undefined;\n return row ? row.id : null;\n}\n\n/** Resolve a (workstream_id, local_id) pair to the task's surrogate\n * id, returning `null` on miss. SDK callers in `src/tasks/*.ts`\n * wrap the null return in `TaskNotFoundError` so the CLI's typed-\n * error → exit-code map (3 = not-found) fires. The leaf intentionally\n * does NOT throw a typed error (it would either pull in a cyclic\n * import or — as before — fake the `.name` and silently flunk\n * `instanceof TaskNotFoundError`, falling through to exit 1).\n * Renamed from `resolveTaskId` in\n * review_substrate_resolve_id_anonymous_errors. */\nexport function tryResolveTaskId(db: Db, workstreamId: number, localId: string): number | null {\n const row = db\n .prepare(\"SELECT id FROM tasks WHERE workstream_id = ? AND local_id = ?\")\n .get(workstreamId, localId) as { id: number } | undefined;\n return row ? row.id : null;\n}\n\n/** Resolve a (workstream_id, agent_name) pair to the agent's surrogate\n * id, returning `null` on miss. SDK callers in `src/agents.ts` wrap\n * the null return in `AgentNotFoundError` so the CLI's typed-error →\n * exit-code map (3 = not-found) fires. See `tryResolveTaskId` for the\n * full rationale (review_substrate_resolve_id_anonymous_errors). */\nexport function tryResolveAgentId(db: Db, workstreamId: number, name: string): number | null {\n const row = db\n .prepare(\"SELECT id FROM agents WHERE workstream_id = ? AND name = ?\")\n .get(workstreamId, name) as { id: number } | undefined;\n return row ? row.id : null;\n}\n\n/**\n * Thrown by openDb when the on-disk DB is older than the current\n * schema. There is no in-place migration ladder; the old DB is left\n * untouched. Maps to exit code 4 (conflict) in cli.ts handle().\n */\nexport class SchemaTooOldError extends Error implements HasNextSteps {\n override readonly name = \"SchemaTooOldError\";\n constructor(\n public readonly detectedVersion: number,\n public readonly requiredVersion: number,\n ) {\n super(\n `Detected v${detectedVersion} schema; v${requiredVersion} is required. mu ships NO in-place migration — your v${detectedVersion} DB is untouched. Back it up or move it aside, then start a fresh v${requiredVersion} DB.`,\n );\n }\n errorNextSteps(): NextStep[] {\n return [\n {\n intent: \"Keep a copy of the old DB before anything else\",\n command: `mu db backup \"$HOME/mu-v${this.detectedVersion}-backup.db\"`,\n },\n {\n intent: \"Move the old DB aside without deleting it\",\n command: `mv \"\\${MU_DB_PATH:-$HOME/.local/state/mu/mu.db}\" \"\\${MU_DB_PATH:-$HOME/.local/state/mu/mu.db}.old\"`,\n },\n {\n intent: `Migrate the old DB into a fresh v${this.requiredVersion} DB (run in a mu git checkout: the npm package does not ship scripts/)`,\n command: `npx tsx scripts/migrate.ts \"\\${MU_DB_PATH:-$HOME/.local/state/mu/mu.db}.old\" --out /tmp/mu-v${this.requiredVersion}.db`,\n },\n {\n intent: \"Verify the fresh DB before swapping\",\n command: `MU_DB_PATH=/tmp/mu-v${this.requiredVersion}.db mu doctor --deep`,\n },\n ];\n }\n}\n\n/**\n * Thrown by openDb when the on-disk DB was written by a NEWER mu.\n * The DB is left untouched. Maps to exit code 4 (conflict).\n */\nexport class SchemaTooNewError extends Error implements HasNextSteps {\n override readonly name = \"SchemaTooNewError\";\n constructor(\n public readonly detectedVersion: number,\n public readonly supportedVersion: number,\n ) {\n super(`DB is v${detectedVersion}; this mu understands up to v${supportedVersion}. Upgrade mu.`);\n }\n errorNextSteps(): NextStep[] {\n return [{ intent: \"Check which mu is on PATH\", command: \"which mu && mu --version\" }];\n }\n}\n\n/** How long openDb retries the switch to WAL while another process holds the lock. */\nconst WAL_SWITCH_RETRY_MS = 5000;\n\n/**\n * `journal_mode = WAL`, retried on SQLITE_BUSY. On a fresh file the\n * switch needs an exclusive lock, and SQLite can return SQLITE_BUSY\n * for it without calling the busy handler, so busy_timeout does not\n * cover it: N processes opening a new DB at once lost one with\n * \"database is locked\". Once the file is WAL the switch is a no-op.\n */\nfunction setWalMode(db: Db): void {\n const deadline = Date.now() + WAL_SWITCH_RETRY_MS;\n const pause = new Int32Array(new SharedArrayBuffer(4));\n for (;;) {\n try {\n db.pragma(\"journal_mode = WAL\");\n return;\n } catch (err) {\n const code = (err as { code?: unknown }).code;\n const busy = typeof code === \"string\" && code.startsWith(\"SQLITE_BUSY\");\n if (!busy || Date.now() >= deadline) throw err;\n Atomics.wait(pause, 0, 0, 10 + Math.floor(Math.random() * 20));\n }\n }\n}\n\n/**\n * Sniff an existing DB's schema version BEFORE applySchema runs, so we\n * can distinguish:\n * - Brand-new DB: no tables at all -> returns null (fresh, will be\n * stamped to CURRENT_SCHEMA_VERSION by applySchema).\n * - Pre-versioning DB (had the original tables before schema_version existed):\n * workstreams exists, schema_version doesn't -> returns 1.\n * - Already-versioned DB: schema_version row present -> returns its\n * value.\n */\nfunction detectExistingSchemaVersion(db: Db): number | null {\n const hasVersionTable = db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='schema_version'\")\n .get() as { name: string } | undefined;\n if (hasVersionTable) {\n const row = db.prepare(\"SELECT version FROM schema_version WHERE id = 1\").get() as\n | { version: number }\n | undefined;\n return row?.version ?? null;\n }\n // No schema_version table. Check whether any of the original\n // tables exist; if so this is a pre-versioning DB.\n const hasWorkstreams = db\n .prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='workstreams'\")\n .get() as { name: string } | undefined;\n if (hasWorkstreams) return 1;\n return null;\n}\n\n/** Seed the singleton machine_identity row (id=1) on first open.\n * No-op once a row exists. The machine_id it writes is the identity\n * every op is stamped with (`ops.machine_id`) and the name of this\n * machine's segment. */\nfunction seedMachineIdentity(db: Db): void {\n const row = db.prepare(\"SELECT COUNT(*) AS count FROM machine_identity\").get() as {\n count: number;\n };\n if (row.count !== 0) return;\n db.prepare(\n `INSERT OR IGNORE INTO machine_identity (id, machine_id, hostname, created_at)\n VALUES (1, ?, ?, ?)`,\n ).run(randomUUID(), hostname(), new Date().toISOString());\n}\n\n/**\n * Apply the schema. Idempotent: tables use CREATE TABLE IF NOT EXISTS;\n * views are dropped and recreated so the latest definition always wins.\n *\n * For fresh DBs this writes the current schema shape and stamps\n * schema_version = CURRENT_SCHEMA_VERSION. For existing v11 DBs this is\n * a no-op for the table CREATEs (IF NOT EXISTS) but DOES recreate the\n * views. Pre-v11 DBs never reach this function — openDb's loud-fail\n * hook rejects them with SchemaTooOldError first.\n *\n * There is no in-place bump ladder. MIN_ACCEPTED === CURRENT, so the\n * only two shapes that reach here are \"brand new\" and \"already v11\";\n * any older-DB fix-up code would be dead by construction.\n */\nfunction applySchema(db: Db): void {\n // Apply the schema DDL atomically. CURRENT_SCHEMA includes\n // `DROP VIEW IF EXISTS goals; CREATE VIEW goals …` (views can't be\n // CREATE-IF-NOT-EXISTS + redefined in one step), so without a\n // transaction two processes opening the same fresh DB concurrently\n // can interleave one's DROP between the other's DROP and CREATE and\n // hit 'view goals already exists'. An IMMEDIATE transaction takes the\n // write lock up front (paired with busy_timeout in openDb) so the\n // whole DDL block is all-or-nothing per process.\n // bug_parallel_spawn_races_drop_agents (schema leg).\n db.exec(\"BEGIN IMMEDIATE\");\n try {\n db.exec(CURRENT_SCHEMA);\n // Seed the legal (status, substate) pairs from code. INSERT OR\n // IGNORE keeps it idempotent; the table is machine-local and never\n // synced, so every machine derives it from the same constant.\n const seed = db.prepare(\n \"INSERT OR IGNORE INTO task_substates (status, substate, is_default) VALUES (?, ?, ?)\",\n );\n for (const [status, substate, isDefault] of TASK_SUBSTATE_ROWS) {\n seed.run(status, substate, isDefault);\n }\n db.exec(\"COMMIT\");\n } catch (err) {\n db.exec(\"ROLLBACK\");\n // A concurrent process already applied the (idempotent) schema —\n // the views/tables now exist. Re-throwing would fail the spawn for\n // a benign race, so swallow the 'already exists' class and proceed;\n // any other error is a real problem and rethrows.\n const msg = err instanceof Error ? err.message : String(err);\n if (!/already exists/i.test(msg)) throw err;\n }\n // Stamp the version on a fresh DB. INSERT OR IGNORE so we don't\n // overwrite the version on an existing v11 DB.\n db.prepare(\"INSERT OR IGNORE INTO schema_version (id, version) VALUES (1, ?)\").run(\n CURRENT_SCHEMA_VERSION,\n );\n}\n\n/** Names CURRENT_SCHEMA creates with IF NOT EXISTS, and the exact SQL\n * SQLite stores for each view (the CREATE statement minus its `;`). */\ninterface ExpectedObjects {\n tables: string[];\n indexes: string[];\n views: Map<string, string>;\n}\nlet expectedCache: ExpectedObjects | undefined;\nfunction expectedObjects(): ExpectedObjects {\n if (expectedCache !== undefined) return expectedCache;\n const names = (re: RegExp): string[] =>\n [...CURRENT_SCHEMA.matchAll(re)].map((m) => m[1]).filter((n) => n !== undefined);\n const views = new Map<string, string>();\n for (const sql of [READY_VIEW_SQL, BLOCKED_VIEW_SQL, GOALS_VIEW_SQL]) {\n const m = /CREATE VIEW (\\w+)[^;]*/.exec(sql);\n if (m?.[1] !== undefined) views.set(m[1], m[0]);\n }\n expectedCache = {\n tables: names(/CREATE TABLE IF NOT EXISTS (\\w+)/g),\n indexes: names(/CREATE (?:UNIQUE )?INDEX IF NOT EXISTS (\\w+)/g),\n views,\n };\n return expectedCache;\n}\n\n/** True when applySchema would change nothing: every table, index and\n * seeded substate row exists, and every view's stored SQL equals this\n * build's definition. Reads only, so openDb on an up-to-date DB takes\n * no write lock and leaves PRAGMA schema_version alone. */\nfunction schemaIsCurrent(db: Db): boolean {\n const rows = db.prepare(\"SELECT type, name, sql FROM sqlite_master\").all() as {\n type: string;\n name: string;\n sql: string | null;\n }[];\n const have = new Map(rows.map((r) => [`${r.type}:${r.name}`, r.sql]));\n const expected = expectedObjects();\n if (expected.tables.some((t) => !have.has(`table:${t}`))) return false;\n if (expected.indexes.some((i) => !have.has(`index:${i}`))) return false;\n for (const [name, sql] of expected.views) {\n if (have.get(`view:${name}`) !== sql) return false;\n }\n const pairs = new Set(\n (\n db.prepare(\"SELECT status, substate FROM task_substates\").all() as {\n status: string;\n substate: string;\n }[]\n ).map((r) => `${r.status}/${r.substate}`),\n );\n return TASK_SUBSTATE_ROWS.every(([status, substate]) => pairs.has(`${status}/${substate}`));\n}\n\n/** The schema version a fresh DB starts at. v11 adds tasks.substate\n * and the task_substates lookup table on top of v10's three-state\n * lifecycle (OPEN, IN_PROGRESS, CLOSED). See CHANGELOG.md. */\nexport const CURRENT_SCHEMA_VERSION = 11;\n\n/** The lowest schema version `openDb` will accept. Equal to\n * CURRENT_SCHEMA_VERSION: openDb runs no migration, so every pre-v11 DB\n * throws `SchemaTooOldError` (exit 4) and is left untouched on disk. */\nconst MIN_ACCEPTED_SCHEMA_VERSION = 11;\n\n/** Tables a healthy DB must contain. Single source of truth so\n * `mu doctor` and any other consumer don't drift. Adding a new table\n * = one new entry here AND a CREATE TABLE in CURRENT_SCHEMA, plus a\n * CURRENT_SCHEMA_VERSION bump (sync_fingerprints went in without one:\n * additive, and an older mu ignores it). Sorted; exactly 12 entries. */\nexport const EXPECTED_TABLES: readonly string[] = [\n \"agents\",\n \"machine_identity\",\n \"ops\",\n \"schema_version\",\n \"sync_fingerprints\",\n \"sync_peers\",\n \"task_edges\",\n \"task_notes\",\n \"task_substates\",\n \"tasks\",\n \"vcs_workspaces\",\n \"workstreams\",\n];\n\n// ─── Syncability — which state crosses machines ───────────────────────\n//\n// Whether an op syncs is a STATIC function of its entity, so it lives\n// here as a constant rather than as a `local` column on `ops`. A\n// per-row decision is a per-row opportunity to get it wrong, and it\n// would cost a column plus a branch at every write site. Downstream\n// sync code READS these; it does not re-decide.\n//\n// Vocabulary (docs/VOCABULARY.md § portable): **portable** tables are\n// syncable across machines; **machine-local** tables never leave the\n// box. Machine-local ops are still RECORDED — `mu log` and the TUI\n// Recent card still show agent spawn/close — they simply never ship.\n// \"Not synced\" is not \"not logged\".\n\n/** Op entities that cross machines. Everything else is machine-local.\n * Readonly tuple (not `string[]`) so `SyncedEntity` is a real union\n * and downstream code gets compile-time checking, not raw strings. */\nexport const SYNCED_ENTITIES = [\"workstream\", \"task\", \"edge\", \"note\", \"message\"] as const;\n\n/** One of the op entities that sync. Derived from the tuple, so\n * adding an entity is a one-line change with no type to keep in step. */\nexport type SyncedEntity = (typeof SYNCED_ENTITIES)[number];\n\n/** Op entities this build KNOWS are machine-local: their payloads name\n * a pane id or an absolute path, so a peer sending one is a real bug\n * and `applyOp` rejects it loudly.\n *\n * WHY THIS LIST EXISTS SEPARATELY FROM \"not in SYNCED_ENTITIES\"\n * ------------------------------------------------------------\n * \"Unknown\" and \"known-local\" are different failures and were\n * conflated, which wedged a real fleet. A peer running a LATER (or\n * earlier) mu wrote `entity:\"marker\"` ops — legal on the writer, whose\n * SYNCED_ENTITIES included it. The reader treated every non-synced\n * entity as a bad peer, so `ingestSegment` recorded a defect and\n * stopped at that line FOREVER: 87% of a 20,305-line segment never\n * applied, and `mu sync --repair` (which only resets the watermark)\n * marched straight back into the same wall.\n *\n * So the rule is asymmetric on purpose: an entity we know must never\n * travel is a defect; an entity we simply do not recognise is tolerated\n * forward-compatibly — recorded in `ops`, projected nowhere, exactly\n * like 'message'. Reader vocabulary may lag writer vocabulary; that is\n * a fact of a mixed fleet, not a corruption. */\nexport const MACHINE_LOCAL_ENTITIES = [\"agent\", \"workspace\", \"event\", \"broadcast\"] as const;\n\nexport type MachineLocalEntity = (typeof MACHINE_LOCAL_ENTITIES)[number];\n\n/** **Portable** tables: their rows mean the same thing on any machine,\n * so their ops ship. Mirrors docs/VOCABULARY.md § portable exactly. */\nexport const PORTABLE_TABLES = [\"task_edges\", \"task_notes\", \"tasks\", \"workstreams\"] as const;\n\nexport type PortableTable = (typeof PORTABLE_TABLES)[number];\n\n/** **Machine-local** tables. Never bulk-copied to a peer, because a\n * row's meaning does not survive the trip:\n *\n * agents holds `pane_id` ('%17') — meaningless elsewhere.\n * vcs_workspaces holds absolute paths — /home/... vs /Users/...\n * on a mixed macOS/Linux fleet.\n * machine_identity IS the per-machine identity.\n * schema_version local bookkeeping.\n * sync_peers local bookkeeping (per-peer watermarks).\n * sync_fingerprints local cache of what the last clean ingest saw.\n * task_substates seeded identically on every machine from\n * TASK_SUBSTATE_ROWS; code, not data.\n * ops see below — the carrier, not cargo.\n *\n * `ops` is listed here deliberately rather than omitted. It is not\n * **portable** in the copy-the-table sense: the table is never\n * wholesale-copied. Individual op ROWS ship, one at a time, filtered\n * by SYNCED_ENTITIES and carried by per-machine **segments** — and\n * `seq` is a local-only append cursor that means nothing on a peer.\n * So for the only question this list answers — \"is this table's\n * content copied across machines?\" — the answer for `ops` is no.\n *\n * Consequence that falls out with no special case: `tasks.owner_id`\n * is an FK into `agents`, and `agents` is machine-local. Therefore\n * OWNERSHIP DOES NOT SYNC. The deleted db-sync.ts reached the same\n * conclusion via an `includeOwners` flag; here it is structural. */\nexport const MACHINE_LOCAL_TABLES = [\n \"agents\",\n \"machine_identity\",\n \"ops\",\n \"schema_version\",\n \"sync_fingerprints\",\n \"sync_peers\",\n \"task_substates\",\n \"vcs_workspaces\",\n] as const;\n\nexport type MachineLocalTable = (typeof MACHINE_LOCAL_TABLES)[number];\n\n// ─── View DDL — single source of truth ────────────────────────────────\n//\n// The three views (ready, blocked, goals) get DROPped + CREATEd by\n// applySchema whenever openDb finds them missing or different from\n// these definitions (schemaIsCurrent). Each constant is self-contained:\n// DROP IF EXISTS + CREATE. Running DROP twice in a row is harmless,\n// so callers that already DROP up-front can still re-execute these\n// without churn.\n//\n// Exported as named constants so consumers can reference the canonical\n// shape (e.g. one-shot migration scripts under scripts/) without\n// duplicating SQL.\n\nexport const READY_VIEW_SQL = `\nDROP VIEW IF EXISTS ready;\nCREATE VIEW ready AS\n SELECT t.*\n FROM tasks t\n WHERE t.status = 'OPEN'\n AND t.substate NOT IN ('parked', 'triage')\n AND NOT EXISTS (\n SELECT 1\n FROM task_edges e\n JOIN tasks b ON e.from_task_id = b.id\n WHERE e.to_task_id = t.id\n AND b.status <> 'CLOSED'\n );\n`;\n\nexport const BLOCKED_VIEW_SQL = `\nDROP VIEW IF EXISTS blocked;\nCREATE VIEW blocked AS\n SELECT t.*\n FROM tasks t\n WHERE t.status = 'OPEN'\n AND EXISTS (\n SELECT 1\n FROM task_edges e\n JOIN tasks b ON e.from_task_id = b.id\n WHERE e.to_task_id = t.id\n AND b.status <> 'CLOSED'\n );\n`;\n\n// A goal is an active endpoint of the DAG — a task with no dependents\n// that we're still working toward. CLOSED is excluded: a finished\n// leaf is not an active goal. Parked tasks STAY goals: tracks are\n// built from goals, and a parked track is still a track.\nexport const GOALS_VIEW_SQL = `\nDROP VIEW IF EXISTS goals;\nCREATE VIEW goals AS\n SELECT t.*\n FROM tasks t\n WHERE t.status <> 'CLOSED'\n AND NOT EXISTS (\n SELECT 1 FROM task_edges WHERE from_task_id = t.id\n );\n`;\n\n// ─── v11 SCHEMA ───────────────────────────────────────────────────────\n//\n// Per docs/architecture/sdk.md § Surrogate-PK and SDK-boundary discipline.\n// Every entity table has:\n// - INTEGER PRIMARY KEY AUTOINCREMENT (surrogate identity)\n// - <scope>_id INTEGER NOT NULL REFERENCES <parent>(id) ON DELETE CASCADE\n// - <name> TEXT NOT NULL (operator-facing, mutable)\n// - UNIQUE (<scope>_id, <name>)\n//\n// Foreign keys are INTEGER. Renames become single-row UPDATEs (no\n// cascade chain). The TEXT name is just an attribute. `ops` is the\n// documented exception: it has NO foreign keys at all and addresses\n// rows by their NATURAL key, because ops outlive the rows (and the\n// workstreams) they record.\n\nconst CURRENT_SCHEMA = `\n-- ─── Schema versioning ────────────────────────────────────────────────\n--\n-- Single-row table tracking which schema version this DB is at. Migrations\n-- read and update this; the row is INSERT-OR-IGNOREd by applySchema with\n-- the current version on a fresh DB.\nCREATE TABLE IF NOT EXISTS schema_version (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n version INTEGER NOT NULL\n);\n\n-- machine_identity: one durable identity per DB/machine, seeded by\n-- openDb after schema creation. hostname is advisory only.\n--\n-- last_wall / last_counter are the persisted hybrid logical clock\n-- (src/hlc.ts, VOCABULARY § HLC). They live here because every mu\n-- invocation is a fresh process — an in-memory counter would reset\n-- constantly and mint duplicate HLCs, which UNIQUE (machine_id, hlc)\n-- on the ops table would then reject.\nCREATE TABLE IF NOT EXISTS machine_identity (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n machine_id TEXT NOT NULL,\n hostname TEXT,\n created_at TEXT NOT NULL,\n last_wall INTEGER NOT NULL DEFAULT 0,\n last_counter INTEGER NOT NULL DEFAULT 0\n);\n\n-- ─── Tables ───────────────────────────────────────────────────────────\n\n-- workstreams: top of the hierarchy. name stays globally unique\n-- because it IS a tmux session name; no <scope_id> column because\n-- there's no parent.\nCREATE TABLE IF NOT EXISTS workstreams (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT UNIQUE NOT NULL,\n created_at TEXT NOT NULL -- ISO 8601\n);\n\n\n-- agents: one row per managed pane. Per-workstream unique on name.\nCREATE TABLE IF NOT EXISTS agents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n workstream_id INTEGER NOT NULL REFERENCES workstreams (id) ON DELETE CASCADE,\n name TEXT NOT NULL, -- per-workstream unique\n cli TEXT NOT NULL DEFAULT 'pi',\n pane_id TEXT NOT NULL,\n status TEXT NOT NULL, -- DEPRECATED (2.0): always 'spawning'; runtime state lives in murmur. Drop at the first v11 migration.\n role TEXT NOT NULL DEFAULT 'full-access',\n tab TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE (workstream_id, name),\n CHECK (status IN (\n 'spawning', 'busy', 'needs_input', 'needs_permission',\n 'free', 'unreachable', 'terminated'\n )),\n CHECK (role IN ('full-access', 'read-only'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_agents_workstream ON agents (workstream_id);\nCREATE INDEX IF NOT EXISTS idx_agents_status ON agents (status);\n\n-- task_substates: the legal (status, substate) pairs. Seeded from\n-- TASK_SUBSTATE_ROWS (src/tasks/status.ts) by applySchema; exactly one\n-- default per status.\nCREATE TABLE IF NOT EXISTS task_substates (\n status TEXT NOT NULL,\n substate TEXT NOT NULL,\n is_default INTEGER NOT NULL DEFAULT 0 CHECK (is_default IN (0, 1)),\n PRIMARY KEY (status, substate)\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS idx_task_substates_one_default\n ON task_substates (status) WHERE is_default = 1;\n\n-- tasks: per-workstream unique on local_id (TRULY local now —\n-- different workstreams may reuse the same local_id).\nCREATE TABLE IF NOT EXISTS tasks (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n workstream_id INTEGER NOT NULL REFERENCES workstreams (id) ON DELETE CASCADE,\n local_id TEXT NOT NULL, -- per-workstream unique\n title TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'OPEN',\n -- OPEN | IN_PROGRESS | CLOSED — see VOCABULARY.md.\n substate TEXT NOT NULL,\n -- Qualifies status. No DEFAULT on purpose: a writer that forgets it\n -- must fail loudly rather than silently pick one.\n impact INTEGER NOT NULL,\n effort_days REAL NOT NULL,\n owner_id INTEGER REFERENCES agents (id) ON DELETE SET NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE (workstream_id, local_id),\n CHECK (impact BETWEEN 1 AND 100),\n CHECK (effort_days > 0),\n FOREIGN KEY (status, substate) REFERENCES task_substates (status, substate)\n DEFERRABLE INITIALLY DEFERRED\n);\n\nCREATE INDEX IF NOT EXISTS idx_tasks_workstream ON tasks (workstream_id);\nCREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks (status);\nCREATE INDEX IF NOT EXISTS idx_tasks_owner ON tasks (owner_id);\n\n-- task_edges: composite PK by pair. INTEGER FKs into tasks.id.\nCREATE TABLE IF NOT EXISTS task_edges (\n from_task_id INTEGER NOT NULL REFERENCES tasks (id) ON DELETE CASCADE,\n to_task_id INTEGER NOT NULL REFERENCES tasks (id) ON DELETE CASCADE,\n created_at TEXT NOT NULL,\n PRIMARY KEY (from_task_id, to_task_id),\n CHECK (from_task_id <> to_task_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_task_edges_to ON task_edges (to_task_id);\n\n-- task_notes: append-only context. author stays free-text\n-- (\"orchestrator\", \"user\", \"π - mu\", \"system\") — not always a\n-- registered agent.\nCREATE TABLE IF NOT EXISTS task_notes (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n task_id INTEGER NOT NULL REFERENCES tasks (id) ON DELETE CASCADE,\n author TEXT,\n content TEXT NOT NULL,\n created_at TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_task_notes_task ON task_notes (task_id);\n\n-- ─── The ops log (VISION.md § 2b, VOCABULARY.md § op / ops log) ──────\n--\n-- The single append-only record of every change. Sync, undo, and\n-- history are all queries or replays over this one table.\n--\n-- Deliberately FK-free. An op must stay readable after the row (and\n-- the workstream) it records is gone — a tombstone op for a destroyed\n-- workstream is the whole point — so 'key' holds the NATURAL key\n-- ('<workstream>/<local_id>'), never a surrogate id. That is also why\n-- keys don't collide across machines.\n--\n-- seq local-only append cursor (AUTOINCREMENT never recycles)\n-- hlc the ORDERING key across machines (VOCABULARY § HLC)\n-- machine_id which peer wrote this op\n-- group_id the undo unit: all ops of one operator action\n-- actor who caused it (may not be a registered worker)\n-- intent semantic label ('task.close', 'agent.spawn')\n-- entity/key what it addresses ('task', 'mu/ops-log')\n-- op 'put' (semantic partial update) | 'del' (tombstone)\n-- payload JSON of ONLY the columns that changed\n--\n-- UNIQUE (machine_id, hlc) is load-bearing: it makes ingest idempotent\n-- for free, which is what lets 'mu sync --repair' be nothing more than\n-- \"re-read that peer's segment from zero\".\nCREATE TABLE IF NOT EXISTS ops (\n seq INTEGER PRIMARY KEY AUTOINCREMENT,\n hlc TEXT NOT NULL,\n machine_id TEXT NOT NULL,\n group_id TEXT NOT NULL,\n actor TEXT,\n intent TEXT,\n entity TEXT NOT NULL,\n key TEXT NOT NULL,\n op TEXT NOT NULL CHECK (op IN ('put','del')),\n payload TEXT NOT NULL,\n created_at TEXT NOT NULL,\n UNIQUE (machine_id, hlc)\n);\n\n-- Four indexes, one per read shape that actually exists:\n-- hlc — replay/rebuild walks the log in HLC order.\n-- entity,key — \"what happened to this task\" (history + per-field merge).\n-- group_id — 'mu undo <group>' gathers one action's ops.\n-- machine_id,entity,hlc — sync flush seeks this machine's SYNCED ops\n-- past the segment's last hlc, so a trailing run of\n-- machine-local ops (agent.*) costs nothing per flush.\n-- (Other machine_id lookups ride the UNIQUE (machine_id, hlc) index;\n-- seq is the PK. No speculative index beyond these.)\nCREATE INDEX IF NOT EXISTS idx_ops_hlc ON ops (hlc);\nCREATE INDEX IF NOT EXISTS idx_ops_entity_key ON ops (entity, key);\nCREATE INDEX IF NOT EXISTS idx_ops_group ON ops (group_id);\nCREATE INDEX IF NOT EXISTS idx_ops_machine_entity_hlc ON ops (machine_id, entity, hlc);\n\n-- sync_peers: one row per known peer, holding its watermark — how far\n-- into that peer's segment we have applied. One integer suffices\n-- because segments are append-only and ordered. Rows are created on\n-- demand at first ingest; there is no membership list to configure.\n-- A Syncthing conflict copy gets its own row, keyed by its file stem.\n-- last_seen_at is the ISO time of the last watermark write.\nCREATE TABLE IF NOT EXISTS sync_peers (\n machine_id TEXT PRIMARY KEY,\n last_applied_seq INTEGER NOT NULL DEFAULT 0,\n last_seen_at TEXT\n);\n\n-- sync_fingerprints: the caught-up fingerprint, '<size> <mtimeMs>\n-- <manifest sha256>' of a peer segment, recorded with the watermark\n-- when ingest read that segment cleanly to its end (src/segments.ts\n-- segmentCaughtUp). Keyed like sync_peers; a watermark write without a\n-- clean read deletes the row. A cache: losing it costs one full read.\n-- Additive, so no schema bump: an older mu ignores it, and any\n-- watermark it writes can no longer match a stale fingerprint.\nCREATE TABLE IF NOT EXISTS sync_fingerprints (\n machine_id TEXT PRIMARY KEY,\n fingerprint TEXT NOT NULL\n);\n\n-- vcs_workspaces: one isolated working copy per agent.\n-- UNIQUE (agent_id) enforces the 1:1 invariant; workstream_id is\n-- denormalised for query convenience. path is UNIQUE because two\n-- agents pointing at the same on-disk workspace would defeat the\n-- purpose.\nCREATE TABLE IF NOT EXISTS vcs_workspaces (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n agent_id INTEGER NOT NULL UNIQUE REFERENCES agents (id) ON DELETE CASCADE,\n workstream_id INTEGER NOT NULL REFERENCES workstreams (id) ON DELETE CASCADE,\n backend TEXT NOT NULL CHECK (backend IN ('jj', 'sl', 'git', 'none')),\n path TEXT NOT NULL UNIQUE,\n parent_ref TEXT,\n created_at TEXT NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_vcs_workspaces_workstream ON vcs_workspaces (workstream_id);\n\n-- ─── Views (replaced when stale so the latest definition wins) ────────\n-- See READY_VIEW_SQL / BLOCKED_VIEW_SQL / GOALS_VIEW_SQL above for the\n-- canonical DDL — interpolated here so applySchema is one db.exec().\n${READY_VIEW_SQL}\n${BLOCKED_VIEW_SQL}\n${GOALS_VIEW_SQL}\n`;\n","// mu — the hybrid logical clock that orders every op (VOCABULARY § HLC).\n//\n// WHY NOT A WALL-CLOCK TIMESTAMP\n// ------------------------------\n// `ops` are merged across machines by last-writer-wins on `hlc`. If that\n// key were `new Date().toISOString()`, a laptop that sleeps for three\n// days and wakes with a clock skewed BEHIND the devserver would stamp\n// every new edit with a time that already passed — so on merge the\n// laptop's fresh work looks older than the devserver's stale work and is\n// silently discarded. No error, no conflict, just missing edits. That is\n// the #1 way homegrown sync corrupts data.\n//\n// An HLC uses wall time as a HINT and a logical counter as the truth:\n// the pair only ever increases, on this machine, forever. A backwards\n// clock jump costs ordering PRECISION (ops bunch up on one millisecond)\n// but never ordering CORRECTNESS.\n//\n// SERIALIZATION FORMAT\n// --------------------\n// A single lexicographically sortable TEXT, because `ORDER BY hlc` must\n// equal causal order and SQLite compares TEXT bytewise:\n//\n// <wall_ms:15 digits>.<counter:6 digits>.<machine_id>\n//\n// Example (wall=1780000000123, counter=7):\n//\n// 001780000000123.000007.9f1c8a2e-4b6d-4f0a-9c31-2f7c5d3e8a10\n//\n// - Both numeric parts are ZERO-PADDED to a fixed width. Without the\n// padding \"9\" would sort after \"10\" and the whole ordering guarantee\n// collapses.\n// - 15 digits of wall_ms covers every representable JS timestamp\n// (max 8_640_000_000_000_000 is 16 digits, but that is year 275760;\n// 15 digits runs to year 318857 — enough, and checked below).\n// - 6 digits of counter allows 1_000_000 ops inside one millisecond\n// before the clock advances. Overflow throws rather than wrapping,\n// because wrapping would silently regress the order.\n// - The separator is `.` — it cannot appear in a uuid (hex + `-` only),\n// so parsing is unambiguous and a machine_id can never spill into a\n// numeric field. It sorts below every digit and hex letter, so the\n// field boundary itself never perturbs the order.\n// - machine_id is the LAST field and is a tiebreak only: two machines\n// that mint the same (wall, counter) get a stable, arbitrary but\n// total order instead of comparing equal.\n//\n// PERSISTENCE\n// -----------\n// Every mu invocation is a separate short-lived process, so an\n// in-memory counter would reset constantly and mint duplicates. The\n// clock state lives in the singleton `machine_identity` row\n// (`last_wall`, `last_counter`), which is also where `machine_id`\n// already lives — one row, one read, one write.\n\nimport { type Db, prepareCached } from \"./db.js\";\n\n/** Zero-pad width for the wall-clock millisecond field. */\nconst WALL_WIDTH = 15;\n/** Zero-pad width for the logical counter field. */\nconst COUNTER_WIDTH = 6;\n/** Field separator. Cannot appear in a uuid. */\nconst SEP = \".\";\n/** Largest value each fixed-width field can hold. */\nconst MAX_WALL = 10 ** WALL_WIDTH - 1;\nconst MAX_COUNTER = 10 ** COUNTER_WIDTH - 1;\n\n/** A parsed HLC. Never construct by hand — use `parseHlc` or `formatHlc`. */\nexport interface Hlc {\n /** Wall-clock hint, milliseconds since the epoch. */\n wallMs: number;\n /** Logical counter; breaks ties within one `wallMs`. */\n counter: number;\n /** The machine that minted this HLC (`machine_identity.machine_id`). */\n machineId: string;\n}\n\n/** Thrown when a TEXT value is not a well-formed HLC. */\nexport class HlcParseError extends Error {\n constructor(readonly value: string) {\n super(`Malformed HLC: ${JSON.stringify(value)}`);\n this.name = \"HlcParseError\";\n }\n}\n\n/** Thrown when a field would not fit its fixed width. A counter\n * overflow means >1e6 ops landed in one millisecond; wrapping would\n * silently regress causal order, so we fail loudly instead. */\nexport class HlcOverflowError extends Error {\n constructor(\n readonly field: \"wall\" | \"counter\",\n readonly value: number,\n ) {\n super(\n field === \"counter\"\n ? `HLC counter overflow (${value} > ${MAX_COUNTER}): more than ${MAX_COUNTER + 1} ops in one millisecond`\n : `HLC wall-clock overflow (${value} > ${MAX_WALL}): system clock is far in the future`,\n );\n this.name = \"HlcOverflowError\";\n }\n}\n\n/** Thrown when the singleton `machine_identity` row is missing. */\nexport class MachineIdentityMissingError extends Error {\n constructor() {\n super(\"machine_identity row (id = 1) is missing; the DB was not opened via openDb()\");\n this.name = \"MachineIdentityMissingError\";\n }\n}\n\n/** Serialize `(wall_ms, counter, machine_id)` to the sortable TEXT form.\n * See the module comment for the exact shape and an example. */\nexport function formatHlc(hlc: Hlc): string {\n const { wallMs, counter, machineId } = hlc;\n if (!Number.isInteger(wallMs) || wallMs < 0) throw new HlcParseError(String(wallMs));\n if (!Number.isInteger(counter) || counter < 0) throw new HlcParseError(String(counter));\n if (wallMs > MAX_WALL) throw new HlcOverflowError(\"wall\", wallMs);\n if (counter > MAX_COUNTER) throw new HlcOverflowError(\"counter\", counter);\n if (machineId.length === 0 || machineId.includes(SEP)) throw new HlcParseError(machineId);\n return `${String(wallMs).padStart(WALL_WIDTH, \"0\")}${SEP}${String(counter).padStart(\n COUNTER_WIDTH,\n \"0\",\n )}${SEP}${machineId}`;\n}\n\n/** Inverse of `formatHlc`. Throws `HlcParseError` on anything else —\n * including the legacy placeholder `<iso>|<uuid>` shape. */\nexport function parseHlc(value: string): Hlc {\n const parts = value.split(SEP);\n if (parts.length !== 3) throw new HlcParseError(value);\n const [wall, counter, machineId] = parts;\n if (wall === undefined || counter === undefined || machineId === undefined) {\n throw new HlcParseError(value);\n }\n if (wall.length !== WALL_WIDTH || counter.length !== COUNTER_WIDTH || machineId.length === 0) {\n throw new HlcParseError(value);\n }\n if (!/^\\d+$/.test(wall) || !/^\\d+$/.test(counter)) throw new HlcParseError(value);\n return { wallMs: Number(wall), counter: Number(counter), machineId };\n}\n\n/** Total order over serialized HLCs: -1 / 0 / 1. Identical to bytewise\n * string comparison (that is the whole point of the format), so\n * `ORDER BY hlc` in SQL and `.sort(compareHlc)` in JS agree. */\nexport function compareHlc(a: string, b: string): -1 | 0 | 1 {\n if (a < b) return -1;\n if (a > b) return 1;\n return 0;\n}\n\ninterface ClockRow {\n machine_id: string;\n last_wall: number;\n last_counter: number;\n}\n\n/**\n * Mint the next HLC for this machine and persist the advance.\n *\n * now = wall clock ms\n * if now > last_wall: wall = now, counter = 0\n * else: wall = last_wall, counter = last_counter + 1\n *\n * The `else` branch is the monotonicity guarantee: when the clock\n * stalls, jumps backwards, or two ops land in the same millisecond, the\n * counter carries the order instead.\n *\n * ATOMICITY — a SINGLE `UPDATE … RETURNING` statement, not an explicit\n * transaction. SQLite makes one statement atomic and takes the write\n * lock for its duration, so the read-modify-write cannot interleave\n * with a competing `mu` process; `busy_timeout = 5000` (set by openDb)\n * makes the loser wait rather than fail. A read-then-write pair inside\n * BEGIN DEFERRED would be upgrade-deadlock prone under the parallel\n * spawn fan-out, and BEGIN IMMEDIATE would be a strictly bigger lock\n * for the same effect. `receiveHlc` cannot use this trick (its\n * three-way max is not expressible as one clean statement) so it does\n * take BEGIN IMMEDIATE.\n *\n * @param now Injectable clock, for tests. Defaults to `Date.now()`.\n */\nexport function nextHlc(db: Db, now: number = Date.now()): string {\n const row = db\n .prepare(\n `UPDATE machine_identity\n SET last_wall = MAX(last_wall, @now),\n last_counter = CASE WHEN @now > last_wall THEN 0 ELSE last_counter + 1 END\n WHERE id = 1\n RETURNING machine_id, last_wall, last_counter`,\n )\n .get({ now: Math.floor(now) }) as ClockRow | undefined;\n if (!row) throw new MachineIdentityMissingError();\n return formatHlc({ wallMs: row.last_wall, counter: row.last_counter, machineId: row.machine_id });\n}\n\n/**\n * Advance the local clock past a peer's HLC while INGESTING their op,\n * and return the local HLC that now dominates it. This is what makes\n * \"laptop edits after seeing the devserver's op\" order correctly: the\n * laptop's next mint is guaranteed greater than anything it has seen,\n * even if its own wall clock is days behind.\n *\n * wall = max(local_wall, remote_wall, now)\n *\n * The counter has four explicit cases, by which of the three won:\n * - `now` strictly won -> counter = 0 (fresh millisecond)\n * - local and remote tie at max -> counter = max(local_c, remote_c) + 1\n * - only local is at max -> counter = local_c + 1\n * - only remote is at max -> counter = remote_c + 1\n *\n * A remote HLC from the PAST therefore never drags the local clock\n * backwards — `max` keeps `local_wall`, and the counter still steps.\n *\n * ATOMICITY — BEGIN IMMEDIATE (`.immediate()`), because the three-way\n * max needs the old row in JS before the new value can be computed, so\n * unlike `nextHlc` it genuinely is a read-then-write pair.\n *\n * @param now Injectable clock, for tests. Defaults to `Date.now()`.\n */\nexport function receiveHlc(db: Db, remoteHlc: string, now: number = Date.now()): string {\n const remote = parseHlc(remoteHlc);\n const wallNow = Math.floor(now);\n const read = prepareCached(\n db,\n \"SELECT machine_id, last_wall, last_counter FROM machine_identity WHERE id = 1\",\n );\n const write = prepareCached(\n db,\n \"UPDATE machine_identity SET last_wall = @wall, last_counter = @counter WHERE id = 1\",\n );\n\n const advance = (): string => {\n const row = read.get() as ClockRow | undefined;\n if (!row) throw new MachineIdentityMissingError();\n const wall = Math.max(row.last_wall, remote.wallMs, wallNow);\n const localAtMax = row.last_wall === wall;\n const remoteAtMax = remote.wallMs === wall;\n let counter: number;\n if (!localAtMax && !remoteAtMax) {\n counter = 0; // `now` strictly won: a genuinely fresh millisecond.\n } else if (localAtMax && remoteAtMax) {\n counter = Math.max(row.last_counter, remote.counter) + 1;\n } else if (localAtMax) {\n counter = row.last_counter + 1;\n } else {\n counter = remote.counter + 1;\n }\n if (counter > MAX_COUNTER) throw new HlcOverflowError(\"counter\", counter);\n write.run({ wall, counter });\n return formatHlc({ wallMs: wall, counter, machineId: row.machine_id });\n };\n\n // Inside a caller's transaction (ingest applies a whole segment in\n // one) the write lock is already held, so a savepoint per op would buy\n // nothing.\n if (db.inTransaction) return advance();\n return db.transaction(advance).immediate();\n}\n","// mu — the **op context** SDK seam (docs/VOCABULARY.md § op context).\n//\n// Triggers capture reliably but blindly: they see a row change, not why\n// it happened. Intent, grouping and actor are recovered by having the\n// SDK write them into the per-connection `_op_ctx` temp table, which the\n// triggers read as they stamp each op.\n//\n// ONE ASSIGNMENT PER PUBLIC SDK FUNCTION, not an emit per mutation.\n// That is the whole reason this is cheap enough to apply everywhere: a\n// cascade close touching 12 tasks sets the context once and gets 12\n// correctly-labelled, correctly-grouped ops for free.\n//\n// WHY A SCOPED WRAPPER RATHER THAN A SETTER\n// -----------------------------------------\n// The obvious alternative is `setOpContext(db, {...})` called at the top\n// of each SDK function. It was rejected: it leaks. Whatever intent was\n// set last stays set for the rest of the process, so the NEXT mutation\n// — possibly in a caller that never set a context, possibly in a\n// finally-block cleanup after a throw — gets mislabelled with a stale\n// intent. A wrong intent is worse than a null one, because `mu log`\n// renders it as confident prose and undo groups by it.\n//\n// `withOpContext(db, {...}, fn)` restores the previous context in a\n// `finally`, so:\n// * a throw inside fn cannot leak the intent (tested),\n// * nesting is predictable — an inner context wins while it runs and\n// the outer one is exactly restored after,\n// * the context's lifetime is visible in the source as a block.\n//\n// Nested calls inherit the OUTER group by default, which is what makes\n// grouping work without any caller threading a group id around:\n// `closeTask` opening a group and calling `setTaskStatus` per cascaded\n// child yields one group covering all of them. An inner call that wants\n// its own group passes `group: \"new\"`.\n\nimport { randomUUID } from \"node:crypto\";\nimport { type Db, prepareCached } from \"./db.js\";\n\n/** What an op context carries. All fields optional — a partial context\n * is fine and a null intent is captured as null (fail safe). */\nexport interface OpContext {\n /** Semantic label, e.g. `task.close`. Human-grade: `mu log` renders\n * prose from it. Use `<entity>.<verb>` with entities from\n * docs/VOCABULARY.md. */\n intent?: string | undefined;\n /**\n * Intent to use ONLY when no enclosing context already set one.\n *\n * For shared internals that several public verbs funnel through.\n * `setTaskStatus` is the motivating case: called directly it is the\n * operator's action and should label itself, but called from\n * `closeTask` the OUTER verb is the operator-meaningful label and\n * must win. Without this, the inner call would report the mechanism\n * instead of the intent.\n *\n * Ignored when `intent` is also provided.\n */\n intentIfUnset?: string | undefined;\n /** Who caused it. Free text, same semantics as the old\n * `agent_logs.source`: an agent name, \"user\", \"system\". */\n actor?: string | undefined;\n /**\n * Grouping for `mu undo`:\n * - omitted inherit the enclosing group, or start one if none.\n * - \"new\" force a fresh group even when nested.\n * - <string> use this exact group id.\n */\n group?: string | \"new\" | undefined;\n}\n\ninterface CtxRow {\n group_id: string | null;\n actor: string | null;\n intent: string | null;\n applying: number;\n}\n\n/** Read the current context. Exported for tests and for `mu doctor`. */\nexport function currentOpContext(db: Db): {\n groupId: string | null;\n actor: string | null;\n intent: string | null;\n applying: boolean;\n} {\n const row = db.prepare(\"SELECT group_id, actor, intent, applying FROM _op_ctx\").get() as\n | CtxRow\n | undefined;\n // No row => this connection never ran installCapture (a readonly\n // open). Report the inert default rather than throwing: callers use\n // this for diagnostics, and a missing context is not an error.\n if (!row) return { groupId: null, actor: null, intent: null, applying: false };\n return {\n groupId: row.group_id,\n actor: row.actor,\n intent: row.intent,\n applying: row.applying !== 0,\n };\n}\n\nfunction writeCtx(db: Db, row: CtxRow): void {\n prepareCached(\n db,\n `UPDATE _op_ctx SET group_id = @group_id, actor = @actor,\n intent = @intent, applying = @applying`,\n ).run(row);\n}\n\nfunction readCtx(db: Db): CtxRow | undefined {\n return prepareCached(db, \"SELECT group_id, actor, intent, applying FROM _op_ctx\").get() as\n | CtxRow\n | undefined;\n}\n\n/**\n * Run `fn` with the given op context applied, restoring the previous\n * context afterwards even if `fn` throws.\n *\n * Synchronous by design. Every mutating mu SDK function is synchronous\n * (better-sqlite3 is), so an async variant would only invite\n * interleaving two contexts on one connection — the temp table is\n * shared per-connection, so two concurrent async scopes would clobber\n * each other with no way to tell whose intent won. Keeping this sync\n * makes that unrepresentable.\n */\nexport function withOpContext<T>(db: Db, ctx: OpContext, fn: () => T): T {\n const previous = readCtx(db);\n if (!previous) {\n // No _op_ctx table on this connection (readonly open, or a DB\n // opened before capture existed). Nothing to stamp and nothing to\n // restore; run the body so behaviour degrades to \"captured with no\n // context\" rather than throwing.\n return fn();\n }\n\n const groupId =\n ctx.group === \"new\"\n ? randomUUID()\n : ctx.group !== undefined\n ? ctx.group\n : (previous.group_id ?? randomUUID());\n\n const intent =\n ctx.intent !== undefined ? ctx.intent : (previous.intent ?? ctx.intentIfUnset ?? null);\n\n writeCtx(db, {\n group_id: groupId,\n // An explicit undefined inherits; only a provided value overrides.\n actor: ctx.actor !== undefined ? ctx.actor : previous.actor,\n intent,\n applying: previous.applying,\n });\n try {\n return fn();\n } finally {\n writeCtx(db, previous);\n }\n}\n\n/**\n * Run `fn` with capture SUPPRESSED — the echo guard.\n *\n * Applying a peer's op writes to `tasks`, which fires the capture\n * trigger, which mints a NEW local op, which flushes to our segment and\n * propagates back to the peer, which applies it and echoes again. This\n * sets `applying = 1` so every trigger's `WHEN` clause short-circuits\n * and the ingest writes rows WITHOUT writing ops.\n *\n * v2-sync wraps its ingest loop in this. It lives here rather than in\n * the sync module because the flag is part of the op-context contract\n * the triggers read, and having exactly one writer of it is the point.\n *\n * Restores the previous value in a `finally`, so a throw mid-ingest\n * cannot leave capture permanently disabled on this connection — which\n * would be the worst possible failure mode, silently dropping every\n * subsequent local change.\n */\nexport function withCaptureSuppressed<T>(db: Db, fn: () => T): T {\n const previous = readCtx(db);\n if (!previous) return fn();\n writeCtx(db, { ...previous, applying: 1 });\n try {\n return fn();\n } finally {\n writeCtx(db, previous);\n }\n}\n","// mu — generic cross-process advisory lock, via atomic `fs.mkdir`.\n//\n// Extracted from src/agents/spawn-lock.ts, which had exactly this logic\n// keyed to a tmux session name. Segments need the same primitive keyed to\n// a sync directory, and two copies of a lock implementation is how they\n// drift — so the mechanism lives here once and both callers name their own\n// resource. spawn-lock.ts keeps its session-specific wrapper and its\n// tests; only the body moved.\n//\n// Why a lockfile at all: every `mu` invocation is a separate short-lived\n// process, so there is no in-process mutex to lean on. `fs.mkdir` is\n// atomic and fails EEXIST when the directory exists — the classic\n// primitive, no dependency (honours the ROADMAP anti-feature pledge).\n//\n// BEST-EFFORT BY DEFAULT. A lock that cannot be taken (a read-only state\n// dir, or still contended at the deadline) falls through to running the\n// body UNLOCKED rather than failing the command. That suits the spawn\n// lock, which only narrows a race. A caller whose body must never run\n// unlocked passes `onUnavailable`, which runs INSTEAD of the body: the\n// segment flush does, because an unlocked append can interleave partial\n// lines or race another flush's self-repair truncate.\n\nimport { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { defaultStateDir } from \"./db.js\";\n\n/** Sub-directory of the state dir holding lock directories. */\nexport function locksDir(): string {\n return join(defaultStateDir(), \"locks\");\n}\n\n/** Default: max time to wait to acquire before giving up. */\nconst DEFAULT_ACQUIRE_TIMEOUT_MS = 15_000;\n/** A held lock older than this is presumed abandoned (crashed process). */\nconst DEFAULT_STALE_LOCK_MS = 30_000;\n/** Poll interval while spinning. */\nconst RETRY_INTERVAL_MS = 25;\n\nexport interface FileLockOptions<T = unknown> {\n acquireTimeoutMs?: number;\n staleLockMs?: number;\n /** Env var consulted for the acquire timeout, if any. */\n timeoutEnvVar?: string;\n /** Run instead of `fn` when the lock cannot be taken (contended past\n * the deadline, or the lock dir cannot be created). Absent, `fn` runs\n * unlocked. */\n onUnavailable?: () => T;\n}\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\nfunction resolveTimeout(opts?: FileLockOptions<unknown>): number {\n const envVar = opts?.timeoutEnvVar;\n if (envVar !== undefined) {\n const raw = process.env[envVar];\n if (raw !== undefined && raw !== \"\") {\n const n = Number.parseInt(raw, 10);\n if (Number.isFinite(n) && n >= 0) return n;\n }\n }\n return opts?.acquireTimeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS;\n}\n\n/** Best-effort staleness probe. A vanished lock returns false so the\n * caller simply retries the mkdir. */\nasync function isStale(path: string, staleMs: number): Promise<boolean> {\n try {\n const s = await stat(path);\n return Date.now() - s.mtimeMs > staleMs;\n } catch {\n return false;\n }\n}\n\n/**\n * Run `fn` while holding the lock directory at `lockPath`.\n *\n * Releases in a `finally`, so a throwing `fn` never leaks the lock.\n * Records pid + acquisition time in `meta.json` for stale-lock\n * diagnostics.\n */\nexport async function withFileLock<T>(\n lockPath: string,\n label: string,\n fn: () => Promise<T>,\n opts?: FileLockOptions<T>,\n): Promise<T> {\n const staleMs = opts?.staleLockMs ?? DEFAULT_STALE_LOCK_MS;\n const deadline = Date.now() + resolveTimeout(opts);\n const onUnavailable = opts?.onUnavailable;\n const unlocked = async (): Promise<T> =>\n onUnavailable === undefined ? await fn() : onUnavailable();\n let held = false;\n\n try {\n await mkdir(locksDir(), { recursive: true });\n } catch {\n // Cannot even create the locks dir: run unlocked rather than refuse.\n return await unlocked();\n }\n\n while (!held) {\n try {\n await mkdir(lockPath); // atomic; EEXIST if already held\n held = true;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") return await unlocked();\n if (await isStale(lockPath, staleMs)) {\n await rm(lockPath, { recursive: true, force: true }).catch(() => {});\n continue;\n }\n if (Date.now() >= deadline) return await unlocked();\n await sleep(RETRY_INTERVAL_MS);\n }\n }\n\n await writeFile(\n join(lockPath, \"meta.json\"),\n JSON.stringify({ pid: process.pid, label, acquiredAt: new Date().toISOString() }),\n ).catch(() => {});\n\n try {\n return await fn();\n } finally {\n await rm(lockPath, { recursive: true, force: true }).catch(() => {});\n }\n}\n\n/** Read a held lock's metadata, or null. Exposed for tests. */\nexport async function readFileLockMeta(\n lockPath: string,\n): Promise<{ pid: number; label: string; acquiredAt: string } | null> {\n try {\n const raw = await readFile(join(lockPath, \"meta.json\"), \"utf8\");\n return JSON.parse(raw) as { pid: number; label: string; acquiredAt: string };\n } catch {\n return null;\n }\n}\n","// Historical op shapes remain readable after their command surface is removed.\n// These intents carried prose payloads under otherwise projectable entities.\nexport const LEGACY_LOG_ONLY_INTENTS: ReadonlySet<string> = new Set([\"workstream.export\"]);\n\nexport function isLegacyLogOnlyIntent(intent: string | null): boolean {\n return intent !== null && LEGACY_LOG_ONLY_INTENTS.has(intent);\n}\n\n/**\n * The same exclusion as a SQL predicate, for queries that must not even\n * TOUCH these rows.\n *\n * A JS-side filter is not always enough: SQLite's `json_type` /\n * `json_extract` raise `malformed JSON` while STEPPING, so a query that\n * merely evaluates a json function over one of these prose payloads\n * fails before any row reaches JS. Callers that read payloads by key\n * therefore have to exclude them in the WHERE clause.\n *\n * Kept next to the set it derives from so the two can never disagree.\n * Emitted as a literal rather than a bound parameter because it is\n * interpolated into prepared SQL; every member is a fixed identifier in\n * this file, never operator input.\n */\nexport const LEGACY_LOG_ONLY_SQL_EXCLUSION: string = `(intent IS NULL OR intent NOT IN (${[\n ...LEGACY_LOG_ONLY_INTENTS,\n]\n .map((i) => `'${i}'`)\n .join(\", \")}))`;\n\n/**\n * Intents renamed after ops carrying the old name were already on\n * disk. Key = current name, value = every historical spelling.\n *\n * The op log is append-only, so a rename cannot rewrite history: the\n * old string stays on the rows it was written to, forever. Everything\n * that READS by intent therefore has to accept both, or a rename\n * silently truncates the user's history at the release boundary —\n * `mu log --intent <new>` would miss every pre-rename op and\n * `mu undo` would not find those groups.\n *\n * `workstream.destroy` became `workstream.teardown` in 1.2.0 because\n * \"destroy\" claims irreversibility that is not true (tombstones are\n * written; `mu undo` restores the rows) and operators were hoarding\n * pre-flight DB copies because of it. ~5k ops carry the old name.\n */\nexport const LEGACY_INTENT_SYNONYMS: ReadonlyMap<string, readonly string[]> = new Map([\n [\"workstream.teardown\", [\"workstream.destroy\"]],\n]);\n\n/** Every spelling of `intent`, current first. A single-element list for\n * the common case of an intent that was never renamed. */\nexport function intentSpellings(intent: string): readonly string[] {\n const legacy = LEGACY_INTENT_SYNONYMS.get(intent);\n return legacy === undefined ? [intent] : [intent, ...legacy];\n}\n","// mu — the APPLY path: how one op lands in the portable tables.\n//\n// The counterpart to src/capture.ts. Capture answers \"a row changed,\n// what op records it\"; this answers \"here is an op, local or from a\n// peer, what does the table look like afterwards\". v2-sync will call\n// `applyOp` once per op it ingests; this module knows nothing about\n// segments, files or watermarks.\n//\n// THE MERGE RULES (docs/VOCABULARY.md; v2-merge-rules)\n// ---------------------------------------------------\n// note / message GROW-ONLY SET. Insert-if-absent by content\n// identity (task, author, content, created_at).\n// Never updated, so never in conflict.\n// task / workstream PER-FIELD LWW by HLC. Not row-level.\n// edge LWW-ELEMENT-SET: add/remove, each carrying an\n// HLC, so a remove and a re-add order correctly.\n// anything else NOT SYNCED. Rejected loudly.\n//\n// WHY PER-FIELD AND NOT ROW-LEVEL\n// -------------------------------\n// The original design note argued row-level LWW sufficed, because \"the\n// operating rule is already no concurrent edits to one workstream on two\n// machines\". That assumption is weak in mu specifically: mu runs\n// autonomous agent crews, so a crew on the devserver closing a task\n// while the operator edits that same task's impact on a laptop is\n// concurrent multi-machine writing BY CONSTRUCTION, not user error.\n// Row-level LWW would let the crew's status=CLOSED clobber the\n// operator's impact=80, silently, with no conflict reported.\n//\n// Per-field costs nothing extra here because capture already emits\n// SEMANTIC PARTIAL UPDATES: a task.close op carries {\"status\":\"CLOSED\"},\n// not a row snapshot. So \"apply each op's keys in HLC order\" IS\n// per-field LWW. No column version vectors, no per-column metadata, none\n// of the cr-sqlite machinery we rejected.\n//\n// PROVENANCE: DERIVED FROM THE OPS LOG, NOT STORED\n// ------------------------------------------------\n// Per-field LWW needs to know, per field, the HLC that last wrote it.\n// The obvious shape is a side table keyed (entity, key, field) -> hlc.\n// This module does NOT do that, and the reason is worth stating because\n// the brief explicitly asked for a justification.\n//\n// The ops log ALREADY IS the per-field provenance. Every op carries its\n// HLC and names exactly the fields it touched, and `idx_ops_entity_key`\n// indexes (entity, key). So \"the HLC that last wrote field F of key K\"\n// is a query over the ~handful of ops for K, not a fact needing separate\n// storage. Deriving it instead of storing it means:\n//\n// * ONE source of truth. A side table is a denormalisation that can\n// disagree with the log, and when it does, every downstream\n// projection (undo, sync) inherits the disagreement. There\n// is no reconciliation procedure that could fix it, because nothing\n// would know which side was right.\n// * Idempotence for free. Re-applying an op compares HLCs against the\n// log, which already contains that op, so a second apply is a no-op\n// by construction rather than by careful bookkeeping. That is what\n// makes \"re-read a peer's segment from zero\" a safe universal\n// repair.\n// * Resurrection survives deletion for free. See below.\n// * Storage cost: ZERO additional bytes. A side table would cost one\n// row per (key, field) — for the 8 captured columns of `tasks`, 8\n// rows per task, each ~60 bytes of key text plus a ~55-byte HLC, so\n// roughly 1KB per task, unbounded in the number of tasks and\n// duplicating data already on disk in `ops`.\n//\n// Measured cost of deriving: ~10us per key against a 16000-op / 2000-task\n// log (index seek over that key's ~8 ops). Ingest is already doing a\n// write per op, so this is not the bottleneck, and it buys the absence of\n// a whole class of drift bug. If a profile ever says otherwise, the fix\n// is a materialised cache keyed off `ops.seq` that can be rebuilt from\n// the log — which is exactly the kind of thing to add when measured, not\n// before.\n//\n// RESURRECTION vs A STALE PUT\n// ---------------------------\n// After a `del`, a LATER `put` must recreate the row (a legitimate\n// re-add), while an EARLIER `put` arriving late must not. Distinguishing\n// them requires provenance that outlives the row — and derived\n// provenance does, automatically, because `ops` rows are never deleted\n// when a table row is. A stored side table would have to be deliberately\n// NOT cleaned up on delete, which is a rule someone eventually\n// \"optimises\" away.\n//\n// TOMBSTONES ARE JUST OPS (v2-tombstones)\n// ---------------------------------------\n// There is no tombstone table. `op='del'` rows ARE the tombstones,\n// ordinary ops carrying an HLC, so out-of-order arrival is just \"compare\n// HLCs\" — the same comparison the update path does. A late `put` older\n// than a seen `del` loses; a `del` older than a seen `put` loses. One\n// code path, no special casing.\n\nimport {\n type Db,\n MACHINE_LOCAL_ENTITIES,\n prepareCached,\n SYNCED_ENTITIES,\n type SyncedEntity,\n} from \"./db.js\";\nimport { compareHlc } from \"./hlc.js\";\nimport { LEGACY_LOG_ONLY_SQL_EXCLUSION } from \"./legacy-ops.js\";\nimport { withCaptureSuppressed } from \"./op-context.js\";\nimport { DEFAULT_SUBSTATE, isTaskStatus, mapLegacyStatus, resolvePair } from \"./tasks/status.js\";\n\n/** An op as applied. Mirrors the `ops` row shape, minus the local-only\n * `seq` (meaningless on a peer) and the advisory `created_at`. */\nexport interface Op {\n /** The ordering key. See docs/VOCABULARY.md § HLC. */\n hlc: string;\n /** Which peer minted it. Half of the (machine_id, hlc) identity. */\n machineId: string;\n /** One user-visible action, for `mu undo`. */\n groupId: string;\n /** Free text: agent name, \"user\", \"system\". */\n actor?: string | null;\n /** Semantic label, e.g. \"task.close\". */\n intent?: string | null;\n /** Which kind of thing this op addresses. */\n entity: string;\n /** The NATURAL key. Never a surrogate id. */\n key: string;\n /** 'put' = semantic partial update, 'del' = tombstone. */\n op: \"put\" | \"del\";\n /** JSON object of ONLY the fields this op touched. */\n payload: string;\n}\n\n/** Thrown when an op names an entity this build KNOWS is machine-local\n * (see `MACHINE_LOCAL_ENTITIES`). Loud by design: a peer shipping a\n * pane id or an absolute path is a real bug we want reported.\n *\n * NOT thrown for an entity we merely do not recognise. That is a\n * reader-behind-writer vocabulary skew in a mixed fleet, and treating\n * it as a defect froze one peer's watermark permanently — see\n * `MACHINE_LOCAL_ENTITIES` in src/db.ts for the incident. */\nexport class OpEntityNotSyncedError extends Error {\n constructor(readonly entity: string) {\n super(\n `op entity ${JSON.stringify(entity)} is machine-local and must never arrive from a peer ` +\n `(synced entities: ${SYNCED_ENTITIES.join(\", \")})`,\n );\n this.name = \"OpEntityNotSyncedError\";\n }\n}\n\n/** Thrown when an op's natural key does not parse for its entity. */\nexport class OpKeyMalformedError extends Error {\n constructor(\n readonly entity: string,\n readonly key: string,\n ) {\n super(`malformed ${entity} key: ${JSON.stringify(key)}`);\n this.name = \"OpKeyMalformedError\";\n }\n}\n\n/** What `applyOp` did, so callers (and tests) can assert on outcomes\n * rather than re-querying. */\nexport interface ApplyResult {\n /** True iff the DB changed. False for a losing op, a duplicate, or a\n * no-op — all three are legitimate and non-exceptional. */\n changed: boolean;\n /** Fields actually written, for a 'put' on task / workstream. Empty\n * when every field in the payload lost its HLC comparison. */\n appliedFields: string[];\n /** Why nothing happened, when `changed` is false. */\n skipped?: \"older-than-tombstone\" | \"older-than-current\" | \"already-present\" | \"absent\";\n}\n\nfunction isSyncedEntity(entity: string): entity is SyncedEntity {\n return (SYNCED_ENTITIES as readonly string[]).includes(entity);\n}\n\n/** Entities this build knows must never travel. Distinct from \"unknown\":\n * only these are a defect. */\nfunction isKnownMachineLocalEntity(entity: string): boolean {\n return (MACHINE_LOCAL_ENTITIES as readonly string[]).includes(entity);\n}\n\n// ─── Derived provenance ───────────────────────────────────────────────\n\n/**\n * The newest HLC among ops for `key` that touched `field`, or null if no\n * op ever has. Ops are the provenance (see the module comment), so this\n * is a plain indexed query rather than a lookup in a side table.\n *\n * `json_type(payload, '$.field') IS NOT NULL` is the presence test, NOT\n * `json_extract(...) IS NOT NULL`. json_extract returns SQL NULL both\n * for an absent key and for a key whose value IS null, which would make\n * a set-to-NULL op invisible to its own provenance — the field would\n * then be permanently rewritable by any older op. json_type returns the\n * string 'null' for a present-but-null member and SQL NULL only when\n * the member is genuinely absent, so it distinguishes the two.\n *\n * The `hlc <> @self` exclusion makes re-application idempotent: an op\n * already in the log must not count itself as a competing writer, or a\n * second apply would compare its HLC against itself and lose.\n */\nfunction fieldHlc(db: Db, op: Op, field: string): string | null {\n const row = prepareCached(\n db,\n `SELECT MAX(hlc) AS hlc\n FROM ops\n WHERE entity = @entity\n AND key = @key\n AND op = 'put'\n AND hlc <> @self\n AND ${LEGACY_LOG_ONLY_SQL_EXCLUSION}\n AND json_type(payload, '$.' || @field) IS NOT NULL`,\n ).get({ entity: op.entity, key: op.key, self: op.hlc, field }) as\n | { hlc: string | null }\n | undefined;\n return row?.hlc ?? null;\n}\n\n/**\n * The newest tombstone HLC for this key, or null if it was never\n * deleted. This is the whole of tombstone handling: a `del` is an\n * ordinary op, so \"has this been deleted, and when\" is one MAX().\n */\nfunction tombstoneHlc(db: Db, op: Op): string | null {\n const row = prepareCached(\n db,\n `SELECT MAX(hlc) AS hlc\n FROM ops\n WHERE entity = @entity AND key = @key AND op = 'del' AND hlc <> @self`,\n ).get({ entity: op.entity, key: op.key, self: op.hlc }) as { hlc: string | null } | undefined;\n return row?.hlc ?? null;\n}\n\n/** The newest HLC of any op for this key, whatever kind. Used by the\n * grow-only and element-set paths, which care about the row's\n * existence rather than individual fields. */\nfunction anyHlc(db: Db, op: Op, kind: \"put\" | \"del\"): string | null {\n const row = prepareCached(\n db,\n `SELECT MAX(hlc) AS hlc\n FROM ops\n WHERE entity = @entity AND key = @key AND op = @kind AND hlc <> @self`,\n ).get({ entity: op.entity, key: op.key, kind, self: op.hlc }) as\n | { hlc: string | null }\n | undefined;\n return row?.hlc ?? null;\n}\n\n/** True iff `candidate` is strictly newer than `incumbent`. A null\n * incumbent means \"nothing has written this yet\", so anything wins. */\nfunction wins(candidate: string, incumbent: string | null): boolean {\n if (incumbent === null) return true;\n return compareHlc(candidate, incumbent) > 0;\n}\n\n// ─── Payload decoding ─────────────────────────────────────────────────\n\n/** A payload field and its value. `value` may legitimately be null —\n * that is a set-to-NULL, not an absent field. */\ntype PayloadEntry = readonly [field: string, value: string | number | null];\n\n/**\n * Decode a payload into ordered entries.\n *\n * Deliberately hand-rolled over `Object.entries(JSON.parse(...))`\n * only in that it validates shape and narrows types; the important part\n * is what it does NOT do: it never uses `json_patch` to merge a payload\n * into a row. json_patch implements RFC 7396, where a null member means\n * DELETE THIS KEY, so `json_patch('{\"owner_id\":7}', '{\"owner_id\":null}')`\n * returns `{}` — the set-to-NULL is silently discarded rather than\n * applied. Since capture emits exactly `{\"owner_id\":null}` when a claim\n * is released, using json_patch anywhere on the apply path would drop\n * every set-to-NULL transition in the system. Fields are applied one at\n * a time with explicit parameter binding instead.\n */\nfunction decodePayload(payload: string): PayloadEntry[] {\n const parsed: unknown = JSON.parse(payload);\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new SyntaxError(`op payload must be a JSON object, got ${payload.slice(0, 40)}`);\n }\n const entries: PayloadEntry[] = [];\n for (const [field, value] of Object.entries(parsed)) {\n if (value === null || typeof value === \"string\" || typeof value === \"number\") {\n entries.push([field, value]);\n continue;\n }\n if (typeof value === \"boolean\") {\n // SQLite has no boolean type; capture never emits one, but a\n // hand-written or future op might.\n entries.push([field, value ? 1 : 0]);\n continue;\n }\n throw new SyntaxError(`op payload field ${JSON.stringify(field)} has unsupported type`);\n }\n return entries;\n}\n\n// ─── Natural key parsing ──────────────────────────────────────────────\n//\n// The inverse of src/capture.ts's key builders. Kept here rather than\n// shared with capture because capture composes keys in SQL and this\n// decomposes them in TS; a \"shared\" helper would be two functions in one\n// file pretending to be one thing.\n\n/** `<workstream>/<local_id>` -> its parts. Task ids match\n * `[a-z][a-z0-9_-]*`, so they never contain '/', making the FIRST '/'\n * the unambiguous separator. */\nfunction parseTaskKey(key: string): { workstream: string; localId: string } {\n const slash = key.indexOf(\"/\");\n if (slash <= 0 || slash === key.length - 1) throw new OpKeyMalformedError(\"task\", key);\n const workstream = key.slice(0, slash);\n const localId = key.slice(slash + 1);\n if (workstream.length === 0 || localId.length === 0) {\n throw new OpKeyMalformedError(\"task\", key);\n }\n return { workstream, localId };\n}\n\n/** `<task-key>#<origin-id>` -> the task key it hangs off. Task ids\n * cannot contain '#', so the LAST '#' separates. The origin id is\n * validated as present (a key without one is malformed) but not\n * returned: it identifies the note on its ORIGIN machine only, and\n * `applyNotePut` uses content identity instead. See its comment. */\nfunction parseNoteKey(key: string): { taskKey: string } {\n const hash = key.lastIndexOf(\"#\");\n if (hash <= 0 || hash === key.length - 1) throw new OpKeyMalformedError(\"note\", key);\n return { taskKey: key.slice(0, hash) };\n}\n\n/** `<blocker>-><blocked>` -> its parts. Task ids MAY end in '-', so\n * `demo/a-->demo/b` is a valid key for blocker `demo/a-`; splitting on\n * the FIRST '->' recovers that correctly, whereas a naive split('->')\n * would produce three fragments. */\nfunction parseEdgeKey(key: string): { blocker: string; blocked: string } {\n const arrow = key.indexOf(\"->\");\n if (arrow <= 0) throw new OpKeyMalformedError(\"edge\", key);\n const blocker = key.slice(0, arrow);\n const blocked = key.slice(arrow + 2);\n if (blocker.length === 0 || blocked.length === 0) throw new OpKeyMalformedError(\"edge\", key);\n return { blocker, blocked };\n}\n\n// ─── Row helpers ──────────────────────────────────────────────────────\n\n/**\n * Columns that must never be written from an op.\n *\n * owner_id is an FK into the machine-local `agents` table, so\n * OWNERSHIP DOES NOT SYNC (src/db.ts § MACHINE_LOCAL_TABLES\n * spells out why). It is CAPTURED, for local history and\n * undo, but applying a peer's owner_id would at best point\n * at an unrelated local agent and at worst violate the FK\n * outright — verified: inserting a task with an owner_id\n * absent from `agents` fails with 'FOREIGN KEY constraint\n * failed'. Stripping it structurally is the only correct\n * move, and it makes the FK a backstop rather than a trap.\n * local_id / name\n * are encoded in the natural key. Taking them from the\n * payload would let a op rename the row out from under its\n * own key.\n */\nconst NEVER_APPLY = new Set([\"owner_id\", \"local_id\", \"name\", \"id\", \"workstream_id\", \"task_id\"]);\n\n/** Ensure the workstream row exists, returning its surrogate id. Rows\n * arrive out of order across entities (a task op can precede its\n * workstream op), so the apply path creates the parent on demand\n * rather than rejecting. The subsequent workstream op then fills in\n * its real fields by ordinary per-field LWW. */\nfunction ensureWorkstreamRow(db: Db, name: string): number {\n const existing = prepareCached(db, \"SELECT id FROM workstreams WHERE name = ?\").get(name) as\n | { id: number }\n | undefined;\n if (existing) return existing.id;\n prepareCached(db, \"INSERT INTO workstreams (name, created_at) VALUES (?, ?)\").run(\n name,\n new Date().toISOString(),\n );\n const created = prepareCached(db, \"SELECT id FROM workstreams WHERE name = ?\").get(name) as\n | { id: number }\n | undefined;\n if (!created) throw new Error(`failed to create workstream row for ${name}`);\n return created.id;\n}\n\n/** Surrogate id for a task natural key, or null when absent. */\nfunction taskRowId(db: Db, key: string): number | null {\n const { workstream, localId } = parseTaskKey(key);\n const row = prepareCached(\n db,\n `SELECT t.id AS id\n FROM tasks t\n JOIN workstreams w ON w.id = t.workstream_id\n WHERE w.name = ? AND t.local_id = ?`,\n ).get(workstream, localId) as { id: number } | undefined;\n return row?.id ?? null;\n}\n\n// ─── Entity appliers ──────────────────────────────────────────────────\n\n/** PER-FIELD LWW for one row of a table with a natural key.\n *\n * For each field in the payload, apply it only if this op's HLC beats\n * the newest HLC that previously wrote THAT FIELD. Fields are\n * independent, so one op can win on `status` and lose on `impact` in\n * the same call — which is exactly the concurrent-crew case. */\nfunction applyFieldLww(\n db: Db,\n op: Op,\n table: \"tasks\" | \"workstreams\",\n rowId: number,\n entries: readonly PayloadEntry[],\n): string[] {\n const applied: string[] = [];\n for (const [field, value] of entries) {\n if (NEVER_APPLY.has(field)) continue;\n if (!wins(op.hlc, fieldHlc(db, op, field))) continue;\n\n // The HLC says this op may write the field. Before doing so, check\n // whether the field ALREADY holds this value.\n //\n // This is what makes re-application a true no-op rather than a\n // redundant rewrite that merely happens to be value-stable. The HLC\n // comparison alone cannot tell \"first apply\" from \"second apply\",\n // because provenance deliberately excludes the op's own HLC (so that\n // record-then-apply and apply-then-record behave identically). Value\n // equality is the honest signal: nothing changed, so report nothing\n // changed. Callers use `changed` to decide whether to log or refresh,\n // and a spurious true would make `mu sync` claim work it did not do.\n //\n // Identifier is not user input: `field` is filtered against the\n // table's real column list by `filterAppliable` before we get here.\n const current = prepareCached(db, `SELECT ${field} AS v FROM ${table} WHERE id = ?`).get(\n rowId,\n ) as { v: string | number | null } | undefined;\n if (current !== undefined && current.v === value) continue;\n\n prepareCached(db, `UPDATE ${table} SET ${field} = ? WHERE id = ?`).run(value, rowId);\n applied.push(field);\n }\n return applied;\n}\n\n/** The columns each portable table will accept from an op. Anything\n * else in a payload is ignored rather than fatal: a peer on a newer mu\n * may legitimately send fields we do not know yet, and dropping them\n * is strictly better than refusing the whole op. */\nconst APPLIABLE_COLUMNS: Record<\"tasks\" | \"workstreams\", readonly string[]> = {\n tasks: [\"title\", \"status\", \"substate\", \"impact\", \"effort_days\", \"created_at\", \"updated_at\"],\n workstreams: [\"created_at\"],\n};\n\nfunction filterAppliable(\n table: \"tasks\" | \"workstreams\",\n entries: readonly PayloadEntry[],\n): PayloadEntry[] {\n const allowed = APPLIABLE_COLUMNS[table];\n return entries.filter(([field]) => allowed.includes(field));\n}\n\nfunction applyTaskPut(db: Db, op: Op): ApplyResult {\n const { workstream, localId } = parseTaskKey(op.key);\n // Decode the pair out of the payload. `substate` is not applied by\n // per-field LWW: repairTaskPair derives it from the log (see there),\n // with this op passed in because the caller may not have recorded it\n // yet. A legacy status (v9 peers, retained history) maps onto a pair;\n // only the decoded projection changes, the payload is recorded as-is.\n // A status this build does not know is dropped like an unknown field.\n const entries: PayloadEntry[] = [];\n for (const entry of filterAppliable(\"tasks\", decodePayload(op.payload))) {\n const [field, value] = entry;\n if (field === \"substate\") continue;\n if (field === \"status\") {\n if (typeof value !== \"string\") continue;\n const legacy = mapLegacyStatus(value);\n if (legacy) entries.push([\"status\", legacy.status]);\n else if (isTaskStatus(value)) entries.push(entry);\n continue;\n }\n entries.push(entry);\n }\n const pending = { hlc: op.hlc, substate: carriedSubstate(JSON.parse(op.payload)) };\n\n const existing = taskRowId(db, op.key);\n if (existing === null) {\n // Row absent. Either it was never created here, or it was deleted.\n // A tombstone NEWER than this put means the delete wins and the row\n // stays gone; an OLDER tombstone means this is a legitimate\n // resurrection. Identical comparison either way — that is the point\n // of tombstones being ordinary ops.\n const tomb = tombstoneHlc(db, op);\n if (tomb !== null && !wins(op.hlc, tomb)) {\n return { changed: false, appliedFields: [], skipped: \"older-than-tombstone\" };\n }\n // Create the row, then let per-field LWW fill it in. The insert uses\n // placeholder values for NOT NULL columns so a partial payload\n // cannot fail the insert; every field the op actually carries is\n // written by applyFieldLww below, and any it does not carry will be\n // filled by whichever op does.\n const wsId = ensureWorkstreamRow(db, workstream);\n const now = new Date().toISOString();\n prepareCached(\n db,\n `INSERT INTO tasks (workstream_id, local_id, title, status, substate, impact, effort_days,\n owner_id, created_at, updated_at)\n VALUES (?, ?, ?, 'OPEN', 'todo', 50, 1, NULL, ?, ?)`,\n ).run(wsId, localId, localId, now, now);\n const rowId = taskRowId(db, op.key);\n if (rowId === null) throw new Error(`failed to create task row for ${op.key}`);\n // Force every carried field on: the row was just created, so there\n // is no incumbent value worth preserving, but the HLC comparison\n // still runs so a stale op cannot overwrite a newer one that\n // arrived first and created the row.\n const applied = applyFieldLww(db, op, \"tasks\", rowId, entries);\n if (repairTaskPair(db, rowId, pending)) applied.push(\"substate\");\n return { changed: true, appliedFields: applied };\n }\n\n const applied = applyFieldLww(db, op, \"tasks\", existing, entries);\n if (repairTaskPair(db, existing, pending)) applied.push(\"substate\");\n return applied.length > 0\n ? { changed: true, appliedFields: applied }\n : { changed: false, appliedFields: [], skipped: \"older-than-current\" };\n}\n\n/** The substate an op payload writes, or null if it writes none.\n *\n * - A legacy status writes the substate it maps to, overriding any\n * substate beside it (mirrors resolvePair).\n * - A known status with no substate writes the status's default.\n * Capture records only changed columns, and the substate sets of the\n * statuses are disjoint, so a v11 status change always carries its\n * substate. A status-only op therefore comes from a v10 peer or\n * pre-v11 history, where every status had exactly its default.\n * - Otherwise the explicit substate, or null. */\nfunction carriedSubstate(payload: unknown): string | null {\n if (payload === null || typeof payload !== \"object\") return null;\n const { status, substate } = payload as Record<string, unknown>;\n if (typeof status === \"string\") {\n const legacy = mapLegacyStatus(status);\n if (legacy) return legacy.substate;\n if (typeof substate !== \"string\" && isTaskStatus(status)) return DEFAULT_SUBSTATE[status];\n }\n return typeof substate === \"string\" ? substate : null;\n}\n\n/**\n * Set a task's substate to the one its op log implies, and keep the\n * (status, substate) pair legal for the deferred FK. Returns true iff it\n * rewrote the row.\n *\n * The substate comes from the newest (by HLC) op that writes one — see\n * carriedSubstate for what counts — resolved against the row's CURRENT\n * status. An unknown substate (newer peer) or one illegal for the\n * status (a concurrent close vs park, where status and substate come\n * from different ops) falls back to DEFAULT_SUBSTATE[status].\n *\n * It reads the LOG, not the row, on purpose. A repair that only looked\n * at the row would bake a fallback into it, and a later op that changes\n * status back would keep the fallback on one arrival order and the real\n * substate on another. Reading the log makes the result a pure function\n * of the set of ops plus the row's status (itself plain LWW), so every\n * peer that applies the same ops reaches the same row. That is why the\n * repair records no op: on the apply path it runs inside\n * withCaptureSuppressed, and every peer computes the same repair on its\n * own. On the undo path capture is live, and the write is recorded as\n * part of the undo group.\n *\n * `pending` is the op being applied, which the caller may not have\n * recorded yet (ingest applies before recording).\n */\nexport function repairTaskPair(\n db: Db,\n rowId: number,\n pending?: { hlc: string; substate: string | null },\n): boolean {\n const row = prepareCached(\n db,\n `SELECT t.status, t.substate, w.name || '/' || t.local_id AS key\n FROM tasks t JOIN workstreams w ON w.id = t.workstream_id\n WHERE t.id = ?`,\n ).get(rowId) as { status: string; substate: string; key: string } | undefined;\n if (!row) return false;\n\n let winner: { hlc: string; substate: string } | null = null;\n const writers = prepareCached(\n db,\n `SELECT hlc, payload FROM ops\n WHERE entity = 'task' AND key = ? AND op = 'put' AND hlc <> ?\n AND ${LEGACY_LOG_ONLY_SQL_EXCLUSION}\n AND (json_type(payload, '$.substate') IS NOT NULL\n OR json_type(payload, '$.status') IS NOT NULL)\n ORDER BY hlc DESC`,\n ).iterate(row.key, pending?.hlc ?? \"\") as Iterable<{ hlc: string; payload: string }>;\n for (const w of writers) {\n const substate = carriedSubstate(JSON.parse(w.payload));\n if (substate === null) continue;\n winner = { hlc: w.hlc, substate };\n break;\n }\n if (pending && pending.substate !== null && wins(pending.hlc, winner?.hlc ?? null)) {\n winner = { hlc: pending.hlc, substate: pending.substate };\n }\n\n const target = resolvePair(row.status, winner?.substate ?? row.substate);\n if (target === null || target.substate === row.substate) return false;\n prepareCached(db, \"UPDATE tasks SET substate = ? WHERE id = ?\").run(target.substate, rowId);\n return true;\n}\n\nfunction applyWorkstreamPut(db: Db, op: Op): ApplyResult {\n const name = op.key;\n if (name.length === 0) throw new OpKeyMalformedError(\"workstream\", name);\n const entries = filterAppliable(\"workstreams\", decodePayload(op.payload));\n\n const existing = prepareCached(db, \"SELECT id FROM workstreams WHERE name = ?\").get(name) as\n | { id: number }\n | undefined;\n if (!existing) {\n const tomb = tombstoneHlc(db, op);\n if (tomb !== null && !wins(op.hlc, tomb)) {\n return { changed: false, appliedFields: [], skipped: \"older-than-tombstone\" };\n }\n const id = ensureWorkstreamRow(db, name);\n const applied = applyFieldLww(db, op, \"workstreams\", id, entries);\n return { changed: true, appliedFields: applied };\n }\n const applied = applyFieldLww(db, op, \"workstreams\", existing.id, entries);\n return applied.length > 0\n ? { changed: true, appliedFields: applied }\n : { changed: false, appliedFields: [], skipped: \"older-than-current\" };\n}\n\n/** GROW-ONLY SET. A note is written once and never updated, so there is\n * no conflict to resolve — only \"is it already here\".\n *\n * IDENTITY IS THE NOTE'S CONTENT, not a surrogate id. A note's local\n * `task_notes.id` is assigned by whichever machine inserted it, so the\n * same logical note has different ids on different machines and the id\n * cannot be the identity. The op key embeds the ORIGIN id\n * (`demo/a#12`), which identifies it on its origin machine, but a peer\n * cannot map that onto a local row without storing a mapping table.\n *\n * So identity is `(task, author, content, created_at)`. Notes are\n * immutable, and every copy of one carries the created_at its origin\n * stamped, so applying a note that is already here is a no-op.\n *\n * `created_at` is in the identity because text alone is not unique.\n * Machine-written notes repeat: the reaper writes the same \"previous\n * owner gone\" line each time it reaps a task, and dispatch writes\n * \"CLAIM: dispatch\" on every claim. Keyed on text alone, a repeat\n * collapsed into the first copy on every peer while the origin kept\n * both, so note counts drifted apart one repeat at a time (a real\n * fleet: 6359 vs 6360). Two notes identical to the millisecond still\n * converge to one row, which is a dedupe rather than a loss.\n *\n * Undo, migrations and reprojection re-emit a note with the created_at\n * it already had, so they still land on the existing row. */\nfunction applyNotePut(db: Db, op: Op): ApplyResult {\n const { taskKey } = parseNoteKey(op.key);\n const taskId = taskRowId(db, taskKey);\n if (taskId === null) {\n // Parent task not here — either its op has not arrived yet, or it\n // was deleted. Notes are FK-bound to a task, so there is nowhere to\n // put this. Skipped rather than fatal: re-reading the peer's segment\n // replays the task op first and this lands then.\n return { changed: false, appliedFields: [], skipped: \"absent\" };\n }\n\n const entries = decodePayload(op.payload);\n const author = entries.find(([f]) => f === \"author\")?.[1] ?? null;\n const content = entries.find(([f]) => f === \"content\")?.[1] ?? \"\";\n const stamped = entries.find(([f]) => f === \"created_at\")?.[1];\n const createdAt = stamped ?? new Date().toISOString();\n const authorText = author === null ? null : String(author);\n\n // A put without created_at (capture always writes one) is matched on\n // text alone: stamping it with \"now\" and then matching on that would\n // make every re-delivery look new.\n const already = prepareCached(\n db,\n `SELECT 1 AS present FROM task_notes\n WHERE task_id = @taskId AND content = @content\n AND COALESCE(author, '') = COALESCE(@author, '')\n AND (@stamped IS NULL OR created_at = @stamped)\n LIMIT 1`,\n ).get({\n taskId,\n content: String(content),\n author: authorText,\n stamped: stamped === undefined || stamped === null ? null : String(stamped),\n }) as { present: number } | undefined;\n if (already) return { changed: false, appliedFields: [], skipped: \"already-present\" };\n\n // A note deleted by a NEWER tombstone must not be re-inserted by a\n // late-arriving put. Same comparison as every other entity.\n const tomb = tombstoneHlc(db, op);\n if (tomb !== null && !wins(op.hlc, tomb)) {\n return { changed: false, appliedFields: [], skipped: \"older-than-tombstone\" };\n }\n\n prepareCached(\n db,\n \"INSERT INTO task_notes (task_id, author, content, created_at) VALUES (?, ?, ?, ?)\",\n ).run(taskId, authorText, String(content), String(createdAt));\n return { changed: true, appliedFields: [\"content\"] };\n}\n\n/** LWW-ELEMENT-SET. An edge is a set member: present or absent, with no\n * fields worth merging. So add and remove each carry an HLC and the\n * newer one wins — a remove followed by a re-add converges to present,\n * and the reverse converges to absent, in either arrival order. */\nfunction applyEdgePut(db: Db, op: Op): ApplyResult {\n const { blocker, blocked } = parseEdgeKey(op.key);\n const fromId = taskRowId(db, blocker);\n const toId = taskRowId(db, blocked);\n if (fromId === null || toId === null) {\n return { changed: false, appliedFields: [], skipped: \"absent\" };\n }\n const removedAt = anyHlc(db, op, \"del\");\n if (removedAt !== null && !wins(op.hlc, removedAt)) {\n return { changed: false, appliedFields: [], skipped: \"older-than-tombstone\" };\n }\n const existing = prepareCached(\n db,\n \"SELECT 1 AS present FROM task_edges WHERE from_task_id = ? AND to_task_id = ?\",\n ).get(fromId, toId) as { present: number } | undefined;\n if (existing) return { changed: false, appliedFields: [], skipped: \"already-present\" };\n\n const entries = decodePayload(op.payload);\n const createdAt = entries.find(([f]) => f === \"created_at\")?.[1] ?? new Date().toISOString();\n prepareCached(\n db,\n \"INSERT INTO task_edges (from_task_id, to_task_id, created_at) VALUES (?, ?, ?)\",\n ).run(fromId, toId, String(createdAt));\n return { changed: true, appliedFields: [\"created_at\"] };\n}\n\n/** A tombstone. Applies iff it is newer than every put for this key —\n * the mirror image of the put path's tombstone check, which is why\n * there is no special casing between them. */\nfunction applyDel(db: Db, op: Op): ApplyResult {\n const newestPut = anyHlc(db, op, \"put\");\n if (newestPut !== null && !wins(op.hlc, newestPut)) {\n // A put NEWER than this delete already happened: the row is alive\n // and must stay so. The tombstone is still recorded in `ops` (by\n // the caller), so it participates in later comparisons.\n return { changed: false, appliedFields: [], skipped: \"older-than-current\" };\n }\n\n switch (op.entity) {\n case \"workstream\": {\n // FK CASCADE removes the tasks, notes and edges beneath it.\n const r = prepareCached(db, \"DELETE FROM workstreams WHERE name = ?\").run(op.key);\n return {\n changed: r.changes > 0,\n appliedFields: [],\n ...(r.changes > 0 ? {} : { skipped: \"absent\" as const }),\n };\n }\n case \"task\": {\n const rowId = taskRowId(db, op.key);\n if (rowId === null) return { changed: false, appliedFields: [], skipped: \"absent\" };\n prepareCached(db, \"DELETE FROM tasks WHERE id = ?\").run(rowId);\n return { changed: true, appliedFields: [] };\n }\n case \"note\": {\n const { taskKey } = parseNoteKey(op.key);\n const taskId = taskRowId(db, taskKey);\n if (taskId === null) return { changed: false, appliedFields: [], skipped: \"absent\" };\n // A note's local surrogate id is not the origin's, so delete by\n // the content identity the grow-only insert used. A self-describing\n // tombstone (capture writes the full row when no put shares its\n // key, drift-641) carries that identity itself; otherwise read it\n // from the put under the same key.\n let entries = decodePayload(op.payload);\n if (!entries.some(([f, v]) => f === \"content\" && v !== null)) {\n const src = prepareCached(\n db,\n `SELECT payload FROM ops\n WHERE entity = 'note' AND key = @key AND op = 'put'\n AND ${LEGACY_LOG_ONLY_SQL_EXCLUSION}\n ORDER BY hlc DESC LIMIT 1`,\n ).get({ key: op.key }) as { payload: string } | undefined;\n if (!src) return { changed: false, appliedFields: [], skipped: \"absent\" };\n entries = decodePayload(src.payload);\n }\n const content = entries.find(([f]) => f === \"content\")?.[1] ?? \"\";\n const author = entries.find(([f]) => f === \"author\")?.[1] ?? null;\n const createdAt = entries.find(([f]) => f === \"created_at\")?.[1] ?? null;\n // created_at narrows the delete to this note, not every repeat of\n // its text. A put without one (never written by capture) falls\n // back to text alone.\n const r = prepareCached(\n db,\n `DELETE FROM task_notes\n WHERE task_id = @taskId AND content = @content\n AND COALESCE(author, '') = COALESCE(@author, '')\n AND (@createdAt IS NULL OR created_at = @createdAt)`,\n ).run({\n taskId,\n content: String(content),\n author: author === null ? null : String(author),\n createdAt: createdAt === null ? null : String(createdAt),\n });\n return {\n changed: r.changes > 0,\n appliedFields: [],\n ...(r.changes > 0 ? {} : { skipped: \"absent\" as const }),\n };\n }\n case \"edge\": {\n const { blocker, blocked } = parseEdgeKey(op.key);\n const fromId = taskRowId(db, blocker);\n const toId = taskRowId(db, blocked);\n if (fromId === null || toId === null) {\n return { changed: false, appliedFields: [], skipped: \"absent\" };\n }\n const r = prepareCached(\n db,\n \"DELETE FROM task_edges WHERE from_task_id = ? AND to_task_id = ?\",\n ).run(fromId, toId);\n return {\n changed: r.changes > 0,\n appliedFields: [],\n ...(r.changes > 0 ? {} : { skipped: \"absent\" as const }),\n };\n }\n default:\n // 'message' has no portable table to delete from.\n return { changed: false, appliedFields: [], skipped: \"absent\" };\n }\n}\n\n// ─── The seam ─────────────────────────────────────────────────────────\n\n/**\n * Apply one op to the portable tables.\n *\n * SYNCHRONOUS, for the same reason `withOpContext` is: the op context is\n * a per-connection temp table, so two interleaved async apply scopes\n * would clobber each other's `applying` flag with no way to tell whose\n * suppression was in force. Keeping this sync makes that\n * unrepresentable rather than merely discouraged.\n *\n * Runs inside `withCaptureSuppressed`, which is THE echo guard: without\n * it, writing a peer's op to `tasks` would fire the capture trigger,\n * mint a fresh local op, flush that back to the peer, and loop forever.\n *\n * Does NOT insert the op into `ops` — that is the caller's job (v2-sync,\n * which owns segment bookkeeping and the (machine_id, hlc) dedupe). This\n * function is deliberately only \"make the tables reflect this op\", so it\n * can be called on a replay of ops already in the log without\n * double-recording them. Provenance queries exclude the op's own HLC\n * precisely so the order of those two steps does not matter.\n *\n * Idempotent: applying the same op twice makes no second change, which\n * is what lets `mu sync --repair` be nothing more than \"re-read that\n * peer's segment from zero\".\n */\nexport function applyOp(db: Db, op: Op): ApplyResult {\n if (isKnownMachineLocalEntity(op.entity)) throw new OpEntityNotSyncedError(op.entity);\n // An entity this build does not recognise is a FORWARD-COMPATIBLE\n // no-op, projected nowhere, exactly like 'message'. Recording the op\n // is the caller's step and is what preserves it for a later build\n // (and for `mu rebuild`) without blocking every op behind it.\n if (!isSyncedEntity(op.entity)) return { changed: false, appliedFields: [] };\n\n return withCaptureSuppressed(db, () => {\n if (op.op === \"del\") return applyDel(db, op);\n\n switch (op.entity) {\n case \"workstream\":\n return applyWorkstreamPut(db, op);\n case \"task\":\n // Own transaction (a savepoint when nested): the per-field\n // UPDATEs pass through an invalid (status, substate) pair, and\n // the deferred FK only tolerates that inside a transaction. In\n // autocommit it would check each UPDATE on its own.\n return db.transaction(() => applyTaskPut(db, op)).immediate();\n case \"note\":\n return applyNotePut(db, op);\n case \"edge\":\n return applyEdgePut(db, op);\n case \"message\":\n // Log lines live in `ops` only; there is no portable table to\n // project them into. Recording the op IS applying it, and that\n // is the caller's step.\n return { changed: false, appliedFields: [] };\n default:\n // Unreachable: the union is closed and every member is handled\n // above. Kept as a total return rather than a throw so an\n // unrecognised entity can never wedge an ingest.\n return { changed: false, appliedFields: [] };\n }\n });\n}\n\n// ─── Deferred projection: the out-of-order arrival repair ─────────────\n\n/**\n * Re-project note and edge ops that could not land when they arrived.\n *\n * THE BUG THIS EXISTS TO FIX (v2-sync-workflow-integration)\n * ---------------------------------------------------------\n * `applyNotePut` / `applyEdgePut` return `skipped:\"absent\"` when the\n * task they hang off is not here YET. That is the right answer at that\n * moment — there is genuinely nowhere to put the row — and their\n * comments promised \"re-reading the peer's segment replays the task op\n * first and this lands then\". It does not. `ingestSegment` counts an\n * `absent` skip as a successful apply and ADVANCES THE WATERMARK past\n * the line, so the segment is never re-read and the note or edge is\n * never projected. The op IS recorded in local `ops`, so the data is\n * not lost — but the live tables silently diverge, permanently.\n *\n * It is not a corner case. `flushSegment` ships only LOCAL ops, so a\n * machine's segment routinely holds `edge`/`note` ops referring to\n * tasks created in ANOTHER machine's segment, and `syncPass` reads\n * peers in `discoverPeers` order — `localeCompare` over random UUID\n * filenames. Whether the parent arrives first is a coin flip. Measured\n * on 8 fresh fleets: 5 dropped the edge, 3 kept it, correlating exactly\n * with segment filename sort order.\n *\n * WHY REPAIR FROM THE LOG RATHER THAN A RETRY QUEUE\n * -------------------------------------------------\n * A queue of \"ops to try again\" would be a second source of truth that\n * can disagree with `ops` — the same denormalisation this module's\n * header rejects for provenance, and it would be lost across processes\n * (mu is one short-lived process per invocation, so an in-memory list\n * only ever fixes ops deferred within a SINGLE pass; the parent often\n * arrives the next day). The ops log already knows everything needed,\n * so this asks it directly: which note/edge puts are resolvable NOW but\n * are not projected?\n *\n * \"Resolvable now\" is doing real work in both queries. Restricting to\n * ops whose parent task rows EXIST means an op orphaned for good (its\n * task was deleted) is not retried on every pass forever, and excluding\n * keys with a NEWER `del` means a legitimately removed edge or note is\n * not resurrected. What is left is exactly the bug's footprint, which\n * in a healthy DB is the empty set — so the normal cost is two indexed\n * queries returning zero rows.\n *\n * Returns the number of ops that changed something, so callers can\n * report it and tests can assert the repair actually fired.\n */\nexport function reprojectDeferredOps(db: Db): number {\n installOpKeyFunctions(db);\n const rows = [\n ...(db\n .prepare(\n `SELECT o.hlc, o.machine_id, o.group_id, o.actor, o.intent, o.entity,\n o.key, o.op, o.payload\n FROM ops o\n JOIN tasks ft ON ft.local_id = edge_local(o.key, 0)\n JOIN workstreams fw ON fw.id = ft.workstream_id AND fw.name = edge_ws(o.key, 0)\n JOIN tasks tt ON tt.local_id = edge_local(o.key, 1)\n JOIN workstreams tw ON tw.id = tt.workstream_id AND tw.name = edge_ws(o.key, 1)\n WHERE o.entity = 'edge' AND o.op = 'put'\n AND NOT EXISTS (SELECT 1 FROM task_edges e\n WHERE e.from_task_id = ft.id AND e.to_task_id = tt.id)\n AND NOT EXISTS (SELECT 1 FROM ops d\n WHERE d.entity = 'edge' AND d.key = o.key\n AND d.op = 'del' AND d.hlc > o.hlc)`,\n )\n .all() as OpRow[]),\n ...(db\n .prepare(\n `SELECT o.hlc, o.machine_id, o.group_id, o.actor, o.intent, o.entity,\n o.key, o.op, o.payload\n FROM ops o\n JOIN tasks t ON t.local_id = note_local(o.key)\n JOIN workstreams w ON w.id = t.workstream_id AND w.name = note_ws(o.key)\n WHERE o.entity = 'note' AND o.op = 'put'\n AND NOT EXISTS (SELECT 1 FROM task_notes n\n WHERE n.task_id = t.id\n AND n.content = COALESCE(json_extract(o.payload, '$.content'), '')\n AND COALESCE(n.author, '')\n = COALESCE(json_extract(o.payload, '$.author'), '')\n AND n.created_at = json_extract(o.payload, '$.created_at'))\n AND NOT EXISTS (SELECT 1 FROM ops d\n WHERE d.entity = 'note' AND d.key = o.key\n AND d.op = 'del' AND d.hlc > o.hlc)`,\n )\n .all() as OpRow[]),\n ];\n if (rows.length === 0) return 0;\n\n let changed = 0;\n for (const row of rows.sort((a, b) => compareHlc(a.hlc, b.hlc))) {\n if (applyOp(db, rowToOp(row)).changed) changed += 1;\n }\n return changed;\n}\n\n/** Raw `ops` row shape, as the two repair queries above return it. */\ninterface OpRow {\n hlc: string;\n machine_id: string;\n group_id: string;\n actor: string | null;\n intent: string | null;\n entity: string;\n key: string;\n op: string;\n payload: string;\n}\n\nfunction rowToOp(row: OpRow): Op {\n return {\n hlc: row.hlc,\n machineId: row.machine_id,\n groupId: row.group_id,\n actor: row.actor,\n intent: row.intent,\n entity: row.entity,\n key: row.key,\n op: row.op === \"del\" ? \"del\" : \"put\",\n payload: row.payload,\n };\n}\n\n/**\n * Register the four key-splitting SQL functions the repair queries use.\n *\n * Natural keys are structured text (`<ws>/<local_id>`,\n * `<blocker>-><blocked>`, `<taskKey>#<originId>`) and the parsers here\n * already handle the awkward cases — a local_id containing `/`, an id\n * ending in `-` so `a-->b` splits correctly. Rather than reimplement\n * that splitting in SQL string functions (where it would be a second,\n * subtly different parser), the SAME TypeScript parsers are exposed to\n * SQLite. Deterministic, so SQLite may cache and index against them.\n *\n * Registered lazily by `reprojectDeferredOps` rather than by `openDb`,\n * because `db.ts` imports `capture.ts` and `apply.ts` imports `db.ts` —\n * so an `openDb`-side registration would need db.ts to import this\n * module and close a runtime import cycle. (capture.ts's header records\n * what that costs: `node dist/cli.js` printing nothing at all.)\n * Re-registration is a documented no-op-ish overwrite in better-sqlite3,\n * verified, so calling it per repair pass is safe and cheap.\n */\nfunction installOpKeyFunctions(db: Db): void {\n const safe = <T>(f: () => T): T | null => {\n try {\n return f();\n } catch {\n // A malformed key is not this query's problem: return NULL so the\n // JOIN drops the row rather than failing the whole ingest.\n return null;\n }\n };\n const opts = { deterministic: true, varargs: false } as const;\n db.function(\"edge_ws\", opts, (key: unknown, side: unknown) =>\n safe(() => {\n const parts = parseEdgeKey(String(key));\n return parseTaskKey(Number(side) === 0 ? parts.blocker : parts.blocked).workstream;\n }),\n );\n db.function(\"edge_local\", opts, (key: unknown, side: unknown) =>\n safe(() => {\n const parts = parseEdgeKey(String(key));\n return parseTaskKey(Number(side) === 0 ? parts.blocker : parts.blocked).localId;\n }),\n );\n db.function(\"note_ws\", opts, (key: unknown) =>\n safe(() => parseTaskKey(parseNoteKey(String(key)).taskKey).workstream),\n );\n db.function(\"note_local\", opts, (key: unknown) =>\n safe(() => parseTaskKey(parseNoteKey(String(key)).taskKey).localId),\n );\n}\n\n/**\n * Apply many ops in HLC order, inside one transaction.\n *\n * HLC order is what makes per-field LWW correct without any extra\n * bookkeeping: process oldest-first and each field simply ends up\n * holding the newest write. Callers may pass ops in arrival order.\n *\n * Grow-only entities are order-insensitive by construction, so a single\n * sort is enough for every rule here.\n */\nexport function applyOps(db: Db, ops: readonly Op[]): ApplyResult[] {\n const ordered = [...ops].sort((a, b) => compareHlc(a.hlc, b.hlc));\n const run = db.transaction(() => ordered.map((op) => applyOp(db, op)));\n return run.immediate();\n}\n","// mu — the segment manifest (`<machine>.manifest`): layer 4 of the\n// segment robustness layers, plus the fields the owner's flush trusts\n// instead of rescanning its own segment. Split out of segments.ts\n// (1500-LOC cap); segments.ts re-exports the public names.\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { type Sha256State, sha256Digest } from \"./sha256-resumable.js\";\n\n/** Segment filename suffix. */\nconst SEGMENT_EXT = \".jsonl\";\n/** Manifest filename suffix. */\nconst MANIFEST_EXT = \".manifest\";\n\n/** Whole-file verification sidecar. */\nexport interface SegmentManifest {\n v: number;\n machine: string;\n count: number;\n lastHlc: string | null;\n sha256: string;\n updatedAt: string;\n /** Bytes of the segment `sha256` covers. Written by the owner so its\n * next flush can trust this manifest instead of rescanning; absent in\n * manifests from older builds. */\n size?: number;\n /** The segment's mtime when this manifest was written (owner-local). */\n mtimeMs?: number;\n /** Running hash state after `size` bytes, so an append rehashes only\n * what it added. */\n shaState?: Sha256State;\n /** sha256 over the fields above (`manifestSeal`). The owner trusts\n * count/size/shaState only when it matches, so a torn or hand-edited\n * manifest falls back to the full scan instead of being persisted. */\n seal?: string;\n}\n\nexport function manifestPath(segment: string): string {\n return segment.replace(new RegExp(`${SEGMENT_EXT}$`), MANIFEST_EXT);\n}\n\n/** A manifest as this build writes it, with every field the owner's\n * fast path relies on. */\nexport type SealedManifest = SegmentManifest & {\n size: number;\n mtimeMs: number;\n shaState: Sha256State;\n seal: string;\n};\n\n/** sha256 over every field the owner's fast path trusts, in a fixed\n * order. Not a defence against a deliberate forger, who could\n * recompute it; it binds count, lastHlc, size and the hash state to\n * each other so a torn write or a hand edit of one field is caught. */\nexport function manifestSeal(m: Omit<SealedManifest, \"seal\" | \"updatedAt\">): string {\n return createHash(\"sha256\")\n .update(\n [\n m.v,\n m.machine,\n m.count,\n m.lastHlc ?? \"\",\n m.sha256,\n m.size,\n m.mtimeMs,\n m.shaState.h,\n m.shaState.n,\n m.shaState.tail,\n ].join(\"\\u001f\"),\n )\n .digest(\"hex\");\n}\n\nconst HEX64 = /^[0-9a-f]{64}$/;\n\n/**\n * True when the manifest's trusted fields agree with each other: well\n * formed, count is zero exactly when size is, the hash state covers\n * `size` bytes and finishes to `sha256`, and the seal matches. Cheap\n * (at most two SHA-256 blocks plus a hash of a few hundred bytes), and\n * it reads no segment bytes. Anything off sends the owner to the full\n * scan, which recounts, rehashes and rewrites the manifest, so a\n * malformed field is never carried into the next manifest.\n */\nexport function manifestSelfConsistent(m: SegmentManifest): m is SealedManifest {\n const { count, lastHlc, size, mtimeMs, shaState, seal } = m;\n if (!Number.isSafeInteger(count) || count < 0) return false;\n if (typeof size !== \"number\" || !Number.isSafeInteger(size) || size < 0) return false;\n if (typeof mtimeMs !== \"number\" || !Number.isFinite(mtimeMs)) return false;\n if (lastHlc !== null && typeof lastHlc !== \"string\") return false;\n if ((count === 0) !== (size === 0) || (count === 0) !== (lastHlc === null)) return false;\n if (typeof m.sha256 !== \"string\" || !HEX64.test(m.sha256)) return false;\n if (typeof seal !== \"string\" || !HEX64.test(seal)) return false;\n if (\n typeof shaState !== \"object\" ||\n shaState === null ||\n typeof shaState.h !== \"string\" ||\n !HEX64.test(shaState.h) ||\n shaState.n !== size ||\n typeof shaState.tail !== \"string\"\n ) {\n return false;\n }\n const tail = Buffer.from(shaState.tail, \"base64\");\n if (tail.length !== size % 64 || tail.toString(\"base64\") !== shaState.tail) return false;\n if (sha256Digest(shaState) !== m.sha256) return false;\n return manifestSeal({ ...m, size, mtimeMs, shaState }) === seal;\n}\n\n/** Write `fields` as the manifest of `segment`, stamped and sealed. */\nexport function writeManifestFile(\n segment: string,\n fields: Omit<SealedManifest, \"seal\" | \"updatedAt\">,\n): void {\n const manifest: SegmentManifest = {\n ...fields,\n updatedAt: new Date().toISOString(),\n seal: manifestSeal(fields),\n };\n writeFileSync(manifestPath(segment), `${JSON.stringify(manifest, null, 2)}\\n`, \"utf8\");\n}\n\n/** Read a segment's manifest, or null when absent/unparsable. */\nexport function readManifest(segment: string): SegmentManifest | null {\n const path = manifestPath(segment);\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as SegmentManifest;\n } catch {\n return null;\n }\n}\n","// mu — SHA-256 whose running state can be saved and resumed.\n//\n// Why not node:crypto: a `Hash` cannot be serialised, and every mu\n// invocation is a fresh process. The segment manifest carries the\n// sha256 of the WHOLE append-only segment, so re-hashing with\n// node:crypto made each flush O(file size) forever. Persisting the\n// running state next to the digest lets the next flush hash only the\n// bytes it appends. The digest is byte-identical to node:crypto's (see\n// test/sha256-resumable.test.ts), so peers verifying with node:crypto\n// see no difference.\n\n/** Serialisable running state: eight hash words (hex), bytes hashed so\n * far, and the partial trailing block not yet compressed (base64). */\nexport interface Sha256State {\n h: string;\n n: number;\n tail: string;\n}\n\nconst K = new Uint32Array([\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,\n]);\n\nconst INITIAL_H = \"6a09e667bb67ae853c6ef372a54ff53a510e527f9b05688c1f83d9ab5be0cd19\";\n\n/** State of a hash that has consumed no bytes. */\nexport function sha256Initial(): Sha256State {\n return { h: INITIAL_H, n: 0, tail: \"\" };\n}\n\nfunction wordsOf(hex: string): Uint32Array {\n const h = new Uint32Array(8);\n for (let i = 0; i < 8; i++) h[i] = Number.parseInt(hex.slice(i * 8, i * 8 + 8), 16);\n return h;\n}\n\nfunction hexOf(h: Uint32Array): string {\n let out = \"\";\n for (const word of h) out += word.toString(16).padStart(8, \"0\");\n return out;\n}\n\nconst W = new Uint32Array(64);\n\n/** Compress every whole 64-byte block of `data` from `offset` into `h`. */\nfunction compress(h: Uint32Array, data: Uint8Array, offset: number, end: number): void {\n let h0 = h[0] ?? 0;\n let h1 = h[1] ?? 0;\n let h2 = h[2] ?? 0;\n let h3 = h[3] ?? 0;\n let h4 = h[4] ?? 0;\n let h5 = h[5] ?? 0;\n let h6 = h[6] ?? 0;\n let h7 = h[7] ?? 0;\n for (let p = offset; p + 64 <= end; p += 64) {\n for (let i = 0; i < 16; i++) {\n const j = p + i * 4;\n W[i] =\n ((data[j] ?? 0) << 24) |\n ((data[j + 1] ?? 0) << 16) |\n ((data[j + 2] ?? 0) << 8) |\n (data[j + 3] ?? 0);\n }\n for (let i = 16; i < 64; i++) {\n const w15 = W[i - 15] ?? 0;\n const w2 = W[i - 2] ?? 0;\n const s0 = ((w15 >>> 7) | (w15 << 25)) ^ ((w15 >>> 18) | (w15 << 14)) ^ (w15 >>> 3);\n const s1 = ((w2 >>> 17) | (w2 << 15)) ^ ((w2 >>> 19) | (w2 << 13)) ^ (w2 >>> 10);\n W[i] = ((W[i - 16] ?? 0) + s0 + (W[i - 7] ?? 0) + s1) | 0;\n }\n let a = h0;\n let b = h1;\n let c = h2;\n let d = h3;\n let e = h4;\n let f = h5;\n let g = h6;\n let hh = h7;\n for (let i = 0; i < 64; i++) {\n const S1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));\n const ch = (e & f) ^ (~e & g);\n const t1 = (hh + S1 + ch + (K[i] ?? 0) + (W[i] ?? 0)) | 0;\n const S0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));\n const maj = (a & b) ^ (a & c) ^ (b & c);\n const t2 = (S0 + maj) | 0;\n hh = g;\n g = f;\n f = e;\n e = (d + t1) | 0;\n d = c;\n c = b;\n b = a;\n a = (t1 + t2) | 0;\n }\n h0 = (h0 + a) | 0;\n h1 = (h1 + b) | 0;\n h2 = (h2 + c) | 0;\n h3 = (h3 + d) | 0;\n h4 = (h4 + e) | 0;\n h5 = (h5 + f) | 0;\n h6 = (h6 + g) | 0;\n h7 = (h7 + hh) | 0;\n }\n h.set([h0, h1, h2, h3, h4, h5, h6, h7]);\n}\n\n/** Feed `data` into `state`, returning the new state. Pure. */\nexport function sha256Update(state: Sha256State, data: Uint8Array): Sha256State {\n const pending = Buffer.from(state.tail, \"base64\");\n const all = pending.length === 0 ? data : Buffer.concat([pending, data]);\n const h = wordsOf(state.h);\n const whole = all.length - (all.length % 64);\n compress(h, all, 0, whole);\n return {\n h: hexOf(h),\n n: state.n + data.length,\n tail: Buffer.from(all.subarray(whole)).toString(\"base64\"),\n };\n}\n\n/** Hex digest of everything fed into `state`. Does not mutate it. */\nexport function sha256Digest(state: Sha256State): string {\n const pending = Buffer.from(state.tail, \"base64\");\n const padLen = pending.length < 56 ? 64 : 128;\n const block = Buffer.alloc(padLen);\n pending.copy(block);\n block[pending.length] = 0x80;\n const bits = state.n * 8;\n block.writeUInt32BE(Math.floor(bits / 2 ** 32), padLen - 8);\n block.writeUInt32BE(bits >>> 0, padLen - 4);\n const h = wordsOf(state.h);\n compress(h, block, 0, padLen);\n return hexOf(h);\n}\n","// mu — segments: how ops LEAVE and ENTER a machine.\n//\n// THE ONE IDEA THAT MAKES THIS WORK\n// ---------------------------------\n// <MU_SYNC_DIR>/<machine_id>.jsonl\n//\n// Each machine APPENDS ONLY to its own segment and read-onlys every\n// other. No file is ever written by two machines, so there is no\n// file-level conflict, ever. That single property is what makes\n// Syncthing, rsync, scp, git, and a USB stick all adequate transport: it\n// removes the one thing every file-mover is bad at. There is nothing to\n// merge, so nothing can merge wrongly.\n//\n// TWO LOGS, ONLY ONE CRITICAL\n// ---------------------------\n// The CANONICAL log is the `ops` table inside mu.db: ACID, WAL,\n// crash-safe, written in the same transaction as the mutation it records.\n// A SEGMENT is DERIVED and REGENERABLE — literally `SELECT ... FROM ops` —\n// so losing one costs a re-flush and nothing else.\n//\n// That asymmetry is what licenses plain append-only files here, and it has\n// one concrete consequence worth stating because it looks like an\n// oversight: NO fsync ON APPEND. Losing the tail to power loss is\n// harmless, because the next flush re-derives it from the table. Paying\n// for durability twice would be paying for nothing.\n//\n// WHY NOT A SQLITE FILE PER PEER\n// ------------------------------\n// Rejected deliberately (design note): a `-wal`/`-shm` sidecar in a synced\n// folder is THE canonical way to corrupt a SQLite DB; a torn transfer is\n// fatal to the WHOLE file rather than costing one JSONL line; and page\n// churn defeats rsync/Syncthing delta transfer, whereas an append-only\n// file is the best case for it.\n//\n// ROBUSTNESS: FOUR LAYERS\n// -----------------------\n// The pattern every append-only log uses (RocksDB, Kafka, etcd,\n// SQLite-WAL): detect the bad record, stop at it, refetch the tail later.\n// Never guess, never skip-and-continue past damage.\n//\n// 1. JSON.parse failure = torn write. FREE, and truncation is the\n// DOMINANT failure mode (a transfer caught in flight).\n// 2. crc32 per line = bit rot that JSON.parse would happily\n// accept. Belt-and-braces, not load-bearing — see the note's\n// honesty about this. ~5 LOC via node:zlib.\n// 3. Monotonic hlc = reordering, duplication, and silent\n// mid-file truncation. Structural, zero extra bytes.\n// 4. Manifest sidecar = whole-file verification (count, last_hlc,\n// sha256). REPORTS, does not halt: it fires when every remaining\n// line is individually valid (a truncation on a line boundary), so\n// the prefix is safe to apply and the fix is a fresh copy.\n//\n// On a bad record (layers 1-3) we stop at the last GOOD one and advance\n// the watermark only that far, then report it. Because `UNIQUE (machine_id, hlc)` makes\n// ingest idempotent, the universal repair is \"re-read from zero\" — so a\n// damaged segment is recoverable, never fatal.\n\nimport { createHash } from \"node:crypto\";\nimport {\n appendFileSync,\n closeSync,\n existsSync,\n mkdirSync,\n openSync,\n readdirSync,\n readFileSync,\n readSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join, resolve, sep } from \"node:path\";\nimport { crc32 } from \"node:zlib\";\nimport { applyOp, type Op, OpEntityNotSyncedError, reprojectDeferredOps } from \"./apply.js\";\nimport { type Db, prepareCached, SYNCED_ENTITIES } from \"./db.js\";\nimport { locksDir, withFileLock } from \"./file-lock.js\";\nimport { receiveHlc } from \"./hlc.js\";\nimport { isLegacyLogOnlyIntent } from \"./legacy-ops.js\";\nimport {\n manifestPath,\n manifestSelfConsistent,\n readManifest,\n writeManifestFile,\n} from \"./segment-manifest.js\";\nimport { type Sha256State, sha256Digest, sha256Initial, sha256Update } from \"./sha256-resumable.js\";\n\nexport { manifestSeal, readManifest, type SegmentManifest } from \"./segment-manifest.js\";\n\n/** Current segment line format. Bumped only on a breaking shape change;\n * a reader that sees a version it does not know REFUSES the line rather\n * than guessing at its meaning. */\nexport const SEGMENT_FORMAT_VERSION = 1;\n\n/** Segment filename suffix. */\nconst SEGMENT_EXT = \".jsonl\";\n\n/** One serialized op, as it appears on a line of a segment. */\nexport interface SegmentLine {\n v: number;\n hlc: string;\n machine: string;\n group: string;\n intent: string | null;\n actor: string | null;\n entity: string;\n key: string;\n op: \"put\" | \"del\";\n payload: unknown;\n crc: string;\n}\n\n/** Why a segment line was rejected. Reported, never silently swallowed. */\nexport type SegmentDefectKind =\n | \"torn-write\"\n | \"manifest-mismatch\"\n | \"crc-mismatch\"\n | \"non-monotonic-hlc\"\n | \"unknown-version\"\n | \"malformed-shape\"\n | \"entity-not-synced\"\n | \"duplicate-op\";\n\nexport interface SegmentDefect {\n kind: SegmentDefectKind;\n /** 1-based line number within the segment. */\n line: number;\n detail: string;\n}\n\n// ─── sync dir + naming ────────────────────────────────────────────────\n\n/**\n * The sync directory, or null when sync is not configured.\n *\n * Null is the normal single-machine case, and every entry point here\n * treats it as \"do nothing, cost nothing\" rather than an error. Sync is\n * opt-in by setting one env var; there is no config file and no\n * membership list (see `discoverPeers`).\n */\nexport function syncDir(): string | null {\n const dir = process.env.MU_SYNC_DIR;\n if (dir === undefined || dir.trim() === \"\") return null;\n refuseUserSyncDirDuringTests(dir);\n return dir;\n}\n\n/**\n * The sibling of `refuseUserDbDuringTests` in src/db.ts, for the OTHER\n * piece of real state a stray test can reach.\n *\n * Pointing MU_DB_PATH at a temp file is not enough to contain a test:\n * sync is ambient, so the first flush stamps the temp DB's fresh\n * `machine_id` onto a segment in whatever MU_SYNC_DIR names. On a dev\n * box that is the user's REAL sync folder, and the result is a\n * permanent phantom peer — `mu sync` lists a machine that never\n * existed, forever, because absence of a segment is the only way a\n * peer disappears and nothing prunes them.\n *\n * Observed: eight such phantoms in ~/mu, each holding one op from a\n * throwaway `workstream init`. They came from the documented\n * smoke-test recipe (`MU_DB_PATH=/tmp/mu-smoke.db mu <verb>`), which\n * overrides the DB and says nothing about the sync dir.\n *\n * So: under a test runner, refuse a sync dir that is not clearly\n * disposable. Tests that exercise sync legitimately already point at a\n * per-test temp dir (mkdtemp under $TMPDIR), which is allowed; the\n * refusal only fires for a path outside it, which is by definition\n * somebody's real folder. Production never sets VITEST, so this is a\n * no-op for the shipped CLI.\n */\nfunction refuseUserSyncDirDuringTests(dir: string): void {\n const inTest = process.env.VITEST !== undefined || process.env.NODE_ENV === \"test\";\n if (!inTest) return;\n const resolved = resolve(dir);\n const temp = resolve(tmpdir());\n if (resolved === temp || resolved.startsWith(temp + sep)) return;\n throw new Error(\n `syncDir refused: tests must NEVER flush ops into a real sync dir (MU_SYNC_DIR=${resolved}). ` +\n `Doing so writes a segment named after this run's machine_id and leaves a permanent phantom peer. ` +\n `Point MU_SYNC_DIR at a mkdtemp() path under ${temp}, or leave it unset (test/_setup.ts clears it by default).`,\n );\n}\n\n/** This machine's id — the identity every op it writes is stamped with. */\nexport function localMachineId(db: Db): string {\n const row = db.prepare(\"SELECT machine_id FROM machine_identity WHERE id = 1\").get() as\n | { machine_id: string }\n | undefined;\n if (row === undefined) throw new Error(\"machine_identity row missing; not a mu DB\");\n return row.machine_id;\n}\n\n/** Path of a machine's own segment inside `dir`. */\nexport function segmentPath(dir: string, machineId: string): string {\n return join(dir, `${machineId}${SEGMENT_EXT}`);\n}\n\n// ─── framing ──────────────────────────────────────────────────────────\n\n/**\n * Canonical serialization the crc is computed over.\n *\n * Field order is FIXED here rather than taken from object key order, so\n * two machines (or two Node versions) cannot disagree about the bytes and\n * produce a spurious mismatch. `payload` is embedded as its stored JSON\n * TEXT, verbatim, for the same reason: re-serializing a parsed object\n * risks key reordering and number reformatting.\n */\nfunction canonicalBytes(line: Omit<SegmentLine, \"crc\">, payloadText: string): string {\n return [\n String(line.v),\n line.hlc,\n line.machine,\n line.group,\n line.intent ?? \"\",\n line.actor ?? \"\",\n line.entity,\n line.key,\n line.op,\n payloadText,\n ].join(\"\\u001f\"); // Unit Separator: cannot occur in any of these fields\n}\n\nfunction computeCrc(line: Omit<SegmentLine, \"crc\">, payloadText: string): string {\n return crc32(canonicalBytes(line, payloadText)).toString(16).padStart(8, \"0\");\n}\n\n/**\n * `ops.payload` is TEXT that is *usually* JSON but is not guaranteed to\n * be: `appendLog` has always accepted a bare prose payload (entity\n * 'message' via `mu log \"text\"`), and pre-1.0 rows carry plenty of it.\n * Embedding such text raw produced `\"payload\":Added 5 tasks, ...` — a\n * line that is not JSON at all, which every later read then reported as\n * a torn write, on every single mu invocation, forever (the segment is\n * regenerated from `ops`, so the repair re-emitted the same bad bytes).\n *\n * So: pass valid JSON through verbatim (byte-preserving, which is what\n * the crc contract needs), and encode anything else as a JSON string.\n */\nfunction payloadTextFor(payload: string): string {\n try {\n JSON.parse(payload);\n return payload;\n } catch {\n return JSON.stringify(payload);\n }\n}\n\n/** Serialize one op row to a segment line (without its trailing newline). */\nexport function encodeSegmentLine(op: {\n hlc: string;\n machineId: string;\n groupId: string;\n intent: string | null;\n actor: string | null;\n entity: string;\n key: string;\n op: \"put\" | \"del\";\n payload: string;\n}): string {\n const base: Omit<SegmentLine, \"crc\"> = {\n v: SEGMENT_FORMAT_VERSION,\n hlc: op.hlc,\n machine: op.machineId,\n group: op.groupId,\n intent: op.intent,\n actor: op.actor,\n entity: op.entity,\n key: op.key,\n op: op.op,\n payload: null, // replaced below; kept out of the crc input shape\n };\n const payloadText = payloadTextFor(op.payload);\n const crc = computeCrc(base, payloadText);\n // Assemble by hand so `payload` is embedded as raw JSON rather than\n // being re-encoded, keeping the bytes the crc covered.\n return `{\"v\":${base.v},\"hlc\":${JSON.stringify(base.hlc)},\"machine\":${JSON.stringify(\n base.machine,\n )},\"group\":${JSON.stringify(base.group)},\"intent\":${JSON.stringify(\n base.intent,\n )},\"actor\":${JSON.stringify(base.actor)},\"entity\":${JSON.stringify(\n base.entity,\n )},\"key\":${JSON.stringify(base.key)},\"op\":${JSON.stringify(\n base.op,\n )},\"payload\":${payloadText},\"crc\":${JSON.stringify(crc)}}`;\n}\n\n/** Outcome of decoding one line. */\ntype DecodeResult =\n | { ok: true; line: SegmentLine; payloadText: string }\n | { ok: false; kind: SegmentDefectKind; detail: string };\n\n/**\n * Decode and verify one line.\n *\n * Layers 1 and 2 both live here. Layer 1 (JSON.parse) is what actually\n * fires in practice — a truncated transfer leaves a partial line, which\n * cannot parse. Layer 2 (crc) only catches damage that leaves valid JSON,\n * i.e. bit rot inside a string or number.\n */\nfunction decodeLine(raw: string): DecodeResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n // LAYER 1: torn write. The dominant failure mode, and free.\n //\n // But only call it TORN when the line actually looks cut off. A\n // complete line that does not parse has a different cause (a writer\n // bug, or a hand edit) and a different remediation, and mislabelling\n // it sends the reader hunting for a crash-during-write that never\n // happened.\n const detail = err instanceof Error ? err.message : String(err);\n return looksComplete(raw)\n ? { ok: false, kind: \"malformed-shape\", detail: `complete line is not valid JSON: ${detail}` }\n : { ok: false, kind: \"torn-write\", detail };\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return { ok: false, kind: \"malformed-shape\", detail: \"line is not a JSON object\" };\n }\n const obj = parsed as Record<string, unknown>;\n\n if (typeof obj.v !== \"number\") {\n return { ok: false, kind: \"malformed-shape\", detail: \"missing numeric 'v'\" };\n }\n if (obj.v !== SEGMENT_FORMAT_VERSION) {\n // Refuse rather than guess: a future version may mean different\n // things by the same field names.\n return {\n ok: false,\n kind: \"unknown-version\",\n detail: `segment format v${obj.v}, this mu understands v${SEGMENT_FORMAT_VERSION}`,\n };\n }\n for (const field of [\"hlc\", \"machine\", \"group\", \"entity\", \"key\", \"op\", \"crc\"]) {\n if (typeof obj[field] !== \"string\") {\n return { ok: false, kind: \"malformed-shape\", detail: `missing string '${field}'` };\n }\n }\n const opKind = obj.op;\n if (opKind !== \"put\" && opKind !== \"del\") {\n return { ok: false, kind: \"malformed-shape\", detail: `bad op '${String(opKind)}'` };\n }\n if (!(\"payload\" in obj)) {\n return { ok: false, kind: \"malformed-shape\", detail: \"missing 'payload'\" };\n }\n\n // Recover the payload's ORIGINAL text from the raw line so the crc is\n // computed over the same bytes the writer covered. Re-serializing the\n // parsed value could reorder keys and would false-positive.\n const payloadText = extractPayloadText(raw);\n if (payloadText === null) {\n return { ok: false, kind: \"malformed-shape\", detail: \"could not locate payload text\" };\n }\n\n const line: SegmentLine = {\n v: obj.v,\n hlc: obj.hlc as string,\n machine: obj.machine as string,\n group: obj.group as string,\n intent: typeof obj.intent === \"string\" ? obj.intent : null,\n actor: typeof obj.actor === \"string\" ? obj.actor : null,\n entity: obj.entity as string,\n key: obj.key as string,\n op: opKind,\n payload: obj.payload,\n crc: obj.crc as string,\n };\n\n // LAYER 2: crc over the canonical bytes. Belt-and-braces.\n const expected = computeCrc({ ...line, payload: null }, payloadText);\n if (expected !== line.crc) {\n return {\n ok: false,\n kind: \"crc-mismatch\",\n detail: `crc ${line.crc} != computed ${expected} (bit rot?)`,\n };\n }\n return { ok: true, line, payloadText: storedPayloadFor(line, payloadText) };\n}\n\n/**\n * The text to store back into `ops.payload`, undoing the wrapping\n * `payloadTextFor` applied on the way out, so a peer's ops table holds\n * the bytes the origin's does and `mu log` renders a prose message as\n * prose rather than as a quoted string.\n *\n * The inverse is exact because the wrap rule is: wrap iff the stored\n * text is NOT valid JSON. So unwrap iff the line's payload is a JSON\n * string whose contents are NOT valid JSON — anything else was passed\n * through verbatim and must stay that way.\n */\nfunction storedPayloadFor(line: SegmentLine, payloadText: string): string {\n if (typeof line.payload !== \"string\") return payloadText;\n try {\n JSON.parse(line.payload);\n return payloadText;\n } catch {\n return line.payload;\n }\n}\n\n/** Whether a line carries the trailing framing `encodeSegmentLine`\n * always writes. A transfer caught in flight cannot: it stops wherever\n * the bytes stopped. */\nfunction looksComplete(raw: string): boolean {\n return raw.trimEnd().endsWith(\"}\") && raw.includes(',\"crc\":\"');\n}\n\n/** Slice out the raw `\"payload\":<json>` text, between its key and the\n * trailing `,\"crc\":`. Written by `encodeSegmentLine`, so the anchors are\n * exact rather than heuristic. */\nfunction extractPayloadText(raw: string): string | null {\n const start = raw.indexOf('\"payload\":');\n if (start < 0) return null;\n const end = raw.lastIndexOf(',\"crc\":');\n if (end <= start) return null;\n return raw.slice(start + '\"payload\":'.length, end);\n}\n\n// ─── flush: ops -> my segment ─────────────────────────────────────────\n\nexport interface FlushResult {\n /** Absolute path written, or null when sync is not configured. */\n segmentPath: string | null;\n /** Ops appended by this call. */\n appended: number;\n /** Total lines in the segment afterwards. */\n total: number;\n /** Ops skipped because their entity is machine-local. A full scan\n * (`verify`, or an untrusted manifest) counts every unflushed one; the\n * fast path counts only those up to the last op it appended, so a\n * no-op ambient flush reports 0 (see `pendingLines`). */\n skippedLocal: number;\n /**\n * Non-null when THIS MACHINE'S OWN segment was found defective past\n * its last good line (bit rot, a torn write not at EOF, a bad manual\n * edit). A segment is DERIVED and REGENERABLE from the canonical\n * `ops` table, so the repair is to truncate the file back to its\n * last good record and let the append below regenerate the rest —\n * never to append after the damage, which is the defect that caused\n * unbounded regrowth (each flush re-deriving the same ops from a\n * watermark frozen at the corruption point and stacking them after\n * it, forever). Surfaced here rather than printed directly: this\n * module does no I/O beyond the filesystem, callers decide how loud\n * to be (`mu sync`, `ambientFlush`).\n */\n selfRepaired: SegmentDefect | null;\n /**\n * True when ops were pending but another process held the segment\n * lock past the wait, so this call wrote nothing. The ops stay\n * unflushed in `ops` (the segment's last hlc is the watermark), and\n * the next flush appends them. Never set on a successful flush.\n */\n lockBusy?: boolean;\n}\n\n/**\n * Append this machine's not-yet-flushed ops to its own segment.\n *\n * FILTERING IS LOAD-BEARING. Only ops whose entity is in\n * `SYNCED_ENTITIES` are written. Machine-local ops (agent.*, workspace.*)\n * are captured and DO appear in `mu log`, but they must never reach a\n * segment: they carry pane ids and absolute paths that are meaningless,\n * and frequently wrong, on another machine. \"Not synced\" is not \"not\n * logged\".\n *\n * Also filters `machine_id = <me>`: a segment holds ONE machine's ops.\n * Ops ingested from a peer live in our `ops` table too, and re-flushing\n * them into our own segment would duplicate a peer's history under our\n * name — and would grow without bound as two machines echoed each other.\n *\n * The high-water mark is the last hlc already in the file (read from the\n * manifest when present, else derived by scanning), so flush is\n * incremental and idempotent: calling it twice appends nothing the second\n * time.\n */\n/** How long an ambient flush (every verb's post-body hook) waits for\n * the segment lock before deferring its ops to the next invocation.\n * An incremental append holds the lock for milliseconds, so 2 s\n * clears a deep queue of parallel appenders; a holder slower than\n * that is doing a full rescan, and the verb should not wait it out. */\nexport const AMBIENT_FLUSH_LOCK_WAIT_MS = 2_000;\n/** Explicit `mu sync` (verify) waits longer: the operator asked for the\n * flush and a full-scan holder takes seconds on a large segment. */\nexport const VERIFY_FLUSH_LOCK_WAIT_MS = 15_000;\n\nexport async function flushSegment(\n db: Db,\n dir: string | null = syncDir(),\n opts?: { verify?: boolean; lockWaitMs?: number },\n): Promise<FlushResult> {\n if (dir === null)\n return { segmentPath: null, appended: 0, total: 0, skippedLocal: 0, selfRepaired: null };\n\n const machineId = localMachineId(db);\n mkdirSync(dir, { recursive: true });\n const path = segmentPath(dir, machineId);\n\n // LOCK-FREE NO-OP. Most verbs write no synced op, and every mu\n // process used to queue on the lock below just to learn that, so N\n // parallel read-only verbs ran their flushes one after another. When\n // our own manifest still describes the file and no op is pending,\n // there is nothing to append and nothing to serialise against: a\n // concurrent appender either finished (we would see its manifest) or\n // has not, and its ops are its own to write.\n // `verify` (explicit `mu sync`) skips both shortcuts and decodes every\n // line, so damage that kept size, mtime and the last line intact\n // (bit rot mid-file) is still found and self-repaired somewhere.\n const verify = opts?.verify === true;\n const pre = verify ? null : trustedTail(path, machineId);\n if (pre !== null) {\n const pending = pendingLines(db, machineId, pre.lastHlc, false);\n if (pending.lines.length === 0) {\n return {\n segmentPath: path,\n appended: 0,\n total: pre.count,\n skippedLocal: pending.skippedLocal,\n selfRepaired: null,\n };\n }\n }\n\n // Serialise concurrent local flushes so two processes cannot interleave\n // partial lines in the same file. Keyed on the sync dir + machine, since\n // that names the single file being appended to.\n //\n // NEVER UNLOCKED. If the lock is still held at the deadline, write\n // nothing: an unlocked append can splice lines into another writer's,\n // or land after its self-repair truncate, and the ops are safe in the\n // DB anyway. The next invocation's flush appends them. A stale lock\n // (crashed holder) is still broken inside withFileLock.\n const lockName = createHash(\"sha256\")\n .update(`${dir}\\u001f${machineId}`)\n .digest(\"hex\")\n .slice(0, 16);\n return withFileLock(\n join(locksDir(), `segment-${lockName}.lock`),\n `segment:${machineId}`,\n () => Promise.resolve(flushLocked(db, path, machineId, verify)),\n {\n acquireTimeoutMs:\n opts?.lockWaitMs ?? (verify ? VERIFY_FLUSH_LOCK_WAIT_MS : AMBIENT_FLUSH_LOCK_WAIT_MS),\n onUnavailable: () => ({\n segmentPath: path,\n appended: 0,\n total: pre?.count ?? 0,\n skippedLocal: 0,\n selfRepaired: null,\n lockBusy: true,\n }),\n },\n );\n}\n\nfunction flushLocked(db: Db, path: string, machineId: string, verify: boolean): FlushResult {\n // Fast path: our own manifest still describes the file (same size and\n // mtime, last line decodes to its lastHlc), so count and high-water\n // mark come from it and nothing before the tail is read.\n const trusted = verify ? null : trustedTail(path, machineId);\n let count: number;\n let since: string | null;\n let selfRepaired: SegmentDefect | null = null;\n if (trusted !== null) {\n count = trusted.count;\n since = trusted.lastHlc;\n } else {\n const existing = readSegmentTail(path);\n count = existing.count;\n since = existing.lastHlc;\n\n // The defect this exists to close: readSegmentTail STOPS at the first\n // bad record either because it hit real damage or because it simply\n // ran out of well-formed lines. Those two cases used to be\n // indistinguishable to this function, and treating \"stopped early on\n // damage\" the same as \"reached clean EOF\" is exactly what let a\n // corrupted line grow the file forever: `since` never advanced past\n // it, so every flush re-selected and re-appended the same ops after\n // it again, unbounded. Distinguish them and heal our own segment\n // (truncate back to the last verified-good line) before appending\n // anything new, rather than stacking fresh data after the wound.\n if (existing.defect !== null) {\n selfRepaired = existing.defect;\n writeFileSync(\n path,\n existing.goodLines.length > 0 ? `${existing.goodLines.join(\"\\n\")}\\n` : \"\",\n \"utf8\",\n );\n }\n }\n\n const pending = pendingLines(db, machineId, since, trusted === null);\n let appended: Buffer | null = null;\n if (pending.lines.length > 0) {\n // NO fsync. The segment is derived from `ops`; a lost tail costs one\n // re-flush, so paying for durability here would buy nothing.\n appended = Buffer.from(`${pending.lines.join(\"\\n\")}\\n`, \"utf8\");\n appendFileSync(path, appended);\n } else if (!existsSync(path)) {\n // Create the file even with nothing to say, so peers can discover\n // this machine before its first change.\n writeFileSync(path, \"\", \"utf8\");\n }\n\n const total = count + pending.lines.length;\n const result = {\n segmentPath: path,\n appended: pending.lines.length,\n total,\n skippedLocal: pending.skippedLocal,\n selfRepaired,\n };\n // Nothing changed and the manifest already says so: leave it alone,\n // so a read-only verb does not hand the sync tool a file to ship.\n if (trusted !== null && appended === null) return result;\n writeManifest(\n path,\n machineId,\n total,\n pending.lastHlc ?? since,\n trusted !== null && appended !== null\n ? { state: trusted.shaState, size: trusted.size, appended }\n : null,\n );\n return result;\n}\n\nconst SYNCED_ENTITIES_SQL = SYNCED_ENTITIES.map((e) => `'${e}'`).join(\", \");\n\n/**\n * This machine's synced ops newer than `since`, encoded as segment\n * lines, plus how many skipped ops (machine-local, legacy log-only)\n * lie in the range this call covered.\n *\n * The entity filter is IN THE SQL, seeking\n * `idx_ops_machine_entity_hlc`, so a run of machine-local ops after the\n * segment's last line (agent.* churn from a long session) is never\n * read: the segment's watermark is the last SYNCED hlc, and filtering\n * in JS rescanned that whole run on every invocation. `INDEXED BY`\n * because without ANALYZE stats the planner prefers the UNIQUE\n * (machine_id, hlc) index and walks the run anyway.\n *\n * `skippedLocal` counts ops up to the last line written by this call.\n * With `countTrailing` (the full-scan path, already O(file)) it also\n * counts skipped ops after it, as before; the fast path does not,\n * because recounting the same trailing run every time is the cost this\n * query exists to avoid.\n */\nfunction pendingLines(\n db: Db,\n machineId: string,\n since: string | null,\n countTrailing: boolean,\n): { lines: string[]; lastHlc: string | null; skippedLocal: number } {\n // \"\" sorts before every hlc, so it stands for \"from the start\" and\n // keeps the range a plain index seek (an `IS NULL OR` defeats it).\n const from = since ?? \"\";\n const rows = prepareCached(\n db,\n `SELECT hlc, machine_id, group_id, intent, actor, entity, key, op, payload\n FROM ops INDEXED BY idx_ops_machine_entity_hlc\n WHERE machine_id = @machineId\n AND entity IN (${SYNCED_ENTITIES_SQL})\n AND hlc > @from\n ORDER BY hlc`,\n ).all({ machineId, from }) as Array<{\n hlc: string;\n machine_id: string;\n group_id: string;\n intent: string | null;\n actor: string | null;\n entity: string;\n key: string;\n op: string;\n payload: string;\n }>;\n\n const lines: string[] = [];\n let lastHlc: string | null = null;\n\n for (const row of rows) {\n if (isLegacyLogOnlyIntent(row.intent)) continue;\n lines.push(\n encodeSegmentLine({\n hlc: row.hlc,\n machineId: row.machine_id,\n groupId: row.group_id,\n intent: row.intent,\n actor: row.actor,\n entity: row.entity,\n key: row.key,\n op: row.op === \"del\" ? \"del\" : \"put\",\n payload: row.payload,\n }),\n );\n lastHlc = row.hlc;\n }\n // Everything in the covered range that did not become a line. A\n // range count on the UNIQUE (machine_id, hlc) index: proportional to\n // the range, never to what trails it on the fast path.\n let row: { n: number };\n if (countTrailing) {\n row = prepareCached(\n db,\n \"SELECT COUNT(*) AS n FROM ops WHERE machine_id = @machineId AND hlc > @from\",\n ).get({ machineId, from }) as { n: number };\n } else if (lastHlc !== null) {\n row = prepareCached(\n db,\n `SELECT COUNT(*) AS n FROM ops\n WHERE machine_id = @machineId AND hlc > @from AND hlc <= @upTo`,\n ).get({ machineId, from, upTo: lastHlc }) as { n: number };\n } else {\n return { lines, lastHlc, skippedLocal: 0 };\n }\n return { lines, lastHlc, skippedLocal: row.n - lines.length };\n}\n\n/**\n * Count, last hlc, size and running hash of OUR OWN segment, taken from\n * its manifest, or null when the manifest cannot be trusted and the\n * caller must scan the file.\n *\n * Trusted only when the manifest is ours, carries the fields this build\n * writes and they agree with each other (`manifestSelfConsistent`:\n * format, hash state finishing to `sha256`, seal), matches the file's\n * current size AND mtime (any rewrite, hand\n * edit or truncation changes one of them), and the file's last line ends\n * in a newline and decodes cleanly to the manifest's lastHlc. That last\n * check reads only the final line, so a torn or corrupt tail still falls\n * through to the full scan and its self-repair. Cost: one stat plus one\n * line, independent of file size.\n */\nfunction trustedTail(\n path: string,\n machineId: string,\n): { count: number; lastHlc: string | null; size: number; shaState: Sha256State } | null {\n const m = readManifest(path);\n if (m === null || m.v !== SEGMENT_FORMAT_VERSION || m.machine !== machineId) return null;\n if (!manifestSelfConsistent(m)) return null;\n const { count, lastHlc, size, mtimeMs, shaState } = m;\n let stat: ReturnType<typeof statSync>;\n try {\n stat = statSync(path);\n } catch {\n return null;\n }\n if (stat.size !== size || stat.mtimeMs !== mtimeMs) return null;\n if (count === 0) return lastHlc === null ? { count, lastHlc, size, shaState } : null;\n const last = readLastLine(path, size);\n if (last === null) return null;\n const decoded = decodeLine(last);\n if (!decoded.ok || decoded.line.hlc !== lastHlc) return null;\n return { count, lastHlc, size, shaState };\n}\n\n/** The last newline-terminated line of the first `size` bytes of\n * `path`, without its newline; null when those bytes do not end in a\n * newline (a torn write). Reads backwards in chunks, so a long line\n * costs its own length and the file's size costs nothing. */\nfunction readLastLine(path: string, size: number): string | null {\n if (size === 0) return null;\n const fd = openSync(path, \"r\");\n try {\n const last = Buffer.alloc(1);\n readSync(fd, last, 0, 1, size - 1);\n if (last[0] !== 0x0a) return null;\n const chunks: Buffer[] = [];\n let end = size - 1;\n while (end > 0) {\n const start = Math.max(0, end - 64 * 1024);\n const buf = Buffer.alloc(end - start);\n readSync(fd, buf, 0, buf.length, start);\n const nl = buf.lastIndexOf(0x0a);\n if (nl >= 0) {\n chunks.unshift(buf.subarray(nl + 1));\n break;\n }\n chunks.unshift(buf);\n end = start;\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n } finally {\n closeSync(fd);\n }\n}\n\n/**\n * What a full, clean ingest saw of a peer's segment: its size, its\n * exact mtime, and the sha256 of its manifest's bytes, plus the count\n * that manifest claims. Null when the segment or its manifest cannot be\n * read. Taken BEFORE the read, so a file that changes mid-read no longer\n * matches next time.\n */\nfunction segmentFingerprint(path: string): { key: string; count: unknown } | null {\n try {\n const { size, mtimeMs } = statSync(path);\n const manifest = readFileSync(manifestPath(path));\n const sha = createHash(\"sha256\").update(manifest).digest(\"hex\");\n let count: unknown = null;\n try {\n count = (JSON.parse(manifest.toString(\"utf8\")) as { count?: unknown }).count;\n } catch {\n // An unparseable manifest still fingerprints; its count is unknown.\n }\n return { key: `${size} ${mtimeMs} ${sha}`, count };\n } catch {\n return null;\n }\n}\n\n/** The fingerprint recorded with a watermark (see `setWatermark`), or\n * null when the last write of the watermark recorded none. */\nfunction recordedFingerprint(db: Db, watermarkKey: string): string | null {\n const row = prepareCached(\n db,\n \"SELECT fingerprint FROM sync_fingerprints WHERE machine_id = ?\",\n ).get(watermarkKey) as { fingerprint: string } | undefined;\n return row?.fingerprint ?? null;\n}\n\n/**\n * True when ingest is caught up on the segment at `path`, judged without\n * reading it: the manifest counts `lines` (the watermark), and the\n * segment's size, exact mtime and manifest bytes are what the last full,\n * defect-free ingest of this file recorded. Any difference (an append, a\n * rewrite whatever its mtime, a new or edited manifest, a watermark\n * written since by a reset or partial ingest) sends the caller down the\n * full read, which hashes the file and reports any mismatch. Cost: one\n * row lookup, one stat and one manifest read.\n */\nexport function segmentCaughtUp(\n db: Db,\n watermarkKey: string,\n path: string,\n lines: number,\n): boolean {\n const recorded = recordedFingerprint(db, watermarkKey);\n if (recorded === null) return false;\n const now = segmentFingerprint(path);\n return now !== null && now.count === lines && now.key === recorded;\n}\n\n/** Number of GOOD lines in a segment (stopping at the first defect, as\n * ingest does). The denominator of \"how far behind am I\" — exported for\n * `mu sync`'s peer table. */\nexport function segmentLineCount(path: string): number {\n return readSegmentTail(path).count;\n}\n\n/**\n * Count + last hlc of an existing segment, cheaply, plus (this is the\n * part that matters) WHY it stopped: `defect` is null when every line\n * decoded cleanly (a genuine, trustworthy EOF), and set when decoding\n * stopped early because a line was bad. Conflating those two used to be\n * the whole bug: a stop-on-damage looked exactly like a stop-on-EOF to\n * `flushLocked`, so it kept appending after the damage forever.\n * `goodLines` is the verified-good prefix, raw, so a caller that finds a\n * defect can truncate back to it byte-for-byte rather than re-encoding.\n */\nfunction readSegmentTail(path: string): {\n count: number;\n lastHlc: string | null;\n goodLines: readonly string[];\n defect: SegmentDefect | null;\n} {\n if (!existsSync(path)) return { count: 0, lastHlc: null, goodLines: [], defect: null };\n const lines = segmentLines(readFileSync(path, \"utf8\"));\n let lastHlc: string | null = null;\n let count = 0;\n let defect: SegmentDefect | null = null;\n for (let index = 0; index < lines.length; index++) {\n const line = lines[index];\n if (line === undefined) break;\n // Same rule as `ingestSegment`: a blank line is damage. Skipping it\n // here while peers halt on it left the owner blind to the defect,\n // so it never self-repaired and every peer stopped there forever.\n if (line.trim() === \"\") {\n defect = { kind: \"malformed-shape\", line: index + 1, detail: \"blank line\" };\n break;\n }\n const decoded = decodeLine(line);\n if (!decoded.ok) {\n defect = { kind: decoded.kind, line: index + 1, detail: decoded.detail };\n break;\n }\n lastHlc = decoded.line.hlc;\n count += 1;\n }\n return { count, lastHlc, goodLines: lines.slice(0, count), defect };\n}\n\n/** Split a segment into its lines exactly as every reader must: a\n * trailing newline is normal, a trailing PARTIAL line is a torn write\n * (kept so layer 1 can catch it), and a blank line stays in place so\n * the caller reports it as damage. One splitter, so the owner's\n * self-check and a peer's ingest cannot disagree about line numbers. */\nfunction segmentLines(raw: string): string[] {\n const lines = raw.split(\"\\n\");\n if (lines.length > 0 && lines[lines.length - 1] === \"\") lines.pop();\n return lines;\n}\n\n/**\n * LAYER 4: whole-file verification sidecar.\n *\n * `incremental` carries the running hash of the bytes the manifest last\n * covered, so an append hashes only what it added. Without it (first\n * flush, a repair, a manifest from an older build, or a file that grew\n * by more than we appended) the whole file is hashed once.\n */\nfunction writeManifest(\n path: string,\n machine: string,\n count: number,\n lastHlc: string | null,\n incremental: { state: Sha256State; size: number; appended: Buffer } | null,\n): void {\n let stat = statSync(path);\n let shaState: Sha256State;\n if (incremental !== null && stat.size === incremental.size + incremental.appended.length) {\n shaState = sha256Update(incremental.state, incremental.appended);\n } else {\n const bytes = readFileSync(path);\n shaState = sha256Update(sha256Initial(), bytes);\n stat = statSync(path);\n }\n writeManifestFile(path, {\n v: SEGMENT_FORMAT_VERSION,\n machine,\n count,\n lastHlc,\n sha256: sha256Digest(shaState),\n size: shaState.n,\n mtimeMs: stat.mtimeMs,\n shaState,\n });\n}\n\n/**\n * Verify a segment against its manifest (layer 4).\n *\n * Whole-file, so it catches damage the per-line layers cannot see: a\n * segment silently replaced wholesale, or truncated exactly on a line\n * boundary (where every remaining line is individually valid).\n */\nexport function verifyAgainstManifest(\n segment: string,\n): { ok: true } | { ok: false; reason: string } {\n const manifest = readManifest(segment);\n if (manifest === null) return { ok: true }; // no manifest: nothing to check\n if (!existsSync(segment)) return { ok: false, reason: \"segment missing but manifest present\" };\n const sha = createHash(\"sha256\").update(readFileSync(segment)).digest(\"hex\");\n if (sha === manifest.sha256) return { ok: true };\n // A GROWN file is expected: the peer appended after writing the\n // manifest we have, or our copy is mid-transfer. That is not damage.\n const tail = readSegmentTail(segment);\n if (tail.count >= manifest.count) {\n return { ok: true };\n }\n return {\n ok: false,\n reason: `sha mismatch and file has FEWER records than the manifest (${tail.count} < ${manifest.count}): truncated`,\n };\n}\n\n// ─── peer discovery ───────────────────────────────────────────────────\n\nexport interface PeerSegment {\n /** Machine id the segment belongs to. */\n machineId: string;\n /** Key of this FILE's watermark in `sync_peers`: the machine id for\n * the peer's own segment, the full file stem for a conflict copy.\n * A copy diverges from its original, so line N of one says nothing\n * about line N of the other; sharing one watermark skipped every op\n * that existed only in the copy. Optional for SDK callers written\n * before it existed: absent means the machine id (`peerWatermarkKey`). */\n watermarkKey?: string;\n /** Path on disk. */\n path: string;\n /** True for a Syncthing-style conflict copy. */\n conflictCopy: boolean;\n}\n\n/**\n * Every segment in `dir` that is not mine.\n *\n * IMPLICIT, with no membership list. `MU_SYNC_PEERS` was explicitly\n * rejected as \"a config file with extra steps that must be kept\n * consistent across every machine\" — dropping a segment in the folder\n * joins the cluster, deleting it leaves.\n *\n * CONFLICT COPIES ARE INGESTED, not ignored. Syncthing names them\n * `<machine>.sync-conflict-20260609-123456-ABCDEFG.jsonl`; they are still\n * valid op logs, and dedup by `(machine_id, hlc)` makes reading them\n * safe. Ignoring them would silently drop real ops precisely when\n * something already went wrong.\n */\nexport function discoverPeers(dir: string, selfMachineId: string): PeerSegment[] {\n if (!existsSync(dir)) return [];\n const peers: PeerSegment[] = [];\n for (const name of readdirSync(dir)) {\n if (!name.endsWith(SEGMENT_EXT)) continue;\n const stem = name.slice(0, -SEGMENT_EXT.length);\n // Syncthing: \"<machine>.sync-conflict-<date>-<time>-<id>\"\n const conflictAt = stem.indexOf(\".sync-conflict-\");\n const conflictCopy = conflictAt > 0;\n const machineId = conflictCopy ? stem.slice(0, conflictAt) : stem;\n if (machineId === selfMachineId && !conflictCopy) continue;\n // A conflict copy OF MY OWN segment is still a peer's view of my\n // history; ingesting it is a no-op thanks to (machine_id, hlc)\n // dedupe, so allow it rather than special-casing.\n const path = join(dir, name);\n try {\n if (!statSync(path).isFile()) continue;\n } catch {\n continue;\n }\n peers.push({ machineId, watermarkKey: conflictCopy ? stem : machineId, path, conflictCopy });\n }\n return peers.sort((a, b) => a.path.localeCompare(b.path));\n}\n\n/** The `sync_peers` key for a segment file: `watermarkKey`, else the\n * machine id (the pre-watermarkKey `PeerSegment` shape). */\nexport function peerWatermarkKey(peer: PeerSegment): string {\n return peer.watermarkKey ?? peer.machineId;\n}\n\n// ─── watermarks ───────────────────────────────────────────────────────\n\n/**\n * How far into one segment file we have applied, keyed by\n * `PeerSegment.watermarkKey` (the machine id, or a conflict copy's own\n * stem).\n *\n * ONE INTEGER SUFFICES because segments are append-only and ordered — a\n * set or a vector clock would be strictly more state for no more\n * information. Stored in `sync_peers.last_applied_seq`, which has been in\n * the v9 schema unused until now.\n *\n * The integer is a LINE COUNT within that peer's segment, not the peer's\n * `ops.seq` (which is a local-only cursor on their machine and means\n * nothing here).\n */\nexport function getWatermark(db: Db, watermarkKey: string): number {\n const row = db\n .prepare(\"SELECT last_applied_seq AS n FROM sync_peers WHERE machine_id = ?\")\n .get(watermarkKey) as { n: number } | undefined;\n return row?.n ?? 0;\n}\n\n/**\n * Store a watermark and stamp `last_seen_at` with the ISO time. The\n * segment fingerprint goes to `sync_fingerprints` when the caller just\n * read the file cleanly to its end (`segmentCaughtUp`). Every other\n * write deletes it, so a reset or partial ingest never vouches for the\n * file.\n */\nexport function setWatermark(\n db: Db,\n watermarkKey: string,\n value: number,\n fingerprint?: string | null,\n): void {\n const now = new Date().toISOString();\n prepareCached(\n db,\n `INSERT INTO sync_peers (machine_id, last_applied_seq, last_seen_at)\n VALUES (@machineId, @value, @seenAt)\n ON CONFLICT (machine_id) DO UPDATE\n SET last_applied_seq = @value, last_seen_at = @seenAt`,\n ).run({ machineId: watermarkKey, value, seenAt: now });\n if (fingerprint == null) {\n prepareCached(db, \"DELETE FROM sync_fingerprints WHERE machine_id = ?\").run(watermarkKey);\n } else {\n prepareCached(\n db,\n `INSERT INTO sync_fingerprints (machine_id, fingerprint) VALUES (?, ?)\n ON CONFLICT (machine_id) DO UPDATE SET fingerprint = excluded.fingerprint`,\n ).run(watermarkKey, fingerprint);\n }\n}\n\n/**\n * The pending-reprojection marker: SQLite's `user_version` header field,\n * 1 while applied ops await `reprojectDeferredOps`. mu uses it for\n * nothing else (the schema version lives in `schema_version`). Written\n * inside the applying transaction, so it commits or rolls back with the\n * ops; reading it costs no table lookup and adds no row anyone lists.\n */\nexport function markReprojectionPending(db: Db): void {\n prepareCached(db, \"PRAGMA user_version = 1\").run();\n}\n\n/**\n * Run `reprojectDeferredOps` when an ingest left the marker behind (or\n * always, with `force`), and clear the marker in the same transaction.\n *\n * The marker is what lets ambient ingest skip the repair scan (~130 ms\n * on a large log) when nothing arrived, yet still retry it after a\n * process died between its ingest commit and the repair. Clearing it\n * atomically with the repair means a concurrent ingest's marker is\n * either seen by this repair or survives it. Returns the rows changed.\n */\nexport function reprojectIfPending(db: Db, opts?: { force?: boolean }): number {\n if (opts?.force !== true && db.pragma(\"user_version\", { simple: true }) === 0) return 0;\n return db\n .transaction(() => {\n const pending = db.pragma(\"user_version\", { simple: true }) !== 0;\n if (!pending && opts?.force !== true) return 0;\n const changed = reprojectDeferredOps(db);\n if (pending) db.pragma(\"user_version = 0\");\n return changed;\n })\n .immediate();\n}\n\n/** Reset a peer's watermark so the next ingest re-reads from zero. The\n * universal repair, safe because ingest is idempotent. */\nexport function resetWatermark(db: Db, watermarkKey: string): void {\n setWatermark(db, watermarkKey, 0);\n}\n\n// ─── ingest: peer segment -> applyOp ──────────────────────────────────\n\nexport interface IngestResult {\n machineId: string;\n path: string;\n /** Lines consumed past the starting watermark: applied plus skipped\n * (refused, re-delivered, historical log-only) lines. A line that\n * halted ingest is not counted. */\n read: number;\n /** Ops applied (some are no-ops: already present, or lost an LWW). */\n applied: number;\n /** Ops that changed a row. */\n changed: number;\n /** Watermark after this ingest. */\n watermark: number;\n /** Problems found, in line order. Reported, never swallowed. */\n defects: readonly SegmentDefect[];\n /** True iff a defect stopped us short of the file's end. */\n truncatedAt: number | null;\n}\n\n/**\n * Read one peer segment from its watermark and apply each op.\n *\n * STOPS AT THE FIRST DAMAGED RECORD and advances the watermark only that\n * far. Never skips a damaged line to continue past it: in an ordered log,\n * a gap is indistinguishable from reordering, and applying ops around a\n * hole risks a state neither machine ever had. The tail is re-read on the\n * next ingest, by which time the transfer has usually completed.\n *\n * A REFUSED line is not a damaged one. A well-formed op naming an entity\n * that must not travel (`entity-not-synced`) is reported as a defect and\n * SKIPPED: it projects nothing, so it leaves no hole, and halting on it\n * makes the watermark unrecoverable by any means the CLI offers.\n *\n * A RE-DELIVERED line is not a damaged one either. A block of ops the\n * peer already wrote, appended verbatim a second time, breaks the hlc\n * ordering (`duplicate-op`) without losing anything: every one of those\n * ops is already in our `ops` table byte-for-byte, so applying them\n * again is a no-op by construction. Halting there is unrecoverable —\n * `--repair` re-reads from zero straight back into the same three\n * lines, forever — so it is reported and SKIPPED. A non-monotonic line\n * we have NOT seen before is still real damage and still halts.\n *\n * A HISTORICAL log-only line (`isLegacyLogOnlyIntent`: a prose payload\n * under an otherwise projectable entity, written by a mu older than the\n * flush filter) is skipped silently, exactly as flush and `--from` skip\n * it. Applying it threw a JSON SyntaxError that rolled back the whole\n * segment on every invocation.\n *\n * A manifest mismatch (layer 4) is reported but does not halt: every\n * line still present is individually valid, so applying them is safe.\n *\n * Calls `receiveHlc` per op so the local clock advances past the peer's,\n * which is what makes \"laptop edits after seeing the devserver's op\" order\n * correctly rather than losing to it.\n */\nexport function ingestSegment(\n db: Db,\n peer: PeerSegment,\n opts?: { verify?: boolean },\n): IngestResult {\n const defects: SegmentDefect[] = [];\n const watermarkKey = peerWatermarkKey(peer);\n const start = getWatermark(db, watermarkKey);\n\n // CAUGHT UP: the file and its manifest are byte-for-byte what the last\n // clean full read saw (size, exact mtime, manifest hash), and the\n // manifest counts the lines we consumed. Nothing to apply, so do not\n // read, hash or split the file. `verify` (explicit `mu sync`) skips\n // this and checks the whole file, so damage that kept size and mtime\n // is still reported somewhere.\n if (opts?.verify !== true && segmentCaughtUp(db, watermarkKey, peer.path, start)) {\n return {\n machineId: peer.machineId,\n path: peer.path,\n read: 0,\n applied: 0,\n changed: 0,\n watermark: start,\n defects,\n truncatedAt: null,\n };\n }\n\n if (!existsSync(peer.path)) {\n return {\n machineId: peer.machineId,\n path: peer.path,\n read: 0,\n applied: 0,\n changed: 0,\n watermark: start,\n defects,\n truncatedAt: null,\n };\n }\n\n const fingerprint = segmentFingerprint(peer.path);\n const verified = verifyAgainstManifest(peer.path);\n if (!verified.ok) {\n // Whole-file damage, distinct from a torn line: every remaining\n // record may be individually valid (truncation exactly on a line\n // boundary), which is precisely what the per-line layers cannot see.\n // Reported, NOT a halt: the lines that remain are a valid prefix, so\n // the per-line layers below still decide how far to apply.\n defects.push({ kind: \"manifest-mismatch\", line: 0, detail: verified.reason });\n }\n\n const lines = segmentLines(readFileSync(peer.path, \"utf8\"));\n\n let applied = 0;\n let changed = 0;\n let watermark = start;\n let truncatedAt: number | null = null;\n let previousHlc: string | null = null;\n\n // Seed the monotonicity check from the last line we already accepted,\n // so a segment rewritten out of order is caught even mid-file.\n if (start > 0 && start <= lines.length) {\n const prior = lines[start - 1];\n if (prior !== undefined) {\n const decoded = decodeLine(prior);\n if (decoded.ok) previousHlc = decoded.line.hlc;\n }\n }\n\n const run = db.transaction(() => {\n for (let index = start; index < lines.length; index++) {\n const raw = lines[index];\n const lineNo = index + 1;\n if (raw === undefined || raw.trim() === \"\") {\n // Blank line: treat as damage rather than skipping, since a\n // well-formed segment never contains one.\n defects.push({ kind: \"malformed-shape\", line: lineNo, detail: \"blank line\" });\n truncatedAt = lineNo;\n break;\n }\n\n const decoded = decodeLine(raw);\n if (!decoded.ok) {\n defects.push({ kind: decoded.kind, line: lineNo, detail: decoded.detail });\n truncatedAt = lineNo;\n break;\n }\n\n const op: Op = {\n hlc: decoded.line.hlc,\n machineId: decoded.line.machine,\n groupId: decoded.line.group,\n actor: decoded.line.actor,\n intent: decoded.line.intent,\n entity: decoded.line.entity,\n key: decoded.line.key,\n op: decoded.line.op,\n payload: decoded.payloadText,\n };\n\n // LAYER 3: monotonic hlc. Structural, zero extra bytes. Catches\n // reordering, duplication, and silent mid-file truncation.\n if (previousHlc !== null && decoded.line.hlc <= previousHlc) {\n // ... unless we have this exact op already, in which case the\n // peer re-appended a block it had already written and there is\n // nothing to reorder: an identical op carries identical state,\n // so skipping it cannot produce a state neither machine had.\n if (isAlreadyRecorded(db, op)) {\n defects.push({\n kind: \"duplicate-op\",\n line: lineNo,\n detail: `hlc ${decoded.line.hlc} re-delivered — skipped`,\n });\n watermark = lineNo;\n continue;\n }\n defects.push({\n kind: \"non-monotonic-hlc\",\n line: lineNo,\n detail: `hlc ${decoded.line.hlc} <= previous ${previousHlc}`,\n });\n truncatedAt = lineNo;\n break;\n }\n\n if (isLegacyLogOnlyIntent(decoded.line.intent)) {\n previousHlc = op.hlc;\n watermark = lineNo;\n continue;\n }\n\n try {\n const result = applyIncomingOp(db, op);\n if (result.changed) changed += 1;\n } catch (err) {\n if (err instanceof OpEntityNotSyncedError) {\n // A peer sent something that must never cross a machine\n // boundary (a pane id, an absolute path). Report it as a\n // bad-peer defect — and SKIP THE LINE rather than stopping.\n //\n // Stopping is right for DAMAGE, where a gap is\n // indistinguishable from reordering. This line is not\n // damaged: it decoded, its crc verified, and its hlc is in\n // order. Refusing it projects nothing, so there is no hole to\n // reason about, and continuing is strictly safer than the\n // alternative we actually shipped — one such line at position\n // 2533 of a 20,305-line segment froze that peer's watermark\n // permanently, and `mu sync --repair` re-read straight back\n // into the same wall. A defect is reported; nothing is lost;\n // the remaining 17,772 ops arrive.\n defects.push({\n kind: \"entity-not-synced\",\n line: lineNo,\n detail: `peer sent machine-local entity '${op.entity}' — skipped`,\n });\n previousHlc = op.hlc;\n watermark = lineNo;\n continue;\n }\n throw err;\n }\n\n applied += 1;\n previousHlc = op.hlc;\n watermark = lineNo;\n }\n // Vouch for the file only after a clean read to its end, so a file\n // with a defect is read (and reported) again on every pass.\n const clean = defects.length === 0 && watermark === lines.length;\n setWatermark(db, watermarkKey, watermark, clean ? (fingerprint?.key ?? null) : null);\n // applyIncomingOp left the reprojection marker in this transaction\n // if anything changed or deferred: a process that dies before the\n // pass-wide reprojection leaves it behind for the next one.\n });\n run.immediate();\n\n return {\n machineId: peer.machineId,\n path: peer.path,\n read: watermark - start,\n applied,\n changed,\n watermark,\n defects,\n truncatedAt,\n };\n}\n\n/**\n * Is this exact op already in our `ops` table?\n *\n * `UNIQUE (machine_id, hlc)` is the op's identity everywhere else in\n * the system — it is what makes `applyIncomingOp` idempotent and\n * \"re-read from zero\" a safe universal repair — so it is the identity\n * used here too. Entity and key are matched as well so a hlc collision\n * between genuinely different ops (which the UNIQUE constraint would\n * itself refuse) can never be mistaken for a re-delivery.\n */\nfunction isAlreadyRecorded(db: Db, op: Op): boolean {\n const row = prepareCached(\n db,\n `SELECT 1 FROM ops\n WHERE machine_id = @machineId AND hlc = @hlc\n AND entity = @entity AND key = @key AND op = @op\n LIMIT 1`,\n ).get({\n machineId: op.machineId,\n hlc: op.hlc,\n entity: op.entity,\n key: op.key,\n op: op.op,\n });\n return row !== undefined;\n}\n\n/**\n * Apply ONE incoming op and record it in the local `ops` table.\n *\n * The shared tail of every ingest path — segment ingest above, and the\n * `mu sync --from <peer.db>` reader in `src/sync.ts`, which is a\n * different READER over the same apply semantics. Extracted so the two\n * cannot drift: a second copy of \"advance the clock, apply, record\" is\n * how one of them silently stops advancing the clock.\n *\n * Three steps, in this order:\n * 1. `receiveHlc` BEFORE applying, so anything we mint afterwards\n * sorts above the peer's op.\n * 2. `applyOp`, which is capture-suppressed (no echo op is minted).\n * 3. Record the op locally so it survives, participates in\n * provenance, and can be re-flushed by rebuild. INSERT OR IGNORE\n * makes this idempotent via UNIQUE (machine_id, hlc) — the\n * property that lets \"re-read from zero\" be the universal repair.\n */\nexport function applyIncomingOp(db: Db, op: Op): { changed: boolean } {\n receiveHlc(db, op.hlc);\n const result = applyOp(db, op);\n // A deferred note/edge (`absent`: its task is not here yet), or a row\n // change that may be the parent some deferred op waits for: either way\n // the next ambient pass must run the repair, however this op arrived\n // (segment, `--from`, or an SDK caller).\n if (result.changed || result.skipped === \"absent\") markReprojectionPending(db);\n prepareCached(\n db,\n `INSERT OR IGNORE INTO ops\n (hlc, machine_id, group_id, actor, intent, entity, key, op, payload, created_at)\n VALUES (@hlc, @machineId, @groupId, @actor, @intent, @entity, @key, @op, @payload, @createdAt)`,\n ).run({\n hlc: op.hlc,\n machineId: op.machineId,\n groupId: op.groupId,\n actor: op.actor ?? null,\n intent: op.intent ?? null,\n entity: op.entity,\n key: op.key,\n op: op.op,\n payload: op.payload,\n createdAt: new Date().toISOString(),\n });\n return { changed: result.changed };\n}\n\n// ─── the two halves, together ─────────────────────────────────────────\n\nexport interface SyncPassResult {\n flushed: FlushResult;\n ingested: readonly IngestResult[];\n /** True iff any peer reported a defect. */\n defective: boolean;\n}\n\n/**\n * One flush + one ingest of every discovered peer.\n *\n * The SDK seam `mu sync` calls (src/cli/sync.ts); it deliberately\n * prints nothing and starts nothing. No daemon, no watcher, no polling\n * loop that outlives the command — the anti-feature pledges are firm, and\n * mu never moves files itself: the operator owns transport.\n *\n * A no-op costing nothing when `MU_SYNC_DIR` is unset, which is the\n * normal single-machine case.\n */\nexport async function syncPass(db: Db, dir: string | null = syncDir()): Promise<SyncPassResult> {\n if (dir === null) {\n return {\n flushed: { segmentPath: null, appended: 0, total: 0, skippedLocal: 0, selfRepaired: null },\n ingested: [],\n defective: false,\n };\n }\n const flushed = await flushSegment(db, dir, { verify: true });\n const self = localMachineId(db);\n const ingested = discoverPeers(dir, self).map((peer) =>\n ingestSegment(db, peer, { verify: true }),\n );\n // AFTER every peer, not per peer: an edge in peer A's segment may name\n // a task in peer B's, and `discoverPeers` order is `localeCompare` over\n // random UUID filenames, so \"parent first\" is a coin flip. One pass at\n // the end sees the union. See `reprojectDeferredOps`.\n reprojectIfPending(db, { force: true });\n return {\n flushed,\n ingested,\n defective: flushed.selfRepaired !== null || ingested.some((r) => r.defects.length > 0),\n };\n}\n","// mu — the sync seam: peer status, the ambient hook, and the two power\n// tools behind `mu sync`.\n//\n// WHAT LIVES HERE AND WHAT DOES NOT\n// ---------------------------------\n// `src/segments.ts` owns the MECHANISM (flush / ingest / watermarks /\n// the four robustness layers). This file owns the OPERATOR-FACING\n// questions that mechanism cannot answer on its own:\n//\n// - who are my peers, how far behind am I, when did I last hear from\n// them (`peerStatuses`)\n// - the AMBIENT hook every mu invocation runs (`ambientIngest` /\n// `ambientFlush`)\n// - a DIFFERENT READER: a peer's `ops` table read straight out of a\n// copied / sshfs-mounted `mu.db` (`ingestFromDb`)\n// - the universal repair: reset a watermark and re-read from zero\n// (`repairPeer`)\n//\n// AMBIENT, NOT A DAEMON\n// ---------------------\n// There is no watcher, no background process, and no polling loop that\n// outlives the command. Sync happens because you already run `mu`\n// constantly: every invocation ingests before the verb body and flushes\n// after it. With `MU_SYNC_DIR` unset both halves are a single `if` that\n// reads one env var, so the single-machine case pays nothing. With 2-5\n// peers it is a handful of `stat`/`read` calls on small append-only\n// files.\n//\n// The TUI is the one long-lived surface, and it hangs the same pass off\n// its SLOW tick (10s), never the 1s fast tick — sync is filesystem work\n// and has no business on a repaint cadence.\n//\n// SYNC MUST NEVER FAIL A COMMAND\n// ------------------------------\n// A truncated segment, an unreadable sync dir, a full disk: all of them\n// warn and return. `mu task add` has to work when sync is broken,\n// because the alternative is a tool that stops working when a folder you\n// do not control misbehaves. Every ambient entry point here is\n// try/catch-total by construction (see `ambientIngest`).\n//\n// TRANSPORT STAYS THE OPERATOR'S\n// ------------------------------\n// mu reads and writes FILES. It does not shell out to ssh/scp/rsync, and\n// it will not grow `--push <host>`: that is a remote backend wearing a\n// small hat (ssh config, jump hosts, ProxyCommand, ports, identity\n// files, interactive prompts inside a TUI tick, network-vs-auth error\n// mapping), and it violates the standing ROADMAP pledge that the user\n// owns transport. Instead, when a peer looks stale we PRINT a\n// copy-pasteable rsync line through the ordinary NextStep convention and\n// let the operator paste it, alias it, or run Syncthing and never see\n// it.\n\nimport { existsSync, statSync } from \"node:fs\";\nimport Database from \"better-sqlite3\";\nimport type { Op } from \"./apply.js\";\nimport { type Db, SYNCED_ENTITIES } from \"./db.js\";\nimport { isLegacyLogOnlyIntent } from \"./legacy-ops.js\";\nimport type { NextStep } from \"./output.js\";\nimport {\n applyIncomingOp,\n discoverPeers,\n type FlushResult,\n flushSegment,\n getWatermark,\n type IngestResult,\n ingestSegment,\n localMachineId,\n peerWatermarkKey,\n reprojectIfPending,\n resetWatermark,\n type SegmentDefect,\n segmentCaughtUp,\n segmentLineCount,\n syncDir,\n} from \"./segments.js\";\n\n/** No discovered peer matches the operator's `--repair <peer>` ref.\n * Exit 3 (not found), like every other resolve-time miss. */\nexport class SyncPeerNotFoundError extends Error {\n override readonly name = \"SyncPeerNotFoundError\";\n constructor(\n readonly ref: string,\n readonly known: readonly string[],\n ) {\n super(\n `no peer matches ${JSON.stringify(ref)}${\n known.length === 0 ? \" (no peers discovered)\" : ` (known peers: ${known.join(\", \")})`\n }`,\n );\n }\n}\n\n/** A `--repair <peer>` prefix matched several peers. A conflict (exit 4),\n * never a guess — the same rule `mu undo <group>` follows for\n * abbreviated group ids. */\nexport class SyncPeerRefAmbiguousError extends Error {\n override readonly name = \"SyncPeerRefAmbiguousError\";\n constructor(\n readonly ref: string,\n readonly candidates: readonly string[],\n ) {\n super(\n `peer ref ${JSON.stringify(ref)} matches ${candidates.length} peers (${candidates.join(\", \")}); pass more characters`,\n );\n }\n}\n\n/** `mu sync --from <path>` pointed at a file that is not there. Exit 3. */\nexport class SyncSourceNotFoundError extends Error {\n override readonly name = \"SyncSourceNotFoundError\";\n constructor(readonly path: string) {\n super(`--from: no such file: ${path}`);\n }\n}\n\n/** A peer whose segment has not moved in this long is reported STALE.\n * A fixed constant, not an env var: it is a display threshold, and mu's\n * whole cluster configuration is deliberately ONE env var. */\nexport const PEER_STALE_MS = 24 * 60 * 60 * 1000;\n\n/** How many characters of a `machine_id` uuid we show. Peers are known\n * only by uuid — `machine_identity.hostname` is machine-LOCAL and never\n * ships, so mu genuinely cannot render a peer's hostname without\n * inventing a membership file. A short prefix is the honest display,\n * and every verb that takes one accepts any unique prefix (the\n * affordance git gives for shas). */\nexport const PEER_SHORT_LEN = 8;\n\nexport interface PeerStatus {\n machineId: string;\n /** First `PEER_SHORT_LEN` chars of the machine id, for display. */\n short: string;\n path: string;\n /** True for a Syncthing-style `*.sync-conflict-*.jsonl` copy. */\n conflictCopy: boolean;\n /** `sync_peers` key of this file's watermark (see `PeerSegment`).\n * `peerStatuses` always sets it. Optional so SDK callers that build\n * the pre-watermarkKey shape still compile; absent means the machine\n * id (`peerWatermarkKey`). */\n watermarkKey?: string;\n /** Lines of this segment file already applied. */\n watermark: number;\n /** GOOD lines currently in the segment (a defect stops the count). */\n total: number;\n /** `total - watermark`: how much of what we HOLD is not yet applied.\n * Non-zero after a defect stopped an ingest short, or mid-transfer. */\n behind: number;\n /** Segment mtime in epoch ms — when transport last delivered. */\n lastSeenMs: number | null;\n /** Age of the segment file, ms. Null when it does not exist. */\n ageMs: number | null;\n stale: boolean;\n}\n\n/** Peer table for the sync dir, newest contact first. Pure read: it\n * neither flushes nor ingests, so `mu sync` can call it after its own\n * pass and the TUI could call it on a tick. */\nexport function peerStatuses(db: Db, dir: string): PeerStatus[] {\n const self = localMachineId(db);\n const now = Date.now();\n const rows = discoverPeers(dir, self).map((peer) => {\n let lastSeenMs: number | null = null;\n try {\n lastSeenMs = statSync(peer.path).mtimeMs;\n } catch {\n lastSeenMs = null;\n }\n const watermarkKey = peerWatermarkKey(peer);\n const watermark = getWatermark(db, watermarkKey);\n // Caught up: the count is the watermark, no need to decode the file.\n const total = segmentCaughtUp(db, watermarkKey, peer.path, watermark)\n ? watermark\n : segmentLineCount(peer.path);\n const ageMs = lastSeenMs === null ? null : Math.max(0, now - lastSeenMs);\n return {\n machineId: peer.machineId,\n short: peer.machineId.slice(0, PEER_SHORT_LEN),\n path: peer.path,\n conflictCopy: peer.conflictCopy,\n watermarkKey,\n watermark,\n total,\n behind: Math.max(0, total - watermark),\n lastSeenMs,\n ageMs,\n stale: ageMs === null || ageMs > PEER_STALE_MS,\n };\n });\n return rows.sort((a, b) => (b.lastSeenMs ?? 0) - (a.lastSeenMs ?? 0));\n}\n\n/** Resolve an operator-typed peer reference (full machine id, or any\n * unique prefix) against the discovered peers. Ambiguity is a\n * UsageError, never a guess — repairing the wrong peer would re-read a\n * whole segment for nothing and confuse the report.\n *\n * A ref names a MACHINE, so a segment and its conflict copies (same\n * machine id) count as one match; the peer's own segment is returned\n * when present. Counting them separately made the short id `mu sync`\n * prints unresolvable. */\nexport function resolvePeerRef(peers: readonly PeerStatus[], ref: string): PeerStatus {\n const matches = peers.filter((p) => p.machineId.startsWith(ref));\n const exact = matches.filter((p) => p.machineId === ref);\n const candidates = exact.length > 0 ? exact : matches;\n const machines = [...new Set(candidates.map((p) => p.machineId))];\n const first = candidates.find((p) => !p.conflictCopy) ?? candidates[0];\n if (first === undefined) {\n throw new SyncPeerNotFoundError(\n ref,\n peers.map((p) => p.short),\n );\n }\n if (machines.length > 1) {\n throw new SyncPeerRefAmbiguousError(\n ref,\n machines.map((m) => m.slice(0, PEER_SHORT_LEN)),\n );\n }\n return first;\n}\n\n/** Reset the watermark of every segment file a peer has (its own and\n * any conflict copies) so the next ingest re-reads them from zero. Safe\n * by construction: apply is idempotent and `ops` dedupes on\n * `UNIQUE (machine_id, hlc)`. */\nexport function repairPeer(db: Db, ref: string, dir: string): PeerStatus {\n const peers = peerStatuses(db, dir);\n const peer = resolvePeerRef(peers, ref);\n for (const p of peers) {\n if (p.machineId === peer.machineId) resetWatermark(db, peerWatermarkKey(p));\n }\n return peer;\n}\n\n// ─── the ambient hook ─────────────────────────────────────────────────\n\n/** Is sync configured at all? THE single `if` the no-sync case pays.\n * Callers check this before awaiting anything, so an unconfigured\n * machine allocates no promise and touches no filesystem. */\nexport function syncEnabled(): boolean {\n return syncDir() !== null;\n}\n\nexport interface AmbientResult {\n /** Peers whose segments were read. Empty when sync is off. */\n ingested: readonly IngestResult[];\n /** Non-fatal problems, already warned about. */\n warnings: readonly string[];\n}\n\nexport interface AmbientOptions {\n /** Suppress the stderr warnings. Set by the TUI, which owns the\n * alternate screen — a stray write there paints garbage over the\n * dashboard. The warnings are still returned, and the Doctor card\n * is where a TUI operator learns about a broken sync dir. */\n quiet?: boolean;\n}\n\nexport interface AmbientFlushOptions extends AmbientOptions {\n /** How long to wait for the segment lock (default\n * AMBIENT_FLUSH_LOCK_WAIT_MS). On timeout nothing is written; the ops\n * stay in the DB and the next flush appends them. */\n lockWaitMs?: number;\n}\n\n/** Format one non-fatal sync problem for stderr. Prefixed so it is\n * unmistakably mu's own aside and not the verb's output. */\nfunction warn(message: string, opts?: AmbientOptions): void {\n if (opts?.quiet === true) return;\n // Deliberately stderr: stdout is the verb's contract (and may be JSON).\n process.stderr.write(`mu: sync: ${message}\\n`);\n}\n\nfunction describeDefects(peerShort: string, defects: readonly SegmentDefect[]): string {\n const first = defects[0];\n const detail = first === undefined ? \"unknown defect\" : `${first.kind} at line ${first.line}`;\n const more = defects.length > 1 ? ` (+${defects.length - 1} more)` : \"\";\n // `--repair` only resets the watermark, so it is advice ONLY for a\n // defect a re-read can get past (a torn write mid-transfer). A refused\n // line is deterministic: re-reading hits the identical line and the\n // hint would be self-referentially useless, which is exactly how the\n // original incident's operator was sent in a circle. A re-delivered\n // op is deterministic for the same reason. So is a manifest mismatch:\n // the file itself is short, re-reading it changes nothing, and only a\n // fresh copy from the peer clears it.\n const skipped = new Set([\"entity-not-synced\", \"duplicate-op\"]);\n const fileWide = new Set([\"manifest-mismatch\"]);\n let hint: string;\n if (defects.every((d) => skipped.has(d.kind))) {\n hint = \" — skipped; the rest of the segment applied\";\n } else if (defects.every((d) => skipped.has(d.kind) || fileWide.has(d.kind))) {\n hint = \" — the file is shorter than its manifest; copy it from the peer again\";\n } else {\n hint = ` — re-read with \\`mu sync --repair ${peerShort}\\``;\n }\n return `peer ${peerShort}: ${detail}${more}${hint}`;\n}\n\n/**\n * INGEST half of the ambient hook: pull every peer segment before the\n * verb body runs, so the command sees the freshest state the filesystem\n * can offer.\n *\n * Total: no input can make this throw. A per-peer failure is isolated so\n * one broken segment cannot hide the others.\n */\nexport async function ambientIngest(db: Db, opts?: AmbientOptions): Promise<AmbientResult> {\n const dir = syncDir();\n if (dir === null) return { ingested: [], warnings: [] };\n const warnings: string[] = [];\n const ingested: IngestResult[] = [];\n try {\n const self = localMachineId(db);\n for (const peer of discoverPeers(dir, self)) {\n try {\n const result = ingestSegment(db, peer);\n ingested.push(result);\n if (result.defects.length > 0) {\n const message = describeDefects(peer.machineId.slice(0, PEER_SHORT_LEN), result.defects);\n warnings.push(message);\n warn(message, opts);\n }\n } catch (err) {\n const message = `peer ${peer.machineId.slice(0, PEER_SHORT_LEN)}: ${err instanceof Error ? err.message : String(err)}`;\n warnings.push(message);\n warn(message, opts);\n }\n }\n // Every peer is in; now project anything that arrived before its\n // parent task did. Deliberately outside the per-peer loop, and\n // deliberately inside the outer try: a repair failure must not fail\n // the verb any more than a torn segment does.\n //\n // Only when an ingest applied something since the last repair. The\n // repair scans every historical edge/note put, which cost ~130 ms on\n // every synced verb while finding nothing: a deferred op can only\n // become projectable when its parent task arrives, and that arrival\n // is an applied op. Each such ingest leaves a marker in the same\n // transaction, so a process that died between its ingest commit and\n // this line is repaired by the next invocation.\n reprojectIfPending(db);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n warnings.push(message);\n warn(message, opts);\n }\n // `await` nothing above: ingest is synchronous better-sqlite3 work.\n // The async signature exists so the caller's seam is uniform with\n // ambientFlush (which takes a file lock).\n return { ingested, warnings };\n}\n\n/**\n * FLUSH half of the ambient hook: append this invocation's own ops to\n * this machine's segment AFTER the verb body has committed them.\n *\n * Order matters and is the whole reason the hook is split in two: a\n * flush before the body would leave the ops the operator just wrote\n * sitting unflushed until the NEXT invocation, so `mu task add` on the\n * laptop followed by `mu sync` on the devserver would show nothing —\n * exactly the no-hands claim, broken.\n *\n * Appends under the cross-process file lock inside `flushSegment`, so\n * two concurrent mu processes cannot interleave partial lines. A flush\n * with nothing to append skips the lock, so read-only verbs never queue.\n * A flush that cannot take the lock within AMBIENT_FLUSH_LOCK_WAIT_MS\n * writes nothing (`lockBusy`) and the verb carries on silently: its ops\n * stay pending in `ops` and the next invocation's flush appends them.\n */\nexport async function ambientFlush(\n db: Db,\n opts?: AmbientFlushOptions,\n): Promise<FlushResult | null> {\n const dir = syncDir();\n if (dir === null) return null;\n try {\n const result = await flushSegment(db, dir, { lockWaitMs: opts?.lockWaitMs });\n if (result.selfRepaired !== null) {\n const d = result.selfRepaired;\n warn(\n `own segment truncated back to its last good line: ${d.kind} at line ${d.line} (${d.detail}) — regenerated from the ops table`,\n opts,\n );\n }\n return result;\n } catch (err) {\n warn(err instanceof Error ? err.message : String(err), opts);\n return null;\n }\n}\n\n/**\n * Both halves in one call, for a caller that has no before/after seam to\n * straddle — today the TUI's SLOW tick (10s; never the 1s fast tick,\n * which is a repaint cadence and has no business doing filesystem work).\n *\n * Ingest first, then flush: the same order the CLI hook uses, so a\n * long-lived TUI converges on exactly the same schedule as a shell that\n * runs one verb every ten seconds.\n */\nexport async function ambientSyncPass(\n db: Db,\n opts?: AmbientOptions,\n): Promise<{ ingested: readonly IngestResult[]; flushed: FlushResult | null }> {\n if (!syncEnabled()) return { ingested: [], flushed: null };\n const { ingested } = await ambientIngest(db, opts);\n const flushed = await ambientFlush(db, opts);\n return { ingested, flushed };\n}\n\n// ─── `mu sync --from <peer.db>`: a different READER ───────────────────\n\nexport interface IngestFromDbResult {\n path: string;\n /** Ops read out of the peer's `ops` table (already filtered). */\n read: number;\n /** Ops that changed a row here. */\n changed: number;\n /** Ops skipped because their entity is machine-local. */\n skippedLocal: number;\n}\n\n/**\n * Ingest straight from a peer's `mu.db`, reading its `ops` table with\n * SQLite instead of parsing a JSONL segment.\n *\n * WHY THIS EARNS A FLAG when `MU_SYNC_DIR=/mnt/whatever mu state` covers\n * the one-off-directory case: it is a DIFFERENT READER, and nothing\n * about an env var can express it. The file you have is a database, not\n * a segment — because you scp'd it, or because you have the devserver's\n * state dir on sshfs and would rather read the real thing than wait for\n * a flush.\n *\n * Opened `readonly` so mu cannot write to a file it does not own, and\n * `fileMustExist` so a typo'd path is an error rather than a freshly\n * created empty DB.\n *\n * Filters exactly as flush does — `SYNCED_ENTITIES` only, and never the\n * peer's copy of OUR ops (we already have those; `UNIQUE (machine_id,\n * hlc)` would dedupe them anyway, but not reading them is cheaper and\n * keeps the reported count honest). Ops the peer itself ingested from a\n * THIRD machine are read, which is how transitive convergence falls out\n * for free.\n *\n * Watermarks are deliberately untouched: a watermark counts LINES of a\n * segment, and a DB has no such coordinate. The next segment ingest for\n * that peer re-reads from wherever it was, applies the same ops again,\n * and changes nothing — idempotence is what makes leaving it alone safe.\n */\nexport function ingestFromDb(db: Db, path: string): IngestFromDbResult {\n if (!existsSync(path)) throw new SyncSourceNotFoundError(path);\n const self = localMachineId(db);\n const source = new Database(path, { readonly: true, fileMustExist: true });\n try {\n const rows = source\n .prepare(\n `SELECT hlc, machine_id, group_id, actor, intent, entity, key, op, payload\n FROM ops\n WHERE machine_id != ?\n ORDER BY hlc`,\n )\n .all(self) as Array<{\n hlc: string;\n machine_id: string;\n group_id: string;\n actor: string | null;\n intent: string | null;\n entity: string;\n key: string;\n op: string;\n payload: string;\n }>;\n\n const synced = new Set<string>(SYNCED_ENTITIES);\n let read = 0;\n let changed = 0;\n let skippedLocal = 0;\n const run = db.transaction(() => {\n for (const row of rows) {\n if (!synced.has(row.entity) || isLegacyLogOnlyIntent(row.intent)) {\n skippedLocal += 1;\n continue;\n }\n const op: Op = {\n hlc: row.hlc,\n machineId: row.machine_id,\n groupId: row.group_id,\n actor: row.actor,\n intent: row.intent,\n entity: row.entity,\n key: row.key,\n op: row.op === \"del\" ? \"del\" : \"put\",\n payload: row.payload,\n };\n const result = applyIncomingOp(db, op);\n read += 1;\n if (result.changed) changed += 1;\n }\n });\n run.immediate();\n // Same out-of-order repair the segment path runs: a peer's `ops`\n // table can hold an edge whose task op we only got from a THIRD\n // machine, in either order.\n changed += reprojectIfPending(db, { force: true });\n return { path, read, changed, skippedLocal };\n } finally {\n try {\n source.close();\n } catch {\n // best effort\n }\n }\n}\n\n// ─── transport hints ──────────────────────────────────────────────────\n\n/**\n * Copy-pasteable transport for a stale peer, via the ordinary NextStep\n * convention. This is what mu does INSTEAD of moving bytes itself.\n *\n * `<host>` is a literal placeholder on purpose: mu has no host list and\n * is not growing one (a peer list would be a config file with extra\n * steps, and one that must be kept consistent on every machine — the\n * very drift it looks like it solves).\n */\nexport function transportNextSteps(dir: string, peers: readonly PeerStatus[]): NextStep[] {\n const stale = peers.filter((p) => p.stale);\n if (stale.length === 0) return [];\n return [\n {\n intent: `Pull fresh segments (${stale.length} stale peer${stale.length === 1 ? \"\" : \"s\"})`,\n command: `rsync -av <host>:${dir}/ ${dir}/`,\n },\n {\n intent: \"Or stop doing it by hand\",\n command: `# share ${dir} with Syncthing on every machine`,\n },\n ];\n}\n"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBzB,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0B9B,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":["randomUUID","randomUUID","join","join","applied","taskKey","createHash","existsSync","mkdirSync","readFileSync","writeFileSync","join","resolve","SEGMENT_EXT","resolve","join","mkdirSync","createHash","writeFileSync","existsSync","row","stat","readFileSync","existsSync","statSync","Database","statSync","existsSync","Database"]}
|