@cleocode/core 2026.10.9 → 2026.10.10-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/build-provenance.json +2 -2
  2. package/dist/decide/sites/registry.d.ts +26 -0
  3. package/dist/decide/sites/registry.d.ts.map +1 -1
  4. package/dist/decide/sites/registry.js +25 -0
  5. package/dist/decide/sites/registry.js.map +1 -1
  6. package/dist/docs/doctor.d.ts +15 -5
  7. package/dist/docs/doctor.d.ts.map +1 -1
  8. package/dist/docs/doctor.js +182 -83
  9. package/dist/docs/doctor.js.map +1 -1
  10. package/dist/docs/triage.d.ts +211 -0
  11. package/dist/docs/triage.d.ts.map +1 -0
  12. package/dist/docs/triage.js +473 -0
  13. package/dist/docs/triage.js.map +1 -0
  14. package/dist/doctor/system-health.d.ts.map +1 -1
  15. package/dist/doctor/system-health.js +54 -8
  16. package/dist/doctor/system-health.js.map +1 -1
  17. package/dist/hooks/release-gate.d.ts +10 -0
  18. package/dist/hooks/release-gate.d.ts.map +1 -1
  19. package/dist/hooks/release-gate.js +9 -3
  20. package/dist/hooks/release-gate.js.map +1 -1
  21. package/dist/project-scope.d.ts +1 -0
  22. package/dist/project-scope.d.ts.map +1 -1
  23. package/dist/project-scope.js +69 -6
  24. package/dist/project-scope.js.map +1 -1
  25. package/dist/resources/run-admission.d.ts +96 -0
  26. package/dist/resources/run-admission.d.ts.map +1 -1
  27. package/dist/resources/run-admission.js +155 -0
  28. package/dist/resources/run-admission.js.map +1 -1
  29. package/dist/resources/run-governed.d.ts +5 -1
  30. package/dist/resources/run-governed.d.ts.map +1 -1
  31. package/dist/resources/run-governed.js +34 -1
  32. package/dist/resources/run-governed.js.map +1 -1
  33. package/dist/spawn/agent-identity.d.ts +2 -0
  34. package/dist/spawn/agent-identity.d.ts.map +1 -1
  35. package/dist/spawn/agent-identity.js +72 -4
  36. package/dist/spawn/agent-identity.js.map +1 -1
  37. package/dist/store/blob-keep.d.ts +15 -0
  38. package/dist/store/blob-keep.d.ts.map +1 -1
  39. package/dist/store/blob-keep.js +20 -0
  40. package/dist/store/blob-keep.js.map +1 -1
  41. package/dist/store/conduit-doc-history.d.ts +265 -0
  42. package/dist/store/conduit-doc-history.d.ts.map +1 -0
  43. package/dist/store/conduit-doc-history.js +468 -0
  44. package/dist/store/conduit-doc-history.js.map +1 -0
  45. package/dist/store/row-identity-registry.d.ts +6 -4
  46. package/dist/store/row-identity-registry.d.ts.map +1 -1
  47. package/dist/store/row-identity-registry.js +59 -10
  48. package/dist/store/row-identity-registry.js.map +1 -1
  49. package/dist/store/schema/cleo-project/conduit.d.ts +554 -7
  50. package/dist/store/schema/cleo-project/conduit.d.ts.map +1 -1
  51. package/dist/store/schema/cleo-project/conduit.js +223 -30
  52. package/dist/store/schema/cleo-project/conduit.js.map +1 -1
  53. package/dist/store/schema/conduit-schema.d.ts +211 -3
  54. package/dist/store/schema/conduit-schema.d.ts.map +1 -1
  55. package/dist/store/schema/conduit-schema.js +53 -14
  56. package/dist/store/schema/conduit-schema.js.map +1 -1
  57. package/dist/store/sync/apply/parent-delete.d.ts.map +1 -1
  58. package/dist/store/sync/apply/parent-delete.js +6 -0
  59. package/dist/store/sync/apply/parent-delete.js.map +1 -1
  60. package/dist/store/sync/timestamp-canon.d.ts.map +1 -1
  61. package/dist/store/sync/timestamp-canon.js +7 -0
  62. package/dist/store/sync/timestamp-canon.js.map +1 -1
  63. package/dist/store/table-classification.d.ts.map +1 -1
  64. package/dist/store/table-classification.js +31 -13
  65. package/dist/store/table-classification.js.map +1 -1
  66. package/dist/tasks/gate-runner.d.ts.map +1 -1
  67. package/dist/tasks/gate-runner.js +44 -5
  68. package/dist/tasks/gate-runner.js.map +1 -1
  69. package/dist/tasks/test-run-binding.d.ts +4 -1
  70. package/dist/tasks/test-run-binding.d.ts.map +1 -1
  71. package/dist/tasks/test-run-binding.js +38 -2
  72. package/dist/tasks/test-run-binding.js.map +1 -1
  73. package/dist/worktree/worktree-adopt.d.ts.map +1 -1
  74. package/dist/worktree/worktree-adopt.js +45 -1
  75. package/dist/worktree/worktree-adopt.js.map +1 -1
  76. package/migrations/drizzle-cleo-project/20261011000000_t13354-conduit-history-rekey/migration.sql +274 -0
  77. package/package.json +13 -13
  78. package/schemas/project-info.schema.json +2 -2
  79. package/templates/git-hooks/commit-msg +2 -0
  80. package/templates/git-hooks/legacy-hashes.json +1 -0
  81. package/templates/git-hooks/pre-push +3 -0
@@ -0,0 +1,468 @@
1
+ /**
2
+ * Canonical accessors for the re-keyed CleoDocs conduit history family
3
+ * (T13354 · spec `cleodocs-rearch-design` §3/§10 · D11165).
4
+ *
5
+ * Every write to `conduit_attachment_versions` / `conduit_attachment_approvals`
6
+ * / `conduit_doc_slug_aliases` / `conduit_doc_heads` /
7
+ * `conduit_attachment_contributors` / `section_crdt_states` goes through the
8
+ * functions here, on the `openDualScopeDb` chokepoint's drizzle handle
9
+ * ({@link getDb}) — gate 3 (no raw opens) and gate 28 (no raw writes to
10
+ * syncing tables; the derived contributors rebuild is raw SQL by design and
11
+ * exempt per (file, table) in `scripts/lint-no-raw-table-writes.mjs`).
12
+ *
13
+ * Semantics implemented here:
14
+ *
15
+ * - Version identity is the row uid + `parent_version_uid` DAG;
16
+ * `version_number` is minted as a LOCAL display ordinal (max + 1 within
17
+ * the doc on this device) and is never a key.
18
+ * - Approvals are append-only; {@link revokeConduitAttachmentApproval}
19
+ * writes a tombstone row (`status: 'revoked'`).
20
+ * - The doc head projection keeps the max-HLC head; a losing concurrent
21
+ * head increments `conflict_count` and is recorded in
22
+ * `last_conflict_json` (typed merge rule `docs.head.max-hlc`).
23
+ * - `section_crdt_states` is local-only; nothing here syncs it, and an
24
+ * apply that lands a version rebases it via
25
+ * {@link rebaseSectionCrdtStates}.
26
+ *
27
+ * @module
28
+ * @task T13354
29
+ * @epic T13340
30
+ * @saga T13339
31
+ */
32
+ import { randomUUID } from 'node:crypto';
33
+ import { ExitCode } from '@cleocode/contracts/exit-codes.js';
34
+ import { and, desc, eq, sql } from 'drizzle-orm';
35
+ import { CleoError } from '../errors.js';
36
+ import { naturalRowUid } from './row-identity.js';
37
+ import { conduitAttachmentApprovals, conduitAttachments, conduitAttachmentVersions, conduitDocHeads, conduitDocSlugAliases, sectionCrdtStates, } from './schema/cleo-project/conduit.js';
38
+ import { getDb } from './sqlite.js';
39
+ /**
40
+ * Refuse an empty identifier at the write boundary.
41
+ *
42
+ * @param name - Field name for the message.
43
+ * @param value - The value to check.
44
+ */
45
+ function requireNonEmpty(name, value) {
46
+ if (value.trim().length === 0) {
47
+ // @sync-invariant none:input-shape a blank identifier is refused before any write; nothing was written
48
+ throw new CleoError(ExitCode.VALIDATION_ERROR, `${name} must be a non-empty string`);
49
+ }
50
+ }
51
+ /**
52
+ * Resolve a document slug to its immutable row uid.
53
+ *
54
+ * Lookup order: the live slug on `conduit_attachments` first (a live id
55
+ * always wins), then the newest alias in `conduit_doc_slug_aliases` (the
56
+ * old-slug lookup, T13354 AC2).
57
+ *
58
+ * @param projectRoot - Absolute path to the CLEO project root.
59
+ * @param slug - The slug to resolve.
60
+ * @returns The doc's `conduit_attachments.uid`, or `null` when unknown.
61
+ */
62
+ export async function resolveConduitDocUid(projectRoot, slug) {
63
+ requireNonEmpty('slug', slug);
64
+ const db = await getDb(projectRoot);
65
+ const live = await db
66
+ .select({ uid: conduitAttachments.uid })
67
+ .from(conduitAttachments)
68
+ .where(eq(conduitAttachments.slug, slug))
69
+ .get();
70
+ if (live?.uid)
71
+ return live.uid;
72
+ const alias = await db
73
+ .select({ docUid: conduitDocSlugAliases.docUid })
74
+ .from(conduitDocSlugAliases)
75
+ .where(eq(conduitDocSlugAliases.slug, slug))
76
+ .orderBy(desc(conduitDocSlugAliases.createdAt))
77
+ .get();
78
+ return alias?.docUid ?? null;
79
+ }
80
+ /**
81
+ * Record an old-slug → doc-uid alias (append-only).
82
+ *
83
+ * The row's uid is the NATURAL identity over (slug, docUid), so two devices
84
+ * recording the same alias merge to one row; a repeat insert is a no-op.
85
+ *
86
+ * @param projectRoot - Absolute path to the CLEO project root.
87
+ * @param alias - Slug, target doc uid and an optional reason.
88
+ * @returns The alias row's uid.
89
+ */
90
+ export async function recordConduitDocAlias(projectRoot, alias) {
91
+ requireNonEmpty('slug', alias.slug);
92
+ requireNonEmpty('docUid', alias.docUid);
93
+ const uid = naturalRowUid('project', 'conduit_doc_slug_aliases', [alias.slug, alias.docUid]);
94
+ const db = await getDb(projectRoot);
95
+ await db
96
+ .insert(conduitDocSlugAliases)
97
+ .values({
98
+ uid,
99
+ slug: alias.slug,
100
+ docUid: alias.docUid,
101
+ reason: alias.reason ?? 'rename',
102
+ createdAt: new Date().toISOString(),
103
+ })
104
+ .onConflictDoNothing()
105
+ .run();
106
+ return uid;
107
+ }
108
+ /**
109
+ * Append a version row to a document's history DAG.
110
+ *
111
+ * `version_number` is minted as (current local max within the doc) + 1 — a
112
+ * display ordinal only; another device minting the same number is NOT a
113
+ * conflict, because version identity is the row uid + parent linkage. The
114
+ * `uid` itself comes from the schema's `defaultRowUid` (a random UUIDv7 at
115
+ * insert), matching the T12341 minted-table pattern.
116
+ *
117
+ * @param projectRoot - Absolute path to the CLEO project root.
118
+ * @param input - The version facts.
119
+ * @returns The inserted row.
120
+ */
121
+ // @sync-invariant docs.versions.append-only the read (local max display ordinal) and the append are one causal step; the uid makes the insert conflict-free
122
+ export async function appendConduitAttachmentVersion(projectRoot, input) {
123
+ requireNonEmpty('attachmentUid', input.attachmentUid);
124
+ requireNonEmpty('authorAgentId', input.authorAgentId);
125
+ requireNonEmpty('storageKey', input.storageKey);
126
+ requireNonEmpty('contentHash', input.contentHash);
127
+ const db = await getDb(projectRoot);
128
+ const latest = await db
129
+ .select({ versionNumber: conduitAttachmentVersions.versionNumber })
130
+ .from(conduitAttachmentVersions)
131
+ .where(eq(conduitAttachmentVersions.attachmentUid, input.attachmentUid))
132
+ .orderBy(desc(conduitAttachmentVersions.versionNumber))
133
+ .get();
134
+ const id = randomUUID();
135
+ await db
136
+ .insert(conduitAttachmentVersions)
137
+ .values({
138
+ id,
139
+ attachmentUid: input.attachmentUid,
140
+ parentVersionUid: input.parentVersionUid,
141
+ versionNumber: (latest?.versionNumber ?? 0) + 1,
142
+ authorAgentId: input.authorAgentId,
143
+ changeType: input.changeType ?? 'patch',
144
+ ...(input.patchText !== undefined ? { patchText: input.patchText } : {}),
145
+ storageKey: input.storageKey,
146
+ contentHash: input.contentHash,
147
+ originalSize: input.originalSize,
148
+ compressedSize: input.compressedSize,
149
+ tokens: input.tokens,
150
+ ...(input.changeSummary !== undefined ? { changeSummary: input.changeSummary } : {}),
151
+ sectionsModified: JSON.stringify(input.sectionsModified ?? []),
152
+ tokensAdded: input.tokensAdded ?? 0,
153
+ tokensRemoved: input.tokensRemoved ?? 0,
154
+ createdAt: new Date().toISOString(),
155
+ })
156
+ .run();
157
+ const row = await db
158
+ .select()
159
+ .from(conduitAttachmentVersions)
160
+ .where(eq(conduitAttachmentVersions.id, id))
161
+ .get();
162
+ if (!row) {
163
+ // @sync-invariant docs.versions.append-only a version insert that cannot be read back means the store lost the write; fail loudly instead of returning a phantom
164
+ throw new CleoError(ExitCode.GENERAL_ERROR, `version insert for doc ${input.attachmentUid} could not be read back`);
165
+ }
166
+ return row;
167
+ }
168
+ /**
169
+ * List a document's versions, newest display ordinal first.
170
+ *
171
+ * @param projectRoot - Absolute path to the CLEO project root.
172
+ * @param attachmentUid - The doc's immutable uid.
173
+ * @returns The version rows.
174
+ */
175
+ export async function listConduitAttachmentVersions(projectRoot, attachmentUid) {
176
+ requireNonEmpty('attachmentUid', attachmentUid);
177
+ const db = await getDb(projectRoot);
178
+ return db
179
+ .select()
180
+ .from(conduitAttachmentVersions)
181
+ .where(eq(conduitAttachmentVersions.attachmentUid, attachmentUid))
182
+ .orderBy(desc(conduitAttachmentVersions.versionNumber))
183
+ .all();
184
+ }
185
+ /**
186
+ * Record an approval verdict as an append-only row.
187
+ *
188
+ * @param projectRoot - Absolute path to the CLEO project root.
189
+ * @param input - The verdict facts.
190
+ * @returns The inserted row.
191
+ */
192
+ export async function recordConduitAttachmentApproval(projectRoot, input) {
193
+ requireNonEmpty('attachmentUid', input.attachmentUid);
194
+ requireNonEmpty('versionUid', input.versionUid);
195
+ requireNonEmpty('reviewerAgentId', input.reviewerAgentId);
196
+ const db = await getDb(projectRoot);
197
+ const id = randomUUID();
198
+ const now = new Date().toISOString();
199
+ await db
200
+ .insert(conduitAttachmentApprovals)
201
+ .values({
202
+ id,
203
+ attachmentUid: input.attachmentUid,
204
+ versionUid: input.versionUid,
205
+ ...(input.sectionId !== undefined ? { sectionId: input.sectionId } : {}),
206
+ reviewerAgentId: input.reviewerAgentId,
207
+ status: input.status ?? 'approved',
208
+ ...(input.comment !== undefined ? { comment: input.comment } : {}),
209
+ versionReviewed: input.versionReviewed,
210
+ createdAt: now,
211
+ updatedAt: now,
212
+ })
213
+ .run();
214
+ const row = await db
215
+ .select()
216
+ .from(conduitAttachmentApprovals)
217
+ .where(eq(conduitAttachmentApprovals.id, id))
218
+ .get();
219
+ if (!row) {
220
+ // @sync-invariant docs.approvals.append-only an approval insert that cannot be read back means the store lost the write; fail loudly instead of returning a phantom
221
+ throw new CleoError(ExitCode.GENERAL_ERROR, `approval insert for version ${input.versionUid} could not be read back`);
222
+ }
223
+ return row;
224
+ }
225
+ /**
226
+ * Revoke an approval as a TOMBSTONE row (never an UPDATE or DELETE).
227
+ *
228
+ * @param projectRoot - Absolute path to the CLEO project root.
229
+ * @param input - The revoke facts (same shape as the original verdict).
230
+ * @returns The tombstone row.
231
+ */
232
+ export async function revokeConduitAttachmentApproval(projectRoot, input) {
233
+ return recordConduitAttachmentApproval(projectRoot, { ...input, status: 'revoked' });
234
+ }
235
+ /**
236
+ * The effective verdicts for one version: the latest row per (reviewer,
237
+ * section) wins, and 'revoked' tombstones cancel the earlier verdict.
238
+ *
239
+ * @param projectRoot - Absolute path to the CLEO project root.
240
+ * @param versionUid - The version uid.
241
+ * @param sectionId - Restrict to one section when given (plus whole-doc rows).
242
+ * @returns The approval rows in creation order.
243
+ */
244
+ export async function listConduitAttachmentApprovals(projectRoot, versionUid, sectionId) {
245
+ requireNonEmpty('versionUid', versionUid);
246
+ const db = await getDb(projectRoot);
247
+ const rows = await db
248
+ .select()
249
+ .from(conduitAttachmentApprovals)
250
+ .where(sectionId === undefined
251
+ ? eq(conduitAttachmentApprovals.versionUid, versionUid)
252
+ : and(eq(conduitAttachmentApprovals.versionUid, versionUid), eq(conduitAttachmentApprovals.sectionId, sectionId)))
253
+ .all();
254
+ return rows.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
255
+ }
256
+ /**
257
+ * Rebuild the DERIVED contributors rollup from the versions table.
258
+ *
259
+ * `conduit_attachment_contributors` is not synced (spec §10): every device
260
+ * recomputes it after apply. Raw set-SQL (DELETE + INSERT … SELECT … GROUP
261
+ * BY) because the rebuild is a pure aggregate — the two statements are the
262
+ * gate-28 exempt sites for this (file, table).
263
+ *
264
+ * @param projectRoot - Absolute path to the CLEO project root.
265
+ * @param attachmentUid - Rebuild one doc only when given, else every doc.
266
+ * @returns The number of rollup rows written.
267
+ */
268
+ export async function rebuildConduitAttachmentContributors(projectRoot, attachmentUid) {
269
+ const db = await getDb(projectRoot);
270
+ if (attachmentUid !== undefined) {
271
+ requireNonEmpty('attachmentUid', attachmentUid);
272
+ await db.run(sql `DELETE FROM conduit_attachment_contributors WHERE attachment_uid = ${attachmentUid}`);
273
+ }
274
+ else {
275
+ await db.run(sql `DELETE FROM conduit_attachment_contributors`);
276
+ }
277
+ const scope = attachmentUid ?? null;
278
+ const result = await db.run(sql `
279
+ INSERT INTO conduit_attachment_contributors (
280
+ attachment_uid, slug, agent_id, version_count,
281
+ total_tokens_added, total_tokens_removed,
282
+ first_contribution_at, last_contribution_at
283
+ )
284
+ SELECT
285
+ v.attachment_uid,
286
+ NULL,
287
+ v.author_agent_id,
288
+ COUNT(*),
289
+ SUM(v.tokens_added),
290
+ SUM(v.tokens_removed),
291
+ MIN(v.created_at),
292
+ MAX(v.created_at)
293
+ FROM conduit_attachment_versions AS v
294
+ WHERE v.attachment_uid IS NOT NULL
295
+ AND (${scope} IS NULL OR v.attachment_uid = ${scope})
296
+ GROUP BY v.attachment_uid, v.author_agent_id
297
+ `);
298
+ return Number(result.changes);
299
+ }
300
+ /**
301
+ * Move a document's current-version projection (typed rule
302
+ * `docs.head.max-hlc`).
303
+ *
304
+ * The row keeps the MAX-HLC head. A candidate that loses to a concurrent
305
+ * head is never silently shadowed: `conflict_count` increments and
306
+ * `last_conflict_json` records the loser (the losing version itself survives
307
+ * in `conduit_attachment_versions`). A repeat of the same head is a no-op.
308
+ *
309
+ * @param projectRoot - Absolute path to the CLEO project root.
310
+ * @param input - The candidate head.
311
+ * @returns Whether the head advanced or a conflict was recorded.
312
+ */
313
+ // @sync-invariant docs.head.max-hlc the read-modify-write IS the max-HLC rule: keep the max head, record the losing concurrent head as a conflict
314
+ export async function upsertConduitDocHead(projectRoot, input) {
315
+ requireNonEmpty('attachmentUid', input.attachmentUid);
316
+ requireNonEmpty('headVersionUid', input.headVersionUid);
317
+ requireNonEmpty('headHlc', input.headHlc);
318
+ const db = await getDb(projectRoot);
319
+ const existing = await db
320
+ .select()
321
+ .from(conduitDocHeads)
322
+ .where(eq(conduitDocHeads.attachmentUid, input.attachmentUid))
323
+ .get();
324
+ const now = new Date().toISOString();
325
+ if (!existing) {
326
+ await db
327
+ .insert(conduitDocHeads)
328
+ .values({
329
+ attachmentUid: input.attachmentUid,
330
+ uid: naturalRowUid('project', 'conduit_doc_heads', [input.attachmentUid]),
331
+ headVersionUid: input.headVersionUid,
332
+ headHlc: input.headHlc,
333
+ conflictCount: 0,
334
+ updatedAt: now,
335
+ })
336
+ .run();
337
+ }
338
+ else if (existing.headVersionUid === input.headVersionUid) {
339
+ // Same head — idempotent re-apply, no conflict.
340
+ }
341
+ else if (input.headHlc > existing.headHlc) {
342
+ await db
343
+ .update(conduitDocHeads)
344
+ .set({ headVersionUid: input.headVersionUid, headHlc: input.headHlc, updatedAt: now })
345
+ .where(eq(conduitDocHeads.attachmentUid, input.attachmentUid))
346
+ .run();
347
+ }
348
+ else {
349
+ const conflict = {
350
+ versionUid: input.headVersionUid,
351
+ hlc: input.headHlc,
352
+ recordedAt: now,
353
+ };
354
+ await db
355
+ .update(conduitDocHeads)
356
+ .set({
357
+ conflictCount: existing.conflictCount + 1,
358
+ lastConflictJson: JSON.stringify(conflict),
359
+ updatedAt: now,
360
+ })
361
+ .where(eq(conduitDocHeads.attachmentUid, input.attachmentUid))
362
+ .run();
363
+ }
364
+ const head = await db
365
+ .select()
366
+ .from(conduitDocHeads)
367
+ .where(eq(conduitDocHeads.attachmentUid, input.attachmentUid))
368
+ .get();
369
+ if (!head) {
370
+ // @sync-invariant docs.head.max-hlc the projection row must exist after its upsert; fail loudly instead of returning a phantom
371
+ throw new CleoError(ExitCode.GENERAL_ERROR, `doc head upsert for ${input.attachmentUid} could not be read back`);
372
+ }
373
+ return {
374
+ advanced: head.headVersionUid === input.headVersionUid && head.headHlc === input.headHlc,
375
+ conflictRecorded: head.headVersionUid !== input.headVersionUid && head.lastConflictJson !== null,
376
+ head,
377
+ };
378
+ }
379
+ /**
380
+ * Read a document's current-version projection row.
381
+ *
382
+ * @param projectRoot - Absolute path to the CLEO project root.
383
+ * @param attachmentUid - The doc's immutable uid.
384
+ * @returns The head row, or `null` when the doc has no projection yet.
385
+ */
386
+ export async function getConduitDocHead(projectRoot, attachmentUid) {
387
+ requireNonEmpty('attachmentUid', attachmentUid);
388
+ const db = await getDb(projectRoot);
389
+ const row = await db
390
+ .select()
391
+ .from(conduitDocHeads)
392
+ .where(eq(conduitDocHeads.attachmentUid, attachmentUid))
393
+ .get();
394
+ return row ?? null;
395
+ }
396
+ /**
397
+ * Read the local Loro state of one document section.
398
+ *
399
+ * @param projectRoot - Absolute path to the CLEO project root.
400
+ * @param attachmentUid - The doc's immutable uid.
401
+ * @param sectionId - The section id.
402
+ * @returns The state row, or `null` when this device has none.
403
+ */
404
+ export async function readSectionCrdtState(projectRoot, attachmentUid, sectionId) {
405
+ requireNonEmpty('attachmentUid', attachmentUid);
406
+ requireNonEmpty('sectionId', sectionId);
407
+ const db = await getDb(projectRoot);
408
+ const row = await db
409
+ .select()
410
+ .from(sectionCrdtStates)
411
+ .where(and(eq(sectionCrdtStates.attachmentUid, attachmentUid), eq(sectionCrdtStates.sectionId, sectionId)))
412
+ .get();
413
+ return row ?? null;
414
+ }
415
+ /**
416
+ * Write the local Loro state of one document section (upsert).
417
+ *
418
+ * LOCAL-ONLY: this state never syncs; content moves cross-device only
419
+ * through landed versions (spec §2 option b).
420
+ *
421
+ * @param projectRoot - Absolute path to the CLEO project root.
422
+ * @param input - The section's snapshot bytes and optional base version.
423
+ */
424
+ export async function writeSectionCrdtState(projectRoot, input) {
425
+ requireNonEmpty('attachmentUid', input.attachmentUid);
426
+ requireNonEmpty('sectionId', input.sectionId);
427
+ const db = await getDb(projectRoot);
428
+ await db
429
+ .insert(sectionCrdtStates)
430
+ .values({
431
+ attachmentUid: input.attachmentUid,
432
+ sectionId: input.sectionId,
433
+ snapshot: input.snapshot,
434
+ baseVersionUid: input.baseVersionUid ?? null,
435
+ updatedAt: new Date().toISOString(),
436
+ })
437
+ .onConflictDoUpdate({
438
+ target: [sectionCrdtStates.attachmentUid, sectionCrdtStates.sectionId],
439
+ set: {
440
+ snapshot: input.snapshot,
441
+ baseVersionUid: input.baseVersionUid ?? null,
442
+ updatedAt: new Date().toISOString(),
443
+ },
444
+ })
445
+ .run();
446
+ }
447
+ /**
448
+ * Rebase every local CRDT state of a document onto a landed version.
449
+ *
450
+ * Called when an apply lands a new version: the local Loro state is reset
451
+ * onto the landed base (`base_version_uid`) so stale local edits do not
452
+ * silently diverge from the synced history (spec §10).
453
+ *
454
+ * @param projectRoot - Absolute path to the CLEO project root.
455
+ * @param attachmentUid - The doc's immutable uid.
456
+ * @param baseVersionUid - The landed version's uid.
457
+ */
458
+ export async function rebaseSectionCrdtStates(projectRoot, attachmentUid, baseVersionUid) {
459
+ requireNonEmpty('attachmentUid', attachmentUid);
460
+ requireNonEmpty('baseVersionUid', baseVersionUid);
461
+ const db = await getDb(projectRoot);
462
+ await db
463
+ .update(sectionCrdtStates)
464
+ .set({ baseVersionUid, updatedAt: new Date().toISOString() })
465
+ .where(eq(sectionCrdtStates.attachmentUid, attachmentUid))
466
+ .run();
467
+ }
468
+ //# sourceMappingURL=conduit-doc-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conduit-doc-history.js","sourceRoot":"","sources":["../../src/store/conduit-doc-history.ts"],"names":[],"mappings":"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"}
@@ -80,8 +80,10 @@ export declare const ROW_IDENTITY_EXEMPT: Readonly<Record<TableScope, Readonly<R
80
80
  *
81
81
  * Since T12894 declared the brain text-keyed tables (11 project, 12 global),
82
82
  * T12895 the brain natural-key tables (3 project, 3 global) and T12896 the
83
- * brain integer-keyed tables (6 project, 6 global), and T12915 declared the
84
- * agent registry (1 global; 6 more reclassified derived or local-only)
83
+ * brain integer-keyed tables (6 project, 6 global), T12915 declared the
84
+ * agent registry (1 global; 6 more reclassified derived or local-only), and
85
+ * T13354 declared the re-keyed conduit doc family (5 project, dropping 4
86
+ * exemptions — contributors became derived and not syncing)
85
87
  * ({@link rowIdentityExemptionSummary} prints the live numbers):
86
88
  *
87
89
  * | category | task | project | global |
@@ -89,7 +91,7 @@ export declare const ROW_IDENTITY_EXEMPT: Readonly<Record<TableScope, Readonly<R
89
91
  * | planned | T12894 | 0 | 0 |
90
92
  * | planned | T12895 | 0 | 0 |
91
93
  * | planned | T12896 | 2 | 1 |
92
- * | planned (conduit) | T12913 | 12 | 0 |
94
+ * | planned (conduit) | T12913 | 8 | 0 |
93
95
  * | planned (lifecycle…) | T12914 | 16 | 0 |
94
96
  * | planned (agents…) | T12915 | 0 | 4 |
95
97
  * | planned (nexus) | T12916 | 0 | 8 |
@@ -98,7 +100,7 @@ export declare const ROW_IDENTITY_EXEMPT: Readonly<Record<TableScope, Readonly<R
98
100
  * | planned (misc) | T12920 | 12 | 0 |
99
101
  * | twin-collapse | T12535 | 30 | 0 |
100
102
  * | not-row-replicated | T12918 | 1 | 1 |
101
- * | total | | 76 | 18 |
103
+ * | total | | 70 | 17 |
102
104
  *
103
105
  * @task T12897
104
106
  */
@@ -1 +1 @@
1
- {"version":3,"file":"row-identity-registry.d.ts","sourceRoot":"","sources":["../../src/store/row-identity-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAkB,eAAe,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEvF,yCAAyC;AACzC,eAAO,MAAM,UAAU,QAAQ,CAAC;AAEhC,2EAA2E;AAC3E,eAAO,MAAM,eAAe,aAAa,CAAC;AA6P1C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,CAAC,CAgKjF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC,CAS/E,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAE9F;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,sBAAsB;IACtB,QAAQ,CAAC,QAAQ,EAAE,4BAA4B,CAAC;IAChD,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAsDD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CACxC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAgInE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAG3E,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAGjF,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAIvE;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,UAAU,GAAG;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC,CAWA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,CAAC;IAChE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACzC,GAAG,0BAA0B,EAAE,CAyD/B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAE7F;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ7E"}
1
+ {"version":3,"file":"row-identity-registry.d.ts","sourceRoot":"","sources":["../../src/store/row-identity-registry.ts"],"names":[],"mappings":"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"}
@@ -399,6 +399,57 @@ export const ROW_IDENTITY = {
399
399
  key: ['brain_entry_id', 'release_id', 'link_type'],
400
400
  task: 'T12895',
401
401
  },
402
+ // CleoDocs schema re-key (T13354 · spec cleodocs-rearch-design §3/§10 ·
403
+ // D11165): the conduit history family keys on the immutable doc row uid.
404
+ {
405
+ table: 'conduit_attachments',
406
+ kind: 'minted',
407
+ key: ['slug'],
408
+ birth: 'created_at',
409
+ birthFacts: ['conversation_id', 'from_agent_id'],
410
+ task: 'T13354',
411
+ },
412
+ {
413
+ // Append-only: version identity is the uid + parent_version_uid DAG;
414
+ // the local UUIDv4 id never travels and cannot collide across devices.
415
+ table: 'conduit_attachment_versions',
416
+ kind: 'minted',
417
+ key: ['id'],
418
+ birth: 'created_at',
419
+ birthFacts: ['author_agent_id', 'content_hash'],
420
+ refs: [
421
+ { column: 'attachment_uid', table: 'conduit_attachments' },
422
+ { column: 'parent_version_uid', table: 'conduit_attachment_versions' },
423
+ ],
424
+ task: 'T13354',
425
+ },
426
+ {
427
+ // Append-only: a revoke is a new row (tombstone), never an UPDATE/DELETE.
428
+ table: 'conduit_attachment_approvals',
429
+ kind: 'minted',
430
+ key: ['id'],
431
+ birth: 'created_at',
432
+ birthFacts: ['reviewer_agent_id'],
433
+ refs: [
434
+ { column: 'attachment_uid', table: 'conduit_attachments' },
435
+ { column: 'version_uid', table: 'conduit_attachment_versions' },
436
+ ],
437
+ task: 'T13354',
438
+ },
439
+ {
440
+ // Natural over the pair: both devices derive one uid for one alias.
441
+ table: 'conduit_doc_slug_aliases',
442
+ kind: 'natural',
443
+ key: ['slug', 'doc_uid'],
444
+ task: 'T13354',
445
+ },
446
+ {
447
+ // One projection row per doc; the key column already holds the doc uid.
448
+ table: 'conduit_doc_heads',
449
+ kind: 'natural',
450
+ key: ['attachment_uid'],
451
+ task: 'T13354',
452
+ },
402
453
  ],
403
454
  global: [
404
455
  ...brainTextKeyed(),
@@ -542,10 +593,6 @@ export const ROW_IDENTITY_EXEMPT = {
542
593
  task: 'T12535',
543
594
  },
544
595
  ...exempt([
545
- 'conduit_attachment_approvals',
546
- 'conduit_attachment_contributors',
547
- 'conduit_attachment_versions',
548
- 'conduit_attachments',
549
596
  'conduit_conversations',
550
597
  'conduit_message_pins',
551
598
  'conduit_messages',
@@ -613,8 +660,10 @@ export const ROW_IDENTITY_EXEMPT = {
613
660
  *
614
661
  * Since T12894 declared the brain text-keyed tables (11 project, 12 global),
615
662
  * T12895 the brain natural-key tables (3 project, 3 global) and T12896 the
616
- * brain integer-keyed tables (6 project, 6 global), and T12915 declared the
617
- * agent registry (1 global; 6 more reclassified derived or local-only)
663
+ * brain integer-keyed tables (6 project, 6 global), T12915 declared the
664
+ * agent registry (1 global; 6 more reclassified derived or local-only), and
665
+ * T13354 declared the re-keyed conduit doc family (5 project, dropping 4
666
+ * exemptions — contributors became derived and not syncing)
618
667
  * ({@link rowIdentityExemptionSummary} prints the live numbers):
619
668
  *
620
669
  * | category | task | project | global |
@@ -622,7 +671,7 @@ export const ROW_IDENTITY_EXEMPT = {
622
671
  * | planned | T12894 | 0 | 0 |
623
672
  * | planned | T12895 | 0 | 0 |
624
673
  * | planned | T12896 | 2 | 1 |
625
- * | planned (conduit) | T12913 | 12 | 0 |
674
+ * | planned (conduit) | T12913 | 8 | 0 |
626
675
  * | planned (lifecycle…) | T12914 | 16 | 0 |
627
676
  * | planned (agents…) | T12915 | 0 | 4 |
628
677
  * | planned (nexus) | T12916 | 0 | 8 |
@@ -631,12 +680,12 @@ export const ROW_IDENTITY_EXEMPT = {
631
680
  * | planned (misc) | T12920 | 12 | 0 |
632
681
  * | twin-collapse | T12535 | 30 | 0 |
633
682
  * | not-row-replicated | T12918 | 1 | 1 |
634
- * | total | | 76 | 18 |
683
+ * | total | | 70 | 17 |
635
684
  *
636
685
  * @task T12897
637
686
  */
638
687
  export const ROW_IDENTITY_EXEMPT_PINNED = {
639
- project: 74,
688
+ project: 70,
640
689
  global: 17,
641
690
  };
642
691
  /**
@@ -648,7 +697,7 @@ export const ROW_IDENTITY_EXEMPT_PINNED = {
648
697
  * @task T12897
649
698
  */
650
699
  export const ROW_IDENTITY_EXEMPT_NAMES_SHA256 = {
651
- project: '55f330a07c43d1b1af86579902b8d2efad2d5a5bbc713d2fd785705d36c8126b',
700
+ project: '03413c00c1a3a2be35c1b1c8729ceb8c89f28624e7919e6e12e2f06b5fba5ef6',
652
701
  global: '60877c1f83b6b1e87bbce6f6e911720853337aa2b10eed7404c06a47e9bffd5c',
653
702
  };
654
703
  /**