phasegate 0.133.0 → 0.135.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 (42) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.ja.md +1 -4
  3. package/README.md +1 -5
  4. package/bin/phasegate +2 -0
  5. package/docs/contracts/lesson-artifact.schema.json +62 -0
  6. package/docs/contracts/requirement-test-matrix.schema.json +62 -0
  7. package/docs/guide/configuration.md +0 -1
  8. package/docs/guide/layer-model.md +9 -9
  9. package/docs/principles/architecture-philosophy.md +26 -55
  10. package/docs/principles/model-routing.md +30 -165
  11. package/docs/principles/testing-rules.md +66 -648
  12. package/package.json +4 -3
  13. package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +2 -2
  14. package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +1 -1
  15. package/scripts/harness/config-foundation/infrastructure/presets/standard.json +1 -1
  16. package/scripts/harness/config-foundation/infrastructure/presets/strict.json +1 -1
  17. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +0 -16
  18. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +0 -16
  19. package/scripts/harness/harness-error/infrastructure/adapters/validator-registry-bridge-adapter.ts +2 -0
  20. package/scripts/harness/harness-error/infrastructure/registry/l4-error-definitions.ts +14 -0
  21. package/scripts/harness/main.ts +3 -3
  22. package/scripts/harness/phase2-extensions/composition-root.ts +7 -1
  23. package/scripts/harness/phase2-extensions/infrastructure/adapters/file-system-document-scanner-adapter.ts +16 -2
  24. package/scripts/harness/phase2-extensions/infrastructure/adapters/harness-config-freshness-adapter.ts +13 -2
  25. package/scripts/harness/phase2-extensions/infrastructure/adapters/regex-pointer-extractor-adapter.ts +35 -4
  26. package/scripts/harness/quick-mode/infrastructure/adapters/validator-system-validator-id-registry-adapter.ts +1 -1
  27. package/scripts/harness/skill-quality/infrastructure/adapters/validator-id-registry-bridge-adapter.ts +1 -1
  28. package/scripts/harness/validator-system/application/dto/run-l4-validators-input.ts +1 -0
  29. package/scripts/harness/validator-system/application/use-cases/run-full-validation-usecase.ts +1 -0
  30. package/scripts/harness/validator-system/application/use-cases/run-l4-validators-usecase.ts +133 -3
  31. package/scripts/harness/validator-system/composition-root.ts +9 -16
  32. package/scripts/harness/validator-system/domain/ports/validator-config-port.ts +1 -1
  33. package/scripts/harness/validator-system/domain/services/validator-execution-service.ts +2 -2
  34. package/scripts/harness/validator-system/domain/services/validator-registry.ts +2 -2
  35. package/scripts/harness/validator-system/domain/value-objects/layer-config.ts +2 -2
  36. package/scripts/harness/validator-system/domain/value-objects/validator-definition.ts +5 -6
  37. package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +11 -6
  38. package/scripts/harness/validator-system/infrastructure/adapters/biome-ast-source-code-analyzer-adapter.ts +29 -10
  39. package/scripts/harness/validator-system/infrastructure/adapters/harness-config-validator-config-adapter.ts +12 -5
  40. package/scripts/harness/validator-system/presentation/handlers/run-validators-handler.ts +6 -35
  41. package/scripts/harness/validator-system/application/dto/run-l0-validators-input.ts +0 -9
  42. package/scripts/harness/validator-system/application/use-cases/run-l0-validators-usecase.ts +0 -60
@@ -10,7 +10,6 @@ import { ValidationRule } from './domain/value-objects/validation-rule.js';
10
10
  import { ValidatorRegistry } from './domain/services/validator-registry.js';
11
11
  import { ValidatorExecutionService } from './domain/services/validator-execution-service.js';
12
12
  import { ValidationResultContractMapper } from './application/mappers/validation-result-contract-mapper.js';
13
- import { RunL0ValidatorsUseCase } from './application/use-cases/run-l0-validators-usecase.js';
14
13
  import { RunL2ValidatorsUseCase } from './application/use-cases/run-l2-validators-usecase.js';
15
14
  import { RunL3ValidatorsUseCase } from './application/use-cases/run-l3-validators-usecase.js';
16
15
  import { RunL4ValidatorsUseCase } from './application/use-cases/run-l4-validators-usecase.js';
@@ -36,6 +35,7 @@ import { ImportGraphSourceAnalysisAdapter } from './infrastructure/adapters/impo
36
35
  import { DriftDetectionService } from './domain/services/l4/drift-detection-service.js';
37
36
  import { ConsistencyCheckService } from './domain/services/l4/consistency-check-service.js';
38
37
  import { DeadCodeDetectionService } from './domain/services/l4/dead-code-detection-service.js';
38
+ import { buildPhase2Extensions } from '../phase2-extensions/composition-root.js';
39
39
  import { RunValidatorsHandler } from './presentation/handlers/run-validators-handler.js';
40
40
  import { RunQuickModeHandler } from './presentation/handlers/run-quick-mode-handler.js';
41
41
  import { ReportValidationResultsHandler } from './presentation/handlers/report-validation-results-handler.js';
@@ -45,15 +45,14 @@ import { join } from 'node:path';
45
45
  const DEFAULT_CONFIG = {
46
46
  preset: 'standard' as const,
47
47
  layers: {
48
- L0: { enabled: true, validators: ['L0-001', 'L0-002'] },
49
48
  L2: { enabled: true, validators: ['L2-001', 'L2-002', 'L2-003'] },
50
49
  L3: { enabled: true, validators: ['L3-001', 'L3-002', 'L3-003', 'L3-004'], coverageThreshold: 90, bundleSizeLimit: 512000 },
51
- L4: { enabled: true, validators: ['L4-001', 'L4-002', 'L4-003'] },
50
+ L4: { enabled: true, validators: ['L4-001', 'L4-002', 'L4-003', 'L4-004', 'L4-005'] },
52
51
  },
53
52
  validate: { failOnWarning: false },
54
53
  };
55
54
 
56
- /** バリデータ定義カタログ(全10件) */
55
+ /** バリデータ定義カタログ */
57
56
  function buildDefaultRegistry(): ValidatorRegistry {
58
57
  const defaultRule = ValidationRule.create({
59
58
  ruleName: 'default-rule',
@@ -61,7 +60,7 @@ function buildDefaultRegistry(): ValidatorRegistry {
61
60
  fixExample: null,
62
61
  });
63
62
 
64
- const createDef = (id: string, layer: 'L0' | 'L2' | 'L3' | 'L4', enabledCondition: 'always' | 'strictOnly' = 'always', externalPolicyRef: string | null = null) =>
63
+ const createDef = (id: string, layer: 'L2' | 'L3' | 'L4', enabledCondition: 'always' | 'strictOnly' = 'always', externalPolicyRef: string | null = null) =>
65
64
  ValidatorDefinition.create({
66
65
  validatorId: ValidatorId.create(id),
67
66
  layer,
@@ -75,7 +74,6 @@ function buildDefaultRegistry(): ValidatorRegistry {
75
74
  });
76
75
 
77
76
  const definitions = [
78
- createDef('L0-001', 'L0', 'always'),
79
77
  createDef('L2-001', 'L2', 'always', 'PhaseGatePolicyPort'),
80
78
  createDef('L2-002', 'L2', 'always', 'MetadataPolicyPort'),
81
79
  createDef('L2-003', 'L2', 'always'),
@@ -86,6 +84,8 @@ function buildDefaultRegistry(): ValidatorRegistry {
86
84
  createDef('L4-001', 'L4', 'always'),
87
85
  createDef('L4-002', 'L4', 'always'),
88
86
  createDef('L4-003', 'L4', 'strictOnly'),
87
+ createDef('L4-004', 'L4', 'always'),
88
+ createDef('L4-005', 'L4', 'always'),
89
89
  ];
90
90
 
91
91
  return new ValidatorRegistry(definitions);
@@ -93,7 +93,6 @@ function buildDefaultRegistry(): ValidatorRegistry {
93
93
 
94
94
  export interface ValidatorSystemModule {
95
95
  registry: ValidatorRegistry;
96
- runL0ValidatorsUseCase: RunL0ValidatorsUseCase;
97
96
  runL1ValidatorsUseCase: RunL1ValidatorsUseCase;
98
97
  runL2ValidatorsUseCase: RunL2ValidatorsUseCase;
99
98
  runL3ValidatorsUseCase: RunL3ValidatorsUseCase;
@@ -124,13 +123,6 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
124
123
  const securityScannerPort = new FileSystemSecurityPatternScannerAdapter();
125
124
  const performanceScannerPort = new AstPerformanceScannerAdapter();
126
125
 
127
- const runL0ValidatorsUseCase = new RunL0ValidatorsUseCase({
128
- validatorRegistry: registry,
129
- validatorExecutionService: executionService,
130
- validatorConfigPort: configPort,
131
- contractMapper,
132
- });
133
-
134
126
  const runL2ValidatorsUseCase = new RunL2ValidatorsUseCase({
135
127
  validatorRegistry: registry,
136
128
  validatorExecutionService: executionService,
@@ -168,6 +160,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
168
160
  const deadCodeDetectionService = new DeadCodeDetectionService({
169
161
  sourceAnalysisPort,
170
162
  });
163
+ const phase2Extensions = buildPhase2Extensions(process.cwd(), configData as never);
171
164
 
172
165
  const runL4ValidatorsUseCase = new RunL4ValidatorsUseCase({
173
166
  validatorRegistry: registry,
@@ -177,6 +170,8 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
177
170
  driftDetectionService,
178
171
  consistencyCheckService,
179
172
  deadCodeDetectionService,
173
+ checkDocFreshnessUseCase: phase2Extensions.checkDocFreshnessUseCase,
174
+ validateDocPointersUseCase: phase2Extensions.validateDocPointersUseCase,
180
175
  });
181
176
 
182
177
  const runQuickModeUseCase = new RunQuickModeUseCase({
@@ -220,7 +215,6 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
220
215
  const handlers = {
221
216
  runValidators: new RunValidatorsHandler({
222
217
  runFullValidationUseCase,
223
- runL0ValidatorsUseCase,
224
218
  runL1ValidatorsUseCase,
225
219
  defaultFailOnWarning,
226
220
  }),
@@ -230,7 +224,6 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
230
224
 
231
225
  return {
232
226
  registry,
233
- runL0ValidatorsUseCase,
234
227
  runL1ValidatorsUseCase,
235
228
  runL2ValidatorsUseCase,
236
229
  runL3ValidatorsUseCase,
@@ -7,5 +7,5 @@
7
7
  import type { LayerConfig } from '../value-objects/layer-config.js';
8
8
 
9
9
  export interface ValidatorConfigPort {
10
- getLayerConfig(layer: 'L0' | 'L2' | 'L3' | 'L4'): Promise<LayerConfig>;
10
+ getLayerConfig(layer: 'L2' | 'L3' | 'L4'): Promise<LayerConfig>;
11
11
  }
@@ -19,7 +19,7 @@ export class ValidatorExecutionError extends Error {
19
19
 
20
20
  export interface ValidatorExecutionServiceDeps {
21
21
  configPort?: {
22
- getLayerConfig(layer: 'L0' | 'L2' | 'L3' | 'L4'): LayerConfig | Promise<LayerConfig>;
22
+ getLayerConfig(layer: 'L2' | 'L3' | 'L4'): LayerConfig | Promise<LayerConfig>;
23
23
  };
24
24
  policyPort?: PhaseGatePolicyPort | { check: (...args: unknown[]) => unknown };
25
25
  [key: string]: unknown;
@@ -132,7 +132,7 @@ export class ValidatorExecutionService {
132
132
  });
133
133
  }
134
134
 
135
- private _getLayerConfigSync(layer: 'L0' | 'L2' | 'L3' | 'L4'): LayerConfig | undefined {
135
+ private _getLayerConfigSync(layer: 'L2' | 'L3' | 'L4'): LayerConfig | undefined {
136
136
  const port = this.deps.configPort;
137
137
  if (!port) return undefined;
138
138
  const result = port.getLayerConfig(layer);
@@ -3,7 +3,7 @@
3
3
  * @unit validator-system
4
4
  *
5
5
  * ValidatorRegistry ドメインサービス
6
- * 全10バリデータ定義のカタログ管理と選択実行インターフェース
6
+ * L2-L4バリデータ定義のカタログ管理と選択実行インターフェース
7
7
  */
8
8
  import { ValidatorId } from '../value-objects/validator-id.js';
9
9
  import { ValidatorDefinition } from '../value-objects/validator-definition.js';
@@ -48,7 +48,7 @@ export class ValidatorRegistry {
48
48
  return this.definitionList;
49
49
  }
50
50
 
51
- listByLayer(layer: 'L0' | 'L2' | 'L3' | 'L4'): readonly ValidatorDefinition[] {
51
+ listByLayer(layer: 'L2' | 'L3' | 'L4'): readonly ValidatorDefinition[] {
52
52
  return this.definitionList.filter((def) => def.layer === layer);
53
53
  }
54
54
 
@@ -8,7 +8,7 @@
8
8
  import { ValidatorId } from './validator-id.js';
9
9
 
10
10
  export interface LayerConfigProps {
11
- readonly layer: 'L0' | 'L2' | 'L3' | 'L4';
11
+ readonly layer: 'L2' | 'L3' | 'L4';
12
12
  readonly enabled: boolean;
13
13
  readonly validatorIds: readonly string[];
14
14
  readonly thresholds: Record<string, number>;
@@ -17,7 +17,7 @@ export interface LayerConfigProps {
17
17
  }
18
18
 
19
19
  export class LayerConfig {
20
- readonly layer: 'L0' | 'L2' | 'L3' | 'L4';
20
+ readonly layer: 'L2' | 'L3' | 'L4';
21
21
  readonly enabled: boolean;
22
22
  readonly validatorIds: readonly string[];
23
23
  readonly thresholds: Readonly<Record<string, number>>;
@@ -10,17 +10,16 @@ import { ValidationRule } from './validation-rule.js';
10
10
 
11
11
  export interface ValidatorDefinitionProps {
12
12
  readonly validatorId: ValidatorId;
13
- readonly layer: 'L0' | 'L2' | 'L3' | 'L4';
13
+ readonly layer: 'L2' | 'L3' | 'L4';
14
14
  readonly name?: string;
15
15
  readonly description?: string;
16
16
  readonly rules: readonly ValidationRule[];
17
17
  readonly enabledCondition: 'always' | 'layerEnabled' | 'strictOnly';
18
18
  readonly externalPolicyRef: string | null;
19
- readonly executionPhase?: 'fuse-hook' | 'pre-commit' | 'ci' | 'scheduled';
19
+ readonly executionPhase?: 'pre-commit' | 'ci' | 'scheduled';
20
20
  }
21
21
 
22
- const LAYER_TO_PHASE: Record<'L0' | 'L2' | 'L3' | 'L4', 'fuse-hook' | 'fuse-hook' | 'pre-commit' | 'ci' | 'scheduled'> = {
23
- L0: 'fuse-hook',
22
+ const LAYER_TO_PHASE: Record<'L2' | 'L3' | 'L4', 'pre-commit' | 'ci' | 'scheduled'> = {
24
23
  L2: 'pre-commit',
25
24
  L3: 'ci',
26
25
  L4: 'scheduled',
@@ -28,13 +27,13 @@ const LAYER_TO_PHASE: Record<'L0' | 'L2' | 'L3' | 'L4', 'fuse-hook' | 'fuse-hook
28
27
 
29
28
  export class ValidatorDefinition {
30
29
  readonly validatorId: ValidatorId;
31
- readonly layer: 'L0' | 'L2' | 'L3' | 'L4';
30
+ readonly layer: 'L2' | 'L3' | 'L4';
32
31
  readonly name: string;
33
32
  readonly description: string;
34
33
  readonly rules: readonly ValidationRule[];
35
34
  readonly enabledCondition: 'always' | 'layerEnabled' | 'strictOnly';
36
35
  readonly externalPolicyRef: string | null;
37
- readonly executionPhase: 'fuse-hook' | 'pre-commit' | 'ci' | 'scheduled';
36
+ readonly executionPhase: 'pre-commit' | 'ci' | 'scheduled';
38
37
 
39
38
  private constructor(props: ValidatorDefinitionProps) {
40
39
  this.validatorId = props.validatorId;
@@ -3,7 +3,7 @@
3
3
  * @unit validator-system
4
4
  *
5
5
  * ValidatorId 値オブジェクト
6
- * L1-001〜L4-003 のバリデータを識別する不変値オブジェクト
6
+ * L1-001〜L4-005 のバリデータを識別する不変値オブジェクト
7
7
  * Wave 2A で L1-017, L1-018, L2-013 を追加
8
8
  */
9
9
 
@@ -20,8 +20,6 @@ const VALIDATOR_ID_PATTERN = /^L[0-4]-\d{3}$/;
20
20
 
21
21
  /** バリデータID -> バリデータ名のマップ */
22
22
  const VALIDATOR_NAME_MAP: Record<string, string> = {
23
- 'L0-001': 'fuse-hook-config',
24
- 'L0-002': 'fuse-mount-status',
25
23
  'L1-017': 'it-test-mock-detection',
26
24
  'L1-018': 'stub-comment-detection',
27
25
  'L2-001': 'phase-gate',
@@ -35,12 +33,19 @@ const VALIDATOR_NAME_MAP: Record<string, string> = {
35
33
  'L4-001': 'drift-detect',
36
34
  'L4-002': 'consistency-check',
37
35
  'L4-003': 'dead-code',
36
+ 'L4-004': 'doc-freshness',
37
+ 'L4-005': 'pointer-validation',
38
38
  };
39
39
 
40
40
  /** バリデータ名 -> バリデータID の逆引きマップ */
41
- const NAME_TO_ID_MAP: Record<string, string> = Object.fromEntries(
42
- Object.entries(VALIDATOR_NAME_MAP).map(([id, name]) => [name, id])
43
- );
41
+ const NAME_TO_ID_MAP: Record<string, string> = {
42
+ ...Object.fromEntries(Object.entries(VALIDATOR_NAME_MAP).map(([id, name]) => [name, id])),
43
+ 'drift-detector': 'L4-001',
44
+ 'consistency-checker': 'L4-002',
45
+ 'dead-code-detector': 'L4-003',
46
+ 'doc-freshness-checker': 'L4-004',
47
+ 'pointer-validator': 'L4-005',
48
+ };
44
49
 
45
50
  /** 有効なValidatorID集合 */
46
51
  const VALID_IDS = new Set(Object.keys(VALIDATOR_NAME_MAP));
@@ -12,9 +12,23 @@ import { basename, join, relative, sep } from 'node:path';
12
12
 
13
13
  const HARNESS_ROOT = join(process.cwd(), 'scripts', 'harness');
14
14
 
15
+ export interface BiomeAstSourceCodeAnalyzerAdapterOptions {
16
+ readonly sourceRoot?: string;
17
+ /** スキャン対象から除外するパスパターン(デフォルト: テストディレクトリを除外) */
18
+ readonly excludePattern?: RegExp;
19
+ }
20
+
15
21
  export class BiomeAstSourceCodeAnalyzerAdapter implements SourceCodeAnalyzerPort {
22
+ private readonly sourceRoot: string;
23
+ private readonly excludePattern: RegExp;
24
+
25
+ constructor(options: BiomeAstSourceCodeAnalyzerAdapterOptions = {}) {
26
+ this.sourceRoot = options.sourceRoot ?? HARNESS_ROOT;
27
+ this.excludePattern = options.excludePattern ?? /__tests__\//;
28
+ }
29
+
16
30
  async analyzeExports(targetUnits?: readonly string[]): Promise<readonly SourceAnalysisResult[]> {
17
- const targetFiles = await collectTargetFiles(targetUnits);
31
+ const targetFiles = await collectTargetFiles(this.sourceRoot, this.excludePattern, targetUnits);
18
32
  if (targetFiles.length === 0) return [];
19
33
 
20
34
  const program = ts.createProgram(targetFiles, {
@@ -30,7 +44,7 @@ export class BiomeAstSourceCodeAnalyzerAdapter implements SourceCodeAnalyzerPort
30
44
  const sourceFile = program.getSourceFile(filePath);
31
45
  if (!sourceFile) continue;
32
46
  results.push({
33
- unitName: resolveUnitName(filePath),
47
+ unitName: resolveUnitName(this.sourceRoot, filePath),
34
48
  filePath,
35
49
  exports: extractExports(sourceFile),
36
50
  imports: extractImports(sourceFile),
@@ -134,26 +148,31 @@ function extractImports(sourceFile: ts.SourceFile): SourceAnalysisResult['import
134
148
  return imports;
135
149
  }
136
150
 
137
- async function collectTargetFiles(targetUnits?: readonly string[]): Promise<readonly string[]> {
151
+ async function collectTargetFiles(
152
+ sourceRoot: string,
153
+ excludePattern: RegExp,
154
+ targetUnits?: readonly string[],
155
+ ): Promise<readonly string[]> {
138
156
  const roots = targetUnits && targetUnits.length > 0
139
- ? targetUnits.map((unit) => join(HARNESS_ROOT, unit))
140
- : [HARNESS_ROOT];
157
+ ? targetUnits.map((unit) => join(sourceRoot, unit))
158
+ : [sourceRoot];
141
159
 
142
160
  const files: string[] = [];
143
161
  for (const root of roots) {
144
- files.push(...await walkTsFiles(root));
162
+ files.push(...await walkTsFiles(root, excludePattern));
145
163
  }
146
164
 
147
165
  return files;
148
166
  }
149
167
 
150
- async function walkTsFiles(root: string): Promise<string[]> {
168
+ async function walkTsFiles(root: string, excludePattern: RegExp): Promise<string[]> {
151
169
  try {
152
170
  const entries = await readdir(root, { withFileTypes: true });
153
171
  const files = await Promise.all(entries.map(async (entry) => {
154
172
  const fullPath = join(root, entry.name);
173
+ if (excludePattern.test(fullPath)) return [];
155
174
  if (entry.isDirectory()) {
156
- return walkTsFiles(fullPath);
175
+ return walkTsFiles(fullPath, excludePattern);
157
176
  }
158
177
  return fullPath.endsWith('.ts') ? [fullPath] : [];
159
178
  }));
@@ -163,8 +182,8 @@ async function walkTsFiles(root: string): Promise<string[]> {
163
182
  }
164
183
  }
165
184
 
166
- function resolveUnitName(filePath: string): string {
167
- const relativePath = relative(HARNESS_ROOT, filePath);
185
+ function resolveUnitName(sourceRoot: string, filePath: string): string {
186
+ const relativePath = relative(sourceRoot, filePath);
168
187
  const [firstSegment] = relativePath.split(sep);
169
188
  return firstSegment || basename(filePath);
170
189
  }
@@ -6,10 +6,10 @@
6
6
  * HarnessConfigV2からLayerConfig VOを構築する
7
7
  */
8
8
  import { LayerConfig } from '../../domain/value-objects/layer-config.js';
9
+ import { ValidatorId } from '../../domain/value-objects/validator-id.js';
9
10
  import type { ValidatorConfigPort } from '../../domain/ports/validator-config-port.js';
10
11
 
11
12
  export interface HarnessConfigLayers {
12
- L0?: { enabled?: boolean; validators?: string[]; strictOnly?: boolean; preset?: string };
13
13
  L2?: { enabled?: boolean; validators?: string[]; strictOnly?: boolean; preset?: string };
14
14
  L3?: { enabled?: boolean; validators?: string[]; strictOnly?: boolean; preset?: string; coverageThreshold?: number; bundleSizeLimit?: number };
15
15
  L4?: { enabled?: boolean; validators?: string[]; strictOnly?: boolean; preset?: string; deadCodeGC?: boolean };
@@ -32,16 +32,15 @@ export class HarnessConfigValidatorConfigAdapter implements ValidatorConfigPort
32
32
  this.config = config;
33
33
  }
34
34
 
35
- async getLayerConfig(layer: 'L0' | 'L2' | 'L3' | 'L4'): Promise<LayerConfig> {
35
+ async getLayerConfig(layer: 'L2' | 'L3' | 'L4'): Promise<LayerConfig> {
36
36
  const preset = (this.config.project?.preset ?? this.config.preset ?? 'standard') as 'minimal' | 'standard' | 'strict';
37
37
  const strictOnly = preset === 'strict';
38
38
  const layerData = this.config.layers?.[layer] ?? {};
39
39
 
40
40
  const defaultValidators: Record<string, string[]> = {
41
- L0: ['L0-001', 'L0-002'],
42
41
  L2: ['L2-001', 'L2-002', 'L2-003'],
43
42
  L3: ['L3-001', 'L3-002', 'L3-003', 'L3-004'],
44
- L4: ['L4-001', 'L4-002', 'L4-003'],
43
+ L4: ['L4-001', 'L4-002', 'L4-003', 'L4-004', 'L4-005'],
45
44
  };
46
45
 
47
46
  const thresholds: Record<string, number> = {};
@@ -64,10 +63,18 @@ export class HarnessConfigValidatorConfigAdapter implements ValidatorConfigPort
64
63
  return LayerConfig.create({
65
64
  layer,
66
65
  enabled: layerData.enabled !== false,
67
- validatorIds: layerData.validators ?? defaultValidators[layer],
66
+ validatorIds: (layerData.validators ?? defaultValidators[layer]).map((idOrName) => this.normalizeValidatorId(idOrName)),
68
67
  thresholds,
69
68
  strictOnly: layerData.strictOnly ?? strictOnly,
70
69
  preset,
71
70
  });
72
71
  }
72
+
73
+ private normalizeValidatorId(idOrName: string): string {
74
+ try {
75
+ return ValidatorId.create(idOrName).value;
76
+ } catch {
77
+ return ValidatorId.fromName(idOrName).value;
78
+ }
79
+ }
73
80
  }
@@ -5,7 +5,6 @@
5
5
  * RunValidatorsHandler — バリデータ実行 CLIハンドラー
6
6
  */
7
7
  import type { RunFullValidationUseCase } from '../../application/use-cases/run-full-validation-usecase.js';
8
- import type { RunL0ValidatorsUseCase } from '../../application/use-cases/run-l0-validators-usecase.js';
9
8
  import type { RunL1ValidatorsUseCase } from '../../application/use-cases/run-l1-validators-usecase.js';
10
9
  import type { AggregatedValidationReport } from '../../application/dto/aggregated-validation-report.js';
11
10
  import { HumanValidationResultFormatter } from '../formatters/human-validation-result-formatter.js';
@@ -25,7 +24,6 @@ export interface RunValidatorsHandlerArgs {
25
24
 
26
25
  export interface RunValidatorsHandlerDeps {
27
26
  runFullValidationUseCase: RunFullValidationUseCase;
28
- runL0ValidatorsUseCase?: RunL0ValidatorsUseCase;
29
27
  runL1ValidatorsUseCase?: RunL1ValidatorsUseCase;
30
28
  /** WI-094 / ADR-017: config 由来の failOnWarning デフォルト。args.failOnWarning が undefined の場合に適用 */
31
29
  defaultFailOnWarning?: boolean;
@@ -33,13 +31,11 @@ export interface RunValidatorsHandlerDeps {
33
31
 
34
32
  export class RunValidatorsHandler {
35
33
  private readonly useCase: RunFullValidationUseCase;
36
- private readonly l0UseCase: RunL0ValidatorsUseCase | undefined;
37
34
  private readonly l1UseCase: RunL1ValidatorsUseCase | undefined;
38
35
  private readonly defaultFailOnWarning: boolean;
39
36
 
40
37
  constructor(deps: RunValidatorsHandlerDeps) {
41
38
  this.useCase = deps.runFullValidationUseCase;
42
- this.l0UseCase = deps.runL0ValidatorsUseCase;
43
39
  this.l1UseCase = deps.runL1ValidatorsUseCase;
44
40
  this.defaultFailOnWarning = deps.defaultFailOnWarning ?? false;
45
41
  }
@@ -47,37 +43,12 @@ export class RunValidatorsHandler {
47
43
  async execute(args: RunValidatorsHandlerArgs): Promise<{ output: string; exitCode: number }> {
48
44
  try {
49
45
  if (args.layer === 'L0') {
50
- const l0UseCase = this.l0UseCase;
51
- if (!l0UseCase) {
52
- return { output: 'L0 validators not configured', exitCode: 1 };
53
- }
54
- const l0Results = await l0UseCase.execute({
55
- validatorIds: args.validatorIds,
56
- });
57
- const l0Report: AggregatedValidationReport = {
58
- overallPassed: l0Results.every((r) => r.passed || r.skipped),
59
- totalValidators: l0Results.length,
60
- passedValidators: l0Results.filter((r) => r.passed).length,
61
- failedValidators: l0Results.filter((r) => !r.passed && !r.skipped).length,
62
- skippedValidators: l0Results.filter((r) => r.skipped).length,
63
- allErrors: l0Results.flatMap((r) => r.errors),
64
- summary: {
65
- totalErrors: l0Results.flatMap((r) => r.errors).filter((e) => e.severity === 'error').length,
66
- totalWarnings: l0Results.flatMap((r) => r.errors).filter((e) => e.severity === 'warning').length,
67
- errorsByLayer: { L2: 0, L3: 0, L4: 0 },
68
- },
69
- results: l0Results,
70
- };
71
- const format = args.format ?? 'human';
72
- let output: string;
73
- if (format === 'agent') {
74
- output = new AgentValidationResultFormatter().format(l0Report);
75
- } else if (format === 'ci') {
76
- output = new CiValidationResultFormatter().format(l0Report);
77
- } else {
78
- output = new HumanValidationResultFormatter().format(l0Report);
79
- }
80
- return { output, exitCode: l0Report.overallPassed ? 0 : 1 };
46
+ const output = [
47
+ 'L0 validator execution has been retired.',
48
+ 'Runtime L0 enforcement is provided by agent-integration hooks and Husky git hooks.',
49
+ 'Use the configured PreToolUse/PostToolUse/Stop/SessionStart/UserPromptSubmit hooks and .husky/pre-commit / .husky/commit-msg instead of validate --layer L0.',
50
+ ].join('\n');
51
+ return { output, exitCode: 0 };
81
52
  }
82
53
 
83
54
  if (args.layer === 'L1') {
@@ -1,9 +0,0 @@
1
- /**
2
- * @layer application
3
- * @unit validator-system
4
- *
5
- * RunL0ValidatorsInput — L0バリデータ実行 UseCase入力DTO
6
- */
7
- export interface RunL0ValidatorsInput {
8
- readonly validatorIds?: readonly string[];
9
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * @layer application
3
- * @unit validator-system
4
- *
5
- * RunL0ValidatorsUseCase — L0 バリデータ実行
6
- */
7
- import { ValidatorId } from '../../domain/value-objects/validator-id.js';
8
- import { ValidationResult } from '../../domain/value-objects/validation-result.js';
9
- import { ValidatorRegistry } from '../../domain/services/validator-registry.js';
10
- import { ValidatorExecutionService } from '../../domain/services/validator-execution-service.js';
11
- import { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
12
- import type { ValidationResultContract } from '../dto/validation-result-contract.js';
13
- import type { RunL0ValidatorsInput } from '../dto/run-l0-validators-input.js';
14
- import type { ValidatorConfigPort } from '../../domain/ports/validator-config-port.js';
15
-
16
- export interface RunL0ValidatorsUseCaseDeps {
17
- validatorRegistry: ValidatorRegistry;
18
- validatorExecutionService: ValidatorExecutionService;
19
- validatorConfigPort: ValidatorConfigPort;
20
- contractMapper: ValidationResultContractMapper;
21
- }
22
-
23
- export class RunL0ValidatorsUseCase {
24
- private readonly registry: ValidatorRegistry;
25
- private readonly executionService: ValidatorExecutionService;
26
- private readonly configPort: ValidatorConfigPort;
27
- private readonly mapper: ValidationResultContractMapper;
28
-
29
- constructor(deps: RunL0ValidatorsUseCaseDeps) {
30
- this.registry = deps.validatorRegistry;
31
- this.executionService = deps.validatorExecutionService;
32
- this.configPort = deps.validatorConfigPort;
33
- this.mapper = deps.contractMapper;
34
- }
35
-
36
- async execute(input: RunL0ValidatorsInput): Promise<readonly ValidationResultContract[]> {
37
- let validatorIds: readonly ValidatorId[];
38
- if (input.validatorIds && input.validatorIds.length > 0) {
39
- validatorIds = input.validatorIds.map((id) => ValidatorId.create(id));
40
- } else {
41
- validatorIds = this.registry.listByLayer('L0').map((d) => d.validatorId);
42
- }
43
-
44
- const definitions = this.registry.select(validatorIds);
45
-
46
- const layerConfig = await this.configPort.getLayerConfig('L0');
47
- if (!layerConfig.enabled) {
48
- return [];
49
- }
50
-
51
- const results = this.executionService.execute(definitions, [layerConfig]);
52
- const finalResults = definitions.map(
53
- (definition) => {
54
- const result = results.find((r) => r.validatorId.value === definition.validatorId.value);
55
- return result ?? ValidationResult.skip(definition.validatorId);
56
- },
57
- );
58
- return this.mapper.toContracts(finalResults);
59
- }
60
- }