@cleocode/core 2026.10.10 → 2026.10.11-rc.ci.680
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/dist/build-provenance.json +2 -2
- package/dist/cloud/nexus-cloud-conflicts.d.ts +8 -3
- package/dist/cloud/nexus-cloud-conflicts.d.ts.map +1 -1
- package/dist/cloud/nexus-cloud-conflicts.js +21 -5
- package/dist/cloud/nexus-cloud-conflicts.js.map +1 -1
- package/dist/cloud/nexus-cloud-journal-activity.d.ts +15 -1
- package/dist/cloud/nexus-cloud-journal-activity.d.ts.map +1 -1
- package/dist/cloud/nexus-cloud-journal-activity.js +8 -2
- package/dist/cloud/nexus-cloud-journal-activity.js.map +1 -1
- package/dist/cloud/nexus-cloud-status.d.ts.map +1 -1
- package/dist/cloud/nexus-cloud-status.js +6 -2
- package/dist/cloud/nexus-cloud-status.js.map +1 -1
- package/dist/cloud/nexus-vault.d.ts.map +1 -1
- package/dist/cloud/nexus-vault.js +52 -8
- package/dist/cloud/nexus-vault.js.map +1 -1
- package/dist/cloud/secret-seal.d.ts +31 -0
- package/dist/cloud/secret-seal.d.ts.map +1 -1
- package/dist/cloud/secret-seal.js +82 -4
- package/dist/cloud/secret-seal.js.map +1 -1
- package/dist/internal.d.ts +2 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +1 -0
- package/dist/internal.js.map +1 -1
- package/dist/memory/decision-cross-link.d.ts +5 -2
- package/dist/memory/decision-cross-link.d.ts.map +1 -1
- package/dist/memory/decision-cross-link.js +5 -2
- package/dist/memory/decision-cross-link.js.map +1 -1
- package/dist/memory/decisions.d.ts.map +1 -1
- package/dist/memory/decisions.js +13 -5
- package/dist/memory/decisions.js.map +1 -1
- package/dist/resources/admission-ledger.d.ts +7 -0
- package/dist/resources/admission-ledger.d.ts.map +1 -1
- package/dist/resources/admission-ledger.js +53 -9
- package/dist/resources/admission-ledger.js.map +1 -1
- package/dist/store/migration-runner.d.ts +17 -0
- package/dist/store/migration-runner.d.ts.map +1 -1
- package/dist/store/migration-runner.js +53 -0
- package/dist/store/migration-runner.js.map +1 -1
- package/dist/store/migration-safety.d.ts +406 -0
- package/dist/store/migration-safety.d.ts.map +1 -0
- package/dist/store/migration-safety.js +587 -0
- package/dist/store/migration-safety.js.map +1 -0
- package/dist/store/portable-bundle.d.ts +8 -0
- package/dist/store/portable-bundle.d.ts.map +1 -1
- package/dist/store/portable-bundle.js +5 -0
- package/dist/store/portable-bundle.js.map +1 -1
- package/dist/store/sync/conflicts.d.ts +37 -0
- package/dist/store/sync/conflicts.d.ts.map +1 -1
- package/dist/store/sync/conflicts.js +88 -0
- package/dist/store/sync/conflicts.js.map +1 -1
- package/dist/store/sync/merge/engine.d.ts.map +1 -1
- package/dist/store/sync/merge/engine.js +18 -0
- package/dist/store/sync/merge/engine.js.map +1 -1
- package/dist/store/sync/merge/rules.d.ts +2 -1
- package/dist/store/sync/merge/rules.d.ts.map +1 -1
- package/dist/store/sync/merge/rules.js +9 -2
- package/dist/store/sync/merge/rules.js.map +1 -1
- package/dist/store/sync/merge/types.d.ts +7 -0
- package/dist/store/sync/merge/types.d.ts.map +1 -1
- package/dist/store/sync/reconcile-copy.d.ts +8 -0
- package/dist/store/sync/reconcile-copy.d.ts.map +1 -1
- package/dist/store/sync/reconcile-copy.js +1 -1
- package/dist/store/sync/reconcile-copy.js.map +1 -1
- package/dist/store/sync/sealer.d.ts +5 -1
- package/dist/store/sync/sealer.d.ts.map +1 -1
- package/dist/store/sync/sealer.js +35 -3
- package/dist/store/sync/sealer.js.map +1 -1
- package/dist/store/vault-manifest.d.ts +72 -0
- package/dist/store/vault-manifest.d.ts.map +1 -1
- package/dist/store/vault-manifest.js +134 -0
- package/dist/store/vault-manifest.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +7 -1
- package/dist/tasks/complete.js.map +1 -1
- package/package.json +13 -13
- package/templates/git-hooks/commit-msg +7 -2
- package/templates/git-hooks/legacy-hashes.json +3 -1
- package/templates/git-hooks/pre-push +9 -3
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The migration safety harness (T13448, saga T13339 / epic T13340).
|
|
3
|
+
*
|
|
4
|
+
* Every store move in the CleoDocs re-architecture (the T13360 migration, the
|
|
5
|
+
* T13361/T13362 legacy retirements) wraps its steps in this harness so a
|
|
6
|
+
* migration can never destroy or corrupt an existing project's store without
|
|
7
|
+
* a verified recovery path. Each registered step executes inside a fixed
|
|
8
|
+
* bracket:
|
|
9
|
+
*
|
|
10
|
+
* 1. **Pre-step backup** — a `VACUUM INTO` snapshot of the whole project
|
|
11
|
+
* store via {@link planMigrationSnapshot} + {@link writeMigrationSnapshot}
|
|
12
|
+
* (the same primitives the twin-collapse repairs use, T12535). The
|
|
13
|
+
* snapshot is registered as a `migration` system backup
|
|
14
|
+
* (`.cleo/backups/sqlite/cleo.db.<backupId>` plus its `<backupId>.meta.json`
|
|
15
|
+
* sidecar), so `cleo backup list` shows it and the per-type rotation
|
|
16
|
+
* applies. The sidecar is the step's **backup receipt**; its timestamp
|
|
17
|
+
* feeds the destructive-step guard. Runs OUTSIDE the transaction
|
|
18
|
+
* (`VACUUM INTO` requires it).
|
|
19
|
+
* 2. **`BEGIN IMMEDIATE`** (T13609) — single-writer exclusion for the whole
|
|
20
|
+
* bracket: a concurrent writer can neither interleave between the
|
|
21
|
+
* fingerprints, the run and the verify (masking or forging count/hash
|
|
22
|
+
* results) nor be silently discarded by a later restore.
|
|
23
|
+
* 3. **Run** — the step's `run(ctx)` executes inside the transaction.
|
|
24
|
+
* Table-rebuild recipes use `PRAGMA defer_foreign_keys = ON` (enforced
|
|
25
|
+
* at COMMIT), never `PRAGMA foreign_keys = OFF` (a no-op in a
|
|
26
|
+
* transaction).
|
|
27
|
+
* 4. **Verify** — machine-readable checks: per-table row counts before/after
|
|
28
|
+
* (matching, or explained by the step's declared `expectedDelta`),
|
|
29
|
+
* content-hash spot checks (an order-independent multiset hash over the
|
|
30
|
+
* table's rows, sampled to `sampleSize` rowids when the table is larger),
|
|
31
|
+
* and `PRAGMA foreign_key_check` (must return zero rows).
|
|
32
|
+
* 5. **Commit or roll back** (T13609) — only a fully verified step is
|
|
33
|
+
* COMMITted; a refused, failed or throwing step is ROLLBACKed, so a
|
|
34
|
+
* failed step is never visible in the live store. The restore path
|
|
35
|
+
* remains the backstop for a commit that is later found bad.
|
|
36
|
+
* 6. **Report** — a JSON-serializable {@link MigrationStepReport} per step
|
|
37
|
+
* (including the `transaction` outcome); a failed verification **halts**
|
|
38
|
+
* the runner and names the failed step. {@link rollbackMigrationStep}
|
|
39
|
+
* consumes exactly the report's backup receipt and before-fingerprints.
|
|
40
|
+
*
|
|
41
|
+
* **Destructive guard** — a step declared `destructive: true` refuses to run
|
|
42
|
+
* unless the harness options pass `force: true` AND the step's backup receipt
|
|
43
|
+
* is younger than the step start (which the harness itself guarantees by
|
|
44
|
+
* taking the snapshot first; a failed or skipped backup therefore refuses the
|
|
45
|
+
* step by construction).
|
|
46
|
+
*
|
|
47
|
+
* **Rollback** — {@link rollbackMigrationStep} restores the step's snapshot
|
|
48
|
+
* through {@link restoreStoreSnapshot} (the programmatic core of
|
|
49
|
+
* `cleo restore backup`, T13240: verified copy, live-writer refusal, the
|
|
50
|
+
* replaced store kept as a pinned `pre-restore-*` backup) and then re-proves
|
|
51
|
+
* the restored store against the pre-step fingerprints (counts and content
|
|
52
|
+
* hashes must match exactly).
|
|
53
|
+
*
|
|
54
|
+
* All store access here is read-only verification SQL plus the `VACUUM INTO`
|
|
55
|
+
* snapshot primitive; steps own their own writes and route them through the
|
|
56
|
+
* canonical accessors (gates 28/38).
|
|
57
|
+
*
|
|
58
|
+
* @module
|
|
59
|
+
* @task T13448
|
|
60
|
+
*/
|
|
61
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
62
|
+
/**
|
|
63
|
+
* Context handed to a migration step's `run`.
|
|
64
|
+
*
|
|
65
|
+
* The `db` handle is the caller's live native handle (opened through the
|
|
66
|
+
* store chokepoint by the caller); the harness never opens stores itself.
|
|
67
|
+
*/
|
|
68
|
+
export interface MigrationStepContext {
|
|
69
|
+
/** Live native handle on the project store the migration operates on. */
|
|
70
|
+
readonly db: DatabaseSync;
|
|
71
|
+
/** Absolute path of the project root whose store is being migrated. */
|
|
72
|
+
readonly projectRoot: string;
|
|
73
|
+
/** Absolute path of the store file behind {@link db} (the backup target). */
|
|
74
|
+
readonly dbPath: string;
|
|
75
|
+
/**
|
|
76
|
+
* Step-scoped log sink (defaults to the module logger).
|
|
77
|
+
*
|
|
78
|
+
* Transaction contract (T13609): `run` executes INSIDE the harness's
|
|
79
|
+
* `BEGIN IMMEDIATE … COMMIT` bracket. Never issue `BEGIN`/`COMMIT`/
|
|
80
|
+
* `ROLLBACK`, `VACUUM`, or checkpoint pragmas yourself — the harness owns
|
|
81
|
+
* the transaction. Table-rebuild recipes must use
|
|
82
|
+
* `PRAGMA defer_foreign_keys = ON` (enforced at COMMIT), not
|
|
83
|
+
* `PRAGMA foreign_keys = OFF` (a no-op inside a transaction). DDL is
|
|
84
|
+
* transactional: a failed verify rolls your changes back.
|
|
85
|
+
*/
|
|
86
|
+
readonly log: (message: string) => void;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Per-step verification declaration.
|
|
90
|
+
*
|
|
91
|
+
* Everything is optional: the defaults verify EVERY user table with a zero
|
|
92
|
+
* expected row-count delta, which is the strictest useful contract for a
|
|
93
|
+
* carried-table migration.
|
|
94
|
+
*/
|
|
95
|
+
export interface MigrationStepVerificationSpec {
|
|
96
|
+
/**
|
|
97
|
+
* Tables to fingerprint before/after. Defaults to every user table
|
|
98
|
+
* (`sqlite_*` internals excluded) present when the step starts. Tables the
|
|
99
|
+
* step creates are reported as `addedTables`, not verified.
|
|
100
|
+
*/
|
|
101
|
+
readonly tables?: readonly string[];
|
|
102
|
+
/**
|
|
103
|
+
* Expected row-count delta per table (`after === before + delta`). A table
|
|
104
|
+
* with a non-zero declared delta is exempt from the content-hash spot
|
|
105
|
+
* check (its sampled row set legitimately changes); declare its carried
|
|
106
|
+
* subset in `tables` + `skipHash` when a hash check is still wanted.
|
|
107
|
+
*/
|
|
108
|
+
readonly expectedDelta?: Readonly<Record<string, number>>;
|
|
109
|
+
/**
|
|
110
|
+
* Content-hash sample size: tables with more rows are spot-checked on
|
|
111
|
+
* `sampleSize` evenly-spaced rowids (sorted order) instead of a full scan.
|
|
112
|
+
* Defaults to {@link DEFAULT_VERIFICATION_SAMPLE_SIZE}.
|
|
113
|
+
*/
|
|
114
|
+
readonly sampleSize?: number;
|
|
115
|
+
/** Tables exempt from the content-hash spot check even with a zero delta. */
|
|
116
|
+
readonly skipHash?: readonly string[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A single registered migration step. `name` must be unique within a run and
|
|
120
|
+
* is what a halted runner reports.
|
|
121
|
+
*/
|
|
122
|
+
export interface MigrationStep {
|
|
123
|
+
/** Unique kebab-case step name (surfaced in reports and the backup note). */
|
|
124
|
+
readonly name: string;
|
|
125
|
+
/** Human-readable description (goes into the backup note). */
|
|
126
|
+
readonly description?: string;
|
|
127
|
+
/**
|
|
128
|
+
* Destructive steps (table drops, legacy retirement) refuse to run without
|
|
129
|
+
* `force: true` in the harness options AND a backup receipt younger than
|
|
130
|
+
* the step start.
|
|
131
|
+
*/
|
|
132
|
+
readonly destructive?: boolean;
|
|
133
|
+
/** Verification declaration; defaults verify all tables with zero delta. */
|
|
134
|
+
readonly verify?: MigrationStepVerificationSpec;
|
|
135
|
+
/** The migration body. Runs inside the backup → run → verify → report bracket. */
|
|
136
|
+
readonly run: (ctx: MigrationStepContext) => void | Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Order-independent content fingerprint of one table at one point in time.
|
|
140
|
+
*/
|
|
141
|
+
export interface TableFingerprint {
|
|
142
|
+
/** Table name. */
|
|
143
|
+
readonly table: string;
|
|
144
|
+
/** Row count at capture time. */
|
|
145
|
+
readonly count: number;
|
|
146
|
+
/**
|
|
147
|
+
* SHA-256 of the sorted multiset of per-row digests — identical for the
|
|
148
|
+
* same row contents in any physical order (so a table REBUILD that carries
|
|
149
|
+
* every row verbatim still matches).
|
|
150
|
+
*/
|
|
151
|
+
readonly hash: string;
|
|
152
|
+
/** `true` when the hash covers every row; `false` when it is a sample. */
|
|
153
|
+
readonly full: boolean;
|
|
154
|
+
/** Rowids hashed, when sampled (`full: false`); empty for full scans. */
|
|
155
|
+
readonly sampledRowids: readonly (number | string)[];
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The backup receipt a step runs under: the migration snapshot registered as
|
|
159
|
+
* a `migration` system backup, plus the sidecar timestamp the destructive
|
|
160
|
+
* guard compares against the step start.
|
|
161
|
+
*/
|
|
162
|
+
export interface StepBackupReceipt {
|
|
163
|
+
/** `<type>-YYYYMMDD-HHmmss[-n]` system-backup id (`cleo backup list`). */
|
|
164
|
+
readonly backupId: string;
|
|
165
|
+
/** Absolute path of the `VACUUM INTO` snapshot file. */
|
|
166
|
+
readonly snapshotPath: string;
|
|
167
|
+
/** ISO-8601 timestamp read back from the `<backupId>.meta.json` sidecar. */
|
|
168
|
+
readonly timestamp: string;
|
|
169
|
+
}
|
|
170
|
+
/** Per-table before/after verification result for one step. */
|
|
171
|
+
export interface TableVerification {
|
|
172
|
+
/** Table name. */
|
|
173
|
+
readonly table: string;
|
|
174
|
+
/** Pre-step fingerprint. */
|
|
175
|
+
readonly before: TableFingerprint;
|
|
176
|
+
/** Post-step fingerprint (`null` when the table was removed). */
|
|
177
|
+
readonly after: TableFingerprint | null;
|
|
178
|
+
/** The declared (or defaulted) expected row-count delta. */
|
|
179
|
+
readonly expectedDelta: number;
|
|
180
|
+
/** Whether the post count equals pre count + expected delta. */
|
|
181
|
+
readonly countOk: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Whether the content hash is unchanged. `null` when skipped (non-zero
|
|
184
|
+
* declared delta, or the table is in `skipHash`).
|
|
185
|
+
*/
|
|
186
|
+
readonly hashOk: boolean | null;
|
|
187
|
+
}
|
|
188
|
+
/** Outcome of a single step. */
|
|
189
|
+
export type MigrationStepStatus = 'completed' | 'failed' | 'refused';
|
|
190
|
+
/**
|
|
191
|
+
* Machine-readable per-step report (JSON-serializable). On a failed step this
|
|
192
|
+
* object IS the rollback input: `backup` names the snapshot and
|
|
193
|
+
* `tables[].before` the fingerprints {@link rollbackMigrationStep} re-proves.
|
|
194
|
+
*/
|
|
195
|
+
export interface MigrationStepReport {
|
|
196
|
+
/** Step name. */
|
|
197
|
+
readonly step: string;
|
|
198
|
+
/** Whether the step declared itself destructive. */
|
|
199
|
+
readonly destructive: boolean;
|
|
200
|
+
/** `completed`, `failed` (verification or run error), or `refused`. */
|
|
201
|
+
readonly status: MigrationStepStatus;
|
|
202
|
+
/** ISO-8601 step start. */
|
|
203
|
+
readonly startedAt: string;
|
|
204
|
+
/** Wall time of the whole bracket (backup + run + verify). */
|
|
205
|
+
readonly durationMs: number;
|
|
206
|
+
/** The pre-step backup receipt (`null` only when the backup itself failed). */
|
|
207
|
+
readonly backup: StepBackupReceipt | null;
|
|
208
|
+
/** Per-table before/after verification. */
|
|
209
|
+
readonly tables: readonly TableVerification[];
|
|
210
|
+
/** Tables created by the step (not covered by before/after verification). */
|
|
211
|
+
readonly addedTables: readonly string[];
|
|
212
|
+
/** Tables dropped by the step. */
|
|
213
|
+
readonly removedTables: readonly string[];
|
|
214
|
+
/** Rows returned by `PRAGMA foreign_key_check` after the step (0 = clean). */
|
|
215
|
+
readonly foreignKeyViolations: number;
|
|
216
|
+
/**
|
|
217
|
+
* Extension-backed tables excluded from verification because they could not
|
|
218
|
+
* be read on this connection (e.g. `vec0` virtual tables without the
|
|
219
|
+
* sqlite-vec extension loaded). These are content-addressed caches, never
|
|
220
|
+
* the source of truth; a step that makes one of them MISSING fails
|
|
221
|
+
* verification (its removal would otherwise be invisible), and every other
|
|
222
|
+
* read error still fails the step (fail-closed).
|
|
223
|
+
*/
|
|
224
|
+
readonly unreadableTables: readonly UnreadableTable[];
|
|
225
|
+
/**
|
|
226
|
+
* Outcome of the step's write transaction (T13609): `committed` when the
|
|
227
|
+
* step verified and its writes are live; `rolled-back` when the step was
|
|
228
|
+
* refused, failed verification, threw, or its COMMIT failed — the failed
|
|
229
|
+
* step is then NEVER visible in the live store; `none` when no transaction
|
|
230
|
+
* was opened (the pre-step backup or BEGIN itself failed).
|
|
231
|
+
*/
|
|
232
|
+
readonly transaction: 'committed' | 'rolled-back' | 'none';
|
|
233
|
+
/** Human-readable failure reasons (empty when `completed`). */
|
|
234
|
+
readonly failures: readonly string[];
|
|
235
|
+
/** Error thrown by `run` (or by the pre-step backup), when that failed. */
|
|
236
|
+
readonly runError: string | null;
|
|
237
|
+
}
|
|
238
|
+
/** A table excluded from verification because it could not be read. */
|
|
239
|
+
export interface UnreadableTable {
|
|
240
|
+
/** Table name. */
|
|
241
|
+
readonly table: string;
|
|
242
|
+
/** Why it was unreadable (e.g. `no such module: vec0`). */
|
|
243
|
+
readonly reason: string;
|
|
244
|
+
}
|
|
245
|
+
/** Overall runner outcome. */
|
|
246
|
+
export type MigrationRunStatus = 'completed' | 'halted' | 'refused';
|
|
247
|
+
/** The runner's machine-readable report. */
|
|
248
|
+
export interface MigrationRunReport {
|
|
249
|
+
/**
|
|
250
|
+
* `completed` when every step verified; `halted` when a step failed
|
|
251
|
+
* (verification, run error, or backup failure); `refused` when a
|
|
252
|
+
* destructive step was refused. Halted/refused runs name the step.
|
|
253
|
+
*/
|
|
254
|
+
readonly status: MigrationRunStatus;
|
|
255
|
+
/** Reports for every step that was attempted (including the failed one). */
|
|
256
|
+
readonly steps: readonly MigrationStepReport[];
|
|
257
|
+
/** The step that halted/refused the run (`null` when completed). */
|
|
258
|
+
readonly haltedStep: string | null;
|
|
259
|
+
/** The first failure reason (`null` when completed). */
|
|
260
|
+
readonly failure: string | null;
|
|
261
|
+
}
|
|
262
|
+
/** Options accepted by {@link runMigrationSteps}. */
|
|
263
|
+
export interface MigrationHarnessOptions {
|
|
264
|
+
/** Live native handle on the project store (caller-opened, chokepoint). */
|
|
265
|
+
readonly db: DatabaseSync;
|
|
266
|
+
/** Absolute path of the project root being migrated. */
|
|
267
|
+
readonly projectRoot: string;
|
|
268
|
+
/**
|
|
269
|
+
* Invocation directory (the worktree guard of the restore path, T12680).
|
|
270
|
+
* Pass the real cwd; tests pass the fixture root.
|
|
271
|
+
*/
|
|
272
|
+
readonly cwd: string;
|
|
273
|
+
/**
|
|
274
|
+
* Path of the store file behind `db` (locates the backup directory).
|
|
275
|
+
* Defaults to the canonical project store path for `projectRoot`.
|
|
276
|
+
*/
|
|
277
|
+
readonly dbPath?: string;
|
|
278
|
+
/**
|
|
279
|
+
* Required for destructive steps, together with a fresh backup receipt.
|
|
280
|
+
* The CLI wrapper maps `--force` here.
|
|
281
|
+
*/
|
|
282
|
+
readonly force?: boolean;
|
|
283
|
+
/** Default content-hash sample size (per-step `sampleSize` wins). */
|
|
284
|
+
readonly sampleSize?: number;
|
|
285
|
+
/** Called with each step's report as it finishes (progress + persistence). */
|
|
286
|
+
readonly onStepReport?: (report: MigrationStepReport) => void;
|
|
287
|
+
}
|
|
288
|
+
/** Default number of rows content-hash spot-checked per oversized table. */
|
|
289
|
+
export declare const DEFAULT_VERIFICATION_SAMPLE_SIZE = 200;
|
|
290
|
+
/**
|
|
291
|
+
* Capture an order-independent content fingerprint of one table.
|
|
292
|
+
*
|
|
293
|
+
* Tables with at most `sampleSize` rows (and `WITHOUT ROWID` tables, which
|
|
294
|
+
* have no rowid to sample) are hashed in full; larger rowid tables are
|
|
295
|
+
* spot-checked on `sampleSize` evenly-spaced rowids. Reads only.
|
|
296
|
+
*
|
|
297
|
+
* @param db - Live native handle.
|
|
298
|
+
* @param table - Table name.
|
|
299
|
+
* @param sampleSize - Full-scan cutoff / sample size (default 200).
|
|
300
|
+
* @returns The fingerprint.
|
|
301
|
+
* @task T13448
|
|
302
|
+
*/
|
|
303
|
+
export declare function fingerprintTable(db: DatabaseSync, table: string, sampleSize?: number): TableFingerprint;
|
|
304
|
+
/**
|
|
305
|
+
* Run `PRAGMA foreign_key_check` and return the violation count. Zero is the
|
|
306
|
+
* only passing value; the pragma reports independently of the
|
|
307
|
+
* `foreign_keys` switch, so a migration that toggles FK enforcement mid-step
|
|
308
|
+
* is still checked. Read-only.
|
|
309
|
+
*
|
|
310
|
+
* @param db - Live native handle.
|
|
311
|
+
* @returns Number of FK violations.
|
|
312
|
+
* @task T13448
|
|
313
|
+
*/
|
|
314
|
+
export declare function countForeignKeyViolations(db: DatabaseSync): number;
|
|
315
|
+
/**
|
|
316
|
+
* Run migration steps inside the backup → BEGIN IMMEDIATE → migrate → verify
|
|
317
|
+
* → COMMIT/ROLLBACK → report bracket (T13448, T13609). Each step's writes are
|
|
318
|
+
* atomic and write-exclusive: a refused, failed or throwing step is rolled
|
|
319
|
+
* back and never becomes visible in the live store, and no concurrent writer
|
|
320
|
+
* can interleave between the before-fingerprints, the run and the verify.
|
|
321
|
+
* Never throws for verification failures, refusals, or step errors: those are
|
|
322
|
+
* reported and halt the run (AC1, AC4). Throws only for invalid invocation
|
|
323
|
+
* (no steps).
|
|
324
|
+
*
|
|
325
|
+
* @param steps - The registered steps, in execution order.
|
|
326
|
+
* @param opts - The store handle, project, force flag and hooks.
|
|
327
|
+
* @returns The machine-readable run report. On `halted`/`refused`, the last
|
|
328
|
+
* step report carries the backup receipt and before-fingerprints needed by
|
|
329
|
+
* {@link rollbackMigrationStep} (the backstop for a commit later found bad).
|
|
330
|
+
* @task T13448
|
|
331
|
+
* @task T13609 — transactional bracket; failed steps are never visible
|
|
332
|
+
*/
|
|
333
|
+
export declare function runMigrationSteps(steps: readonly MigrationStep[], opts: MigrationHarnessOptions): Promise<MigrationRunReport>;
|
|
334
|
+
/** Parameters of {@link rollbackMigrationStep}. */
|
|
335
|
+
export interface MigrationRollbackParams {
|
|
336
|
+
/** Absolute path of the project root whose store is restored. */
|
|
337
|
+
readonly projectRoot: string;
|
|
338
|
+
/** Invocation directory (worktree guard; tests pass the fixture root). */
|
|
339
|
+
readonly cwd: string;
|
|
340
|
+
/** The halted/failed step's name (echoed into the report). */
|
|
341
|
+
readonly step: string;
|
|
342
|
+
/** The step's backup receipt (`stepReport.backup`). */
|
|
343
|
+
readonly backup: StepBackupReceipt;
|
|
344
|
+
/** The step's pre-step fingerprints (`stepReport.tables.map(t => t.before)`). */
|
|
345
|
+
readonly before: readonly TableFingerprint[];
|
|
346
|
+
/** From a git worktree: allow overwriting the owning project's live store. */
|
|
347
|
+
readonly confirmOwnerStore?: boolean;
|
|
348
|
+
/** Sample size used for re-fingerprinting (must match the run's). */
|
|
349
|
+
readonly sampleSize?: number;
|
|
350
|
+
}
|
|
351
|
+
/** Per-table rollback verification result. */
|
|
352
|
+
export interface RollbackTableResult {
|
|
353
|
+
/** Table name. */
|
|
354
|
+
readonly table: string;
|
|
355
|
+
/** The pre-step fingerprint the restore must reproduce. */
|
|
356
|
+
readonly expected: TableFingerprint;
|
|
357
|
+
/** The fingerprint of the restored store (`null` when unreadable/skipped). */
|
|
358
|
+
readonly actual: TableFingerprint | null;
|
|
359
|
+
/** Whether the restored row count matches the pre-step count. */
|
|
360
|
+
readonly countOk: boolean;
|
|
361
|
+
/** Whether the restored content hash matches the pre-step hash. */
|
|
362
|
+
readonly hashOk: boolean;
|
|
363
|
+
/**
|
|
364
|
+
* `null` when the table was re-verified; otherwise the reason it was
|
|
365
|
+
* skipped (extension-backed table unreadable on the verifying connection,
|
|
366
|
+
* e.g. `no such module: vec0`). Skipped tables cannot fail the rollback.
|
|
367
|
+
*/
|
|
368
|
+
readonly skipped: string | null;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Rollback report: what was restored and whether the restored store provably
|
|
372
|
+
* matches the pre-step snapshot (counts and content hashes).
|
|
373
|
+
*/
|
|
374
|
+
export interface MigrationRollbackReport {
|
|
375
|
+
/** The step that was rolled back. */
|
|
376
|
+
readonly step: string;
|
|
377
|
+
/** Whether {@link restoreStoreSnapshot} placed the snapshot. */
|
|
378
|
+
readonly restored: boolean;
|
|
379
|
+
/** `true` when restored AND every table re-matches its pre-step fingerprint. */
|
|
380
|
+
readonly verified: boolean;
|
|
381
|
+
/** The `cleo restore backup --id …` undo of THIS restore (T13240), when kept. */
|
|
382
|
+
readonly undo: string | null;
|
|
383
|
+
/** The pinned `pre-restore-*` backup id of the replaced (migrated) store. */
|
|
384
|
+
readonly keptBackupId: string | null;
|
|
385
|
+
/** Per-table verification against the pre-step fingerprints. */
|
|
386
|
+
readonly tables: readonly RollbackTableResult[];
|
|
387
|
+
/** Human-readable failures (empty when `verified`). */
|
|
388
|
+
readonly failures: readonly string[];
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Roll back one migration step: restore its pre-step snapshot through the
|
|
392
|
+
* programmatic core of `cleo restore backup` ({@link restoreStoreSnapshot} —
|
|
393
|
+
* verified copy, quiescence/live-writer refusal, the replaced store kept as
|
|
394
|
+
* a pinned `pre-restore-*` backup), then re-prove the restored store against
|
|
395
|
+
* the step's pre-step fingerprints. This is the tested rollback path of AC3.
|
|
396
|
+
*
|
|
397
|
+
* Note: the restore closes every in-process handle on the store (T13240
|
|
398
|
+
* quiescence) — discard any native handle captured before calling this and
|
|
399
|
+
* re-open through the chokepoint afterwards.
|
|
400
|
+
*
|
|
401
|
+
* @param params - The step, its backup receipt and its before-fingerprints.
|
|
402
|
+
* @returns The rollback report; `verified` is the assertion surface.
|
|
403
|
+
* @task T13448
|
|
404
|
+
*/
|
|
405
|
+
export declare function rollbackMigrationStep(params: MigrationRollbackParams): Promise<MigrationRollbackReport>;
|
|
406
|
+
//# sourceMappingURL=migration-safety.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-safety.d.ts","sourceRoot":"","sources":["../../src/store/migration-safety.ts"],"names":[],"mappings":"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"}
|