phasegate 0.134.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 (28) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/bin/phasegate +2 -0
  3. package/docs/contracts/lesson-artifact.schema.json +62 -0
  4. package/docs/contracts/requirement-test-matrix.schema.json +62 -0
  5. package/docs/guide/layer-model.md +2 -2
  6. package/docs/principles/architecture-philosophy.md +26 -55
  7. package/docs/principles/model-routing.md +30 -165
  8. package/docs/principles/testing-rules.md +66 -648
  9. package/package.json +4 -3
  10. package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +2 -2
  11. package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +1 -1
  12. package/scripts/harness/config-foundation/infrastructure/presets/standard.json +1 -1
  13. package/scripts/harness/config-foundation/infrastructure/presets/strict.json +1 -1
  14. package/scripts/harness/harness-error/infrastructure/adapters/validator-registry-bridge-adapter.ts +2 -0
  15. package/scripts/harness/harness-error/infrastructure/registry/l4-error-definitions.ts +14 -0
  16. package/scripts/harness/phase2-extensions/composition-root.ts +7 -1
  17. package/scripts/harness/phase2-extensions/infrastructure/adapters/file-system-document-scanner-adapter.ts +16 -2
  18. package/scripts/harness/phase2-extensions/infrastructure/adapters/harness-config-freshness-adapter.ts +13 -2
  19. package/scripts/harness/phase2-extensions/infrastructure/adapters/regex-pointer-extractor-adapter.ts +35 -4
  20. package/scripts/harness/quick-mode/infrastructure/adapters/validator-system-validator-id-registry-adapter.ts +1 -1
  21. package/scripts/harness/skill-quality/infrastructure/adapters/validator-id-registry-bridge-adapter.ts +1 -1
  22. package/scripts/harness/validator-system/application/dto/run-l4-validators-input.ts +1 -0
  23. package/scripts/harness/validator-system/application/use-cases/run-full-validation-usecase.ts +1 -0
  24. package/scripts/harness/validator-system/application/use-cases/run-l4-validators-usecase.ts +133 -3
  25. package/scripts/harness/validator-system/composition-root.ts +8 -2
  26. package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +11 -4
  27. package/scripts/harness/validator-system/infrastructure/adapters/biome-ast-source-code-analyzer-adapter.ts +29 -10
  28. package/scripts/harness/validator-system/infrastructure/adapters/harness-config-validator-config-adapter.ts +11 -2
@@ -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,6 +6,7 @@
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 {
@@ -39,7 +40,7 @@ export class HarnessConfigValidatorConfigAdapter implements ValidatorConfigPort
39
40
  const defaultValidators: Record<string, string[]> = {
40
41
  L2: ['L2-001', 'L2-002', 'L2-003'],
41
42
  L3: ['L3-001', 'L3-002', 'L3-003', 'L3-004'],
42
- L4: ['L4-001', 'L4-002', 'L4-003'],
43
+ L4: ['L4-001', 'L4-002', 'L4-003', 'L4-004', 'L4-005'],
43
44
  };
44
45
 
45
46
  const thresholds: Record<string, number> = {};
@@ -62,10 +63,18 @@ export class HarnessConfigValidatorConfigAdapter implements ValidatorConfigPort
62
63
  return LayerConfig.create({
63
64
  layer,
64
65
  enabled: layerData.enabled !== false,
65
- validatorIds: layerData.validators ?? defaultValidators[layer],
66
+ validatorIds: (layerData.validators ?? defaultValidators[layer]).map((idOrName) => this.normalizeValidatorId(idOrName)),
66
67
  thresholds,
67
68
  strictOnly: layerData.strictOnly ?? strictOnly,
68
69
  preset,
69
70
  });
70
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
+ }
71
80
  }