phasegate 0.160.21 → 0.162.0

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 (96) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +6 -1
  3. package/docs/contracts/requirement-test-matrix.schema.json +1 -1
  4. package/docs/guide/cli-reference.md +1 -1
  5. package/docs/guide/configuration.md +31 -1
  6. package/docs/guide/skills-overview.md +2 -0
  7. package/docs/principles/model-routing.md +1 -0
  8. package/docs/templates/personal/phasegate-local-config.json +4 -1
  9. package/docs/templates/project/phasegate.config.json +4 -1
  10. package/package.json +6 -3
  11. package/scripts/harness/agent-integration/domain/services/bash-write-target-extractor.ts +91 -23
  12. package/scripts/harness/agent-integration/domain/value-objects/protected-file-list.ts +4 -0
  13. package/scripts/harness/agent-integration/domain/value-objects/write-target-scope.ts +54 -5
  14. package/scripts/harness/agent-integration/infrastructure/adapters/ci-governance-baseline-grandfather-adapter.ts +25 -2
  15. package/scripts/harness/agent-integration/infrastructure/adapters/phase-gate-query-adapter.ts +17 -2
  16. package/scripts/harness/biome-ast-engine/domain/value-objects/import-graph.ts +28 -1
  17. package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +6 -1
  18. package/scripts/harness/config-foundation/domain/harness-config.ts +10 -0
  19. package/scripts/harness/config-foundation/domain/services/preset-resolution-service.ts +2 -0
  20. package/scripts/harness/config-foundation/domain/value-objects/l3-config.ts +4 -0
  21. package/scripts/harness/config-foundation/domain/value-objects/layers-config.ts +1 -1
  22. package/scripts/harness/config-foundation/domain/value-objects/project-config.ts +20 -5
  23. package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +2 -1
  24. package/scripts/harness/config-foundation/infrastructure/presets/standard.json +2 -1
  25. package/scripts/harness/config-foundation/infrastructure/presets/strict.json +2 -1
  26. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +39 -9
  27. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +39 -9
  28. package/scripts/harness/harness-api/infrastructure/adapters/phase-dependency-model-query-adapter.ts +18 -4
  29. package/scripts/harness/harness-api/infrastructure/adapters/validator-system-execution-adapter.ts +27 -4
  30. package/scripts/harness/installation/application/ports/model-delegation-port.ts +10 -0
  31. package/scripts/harness/installation/application/usecases/run-install.ts +67 -5
  32. package/scripts/harness/installation/application/usecases/run-reconcile.ts +53 -5
  33. package/scripts/harness/installation/composition-root.ts +4 -2
  34. package/scripts/harness/installation/infrastructure/adapters/skill-deployer-model-delegation-adapter.ts +16 -0
  35. package/scripts/harness/installation/presentation/cli/install-handler.ts +2 -1
  36. package/scripts/harness/main.ts +99 -13
  37. package/scripts/harness/nyquist-validation/application/dto/generate-matrix-output.ts +9 -7
  38. package/scripts/harness/nyquist-validation/domain/services/matrix-validation-service.ts +27 -2
  39. package/scripts/harness/nyquist-validation/domain/services/requirement-intent-coverage-service.ts +4 -4
  40. package/scripts/harness/nyquist-validation/domain/value-objects/intent-coverage.ts +33 -0
  41. package/scripts/harness/nyquist-validation/infrastructure/adapters/markdown-requirement-source-adapter.ts +3 -1
  42. package/scripts/harness/quick-mode/application/usecases/classify-change-category-usecase.ts +8 -3
  43. package/scripts/harness/quick-mode/composition-root.ts +3 -0
  44. package/scripts/harness/quick-mode/domain/value-objects/quick-mode-config.ts +6 -1
  45. package/scripts/harness/quick-mode/infrastructure/adapters/validator-system-quick-mode-execution-adapter.ts +18 -0
  46. package/scripts/harness/quick-mode/presentation/handlers/ci-check-quick-mode-handler.ts +51 -5
  47. package/scripts/harness/setup/skill-deployer.ts +47 -0
  48. package/scripts/harness/skill-quality/domain/services/skill-structure-validator.ts +21 -0
  49. package/scripts/harness/skill-quality/domain/value-objects/skill-structure.ts +2 -0
  50. package/scripts/harness/skill-quality/infrastructure/adapters/l1-biome-validator-adapter.ts +12 -2
  51. package/scripts/harness/skill-quality/infrastructure/adapters/l2-validator-system-adapter.ts +12 -2
  52. package/scripts/harness/traceability-model/application/usecases/apply-work-item-status-usecase.ts +6 -1
  53. package/scripts/harness/traceability-model/infrastructure/parsers/story-catalog-parser.ts +28 -9
  54. package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +76 -25
  55. package/scripts/harness/validator-system/application/use-cases/run-l4-validators-usecase.ts +20 -8
  56. package/scripts/harness/validator-system/composition-root.ts +8 -1
  57. package/scripts/harness/validator-system/domain/ports/validator-config-port.ts +2 -0
  58. package/scripts/harness/validator-system/domain/services/validator-language-capability-service.ts +64 -0
  59. package/scripts/harness/validator-system/infrastructure/adapters/file-system-security-pattern-scanner-adapter.ts +16 -6
  60. package/scripts/harness/validator-system/infrastructure/adapters/file-system-work-item-reflection-adapter.ts +10 -1
  61. package/scripts/harness/validator-system/infrastructure/adapters/harness-config-validator-config-adapter.ts +7 -1
  62. package/scripts/harness/validator-system/infrastructure/adapters/import-graph-source-analysis-adapter.ts +35 -3
  63. package/scripts/harness/validator-system/infrastructure/adapters/nyquist-ac-coverage-policy-adapter.ts +86 -14
  64. package/scripts/harness/validator-system/infrastructure/adapters/phase-dependency-phase-gate-policy-adapter.ts +29 -3
  65. package/skills/cascade-updater/SKILL.md +1 -0
  66. package/skills/codebase-mapper/SKILL.md +1 -0
  67. package/skills/codex-delegator/SKILL.md +1 -0
  68. package/skills/consistency-checker/SKILL.md +1 -0
  69. package/skills/doc-freshness-checker/SKILL.md +1 -0
  70. package/skills/domain-designer/SKILL.md +1 -0
  71. package/skills/engineering-perspective/SKILL.md +1 -0
  72. package/skills/environment-designer/SKILL.md +1 -0
  73. package/skills/implementation-planner/SKILL.md +1 -0
  74. package/skills/implementation-readiness-checker/SKILL.md +1 -0
  75. package/skills/it-test-designer/SKILL.md +1 -0
  76. package/skills/it-test-logic-designer/SKILL.md +1 -0
  77. package/skills/logical-designer/SKILL.md +1 -0
  78. package/skills/mock-designer/SKILL.md +1 -0
  79. package/skills/phasegate-config-doctor/SKILL.md +1 -0
  80. package/skills/phasegate-toolkit-guide/SKILL.md +1 -0
  81. package/skills/pointer-validator/SKILL.md +1 -0
  82. package/skills/product-architect/SKILL.md +1 -0
  83. package/skills/quick-implementor/SKILL.md +1 -0
  84. package/skills/scenario-test-designer/SKILL.md +1 -0
  85. package/skills/scenario-test-logic-designer/SKILL.md +1 -0
  86. package/skills/skill-creator/SKILL.md +1 -0
  87. package/skills/story-implementor/SKILL.md +1 -0
  88. package/skills/story-mapper/SKILL.md +1 -0
  89. package/skills/story-writer/SKILL.md +1 -0
  90. package/skills/test-coverage-checker/SKILL.md +1 -0
  91. package/skills/uiux-designer/SKILL.md +1 -0
  92. package/skills/unit-designer/SKILL.md +1 -0
  93. package/skills/unit-test-designer/SKILL.md +1 -0
  94. package/skills/unit-test-logic-designer/SKILL.md +1 -0
  95. package/templates/.claude/scripts/deny-check.sh +73 -12
  96. package/templates/.claude/settings.json +4 -0
@@ -3,6 +3,7 @@
3
3
  * @unit config-foundation
4
4
  * @work-item-id WI-133 / WI-156
5
5
  * @work-item-id WI-217
6
+ * @work-item-id WI-212
6
7
  */
7
8
  import type { HarnessConfigV2 } from '../../domain/harness-config.js';
8
9
 
@@ -33,7 +34,10 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
33
34
  : l4Validators;
34
35
 
35
36
  return {
36
- project: { preset: resolvedConfig.project.preset },
37
+ project: {
38
+ preset: resolvedConfig.project.preset,
39
+ languages: resolvedConfig.project.languages ?? ['typescript'],
40
+ },
37
41
  paths: {
38
42
  designDocs: resolvedConfig.paths.designDocs,
39
43
  inceptionDocs: resolvedConfig.paths.inceptionDocs,
@@ -44,6 +48,7 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
44
48
  enabled: resolvedConfig.layers.L3.enabled,
45
49
  validators: l3Validators.length > 0 ? l3Validators : ['L3-001', 'L3-002', 'L3-003', 'L3-004'],
46
50
  coverageThreshold: resolvedConfig.layers.L3.coverageThreshold,
51
+ requirementMatrixPath: resolvedConfig.layers.L3.requirementMatrixPath,
47
52
  },
48
53
  L4: {
49
54
  enabled: resolvedConfig.layers.L4.enabled,
@@ -2,6 +2,8 @@
2
2
  * @layer domain
3
3
  * @unit config-foundation
4
4
  * @work-item-id WI-012
5
+ * @work-item-id WI-212
6
+ * @work-item-id WI-219
5
7
  */
6
8
  import { ConfigFoundationDomainError } from './errors/config-foundation-domain-error.js';
7
9
  import { ConfigValidationError } from './errors/config-validation-error.js';
@@ -30,6 +32,7 @@ import type {
30
32
  export type LayerId = 'L1' | 'L2' | 'L3' | 'L4';
31
33
  export type PresetId = 'minimal' | 'standard' | 'strict';
32
34
  export type PlanningModeValue = 'interactive' | 'embedded-qa' | 'manual';
35
+ export type ModelDelegationPolicy = 'delegate-sonnet' | 'none';
33
36
  export type { PhaseDependenciesPresetId };
34
37
  type DeepPartial<T> = {
35
38
  [K in keyof T]?: T[K] extends Array<infer TItem>
@@ -43,6 +46,7 @@ export interface HarnessConfigSourceDocument {
43
46
  project: {
44
47
  name: string;
45
48
  preset: PresetId;
49
+ languages?: string[];
46
50
  };
47
51
  layers: DeepPartial<HarnessConfigResolvedDocument['layers']>;
48
52
  quickMode: Partial<HarnessConfigResolvedDocument['quickMode']>;
@@ -54,6 +58,7 @@ export interface HarnessConfigSourceDocument {
54
58
  ci?: HarnessConfigResolvedDocument['ci'];
55
59
  validate?: HarnessConfigResolvedDocument['validate'];
56
60
  preCommit?: Partial<HarnessConfigResolvedDocument['preCommit']>;
61
+ modelRouting?: HarnessConfigResolvedDocument['modelRouting'];
57
62
  phase2Extensions?: HarnessConfigResolvedDocument['phase2Extensions'];
58
63
  architecture?: ArchitectureConfigSource;
59
64
  }
@@ -62,6 +67,7 @@ export interface HarnessConfigResolvedDocument {
62
67
  project: {
63
68
  name: string;
64
69
  preset: PresetId;
70
+ languages?: string[];
65
71
  };
66
72
  layers: {
67
73
  L1: {
@@ -76,6 +82,7 @@ export interface HarnessConfigResolvedDocument {
76
82
  enabled: boolean;
77
83
  validators: string[];
78
84
  coverageThreshold: number;
85
+ requirementMatrixPath?: string;
79
86
  };
80
87
  L4: {
81
88
  enabled: boolean;
@@ -125,6 +132,9 @@ export interface HarnessConfigResolvedDocument {
125
132
  preCommit?: {
126
133
  implementationExtensions: string[];
127
134
  };
135
+ modelRouting?: {
136
+ delegation: ModelDelegationPolicy;
137
+ };
128
138
  phase2Extensions?: {
129
139
  initialCreationExpirationRules?: Array<{
130
140
  ruleId: string;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @layer domain
3
3
  * @unit config-foundation
4
+ * @work-item-id WI-212
4
5
  */
5
6
  import { ConfigFoundationDomainError } from '../errors/config-foundation-domain-error.js';
6
7
  import type {
@@ -152,6 +153,7 @@ export class PresetResolutionService {
152
153
  project: {
153
154
  name: sourceDocument.project.name,
154
155
  preset: sourceDocument.project.preset,
156
+ languages: sourceDocument.project.languages ?? ['typescript'],
155
157
  },
156
158
  layers: deepMerge(presetDefinition.layers, sourceDocument.layers, 'layers'),
157
159
  quickMode: deepMerge(
@@ -10,12 +10,14 @@ interface L3ConfigProps {
10
10
  readonly enabled: boolean;
11
11
  readonly validators: string[];
12
12
  readonly coverageThreshold: number;
13
+ readonly requirementMatrixPath?: string;
13
14
  }
14
15
 
15
16
  export class L3Config {
16
17
  readonly enabled: boolean;
17
18
  readonly validators: readonly string[];
18
19
  readonly coverageThreshold: number;
20
+ readonly requirementMatrixPath?: string;
19
21
 
20
22
  constructor(props: L3ConfigProps) {
21
23
  if (props.coverageThreshold < 0) {
@@ -37,6 +39,7 @@ export class L3Config {
37
39
  this.enabled = props.enabled;
38
40
  this.validators = Object.freeze([...props.validators]);
39
41
  this.coverageThreshold = props.coverageThreshold;
42
+ this.requirementMatrixPath = props.requirementMatrixPath;
40
43
  Object.freeze(this);
41
44
  }
42
45
 
@@ -44,6 +47,7 @@ export class L3Config {
44
47
  enabled: boolean;
45
48
  validators: string[];
46
49
  coverageThreshold: number;
50
+ requirementMatrixPath?: string;
47
51
  }): L3Config {
48
52
  return new L3Config(raw);
49
53
  }
@@ -13,7 +13,7 @@ import { L4Config } from './l4-config.js';
13
13
  interface ResolvedLayersDocument {
14
14
  L1: { enabled: boolean; rules: Record<string, string> };
15
15
  L2: { enabled: boolean; validators: string[] };
16
- L3: { enabled: boolean; validators: string[]; coverageThreshold: number };
16
+ L3: { enabled: boolean; validators: string[]; coverageThreshold: number; requirementMatrixPath?: string };
17
17
  L4: { enabled: boolean; validators: string[]; schedule: string };
18
18
  }
19
19
 
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @layer domain
3
3
  * @unit config-foundation
4
+ * @work-item-id WI-212
4
5
  *
5
6
  * ProjectConfig値オブジェクト - プロジェクト名とPresetを保持する
6
7
  */
@@ -10,35 +11,49 @@ import { Preset } from './preset.js';
10
11
  interface ProjectConfigProps {
11
12
  readonly name: string;
12
13
  readonly preset: Preset;
14
+ readonly languages?: readonly string[];
13
15
  }
14
16
 
15
17
  export class ProjectConfig {
16
18
  readonly name: string;
17
19
  readonly preset: Preset;
20
+ readonly languages: readonly string[];
18
21
 
19
22
  constructor(props: ProjectConfigProps) {
20
23
  if (!props.name || props.name.trim() === '') {
21
24
  throw new ConfigValidationError('ProjectConfig: name must not be empty');
22
25
  }
26
+ const sourceLanguages = props.languages ?? ['typescript'];
27
+ if (sourceLanguages.length === 0) {
28
+ throw new ConfigValidationError('ProjectConfig: languages must not be empty');
29
+ }
30
+ const normalizedLanguages = sourceLanguages.map((language) => language.trim()).filter((language) => language.length > 0);
31
+ if (normalizedLanguages.length !== sourceLanguages.length) {
32
+ throw new ConfigValidationError('ProjectConfig: languages must contain non-empty strings');
33
+ }
23
34
  this.name = props.name;
24
35
  this.preset = props.preset;
36
+ this.languages = Object.freeze([...normalizedLanguages]);
25
37
  Object.freeze(this);
26
38
  }
27
39
 
28
- static create(raw: { name: string; preset: string }): ProjectConfig {
40
+ static create(raw: { name: string; preset: string; languages?: readonly string[] }): ProjectConfig {
29
41
  const preset = Preset.create(raw.preset);
30
- return new ProjectConfig({ name: raw.name, preset });
42
+ return new ProjectConfig({ name: raw.name, preset, languages: raw.languages ?? ['typescript'] });
31
43
  }
32
44
 
33
45
  rename(name: string): ProjectConfig {
34
- return new ProjectConfig({ name, preset: this.preset });
46
+ return new ProjectConfig({ name, preset: this.preset, languages: this.languages });
35
47
  }
36
48
 
37
49
  changePreset(preset: Preset): ProjectConfig {
38
- return new ProjectConfig({ name: this.name, preset });
50
+ return new ProjectConfig({ name: this.name, preset, languages: this.languages });
39
51
  }
40
52
 
41
53
  equals(other: ProjectConfig): boolean {
42
- return this.name === other.name && this.preset.equals(other.preset);
54
+ return this.name === other.name
55
+ && this.preset.equals(other.preset)
56
+ && this.languages.length === other.languages.length
57
+ && this.languages.every((language, index) => language === other.languages[index]);
43
58
  }
44
59
  }
@@ -11,7 +11,8 @@
11
11
  "L3": {
12
12
  "enabled": false,
13
13
  "validators": ["consistency"],
14
- "coverageThreshold": 0
14
+ "coverageThreshold": 0,
15
+ "requirementMatrixPath": ".harness/requirement-test-matrix.json"
15
16
  },
16
17
  "L4": {
17
18
  "enabled": false,
@@ -11,7 +11,8 @@
11
11
  "L3": {
12
12
  "enabled": true,
13
13
  "validators": ["consistency", "test-quality"],
14
- "coverageThreshold": 90
14
+ "coverageThreshold": 90,
15
+ "requirementMatrixPath": ".harness/requirement-test-matrix.json"
15
16
  },
16
17
  "L4": {
17
18
  "enabled": false,
@@ -11,7 +11,8 @@
11
11
  "L3": {
12
12
  "enabled": true,
13
13
  "validators": ["consistency", "test-quality"],
14
- "coverageThreshold": 95
14
+ "coverageThreshold": 95,
15
+ "requirementMatrixPath": ".harness/requirement-test-matrix.json"
15
16
  },
16
17
  "L4": {
17
18
  "enabled": true,
@@ -33,6 +33,15 @@
33
33
  "strict"
34
34
  ]
35
35
  },
36
+ "languages": {
37
+ "type": "array",
38
+ "items": {
39
+ "type": "string",
40
+ "minLength": 1
41
+ },
42
+ "minItems": 1,
43
+ "uniqueItems": true
44
+ },
36
45
  "paths": {
37
46
  "type": "object",
38
47
  "additionalProperties": false,
@@ -117,6 +126,10 @@
117
126
  "type": "number",
118
127
  "minimum": 0,
119
128
  "maximum": 100
129
+ },
130
+ "requirementMatrixPath": {
131
+ "type": "string",
132
+ "minLength": 1
120
133
  }
121
134
  }
122
135
  },
@@ -335,20 +348,21 @@
335
348
  "type": "object",
336
349
  "additionalProperties": false,
337
350
  "required": [
338
- "unitId",
339
- "artifacts"
351
+ "inception",
352
+ "product",
353
+ "required"
340
354
  ],
341
355
  "properties": {
342
- "unitId": {
356
+ "inception": {
343
357
  "type": "string",
344
358
  "minLength": 1
345
359
  },
346
- "artifacts": {
347
- "type": "array",
348
- "items": {
349
- "type": "string",
350
- "minLength": 1
351
- }
360
+ "product": {
361
+ "type": "string",
362
+ "minLength": 1
363
+ },
364
+ "required": {
365
+ "type": "boolean"
352
366
  }
353
367
  }
354
368
  }
@@ -474,6 +488,22 @@
474
488
  }
475
489
  }
476
490
  },
491
+ "modelRouting": {
492
+ "type": "object",
493
+ "additionalProperties": false,
494
+ "required": [
495
+ "delegation"
496
+ ],
497
+ "properties": {
498
+ "delegation": {
499
+ "type": "string",
500
+ "enum": [
501
+ "delegate-sonnet",
502
+ "none"
503
+ ]
504
+ }
505
+ }
506
+ },
477
507
  "protectedFiles": {
478
508
  "type": "object",
479
509
  "additionalProperties": false,
@@ -43,6 +43,15 @@
43
43
  "strict"
44
44
  ]
45
45
  },
46
+ "languages": {
47
+ "type": "array",
48
+ "items": {
49
+ "type": "string",
50
+ "minLength": 1
51
+ },
52
+ "minItems": 1,
53
+ "uniqueItems": true
54
+ },
46
55
  "paths": {
47
56
  "type": "object",
48
57
  "additionalProperties": false,
@@ -127,6 +136,10 @@
127
136
  "type": "number",
128
137
  "minimum": 0,
129
138
  "maximum": 100
139
+ },
140
+ "requirementMatrixPath": {
141
+ "type": "string",
142
+ "minLength": 1
130
143
  }
131
144
  }
132
145
  },
@@ -345,20 +358,21 @@
345
358
  "type": "object",
346
359
  "additionalProperties": false,
347
360
  "required": [
348
- "unitId",
349
- "artifacts"
361
+ "inception",
362
+ "product",
363
+ "required"
350
364
  ],
351
365
  "properties": {
352
- "unitId": {
366
+ "inception": {
353
367
  "type": "string",
354
368
  "minLength": 1
355
369
  },
356
- "artifacts": {
357
- "type": "array",
358
- "items": {
359
- "type": "string",
360
- "minLength": 1
361
- }
370
+ "product": {
371
+ "type": "string",
372
+ "minLength": 1
373
+ },
374
+ "required": {
375
+ "type": "boolean"
362
376
  }
363
377
  }
364
378
  }
@@ -492,6 +506,22 @@
492
506
  }
493
507
  }
494
508
  },
509
+ "modelRouting": {
510
+ "type": "object",
511
+ "additionalProperties": false,
512
+ "required": [
513
+ "delegation"
514
+ ],
515
+ "properties": {
516
+ "delegation": {
517
+ "type": "string",
518
+ "enum": [
519
+ "delegate-sonnet",
520
+ "none"
521
+ ]
522
+ }
523
+ }
524
+ },
495
525
  "protectedFiles": {
496
526
  "type": "object",
497
527
  "additionalProperties": false,
@@ -61,8 +61,15 @@ export class PhaseDependencyModelQueryAdapter implements PhaseGateQueryPort {
61
61
  }
62
62
  }
63
63
  return results;
64
- } catch {
65
- return [];
64
+ } catch (err) {
65
+ // Fail-closed: returning [] here would make CheckReadyResult.fromStories treat
66
+ // "no stories" as an unconditional pass. Surface the error so the dispatcher
67
+ // reports a non-passing (error) result instead of silently opening the gate.
68
+ const message = err instanceof Error ? err.message : String(err);
69
+ console.error(`[harness-api] queryAllStories failed to evaluate phase gates: ${message}`);
70
+ throw err instanceof Error
71
+ ? err
72
+ : new Error(`queryAllStories failed to evaluate phase gates: ${message}`);
66
73
  }
67
74
  },
68
75
 
@@ -91,8 +98,15 @@ export class PhaseDependencyModelQueryAdapter implements PhaseGateQueryPort {
91
98
  currentPhase: `PHASE-${result.targetLevel}`,
92
99
  completedGates: result.passed ? [`level-${result.targetLevel}`] : [],
93
100
  });
94
- } catch {
95
- return null;
101
+ } catch (err) {
102
+ // Fail-closed: returning null here conflates a genuine execution error with
103
+ // "unit not found" and hides the failure. Surface the error so the dispatcher
104
+ // reports a non-passing (error) result instead of masking it.
105
+ const message = err instanceof Error ? err.message : String(err);
106
+ console.error(`[harness-api] queryUnit failed to evaluate phase gate for '${unitId}': ${message}`);
107
+ throw err instanceof Error
108
+ ? err
109
+ : new Error(`queryUnit failed to evaluate phase gate for '${unitId}': ${message}`);
96
110
  }
97
111
  },
98
112
  };
@@ -10,6 +10,19 @@ import type { DriftItem } from '../../domain/value-objects/drift-report-summary.
10
10
  import { toValidatorSystemConfig } from '../../../config-foundation/application/mappers/validator-system-config-mapper.js';
11
11
  import { ConfigNotFoundError } from '../../../config-foundation/infrastructure/repositories/file-system-config-repository.js';
12
12
 
13
+ /**
14
+ * validator-system config(toValidatorSystemConfig の出力)から
15
+ * L3-004 用の requirement-test-matrix.json パスを取り出す。
16
+ * 未設定・config 不在時は undefined を返し、下流の AC coverage adapter が
17
+ * 既定値(.harness/requirement-test-matrix.json)へフォールバックする。
18
+ */
19
+ function extractRequirementMatrixPath(config: object | undefined): string | undefined {
20
+ if (!config) return undefined;
21
+ const layers = (config as { layers?: { L3?: { requirementMatrixPath?: unknown } } }).layers;
22
+ const path = layers?.L3?.requirementMatrixPath;
23
+ return typeof path === 'string' && path.length > 0 ? path : undefined;
24
+ }
25
+
13
26
  // Override interface preserved for testing
14
27
  export interface IValidatorSystemStub {
15
28
  runL3Validators(): Promise<ValidatorCheckItem[]>;
@@ -40,8 +53,12 @@ export class ValidatorSystemExecutionAdapter implements ValidatorExecutionPort {
40
53
  return {
41
54
  async runL3Validators(): Promise<ValidatorCheckItem[]> {
42
55
  const { createValidatorSystemModule } = await import('../../../validator-system/composition-root.js');
43
- const mod = createValidatorSystemModule(await loadValidatorSystemConfig());
44
- const results = await mod.runL3ValidatorsUseCase.execute({ targetPaths: [] });
56
+ const config = await loadValidatorSystemConfig();
57
+ const mod = createValidatorSystemModule(config);
58
+ const results = await mod.runL3ValidatorsUseCase.execute({
59
+ targetPaths: [],
60
+ requirementMatrixPath: extractRequirementMatrixPath(config),
61
+ });
45
62
  return results.map((r) => ({
46
63
  validatorId: r.validatorId,
47
64
  passed: r.passed,
@@ -52,8 +69,14 @@ export class ValidatorSystemExecutionAdapter implements ValidatorExecutionPort {
52
69
 
53
70
  async runAllValidators(): Promise<ValidatorCheckItem[]> {
54
71
  const { createValidatorSystemModule } = await import('../../../validator-system/composition-root.js');
55
- const mod = createValidatorSystemModule(await loadValidatorSystemConfig());
56
- const report = await mod.runFullValidationUseCase.execute({ targetPaths: [], unitName: '', currentPhase: '' });
72
+ const config = await loadValidatorSystemConfig();
73
+ const mod = createValidatorSystemModule(config);
74
+ const report = await mod.runFullValidationUseCase.execute({
75
+ targetPaths: [],
76
+ unitName: '',
77
+ currentPhase: '',
78
+ requirementMatrixPath: extractRequirementMatrixPath(config),
79
+ });
57
80
  return report.results.map((r) => ({
58
81
  validatorId: r.validatorId,
59
82
  passed: r.passed,
@@ -0,0 +1,10 @@
1
+ // @unit installation
2
+ // @layer application
3
+ // @work-item-id WI-219
4
+
5
+ export type ModelDelegationPolicy = "delegate-sonnet" | "none";
6
+
7
+ export interface ModelDelegationPort {
8
+ readPolicy(projectRoot: string): Promise<ModelDelegationPolicy>;
9
+ renderSkill(content: string, policy: ModelDelegationPolicy): string;
10
+ }