@lumenflow/cli 5.2.8 → 5.2.10

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.
@@ -16,6 +16,7 @@ import { validateWURulesSync } from '@lumenflow/core/wu-rules-engine';
16
16
  import { validateNoPlaceholders, buildPlaceholderErrorMessage } from '@lumenflow/core/wu-validator';
17
17
  import { isCodeFile } from '@lumenflow/core/manual-test-validator';
18
18
  import { isDocsOrProcessType, hasManualTests } from '@lumenflow/core/wu-type-helpers';
19
+ import { evaluateTddDiffEvidenceWaiver, resolveTddDiffEvidencePolicy, } from '@lumenflow/packs-software-delivery/policy/gates-config';
19
20
  import { buildWUContent } from './wu-create-content.js';
20
21
  /** Log prefix for console output */
21
22
  const LOG_PREFIX = '[wu:create]';
@@ -29,16 +30,55 @@ export function containsCodeFiles(codePaths) {
29
30
  export function hasAnyItems(value) {
30
31
  return Array.isArray(value) && value.length > 0;
31
32
  }
33
+ /** Test-path keywords for filtering completeness errors when waived */
34
+ const TEST_PATH_ERROR_MARKERS = [
35
+ 'test path required',
36
+ 'tests.unit',
37
+ 'tests.e2e',
38
+ 'tests.integration',
39
+ 'tests.manual',
40
+ 'at least one test entry',
41
+ 'at least one test path',
42
+ 'no automated tests',
43
+ 'requires test_paths',
44
+ 'has no automated tests',
45
+ ];
46
+ /**
47
+ * WU-2881: Identify test-path-related errors so we can suppress them when the
48
+ * resolved tdd_diff_evidence policy waives the requirement.
49
+ *
50
+ * Other completeness errors (description, code_paths, schema) MUST still
51
+ * surface — only test-path errors are policy-gated.
52
+ */
53
+ function isTestPathRelatedError(error) {
54
+ const lower = error.toLowerCase();
55
+ return TEST_PATH_ERROR_MARKERS.some((marker) => lower.includes(marker.toLowerCase()));
56
+ }
57
+ /**
58
+ * WU-2881: Print a one-line audit-trail message when the test-path requirement
59
+ * is waived at create-time. Reviewers need to see at a glance WHY a feature WU
60
+ * shipped without tests.
61
+ */
62
+ function logTestPathsWaived(waiver) {
63
+ console.log(`${LOG_PREFIX} Test paths waived: ${waiver.detail}`);
64
+ }
32
65
  /**
33
66
  * Validate WU spec for creation
34
67
  *
35
68
  * WU-1329: Strict mode (default) validates that code_paths and test_paths exist on disk.
36
69
  * Use opts.strict = false to bypass path existence checks.
37
70
  *
71
+ * WU-2881: Consults `software_delivery.gates.tdd_diff_evidence` to decide
72
+ * whether to enforce the test-path requirement. When the resolved policy
73
+ * waives the WU (mode=off, type not in applies_to_types, or all code_paths
74
+ * under exempt_paths), `tests.manual` is no longer required and downstream
75
+ * completeness errors about missing test paths are suppressed. An audit-trail
76
+ * line is printed in every waiver case so reviewers can see why.
77
+ *
38
78
  * @param params - Validation parameters
39
79
  * @returns {{ valid: boolean, errors: string[] }}
40
80
  */
41
- export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
81
+ export function validateCreateSpec({ id, lane, title, priority, type, opts, projectRoot, policyResolver, }) {
42
82
  const errors = [];
43
83
  const effectiveType = type || DEFAULT_TYPE;
44
84
  // WU-1329: Strict mode flag retained for backwards compatibility in CLI UX.
@@ -64,9 +104,26 @@ export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
64
104
  errors.push('--code-paths is required for non-documentation WUs');
65
105
  }
66
106
  }
107
+ // WU-2881: Consult the configurable tdd_diff_evidence policy so wu:create
108
+ // agrees with the wu:prep diff-evidence gate. Documentation/process types
109
+ // remain unconditionally exempt (the carve-out below is independent of the
110
+ // policy and predates it).
111
+ let tddWaiver = { waived: false };
112
+ if (!isDocsOrProcessType(effectiveType)) {
113
+ const resolver = policyResolver ?? resolveTddDiffEvidencePolicy;
114
+ const policy = resolver(projectRoot ?? process.cwd());
115
+ tddWaiver = evaluateTddDiffEvidenceWaiver({
116
+ policy,
117
+ type: effectiveType,
118
+ codePaths: opts.codePaths ?? [],
119
+ });
120
+ }
67
121
  // WU-2263: Enforce tests.manual for non-doc/process WUs at create time
68
122
  // (aligns with wu:claim's validateManualTestsForClaim, WU-1508)
69
- if (!isDocsOrProcessType(effectiveType)) {
123
+ // WU-2881: Skip when the configurable tdd_diff_evidence policy waives the
124
+ // test-path requirement (mode=off / type not in applies_to_types / all
125
+ // code_paths under exempt_paths).
126
+ if (!isDocsOrProcessType(effectiveType) && !tddWaiver.waived) {
70
127
  const tests = {
71
128
  manual: opts.testPathsManual,
72
129
  unit: opts.testPathsUnit,
@@ -77,6 +134,9 @@ export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
77
134
  ' Add at least one manual verification step under tests.manual.');
78
135
  }
79
136
  }
137
+ if (tddWaiver.waived) {
138
+ logTestPathsWaived(tddWaiver);
139
+ }
80
140
  // WU-1755: --plan flag auto-generates a spec-ref at wu-create.ts:419 via mergeSpecRefs(),
81
141
  // so skip this validation when --plan is provided (the ref will exist by the time YAML is written).
82
142
  if (effectiveType === WU_TYPES.FEATURE && !hasSpecRefs(opts.specRefs) && !opts.plan) {
@@ -127,10 +187,22 @@ export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
127
187
  code_paths: wuContent.code_paths,
128
188
  tests: wuContent.tests,
129
189
  }, { phase: 'intent' });
130
- errors.push(...intentRules.errors.map((issue) => issue.message));
190
+ // WU-2881: Filter out test-path-related rule violations when the
191
+ // tdd_diff_evidence policy waives the WU. Other intent-rule errors
192
+ // (e.g. code-path validation) still surface.
193
+ const intentMessages = intentRules.errors.map((issue) => issue.message);
194
+ const filteredIntentMessages = tddWaiver.waived
195
+ ? intentMessages.filter((msg) => !isTestPathRelatedError(msg))
196
+ : intentMessages;
197
+ errors.push(...filteredIntentMessages);
131
198
  const completeness = validateSpecCompleteness(wuContent, id);
132
199
  if (!completeness.valid) {
133
- errors.push(...completeness.errors);
200
+ // WU-2881: When tdd_diff_evidence policy waives test paths, drop
201
+ // test-path-related completeness errors but keep all others.
202
+ const completenessErrors = tddWaiver.waived
203
+ ? completeness.errors.filter((err) => !isTestPathRelatedError(err))
204
+ : completeness.errors;
205
+ errors.push(...completenessErrors);
134
206
  }
135
207
  }
136
208
  if (errors.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"wu-create-validation.js","sourceRoot":"","sources":["../src/wu-create-validation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wu-create-validation.js","sourceRoot":"","sources":["../src/wu-create-validation.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/cli",
3
- "version": "5.2.8",
3
+ "version": "5.2.10",
4
4
  "description": "Command-line interface for LumenFlow workflow framework",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -197,16 +197,16 @@
197
197
  "xstate": "^5.28.0",
198
198
  "yaml": "^2.8.2",
199
199
  "zod": "^4.3.6",
200
- "@lumenflow/agent": "5.2.8",
201
- "@lumenflow/host": "^5.2.8",
202
- "@lumenflow/memory": "5.2.8",
203
- "@lumenflow/core": "5.2.8",
204
- "@lumenflow/initiatives": "5.2.8",
205
- "@lumenflow/control-plane-sdk": "5.2.8",
206
- "@lumenflow/packs-software-delivery": "^5.2.8",
207
- "@lumenflow/metrics": "5.2.8",
208
- "@lumenflow/kernel": "5.2.8",
209
- "@lumenflow/packs-agent-runtime": "^5.2.8"
200
+ "@lumenflow/agent": "5.2.10",
201
+ "@lumenflow/core": "5.2.10",
202
+ "@lumenflow/kernel": "5.2.10",
203
+ "@lumenflow/memory": "5.2.10",
204
+ "@lumenflow/initiatives": "5.2.10",
205
+ "@lumenflow/host": "^5.2.10",
206
+ "@lumenflow/metrics": "5.2.10",
207
+ "@lumenflow/control-plane-sdk": "5.2.10",
208
+ "@lumenflow/packs-agent-runtime": "^5.2.10",
209
+ "@lumenflow/packs-software-delivery": "^5.2.10"
210
210
  },
211
211
  "devDependencies": {
212
212
  "@vitest/coverage-v8": "^4.0.18",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/packs-agent-runtime",
3
- "version": "5.2.8",
3
+ "version": "5.2.10",
4
4
  "description": "Agent runtime pack scaffold for LumenFlow — governed model-turn execution, pack config, and provider capability baselines",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/packs-sidekick",
3
- "version": "5.2.8",
3
+ "version": "5.2.10",
4
4
  "description": "Sidekick personal assistant pack for LumenFlow — 16 tools for task management, typed memory, channels, routines, and audit",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/packs-software-delivery",
3
- "version": "5.2.8",
3
+ "version": "5.2.10",
4
4
  "description": "Software delivery pack for LumenFlow — work units, gates, lanes, initiatives, and agent coordination",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -80,7 +80,10 @@ export {
80
80
  resolveTestPolicy,
81
81
  resolveTddDiffEvidencePolicy,
82
82
  resolveTddOrderingPolicy,
83
+ evaluateTddDiffEvidenceWaiver,
84
+ isPathExemptByTddDiffEvidence,
83
85
  } from './gates-coverage.js';
86
+ export type { TddDiffEvidenceWaiver, TddDiffEvidenceWaiverReason } from './gates-coverage.js';
84
87
 
85
88
  // Re-export package manager / test runner resolution
86
89
  export {
@@ -12,6 +12,7 @@
12
12
  * @module gates-coverage
13
13
  */
14
14
 
15
+ import { minimatch } from 'minimatch';
15
16
  import { asRecord, isBoolean, isNumber } from '../constants/object-guards.js';
16
17
  import {
17
18
  resolvePolicy,
@@ -230,6 +231,104 @@ export function resolveTddDiffEvidencePolicy(projectRoot: string): TddDiffEviden
230
231
  return resolvePolicyFromConfig(rawConfig).tdd_diff_evidence;
231
232
  }
232
233
 
234
+ const TDD_GLOB_MATCH_OPTIONS = { dot: true } as const;
235
+
236
+ /**
237
+ * Result of evaluating whether a WU is waived from the TDD diff-evidence
238
+ * test-path requirement based on the resolved tdd_diff_evidence policy.
239
+ *
240
+ * Used by both wu:create (test-path requirement) and wu:prep
241
+ * (diff-evidence enforcement) so that the two surfaces stay in lockstep.
242
+ *
243
+ * WU-2881: Surfacing the rationale via `reason` lets callers print an
244
+ * audit-trail line so reviewers can see WHY a WU bypassed test paths.
245
+ */
246
+ export type TddDiffEvidenceWaiver =
247
+ | { waived: false }
248
+ | { waived: true; reason: TddDiffEvidenceWaiverReason; detail: string };
249
+
250
+ export type TddDiffEvidenceWaiverReason = 'mode-off' | 'type-not-applicable' | 'all-paths-exempt';
251
+
252
+ /**
253
+ * WU-2881: Pure helper used by wu:create (and reusable by wu:prep) to decide
254
+ * whether the resolved tdd_diff_evidence policy waives the test-path
255
+ * requirement for a given WU shape.
256
+ *
257
+ * Returns waived=true when ANY of the following hold:
258
+ * 1. policy.mode === 'off'
259
+ * 2. policy.applies_to_types does not include the WU's type
260
+ * 3. The WU has at least one code_path AND every code_path matches one of
261
+ * policy.exempt_paths globs
262
+ *
263
+ * Mixed cases (some code_paths exempt, others not) are NOT waived — strict
264
+ * behavior preserved per WU-2881 acceptance criteria.
265
+ */
266
+ export function evaluateTddDiffEvidenceWaiver(options: {
267
+ policy: TddDiffEvidencePolicy;
268
+ type: string | undefined;
269
+ codePaths: readonly string[];
270
+ }): TddDiffEvidenceWaiver {
271
+ const { policy, type, codePaths } = options;
272
+
273
+ if (policy.mode === 'off') {
274
+ return {
275
+ waived: true,
276
+ reason: 'mode-off',
277
+ detail: 'tdd_diff_evidence.mode=off (workspace.yaml)',
278
+ };
279
+ }
280
+
281
+ if (typeof type !== 'string' || !policy.applies_to_types.some((t) => t === type)) {
282
+ return {
283
+ waived: true,
284
+ reason: 'type-not-applicable',
285
+ detail: `WU type '${type ?? '<unknown>'}' not in tdd_diff_evidence.applies_to_types=[${policy.applies_to_types.join(', ')}]`,
286
+ };
287
+ }
288
+
289
+ if (codePaths.length > 0 && policy.exempt_paths.length > 0) {
290
+ const matchedPatterns = new Set<string>();
291
+ const allExempt = codePaths.every((codePath) => {
292
+ const normalized = codePath.replace(/\\/g, '/');
293
+ const matchedPattern = policy.exempt_paths.find((pattern) =>
294
+ minimatch(normalized, pattern, TDD_GLOB_MATCH_OPTIONS),
295
+ );
296
+ if (matchedPattern) {
297
+ matchedPatterns.add(matchedPattern);
298
+ return true;
299
+ }
300
+ return false;
301
+ });
302
+
303
+ if (allExempt) {
304
+ return {
305
+ waived: true,
306
+ reason: 'all-paths-exempt',
307
+ detail: `all code_paths under exempt_paths globs (${[...matchedPatterns].join(', ')})`,
308
+ };
309
+ }
310
+ }
311
+
312
+ return { waived: false };
313
+ }
314
+
315
+ /**
316
+ * WU-2881: Match a single file path against the policy's exempt_paths globs.
317
+ *
318
+ * Centralizes the minimatch invocation so wu:prep and other callers can share
319
+ * one canonical exempt-path matcher.
320
+ */
321
+ export function isPathExemptByTddDiffEvidence(
322
+ filePath: string,
323
+ exemptPaths: readonly string[],
324
+ ): boolean {
325
+ if (exemptPaths.length === 0) {
326
+ return false;
327
+ }
328
+ const normalized = filePath.replace(/\\/g, '/');
329
+ return exemptPaths.some((pattern) => minimatch(normalized, pattern, TDD_GLOB_MATCH_OPTIONS));
330
+ }
331
+
233
332
  /**
234
333
  * WU-2650: Resolve the commit-order (RED-first) policy.
235
334
  *
@@ -25,5 +25,20 @@ if [ "$1" = "worktree" ] && [ "$2" = "remove" ]; then
25
25
  exit 1
26
26
  fi
27
27
 
28
+ # WU-2884: Block GIT_EDITOR override unless trusted rebase context is active.
29
+ # Framework rebase callers (wu:done) set LUMENFLOW_REBASE_CONTEXT=wu-done
30
+ # in a try/finally before invoking git. An attacker cannot fabricate the
31
+ # sentinel without already running inside the framework's process tree.
32
+ if [ -n "${GIT_EDITOR:-}" ] && [ "${LUMENFLOW_REBASE_CONTEXT:-}" != "wu-done" ]; then
33
+ if [ "${LUMENFLOW_FORCE:-}" != "1" ]; then
34
+ echo "" >&2
35
+ echo "=== LUMENFLOW SAFETY BLOCK ===" >&2
36
+ echo "BLOCKED: GIT_EDITOR override is unsafe outside framework rebase context." >&2
37
+ echo "Set LUMENFLOW_REBASE_CONTEXT=wu-done (framework only) or LUMENFLOW_FORCE=1 to bypass." >&2
38
+ echo "==============================" >&2
39
+ exit 1
40
+ fi
41
+ fi
42
+
28
43
  # Pass through to real git
29
44
  exec git "$@"