@cleocode/core 2026.6.6 → 2026.6.7

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 (127) hide show
  1. package/dist/dispatch/contracts/output-contracts.d.ts +36 -0
  2. package/dist/dispatch/contracts/output-contracts.d.ts.map +1 -0
  3. package/dist/dispatch/contracts/output-contracts.js +38 -0
  4. package/dist/dispatch/contracts/output-contracts.js.map +1 -0
  5. package/dist/dispatch/describe-operation.d.ts +98 -0
  6. package/dist/dispatch/describe-operation.d.ts.map +1 -0
  7. package/dist/dispatch/describe-operation.js +101 -0
  8. package/dist/dispatch/describe-operation.js.map +1 -0
  9. package/dist/docs/export-document.js +910 -518
  10. package/dist/docs/export-document.js.map +3 -3
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +5 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/internal.d.ts +2 -0
  16. package/dist/internal.d.ts.map +1 -1
  17. package/dist/internal.js +6 -0
  18. package/dist/internal.js.map +1 -1
  19. package/dist/llm/index.d.ts +1 -3
  20. package/dist/llm/index.d.ts.map +1 -1
  21. package/dist/llm/index.js +1 -2
  22. package/dist/llm/index.js.map +1 -1
  23. package/dist/llm/model-metadata.d.ts +14 -0
  24. package/dist/llm/model-metadata.d.ts.map +1 -1
  25. package/dist/llm/model-metadata.js +23 -0
  26. package/dist/llm/model-metadata.js.map +1 -1
  27. package/dist/llm/model-runner.d.ts.map +1 -1
  28. package/dist/llm/model-runner.js +104 -74
  29. package/dist/llm/model-runner.js.map +1 -1
  30. package/dist/llm/plugin-facade.js +1006 -588
  31. package/dist/llm/plugin-facade.js.map +3 -3
  32. package/dist/llm/provider-registry/builtin/anthropic.d.ts.map +1 -1
  33. package/dist/llm/provider-registry/builtin/anthropic.js +4 -0
  34. package/dist/llm/provider-registry/builtin/anthropic.js.map +1 -1
  35. package/dist/llm/provider-registry/builtin/gemini.d.ts.map +1 -1
  36. package/dist/llm/provider-registry/builtin/gemini.js +4 -0
  37. package/dist/llm/provider-registry/builtin/gemini.js.map +1 -1
  38. package/dist/llm/provider-registry/builtin/ollama.d.ts.map +1 -1
  39. package/dist/llm/provider-registry/builtin/ollama.js +4 -0
  40. package/dist/llm/provider-registry/builtin/ollama.js.map +1 -1
  41. package/dist/llm/provider-registry/builtin/openai.d.ts.map +1 -1
  42. package/dist/llm/provider-registry/builtin/openai.js +6 -0
  43. package/dist/llm/provider-registry/builtin/openai.js.map +1 -1
  44. package/dist/llm/transports/index.d.ts +5 -3
  45. package/dist/llm/transports/index.d.ts.map +1 -1
  46. package/dist/llm/transports/index.js +5 -2
  47. package/dist/llm/transports/index.js.map +1 -1
  48. package/dist/reconciliation/reconciliation-engine.d.ts.map +1 -1
  49. package/dist/reconciliation/reconciliation-engine.js +3 -0
  50. package/dist/reconciliation/reconciliation-engine.js.map +1 -1
  51. package/dist/release/plan.d.ts +27 -0
  52. package/dist/release/plan.d.ts.map +1 -1
  53. package/dist/release/plan.js +36 -2
  54. package/dist/release/plan.js.map +1 -1
  55. package/dist/release/provenance-fk.d.ts +74 -0
  56. package/dist/release/provenance-fk.d.ts.map +1 -0
  57. package/dist/release/provenance-fk.js +122 -0
  58. package/dist/release/provenance-fk.js.map +1 -0
  59. package/dist/release/reconcile.d.ts +2 -53
  60. package/dist/release/reconcile.d.ts.map +1 -1
  61. package/dist/release/reconcile.js +13 -93
  62. package/dist/release/reconcile.js.map +1 -1
  63. package/dist/sticky/convert.d.ts.map +1 -1
  64. package/dist/sticky/convert.js +3 -0
  65. package/dist/sticky/convert.js.map +1 -1
  66. package/dist/store/exodus/column-transforms.d.ts +35 -8
  67. package/dist/store/exodus/column-transforms.d.ts.map +1 -1
  68. package/dist/store/exodus/column-transforms.js +47 -13
  69. package/dist/store/exodus/column-transforms.js.map +1 -1
  70. package/dist/store/exodus/count-parity.d.ts +71 -0
  71. package/dist/store/exodus/count-parity.d.ts.map +1 -0
  72. package/dist/store/exodus/count-parity.js +124 -0
  73. package/dist/store/exodus/count-parity.js.map +1 -0
  74. package/dist/store/exodus/health.d.ts +70 -0
  75. package/dist/store/exodus/health.d.ts.map +1 -0
  76. package/dist/store/exodus/health.js +130 -0
  77. package/dist/store/exodus/health.js.map +1 -0
  78. package/dist/store/exodus/index.d.ts +3 -0
  79. package/dist/store/exodus/index.d.ts.map +1 -1
  80. package/dist/store/exodus/index.js +3 -0
  81. package/dist/store/exodus/index.js.map +1 -1
  82. package/dist/store/exodus/migrate.d.ts.map +1 -1
  83. package/dist/store/exodus/migrate.js +98 -31
  84. package/dist/store/exodus/migrate.js.map +1 -1
  85. package/dist/store/exodus/plan.d.ts +48 -4
  86. package/dist/store/exodus/plan.d.ts.map +1 -1
  87. package/dist/store/exodus/plan.js +67 -9
  88. package/dist/store/exodus/plan.js.map +1 -1
  89. package/dist/store/exodus/seal.d.ts +69 -0
  90. package/dist/store/exodus/seal.d.ts.map +1 -0
  91. package/dist/store/exodus/seal.js +73 -0
  92. package/dist/store/exodus/seal.js.map +1 -0
  93. package/dist/store/exodus/types.d.ts +24 -1
  94. package/dist/store/exodus/types.d.ts.map +1 -1
  95. package/dist/store/exodus/types.js.map +1 -1
  96. package/dist/store/exodus/verify-migration.d.ts.map +1 -1
  97. package/dist/store/exodus/verify-migration.js +53 -26
  98. package/dist/store/exodus/verify-migration.js.map +1 -1
  99. package/dist/tasks/add.d.ts +13 -0
  100. package/dist/tasks/add.d.ts.map +1 -1
  101. package/dist/tasks/add.js +50 -18
  102. package/dist/tasks/add.js.map +1 -1
  103. package/dist/tasks/archive.d.ts.map +1 -1
  104. package/dist/tasks/archive.js +12 -7
  105. package/dist/tasks/archive.js.map +1 -1
  106. package/dist/tasks/child-disposition.d.ts +66 -0
  107. package/dist/tasks/child-disposition.d.ts.map +1 -0
  108. package/dist/tasks/child-disposition.js +80 -0
  109. package/dist/tasks/child-disposition.js.map +1 -0
  110. package/dist/tasks/delete-preview.js +1 -1
  111. package/dist/tasks/delete-preview.js.map +1 -1
  112. package/dist/tasks/deletion-strategy.d.ts +21 -3
  113. package/dist/tasks/deletion-strategy.d.ts.map +1 -1
  114. package/dist/tasks/deletion-strategy.js +61 -15
  115. package/dist/tasks/deletion-strategy.js.map +1 -1
  116. package/dist/tasks/engine-wrap.d.ts +8 -0
  117. package/dist/tasks/engine-wrap.d.ts.map +1 -1
  118. package/dist/tasks/engine-wrap.js +22 -9
  119. package/dist/tasks/engine-wrap.js.map +1 -1
  120. package/dist/tasks/update.d.ts.map +1 -1
  121. package/dist/tasks/update.js +12 -0
  122. package/dist/tasks/update.js.map +1 -1
  123. package/package.json +12 -12
  124. package/dist/llm/transports/openai.d.ts +0 -181
  125. package/dist/llm/transports/openai.d.ts.map +0 -1
  126. package/dist/llm/transports/openai.js +0 -645
  127. package/dist/llm/transports/openai.js.map +0 -1
@@ -210,6 +210,25 @@ export declare function buildEpochToIsoExpr(srcRef: string): string;
210
210
  * @returns Set of column names that require ISO GLOB validation.
211
211
  */
212
212
  export declare function detectIsoGlobColumns(db: DatabaseSync, tableName: string, targetSchema?: string): Set<string>;
213
+ /**
214
+ * Target-column metadata a {@link buildDigestExpr} caller passes so the digest
215
+ * can mirror migrate's NOT-NULL `COALESCE(..., type_default)` substitution
216
+ * (T11836).
217
+ *
218
+ * Keyed by column name, this carries the consolidated target's NOT-NULL flag and
219
+ * declared schema default for every column the digest visits, sourced from the
220
+ * target `PRAGMA table_info`. A column is NOT-NULL-without-default when
221
+ * `notnull === 1 && dflt_value === null` — exactly the condition under which
222
+ * migrate's `buildSelectExpr` wraps the value in `COALESCE(expr, type_default)`.
223
+ */
224
+ export interface TargetColumnInfo {
225
+ /** `PRAGMA table_info.notnull` — `1` for a NOT NULL column, `0` otherwise. */
226
+ readonly notnull: number;
227
+ /** `PRAGMA table_info.dflt_value` — the column's schema default, or `null`. */
228
+ readonly dflt_value: string | null;
229
+ /** `PRAGMA table_info.type` — raw affinity string (drives {@link typeDefaultLiteral}). */
230
+ readonly type: string;
231
+ }
213
232
  /**
214
233
  * Build the SQL expression a column's SOURCE value must pass through so it
215
234
  * matches the canonical value the migration STORES in the target — for use by
@@ -224,13 +243,19 @@ export declare function detectIsoGlobColumns(db: DatabaseSync, tableName: string
224
243
  * 3. **Enum-value normalization** ({@link enumNormExpr}).
225
244
  * 4. **Plain column reference** otherwise.
226
245
  *
227
- * Crucially it does NOT add the NOT-NULL `COALESCE(..., type_default)` wrapping
228
- * that `buildSelectExpr` uses: that wrapping only ever fires on a NULL source
229
- * value that the target stores as a type-default, which is a NULL→default value
230
- * CHANGE the digest should not paper over (a genuine NULL→'' divergence remains a
231
- * real, visible content difference, not a coercion artifact). The verifier
232
- * intentionally omits it so the digest reflects the canonical value transforms
233
- * (epoch/enum/clamp) WITHOUT masking a true NULL→default substitution.
246
+ * ## NOT-NULL default substitution mirroring (T11836)
247
+ *
248
+ * After the value transform, the result is wrapped in the SAME
249
+ * `COALESCE(expr, type_default)` substitution migrate's `buildSelectExpr` uses
250
+ * for a TARGET column that is NOT NULL without a schema default (see
251
+ * {@link maybeCoalesceNotNull}). migrate stores the type default (`''`/`0`/
252
+ * `0.0`/`x''`) for a NULL source value in such a column; without mirroring it
253
+ * here the source digest would read NULL and diverge from the stored default — a
254
+ * false `hashMatch === false` on a faithful FRESH migration (the exact T11836
255
+ * symptom). Mirroring it makes a NULL→NOT-NULL-default substitution a NON-FATAL
256
+ * diagnostic class rather than a hash failure. The target metadata is supplied
257
+ * via the `tgtColByCol` map; when it is absent (best-effort) no COALESCE is
258
+ * applied and a genuine NULL→'' divergence remains visible as before.
234
259
  *
235
260
  * The returned expression is a bare SQL value expression (no `AS "col"` alias)
236
261
  * suitable for embedding directly in a `SELECT <expr> ... ORDER BY ...` digest
@@ -241,8 +266,10 @@ export declare function detectIsoGlobColumns(db: DatabaseSync, tableName: string
241
266
  * @param col - Column name (present in BOTH source and target).
242
267
  * @param srcType - Raw `type` string from the source `PRAGMA table_info`.
243
268
  * @param isoGlobCols - Set of target columns carrying an ISO GLOB CHECK.
269
+ * @param tgtCol - Target column metadata (NOT-NULL flag + default +
270
+ * affinity) for `col`, or `undefined` when unavailable.
244
271
  * @returns A SQL value expression that maps the raw source value to the canonical
245
272
  * value the target stores.
246
273
  */
247
- export declare function buildDigestExpr(targetTableName: string, col: string, srcType: string, isoGlobCols: ReadonlySet<string>): string;
274
+ export declare function buildDigestExpr(targetTableName: string, col: string, srcType: string, isoGlobCols: ReadonlySet<string>, tgtCol?: TargetColumnInfo): string;
248
275
  //# sourceMappingURL=column-transforms.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"column-transforms.d.ts","sourceRoot":"","sources":["../../../src/store/exodus/column-transforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAO1D;AAMD;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CA0H/D,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhG;AAMD;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAc7D,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,MAAM,EACvB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAIf;AAaD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,EAAG,YAAwB,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAS1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,EACjB,YAAY,SAAS,GACpB,GAAG,CAAC,MAAM,CAAC,CAmBb;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,eAAe,CAC7B,eAAe,EAAE,MAAM,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B,MAAM,CAoBR"}
1
+ {"version":3,"file":"column-transforms.d.ts","sourceRoot":"","sources":["../../../src/store/exodus/column-transforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAO1D;AAMD;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CA0H/D,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhG;AAMD;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAc7D,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,MAAM,EACvB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAIf;AAaD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,EAAG,YAAwB,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAS1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,YAAY,EAChB,SAAS,EAAE,MAAM,EACjB,YAAY,SAAS,GACpB,GAAG,CAAC,MAAM,CAAC,CAmBb;AAqBD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,0FAA0F;IAC1F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,eAAe,CAC7B,eAAe,EAAE,MAAM,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,EAChC,MAAM,CAAC,EAAE,gBAAgB,GACxB,MAAM,CAqBR"}
@@ -388,6 +388,31 @@ function isIntegerSourceType(srcType) {
388
388
  const upper = srcType.toUpperCase();
389
389
  return upper.includes('INT') || upper === '' || upper === 'NUMERIC';
390
390
  }
391
+ /**
392
+ * Wrap a digest value expression in the SAME `COALESCE(expr, type_default)`
393
+ * substitution migrate's `buildSelectExpr` applies, when (and only when) the
394
+ * matching TARGET column is NOT NULL without a schema default (T11836).
395
+ *
396
+ * On a faithful FRESH migration a NULL source value in such a column is stored
397
+ * as the type default (`''`/`0`/`0.0`/`x''`) by migrate; digesting the source
398
+ * raw would read NULL and diverge from the stored default — a false
399
+ * `hashMatch === false` at equal row counts. Mirroring the COALESCE here makes
400
+ * the source digest reflect what migrate actually stored, so the substitution is
401
+ * a NON-FATAL diagnostic class rather than a content-corruption failure.
402
+ *
403
+ * @param expr - The value expression produced by an upstream transform branch.
404
+ * @param tgtCol - Target column metadata, or `undefined` when unavailable (no
405
+ * COALESCE applied — best-effort, biased to surfacing a real difference).
406
+ * @returns The expression, COALESCE-wrapped when the target is NOT-NULL-without-default.
407
+ */
408
+ function maybeCoalesceNotNull(expr, tgtCol) {
409
+ if (tgtCol === undefined)
410
+ return expr;
411
+ const isNotNullWithoutDefault = tgtCol.notnull === 1 && tgtCol.dflt_value === null;
412
+ if (!isNotNullWithoutDefault)
413
+ return expr;
414
+ return `COALESCE(${expr}, ${typeDefaultLiteral(tgtCol.type)})`;
415
+ }
391
416
  /**
392
417
  * Build the SQL expression a column's SOURCE value must pass through so it
393
418
  * matches the canonical value the migration STORES in the target — for use by
@@ -402,13 +427,19 @@ function isIntegerSourceType(srcType) {
402
427
  * 3. **Enum-value normalization** ({@link enumNormExpr}).
403
428
  * 4. **Plain column reference** otherwise.
404
429
  *
405
- * Crucially it does NOT add the NOT-NULL `COALESCE(..., type_default)` wrapping
406
- * that `buildSelectExpr` uses: that wrapping only ever fires on a NULL source
407
- * value that the target stores as a type-default, which is a NULL→default value
408
- * CHANGE the digest should not paper over (a genuine NULL→'' divergence remains a
409
- * real, visible content difference, not a coercion artifact). The verifier
410
- * intentionally omits it so the digest reflects the canonical value transforms
411
- * (epoch/enum/clamp) WITHOUT masking a true NULL→default substitution.
430
+ * ## NOT-NULL default substitution mirroring (T11836)
431
+ *
432
+ * After the value transform, the result is wrapped in the SAME
433
+ * `COALESCE(expr, type_default)` substitution migrate's `buildSelectExpr` uses
434
+ * for a TARGET column that is NOT NULL without a schema default (see
435
+ * {@link maybeCoalesceNotNull}). migrate stores the type default (`''`/`0`/
436
+ * `0.0`/`x''`) for a NULL source value in such a column; without mirroring it
437
+ * here the source digest would read NULL and diverge from the stored default — a
438
+ * false `hashMatch === false` on a faithful FRESH migration (the exact T11836
439
+ * symptom). Mirroring it makes a NULL→NOT-NULL-default substitution a NON-FATAL
440
+ * diagnostic class rather than a hash failure. The target metadata is supplied
441
+ * via the `tgtColByCol` map; when it is absent (best-effort) no COALESCE is
442
+ * applied and a genuine NULL→'' divergence remains visible as before.
412
443
  *
413
444
  * The returned expression is a bare SQL value expression (no `AS "col"` alias)
414
445
  * suitable for embedding directly in a `SELECT <expr> ... ORDER BY ...` digest
@@ -419,26 +450,29 @@ function isIntegerSourceType(srcType) {
419
450
  * @param col - Column name (present in BOTH source and target).
420
451
  * @param srcType - Raw `type` string from the source `PRAGMA table_info`.
421
452
  * @param isoGlobCols - Set of target columns carrying an ISO GLOB CHECK.
453
+ * @param tgtCol - Target column metadata (NOT-NULL flag + default +
454
+ * affinity) for `col`, or `undefined` when unavailable.
422
455
  * @returns A SQL value expression that maps the raw source value to the canonical
423
456
  * value the target stores.
424
457
  */
425
- export function buildDigestExpr(targetTableName, col, srcType, isoGlobCols) {
458
+ export function buildDigestExpr(targetTableName, col, srcType, isoGlobCols, tgtCol) {
426
459
  const srcRef = `"${col}"`;
427
460
  // Priority 1: Epoch→ISO coercion — applies when the target has an ISO GLOB
428
461
  // CHECK and the source column is INTEGER (epoch) typed. Mirrors migrate's
429
462
  // per-row magnitude heuristic exactly.
430
463
  if (isoGlobCols.has(col) && isIntegerSourceType(srcType)) {
431
- return buildEpochToIsoExpr(srcRef);
464
+ return maybeCoalesceNotNull(buildEpochToIsoExpr(srcRef), tgtCol);
432
465
  }
433
466
  // Priority 2: Non-finite numeric clamp (Inf/-Inf/NaN → finite in-range).
434
467
  const clampExpr = numericClampExpr(targetTableName, col, srcRef);
435
468
  if (clampExpr !== null)
436
- return clampExpr;
469
+ return maybeCoalesceNotNull(clampExpr, tgtCol);
437
470
  // Priority 3: Enum-value normalization (legacy value → canonical member).
438
471
  const normExpr = enumNormExpr(targetTableName, col, srcRef);
439
472
  if (normExpr !== null)
440
- return normExpr;
441
- // Priority 4: plain column reference (no transform migrate would have applied).
442
- return srcRef;
473
+ return maybeCoalesceNotNull(normExpr, tgtCol);
474
+ // Priority 4: plain column reference, COALESCE-wrapped when the target is
475
+ // NOT NULL without a default (mirrors migrate's T11533 substitution — T11836).
476
+ return maybeCoalesceNotNull(srcRef, tgtCol);
443
477
  }
444
478
  //# sourceMappingURL=column-transforms.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"column-transforms.js","sourceRoot":"","sources":["../../../src/store/exodus/column-transforms.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"column-transforms.js","sourceRoot":"","sources":["../../../src/store/exodus/column-transforms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Memory-safe COUNT(*)-only exodus parity — the deficit gate WITHOUT the content
3
+ * digest (T11837).
4
+ *
5
+ * `verifyMigration` is the full parity guard (row counts + content digest + FK +
6
+ * enum drift), but its content digest streams every row of every table. For the
7
+ * fleet-flow surface — `cleo exodus seal` (certify an already-migrated install)
8
+ * and `cleo doctor exodus` (health report) — we only need the DEFICIT gate that
9
+ * `isDataContinuityOk` actually enforces: per-table `target COUNT(*) >= source
10
+ * COUNT(*)`. That is a set-based query SQLite answers without materialising a
11
+ * single row, so it is safe to run against a 1.7 GB-class legacy `brain.db`
12
+ * (where the digest would be expensive). A SURPLUS (target > source — the live
13
+ * consolidated DB has moved ahead of the frozen legacy snapshot) is NOT loss and
14
+ * is tolerated, exactly as in `isDataContinuityOk`.
15
+ *
16
+ * This is intentionally a SEPARATE primitive from `verifyMigration` — sealing an
17
+ * already-migrated install must never re-run the heavy digest that this whole
18
+ * fleet-hardening epic (T11833) exists to avoid.
19
+ *
20
+ * @task T11837 (fleet-flow surface — count-only parity for seal + health)
21
+ * @epic T11833 (EP-EXODUS-FLEET-HARDENING)
22
+ * @saga T11242 (SG-DB-SUBSTRATE-V2)
23
+ */
24
+ import type { ExodusScope, LegacyDbDescriptor } from './types.js';
25
+ /** Per-table COUNT(*) comparison between a legacy source table and its target. */
26
+ export interface CountParityEntry {
27
+ /** Logical source DB name (`LegacyDbDescriptor.name`). */
28
+ readonly sourceDb: string;
29
+ /** Physical legacy source table name. */
30
+ readonly sourceTable: string;
31
+ /** Consolidated target table name. */
32
+ readonly targetTable: string;
33
+ /** Effective target scope (per-table override included — ADR-090 nexus graph). */
34
+ readonly scope: ExodusScope;
35
+ /** Source row count. */
36
+ readonly sourceCount: number;
37
+ /** Consolidated target row count (0 when the target table is absent). */
38
+ readonly targetCount: number;
39
+ /** `sourceCount - targetCount` when positive (rows MISSING in target); else 0. */
40
+ readonly deficit: number;
41
+ }
42
+ /** Result of a COUNT(*)-only parity sweep across all source tables. */
43
+ export interface CountParityResult {
44
+ /** `true` when NO data-bearing table has a deficit. */
45
+ readonly ok: boolean;
46
+ /** Every compared table (parity, surplus, and deficit). */
47
+ readonly entries: readonly CountParityEntry[];
48
+ /** The subset with a genuine deficit (`targetCount < sourceCount`). */
49
+ readonly deficits: readonly CountParityEntry[];
50
+ /** Count of tables compared. */
51
+ readonly checked: number;
52
+ /** Count of skipped tables (derived/FTS/internal or virtual that cannot be counted). */
53
+ readonly skipped: number;
54
+ }
55
+ /**
56
+ * Compute COUNT(*)-only parity for every legacy source table against the
57
+ * consolidated dual-scope target — the deficit gate, never the heavy digest.
58
+ *
59
+ * Opens all DBs read-only. A table whose consolidated counterpart is ABSENT with
60
+ * source rows is a deficit (`targetCount: 0`). Derived/FTS/internal tables that
61
+ * map to `skip`, and virtual tables that cannot be counted, are skipped.
62
+ *
63
+ * @param sources - Legacy source descriptors (from `buildExodusPlan()`).
64
+ * @param projectDbPath - Absolute path to the consolidated project `cleo.db`.
65
+ * @param globalDbPath - Absolute path to the consolidated global `cleo.db`.
66
+ * @returns A {@link CountParityResult}; `ok === false` when any table has a deficit.
67
+ *
68
+ * @task T11837
69
+ */
70
+ export declare function computeCountParity(sources: readonly LegacyDbDescriptor[], projectDbPath: string, globalDbPath: string): CountParityResult;
71
+ //# sourceMappingURL=count-parity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"count-parity.d.ts","sourceRoot":"","sources":["../../../src/store/exodus/count-parity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAIlE,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,sCAAsC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,wBAAwB;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kFAAkF;IAClF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC9C,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C,gCAAgC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAkCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS,kBAAkB,EAAE,EACtC,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,GACnB,iBAAiB,CA8DnB"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Memory-safe COUNT(*)-only exodus parity — the deficit gate WITHOUT the content
3
+ * digest (T11837).
4
+ *
5
+ * `verifyMigration` is the full parity guard (row counts + content digest + FK +
6
+ * enum drift), but its content digest streams every row of every table. For the
7
+ * fleet-flow surface — `cleo exodus seal` (certify an already-migrated install)
8
+ * and `cleo doctor exodus` (health report) — we only need the DEFICIT gate that
9
+ * `isDataContinuityOk` actually enforces: per-table `target COUNT(*) >= source
10
+ * COUNT(*)`. That is a set-based query SQLite answers without materialising a
11
+ * single row, so it is safe to run against a 1.7 GB-class legacy `brain.db`
12
+ * (where the digest would be expensive). A SURPLUS (target > source — the live
13
+ * consolidated DB has moved ahead of the frozen legacy snapshot) is NOT loss and
14
+ * is tolerated, exactly as in `isDataContinuityOk`.
15
+ *
16
+ * This is intentionally a SEPARATE primitive from `verifyMigration` — sealing an
17
+ * already-migrated install must never re-run the heavy digest that this whole
18
+ * fleet-hardening epic (T11833) exists to avoid.
19
+ *
20
+ * @task T11837 (fleet-flow surface — count-only parity for seal + health)
21
+ * @epic T11833 (EP-EXODUS-FLEET-HARDENING)
22
+ * @saga T11242 (SG-DB-SUBSTRATE-V2)
23
+ */
24
+ import { existsSync } from 'node:fs';
25
+ import { getLogger } from '../../logger.js';
26
+ import { openCleoDbSnapshot } from '../open-cleo-db.js';
27
+ import { resolveConsolidatedTableName, resolveTableTargetScope } from './table-name-map.js';
28
+ const log = getLogger('exodus-count-parity');
29
+ /** List user tables (excluding SQLite internals + Drizzle journal). */
30
+ function listTables(db) {
31
+ return db
32
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name")
33
+ .all().map((r) => r.name);
34
+ }
35
+ /** `true` if `tableName` exists in `db`. */
36
+ function tableExists(db, tableName) {
37
+ const escaped = tableName.replace(/'/g, "''");
38
+ return (db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='${escaped}'`).get() !==
39
+ undefined);
40
+ }
41
+ /** Memory-safe `COUNT(*)`. Returns `null` for a virtual/FTS table that cannot be counted. */
42
+ function rowCount(db, tableName) {
43
+ try {
44
+ const row = db.prepare(`SELECT COUNT(*) AS c FROM "${tableName}"`).get();
45
+ return Number(row?.c ?? 0);
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ }
51
+ /**
52
+ * Compute COUNT(*)-only parity for every legacy source table against the
53
+ * consolidated dual-scope target — the deficit gate, never the heavy digest.
54
+ *
55
+ * Opens all DBs read-only. A table whose consolidated counterpart is ABSENT with
56
+ * source rows is a deficit (`targetCount: 0`). Derived/FTS/internal tables that
57
+ * map to `skip`, and virtual tables that cannot be counted, are skipped.
58
+ *
59
+ * @param sources - Legacy source descriptors (from `buildExodusPlan()`).
60
+ * @param projectDbPath - Absolute path to the consolidated project `cleo.db`.
61
+ * @param globalDbPath - Absolute path to the consolidated global `cleo.db`.
62
+ * @returns A {@link CountParityResult}; `ok === false` when any table has a deficit.
63
+ *
64
+ * @task T11837
65
+ */
66
+ export function computeCountParity(sources, projectDbPath, globalDbPath) {
67
+ const entries = [];
68
+ let skipped = 0;
69
+ if (!existsSync(projectDbPath) || !existsSync(globalDbPath)) {
70
+ return { ok: false, entries: [], deficits: [], checked: 0, skipped: 0 };
71
+ }
72
+ const projectSnap = openCleoDbSnapshot(projectDbPath, { readOnly: true });
73
+ const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
74
+ try {
75
+ for (const src of sources) {
76
+ if (!existsSync(src.path))
77
+ continue;
78
+ const srcSnap = openCleoDbSnapshot(src.path, { readOnly: true });
79
+ try {
80
+ for (const legacyTable of listTables(srcSnap.db)) {
81
+ const resolution = resolveConsolidatedTableName(src.name, legacyTable);
82
+ if (resolution.kind === 'skip') {
83
+ skipped++;
84
+ continue;
85
+ }
86
+ const targetTable = resolution.targetName;
87
+ const scope = resolveTableTargetScope(src.name, legacyTable, src.targetScope);
88
+ const targetSnap = scope === 'project' ? projectSnap : globalSnap;
89
+ const sourceCount = rowCount(srcSnap.db, legacyTable);
90
+ if (sourceCount === null) {
91
+ skipped++;
92
+ continue;
93
+ }
94
+ const targetCount = tableExists(targetSnap.db, targetTable)
95
+ ? (rowCount(targetSnap.db, targetTable) ?? 0)
96
+ : 0;
97
+ const deficit = targetCount < sourceCount ? sourceCount - targetCount : 0;
98
+ entries.push({
99
+ sourceDb: src.name,
100
+ sourceTable: legacyTable,
101
+ targetTable,
102
+ scope,
103
+ sourceCount,
104
+ targetCount,
105
+ deficit,
106
+ });
107
+ }
108
+ }
109
+ finally {
110
+ srcSnap.close();
111
+ }
112
+ }
113
+ }
114
+ finally {
115
+ projectSnap.close();
116
+ globalSnap.close();
117
+ }
118
+ const deficits = entries.filter((e) => e.deficit > 0);
119
+ if (deficits.length > 0) {
120
+ log.warn({ deficitCount: deficits.length, sample: deficits.slice(0, 5) }, `exodus count-parity: ${deficits.length} table(s) have FEWER rows in the consolidated target than the legacy source`);
121
+ }
122
+ return { ok: deficits.length === 0, entries, deficits, checked: entries.length, skipped };
123
+ }
124
+ //# sourceMappingURL=count-parity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"count-parity.js","sourceRoot":"","sources":["../../../src/store/exodus/count-parity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * `cleo doctor exodus` core — read-only exodus health report (T11837).
3
+ *
4
+ * The fleet pre-check the owner flow opens with: a single, read-only snapshot of
5
+ * where each scope stands so an operator (or the rollout automation) can route
6
+ * the next step — already-sealed, migrated-but-unsealed (→ `cleo exodus seal`),
7
+ * fresh-needs-migration, or no-cleo-data — and so any LARGE legacy DB is flagged
8
+ * for individual attention before the streamed-verify build touches it.
9
+ *
10
+ * Pure assembly over existing primitives (`buildExodusPlan`, `runExodusStatus`,
11
+ * `hasExodusCompleteMarker`, `detectStrandedResidue`, {@link computeCountParity}).
12
+ * Never writes; never runs the heavy digest.
13
+ *
14
+ * @task T11837 (fleet-flow surface — exodus health-check)
15
+ * @epic T11833 (EP-EXODUS-FLEET-HARDENING)
16
+ * @saga T11242 (SG-DB-SUBSTRATE-V2)
17
+ */
18
+ import type { ExodusScope } from './types.js';
19
+ /** Per-scope migration state. */
20
+ export type ExodusScopeState = 'sealed' | 'migrated-unsealed' | 'needs-migration' | 'no-cleo-data';
21
+ /** One legacy source DB's presence + size. */
22
+ export interface ExodusSourceHealth {
23
+ readonly name: string;
24
+ readonly path: string;
25
+ readonly present: boolean;
26
+ readonly bytes: number;
27
+ /** `true` when `bytes >= LARGE_DB_BYTES` (route through streamed-verify build). */
28
+ readonly large: boolean;
29
+ }
30
+ /** Health of one scope (project | global). */
31
+ export interface ExodusScopeHealth {
32
+ readonly scope: ExodusScope;
33
+ readonly state: ExodusScopeState;
34
+ readonly consolidatedExists: boolean;
35
+ readonly markerPresent: boolean;
36
+ readonly legacySources: readonly ExodusSourceHealth[];
37
+ readonly strandedResidue: readonly string[];
38
+ }
39
+ /** Full read-only exodus health report. */
40
+ export interface ExodusHealth {
41
+ readonly project: ExodusScopeHealth;
42
+ readonly global: ExodusScopeHealth;
43
+ /** Disk pre-flight (current 3×-of-sum policy). */
44
+ readonly diskHeadroomOk: boolean;
45
+ readonly availableBytes: number;
46
+ readonly requiredBytes: number;
47
+ /** Whether `CLEO_DISABLE_EXODUS_ON_OPEN` is set (the fleet brake). */
48
+ readonly killSwitchSet: boolean;
49
+ /** COUNT(*)-only data-continuity across present sources (no digest). */
50
+ readonly dataParityOk: boolean;
51
+ readonly dataDeficits: number;
52
+ /** Legacy DBs ≥ 500 MB across both scopes (need individual attention). */
53
+ readonly largeLegacyDbs: ReadonlyArray<{
54
+ name: string;
55
+ scope: ExodusScope;
56
+ bytes: number;
57
+ }>;
58
+ /** Actionable next-step recommendations. */
59
+ readonly recommendations: readonly string[];
60
+ }
61
+ /**
62
+ * Build a read-only exodus health report for the current project + global scope.
63
+ *
64
+ * @param cwd - Working directory used to resolve the project `.cleo/` dir.
65
+ * @returns The assembled {@link ExodusHealth}.
66
+ *
67
+ * @task T11837
68
+ */
69
+ export declare function buildExodusHealth(cwd: string | undefined): ExodusHealth;
70
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../src/store/exodus/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK9C,iCAAiC;AACjC,MAAM,MAAM,gBAAgB,GACxB,QAAQ,GACR,mBAAmB,GACnB,iBAAiB,GACjB,cAAc,CAAC;AAEnB,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACtD,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5F,4CAA4C;IAC5C,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CA+GvE"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * `cleo doctor exodus` core — read-only exodus health report (T11837).
3
+ *
4
+ * The fleet pre-check the owner flow opens with: a single, read-only snapshot of
5
+ * where each scope stands so an operator (or the rollout automation) can route
6
+ * the next step — already-sealed, migrated-but-unsealed (→ `cleo exodus seal`),
7
+ * fresh-needs-migration, or no-cleo-data — and so any LARGE legacy DB is flagged
8
+ * for individual attention before the streamed-verify build touches it.
9
+ *
10
+ * Pure assembly over existing primitives (`buildExodusPlan`, `runExodusStatus`,
11
+ * `hasExodusCompleteMarker`, `detectStrandedResidue`, {@link computeCountParity}).
12
+ * Never writes; never runs the heavy digest.
13
+ *
14
+ * @task T11837 (fleet-flow surface — exodus health-check)
15
+ * @epic T11833 (EP-EXODUS-FLEET-HARDENING)
16
+ * @saga T11242 (SG-DB-SUBSTRATE-V2)
17
+ */
18
+ import { existsSync, statSync } from 'node:fs';
19
+ import { hasExodusCompleteMarker } from './archive.js';
20
+ import { computeCountParity } from './count-parity.js';
21
+ import { buildExodusPlan } from './plan.js';
22
+ /** Legacy DBs at or above this size are flagged for individual rollout attention. */
23
+ const LARGE_DB_BYTES = 500 * 1024 * 1024;
24
+ /**
25
+ * Build a read-only exodus health report for the current project + global scope.
26
+ *
27
+ * @param cwd - Working directory used to resolve the project `.cleo/` dir.
28
+ * @returns The assembled {@link ExodusHealth}.
29
+ *
30
+ * @task T11837
31
+ */
32
+ export function buildExodusHealth(cwd) {
33
+ const plan = buildExodusPlan(cwd);
34
+ const anyLegacyPresent = plan.sources.some((s) => existsSync(s.path));
35
+ // COUNT(*)-only parity (no digest). Trivially ok when no legacy sources remain.
36
+ const parity = anyLegacyPresent
37
+ ? computeCountParity(plan.sources, plan.projectDbPath, plan.globalDbPath)
38
+ : { ok: true, entries: [], deficits: [], checked: 0, skipped: 0 };
39
+ const consolidatedExistsByScope = {
40
+ project: existsSync(plan.projectDbPath),
41
+ global: existsSync(plan.globalDbPath),
42
+ };
43
+ const buildScope = (scope) => {
44
+ const sources = plan.sources
45
+ .filter((s) => s.targetScope === scope)
46
+ .map((s) => {
47
+ const present = existsSync(s.path);
48
+ let bytes = 0;
49
+ if (present) {
50
+ try {
51
+ bytes = statSync(s.path).size;
52
+ }
53
+ catch {
54
+ bytes = 0;
55
+ }
56
+ }
57
+ return { name: s.name, path: s.path, present, bytes, large: bytes >= LARGE_DB_BYTES };
58
+ });
59
+ const markerPresent = hasExodusCompleteMarker(scope, cwd);
60
+ const legacyPresent = sources.some((s) => s.present);
61
+ const consolidatedExists = consolidatedExistsByScope[scope];
62
+ const scopeEntries = parity.entries.filter((e) => e.scope === scope);
63
+ const scopeHasDeficit = scopeEntries.some((e) => e.deficit > 0);
64
+ const scopeHasData = scopeEntries.some((e) => e.targetCount > 0);
65
+ let state;
66
+ if (markerPresent) {
67
+ state = 'sealed';
68
+ }
69
+ else if (legacyPresent && consolidatedExists && scopeHasData && !scopeHasDeficit) {
70
+ state = 'migrated-unsealed';
71
+ }
72
+ else if (legacyPresent) {
73
+ state = 'needs-migration';
74
+ }
75
+ else {
76
+ state = 'no-cleo-data';
77
+ }
78
+ // Stranded residue is only meaningful once a marker exists for the scope.
79
+ const stranded = sources.filter((s) => s.present && markerPresent).map((s) => s.name);
80
+ return {
81
+ scope,
82
+ state,
83
+ consolidatedExists,
84
+ markerPresent,
85
+ legacySources: sources,
86
+ strandedResidue: stranded,
87
+ };
88
+ };
89
+ const project = buildScope('project');
90
+ const global = buildScope('global');
91
+ const largeLegacyDbs = [
92
+ ...project.legacySources
93
+ .filter((s) => s.large)
94
+ .map((s) => ({ name: s.name, scope: 'project', bytes: s.bytes })),
95
+ ...global.legacySources
96
+ .filter((s) => s.large)
97
+ .map((s) => ({ name: s.name, scope: 'global', bytes: s.bytes })),
98
+ ];
99
+ const recommendations = [];
100
+ for (const sc of [project, global]) {
101
+ if (sc.state === 'migrated-unsealed') {
102
+ recommendations.push(`${sc.scope}: data is consolidated but unsealed — run \`cleo exodus seal --scope ${sc.scope}\` to archive legacy DBs + stop on-open re-firing.`);
103
+ }
104
+ else if (sc.state === 'needs-migration') {
105
+ recommendations.push(`${sc.scope}: legacy data not yet consolidated — run \`cleo exodus migrate --scope ${sc.scope}\`.`);
106
+ }
107
+ else if (sc.strandedResidue.length > 0) {
108
+ recommendations.push(`${sc.scope}: ${sc.strandedResidue.length} stranded legacy DB(s) after a sealed cutover — run \`cleo doctor exodus-residue --fix\`.`);
109
+ }
110
+ }
111
+ if (largeLegacyDbs.length > 0) {
112
+ recommendations.push(`${largeLegacyDbs.length} large legacy DB(s) (≥500 MB) — migrate these only with the streamed-verify build (T11834) to avoid the verify OOM.`);
113
+ }
114
+ if (!parity.ok) {
115
+ recommendations.push(`${parity.deficits.length} table(s) show a row deficit in cleo.db — DO NOT seal; run \`cleo exodus migrate\` first.`);
116
+ }
117
+ return {
118
+ project,
119
+ global,
120
+ diskHeadroomOk: plan.diskPreflight,
121
+ availableBytes: plan.availableBytes,
122
+ requiredBytes: 3 * plan.totalSourceBytes,
123
+ killSwitchSet: process.env.CLEO_DISABLE_EXODUS_ON_OPEN === '1',
124
+ dataParityOk: parity.ok,
125
+ dataDeficits: parity.deficits.length,
126
+ largeLegacyDbs,
127
+ recommendations,
128
+ };
129
+ }
130
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/store/exodus/health.ts"],"names":[],"mappings":"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"}
@@ -9,8 +9,11 @@
9
9
  * @saga T11242
10
10
  */
11
11
  export { type ArchivedSourceResult, type ArchiveMigratedSourcesResult, archiveMigratedSources, archiveSourceDb, archiveStrandedResidue, detectStrandedResidue, type ExodusCompleteMarker, exodusArchiveDir, exodusMarkerPath, hasExodusCompleteMarker, type StrandedResidueEntry, writeExodusCompleteMarker, } from './archive.js';
12
+ export { type CountParityEntry, type CountParityResult, computeCountParity, } from './count-parity.js';
13
+ export { buildExodusHealth, type ExodusHealth, type ExodusScopeHealth, type ExodusScopeState, type ExodusSourceHealth, } from './health.js';
12
14
  export { clearExodusJournal, runExodusMigrate } from './migrate.js';
13
15
  export { buildExodusPlan, deriveStagingDirName, sourcesPresent } from './plan.js';
16
+ export { type SealResult, type SealScopeArg, type SealScopeOutcome, sealExodus, } from './seal.js';
14
17
  export { runExodusStatus } from './status.js';
15
18
  export { isDerivedOrInternalTable, resolveConsolidatedTableName, reverseLookup, type TableNameResolution, } from './table-name-map.js';
16
19
  export { EXODUS_TARGET_SCHEMA_VERSION, type ExodusJournal, type ExodusMigrateResult, type ExodusPlan, type ExodusScope, type ExodusStatusResult, type ExodusVerifyResult, type JournalTableEntry, type LegacyDbDescriptor, type TableCopyResult, type TableMigrationStatus, type VerifyTableResult, } from './types.js';