@lumenflow/cli 5.5.0 → 5.7.14

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 (229) hide show
  1. package/README.md +41 -40
  2. package/dist/db-journal-recover.js +400 -0
  3. package/dist/db-journal-recover.js.map +1 -0
  4. package/dist/docs-sync.js +8 -3
  5. package/dist/docs-sync.js.map +1 -1
  6. package/dist/doctor.js +11 -0
  7. package/dist/doctor.js.map +1 -1
  8. package/dist/gate-defaults.js +37 -0
  9. package/dist/gate-defaults.js.map +1 -1
  10. package/dist/gates/monolithic-file-contention-guard.js +167 -0
  11. package/dist/gates/monolithic-file-contention-guard.js.map +1 -0
  12. package/dist/gates/prod-migration-drift.js +207 -0
  13. package/dist/gates/prod-migration-drift.js.map +1 -0
  14. package/dist/gates/test-over-deletion-guard.js +280 -0
  15. package/dist/gates/test-over-deletion-guard.js.map +1 -0
  16. package/dist/gates-runners.js +44 -3
  17. package/dist/gates-runners.js.map +1 -1
  18. package/dist/gates.js +3 -2
  19. package/dist/gates.js.map +1 -1
  20. package/dist/hooks/config-resolver.js +16 -1
  21. package/dist/hooks/config-resolver.js.map +1 -1
  22. package/dist/hooks/dirty-guard.js +43 -2
  23. package/dist/hooks/dirty-guard.js.map +1 -1
  24. package/dist/hooks/git-status-parser.js +22 -8
  25. package/dist/hooks/git-status-parser.js.map +1 -1
  26. package/dist/init-templates.js +241 -0
  27. package/dist/init-templates.js.map +1 -1
  28. package/dist/init.js +122 -16
  29. package/dist/init.js.map +1 -1
  30. package/dist/lumenflow-setup.js +144 -0
  31. package/dist/lumenflow-setup.js.map +1 -0
  32. package/dist/lumenflow-upgrade.js +43 -1
  33. package/dist/lumenflow-upgrade.js.map +1 -1
  34. package/dist/mem-create.js +10 -1
  35. package/dist/mem-create.js.map +1 -1
  36. package/dist/mem-signal.js +21 -4
  37. package/dist/mem-signal.js.map +1 -1
  38. package/dist/orchestrate-initiative.js +28 -3
  39. package/dist/orchestrate-initiative.js.map +1 -1
  40. package/dist/public-manifest.js +17 -7
  41. package/dist/public-manifest.js.map +1 -1
  42. package/dist/release.js +53 -18
  43. package/dist/release.js.map +1 -1
  44. package/dist/wu-done-gates.js +13 -9
  45. package/dist/wu-done-gates.js.map +1 -1
  46. package/dist/wu-done.js +14 -2
  47. package/dist/wu-done.js.map +1 -1
  48. package/dist/wu-edit-operations.js +74 -0
  49. package/dist/wu-edit-operations.js.map +1 -1
  50. package/dist/wu-edit-validators.js +58 -0
  51. package/dist/wu-edit-validators.js.map +1 -1
  52. package/dist/wu-edit.js +106 -4
  53. package/dist/wu-edit.js.map +1 -1
  54. package/dist/wu-prep.js +57 -9
  55. package/dist/wu-prep.js.map +1 -1
  56. package/dist/wu-recover.js +6 -0
  57. package/dist/wu-recover.js.map +1 -1
  58. package/dist/wu-release.js +120 -2
  59. package/dist/wu-release.js.map +1 -1
  60. package/dist/wu-sizing-validation.js +47 -17
  61. package/dist/wu-sizing-validation.js.map +1 -1
  62. package/dist/wu-status.js +33 -0
  63. package/dist/wu-status.js.map +1 -1
  64. package/package.json +13 -12
  65. package/packs/agent-runtime/package.json +1 -1
  66. package/packs/sidekick/package.json +1 -1
  67. package/packs/software-delivery/package.json +1 -1
  68. package/templates/core/AGENTS.md.template +67 -3
  69. package/templates/core/LUMENFLOW.md.template +196 -47
  70. package/dist/distribution-preflight.js +0 -230
  71. package/dist/distribution-preflight.js.map +0 -1
  72. package/packs/agent-runtime/agent-heartbeat.ts +0 -163
  73. package/packs/agent-runtime/auto-session-integration.ts +0 -888
  74. package/packs/agent-runtime/capability-factory.ts +0 -104
  75. package/packs/agent-runtime/constants.ts +0 -21
  76. package/packs/agent-runtime/delegation-registry-schema.ts +0 -220
  77. package/packs/agent-runtime/delegation-registry-store.ts +0 -269
  78. package/packs/agent-runtime/delegation-tree.ts +0 -328
  79. package/packs/agent-runtime/index.ts +0 -20
  80. package/packs/agent-runtime/manifest.ts +0 -348
  81. package/packs/agent-runtime/memory-coordination-contract.ts +0 -86
  82. package/packs/agent-runtime/orchestration.ts +0 -2027
  83. package/packs/agent-runtime/pack-registration.ts +0 -110
  84. package/packs/agent-runtime/policy-factory.ts +0 -165
  85. package/packs/agent-runtime/remote-controls/index.ts +0 -7
  86. package/packs/agent-runtime/remote-controls/operations.ts +0 -405
  87. package/packs/agent-runtime/remote-controls/port.ts +0 -48
  88. package/packs/agent-runtime/remote-controls/state-store.ts +0 -258
  89. package/packs/agent-runtime/remote-controls/types.ts +0 -105
  90. package/packs/agent-runtime/session-schema.ts +0 -467
  91. package/packs/agent-runtime/tool-impl/agent-turn-tools.ts +0 -793
  92. package/packs/agent-runtime/tool-impl/index.ts +0 -6
  93. package/packs/agent-runtime/tool-impl/provider-adapters.ts +0 -1245
  94. package/packs/agent-runtime/tool-impl/remote-controls.mock.ts +0 -256
  95. package/packs/agent-runtime/tool-impl/remote-controls.ts +0 -273
  96. package/packs/agent-runtime/tools/index.ts +0 -4
  97. package/packs/agent-runtime/tools/types.ts +0 -47
  98. package/packs/agent-runtime/turn-lifecycle-events.ts +0 -590
  99. package/packs/agent-runtime/types.ts +0 -128
  100. package/packs/agent-runtime/vitest.config.ts +0 -11
  101. package/packs/sidekick/channel-ingress.ts +0 -137
  102. package/packs/sidekick/constants.ts +0 -10
  103. package/packs/sidekick/index.ts +0 -8
  104. package/packs/sidekick/manifest-schema.ts +0 -49
  105. package/packs/sidekick/manifest.ts +0 -512
  106. package/packs/sidekick/pack-registration.ts +0 -110
  107. package/packs/sidekick/policy-factory.ts +0 -38
  108. package/packs/sidekick/sidekick-events.ts +0 -694
  109. package/packs/sidekick/src/adapters/cloud-queue.ts +0 -101
  110. package/packs/sidekick/src/adapters/control-plane-bridge.adapter.ts +0 -386
  111. package/packs/sidekick/src/adapters/filesystem-bridge.adapter.ts +0 -228
  112. package/packs/sidekick/src/domain/channel.types.ts +0 -64
  113. package/packs/sidekick/src/ports/channel-bridge.port.ts +0 -92
  114. package/packs/sidekick/src/routines/commit.ts +0 -74
  115. package/packs/sidekick/tool-impl/channel-tools.ts +0 -577
  116. package/packs/sidekick/tool-impl/channel-transports.ts +0 -75
  117. package/packs/sidekick/tool-impl/index.ts +0 -29
  118. package/packs/sidekick/tool-impl/memory-tools.ts +0 -290
  119. package/packs/sidekick/tool-impl/routine-commit.ts +0 -102
  120. package/packs/sidekick/tool-impl/routine-tools.ts +0 -440
  121. package/packs/sidekick/tool-impl/runtime-context.ts +0 -28
  122. package/packs/sidekick/tool-impl/shared.ts +0 -125
  123. package/packs/sidekick/tool-impl/storage.ts +0 -325
  124. package/packs/sidekick/tool-impl/system-tools.ts +0 -160
  125. package/packs/sidekick/tool-impl/task-tools.ts +0 -506
  126. package/packs/sidekick/tools/channel-tools.ts +0 -53
  127. package/packs/sidekick/tools/index.ts +0 -9
  128. package/packs/sidekick/tools/memory-tools.ts +0 -53
  129. package/packs/sidekick/tools/routine-tools.ts +0 -53
  130. package/packs/sidekick/tools/system-tools.ts +0 -47
  131. package/packs/sidekick/tools/task-tools.ts +0 -61
  132. package/packs/sidekick/tools/types.ts +0 -57
  133. package/packs/sidekick/vitest.config.ts +0 -11
  134. package/packs/software-delivery/constants.ts +0 -10
  135. package/packs/software-delivery/extensions.ts +0 -140
  136. package/packs/software-delivery/gate-policies.ts +0 -134
  137. package/packs/software-delivery/index.ts +0 -8
  138. package/packs/software-delivery/manifest-schema.ts +0 -268
  139. package/packs/software-delivery/manifest.ts +0 -657
  140. package/packs/software-delivery/pack-registration.ts +0 -113
  141. package/packs/software-delivery/src/commands/index.ts +0 -5
  142. package/packs/software-delivery/src/config/delivery-review-contract.ts +0 -256
  143. package/packs/software-delivery/src/config/env-accessors.ts +0 -66
  144. package/packs/software-delivery/src/config/index.ts +0 -8
  145. package/packs/software-delivery/src/config/normalize-config-keys.ts +0 -9
  146. package/packs/software-delivery/src/config/schemas/lumenflow-config-schema-types.ts +0 -460
  147. package/packs/software-delivery/src/config/workspace-reader.ts +0 -375
  148. package/packs/software-delivery/src/constants/backlog-patterns.ts +0 -31
  149. package/packs/software-delivery/src/constants/client-ids.ts +0 -19
  150. package/packs/software-delivery/src/constants/config-contract.ts +0 -7
  151. package/packs/software-delivery/src/constants/docs-layout-presets.ts +0 -50
  152. package/packs/software-delivery/src/constants/duration-constants.ts +0 -20
  153. package/packs/software-delivery/src/constants/gate-constants.ts +0 -32
  154. package/packs/software-delivery/src/constants/index.ts +0 -29
  155. package/packs/software-delivery/src/constants/lock-constants.ts +0 -35
  156. package/packs/software-delivery/src/constants/object-guards.ts +0 -12
  157. package/packs/software-delivery/src/constants/section-headings.ts +0 -107
  158. package/packs/software-delivery/src/constants/wu-cli-constants.ts +0 -500
  159. package/packs/software-delivery/src/constants/wu-domain-constants.ts +0 -466
  160. package/packs/software-delivery/src/constants/wu-git-constants.ts +0 -7
  161. package/packs/software-delivery/src/constants/wu-id-format.ts +0 -327
  162. package/packs/software-delivery/src/constants/wu-paths-constants.ts +0 -384
  163. package/packs/software-delivery/src/constants/wu-statuses.ts +0 -287
  164. package/packs/software-delivery/src/constants/wu-type-helpers.ts +0 -67
  165. package/packs/software-delivery/src/constants/wu-ui-constants.ts +0 -267
  166. package/packs/software-delivery/src/constants/wu-validation-constants.ts +0 -73
  167. package/packs/software-delivery/src/domain/index.ts +0 -5
  168. package/packs/software-delivery/src/domain/orchestration.constants.ts +0 -166
  169. package/packs/software-delivery/src/domain/orchestration.schemas.ts +0 -238
  170. package/packs/software-delivery/src/domain/orchestration.types.ts +0 -176
  171. package/packs/software-delivery/src/methodology/incremental-test.ts +0 -122
  172. package/packs/software-delivery/src/methodology/index.ts +0 -6
  173. package/packs/software-delivery/src/methodology/manual-test-validator.ts +0 -292
  174. package/packs/software-delivery/src/policy/coverage-gate.ts +0 -270
  175. package/packs/software-delivery/src/policy/gates-agent-mode.ts +0 -223
  176. package/packs/software-delivery/src/policy/gates-config-internal.ts +0 -121
  177. package/packs/software-delivery/src/policy/gates-config.ts +0 -300
  178. package/packs/software-delivery/src/policy/gates-coverage.ts +0 -356
  179. package/packs/software-delivery/src/policy/gates-presets.ts +0 -134
  180. package/packs/software-delivery/src/policy/gates-schemas.ts +0 -173
  181. package/packs/software-delivery/src/policy/index.ts +0 -22
  182. package/packs/software-delivery/src/policy/package-manager-resolver.ts +0 -319
  183. package/packs/software-delivery/src/policy/resolve-policy.ts +0 -601
  184. package/packs/software-delivery/src/ports/config.ports.ts +0 -90
  185. package/packs/software-delivery/src/ports/dashboard-renderer.port.ts +0 -125
  186. package/packs/software-delivery/src/ports/index.ts +0 -10
  187. package/packs/software-delivery/src/ports/sync-validator.ports.ts +0 -59
  188. package/packs/software-delivery/src/ports/wu-helpers.ports.ts +0 -168
  189. package/packs/software-delivery/src/ports/wu-state.ports.ts +0 -241
  190. package/packs/software-delivery/src/primitives/index.ts +0 -5
  191. package/packs/software-delivery/src/runtime/index.ts +0 -6
  192. package/packs/software-delivery/src/runtime/work-classifier.ts +0 -561
  193. package/packs/software-delivery/src/sandbox/index.ts +0 -10
  194. package/packs/software-delivery/src/sandbox/sandbox-allowlist.ts +0 -118
  195. package/packs/software-delivery/src/sandbox/sandbox-backend-linux.ts +0 -88
  196. package/packs/software-delivery/src/sandbox/sandbox-backend-macos.ts +0 -154
  197. package/packs/software-delivery/src/sandbox/sandbox-backend-windows.ts +0 -47
  198. package/packs/software-delivery/src/sandbox/sandbox-profile.ts +0 -153
  199. package/packs/software-delivery/src/schemas/index.ts +0 -5
  200. package/packs/software-delivery/src/state/date-utils.ts +0 -158
  201. package/packs/software-delivery/src/state/index.ts +0 -15
  202. package/packs/software-delivery/src/state/state-machine.ts +0 -119
  203. package/packs/software-delivery/src/state/wu-doc-types.ts +0 -51
  204. package/packs/software-delivery/src/state/wu-paths.ts +0 -381
  205. package/packs/software-delivery/src/state/wu-schema.ts +0 -1139
  206. package/packs/software-delivery/src/state/wu-state-schema.ts +0 -255
  207. package/packs/software-delivery/src/state/wu-yaml.ts +0 -338
  208. package/packs/software-delivery/tool-impl/agent-tools.ts +0 -263
  209. package/packs/software-delivery/tool-impl/delegation-tools.ts +0 -66
  210. package/packs/software-delivery/tool-impl/flow-metrics-tools.ts +0 -219
  211. package/packs/software-delivery/tool-impl/git-runner.ts +0 -113
  212. package/packs/software-delivery/tool-impl/git-tools.ts +0 -316
  213. package/packs/software-delivery/tool-impl/index.ts +0 -15
  214. package/packs/software-delivery/tool-impl/initiative-orchestration-tools.ts +0 -720
  215. package/packs/software-delivery/tool-impl/lane-lock.ts +0 -246
  216. package/packs/software-delivery/tool-impl/memory-tools.ts +0 -470
  217. package/packs/software-delivery/tool-impl/pending-runtime-tools.ts +0 -21
  218. package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +0 -329
  219. package/packs/software-delivery/tool-impl/runtime-native-tools.ts +0 -687
  220. package/packs/software-delivery/tool-impl/worker-loader.ts +0 -52
  221. package/packs/software-delivery/tool-impl/worktree-tools.ts +0 -46
  222. package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +0 -807
  223. package/packs/software-delivery/tools/delegation-tools.ts +0 -23
  224. package/packs/software-delivery/tools/git-tools.ts +0 -55
  225. package/packs/software-delivery/tools/index.ts +0 -8
  226. package/packs/software-delivery/tools/lane-lock-tool.ts +0 -37
  227. package/packs/software-delivery/tools/types.ts +0 -71
  228. package/packs/software-delivery/tools/worktree-tools.ts +0 -49
  229. package/packs/software-delivery/vitest.config.ts +0 -11
@@ -0,0 +1,207 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: LicenseRef-LumenFlow-Proprietary
3
+ /**
4
+ * prod-migration-drift gate (WU-2944, INIT-069 Item 14)
5
+ *
6
+ * Detects when the production database is N+ migrations behind the canonical
7
+ * migrations/ directory on main. Driver: cloud INIT-105 item 14 — prod
8
+ * silently accumulated 7+ migrations of drift before any human noticed; no
9
+ * automated detection caught it.
10
+ *
11
+ * Contract (INIT-068 / WU-2926):
12
+ * - checkApplicability: 'applicable' iff repo has migrations/ AND
13
+ * `software_delivery.gates.overrides.prod-migration-drift.connection_string_env_var`
14
+ * is configured. Default behaviour for repos that have not opted in is
15
+ * 'not-applicable' (clean opt-out — no DB credentials required).
16
+ * - checkPreconditions: 'satisfied' iff the configured env var resolves AND
17
+ * the prod DB is reachable (probe). Otherwise 'missing'.
18
+ * - prereq_strategy: 'auto-skip' (advisory; non-prod / disconnected runs
19
+ * auto-skip rather than block).
20
+ * - skippable_default: true (per-repo override surface to make safety-critical).
21
+ *
22
+ * NOT registered into local `wu:prep` by default — most repos won't have
23
+ * PROD_DATABASE_URL configured locally. The gate auto-skips not-applicable
24
+ * until the override is set, so adding it to the registry is safe.
25
+ *
26
+ * Per-repo override surface:
27
+ * software_delivery.gates.overrides.prod-migration-drift.connection_string_env_var=PROD_DATABASE_URL
28
+ * software_delivery.gates.overrides.prod-migration-drift.threshold=5
29
+ * software_delivery.gates.overrides.prod-migration-drift.skippable=false # tighten
30
+ *
31
+ * @module gates/prod-migration-drift
32
+ */
33
+ import { existsSync, readdirSync, statSync } from 'node:fs';
34
+ import path from 'node:path';
35
+ import { GATE_NAMES } from '@lumenflow/core/wu-constants';
36
+ import { getGatesSection } from '@lumenflow/packs-software-delivery/policy/gates-config-internal';
37
+ import { makeGateLogger } from '../gates-utils.js';
38
+ /** WU-2944: default drift threshold (failed when drift > threshold). */
39
+ export const DEFAULT_DRIFT_THRESHOLD = 5;
40
+ /** WU-2944: canonical override key for `pnpm config:set`. */
41
+ export const PROD_MIGRATION_DRIFT_OVERRIDE_KEY = 'software_delivery.gates.overrides.prod-migration-drift';
42
+ const MIGRATIONS_DIRNAME = 'migrations';
43
+ const SQL_FILE_PATTERN = /\.sql$/i;
44
+ /**
45
+ * Compute the set of migrations present on main but not applied to prod.
46
+ *
47
+ * Pure function: deterministic, no IO. The "drift" we surface is one-directional
48
+ * (main → prod). Migrations applied on prod that no longer exist on main are
49
+ * a separate concern (rollback / stale snapshot) and not flagged here.
50
+ */
51
+ export function detectMigrationDrift(input) {
52
+ const applied = new Set(input.appliedMigrations);
53
+ const missingFromProd = input.mainMigrations.filter((m) => !applied.has(m));
54
+ const driftCount = missingFromProd.length;
55
+ return {
56
+ missingFromProd,
57
+ driftCount,
58
+ failed: driftCount > input.threshold,
59
+ };
60
+ }
61
+ /**
62
+ * Read the canonical migrations/ directory and return `.sql` filenames in
63
+ * lexicographic order. Returns `[]` when the directory does not exist (which
64
+ * is also the clean opt-out signal for `checkApplicability`).
65
+ */
66
+ export function readMigrationsDir(cwd) {
67
+ const dir = path.join(cwd, MIGRATIONS_DIRNAME);
68
+ try {
69
+ if (!existsSync(dir))
70
+ return [];
71
+ if (!statSync(dir).isDirectory())
72
+ return [];
73
+ return readdirSync(dir)
74
+ .filter((f) => SQL_FILE_PATTERN.test(f))
75
+ .sort();
76
+ }
77
+ catch {
78
+ return [];
79
+ }
80
+ }
81
+ /**
82
+ * Read `software_delivery.gates.overrides.prod-migration-drift` from
83
+ * workspace.yaml. Returns undefined when missing or malformed so callers
84
+ * fall through to "not-applicable" (clean opt-out).
85
+ */
86
+ function readOverride(cwd) {
87
+ try {
88
+ const section = getGatesSection(cwd);
89
+ const raw = section?.overrides?.[GATE_NAMES.PROD_MIGRATION_DRIFT];
90
+ if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
91
+ return raw;
92
+ }
93
+ return undefined;
94
+ }
95
+ catch {
96
+ return undefined;
97
+ }
98
+ }
99
+ function resolveThreshold(override) {
100
+ const t = override?.threshold;
101
+ if (typeof t === 'number' && Number.isInteger(t) && t >= 0)
102
+ return t;
103
+ return DEFAULT_DRIFT_THRESHOLD;
104
+ }
105
+ /**
106
+ * Default probe: refuses to attempt a real DB connection from the gate
107
+ * runtime — the gate intentionally ships without a Postgres driver dependency
108
+ * to keep `@lumenflow/cli` slim. Real prod-drift detection happens in CI
109
+ * workflows (or via a project-supplied probe), not on every local `wu:prep`.
110
+ *
111
+ * In CI, the gate is invoked with a probe injected via
112
+ * `ctx.__prodDriftProbe` (see scheduled prod-drift workflow). When no probe
113
+ * is supplied, we report unreachable so the runtime cleanly auto-skips
114
+ * (`prereq_strategy: 'auto-skip'`) rather than fabricating a passing result.
115
+ */
116
+ const defaultProbe = () => Promise.resolve({ reachable: false, applied: [] });
117
+ function readProbe(ctx) {
118
+ const ext = ctx;
119
+ return ext.__prodDriftProbe ?? defaultProbe;
120
+ }
121
+ // ─────────────────────────────────────────────────────────────────────────
122
+ // Gate definition (INIT-068 contract)
123
+ // ─────────────────────────────────────────────────────────────────────────
124
+ async function checkApplicability(ctx) {
125
+ const cwd = ctx.cwd ?? process.cwd();
126
+ const override = readOverride(cwd);
127
+ if (!override?.connection_string_env_var)
128
+ return 'not-applicable';
129
+ if (readMigrationsDir(cwd).length === 0)
130
+ return 'not-applicable';
131
+ return 'applicable';
132
+ }
133
+ async function checkPreconditions(ctx) {
134
+ const cwd = ctx.cwd ?? process.cwd();
135
+ const override = readOverride(cwd);
136
+ const envVar = override?.connection_string_env_var;
137
+ if (!envVar)
138
+ return 'missing';
139
+ const connectionString = process.env[envVar];
140
+ if (!connectionString || connectionString.length === 0)
141
+ return 'missing';
142
+ // Probe reachability. Default probe always reports unreachable so missing
143
+ // CI/probe injection auto-skips cleanly under `prereq_strategy: 'auto-skip'`.
144
+ const probe = readProbe(ctx);
145
+ try {
146
+ const result = await probe({ connectionString, cwd });
147
+ return result.reachable ? 'satisfied' : 'missing';
148
+ }
149
+ catch {
150
+ return 'missing';
151
+ }
152
+ }
153
+ async function run(ctx) {
154
+ const start = Date.now();
155
+ const cwd = ctx.cwd ?? process.cwd();
156
+ const logLine = makeGateLogger({
157
+ agentLog: ctx.agentLog ?? null,
158
+ useAgentMode: ctx.useAgentMode,
159
+ });
160
+ logLine('\n> prod-migration-drift check\n');
161
+ const override = readOverride(cwd);
162
+ const envVar = override?.connection_string_env_var;
163
+ if (!envVar) {
164
+ // checkApplicability should have prevented this; defensive auto-pass.
165
+ logLine('ℹ️ No prod-migration-drift override configured; skipping.');
166
+ return { ok: true, duration: Date.now() - start };
167
+ }
168
+ const connectionString = process.env[envVar];
169
+ if (!connectionString) {
170
+ logLine(`ℹ️ Env var ${envVar} not set; skipping (auto-skip).`);
171
+ return { ok: true, duration: Date.now() - start };
172
+ }
173
+ const mainMigrations = readMigrationsDir(cwd);
174
+ const probe = readProbe(ctx);
175
+ const probeResult = await probe({ connectionString, cwd });
176
+ if (!probeResult.reachable) {
177
+ logLine(`⚠️ Prod DB unreachable via ${envVar}; skipping (auto-skip).`);
178
+ return { ok: true, duration: Date.now() - start };
179
+ }
180
+ const threshold = resolveThreshold(override);
181
+ const drift = detectMigrationDrift({
182
+ mainMigrations,
183
+ appliedMigrations: probeResult.applied,
184
+ threshold,
185
+ });
186
+ if (!drift.failed) {
187
+ logLine(`prod-migration-drift check passed (drift=${drift.driftCount}, threshold=${threshold}).`);
188
+ return { ok: true, duration: Date.now() - start };
189
+ }
190
+ logLine(`❌ prod-migration-drift: prod is ${drift.driftCount} migration(s) behind main (threshold=${threshold}).`);
191
+ for (const m of drift.missingFromProd) {
192
+ logLine(` - missing from prod: ${m}`);
193
+ }
194
+ logLine('Hint: review the migration backlog before deploying. Apply migrations to prod incrementally, ' +
195
+ 'or split deploys to land smaller migration sequences. To raise/lower the threshold per repo: ' +
196
+ `\`pnpm config:set ${PROD_MIGRATION_DRIFT_OVERRIDE_KEY}.threshold=<n>\`.`);
197
+ return { ok: false, duration: Date.now() - start };
198
+ }
199
+ export const prodMigrationDriftGate = {
200
+ name: GATE_NAMES.PROD_MIGRATION_DRIFT,
201
+ run,
202
+ skippable_default: true,
203
+ prereq_strategy: 'auto-skip',
204
+ checkApplicability,
205
+ checkPreconditions,
206
+ };
207
+ //# sourceMappingURL=prod-migration-drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prod-migration-drift.js","sourceRoot":"","sources":["../../src/gates/prod-migration-drift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,280 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: LicenseRef-LumenFlow-Proprietary
3
+ /**
4
+ * test-over-deletion-guard (WU-2943, INIT-069 Item 12)
5
+ *
6
+ * Heuristic gate riding the INIT-068 GateDefinition contract. When `wu:prep`
7
+ * runs, scan deleted `.test.ts` / `.test.tsx` files; parse top-level
8
+ * `describe()` / `describe.each()` string literals; flag any whose described
9
+ * symbols are NOT inside the current WU's `code_paths`.
10
+ *
11
+ * Driver: cloud INIT-105 item 12. WU-1502 dropped a substrate and incidentally
12
+ * over-deleted tests covering other concerns. Codex flagged it during review.
13
+ *
14
+ * Contract (INIT-068 / WU-2926):
15
+ * - checkApplicability: 'applicable' iff diff includes deleted .test.ts(x)
16
+ * - checkPreconditions: 'satisfied' (no env prereqs)
17
+ * - prereq_strategy: 'auto-skip'
18
+ * - skippable_default: true (advisory — agents can --skip-gate when intentional)
19
+ * - Per-repo configurable via software_delivery.gates.overrides.<gate_id>
20
+ *
21
+ * @module gates/test-over-deletion-guard
22
+ */
23
+ import { existsSync } from 'node:fs';
24
+ import path from 'node:path';
25
+ import { GATE_NAMES } from '@lumenflow/core/wu-constants';
26
+ import { createGitForPath } from '@lumenflow/core/git-adapter';
27
+ import { getCurrentWU } from '@lumenflow/core/telemetry';
28
+ import { createWuPaths } from '@lumenflow/core/wu-paths';
29
+ import { readWURaw } from '@lumenflow/core/wu-yaml';
30
+ import { resolveIntegrationTargetRef } from '@lumenflow/core/integration-target';
31
+ import { makeGateLogger } from '../gates-utils.js';
32
+ const TEST_FILE_PATTERN = /\.test\.tsx?$/;
33
+ // Bounded literal regex: the inner class explicitly excludes the matching
34
+ // quote, the `[^)]{0,256}` chunk is bounded, and the outer engine is RE2-safe
35
+ // (no nested quantifiers over the same captured class). Suppresses
36
+ // security/detect-unsafe-regex which heuristically flags any class.
37
+ // eslint-disable-next-line security/detect-unsafe-regex
38
+ const DESCRIBE_LITERAL_RE = /\bdescribe(?:\.each\s*\([^)]{0,256}\))?\s*\(\s*(['"`])([^'"`]+)\1/g;
39
+ // ─────────────────────────────────────────────────────────────────────────
40
+ // Pure helpers (exported for tests)
41
+ // ─────────────────────────────────────────────────────────────────────────
42
+ /**
43
+ * Parse top-level describe()/describe.each() string literals from test source.
44
+ *
45
+ * Simple regex parser (no AST) per the WU-2943 spec: "via simple AST or regex".
46
+ * Captures the first string-literal argument of `describe(...)` and
47
+ * `describe.each(...)(...)`.
48
+ */
49
+ export function parseDescribedSymbols(source) {
50
+ const out = new Set();
51
+ for (const match of source.matchAll(DESCRIBE_LITERAL_RE)) {
52
+ const literal = match[2];
53
+ if (typeof literal === 'string' && literal.length > 0) {
54
+ out.add(literal);
55
+ }
56
+ }
57
+ return [...out];
58
+ }
59
+ /**
60
+ * For each deleted test file, decide whether its described symbols are
61
+ * "outside" the current WU's code_paths.
62
+ *
63
+ * Heuristic match: a described symbol is considered IN scope if any
64
+ * code_paths entry's basename (without `.ts/.tsx`) equals the symbol, or if
65
+ * any code_paths entry's path normalised contains the symbol as a substring.
66
+ * Otherwise the symbol is flagged.
67
+ *
68
+ * WU-2989: `deletedSourcePaths` (paths of non-test source files removed in
69
+ * the same diff) also contribute scope tokens. This resolves the mutual
70
+ * unsatisfiability between preflight (requires every code_paths entry to
71
+ * exist on disk) and this gate (requires the described symbol's source to
72
+ * be findable from code_paths) when a WU intentionally deletes a source
73
+ * file alongside its co-located test file. The deletion diff itself is the
74
+ * symbol-provenance signal — no WU-spec schema change required.
75
+ */
76
+ export function detectCrossScopeDeletions(input) {
77
+ const { deletedTestFiles, codePaths, deletedSourcePaths = [] } = input;
78
+ // Scope tokens come from BOTH live code_paths (post-delete) and source
79
+ // paths deleted in the same diff. Both flavours are basename- and
80
+ // substring-matched identically.
81
+ const tokens = buildScopeTokens([...codePaths, ...deletedSourcePaths]);
82
+ const findings = [];
83
+ for (const file of deletedTestFiles) {
84
+ const symbols = parseDescribedSymbols(file.content);
85
+ const unrecognised = symbols.filter((s) => !isSymbolInScope(s, tokens));
86
+ if (unrecognised.length > 0) {
87
+ findings.push({ testFile: file.path, unrecognisedSymbols: unrecognised });
88
+ }
89
+ }
90
+ return findings;
91
+ }
92
+ function buildScopeTokens(codePaths) {
93
+ const basenames = new Set();
94
+ const paths = [];
95
+ for (const p of codePaths) {
96
+ if (typeof p !== 'string' || p.length === 0)
97
+ continue;
98
+ const normalised = p.replace(/\\/g, '/').toLowerCase();
99
+ paths.push(normalised);
100
+ const base = path.basename(normalised).replace(/\.[^.]+$/, '');
101
+ if (base.length > 0)
102
+ basenames.add(base);
103
+ // Also kebab → camel/pascal token, so 'payment-gateway' matches 'PaymentGateway'.
104
+ const camel = base.replace(/[-_]([a-z])/g, (_, c) => c.toUpperCase());
105
+ if (camel.length > 0)
106
+ basenames.add(camel.toLowerCase());
107
+ }
108
+ return { basenames, paths };
109
+ }
110
+ function isSymbolInScope(symbol, tokens) {
111
+ const lower = symbol.toLowerCase();
112
+ if (tokens.basenames.has(lower))
113
+ return true;
114
+ for (const p of tokens.paths) {
115
+ if (p.includes(lower))
116
+ return true;
117
+ }
118
+ return false;
119
+ }
120
+ async function getDiffNameStatus(cwd, baseRef) {
121
+ try {
122
+ const git = createGitForPath(cwd);
123
+ const out = await git.raw(['diff', '--name-status', `${baseRef}...HEAD`]);
124
+ return out
125
+ .split('\n')
126
+ .map((line) => line.trim())
127
+ .filter(Boolean)
128
+ .map((line) => {
129
+ const [status, ...rest] = line.split(/\s+/);
130
+ return { status: status ?? '', path: rest.join(' ') };
131
+ });
132
+ }
133
+ catch {
134
+ return [];
135
+ }
136
+ }
137
+ async function resolveMergeBase(cwd) {
138
+ // Prefer the configured tracking ref (origin/main or override). Fall back
139
+ // to local `main` when no remote exists (fresh clones, ephemeral test
140
+ // repos). Final fallback: empty repo with no main → null.
141
+ const candidates = [resolveIntegrationTargetRef(), 'main'];
142
+ const seen = new Set();
143
+ const git = createGitForPath(cwd);
144
+ for (const candidate of candidates) {
145
+ if (!candidate || seen.has(candidate))
146
+ continue;
147
+ seen.add(candidate);
148
+ try {
149
+ const base = await git.mergeBase('HEAD', candidate);
150
+ if (base)
151
+ return base;
152
+ }
153
+ catch {
154
+ // try next candidate
155
+ }
156
+ }
157
+ return null;
158
+ }
159
+ async function getDeletedDiffArtifacts(cwd) {
160
+ const mergeBase = await resolveMergeBase(cwd);
161
+ if (!mergeBase)
162
+ return { testFiles: [], sourcePaths: [] };
163
+ const entries = await getDiffNameStatus(cwd, mergeBase);
164
+ const deleted = entries.filter((e) => e.status.startsWith('D'));
165
+ const deletedTests = deleted.filter((e) => TEST_FILE_PATTERN.test(e.path));
166
+ // WU-2989: non-test deletions provide symbol provenance for the test-scope
167
+ // check. We don't need their content — only their paths/basenames.
168
+ const sourcePaths = deleted.filter((e) => !TEST_FILE_PATTERN.test(e.path)).map((e) => e.path);
169
+ const testFiles = [];
170
+ const git = createGitForPath(cwd);
171
+ for (const entry of deletedTests) {
172
+ // Read content from the merge-base (where the file still existed).
173
+ // showFileAtRef returns '' when the file is unreadable — treat that as
174
+ // a best-effort skip rather than a gate block.
175
+ const content = await git.showFileAtRef(mergeBase, entry.path);
176
+ if (content.length > 0) {
177
+ testFiles.push({ path: entry.path, content });
178
+ }
179
+ }
180
+ return { testFiles, sourcePaths };
181
+ }
182
+ // Back-compat thin wrapper for legacy callers that only need the test files.
183
+ async function getDeletedTestFiles(cwd) {
184
+ return (await getDeletedDiffArtifacts(cwd)).testFiles;
185
+ }
186
+ async function loadCurrentWUCodePathsForCwd(cwd) {
187
+ // Mirror gates-utils.loadCurrentWUCodePaths but rooted at an arbitrary cwd
188
+ // (the gate runs against the worktree, not necessarily process.cwd()).
189
+ let wuId = getCurrentWU();
190
+ if (!wuId) {
191
+ try {
192
+ const branch = await createGitForPath(cwd).getCurrentBranch();
193
+ const m = branch.match(/wu-(\d+)/i);
194
+ if (m)
195
+ wuId = `WU-${m[1]}`;
196
+ }
197
+ catch {
198
+ // ignore
199
+ }
200
+ }
201
+ if (!wuId)
202
+ return [];
203
+ try {
204
+ const wuPaths = createWuPaths({ projectRoot: cwd });
205
+ const yamlPath = wuPaths.WU(wuId);
206
+ const abs = path.isAbsolute(yamlPath) ? yamlPath : path.join(cwd, yamlPath);
207
+ if (!existsSync(abs))
208
+ return [];
209
+ const doc = readWURaw(abs);
210
+ if (doc && Array.isArray(doc.code_paths)) {
211
+ return doc.code_paths.filter((p) => typeof p === 'string');
212
+ }
213
+ }
214
+ catch {
215
+ // ignore — return empty so gate auto-skips not-applicable on missing WU
216
+ }
217
+ return [];
218
+ }
219
+ // ─────────────────────────────────────────────────────────────────────────
220
+ // Gate definition (INIT-068 contract)
221
+ // ─────────────────────────────────────────────────────────────────────────
222
+ async function checkApplicability(ctx) {
223
+ const cwd = ctx.cwd ?? process.cwd();
224
+ const deleted = await getDeletedTestFiles(cwd);
225
+ return deleted.length > 0 ? 'applicable' : 'not-applicable';
226
+ }
227
+ async function checkPreconditions(_ctx) {
228
+ // No environmental prerequisites: this gate only consults the git diff +
229
+ // the current WU spec, both of which are repo-local.
230
+ return 'satisfied';
231
+ }
232
+ async function run(ctx) {
233
+ const start = Date.now();
234
+ const cwd = ctx.cwd ?? process.cwd();
235
+ const logLine = makeGateLogger({
236
+ agentLog: ctx.agentLog ?? null,
237
+ useAgentMode: ctx.useAgentMode,
238
+ });
239
+ logLine('\n> test-over-deletion check\n');
240
+ const { testFiles: deleted, sourcePaths: deletedSourcePaths } = await getDeletedDiffArtifacts(cwd);
241
+ if (deleted.length === 0) {
242
+ logLine('ℹ️ No deleted test files; nothing to evaluate.');
243
+ return { ok: true, duration: Date.now() - start };
244
+ }
245
+ const codePaths = await loadCurrentWUCodePathsForCwd(cwd);
246
+ if (codePaths.length === 0) {
247
+ // Without a WU spec we can't decide scope. Auto-pass (advisory) and warn.
248
+ logLine('⚠️ No WU code_paths resolvable; skipping describe()-symbol scope check.');
249
+ return { ok: true, duration: Date.now() - start };
250
+ }
251
+ // WU-2989: pass deleted source paths from the same diff so co-deleted
252
+ // source+test pairs satisfy this gate without --skip-gate.
253
+ const findings = detectCrossScopeDeletions({
254
+ deletedTestFiles: deleted,
255
+ codePaths,
256
+ deletedSourcePaths,
257
+ });
258
+ if (findings.length === 0) {
259
+ logLine('test-over-deletion check passed.');
260
+ return { ok: true, duration: Date.now() - start };
261
+ }
262
+ logLine("❌ test-over-deletion: deleted tests reference symbols outside this WU's code_paths.");
263
+ for (const f of findings) {
264
+ logLine(` - ${f.testFile}`);
265
+ for (const s of f.unrecognisedSymbols) {
266
+ logLine(` describe('${s}') — not found in code_paths`);
267
+ }
268
+ }
269
+ logLine('Hint: confirm the deletion is intentional and in scope, or split the unrelated removal into its own WU.');
270
+ return { ok: false, duration: Date.now() - start };
271
+ }
272
+ export const testOverDeletionGate = {
273
+ name: GATE_NAMES.TEST_OVER_DELETION,
274
+ run,
275
+ skippable_default: true,
276
+ prereq_strategy: 'auto-skip',
277
+ checkApplicability,
278
+ checkPreconditions,
279
+ };
280
+ //# sourceMappingURL=test-over-deletion-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-over-deletion-guard.js","sourceRoot":"","sources":["../../src/gates/test-over-deletion-guard.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@
9
9
  * @module gates-runners
10
10
  */
11
11
  import { spawnSync } from 'node:child_process';
12
- import { existsSync, mkdirSync, readFileSync, writeFileSync, writeSync } from 'node:fs';
12
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, writeSync, } from 'node:fs';
13
13
  import { access } from 'node:fs/promises';
14
14
  import { createRequire } from 'node:module';
15
15
  import path from 'node:path';
@@ -19,7 +19,7 @@ import { createGitForPath } from '@lumenflow/core/git-adapter';
19
19
  import { resolveGatesCommands, resolveTestRunner, getGatesSection, resolveScopedUnitTestExecutionPlan, formatScopedUnitTestFallbackMessage, } from '@lumenflow/packs-software-delivery/policy/gates-config';
20
20
  import { CoChangeRuleConfigSchema, ConditionalCommandConfigSchema, } from '@lumenflow/core/config-schema';
21
21
  import { validateBacklogSync } from '@lumenflow/core/validators/backlog-sync';
22
- import { DELIVERY_REVIEW_ARTIFACT_DIR, DeliveryReviewResultSchema, calculateDeliveryReviewVerdict, createWuPaths, flattenDeliveryReviewAcceptanceCriteria, isCodePathCoveredByChangedFiles, isDeliveryReviewSkippedForType, isPathLikeTestEntry, readWU, resolveDeliveryReviewRuntimeConfig, validateClaimValidation, } from '@lumenflow/core';
22
+ import { DELIVERY_REVIEW_ARTIFACT_DIR, DeliveryReviewResultSchema, calculateDeliveryReviewVerdict, createWuPaths, flattenDeliveryReviewAcceptanceCriteria, isCodePathCoveredByChangedFiles, isDeliveryReviewSkippedForType, isPathLikeTestEntry, readWU, resolveDeliveryReviewRuntimeConfig, validateClaimValidation, DOCS_LAYOUT_PRESETS, } from '@lumenflow/core';
23
23
  import { runSupabaseDocsLinter } from '@lumenflow/core/validators/supabase-docs-linter';
24
24
  import { isIntegrationMainBranch, resolveIntegrationTargetRef, } from '@lumenflow/core/integration-target';
25
25
  import { PACKAGES, PKG_MANAGER, ESLINT_FLAGS, ESLINT_COMMANDS, ESLINT_DEFAULTS, SCRIPTS, CACHE_STRATEGIES, DIRECTORIES, EXIT_CODES, FILE_SYSTEM, } from '@lumenflow/core/wu-constants';
@@ -49,6 +49,8 @@ const DEFAULT_MIGRATION_VERIFY_PATTERNS = [
49
49
  'prisma/migrations/**',
50
50
  'drizzle/migrations/**',
51
51
  ];
52
+ const WU_DB_IMPACTING_FIELD = 'db_impacting';
53
+ const WU_YAML_EXTENSION = '.yaml';
52
54
  const DELIVERY_REVIEW_HIGH_RISK_PATH_PATTERN = /(auth|permission|secret|token|credential|billing|payment|migration|schema|policy|sandbox|security|hook)/i;
53
55
  const DELIVERY_REVIEW_TEST_PATH_PATTERN = /(^|\/)(__tests__\/|.*\.(test|spec)\.[A-Za-z0-9]+$)/i;
54
56
  function asStringArray(value) {
@@ -785,6 +787,38 @@ export function getMatchingCoChangeRulesForPaths(options) {
785
787
  export function shouldRunMigrationVerifyForChanges(options) {
786
788
  return hasPatternMatch(options.changedFiles, [...DEFAULT_MIGRATION_VERIFY_PATTERNS]);
787
789
  }
790
+ async function isDbImpactingDisabledForCurrentWU(cwd) {
791
+ const wuId = (await detectCurrentWUForCwd(cwd)) ?? findSingleWuIdInWuDirectory(cwd);
792
+ if (!wuId) {
793
+ return false;
794
+ }
795
+ try {
796
+ const wuPaths = createWuPaths({ projectRoot: cwd });
797
+ const wuPath = path.join(cwd, wuPaths.WU(wuId));
798
+ const wu = readWU(wuPath, wuId);
799
+ return wu[WU_DB_IMPACTING_FIELD] === false;
800
+ }
801
+ catch {
802
+ return false;
803
+ }
804
+ }
805
+ function findSingleWuIdInWuDirectory(cwd) {
806
+ try {
807
+ const wuPaths = createWuPaths({ projectRoot: cwd });
808
+ const wuDir = path.join(cwd, wuPaths.WU_DIR());
809
+ if (!existsSync(wuDir)) {
810
+ return null;
811
+ }
812
+ const wuFiles = readdirSync(wuDir).filter((entry) => entry.endsWith(WU_YAML_EXTENSION));
813
+ if (wuFiles.length !== 1) {
814
+ return null;
815
+ }
816
+ return path.basename(wuFiles[0], WU_YAML_EXTENSION);
817
+ }
818
+ catch {
819
+ return null;
820
+ }
821
+ }
788
822
  function resolveConditionalCommandGuidanceRefs(commands, projectRoot, logWarning) {
789
823
  return commands.map((command) => {
790
824
  if (!command.guidance_ref) {
@@ -928,6 +962,10 @@ export async function runMigrationVerifyGate({ agentLog, useAgentMode, cwd }) {
928
962
  logLine('ℹ️ No changed files detected; skipping migration verification.');
929
963
  return { ok: true, duration: Date.now() - start };
930
964
  }
965
+ if (await isDbImpactingDisabledForCurrentWU(effectiveCwd)) {
966
+ logLine('ℹ️ WU declares db_impacting:false; skipping migration verification.');
967
+ return { ok: true, duration: Date.now() - start };
968
+ }
931
969
  const conditionalCommands = getResolvedConditionalCommands(effectiveCwd, (msg) => logLine(`⚠️ ${msg}`));
932
970
  const matchingConditionalCommands = getMatchingConditionalCommandsForPaths({
933
971
  filePaths: changedFiles,
@@ -1360,6 +1398,9 @@ function readApplicabilityPathsOverride(gateId, cwd) {
1360
1398
  */
1361
1399
  export async function checkMigrationVerifyApplicability(ctx) {
1362
1400
  try {
1401
+ if (await isDbImpactingDisabledForCurrentWU(ctx.cwd ?? process.cwd())) {
1402
+ return 'not-applicable';
1403
+ }
1363
1404
  const git = createGitForPath(ctx.cwd ?? process.cwd());
1364
1405
  const changed = await getChangedFilesForIncremental({ git });
1365
1406
  return shouldRunMigrationVerifyForChanges({ changedFiles: changed })
@@ -1395,7 +1436,7 @@ export function checkInvariantsPreconditions(ctx) {
1395
1436
  'invariants.yaml',
1396
1437
  'invariants.yml',
1397
1438
  '.lumenflow/invariants.yaml',
1398
- 'docs/operations/_frameworks/lumenflow/invariants.yaml',
1439
+ `${DOCS_LAYOUT_PRESETS.arc42.operations}/_frameworks/lumenflow/invariants.yaml`,
1399
1440
  ];
1400
1441
  for (const rel of candidates) {
1401
1442
  if (existsSync(path.join(cwd, rel)))