@cleocode/core 2026.6.4 → 2026.6.6

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 (59) hide show
  1. package/dist/docs/export-document.js +189 -137
  2. package/dist/docs/export-document.js.map +2 -2
  3. package/dist/llm/api-mode.d.ts +64 -0
  4. package/dist/llm/api-mode.d.ts.map +1 -0
  5. package/dist/llm/api-mode.js +72 -0
  6. package/dist/llm/api-mode.js.map +1 -0
  7. package/dist/llm/api.d.ts.map +1 -1
  8. package/dist/llm/api.js +6 -37
  9. package/dist/llm/api.js.map +1 -1
  10. package/dist/llm/auxiliary-fallback.d.ts.map +1 -1
  11. package/dist/llm/auxiliary-fallback.js +24 -38
  12. package/dist/llm/auxiliary-fallback.js.map +1 -1
  13. package/dist/llm/model-runner.d.ts +127 -0
  14. package/dist/llm/model-runner.d.ts.map +1 -0
  15. package/dist/llm/model-runner.js +282 -0
  16. package/dist/llm/model-runner.js.map +1 -0
  17. package/dist/llm/plugin-facade.js +29391 -1473
  18. package/dist/llm/plugin-facade.js.map +3 -3
  19. package/dist/llm/role-executor.d.ts +6 -5
  20. package/dist/llm/role-executor.d.ts.map +1 -1
  21. package/dist/llm/role-executor.js +40 -86
  22. package/dist/llm/role-executor.js.map +1 -1
  23. package/dist/llm/role-resolver.d.ts +28 -1
  24. package/dist/llm/role-resolver.d.ts.map +1 -1
  25. package/dist/llm/role-resolver.js +10 -0
  26. package/dist/llm/role-resolver.js.map +1 -1
  27. package/dist/llm/session-factory.d.ts +4 -6
  28. package/dist/llm/session-factory.d.ts.map +1 -1
  29. package/dist/llm/session-factory.js +6 -72
  30. package/dist/llm/session-factory.js.map +1 -1
  31. package/dist/llm/system-resolver.d.ts.map +1 -1
  32. package/dist/llm/system-resolver.js +6 -0
  33. package/dist/llm/system-resolver.js.map +1 -1
  34. package/dist/llm/tool-loop.d.ts.map +1 -1
  35. package/dist/llm/tool-loop.js +9 -32
  36. package/dist/llm/tool-loop.js.map +1 -1
  37. package/dist/memory/dialectic-evaluator.d.ts +13 -6
  38. package/dist/memory/dialectic-evaluator.d.ts.map +1 -1
  39. package/dist/memory/dialectic-evaluator.js +18 -7
  40. package/dist/memory/dialectic-evaluator.js.map +1 -1
  41. package/dist/memory/llm-backend-resolver.d.ts +23 -3
  42. package/dist/memory/llm-backend-resolver.d.ts.map +1 -1
  43. package/dist/memory/llm-backend-resolver.js +135 -0
  44. package/dist/memory/llm-backend-resolver.js.map +1 -1
  45. package/dist/release/reconcile.d.ts +61 -0
  46. package/dist/release/reconcile.d.ts.map +1 -1
  47. package/dist/release/reconcile.js +187 -2
  48. package/dist/release/reconcile.js.map +1 -1
  49. package/dist/store/exodus/column-transforms.d.ts +248 -0
  50. package/dist/store/exodus/column-transforms.d.ts.map +1 -0
  51. package/dist/store/exodus/column-transforms.js +444 -0
  52. package/dist/store/exodus/column-transforms.js.map +1 -0
  53. package/dist/store/exodus/migrate.d.ts.map +1 -1
  54. package/dist/store/exodus/migrate.js +5 -267
  55. package/dist/store/exodus/migrate.js.map +1 -1
  56. package/dist/store/exodus/verify-migration.d.ts.map +1 -1
  57. package/dist/store/exodus/verify-migration.js +61 -3
  58. package/dist/store/exodus/verify-migration.js.map +1 -1
  59. package/package.json +12 -12
@@ -31695,6 +31695,162 @@ var init_open_cleo_db = __esm({
31695
31695
  }
31696
31696
  });
31697
31697
 
31698
+ // packages/core/src/store/exodus/column-transforms.ts
31699
+ function typeDefaultLiteral(colType) {
31700
+ const upper = colType.toUpperCase();
31701
+ if (upper.includes("INT")) return "0";
31702
+ if (upper.includes("REAL") || upper.includes("FLOAT") || upper.includes("DOUBLE")) return "0.0";
31703
+ if (upper.includes("BLOB")) return "x''";
31704
+ return "''";
31705
+ }
31706
+ function enumNormExpr(targetTableName, col, srcRef) {
31707
+ const key = `${targetTableName}.${col}`;
31708
+ const fn = ENUM_NORMALIZATIONS.get(key);
31709
+ return fn ? fn(srcRef) : null;
31710
+ }
31711
+ function numericClampExpr(targetTableName, col, srcRef) {
31712
+ const key = `${targetTableName}.${col}`;
31713
+ const fn = NUMERIC_CLAMPS.get(key);
31714
+ return fn ? fn(srcRef) : null;
31715
+ }
31716
+ function buildEpochToIsoExpr(srcRef) {
31717
+ return `CASE WHEN ${srcRef} IS NULL THEN NULL WHEN ${srcRef} < ${EPOCH_SECONDS_THRESHOLD} THEN strftime('%Y-%m-%dT%H:%M:%fZ', ${srcRef}, 'unixepoch') ELSE strftime('%Y-%m-%dT%H:%M:%fZ', ${srcRef}/1000.0, 'unixepoch') END`;
31718
+ }
31719
+ function detectIsoGlobColumns(db, tableName, targetSchema = "main") {
31720
+ const escapedTable = tableName.replace(/'/g, "''");
31721
+ const row = db.prepare(
31722
+ `SELECT sql FROM "${targetSchema}".sqlite_master WHERE type='table' AND name='${escapedTable}'`
31723
+ ).get();
31724
+ if (!row?.sql) return /* @__PURE__ */ new Set();
31725
+ const isoColumns = /* @__PURE__ */ new Set();
31726
+ ISO_CHECK_REGEX.lastIndex = 0;
31727
+ for (const match of row.sql.matchAll(ISO_CHECK_REGEX)) {
31728
+ isoColumns.add(match[1]);
31729
+ }
31730
+ return isoColumns;
31731
+ }
31732
+ function isIntegerSourceType(srcType) {
31733
+ const upper = srcType.toUpperCase();
31734
+ return upper.includes("INT") || upper === "" || upper === "NUMERIC";
31735
+ }
31736
+ function buildDigestExpr(targetTableName, col, srcType, isoGlobCols) {
31737
+ const srcRef = `"${col}"`;
31738
+ if (isoGlobCols.has(col) && isIntegerSourceType(srcType)) {
31739
+ return buildEpochToIsoExpr(srcRef);
31740
+ }
31741
+ const clampExpr = numericClampExpr(targetTableName, col, srcRef);
31742
+ if (clampExpr !== null) return clampExpr;
31743
+ const normExpr = enumNormExpr(targetTableName, col, srcRef);
31744
+ if (normExpr !== null) return normExpr;
31745
+ return srcRef;
31746
+ }
31747
+ var ENUM_NORMALIZATIONS, NUMERIC_CLAMPS, ISO_CHECK_REGEX, EPOCH_SECONDS_THRESHOLD;
31748
+ var init_column_transforms = __esm({
31749
+ "packages/core/src/store/exodus/column-transforms.ts"() {
31750
+ "use strict";
31751
+ ENUM_NORMALIZATIONS = /* @__PURE__ */ new Map([
31752
+ // --- task_commits.link_source -------------------------------------------
31753
+ // 'commit-message' → 'commit-subject' (pre-T9506 legacy value)
31754
+ [
31755
+ "tasks_task_commits.link_source",
31756
+ (src) => `CASE ${src} WHEN 'commit-message' THEN 'commit-subject' ELSE ${src} END`
31757
+ ],
31758
+ // --- architecture_decisions.status (case + date-suffix normalization) ----
31759
+ // 'Accepted', 'ACCEPTED', 'approved', 'Accepted (2026-04-18)', … → 'accepted'
31760
+ // 'Proposed', 'PROPOSED' → 'proposed'
31761
+ // 'Superseded', 'SUPERSEDED' → 'superseded'
31762
+ [
31763
+ "tasks_architecture_decisions.status",
31764
+ (src) => `CASE WHEN lower(${src}) = 'accepted' OR lower(${src}) LIKE 'accepted %' OR lower(${src}) = 'approved' THEN 'accepted' WHEN lower(${src}) = 'proposed' THEN 'proposed' WHEN lower(${src}) = 'superseded' THEN 'superseded' WHEN lower(${src}) = 'deprecated' THEN 'deprecated' ELSE ${src} END`
31765
+ ],
31766
+ // --- brain_* enum normalizations REMOVED (T11647) -----------------------
31767
+ // The brain memory family now lands in the consolidated cleo.db in its LEGACY
31768
+ // RUNTIME shape — INTEGER epoch timestamps and, critically, NO SQL CHECK
31769
+ // constraints (the `text({ enum })` unions are enforced only at the
31770
+ // application layer, exactly as the runtime `drizzle-brain` tables are). With
31771
+ // no brain CHECK constraint to satisfy, exodus MUST copy every brain enum
31772
+ // value VERBATIM — coercing them (e.g. source_type 'observer-compressed'/
31773
+ // 'sleep-consolidation' → 'agent', type 'observation'/'proposal'/'pattern' →
31774
+ // nearest) would now be unnecessary data CORRUPTION, not a constraint fix.
31775
+ // The previous brain entries (brain_observations.{source_type,type},
31776
+ // brain_decisions.{confirmation_state,decision_category,confidence,outcome,
31777
+ // decided_by}) are therefore deleted. The non-brain entries below still apply
31778
+ // because those consolidated tables retain their CHECK constraints.
31779
+ // --- tasks_token_usage.transport (T11548 → REMOVED T11649) ---------------
31780
+ // NO normalization. 'mcp' is a first-class transport origin (MCP-gateway
31781
+ // requests) and is preserved verbatim. The consolidated CHECK enum was WIDENED
31782
+ // to include 'mcp' (canonical TOKEN_USAGE_TRANSPORTS SSoT + forward migration
31783
+ // 20260602000002_t11649-token-usage-transport-mcp), so the value lands without
31784
+ // coercion. The earlier 'mcp' → 'agent' mapping was a silent semantic alteration
31785
+ // of ~194 rows (count-preserving, NOT integrity-preserving) — see T11649.
31786
+ // (brain_decisions.{decision_category,confidence} normalizations removed —
31787
+ // T11647: brain target = runtime shape with no CHECK; copy values verbatim.)
31788
+ // --- tasks_commits.conventional_type (T11548 + T11578) -------------------
31789
+ // The consolidated CHECK enum is feat/fix/chore/docs/refactor/test/build/ci/
31790
+ // perf/revert/breaking. Real git history carries non-conventional subjects:
31791
+ // - 'style' → 'chore' (pre-T11548 mapping; no 'style' in enum).
31792
+ // - 'merge'/'release' → 'chore' (T11578): merge + release commits are
31793
+ // maintenance-class; the precise semantic is preserved by the dedicated
31794
+ // `is_merge_commit` / `is_release_commit` boolean columns, so collapsing
31795
+ // `conventional_type` to the maintenance catch-all 'chore' is lossless at
31796
+ // the row grain. Without this the 'merge'/'release' rows violate the CHECK,
31797
+ // `INSERT OR IGNORE` drops the WHOLE commits table, and the exodus-on-open
31798
+ // data-continuity gate aborts the cutover (T11578 CI regression).
31799
+ // - any OTHER out-of-enum value → 'chore' (defensive: future non-conventional
31800
+ // subjects must never re-break the zero-deficit gate; the boolean flags and
31801
+ // raw subject text remain the precise provenance).
31802
+ [
31803
+ "tasks_commits.conventional_type",
31804
+ (src) => `CASE WHEN ${src} IS NULL THEN NULL WHEN ${src} IN ('feat', 'fix', 'chore', 'docs', 'refactor', 'test', 'build', 'ci', 'perf', 'revert', 'breaking') THEN ${src} ELSE 'chore' END`
31805
+ ],
31806
+ // --- tasks_task_relations.relation_type (T11548) -------------------------
31807
+ // 'grouped-by' → 'groups' (enum: related/blocks/duplicates/absorbs/fixes/extends/
31808
+ // supersedes/groups). 4 rows.
31809
+ [
31810
+ "tasks_task_relations.relation_type",
31811
+ (src) => `CASE ${src} WHEN 'grouped-by' THEN 'groups' ELSE ${src} END`
31812
+ ],
31813
+ // --- tasks_lifecycle_stages.stage_name (T11548) --------------------------
31814
+ // Legacy camelCase / past-tense values → canonical snake_case stage names.
31815
+ // 'implemented' → 'implementation', 'qaPassed' → 'validation',
31816
+ // 'testsPassed' → 'testing'. 3 rows.
31817
+ [
31818
+ "tasks_lifecycle_stages.stage_name",
31819
+ (src) => `CASE ${src} WHEN 'implemented' THEN 'implementation' WHEN 'qaPassed' THEN 'validation' WHEN 'testsPassed' THEN 'testing' ELSE ${src} END`
31820
+ ],
31821
+ // --- tasks_architecture_decisions.gate_status (T11548) ------------------
31822
+ // 'passed (T5313 consensus)' → 'passed', 'approved' → 'passed'
31823
+ // (enum: pending/passed/failed/waived). 2 rows.
31824
+ [
31825
+ "tasks_architecture_decisions.gate_status",
31826
+ (src) => `CASE WHEN ${src} LIKE 'passed%' THEN 'passed' WHEN ${src} = 'approved' THEN 'passed' ELSE ${src} END`
31827
+ ],
31828
+ // --- tasks_evidence_ac_bindings.binding_type (T11548) -------------------
31829
+ // Values with a 'validator:...' prefix → 'direct'
31830
+ // (enum: direct/satisfies/coverage). 3 rows.
31831
+ // Strip the namespace prefix introduced before the enum was tightened.
31832
+ [
31833
+ "tasks_evidence_ac_bindings.binding_type",
31834
+ (src) => `CASE WHEN ${src} LIKE 'validator:%' THEN 'direct' ELSE ${src} END`
31835
+ ]
31836
+ // (brain_decisions.{outcome,decided_by} normalizations removed — T11647:
31837
+ // brain target = runtime shape with no CHECK; legacy values like 'accepted',
31838
+ // 'rejected', 'prime' now survive VERBATIM instead of being coerced.)
31839
+ ]);
31840
+ NUMERIC_CLAMPS = /* @__PURE__ */ new Map([
31841
+ // --- brain_weight_history.delta_weight (T11782) -------------------------
31842
+ // +Inf → 1.0 (max canonical reinforcement), -Inf → -1.0 (max canonical
31843
+ // depression), NaN → 0.0 (no-op delta). Finite values pass through.
31844
+ [
31845
+ "brain_weight_history.delta_weight",
31846
+ (src) => `CASE WHEN ${src} = 9e999 THEN 1.0 WHEN ${src} = -9e999 THEN -1.0 WHEN ${src} != ${src} THEN 0.0 ELSE ${src} END`
31847
+ ]
31848
+ ]);
31849
+ ISO_CHECK_REGEX = /CHECK\s*\(\s*"([^"]+)"\s+IS\s+NULL\s+OR\s+"[^"]+"\s+GLOB\s+'\[0-9/gi;
31850
+ EPOCH_SECONDS_THRESHOLD = 1e11;
31851
+ }
31852
+ });
31853
+
31698
31854
  // packages/core/src/store/exodus/table-name-map.ts
31699
31855
  function resolveTableTargetScope(sourceName, legacyTable, sourceScope) {
31700
31856
  if (inferSourceKind(sourceName) === "nexus" && NEXUS_GRAPH_PROJECT_TABLES.has(legacyTable)) {
@@ -32120,23 +32276,6 @@ function makeAttachAlias(name2, index2) {
32120
32276
  const safe = name2.replace(/[^a-z0-9]/gi, "_").replace(/_+/g, "_").slice(0, 20);
32121
32277
  return `_src_${safe}_${index2}`;
32122
32278
  }
32123
- function typeDefaultLiteral(colType) {
32124
- const upper = colType.toUpperCase();
32125
- if (upper.includes("INT")) return "0";
32126
- if (upper.includes("REAL") || upper.includes("FLOAT") || upper.includes("DOUBLE")) return "0.0";
32127
- if (upper.includes("BLOB")) return "x''";
32128
- return "''";
32129
- }
32130
- function enumNormExpr(targetTableName, col, srcRef) {
32131
- const key = `${targetTableName}.${col}`;
32132
- const fn = ENUM_NORMALIZATIONS.get(key);
32133
- return fn ? fn(srcRef) : null;
32134
- }
32135
- function numericClampExpr(targetTableName, col, srcRef) {
32136
- const key = `${targetTableName}.${col}`;
32137
- const fn = NUMERIC_CLAMPS.get(key);
32138
- return fn ? fn(srcRef) : null;
32139
- }
32140
32279
  function epochUnitForSource(sourceName) {
32141
32280
  const key = sourceName.toLowerCase();
32142
32281
  for (const [pattern, unit] of SOURCE_EPOCH_UNITS) {
@@ -32144,22 +32283,6 @@ function epochUnitForSource(sourceName) {
32144
32283
  }
32145
32284
  return "seconds";
32146
32285
  }
32147
- function buildEpochToIsoExpr(srcRef) {
32148
- return `CASE WHEN ${srcRef} IS NULL THEN NULL WHEN ${srcRef} < ${EPOCH_SECONDS_THRESHOLD} THEN strftime('%Y-%m-%dT%H:%M:%fZ', ${srcRef}, 'unixepoch') ELSE strftime('%Y-%m-%dT%H:%M:%fZ', ${srcRef}/1000.0, 'unixepoch') END`;
32149
- }
32150
- function detectIsoGlobColumns(db, tableName, targetSchema = "main") {
32151
- const escapedTable = tableName.replace(/'/g, "''");
32152
- const row = db.prepare(
32153
- `SELECT sql FROM "${targetSchema}".sqlite_master WHERE type='table' AND name='${escapedTable}'`
32154
- ).get();
32155
- if (!row?.sql) return /* @__PURE__ */ new Set();
32156
- const isoColumns = /* @__PURE__ */ new Set();
32157
- ISO_CHECK_REGEX.lastIndex = 0;
32158
- for (const match of row.sql.matchAll(ISO_CHECK_REGEX)) {
32159
- isoColumns.add(match[1]);
32160
- }
32161
- return isoColumns;
32162
- }
32163
32286
  function buildSelectExpr(attachAlias, legacyTable, targetTableName, col, srcType, tgtInfo, isoGlobCols) {
32164
32287
  const srcRef = `"${attachAlias}"."${legacyTable}"."${col}"`;
32165
32288
  const srcUpper = srcType.toUpperCase();
@@ -32618,7 +32741,7 @@ async function migrateScope(scope, sources, targetNativeDb, journal, stagingDir,
32618
32741
  }
32619
32742
  }
32620
32743
  }
32621
- var log2, LOCK_SENTINEL_SUFFIX, JOURNAL_FILENAME, ENUM_NORMALIZATIONS, NUMERIC_CLAMPS, ISO_CHECK_REGEX, SOURCE_EPOCH_UNITS, EPOCH_SECONDS_THRESHOLD;
32744
+ var log2, LOCK_SENTINEL_SUFFIX, JOURNAL_FILENAME, SOURCE_EPOCH_UNITS;
32622
32745
  var init_migrate = __esm({
32623
32746
  "packages/core/src/store/exodus/migrate.ts"() {
32624
32747
  "use strict";
@@ -32626,110 +32749,12 @@ var init_migrate = __esm({
32626
32749
  init_ensure_config();
32627
32750
  init_dual_scope_db();
32628
32751
  init_open_cleo_db();
32752
+ init_column_transforms();
32629
32753
  init_table_name_map();
32630
32754
  init_types();
32631
32755
  log2 = getLogger("exodus-migrate");
32632
32756
  LOCK_SENTINEL_SUFFIX = ".exodus-lock";
32633
32757
  JOURNAL_FILENAME = "exodus-journal.json";
32634
- ENUM_NORMALIZATIONS = /* @__PURE__ */ new Map([
32635
- // --- task_commits.link_source -------------------------------------------
32636
- // 'commit-message' → 'commit-subject' (pre-T9506 legacy value)
32637
- [
32638
- "tasks_task_commits.link_source",
32639
- (src) => `CASE ${src} WHEN 'commit-message' THEN 'commit-subject' ELSE ${src} END`
32640
- ],
32641
- // --- architecture_decisions.status (case + date-suffix normalization) ----
32642
- // 'Accepted', 'ACCEPTED', 'approved', 'Accepted (2026-04-18)', … → 'accepted'
32643
- // 'Proposed', 'PROPOSED' → 'proposed'
32644
- // 'Superseded', 'SUPERSEDED' → 'superseded'
32645
- [
32646
- "tasks_architecture_decisions.status",
32647
- (src) => `CASE WHEN lower(${src}) = 'accepted' OR lower(${src}) LIKE 'accepted %' OR lower(${src}) = 'approved' THEN 'accepted' WHEN lower(${src}) = 'proposed' THEN 'proposed' WHEN lower(${src}) = 'superseded' THEN 'superseded' WHEN lower(${src}) = 'deprecated' THEN 'deprecated' ELSE ${src} END`
32648
- ],
32649
- // --- brain_* enum normalizations REMOVED (T11647) -----------------------
32650
- // The brain memory family now lands in the consolidated cleo.db in its LEGACY
32651
- // RUNTIME shape — INTEGER epoch timestamps and, critically, NO SQL CHECK
32652
- // constraints (the `text({ enum })` unions are enforced only at the
32653
- // application layer, exactly as the runtime `drizzle-brain` tables are). With
32654
- // no brain CHECK constraint to satisfy, exodus MUST copy every brain enum
32655
- // value VERBATIM — coercing them (e.g. source_type 'observer-compressed'/
32656
- // 'sleep-consolidation' → 'agent', type 'observation'/'proposal'/'pattern' →
32657
- // nearest) would now be unnecessary data CORRUPTION, not a constraint fix.
32658
- // The previous brain entries (brain_observations.{source_type,type},
32659
- // brain_decisions.{confirmation_state,decision_category,confidence,outcome,
32660
- // decided_by}) are therefore deleted. The non-brain entries below still apply
32661
- // because those consolidated tables retain their CHECK constraints.
32662
- // --- tasks_token_usage.transport (T11548 → REMOVED T11649) ---------------
32663
- // NO normalization. 'mcp' is a first-class transport origin (MCP-gateway
32664
- // requests) and is preserved verbatim. The consolidated CHECK enum was WIDENED
32665
- // to include 'mcp' (canonical TOKEN_USAGE_TRANSPORTS SSoT + forward migration
32666
- // 20260602000002_t11649-token-usage-transport-mcp), so the value lands without
32667
- // coercion. The earlier 'mcp' → 'agent' mapping was a silent semantic alteration
32668
- // of ~194 rows (count-preserving, NOT integrity-preserving) — see T11649.
32669
- // (brain_decisions.{decision_category,confidence} normalizations removed —
32670
- // T11647: brain target = runtime shape with no CHECK; copy values verbatim.)
32671
- // --- tasks_commits.conventional_type (T11548 + T11578) -------------------
32672
- // The consolidated CHECK enum is feat/fix/chore/docs/refactor/test/build/ci/
32673
- // perf/revert/breaking. Real git history carries non-conventional subjects:
32674
- // - 'style' → 'chore' (pre-T11548 mapping; no 'style' in enum).
32675
- // - 'merge'/'release' → 'chore' (T11578): merge + release commits are
32676
- // maintenance-class; the precise semantic is preserved by the dedicated
32677
- // `is_merge_commit` / `is_release_commit` boolean columns, so collapsing
32678
- // `conventional_type` to the maintenance catch-all 'chore' is lossless at
32679
- // the row grain. Without this the 'merge'/'release' rows violate the CHECK,
32680
- // `INSERT OR IGNORE` drops the WHOLE commits table, and the exodus-on-open
32681
- // data-continuity gate aborts the cutover (T11578 CI regression).
32682
- // - any OTHER out-of-enum value → 'chore' (defensive: future non-conventional
32683
- // subjects must never re-break the zero-deficit gate; the boolean flags and
32684
- // raw subject text remain the precise provenance).
32685
- [
32686
- "tasks_commits.conventional_type",
32687
- (src) => `CASE WHEN ${src} IS NULL THEN NULL WHEN ${src} IN ('feat', 'fix', 'chore', 'docs', 'refactor', 'test', 'build', 'ci', 'perf', 'revert', 'breaking') THEN ${src} ELSE 'chore' END`
32688
- ],
32689
- // --- tasks_task_relations.relation_type (T11548) -------------------------
32690
- // 'grouped-by' → 'groups' (enum: related/blocks/duplicates/absorbs/fixes/extends/
32691
- // supersedes/groups). 4 rows.
32692
- [
32693
- "tasks_task_relations.relation_type",
32694
- (src) => `CASE ${src} WHEN 'grouped-by' THEN 'groups' ELSE ${src} END`
32695
- ],
32696
- // --- tasks_lifecycle_stages.stage_name (T11548) --------------------------
32697
- // Legacy camelCase / past-tense values → canonical snake_case stage names.
32698
- // 'implemented' → 'implementation', 'qaPassed' → 'validation',
32699
- // 'testsPassed' → 'testing'. 3 rows.
32700
- [
32701
- "tasks_lifecycle_stages.stage_name",
32702
- (src) => `CASE ${src} WHEN 'implemented' THEN 'implementation' WHEN 'qaPassed' THEN 'validation' WHEN 'testsPassed' THEN 'testing' ELSE ${src} END`
32703
- ],
32704
- // --- tasks_architecture_decisions.gate_status (T11548) ------------------
32705
- // 'passed (T5313 consensus)' → 'passed', 'approved' → 'passed'
32706
- // (enum: pending/passed/failed/waived). 2 rows.
32707
- [
32708
- "tasks_architecture_decisions.gate_status",
32709
- (src) => `CASE WHEN ${src} LIKE 'passed%' THEN 'passed' WHEN ${src} = 'approved' THEN 'passed' ELSE ${src} END`
32710
- ],
32711
- // --- tasks_evidence_ac_bindings.binding_type (T11548) -------------------
32712
- // Values with a 'validator:...' prefix → 'direct'
32713
- // (enum: direct/satisfies/coverage). 3 rows.
32714
- // Strip the namespace prefix introduced before the enum was tightened.
32715
- [
32716
- "tasks_evidence_ac_bindings.binding_type",
32717
- (src) => `CASE WHEN ${src} LIKE 'validator:%' THEN 'direct' ELSE ${src} END`
32718
- ]
32719
- // (brain_decisions.{outcome,decided_by} normalizations removed — T11647:
32720
- // brain target = runtime shape with no CHECK; legacy values like 'accepted',
32721
- // 'rejected', 'prime' now survive VERBATIM instead of being coerced.)
32722
- ]);
32723
- NUMERIC_CLAMPS = /* @__PURE__ */ new Map([
32724
- // --- brain_weight_history.delta_weight (T11782) -------------------------
32725
- // +Inf → 1.0 (max canonical reinforcement), -Inf → -1.0 (max canonical
32726
- // depression), NaN → 0.0 (no-op delta). Finite values pass through.
32727
- [
32728
- "brain_weight_history.delta_weight",
32729
- (src) => `CASE WHEN ${src} = 9e999 THEN 1.0 WHEN ${src} = -9e999 THEN -1.0 WHEN ${src} != ${src} THEN 0.0 ELSE ${src} END`
32730
- ]
32731
- ]);
32732
- ISO_CHECK_REGEX = /CHECK\s*\(\s*"([^"]+)"\s+IS\s+NULL\s+OR\s+"[^"]+"\s+GLOB\s+'\[0-9/gi;
32733
32758
  SOURCE_EPOCH_UNITS = /* @__PURE__ */ new Map([
32734
32759
  ["conduit", "seconds"],
32735
32760
  ["brain", "milliseconds"],
@@ -32740,7 +32765,6 @@ var init_migrate = __esm({
32740
32765
  ["nexus", "milliseconds"],
32741
32766
  ["skills", "milliseconds"]
32742
32767
  ]);
32743
- EPOCH_SECONDS_THRESHOLD = 1e11;
32744
32768
  }
32745
32769
  });
32746
32770
 
@@ -32923,11 +32947,21 @@ function orderByClause(db, tableName) {
32923
32947
  }
32924
32948
  return "rowid";
32925
32949
  }
32926
- function computeTableDigest(db, tableName, columns) {
32950
+ function computeTableDigest(db, tableName, columns, transform) {
32927
32951
  const { createHash: createHash3 } = _require("node:crypto");
32928
32952
  const hasher = createHash3("sha256");
32929
32953
  const orderBy = orderByClause(db, tableName);
32930
- const selectClause = columns !== null && columns.length > 0 ? columns.map((c) => `"${c}"`).join(", ") : "*";
32954
+ let selectClause;
32955
+ if (columns !== null && columns.length > 0) {
32956
+ selectClause = columns.map((c) => {
32957
+ if (transform === void 0) return `"${c}"`;
32958
+ const srcType = transform.srcTypeByCol.get(c) ?? "";
32959
+ const expr = buildDigestExpr(transform.targetTableName, c, srcType, transform.isoGlobCols);
32960
+ return `${expr} AS "${c}"`;
32961
+ }).join(", ");
32962
+ } else {
32963
+ selectClause = "*";
32964
+ }
32931
32965
  let rows;
32932
32966
  try {
32933
32967
  rows = db.prepare(`SELECT ${selectClause} FROM "${tableName}" ORDER BY ${orderBy}`).all();
@@ -32962,6 +32996,17 @@ function sharedColumnsSorted(srcDb, srcTable, tgtDb, tgtTable) {
32962
32996
  return null;
32963
32997
  }
32964
32998
  }
32999
+ function buildSourceDigestTransform(srcDb, srcTable, tgtDb, targetTableName) {
33000
+ try {
33001
+ const srcTypeByCol = new Map(
33002
+ srcDb.prepare(`PRAGMA table_info("${srcTable}")`).all().map((r) => [r.name, r.type])
33003
+ );
33004
+ const isoGlobCols = detectIsoGlobColumns(tgtDb, targetTableName);
33005
+ return { targetTableName, srcTypeByCol, isoGlobCols };
33006
+ } catch {
33007
+ return void 0;
33008
+ }
33009
+ }
32965
33010
  function listTables2(db) {
32966
33011
  const rows = db.prepare(
32967
33012
  "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name"
@@ -33209,7 +33254,13 @@ function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
33209
33254
  targetSnap.db,
33210
33255
  targetTableName
33211
33256
  );
33212
- const srcDigest = computeTableDigest(srcSnap.db, legacyTableName, cols);
33257
+ const srcTransform = buildSourceDigestTransform(
33258
+ srcSnap.db,
33259
+ legacyTableName,
33260
+ targetSnap.db,
33261
+ targetTableName
33262
+ );
33263
+ const srcDigest = computeTableDigest(srcSnap.db, legacyTableName, cols, srcTransform);
33213
33264
  const tgtDigest = computeTableDigest(targetSnap.db, targetTableName, cols);
33214
33265
  const countMatch = srcDigest.count === tgtDigest.count;
33215
33266
  const hashMatch = srcDigest.hash === tgtDigest.hash;
@@ -33322,6 +33373,7 @@ var init_verify_migration = __esm({
33322
33373
  init_src();
33323
33374
  init_logger2();
33324
33375
  init_open_cleo_db();
33376
+ init_column_transforms();
33325
33377
  init_table_name_map();
33326
33378
  log3 = getLogger("verify-migration");
33327
33379
  _require = createRequire3(import.meta.url);