@lumenflow/cli 5.4.0 → 5.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -40
- package/dist/db-journal-recover.js +400 -0
- package/dist/db-journal-recover.js.map +1 -0
- package/dist/docs-sync.js +8 -3
- package/dist/docs-sync.js.map +1 -1
- package/dist/gate-defaults.js +191 -9
- package/dist/gate-defaults.js.map +1 -1
- package/dist/gate-registry.js.map +1 -1
- package/dist/gates/monolithic-file-contention-guard.js +167 -0
- package/dist/gates/monolithic-file-contention-guard.js.map +1 -0
- package/dist/gates/prod-migration-drift.js +207 -0
- package/dist/gates/prod-migration-drift.js.map +1 -0
- package/dist/gates/test-over-deletion-guard.js +255 -0
- package/dist/gates/test-over-deletion-guard.js.map +1 -0
- package/dist/gates-runners.js +401 -2
- package/dist/gates-runners.js.map +1 -1
- package/dist/gates.js +349 -4
- package/dist/gates.js.map +1 -1
- package/dist/lumenflow-setup.js +144 -0
- package/dist/lumenflow-setup.js.map +1 -0
- package/dist/lumenflow-upgrade.js +2 -1
- package/dist/lumenflow-upgrade.js.map +1 -1
- package/dist/mem-create.js +10 -1
- package/dist/mem-create.js.map +1 -1
- package/dist/mem-signal.js +21 -4
- package/dist/mem-signal.js.map +1 -1
- package/dist/metrics-cli.js +19 -2
- package/dist/metrics-cli.js.map +1 -1
- package/dist/metrics-snapshot.js +25 -2
- package/dist/metrics-snapshot.js.map +1 -1
- package/dist/orchestrate-initiative.js +28 -3
- package/dist/orchestrate-initiative.js.map +1 -1
- package/dist/public-manifest.js +17 -0
- package/dist/public-manifest.js.map +1 -1
- package/dist/release.js +53 -18
- package/dist/release.js.map +1 -1
- package/dist/wu-done-gates.js +121 -8
- package/dist/wu-done-gates.js.map +1 -1
- package/dist/wu-done.js +30 -6
- package/dist/wu-done.js.map +1 -1
- package/dist/wu-edit-operations.js +74 -0
- package/dist/wu-edit-operations.js.map +1 -1
- package/dist/wu-edit-validators.js +58 -0
- package/dist/wu-edit-validators.js.map +1 -1
- package/dist/wu-edit.js +106 -4
- package/dist/wu-edit.js.map +1 -1
- package/dist/wu-prep.js +132 -8
- package/dist/wu-prep.js.map +1 -1
- package/dist/wu-recover.js +6 -0
- package/dist/wu-recover.js.map +1 -1
- package/dist/wu-release.js +120 -2
- package/dist/wu-release.js.map +1 -1
- package/dist/wu-sizing-validation.js +47 -17
- package/dist/wu-sizing-validation.js.map +1 -1
- package/dist/wu-status.js +33 -0
- package/dist/wu-status.js.map +1 -1
- package/package.json +13 -11
- package/packs/agent-runtime/package.json +1 -1
- package/packs/sidekick/package.json +1 -1
- package/packs/software-delivery/package.json +1 -1
- package/templates/core/AGENTS.md.template +162 -26
- package/templates/core/LUMENFLOW.md.template +381 -70
- package/templates/core/ai/onboarding/agent-invocation-guide.md.template +0 -5
- package/templates/core/ai/onboarding/agent-safety-card.md.template +63 -17
- package/templates/core/ai/onboarding/initiative-orchestration.md.template +4 -0
- package/templates/core/ai/onboarding/release-process.md.template +7 -7
- package/templates/core/ai/onboarding/vendor-support.md.template +74 -10
- package/templates/vendors/claude/.claude/skills/frontend-design/SKILL.md.template +1 -1
- package/templates/vendors/claude/.claude/skills/wu-lifecycle/SKILL.md.template +28 -0
- package/packs/agent-runtime/agent-heartbeat.ts +0 -163
- package/packs/agent-runtime/auto-session-integration.ts +0 -888
- package/packs/agent-runtime/capability-factory.ts +0 -104
- package/packs/agent-runtime/constants.ts +0 -21
- package/packs/agent-runtime/delegation-registry-schema.ts +0 -220
- package/packs/agent-runtime/delegation-registry-store.ts +0 -269
- package/packs/agent-runtime/delegation-tree.ts +0 -328
- package/packs/agent-runtime/index.ts +0 -20
- package/packs/agent-runtime/manifest.ts +0 -348
- package/packs/agent-runtime/memory-coordination-contract.ts +0 -86
- package/packs/agent-runtime/orchestration.ts +0 -2027
- package/packs/agent-runtime/pack-registration.ts +0 -110
- package/packs/agent-runtime/policy-factory.ts +0 -165
- package/packs/agent-runtime/remote-controls/index.ts +0 -7
- package/packs/agent-runtime/remote-controls/operations.ts +0 -405
- package/packs/agent-runtime/remote-controls/port.ts +0 -48
- package/packs/agent-runtime/remote-controls/state-store.ts +0 -258
- package/packs/agent-runtime/remote-controls/types.ts +0 -105
- package/packs/agent-runtime/session-schema.ts +0 -467
- package/packs/agent-runtime/tool-impl/agent-turn-tools.ts +0 -793
- package/packs/agent-runtime/tool-impl/index.ts +0 -6
- package/packs/agent-runtime/tool-impl/provider-adapters.ts +0 -1245
- package/packs/agent-runtime/tool-impl/remote-controls.mock.ts +0 -256
- package/packs/agent-runtime/tool-impl/remote-controls.ts +0 -273
- package/packs/agent-runtime/tools/index.ts +0 -4
- package/packs/agent-runtime/tools/types.ts +0 -47
- package/packs/agent-runtime/turn-lifecycle-events.ts +0 -590
- package/packs/agent-runtime/types.ts +0 -128
- package/packs/agent-runtime/vitest.config.ts +0 -11
- package/packs/sidekick/channel-ingress.ts +0 -137
- package/packs/sidekick/constants.ts +0 -10
- package/packs/sidekick/index.ts +0 -8
- package/packs/sidekick/manifest-schema.ts +0 -49
- package/packs/sidekick/manifest.ts +0 -512
- package/packs/sidekick/pack-registration.ts +0 -110
- package/packs/sidekick/policy-factory.ts +0 -38
- package/packs/sidekick/sidekick-events.ts +0 -694
- package/packs/sidekick/src/adapters/cloud-queue.ts +0 -101
- package/packs/sidekick/src/adapters/control-plane-bridge.adapter.ts +0 -386
- package/packs/sidekick/src/adapters/filesystem-bridge.adapter.ts +0 -228
- package/packs/sidekick/src/domain/channel.types.ts +0 -64
- package/packs/sidekick/src/ports/channel-bridge.port.ts +0 -92
- package/packs/sidekick/src/routines/commit.ts +0 -74
- package/packs/sidekick/tool-impl/channel-tools.ts +0 -577
- package/packs/sidekick/tool-impl/channel-transports.ts +0 -75
- package/packs/sidekick/tool-impl/index.ts +0 -29
- package/packs/sidekick/tool-impl/memory-tools.ts +0 -290
- package/packs/sidekick/tool-impl/routine-commit.ts +0 -102
- package/packs/sidekick/tool-impl/routine-tools.ts +0 -440
- package/packs/sidekick/tool-impl/runtime-context.ts +0 -28
- package/packs/sidekick/tool-impl/shared.ts +0 -125
- package/packs/sidekick/tool-impl/storage.ts +0 -325
- package/packs/sidekick/tool-impl/system-tools.ts +0 -160
- package/packs/sidekick/tool-impl/task-tools.ts +0 -506
- package/packs/sidekick/tools/channel-tools.ts +0 -53
- package/packs/sidekick/tools/index.ts +0 -9
- package/packs/sidekick/tools/memory-tools.ts +0 -53
- package/packs/sidekick/tools/routine-tools.ts +0 -53
- package/packs/sidekick/tools/system-tools.ts +0 -47
- package/packs/sidekick/tools/task-tools.ts +0 -61
- package/packs/sidekick/tools/types.ts +0 -57
- package/packs/sidekick/vitest.config.ts +0 -11
- package/packs/software-delivery/constants.ts +0 -10
- package/packs/software-delivery/extensions.ts +0 -140
- package/packs/software-delivery/gate-policies.ts +0 -134
- package/packs/software-delivery/index.ts +0 -8
- package/packs/software-delivery/manifest-schema.ts +0 -268
- package/packs/software-delivery/manifest.ts +0 -657
- package/packs/software-delivery/pack-registration.ts +0 -113
- package/packs/software-delivery/src/commands/index.ts +0 -5
- package/packs/software-delivery/src/config/delivery-review-contract.ts +0 -256
- package/packs/software-delivery/src/config/env-accessors.ts +0 -66
- package/packs/software-delivery/src/config/index.ts +0 -8
- package/packs/software-delivery/src/config/normalize-config-keys.ts +0 -9
- package/packs/software-delivery/src/config/schemas/lumenflow-config-schema-types.ts +0 -460
- package/packs/software-delivery/src/config/workspace-reader.ts +0 -375
- package/packs/software-delivery/src/constants/backlog-patterns.ts +0 -31
- package/packs/software-delivery/src/constants/client-ids.ts +0 -19
- package/packs/software-delivery/src/constants/config-contract.ts +0 -7
- package/packs/software-delivery/src/constants/docs-layout-presets.ts +0 -50
- package/packs/software-delivery/src/constants/duration-constants.ts +0 -20
- package/packs/software-delivery/src/constants/gate-constants.ts +0 -32
- package/packs/software-delivery/src/constants/index.ts +0 -29
- package/packs/software-delivery/src/constants/lock-constants.ts +0 -35
- package/packs/software-delivery/src/constants/object-guards.ts +0 -12
- package/packs/software-delivery/src/constants/section-headings.ts +0 -107
- package/packs/software-delivery/src/constants/wu-cli-constants.ts +0 -488
- package/packs/software-delivery/src/constants/wu-domain-constants.ts +0 -466
- package/packs/software-delivery/src/constants/wu-git-constants.ts +0 -7
- package/packs/software-delivery/src/constants/wu-id-format.ts +0 -327
- package/packs/software-delivery/src/constants/wu-paths-constants.ts +0 -384
- package/packs/software-delivery/src/constants/wu-statuses.ts +0 -287
- package/packs/software-delivery/src/constants/wu-type-helpers.ts +0 -67
- package/packs/software-delivery/src/constants/wu-ui-constants.ts +0 -267
- package/packs/software-delivery/src/constants/wu-validation-constants.ts +0 -73
- package/packs/software-delivery/src/domain/index.ts +0 -5
- package/packs/software-delivery/src/domain/orchestration.constants.ts +0 -166
- package/packs/software-delivery/src/domain/orchestration.schemas.ts +0 -238
- package/packs/software-delivery/src/domain/orchestration.types.ts +0 -176
- package/packs/software-delivery/src/methodology/incremental-test.ts +0 -122
- package/packs/software-delivery/src/methodology/index.ts +0 -6
- package/packs/software-delivery/src/methodology/manual-test-validator.ts +0 -292
- package/packs/software-delivery/src/policy/coverage-gate.ts +0 -270
- package/packs/software-delivery/src/policy/gates-agent-mode.ts +0 -223
- package/packs/software-delivery/src/policy/gates-config-internal.ts +0 -121
- package/packs/software-delivery/src/policy/gates-config.ts +0 -300
- package/packs/software-delivery/src/policy/gates-coverage.ts +0 -356
- package/packs/software-delivery/src/policy/gates-presets.ts +0 -134
- package/packs/software-delivery/src/policy/gates-schemas.ts +0 -173
- package/packs/software-delivery/src/policy/index.ts +0 -22
- package/packs/software-delivery/src/policy/package-manager-resolver.ts +0 -319
- package/packs/software-delivery/src/policy/resolve-policy.ts +0 -601
- package/packs/software-delivery/src/ports/config.ports.ts +0 -90
- package/packs/software-delivery/src/ports/dashboard-renderer.port.ts +0 -125
- package/packs/software-delivery/src/ports/index.ts +0 -10
- package/packs/software-delivery/src/ports/sync-validator.ports.ts +0 -59
- package/packs/software-delivery/src/ports/wu-helpers.ports.ts +0 -168
- package/packs/software-delivery/src/ports/wu-state.ports.ts +0 -241
- package/packs/software-delivery/src/primitives/index.ts +0 -5
- package/packs/software-delivery/src/runtime/index.ts +0 -6
- package/packs/software-delivery/src/runtime/work-classifier.ts +0 -561
- package/packs/software-delivery/src/sandbox/index.ts +0 -10
- package/packs/software-delivery/src/sandbox/sandbox-allowlist.ts +0 -118
- package/packs/software-delivery/src/sandbox/sandbox-backend-linux.ts +0 -88
- package/packs/software-delivery/src/sandbox/sandbox-backend-macos.ts +0 -154
- package/packs/software-delivery/src/sandbox/sandbox-backend-windows.ts +0 -47
- package/packs/software-delivery/src/sandbox/sandbox-profile.ts +0 -153
- package/packs/software-delivery/src/schemas/index.ts +0 -5
- package/packs/software-delivery/src/state/date-utils.ts +0 -158
- package/packs/software-delivery/src/state/index.ts +0 -15
- package/packs/software-delivery/src/state/state-machine.ts +0 -119
- package/packs/software-delivery/src/state/wu-doc-types.ts +0 -51
- package/packs/software-delivery/src/state/wu-paths.ts +0 -381
- package/packs/software-delivery/src/state/wu-schema.ts +0 -1139
- package/packs/software-delivery/src/state/wu-state-schema.ts +0 -255
- package/packs/software-delivery/src/state/wu-yaml.ts +0 -338
- package/packs/software-delivery/tool-impl/agent-tools.ts +0 -263
- package/packs/software-delivery/tool-impl/delegation-tools.ts +0 -66
- package/packs/software-delivery/tool-impl/flow-metrics-tools.ts +0 -219
- package/packs/software-delivery/tool-impl/git-runner.ts +0 -113
- package/packs/software-delivery/tool-impl/git-tools.ts +0 -316
- package/packs/software-delivery/tool-impl/index.ts +0 -15
- package/packs/software-delivery/tool-impl/initiative-orchestration-tools.ts +0 -720
- package/packs/software-delivery/tool-impl/lane-lock.ts +0 -246
- package/packs/software-delivery/tool-impl/memory-tools.ts +0 -470
- package/packs/software-delivery/tool-impl/pending-runtime-tools.ts +0 -21
- package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +0 -329
- package/packs/software-delivery/tool-impl/runtime-native-tools.ts +0 -687
- package/packs/software-delivery/tool-impl/worker-loader.ts +0 -52
- package/packs/software-delivery/tool-impl/worktree-tools.ts +0 -46
- package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +0 -807
- package/packs/software-delivery/tools/delegation-tools.ts +0 -23
- package/packs/software-delivery/tools/git-tools.ts +0 -55
- package/packs/software-delivery/tools/index.ts +0 -8
- package/packs/software-delivery/tools/lane-lock-tool.ts +0 -37
- package/packs/software-delivery/tools/types.ts +0 -71
- package/packs/software-delivery/tools/worktree-tools.ts +0 -49
- 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,255 @@
|
|
|
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
|
+
export function detectCrossScopeDeletions(input) {
|
|
69
|
+
const { deletedTestFiles, codePaths } = input;
|
|
70
|
+
const tokens = buildScopeTokens(codePaths);
|
|
71
|
+
const findings = [];
|
|
72
|
+
for (const file of deletedTestFiles) {
|
|
73
|
+
const symbols = parseDescribedSymbols(file.content);
|
|
74
|
+
const unrecognised = symbols.filter((s) => !isSymbolInScope(s, tokens));
|
|
75
|
+
if (unrecognised.length > 0) {
|
|
76
|
+
findings.push({ testFile: file.path, unrecognisedSymbols: unrecognised });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return findings;
|
|
80
|
+
}
|
|
81
|
+
function buildScopeTokens(codePaths) {
|
|
82
|
+
const basenames = new Set();
|
|
83
|
+
const paths = [];
|
|
84
|
+
for (const p of codePaths) {
|
|
85
|
+
if (typeof p !== 'string' || p.length === 0)
|
|
86
|
+
continue;
|
|
87
|
+
const normalised = p.replace(/\\/g, '/').toLowerCase();
|
|
88
|
+
paths.push(normalised);
|
|
89
|
+
const base = path.basename(normalised).replace(/\.[^.]+$/, '');
|
|
90
|
+
if (base.length > 0)
|
|
91
|
+
basenames.add(base);
|
|
92
|
+
// Also kebab → camel/pascal token, so 'payment-gateway' matches 'PaymentGateway'.
|
|
93
|
+
const camel = base.replace(/[-_]([a-z])/g, (_, c) => c.toUpperCase());
|
|
94
|
+
if (camel.length > 0)
|
|
95
|
+
basenames.add(camel.toLowerCase());
|
|
96
|
+
}
|
|
97
|
+
return { basenames, paths };
|
|
98
|
+
}
|
|
99
|
+
function isSymbolInScope(symbol, tokens) {
|
|
100
|
+
const lower = symbol.toLowerCase();
|
|
101
|
+
if (tokens.basenames.has(lower))
|
|
102
|
+
return true;
|
|
103
|
+
for (const p of tokens.paths) {
|
|
104
|
+
if (p.includes(lower))
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
async function getDiffNameStatus(cwd, baseRef) {
|
|
110
|
+
try {
|
|
111
|
+
const git = createGitForPath(cwd);
|
|
112
|
+
const out = await git.raw(['diff', '--name-status', `${baseRef}...HEAD`]);
|
|
113
|
+
return out
|
|
114
|
+
.split('\n')
|
|
115
|
+
.map((line) => line.trim())
|
|
116
|
+
.filter(Boolean)
|
|
117
|
+
.map((line) => {
|
|
118
|
+
const [status, ...rest] = line.split(/\s+/);
|
|
119
|
+
return { status: status ?? '', path: rest.join(' ') };
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async function resolveMergeBase(cwd) {
|
|
127
|
+
// Prefer the configured tracking ref (origin/main or override). Fall back
|
|
128
|
+
// to local `main` when no remote exists (fresh clones, ephemeral test
|
|
129
|
+
// repos). Final fallback: empty repo with no main → null.
|
|
130
|
+
const candidates = [resolveIntegrationTargetRef(), 'main'];
|
|
131
|
+
const seen = new Set();
|
|
132
|
+
const git = createGitForPath(cwd);
|
|
133
|
+
for (const candidate of candidates) {
|
|
134
|
+
if (!candidate || seen.has(candidate))
|
|
135
|
+
continue;
|
|
136
|
+
seen.add(candidate);
|
|
137
|
+
try {
|
|
138
|
+
const base = await git.mergeBase('HEAD', candidate);
|
|
139
|
+
if (base)
|
|
140
|
+
return base;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// try next candidate
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
async function getDeletedTestFiles(cwd) {
|
|
149
|
+
const mergeBase = await resolveMergeBase(cwd);
|
|
150
|
+
if (!mergeBase)
|
|
151
|
+
return [];
|
|
152
|
+
const entries = await getDiffNameStatus(cwd, mergeBase);
|
|
153
|
+
const deletedTests = entries.filter((e) => e.status.startsWith('D') && TEST_FILE_PATTERN.test(e.path));
|
|
154
|
+
const out = [];
|
|
155
|
+
const git = createGitForPath(cwd);
|
|
156
|
+
for (const entry of deletedTests) {
|
|
157
|
+
// Read content from the merge-base (where the file still existed).
|
|
158
|
+
// showFileAtRef returns '' when the file is unreadable — treat that as
|
|
159
|
+
// a best-effort skip rather than a gate block.
|
|
160
|
+
const content = await git.showFileAtRef(mergeBase, entry.path);
|
|
161
|
+
if (content.length > 0) {
|
|
162
|
+
out.push({ path: entry.path, content });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
async function loadCurrentWUCodePathsForCwd(cwd) {
|
|
168
|
+
// Mirror gates-utils.loadCurrentWUCodePaths but rooted at an arbitrary cwd
|
|
169
|
+
// (the gate runs against the worktree, not necessarily process.cwd()).
|
|
170
|
+
let wuId = getCurrentWU();
|
|
171
|
+
if (!wuId) {
|
|
172
|
+
try {
|
|
173
|
+
const branch = await createGitForPath(cwd).getCurrentBranch();
|
|
174
|
+
const m = branch.match(/wu-(\d+)/i);
|
|
175
|
+
if (m)
|
|
176
|
+
wuId = `WU-${m[1]}`;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// ignore
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (!wuId)
|
|
183
|
+
return [];
|
|
184
|
+
try {
|
|
185
|
+
const wuPaths = createWuPaths({ projectRoot: cwd });
|
|
186
|
+
const yamlPath = wuPaths.WU(wuId);
|
|
187
|
+
const abs = path.isAbsolute(yamlPath) ? yamlPath : path.join(cwd, yamlPath);
|
|
188
|
+
if (!existsSync(abs))
|
|
189
|
+
return [];
|
|
190
|
+
const doc = readWURaw(abs);
|
|
191
|
+
if (doc && Array.isArray(doc.code_paths)) {
|
|
192
|
+
return doc.code_paths.filter((p) => typeof p === 'string');
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// ignore — return empty so gate auto-skips not-applicable on missing WU
|
|
197
|
+
}
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
201
|
+
// Gate definition (INIT-068 contract)
|
|
202
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
203
|
+
async function checkApplicability(ctx) {
|
|
204
|
+
const cwd = ctx.cwd ?? process.cwd();
|
|
205
|
+
const deleted = await getDeletedTestFiles(cwd);
|
|
206
|
+
return deleted.length > 0 ? 'applicable' : 'not-applicable';
|
|
207
|
+
}
|
|
208
|
+
async function checkPreconditions(_ctx) {
|
|
209
|
+
// No environmental prerequisites: this gate only consults the git diff +
|
|
210
|
+
// the current WU spec, both of which are repo-local.
|
|
211
|
+
return 'satisfied';
|
|
212
|
+
}
|
|
213
|
+
async function run(ctx) {
|
|
214
|
+
const start = Date.now();
|
|
215
|
+
const cwd = ctx.cwd ?? process.cwd();
|
|
216
|
+
const logLine = makeGateLogger({
|
|
217
|
+
agentLog: ctx.agentLog ?? null,
|
|
218
|
+
useAgentMode: ctx.useAgentMode,
|
|
219
|
+
});
|
|
220
|
+
logLine('\n> test-over-deletion check\n');
|
|
221
|
+
const deleted = await getDeletedTestFiles(cwd);
|
|
222
|
+
if (deleted.length === 0) {
|
|
223
|
+
logLine('ℹ️ No deleted test files; nothing to evaluate.');
|
|
224
|
+
return { ok: true, duration: Date.now() - start };
|
|
225
|
+
}
|
|
226
|
+
const codePaths = await loadCurrentWUCodePathsForCwd(cwd);
|
|
227
|
+
if (codePaths.length === 0) {
|
|
228
|
+
// Without a WU spec we can't decide scope. Auto-pass (advisory) and warn.
|
|
229
|
+
logLine('⚠️ No WU code_paths resolvable; skipping describe()-symbol scope check.');
|
|
230
|
+
return { ok: true, duration: Date.now() - start };
|
|
231
|
+
}
|
|
232
|
+
const findings = detectCrossScopeDeletions({ deletedTestFiles: deleted, codePaths });
|
|
233
|
+
if (findings.length === 0) {
|
|
234
|
+
logLine('test-over-deletion check passed.');
|
|
235
|
+
return { ok: true, duration: Date.now() - start };
|
|
236
|
+
}
|
|
237
|
+
logLine("❌ test-over-deletion: deleted tests reference symbols outside this WU's code_paths.");
|
|
238
|
+
for (const f of findings) {
|
|
239
|
+
logLine(` - ${f.testFile}`);
|
|
240
|
+
for (const s of f.unrecognisedSymbols) {
|
|
241
|
+
logLine(` describe('${s}') — not found in code_paths`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
logLine('Hint: confirm the deletion is intentional and in scope, or split the unrelated removal into its own WU.');
|
|
245
|
+
return { ok: false, duration: Date.now() - start };
|
|
246
|
+
}
|
|
247
|
+
export const testOverDeletionGate = {
|
|
248
|
+
name: GATE_NAMES.TEST_OVER_DELETION,
|
|
249
|
+
run,
|
|
250
|
+
skippable_default: true,
|
|
251
|
+
prereq_strategy: 'auto-skip',
|
|
252
|
+
checkApplicability,
|
|
253
|
+
checkPreconditions,
|
|
254
|
+
};
|
|
255
|
+
//# 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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"}
|