@cleocode/core 2026.10.6 → 2026.10.7-rc.ci.674

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 (242) hide show
  1. package/dist/build-provenance.json +2 -2
  2. package/dist/cloud/http.d.ts +8 -0
  3. package/dist/cloud/http.d.ts.map +1 -1
  4. package/dist/cloud/http.js +11 -0
  5. package/dist/cloud/http.js.map +1 -1
  6. package/dist/cloud/journal.d.ts +6 -0
  7. package/dist/cloud/journal.d.ts.map +1 -1
  8. package/dist/cloud/journal.js +1 -1
  9. package/dist/cloud/journal.js.map +1 -1
  10. package/dist/cloud/nexus-cloud-status.d.ts.map +1 -1
  11. package/dist/cloud/nexus-cloud-status.js +3 -1
  12. package/dist/cloud/nexus-cloud-status.js.map +1 -1
  13. package/dist/cloud/nexus-vault.d.ts +86 -1
  14. package/dist/cloud/nexus-vault.d.ts.map +1 -1
  15. package/dist/cloud/nexus-vault.js +875 -98
  16. package/dist/cloud/nexus-vault.js.map +1 -1
  17. package/dist/docs/doctor.d.ts +183 -0
  18. package/dist/docs/doctor.d.ts.map +1 -0
  19. package/dist/docs/doctor.js +537 -0
  20. package/dist/docs/doctor.js.map +1 -0
  21. package/dist/doctor/system-health.d.ts +189 -0
  22. package/dist/doctor/system-health.d.ts.map +1 -0
  23. package/dist/doctor/system-health.js +783 -0
  24. package/dist/doctor/system-health.js.map +1 -0
  25. package/dist/git/hooks-install.d.ts +17 -34
  26. package/dist/git/hooks-install.d.ts.map +1 -1
  27. package/dist/git/hooks-install.js +173 -70
  28. package/dist/git/hooks-install.js.map +1 -1
  29. package/dist/harness/ask-enforce.d.ts +43 -0
  30. package/dist/harness/ask-enforce.d.ts.map +1 -0
  31. package/dist/harness/ask-enforce.js +165 -0
  32. package/dist/harness/ask-enforce.js.map +1 -0
  33. package/dist/hooks.d.ts +8 -30
  34. package/dist/hooks.d.ts.map +1 -1
  35. package/dist/hooks.js +36 -116
  36. package/dist/hooks.js.map +1 -1
  37. package/dist/init.d.ts +2 -1
  38. package/dist/init.d.ts.map +1 -1
  39. package/dist/init.js +5 -14
  40. package/dist/init.js.map +1 -1
  41. package/dist/injection.d.ts +2 -2
  42. package/dist/injection.d.ts.map +1 -1
  43. package/dist/injection.js +108 -10
  44. package/dist/injection.js.map +1 -1
  45. package/dist/internal.d.ts +1 -1
  46. package/dist/internal.d.ts.map +1 -1
  47. package/dist/internal.js +1 -1
  48. package/dist/internal.js.map +1 -1
  49. package/dist/issue/create.d.ts +4 -0
  50. package/dist/issue/create.d.ts.map +1 -1
  51. package/dist/issue/create.js +12 -0
  52. package/dist/issue/create.js.map +1 -1
  53. package/dist/issue/index.d.ts +1 -1
  54. package/dist/issue/index.d.ts.map +1 -1
  55. package/dist/issue/index.js +1 -1
  56. package/dist/issue/index.js.map +1 -1
  57. package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
  58. package/dist/orchestrate/spawn-ops.js +8 -2
  59. package/dist/orchestrate/spawn-ops.js.map +1 -1
  60. package/dist/orchestration/lean-change.d.ts +15 -0
  61. package/dist/orchestration/lean-change.d.ts.map +1 -0
  62. package/dist/orchestration/lean-change.js +17 -0
  63. package/dist/orchestration/lean-change.js.map +1 -0
  64. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  65. package/dist/orchestration/spawn-prompt.js +6 -4
  66. package/dist/orchestration/spawn-prompt.js.map +1 -1
  67. package/dist/release/ci-evidence.d.ts +59 -0
  68. package/dist/release/ci-evidence.d.ts.map +1 -1
  69. package/dist/release/ci-evidence.js +150 -5
  70. package/dist/release/ci-evidence.js.map +1 -1
  71. package/dist/release/plan.d.ts.map +1 -1
  72. package/dist/release/plan.js +11 -2
  73. package/dist/release/plan.js.map +1 -1
  74. package/dist/release/pr-evidence.d.ts +15 -0
  75. package/dist/release/pr-evidence.d.ts.map +1 -1
  76. package/dist/release/pr-evidence.js +42 -1
  77. package/dist/release/pr-evidence.js.map +1 -1
  78. package/dist/release/reconcile.js +2 -2
  79. package/dist/release/reconcile.js.map +1 -1
  80. package/dist/release/verify-provenance.js +2 -2
  81. package/dist/release/verify-provenance.js.map +1 -1
  82. package/dist/resources/admission-ledger.d.ts +8 -0
  83. package/dist/resources/admission-ledger.d.ts.map +1 -1
  84. package/dist/resources/admission-ledger.js +5 -0
  85. package/dist/resources/admission-ledger.js.map +1 -1
  86. package/dist/resources/claim-keepalive.d.ts +34 -0
  87. package/dist/resources/claim-keepalive.d.ts.map +1 -0
  88. package/dist/resources/claim-keepalive.js +49 -0
  89. package/dist/resources/claim-keepalive.js.map +1 -0
  90. package/dist/resources/governor.d.ts.map +1 -1
  91. package/dist/resources/governor.js +3 -0
  92. package/dist/resources/governor.js.map +1 -1
  93. package/dist/scaffold/ensure-config.js +1 -1
  94. package/dist/scaffold/ensure-config.js.map +1 -1
  95. package/dist/store/attachment-store.d.ts.map +1 -1
  96. package/dist/store/attachment-store.js +2 -1
  97. package/dist/store/attachment-store.js.map +1 -1
  98. package/dist/store/restore-marker.d.ts +50 -7
  99. package/dist/store/restore-marker.d.ts.map +1 -1
  100. package/dist/store/restore-marker.js +77 -25
  101. package/dist/store/restore-marker.js.map +1 -1
  102. package/dist/store/row-identity-registry.d.ts +6 -4
  103. package/dist/store/row-identity-registry.d.ts.map +1 -1
  104. package/dist/store/row-identity-registry.js +156 -33
  105. package/dist/store/row-identity-registry.js.map +1 -1
  106. package/dist/store/schema/cleo-project/provenance-orphans.d.ts +16 -0
  107. package/dist/store/schema/cleo-project/provenance-orphans.d.ts.map +1 -1
  108. package/dist/store/schema/cleo-project/provenance-orphans.js +4 -1
  109. package/dist/store/schema/cleo-project/provenance-orphans.js.map +1 -1
  110. package/dist/store/schema/cleo-shared/brain.d.ts +240 -0
  111. package/dist/store/schema/cleo-shared/brain.d.ts.map +1 -1
  112. package/dist/store/schema/cleo-shared/brain.js +69 -0
  113. package/dist/store/schema/cleo-shared/brain.js.map +1 -1
  114. package/dist/store/schema/tasks.d.ts +1 -1
  115. package/dist/store/schema/tasks.d.ts.map +1 -1
  116. package/dist/store/schema/tasks.js +9 -1
  117. package/dist/store/schema/tasks.js.map +1 -1
  118. package/dist/store/sync/apply/applier.d.ts.map +1 -1
  119. package/dist/store/sync/apply/applier.js +85 -3
  120. package/dist/store/sync/apply/applier.js.map +1 -1
  121. package/dist/store/sync/apply/parent-delete.d.ts.map +1 -1
  122. package/dist/store/sync/apply/parent-delete.js +4 -0
  123. package/dist/store/sync/apply/parent-delete.js.map +1 -1
  124. package/dist/store/sync/capture.d.ts +8 -0
  125. package/dist/store/sync/capture.d.ts.map +1 -1
  126. package/dist/store/sync/capture.js +20 -0
  127. package/dist/store/sync/capture.js.map +1 -1
  128. package/dist/store/sync/clock-store.d.ts +21 -0
  129. package/dist/store/sync/clock-store.d.ts.map +1 -1
  130. package/dist/store/sync/clock-store.js +47 -0
  131. package/dist/store/sync/clock-store.js.map +1 -1
  132. package/dist/store/sync/conflicts.d.ts +13 -0
  133. package/dist/store/sync/conflicts.d.ts.map +1 -1
  134. package/dist/store/sync/conflicts.js +22 -0
  135. package/dist/store/sync/conflicts.js.map +1 -1
  136. package/dist/store/sync/genesis.d.ts +113 -12
  137. package/dist/store/sync/genesis.d.ts.map +1 -1
  138. package/dist/store/sync/genesis.js +325 -27
  139. package/dist/store/sync/genesis.js.map +1 -1
  140. package/dist/store/sync/merge/types.d.ts +8 -2
  141. package/dist/store/sync/merge/types.d.ts.map +1 -1
  142. package/dist/store/sync/pull.d.ts +192 -0
  143. package/dist/store/sync/pull.d.ts.map +1 -0
  144. package/dist/store/sync/pull.js +429 -0
  145. package/dist/store/sync/pull.js.map +1 -0
  146. package/dist/store/sync/push.d.ts +110 -0
  147. package/dist/store/sync/push.d.ts.map +1 -0
  148. package/dist/store/sync/push.js +172 -0
  149. package/dist/store/sync/push.js.map +1 -0
  150. package/dist/store/sync/replay-pin.d.ts +70 -0
  151. package/dist/store/sync/replay-pin.d.ts.map +1 -0
  152. package/dist/store/sync/replay-pin.js +172 -0
  153. package/dist/store/sync/replay-pin.js.map +1 -0
  154. package/dist/store/sync/sealer.d.ts.map +1 -1
  155. package/dist/store/sync/sealer.js +6 -2
  156. package/dist/store/sync/sealer.js.map +1 -1
  157. package/dist/store/sync/timestamp-canon.d.ts.map +1 -1
  158. package/dist/store/sync/timestamp-canon.js +15 -0
  159. package/dist/store/sync/timestamp-canon.js.map +1 -1
  160. package/dist/store/table-classification.d.ts.map +1 -1
  161. package/dist/store/table-classification.js +51 -15
  162. package/dist/store/table-classification.js.map +1 -1
  163. package/dist/store/tasks-schema.d.ts +1 -1
  164. package/dist/store/tasks-schema.d.ts.map +1 -1
  165. package/dist/store/tasks-schema.js +1 -1
  166. package/dist/store/tasks-schema.js.map +1 -1
  167. package/dist/store/twin-collapse.d.ts.map +1 -1
  168. package/dist/store/twin-collapse.js +5 -0
  169. package/dist/store/twin-collapse.js.map +1 -1
  170. package/dist/store/vault-manifest.d.ts +7 -0
  171. package/dist/store/vault-manifest.d.ts.map +1 -1
  172. package/dist/store/vault-manifest.js +4 -0
  173. package/dist/store/vault-manifest.js.map +1 -1
  174. package/dist/tasks/ac-table.d.ts +17 -0
  175. package/dist/tasks/ac-table.d.ts.map +1 -1
  176. package/dist/tasks/ac-table.js +49 -0
  177. package/dist/tasks/ac-table.js.map +1 -1
  178. package/dist/tasks/affected-scope.d.ts +52 -3
  179. package/dist/tasks/affected-scope.d.ts.map +1 -1
  180. package/dist/tasks/affected-scope.js +94 -3
  181. package/dist/tasks/affected-scope.js.map +1 -1
  182. package/dist/tasks/change-set.d.ts.map +1 -1
  183. package/dist/tasks/change-set.js +9 -5
  184. package/dist/tasks/change-set.js.map +1 -1
  185. package/dist/tasks/complete-ci.d.ts +2 -0
  186. package/dist/tasks/complete-ci.d.ts.map +1 -1
  187. package/dist/tasks/complete-ci.js +26 -7
  188. package/dist/tasks/complete-ci.js.map +1 -1
  189. package/dist/tasks/complete.d.ts.map +1 -1
  190. package/dist/tasks/complete.js +10 -0
  191. package/dist/tasks/complete.js.map +1 -1
  192. package/dist/tasks/done-plan.d.ts.map +1 -1
  193. package/dist/tasks/done-plan.js +63 -6
  194. package/dist/tasks/done-plan.js.map +1 -1
  195. package/dist/tasks/evidence.d.ts +3 -0
  196. package/dist/tasks/evidence.d.ts.map +1 -1
  197. package/dist/tasks/evidence.js +106 -2
  198. package/dist/tasks/evidence.js.map +1 -1
  199. package/dist/tasks/gate-preview.d.ts +19 -1
  200. package/dist/tasks/gate-preview.d.ts.map +1 -1
  201. package/dist/tasks/gate-preview.js +44 -2
  202. package/dist/tasks/gate-preview.js.map +1 -1
  203. package/dist/tasks/gate-runner.d.ts +16 -0
  204. package/dist/tasks/gate-runner.d.ts.map +1 -1
  205. package/dist/tasks/gate-runner.js +25 -2
  206. package/dist/tasks/gate-runner.js.map +1 -1
  207. package/dist/tasks/qa-run-binding.d.ts +88 -0
  208. package/dist/tasks/qa-run-binding.d.ts.map +1 -0
  209. package/dist/tasks/qa-run-binding.js +188 -0
  210. package/dist/tasks/qa-run-binding.js.map +1 -0
  211. package/dist/tasks/req.d.ts +50 -0
  212. package/dist/tasks/req.d.ts.map +1 -1
  213. package/dist/tasks/req.js +99 -1
  214. package/dist/tasks/req.js.map +1 -1
  215. package/dist/tasks/test-run-binding.d.ts +29 -0
  216. package/dist/tasks/test-run-binding.d.ts.map +1 -1
  217. package/dist/tasks/test-run-binding.js +47 -23
  218. package/dist/tasks/test-run-binding.js.map +1 -1
  219. package/dist/tasks/tool-resolver.d.ts +9 -0
  220. package/dist/tasks/tool-resolver.d.ts.map +1 -1
  221. package/dist/tasks/tool-resolver.js +14 -3
  222. package/dist/tasks/tool-resolver.js.map +1 -1
  223. package/dist/tasks/tool-semaphore.d.ts.map +1 -1
  224. package/dist/tasks/tool-semaphore.js +3 -0
  225. package/dist/tasks/tool-semaphore.js.map +1 -1
  226. package/dist/upgrade.d.ts.map +1 -1
  227. package/dist/upgrade.js +10 -1
  228. package/dist/upgrade.js.map +1 -1
  229. package/dist/validation/engine-ops.d.ts.map +1 -1
  230. package/dist/validation/engine-ops.js +14 -3
  231. package/dist/validation/engine-ops.js.map +1 -1
  232. package/migrations/drizzle-cleo-global/20261010130000_t12895-brain-natural-uids/migration.sql +28 -0
  233. package/migrations/drizzle-cleo-global/20261010140000_t12896-brain-autoinc-uids/migration.sql +54 -0
  234. package/migrations/drizzle-cleo-project/20261010130000_t12895-brain-natural-uids/migration.sql +36 -0
  235. package/migrations/drizzle-cleo-project/20261010140000_t12896-brain-autoinc-uids/migration.sql +58 -0
  236. package/migrations/sync-journal/20261008120000_t12343-pull-cursor/migration.sql +28 -0
  237. package/migrations/sync-journal/20261009120000_t13318-seen-floor/migration.sql +41 -0
  238. package/package.json +18 -18
  239. package/templates/CLEO-INJECTION.md +5 -3
  240. package/templates/CLEO-REFERENCE.md +1 -1
  241. package/templates/git-hooks/legacy-hashes.json +20 -0
  242. package/templates/git-hooks/pre-commit +1 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Pull one stream's journal into the store (journal spec §3.1 "Receive",
3
+ * §2.9; T12343 S5-1).
4
+ *
5
+ * {@link pullStream} pages through the stream after the store's persisted
6
+ * `_sync_cursor` (the journal client verifies order, gaps, the replica-to-
7
+ * device pin, trust, hashes and decryption before anything is returned),
8
+ * and for each segment, in ONE local transaction per page:
9
+ * - decodes it: `deflate-raw(canonical JSON of LedgerTxn[])`, parsed with
10
+ * the ledger schema; a vault delta segment (`cleo-vault-delta/v1`, a count
11
+ * correction a vault push appended before the stream's genesis) carries no
12
+ * ops and is passed over;
13
+ * - checks every transaction's signature against the segment's device key
14
+ * (§2.8); one bad signature refuses the segment, and the pull stops there:
15
+ * the segments before it are staged and applied, the segment and what
16
+ * follows are not;
17
+ * - skips every transaction id already staged from this stream
18
+ * (`_sync_seen_txn`): a re-delivered transaction is never staged twice, so
19
+ * a counter delta is never applied twice;
20
+ * - refuses a transaction at or below its origin's floor that has no seen
21
+ * row (`_sync_seen_floor`, T13318): an origin's transactions are first
22
+ * delivered in `local_seq` order, so such a transaction was either pruned
23
+ * from the seen ledger or arrived out of order; the pull stops there, loud,
24
+ * and never skips it as seen;
25
+ * - stages the rest (`stageTxns`), schema-ahead ones included (the applier
26
+ * holds them `refused-schema` and replays them after an upgrade);
27
+ * - advances the cursor.
28
+ *
29
+ * Then the applier applies what is staged, in stream order, own echoes
30
+ * included (they feed the fast path and the scoped rebase, §3.5).
31
+ *
32
+ * The page source is a port ({@link SegmentPuller}): the journal client in
33
+ * production (`cloud/nexus-vault.ts`), a fake in tests.
34
+ *
35
+ * @task T12343
36
+ * @module store/sync/pull
37
+ */
38
+ import type { DatabaseSync } from 'node:sqlite';
39
+ import type { TableScope } from '@cleocode/contracts';
40
+ import { LedgerTxn } from '@cleocode/contracts/ledger';
41
+ import { type ApplyReport, type ApplyStagedOptions } from './apply/applier.js';
42
+ /** Where a pull stands (the journal client's `PullCursor`). */
43
+ export interface StreamCursor {
44
+ /** The last stream seq staged. */
45
+ readonly after: number;
46
+ /** Whether `replicas` lists every replica with a segment at or below `after`. */
47
+ readonly knowsAllReplicas: boolean;
48
+ /** Per replica: the device pinned to it and its last replicaSeq staged. */
49
+ readonly replicas: Readonly<Record<string, {
50
+ readonly deviceId: string;
51
+ readonly replicaSeq: number;
52
+ }>>;
53
+ }
54
+ /** One verified, decrypted segment, as the journal client returns it. */
55
+ export interface PulledStreamSegment {
56
+ readonly seq: number;
57
+ readonly replicaId: string;
58
+ readonly replicaSeq: number;
59
+ readonly deviceId: string;
60
+ readonly plaintext: Uint8Array;
61
+ readonly schemaVersion: number;
62
+ }
63
+ /** Pulls the next verified page after `cursor`. */
64
+ export type SegmentPuller = (cursor: StreamCursor) => Promise<{
65
+ readonly segments: readonly PulledStreamSegment[];
66
+ readonly cursor: StreamCursor;
67
+ readonly head: number;
68
+ }>;
69
+ /** The index of a segment's first transaction its device did not sign, or null when every one is signed. */
70
+ export type TxnVerifier = (deviceId: string, txns: readonly LedgerTxn[]) => number | null;
71
+ /** The plaintext kind of a vault count-delta segment (`cloud/nexus-vault.ts`). */
72
+ export declare const VAULT_DELTA_KIND = "cleo-vault-delta/v1";
73
+ /** Options for {@link pullStream}. */
74
+ export interface PullStreamOptions {
75
+ readonly scope: TableScope;
76
+ readonly stream: string;
77
+ /** This store's bound replica (own echoes are recognised by it). */
78
+ readonly replica: string;
79
+ readonly pull: SegmentPuller;
80
+ readonly verify: TxnVerifier;
81
+ /** The cursor to start from when the store has none persisted (the checkpoint it was cut from or restored). */
82
+ readonly initialCursor: StreamCursor;
83
+ /** Wall clock. @defaultValue Date.now */
84
+ readonly now?: () => number;
85
+ /** Seals pending local captures before a rebase (the applier's `seal`). */
86
+ readonly seal: ApplyStagedOptions['seal'];
87
+ /** Applier options passed through (pages, budget). */
88
+ readonly apply?: Partial<Pick<ApplyStagedOptions, 'pageOps' | 'pageMs' | 'undoBudgetBytes'>>;
89
+ /** Environment for the `sync.pull` kill switch. @defaultValue process.env */
90
+ readonly env?: NodeJS.ProcessEnv;
91
+ /**
92
+ * After staging, drop each origin's seen-txn rows below its staged floor
93
+ * ({@link pruneSeenTxns}, T13318). A pruned transaction delivered again is
94
+ * refused (`below-floor`), never applied twice. @defaultValue false
95
+ */
96
+ readonly pruneSeen?: boolean;
97
+ }
98
+ /**
99
+ * Why {@link pullStream} stopped short, as a kind callers branch on (the
100
+ * message in `refused` is for people and may be reworded):
101
+ * - `pull-off`: `sync.pull` is off, nothing was pulled;
102
+ * - `segment`: a segment is malformed, carries a transaction its device did
103
+ * not sign, or a transaction that is not its replica's;
104
+ * - `below-floor`: a segment carries a transaction at or below its origin's
105
+ * staged floor with no seen row: pruned from the seen ledger, or delivered
106
+ * out of `local_seq` order (T13318).
107
+ */
108
+ export type PullRefusal = 'pull-off' | 'segment' | 'below-floor';
109
+ /** What {@link pullStream} did. */
110
+ export interface PullStreamReport {
111
+ readonly stream: string;
112
+ /**
113
+ * Why the pull stopped short, or null: `sync.pull` off (nothing pulled), or
114
+ * a refused segment (a malformed body or a transaction its device did not
115
+ * sign), naming its seq, replica and device. Everything before a refused
116
+ * segment was staged and applied, and the cursor stops just before it.
117
+ */
118
+ readonly refused: string | null;
119
+ /** The kind of `refused` ({@link PullRefusal}), or null when nothing was refused. */
120
+ readonly refusedKind: PullRefusal | null;
121
+ /** Segments received, vault deltas passed over, transactions staged, re-deliveries skipped. */
122
+ readonly segments: number;
123
+ readonly vaultDeltas: number;
124
+ readonly staged: number;
125
+ readonly redelivered: number;
126
+ /** The stream position the store has staged up to, and the server's head. */
127
+ readonly after: number;
128
+ readonly head: number;
129
+ /** What the applier did, or null when the pull was refused. */
130
+ readonly apply: ApplyReport | null;
131
+ }
132
+ /** A segment the store refuses to stage (a malformed body or a bad transaction signature). */
133
+ export declare class SegmentRefusedError extends Error {
134
+ readonly code = "E_SYNC_SEGMENT_REFUSED";
135
+ }
136
+ /** The store's persisted cursor for `stream`, or null. */
137
+ export declare function readStreamCursor(db: DatabaseSync, stream: string): StreamCursor | null;
138
+ /**
139
+ * Persist the store's pull position for `stream`, in the caller's
140
+ * transaction (the pull's page, or a JOIN seeding it from the checkpoint it
141
+ * restored).
142
+ *
143
+ * @param db - The store.
144
+ * @param stream - The stream.
145
+ * @param cursor - The position.
146
+ * @param nowIso - The time.
147
+ */
148
+ export declare function writeStreamCursor(db: DatabaseSync, stream: string, cursor: StreamCursor, nowIso: string): void;
149
+ /**
150
+ * The size of `_sync_seen_txn` (T13317), for `cleo cloud status`: rows per
151
+ * stream and the estimated payload bytes (stream and txn text plus the seq
152
+ * integer, without SQLite's page overhead). Read-only, and O(origins): it
153
+ * sums the per-origin counts `_sync_seen_floor` keeps with every insert and
154
+ * prune (T13318), never the ledger itself.
155
+ *
156
+ * @param db - The store.
157
+ * @returns Zeroes when the tables are not installed; the ledger walked when
158
+ * only the floor table is missing.
159
+ */
160
+ export declare function seenTxnReport(db: DatabaseSync): {
161
+ rows: number;
162
+ bytes: number;
163
+ byStream: Record<string, number>;
164
+ };
165
+ /**
166
+ * Drop each origin's seen-txn rows of `stream` below its staged floor,
167
+ * keeping `_sync_seen_txn` bounded (§3.1, T13318), and record how far each
168
+ * origin was pruned (`pruned_upto`). Safe because an origin's transactions
169
+ * are first delivered in `local_seq` order and the pull refuses any
170
+ * transaction at or below the floor that has no seen row (`below-floor`):
171
+ * a pruned transaction delivered again is refused loudly, never applied
172
+ * twice. The row at the floor itself is kept, so re-delivery of the latest
173
+ * transaction is still skipped quietly.
174
+ *
175
+ * @param db - The store, outside a transaction.
176
+ * @param stream - The stream.
177
+ * @returns How many rows were dropped.
178
+ */
179
+ export declare function pruneSeenTxns(db: DatabaseSync, stream: string): number;
180
+ /**
181
+ * Pull and stage a stream's new segments, then apply (module docs). Must run
182
+ * outside a transaction. A refused segment stops the pull: everything
183
+ * before it is staged and applied, the cursor stops just before it, and the
184
+ * report's `refused` names it (T13307), so the next pull reaches it again
185
+ * without re-staging anything.
186
+ *
187
+ * @param db - The store.
188
+ * @param o - {@link PullStreamOptions}.
189
+ * @returns What was received, staged and applied.
190
+ */
191
+ export declare function pullStream(db: DatabaseSync, o: PullStreamOptions): Promise<PullStreamReport>;
192
+ //# sourceMappingURL=pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/store/sync/pull.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,429 @@
1
+ /**
2
+ * Pull one stream's journal into the store (journal spec §3.1 "Receive",
3
+ * §2.9; T12343 S5-1).
4
+ *
5
+ * {@link pullStream} pages through the stream after the store's persisted
6
+ * `_sync_cursor` (the journal client verifies order, gaps, the replica-to-
7
+ * device pin, trust, hashes and decryption before anything is returned),
8
+ * and for each segment, in ONE local transaction per page:
9
+ * - decodes it: `deflate-raw(canonical JSON of LedgerTxn[])`, parsed with
10
+ * the ledger schema; a vault delta segment (`cleo-vault-delta/v1`, a count
11
+ * correction a vault push appended before the stream's genesis) carries no
12
+ * ops and is passed over;
13
+ * - checks every transaction's signature against the segment's device key
14
+ * (§2.8); one bad signature refuses the segment, and the pull stops there:
15
+ * the segments before it are staged and applied, the segment and what
16
+ * follows are not;
17
+ * - skips every transaction id already staged from this stream
18
+ * (`_sync_seen_txn`): a re-delivered transaction is never staged twice, so
19
+ * a counter delta is never applied twice;
20
+ * - refuses a transaction at or below its origin's floor that has no seen
21
+ * row (`_sync_seen_floor`, T13318): an origin's transactions are first
22
+ * delivered in `local_seq` order, so such a transaction was either pruned
23
+ * from the seen ledger or arrived out of order; the pull stops there, loud,
24
+ * and never skips it as seen;
25
+ * - stages the rest (`stageTxns`), schema-ahead ones included (the applier
26
+ * holds them `refused-schema` and replays them after an upgrade);
27
+ * - advances the cursor.
28
+ *
29
+ * Then the applier applies what is staged, in stream order, own echoes
30
+ * included (they feed the fast path and the scoped rebase, §3.5).
31
+ *
32
+ * The page source is a port ({@link SegmentPuller}): the journal client in
33
+ * production (`cloud/nexus-vault.ts`), a fake in tests.
34
+ *
35
+ * @task T12343
36
+ * @module store/sync/pull
37
+ */
38
+ import { inflateRawSync } from 'node:zlib';
39
+ import { LedgerTxn } from '@cleocode/contracts/ledger';
40
+ import { applyStagedTxns } from './apply/applier.js';
41
+ import { withImmediateTransaction } from './clock-store.js';
42
+ import { isSyncFlagOn } from './flags.js';
43
+ import { stageTxns } from './inbox.js';
44
+ import { ensureSyncSchema, hasTable, healSyncSchema } from './schema.js';
45
+ /** The plaintext kind of a vault count-delta segment (`cloud/nexus-vault.ts`). */
46
+ export const VAULT_DELTA_KIND = 'cleo-vault-delta/v1';
47
+ /** A segment the store refuses to stage (a malformed body or a bad transaction signature). */
48
+ export class SegmentRefusedError extends Error {
49
+ code = 'E_SYNC_SEGMENT_REFUSED';
50
+ }
51
+ /** The store's persisted cursor for `stream`, or null. */
52
+ export function readStreamCursor(db, stream) {
53
+ if (!hasTable(db, '_sync_cursor'))
54
+ return null;
55
+ const row = db.prepare('SELECT cursor_json FROM _sync_cursor WHERE stream = ?').get(stream);
56
+ return row ? JSON.parse(row.cursor_json) : null;
57
+ }
58
+ /**
59
+ * Persist the store's pull position for `stream`, in the caller's
60
+ * transaction (the pull's page, or a JOIN seeding it from the checkpoint it
61
+ * restored).
62
+ *
63
+ * @param db - The store.
64
+ * @param stream - The stream.
65
+ * @param cursor - The position.
66
+ * @param nowIso - The time.
67
+ */
68
+ export function writeStreamCursor(db, stream, cursor, nowIso) {
69
+ db.prepare('INSERT INTO _sync_cursor (stream, cursor_json, updated_at) VALUES (?, ?, ?) ' +
70
+ 'ON CONFLICT (stream) DO UPDATE SET cursor_json = excluded.cursor_json, updated_at = excluded.updated_at').run(stream, JSON.stringify(cursor), nowIso);
71
+ }
72
+ /** Decode a segment's transactions, or `null` for a vault delta segment. */
73
+ function decode(seg) {
74
+ let text;
75
+ try {
76
+ text = inflateRawSync(seg.plaintext).toString('utf8');
77
+ }
78
+ catch {
79
+ // Not deflated: a vault delta segment is plain JSON.
80
+ try {
81
+ const raw = JSON.parse(Buffer.from(seg.plaintext).toString('utf8'));
82
+ if (typeof raw === 'object' &&
83
+ raw !== null &&
84
+ 'kind' in raw &&
85
+ raw.kind === VAULT_DELTA_KIND) {
86
+ return null;
87
+ }
88
+ }
89
+ catch {
90
+ // fall through to the refusal
91
+ }
92
+ // @sync-invariant none:input-shape a segment body that is neither a ledger segment nor a vault delta is never staged
93
+ throw new SegmentRefusedError(`segment ${seg.seq} of replica ${seg.replicaId}: not a ledger segment`);
94
+ }
95
+ const parsed = LedgerTxn.array().safeParse(JSON.parse(text));
96
+ if (!parsed.success) {
97
+ // @sync-invariant none:input-shape a ledger segment that does not parse is never staged
98
+ throw new SegmentRefusedError(`segment ${seg.seq} of replica ${seg.replicaId}: transactions do not parse`);
99
+ }
100
+ return parsed.data;
101
+ }
102
+ /** A segment's transactions (null for a vault delta), or why it is refused. */
103
+ function refusalOf(seg, verify) {
104
+ let txns;
105
+ try {
106
+ txns = decode(seg);
107
+ }
108
+ catch (err) {
109
+ if (err instanceof SegmentRefusedError)
110
+ return err.message;
111
+ throw err;
112
+ }
113
+ if (txns !== null) {
114
+ const bad = verify(seg.deviceId, txns);
115
+ if (bad !== null) {
116
+ return `segment ${seg.seq} of replica ${seg.replicaId}: transaction ${bad} is not signed by device ${seg.deviceId}`;
117
+ }
118
+ // A replica packs only its own transactions (`buildSegment`); the floor
119
+ // is kept per origin, so a foreign id is refused, never staged.
120
+ const foreign = txns.find((t) => localSeqOf(t.txn, seg.replicaId) === null);
121
+ if (foreign !== undefined) {
122
+ return `segment ${seg.seq} of replica ${seg.replicaId}: transaction ${foreign.txn} is not one of its transactions`;
123
+ }
124
+ }
125
+ return { txns };
126
+ }
127
+ /**
128
+ * The `local_seq` of `txn` when it is `replica`'s (`<replica>:<local_seq>`,
129
+ * minted by the sealer from 1), else null.
130
+ */
131
+ function localSeqOf(txn, replica) {
132
+ const prefix = `${replica}:`;
133
+ if (!txn.startsWith(prefix))
134
+ return null;
135
+ const rest = txn.slice(prefix.length);
136
+ if (!/^[1-9][0-9]*$/.test(rest))
137
+ return null;
138
+ const n = Number(rest);
139
+ return Number.isSafeInteger(n) ? n : null;
140
+ }
141
+ function readFloor(db, stream, origin) {
142
+ const row = db
143
+ .prepare('SELECT staged_upto, pruned_upto FROM _sync_seen_floor WHERE stream = ? AND origin = ?')
144
+ .get(stream, origin);
145
+ return row
146
+ ? { stagedUpto: Number(row.staged_upto), prunedUpto: Number(row.pruned_upto) }
147
+ : { stagedUpto: 0, prunedUpto: 0 };
148
+ }
149
+ /**
150
+ * Split a verified segment's transactions into re-deliveries (a seen row
151
+ * exists) and fresh ones, against the origin's floor (T13318). Read-only. A
152
+ * transaction with no seen row at or below the floor refuses the whole
153
+ * segment: its seen row was pruned, or it arrived out of `local_seq` order,
154
+ * and either way skipping it as seen could lose it.
155
+ */
156
+ function planFresh(db, stream, seg, txns) {
157
+ const floor = readFloor(db, stream, seg.replicaId);
158
+ const isSeen = db.prepare('SELECT 1 FROM _sync_seen_txn WHERE stream = ? AND txn = ?');
159
+ const inSegment = new Set();
160
+ const fresh = [];
161
+ let redelivered = 0;
162
+ let upto = floor.stagedUpto;
163
+ for (const t of txns) {
164
+ if (inSegment.has(t.txn) || isSeen.get(stream, t.txn) !== undefined) {
165
+ redelivered += 1;
166
+ continue;
167
+ }
168
+ // refusalOf proved every id is the segment replica's.
169
+ const seq = localSeqOf(t.txn, seg.replicaId) ?? 0;
170
+ if (seq <= upto) {
171
+ const why = seq <= floor.prunedUpto
172
+ ? `its seen row was pruned (pruned_upto ${floor.prunedUpto})`
173
+ : 'it arrived out of local_seq order';
174
+ return {
175
+ refused: `segment ${seg.seq} of replica ${seg.replicaId}: transaction ${t.txn} is at or below the origin's staged floor ${upto} on ${stream} with no seen row: ${why}; it is not staged`,
176
+ };
177
+ }
178
+ inSegment.add(t.txn);
179
+ fresh.push(t);
180
+ upto = seq;
181
+ }
182
+ return { fresh, redelivered, stagedUpto: upto };
183
+ }
184
+ /** `cursor` advanced over `segs` (a page cut short by a refused segment). */
185
+ function advance(cursor, segs) {
186
+ const replicas = { ...cursor.replicas };
187
+ for (const s of segs)
188
+ replicas[s.replicaId] = { deviceId: s.deviceId, replicaSeq: s.replicaSeq };
189
+ return {
190
+ after: segs.at(-1)?.seq ?? cursor.after,
191
+ knowsAllReplicas: cursor.knowsAllReplicas,
192
+ replicas,
193
+ };
194
+ }
195
+ /** Bytes counted for a seen-txn row's `seq` integer. */
196
+ const SEEN_SEQ_BYTES = 8;
197
+ /** Estimated payload bytes of one seen-txn row (stream and txn text plus the seq integer). */
198
+ const seenBytes = (stream, txn) => Buffer.byteLength(stream, 'utf8') + Buffer.byteLength(txn, 'utf8') + SEEN_SEQ_BYTES;
199
+ /**
200
+ * Install the floor table before a pull: a store whose journal predates it
201
+ * gains it, and a store whose journal records the folder but lost the table
202
+ * gets it re-created (§2.3a rule 9), its counts re-seeded from the seen rows.
203
+ *
204
+ * @param db - The store, outside a transaction.
205
+ */
206
+ function ensureSeenFloor(db) {
207
+ if (hasTable(db, '_sync_seen_floor'))
208
+ return;
209
+ ensureSyncSchema(db);
210
+ healSyncSchema(db, ['_sync_seen_floor']);
211
+ }
212
+ /**
213
+ * {@link seenTxnReport} for a store with seen rows but no floor table yet
214
+ * (its next pull installs it): the ledger walked once, O(rows).
215
+ */
216
+ function seenLedgerWalk(db) {
217
+ const byStream = {};
218
+ let rows = 0;
219
+ let bytes = 0;
220
+ if (!hasTable(db, '_sync_seen_txn'))
221
+ return { rows, bytes, byStream };
222
+ for (const r of db
223
+ .prepare(`SELECT stream, count(*) AS n, sum(octet_length(stream) + octet_length(txn) + ${SEEN_SEQ_BYTES}) AS b
224
+ FROM _sync_seen_txn GROUP BY stream ORDER BY stream`)
225
+ .all()) {
226
+ byStream[r.stream] = Number(r.n);
227
+ rows += Number(r.n);
228
+ bytes += Number(r.b ?? 0);
229
+ }
230
+ return { rows, bytes, byStream };
231
+ }
232
+ /**
233
+ * The size of `_sync_seen_txn` (T13317), for `cleo cloud status`: rows per
234
+ * stream and the estimated payload bytes (stream and txn text plus the seq
235
+ * integer, without SQLite's page overhead). Read-only, and O(origins): it
236
+ * sums the per-origin counts `_sync_seen_floor` keeps with every insert and
237
+ * prune (T13318), never the ledger itself.
238
+ *
239
+ * @param db - The store.
240
+ * @returns Zeroes when the tables are not installed; the ledger walked when
241
+ * only the floor table is missing.
242
+ */
243
+ export function seenTxnReport(db) {
244
+ if (!hasTable(db, '_sync_seen_floor'))
245
+ return seenLedgerWalk(db);
246
+ const byStream = {};
247
+ let rows = 0;
248
+ let bytes = 0;
249
+ for (const r of db
250
+ .prepare(`SELECT stream, sum(seen_rows) AS n, sum(seen_bytes) AS b
251
+ FROM _sync_seen_floor GROUP BY stream HAVING sum(seen_rows) > 0 ORDER BY stream`)
252
+ .all()) {
253
+ byStream[r.stream] = Number(r.n);
254
+ rows += Number(r.n);
255
+ bytes += Number(r.b ?? 0);
256
+ }
257
+ return { rows, bytes, byStream };
258
+ }
259
+ /**
260
+ * Drop each origin's seen-txn rows of `stream` below its staged floor,
261
+ * keeping `_sync_seen_txn` bounded (§3.1, T13318), and record how far each
262
+ * origin was pruned (`pruned_upto`). Safe because an origin's transactions
263
+ * are first delivered in `local_seq` order and the pull refuses any
264
+ * transaction at or below the floor that has no seen row (`below-floor`):
265
+ * a pruned transaction delivered again is refused loudly, never applied
266
+ * twice. The row at the floor itself is kept, so re-delivery of the latest
267
+ * transaction is still skipped quietly.
268
+ *
269
+ * @param db - The store, outside a transaction.
270
+ * @param stream - The stream.
271
+ * @returns How many rows were dropped.
272
+ */
273
+ export function pruneSeenTxns(db, stream) {
274
+ if (!hasTable(db, '_sync_seen_floor'))
275
+ return 0;
276
+ return withImmediateTransaction(db, () => {
277
+ const floors = db
278
+ .prepare('SELECT origin, staged_upto FROM _sync_seen_floor WHERE stream = ? AND staged_upto - 1 > pruned_upto')
279
+ .all(stream);
280
+ // The origin's ids sort between '<origin>:' and '<origin>;' (':' + 1),
281
+ // a range of the (stream, txn) primary key.
282
+ const rowsOf = db.prepare(`SELECT txn FROM _sync_seen_txn
283
+ WHERE stream = ? AND txn >= ? AND txn < ? AND CAST(substr(txn, ?) AS INTEGER) <= ?`);
284
+ const drop = db.prepare('DELETE FROM _sync_seen_txn WHERE stream = ? AND txn = ?');
285
+ const mark = db.prepare(`UPDATE _sync_seen_floor
286
+ SET pruned_upto = ?, seen_rows = max(seen_rows - ?, 0), seen_bytes = max(seen_bytes - ?, 0)
287
+ WHERE stream = ? AND origin = ?`);
288
+ let dropped = 0;
289
+ for (const f of floors) {
290
+ const upto = Number(f.staged_upto) - 1;
291
+ const victims = rowsOf.all(stream, `${f.origin}:`, `${f.origin};`, f.origin.length + 2, upto);
292
+ let bytes = 0;
293
+ for (const v of victims) {
294
+ drop.run(stream, v.txn);
295
+ bytes += seenBytes(stream, v.txn);
296
+ }
297
+ mark.run(upto, victims.length, bytes, stream, f.origin);
298
+ dropped += victims.length;
299
+ }
300
+ return dropped;
301
+ });
302
+ }
303
+ /**
304
+ * Pull and stage a stream's new segments, then apply (module docs). Must run
305
+ * outside a transaction. A refused segment stops the pull: everything
306
+ * before it is staged and applied, the cursor stops just before it, and the
307
+ * report's `refused` names it (T13307), so the next pull reaches it again
308
+ * without re-staging anything.
309
+ *
310
+ * @param db - The store.
311
+ * @param o - {@link PullStreamOptions}.
312
+ * @returns What was received, staged and applied.
313
+ */
314
+ export async function pullStream(db, o) {
315
+ const now = o.now ?? Date.now;
316
+ if (!isSyncFlagOn(db, 'sync.pull', o.env ?? process.env)) {
317
+ return {
318
+ stream: o.stream,
319
+ refused: 'sync.pull is off',
320
+ refusedKind: 'pull-off',
321
+ segments: 0,
322
+ vaultDeltas: 0,
323
+ staged: 0,
324
+ redelivered: 0,
325
+ after: readStreamCursor(db, o.stream)?.after ?? o.initialCursor.after,
326
+ head: 0,
327
+ apply: null,
328
+ };
329
+ }
330
+ ensureSeenFloor(db);
331
+ let cursor = readStreamCursor(db, o.stream) ?? o.initialCursor;
332
+ let segments = 0;
333
+ let vaultDeltas = 0;
334
+ let staged = 0;
335
+ let redelivered = 0;
336
+ let head = cursor.after;
337
+ let refused = null;
338
+ let refusedKind = null;
339
+ for (;;) {
340
+ const page = await o.pull(cursor);
341
+ head = page.head;
342
+ const nowIso = new Date(now()).toISOString();
343
+ // Decode and verify the page before writing anything of it, up to the
344
+ // first segment refused (T13307): what precedes it is staged and applied,
345
+ // the cursor stops just before it, and the refusal is reported.
346
+ const decoded = [];
347
+ for (const seg of page.segments) {
348
+ const why = refusalOf(seg, o.verify);
349
+ if (typeof why === 'string') {
350
+ refused = why;
351
+ refusedKind = 'segment';
352
+ break;
353
+ }
354
+ decoded.push({ seg, txns: why.txns });
355
+ }
356
+ cursor = withImmediateTransaction(db, () => {
357
+ const seen = db.prepare('INSERT INTO _sync_seen_txn (stream, txn, seq) VALUES (?, ?, ?)');
358
+ const raise = db.prepare(`INSERT INTO _sync_seen_floor (stream, origin, staged_upto, seen_rows, seen_bytes)
359
+ VALUES (?, ?, ?, ?, ?)
360
+ ON CONFLICT (stream, origin) DO UPDATE SET
361
+ staged_upto = excluded.staged_upto,
362
+ seen_rows = seen_rows + excluded.seen_rows,
363
+ seen_bytes = seen_bytes + excluded.seen_bytes`);
364
+ const done = [];
365
+ for (const { seg, txns } of decoded) {
366
+ if (txns !== null) {
367
+ const plan = planFresh(db, o.stream, seg, txns);
368
+ if ('refused' in plan) {
369
+ refused = plan.refused;
370
+ refusedKind = 'below-floor';
371
+ break;
372
+ }
373
+ redelivered += plan.redelivered;
374
+ if (plan.fresh.length > 0) {
375
+ let bytes = 0;
376
+ for (const t of plan.fresh) {
377
+ seen.run(o.stream, t.txn, seg.seq);
378
+ bytes += seenBytes(o.stream, t.txn);
379
+ }
380
+ raise.run(o.stream, seg.replicaId, plan.stagedUpto, plan.fresh.length, bytes);
381
+ staged += stageTxns(db, o.stream, {
382
+ seq: seg.seq,
383
+ replicaId: seg.replicaId,
384
+ replicaSeq: seg.replicaSeq,
385
+ deviceId: seg.deviceId,
386
+ schemaVersion: seg.schemaVersion,
387
+ txns: plan.fresh,
388
+ }, nowIso);
389
+ }
390
+ }
391
+ else {
392
+ vaultDeltas += 1;
393
+ }
394
+ segments += 1;
395
+ done.push(seg);
396
+ }
397
+ const next = refused === null ? page.cursor : advance(cursor, done);
398
+ writeStreamCursor(db, o.stream, next, nowIso);
399
+ return next;
400
+ });
401
+ if (refused !== null)
402
+ break;
403
+ if (page.segments.length === 0 || cursor.after >= page.head)
404
+ break;
405
+ }
406
+ if (o.pruneSeen === true)
407
+ pruneSeenTxns(db, o.stream);
408
+ const apply = applyStagedTxns(db, {
409
+ scope: o.scope,
410
+ stream: o.stream,
411
+ replica: o.replica,
412
+ now,
413
+ seal: o.seal,
414
+ ...(o.apply ?? {}),
415
+ });
416
+ return {
417
+ stream: o.stream,
418
+ refused,
419
+ refusedKind,
420
+ segments,
421
+ vaultDeltas,
422
+ staged,
423
+ redelivered,
424
+ after: cursor.after,
425
+ head,
426
+ apply,
427
+ };
428
+ }
429
+ //# sourceMappingURL=pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../../src/store/sync/pull.ts"],"names":[],"mappings":"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"}