phasegate 0.165.0 → 0.171.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.
- package/CHANGELOG.md +63 -0
- package/docs/ADR/021-severity-contract.md +46 -0
- package/docs/contracts/requirement-test-matrix.schema.json +5 -0
- package/package.json +1 -1
- package/scripts/harness/attestation/application/dto/attestation-document.ts +2 -0
- package/scripts/harness/attestation/application/dto/verify-attestation-output.ts +2 -0
- package/scripts/harness/attestation/application/mappers/attestation-record-mapper.ts +13 -0
- package/scripts/harness/attestation/application/ports/ac-bound-allowlist-port.ts +12 -0
- package/scripts/harness/attestation/application/ports/matrix-source-port.ts +16 -0
- package/scripts/harness/attestation/application/usecases/produce-attestation-usecase.ts +39 -0
- package/scripts/harness/attestation/application/usecases/verify-attestation-usecase.ts +60 -1
- package/scripts/harness/attestation/composition-root.ts +14 -0
- package/scripts/harness/attestation/domain/entities/attestation-record.ts +13 -0
- package/scripts/harness/attestation/domain/services/ac-bound-scope-service.ts +80 -0
- package/scripts/harness/attestation/infrastructure/adapters/config-ac-bound-allowlist-adapter.ts +23 -0
- package/scripts/harness/attestation/infrastructure/adapters/file-system-matrix-source-adapter.ts +25 -0
- package/scripts/harness/attestation/presentation/handlers/verify-attestation-handler.ts +1 -0
- package/scripts/harness/ci-governance/infrastructure/adapters/validator-id-registry-adapter.ts +8 -0
- package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +3 -0
- package/scripts/harness/config-foundation/domain/harness-config.ts +1 -0
- package/scripts/harness/config-foundation/domain/value-objects/l3-config.ts +4 -0
- package/scripts/harness/config-foundation/domain/value-objects/layers-config.ts +1 -1
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +7 -0
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +7 -0
- package/scripts/harness/harness-error/domain/errors/severity-downgrade-violation-error.ts +1 -1
- package/scripts/harness/main.ts +2 -2
- package/scripts/harness/nyquist-validation/application/dto/generate-matrix-output.ts +42 -0
- package/scripts/harness/nyquist-validation/application/mappers/coverage-result-mapper.ts +13 -15
- package/scripts/harness/nyquist-validation/application/mappers/impact-analysis-result-mapper.ts +12 -12
- package/scripts/harness/nyquist-validation/application/usecases/analyze-impact-usecase.ts +11 -11
- package/scripts/harness/nyquist-validation/application/usecases/calculate-coverage-usecase.ts +11 -11
- package/scripts/harness/nyquist-validation/application/usecases/check-ac-coverage-gate-usecase.ts +9 -9
- package/scripts/harness/nyquist-validation/application/usecases/generate-requirement-test-matrix-usecase.ts +62 -7
- package/scripts/harness/nyquist-validation/domain/aggregates/requirement-test-matrix.ts +1 -1
- package/scripts/harness/nyquist-validation/domain/entities/story-mapping.ts +1 -1
- package/scripts/harness/nyquist-validation/domain/services/ac-coverage-gate-policy.ts +1 -1
- package/scripts/harness/nyquist-validation/domain/services/coverage-calculation-service.ts +1 -1
- package/scripts/harness/nyquist-validation/domain/services/impact-analysis-service.ts +2 -2
- package/scripts/harness/nyquist-validation/domain/services/matrix-validation-service.ts +5 -5
- package/scripts/harness/nyquist-validation/domain/value-objects/impact-analysis-result.ts +1 -1
- package/scripts/harness/nyquist-validation/infrastructure/adapters/ajv-json-schema-validator-adapter.ts +3 -3
- package/scripts/harness/nyquist-validation/infrastructure/adapters/config-foundation-coverage-threshold-adapter.ts +3 -3
- package/scripts/harness/nyquist-validation/infrastructure/adapters/type-script-test-reference-source-adapter.ts +110 -8
- package/scripts/harness/nyquist-validation/infrastructure/schema/matrix-schema-loader.ts +5 -0
- package/scripts/harness/validator-system/application/dto/run-l3-validators-input.ts +2 -0
- package/scripts/harness/validator-system/application/use-cases/run-l1-validators-usecase.ts +1 -1
- package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +3 -3
- package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +33 -3
- package/scripts/harness/validator-system/application/use-cases/run-l4-validators-usecase.ts +26 -3
- package/scripts/harness/validator-system/application/use-cases/run-quick-mode-usecase.ts +3 -3
- package/scripts/harness/validator-system/composition-root.ts +22 -0
- package/scripts/harness/validator-system/domain/ports/ac-bound-coverage-policy-port.ts +22 -0
- package/scripts/harness/validator-system/domain/ports/ac-level-traceability-port.ts +14 -0
- package/scripts/harness/validator-system/domain/services/l4/ac-level-traceability-service.ts +102 -0
- package/scripts/harness/validator-system/domain/services/validator-execution-service.ts +1 -1
- package/scripts/harness/validator-system/domain/services/validator-registry.ts +2 -2
- package/scripts/harness/validator-system/domain/value-objects/layer-config.ts +1 -1
- package/scripts/harness/validator-system/domain/value-objects/validation-result.ts +1 -1
- package/scripts/harness/validator-system/domain/value-objects/validator-definition.ts +2 -2
- package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +5 -0
- package/scripts/harness/validator-system/infrastructure/adapters/json-coverage-report-adapter.ts +1 -1
- package/scripts/harness/validator-system/infrastructure/adapters/nyquist-ac-bound-coverage-policy-adapter.ts +118 -0
- package/scripts/harness/validator-system/infrastructure/adapters/nyquist-ac-level-traceability-adapter.ts +104 -0
- package/scripts/harness/validator-system/presentation/handlers/report-validation-results-handler.ts +4 -4
|
@@ -35,15 +35,15 @@ function extractStoryMappings(rawData: unknown): RawStoryMappingEntry[] {
|
|
|
35
35
|
if (rawData === null || typeof rawData !== 'object') return [];
|
|
36
36
|
const obj = rawData as Record<string, unknown>;
|
|
37
37
|
|
|
38
|
-
const source = Array.isArray(obj
|
|
39
|
-
? (obj
|
|
40
|
-
: Array.isArray(obj
|
|
41
|
-
? (obj
|
|
38
|
+
const source = Array.isArray(obj.stories)
|
|
39
|
+
? (obj.stories as unknown[])
|
|
40
|
+
: Array.isArray(obj.storyMappings)
|
|
41
|
+
? (obj.storyMappings as unknown[])
|
|
42
42
|
: [];
|
|
43
43
|
|
|
44
44
|
return source.map((item) => {
|
|
45
45
|
const entry = item as Record<string, unknown>;
|
|
46
|
-
return { storyId: String(entry
|
|
46
|
+
return { storyId: String(entry.storyId ?? '') };
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -15,13 +15,13 @@ function convertAjvError(err: ErrorObject): NyquistHarnessError {
|
|
|
15
15
|
|
|
16
16
|
switch (err.keyword) {
|
|
17
17
|
case 'required':
|
|
18
|
-
message = `${err.instancePath || '(root)'} に必須フィールド '${String(err.params
|
|
18
|
+
message = `${err.instancePath || '(root)'} に必須フィールド '${String(err.params.missingProperty ?? '')}' がありません`;
|
|
19
19
|
break;
|
|
20
20
|
case 'type':
|
|
21
|
-
message = `${err.instancePath} の型が不正です。期待: ${String(err.params
|
|
21
|
+
message = `${err.instancePath} の型が不正です。期待: ${String(err.params.type ?? '')}`;
|
|
22
22
|
break;
|
|
23
23
|
case 'pattern':
|
|
24
|
-
message = `${err.instancePath} の値が形式 '${String(err.params
|
|
24
|
+
message = `${err.instancePath} の値が形式 '${String(err.params.pattern ?? '')}' に一致しません`;
|
|
25
25
|
break;
|
|
26
26
|
case 'enum':
|
|
27
27
|
message = `${err.instancePath} の値は許容値のいずれでもありません`;
|
|
@@ -35,10 +35,10 @@ export class ConfigFoundationCoverageThresholdAdapter implements CoverageThresho
|
|
|
35
35
|
preset = 'standard';
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const active = THRESHOLDS[preset] ?? THRESHOLDS
|
|
38
|
+
const active = THRESHOLDS[preset] ?? THRESHOLDS.standard;
|
|
39
39
|
return {
|
|
40
|
-
standard: THRESHOLDS
|
|
41
|
-
strict: THRESHOLDS
|
|
40
|
+
standard: THRESHOLDS.standard ?? 0.90,
|
|
41
|
+
strict: THRESHOLDS.strict ?? 0.95,
|
|
42
42
|
active: active ?? 0.90,
|
|
43
43
|
};
|
|
44
44
|
}
|
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
// @layer infrastructure
|
|
2
2
|
// @unit nyquist-validation
|
|
3
3
|
// @work-item-id WI-125
|
|
4
|
+
// @work-item-id WI-222
|
|
4
5
|
|
|
5
6
|
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
6
7
|
import path from 'node:path';
|
|
7
8
|
import type { TestReferenceSourcePort } from '../../application/usecases/generate-requirement-test-matrix-usecase.js';
|
|
8
|
-
import type { TestReferenceSourceDto } from '../../application/dto/generate-matrix-output.js';
|
|
9
|
+
import type { OrphanAcTagDto, TestReferenceSourceDto } from '../../application/dto/generate-matrix-output.js';
|
|
9
10
|
|
|
10
11
|
// StoryId は HXX-XX 形式に加え Phase 2 拡張 Epic の HF\d+-XX 形式も許容する
|
|
11
12
|
// (markdown-requirement-source-adapter の STORY_HEADING / traceability-model の StoryId 正規表現と整合)。
|
|
12
13
|
// 旧 /H\d{2}-\d{2}/ は HF2-01 等を取りこぼし、正しく注釈されたテストが「テストなし」と誤判定されていた。
|
|
13
14
|
const STORY_TAG = /@story(?:-id)?\s+(H(?:F\d+|\d{2})-\d{2})/;
|
|
14
|
-
const
|
|
15
|
+
const STORY_TAG_GLOBAL = /@story(?:-id)?\s+(H(?:F\d+|\d{2})-\d{2})/g;
|
|
16
|
+
// HF2-05: @ac は 1 行に複数 AC を許容する。行末までの全トークンを個別に解釈する。
|
|
17
|
+
// 各トークンは絶対形式 `HXX-YY-N`(story-relative でない)または相対形式 `AC-N`。
|
|
18
|
+
const AC_TAG_LINE = /@ac\s+(.+?)\s*$/;
|
|
19
|
+
const AC_ABSOLUTE_TOKEN = /^(H(?:F\d+|\d{2})-\d{2})-([1-9][0-9]*)$/;
|
|
20
|
+
const AC_RELATIVE_TOKEN = /^AC-([1-9][0-9]*)$/;
|
|
21
|
+
// テストケース開始行の検出(it / test、.each やスペースを許容)。
|
|
22
|
+
const TEST_START = /\b(?:it|test)(?:\.each\([^)]*\))?\s*\(\s*['"`]([^'"`]+)['"`]/;
|
|
23
|
+
|
|
24
|
+
interface PendingAcToken {
|
|
25
|
+
readonly rawTag: string;
|
|
26
|
+
readonly resolvedAcId: string | null;
|
|
27
|
+
readonly reason: OrphanAcTagDto['reason'] | null;
|
|
28
|
+
}
|
|
15
29
|
|
|
16
30
|
async function collectTestFiles(root: string): Promise<readonly string[]> {
|
|
17
31
|
const rootStat = await stat(root).catch(() => null);
|
|
@@ -43,15 +57,103 @@ export class TypeScriptTestReferenceSourceAdapter implements TestReferenceSource
|
|
|
43
57
|
const storyId = storyMatch[1];
|
|
44
58
|
const relativePath = path.relative(process.cwd(), filePath).replaceAll(path.sep, '/');
|
|
45
59
|
const testType = classifyTestType(relativePath);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
// HF2-05: 相対 @ac (AC-N) はファイルに @story がちょうど 1 件のときのみ解決する。
|
|
61
|
+
const storyCount = [...content.matchAll(STORY_TAG_GLOBAL)].length;
|
|
62
|
+
references.push(...this.scanFile({ content, storyId, relativePath, testType, storyCount }));
|
|
63
|
+
}
|
|
64
|
+
return Object.freeze(references);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* HF2-05: ファイル内容を行単位で走査し、直前の it()/test() 以降に現れた @ac を
|
|
69
|
+
* 「最近接の @ac」として次のテストケースへ紐づける(positional scan)。
|
|
70
|
+
* @ac が無いテストは従来どおり acIds 無しの参照を生成する。
|
|
71
|
+
*/
|
|
72
|
+
private scanFile(args: {
|
|
73
|
+
content: string;
|
|
74
|
+
storyId: string;
|
|
75
|
+
relativePath: string;
|
|
76
|
+
testType: 'unit' | 'it' | 'scenario';
|
|
77
|
+
storyCount: number;
|
|
78
|
+
}): TestReferenceSourceDto[] {
|
|
79
|
+
const { content, storyId, relativePath, testType, storyCount } = args;
|
|
80
|
+
const lines = content.split('\n');
|
|
81
|
+
const result: TestReferenceSourceDto[] = [];
|
|
82
|
+
let pending: PendingAcToken[] = [];
|
|
83
|
+
|
|
84
|
+
for (const line of lines) {
|
|
85
|
+
const acMatch = line.match(AC_TAG_LINE);
|
|
86
|
+
if (acMatch) {
|
|
87
|
+
for (const token of acMatch[1].trim().split(/\s+/)) {
|
|
88
|
+
if (token.length > 0) pending.push(this.resolveAcToken(token, storyId, storyCount));
|
|
89
|
+
}
|
|
49
90
|
continue;
|
|
50
91
|
}
|
|
51
|
-
|
|
52
|
-
|
|
92
|
+
const testMatch = line.match(TEST_START);
|
|
93
|
+
if (testMatch) {
|
|
94
|
+
result.push(this.buildReference({
|
|
95
|
+
storyId,
|
|
96
|
+
relativePath,
|
|
97
|
+
testType,
|
|
98
|
+
testName: testMatch[1],
|
|
99
|
+
pending,
|
|
100
|
+
}));
|
|
101
|
+
pending = [];
|
|
53
102
|
}
|
|
54
103
|
}
|
|
55
|
-
|
|
104
|
+
|
|
105
|
+
// it()/test() が 1 件も無い注釈済みファイルは、file-level 参照 1 件を維持する(従来挙動)。
|
|
106
|
+
if (result.length === 0) {
|
|
107
|
+
result.push({ storyId, filePath: relativePath, testType });
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private buildReference(args: {
|
|
113
|
+
storyId: string;
|
|
114
|
+
relativePath: string;
|
|
115
|
+
testType: 'unit' | 'it' | 'scenario';
|
|
116
|
+
testName: string;
|
|
117
|
+
pending: readonly PendingAcToken[];
|
|
118
|
+
}): TestReferenceSourceDto {
|
|
119
|
+
const { storyId, relativePath, testType, testName, pending } = args;
|
|
120
|
+
const base: TestReferenceSourceDto = { storyId, filePath: relativePath, testType, testName };
|
|
121
|
+
if (pending.length === 0) return base;
|
|
122
|
+
|
|
123
|
+
const acIds = pending.filter((p) => p.resolvedAcId !== null).map((p) => p.resolvedAcId as string);
|
|
124
|
+
const orphanAcTags: OrphanAcTagDto[] = pending
|
|
125
|
+
.filter((p) => p.resolvedAcId === null && p.reason !== null)
|
|
126
|
+
.map((p) => ({ storyId, filePath: relativePath, testName, rawTag: p.rawTag, reason: p.reason as OrphanAcTagDto['reason'] }));
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
...base,
|
|
130
|
+
...(acIds.length > 0 ? { acIds: Object.freeze([...new Set(acIds)]) } : {}),
|
|
131
|
+
...(orphanAcTags.length > 0 ? { orphanAcTags: Object.freeze(orphanAcTags) } : {}),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* 1 個の @ac トークンを解釈する。
|
|
137
|
+
* - 絶対形式 `HXX-YY-N`: story が一致すれば `AC-N` に解決、不一致なら ac-not-in-story orphan。
|
|
138
|
+
* - 相対形式 `AC-N`: @story が単一なら `AC-N` に解決、複数なら relative-multi-story orphan。
|
|
139
|
+
*/
|
|
140
|
+
private resolveAcToken(token: string, storyId: string, storyCount: number): PendingAcToken {
|
|
141
|
+
const absolute = token.match(AC_ABSOLUTE_TOKEN);
|
|
142
|
+
if (absolute) {
|
|
143
|
+
const [, tokenStory, acNumber] = absolute;
|
|
144
|
+
if (tokenStory === storyId) {
|
|
145
|
+
return { rawTag: token, resolvedAcId: `AC-${acNumber}`, reason: null };
|
|
146
|
+
}
|
|
147
|
+
return { rawTag: token, resolvedAcId: null, reason: 'ac-not-in-story' };
|
|
148
|
+
}
|
|
149
|
+
const relative = token.match(AC_RELATIVE_TOKEN);
|
|
150
|
+
if (relative) {
|
|
151
|
+
if (storyCount === 1) {
|
|
152
|
+
return { rawTag: token, resolvedAcId: `AC-${relative[1]}`, reason: null };
|
|
153
|
+
}
|
|
154
|
+
return { rawTag: token, resolvedAcId: null, reason: 'relative-multi-story' };
|
|
155
|
+
}
|
|
156
|
+
// 形式不明トークンは advisory orphan として ac-not-in-story 扱い。
|
|
157
|
+
return { rawTag: token, resolvedAcId: null, reason: 'ac-not-in-story' };
|
|
56
158
|
}
|
|
57
159
|
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @layer infrastructure
|
|
3
3
|
* @unit nyquist-validation
|
|
4
|
+
* @work-item-id WI-222
|
|
4
5
|
*
|
|
5
6
|
* requirement-test-matrix.schema.json ローダー(シングルトンキャッシュ付き)
|
|
7
|
+
*
|
|
8
|
+
* HF2-05 (schema 1.1): testReferences に optional な `binding` enum("ac"|"file")を追加。
|
|
9
|
+
* 1.1 は追加フィールドが optional かつ additionalProperties:false を満たすため、
|
|
10
|
+
* `binding` を持たない 1.0 マトリクスも引き続き検証を通過する(後方互換)。
|
|
6
11
|
*/
|
|
7
12
|
import { readFile } from 'node:fs/promises';
|
|
8
13
|
import { resolve, join } from 'node:path';
|
|
@@ -9,4 +9,6 @@ export interface RunL3ValidatorsInput {
|
|
|
9
9
|
readonly targetPaths: readonly string[];
|
|
10
10
|
readonly coverageReportPath?: string;
|
|
11
11
|
readonly requirementMatrixPath?: string;
|
|
12
|
+
/** L3-005(AC-bound coverage)のスコープ対象 story-id 配列。省略時 []。 */
|
|
13
|
+
readonly acBoundStories?: readonly string[];
|
|
12
14
|
}
|
|
@@ -10,7 +10,7 @@ import { ValidatorId } from '../../domain/value-objects/validator-id.js';
|
|
|
10
10
|
import { ValidationResult } from '../../domain/value-objects/validation-result.js';
|
|
11
11
|
import { ItTestMockDetectionService } from '../../domain/services/it-test-mock-detection-service.js';
|
|
12
12
|
import { StubCommentDetectionService } from '../../domain/services/stub-comment-detection-service.js';
|
|
13
|
-
import { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
13
|
+
import type { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
14
14
|
import type { ValidationResultContract } from '../dto/validation-result-contract.js';
|
|
15
15
|
import type { RunL1ValidatorsInput } from '../dto/run-l1-validators-input.js';
|
|
16
16
|
import type { ItTestFileAnalyzerPort } from '../../domain/ports/it-test-file-analyzer-port.js';
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
9
|
import { ValidatorId, InvalidValidatorIdError } from '../../domain/value-objects/validator-id.js';
|
|
10
10
|
import { ValidationResult, type HarnessErrorLike } from '../../domain/value-objects/validation-result.js';
|
|
11
|
-
import { ValidatorRegistry } from '../../domain/services/validator-registry.js';
|
|
12
|
-
import { ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
|
|
13
|
-
import { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
11
|
+
import type { ValidatorRegistry } from '../../domain/services/validator-registry.js';
|
|
12
|
+
import { type ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
|
|
13
|
+
import type { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
14
14
|
import type { ValidationResultContract } from '../dto/validation-result-contract.js';
|
|
15
15
|
import type { RunL2ValidatorsInput } from '../dto/run-l2-validators-input.js';
|
|
16
16
|
import type { ValidatorConfigPort } from '../../domain/ports/validator-config-port.js';
|
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { ValidatorId } from '../../domain/value-objects/validator-id.js';
|
|
9
9
|
import { ValidationResult } from '../../domain/value-objects/validation-result.js';
|
|
10
|
-
import { ValidatorRegistry } from '../../domain/services/validator-registry.js';
|
|
11
|
-
import { ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
|
|
10
|
+
import type { ValidatorRegistry } from '../../domain/services/validator-registry.js';
|
|
11
|
+
import { type ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
|
|
12
12
|
import { ValidatorLanguageCapabilityService } from '../../domain/services/validator-language-capability-service.js';
|
|
13
|
-
import { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
13
|
+
import type { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
14
14
|
import type { ValidationResultContract } from '../dto/validation-result-contract.js';
|
|
15
15
|
import type { RunL3ValidatorsInput } from '../dto/run-l3-validators-input.js';
|
|
16
16
|
import type { ValidatorConfigPort } from '../../domain/ports/validator-config-port.js';
|
|
17
17
|
import type { AcCoveragePolicyPort } from '../../domain/ports/ac-coverage-policy-port.js';
|
|
18
|
+
import type { AcBoundCoveragePolicyPort } from '../../domain/ports/ac-bound-coverage-policy-port.js';
|
|
18
19
|
import type { SecurityPatternScannerPort } from '../../domain/ports/security-pattern-scanner-port.js';
|
|
19
20
|
import type { PerformanceScannerPort } from '../../domain/ports/performance-scanner-port.js';
|
|
20
21
|
|
|
@@ -31,9 +32,12 @@ export interface RunL3ValidatorsUseCaseDeps {
|
|
|
31
32
|
validatorConfigPort: ValidatorConfigPort;
|
|
32
33
|
contractMapper: ValidationResultContractMapper;
|
|
33
34
|
acCoveragePolicyPort?: AcCoveragePolicyPort;
|
|
35
|
+
acBoundCoveragePolicyPort?: AcBoundCoveragePolicyPort;
|
|
34
36
|
coverageReportPort?: { getCoverage(): Promise<{ overallCoverage: number; perFileCoverage: readonly { filePath: string; coverage: number }[] }> };
|
|
35
37
|
securityScannerPort?: SecurityPatternScannerPort;
|
|
36
38
|
performanceScannerPort?: PerformanceScannerPort;
|
|
39
|
+
/** L3-005 のスコープ対象 story-id(config layers.L3.acBoundStories 由来。既定 [])。 */
|
|
40
|
+
acBoundStories?: readonly string[];
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
export class RunL3ValidatorsUseCase {
|
|
@@ -42,9 +46,11 @@ export class RunL3ValidatorsUseCase {
|
|
|
42
46
|
private readonly configPort: ValidatorConfigPort;
|
|
43
47
|
private readonly mapper: ValidationResultContractMapper;
|
|
44
48
|
private readonly acCoveragePolicyPort?: AcCoveragePolicyPort;
|
|
49
|
+
private readonly acBoundCoveragePolicyPort?: AcBoundCoveragePolicyPort;
|
|
45
50
|
private readonly coverageReportPort?: RunL3ValidatorsUseCaseDeps['coverageReportPort'];
|
|
46
51
|
private readonly securityScannerPort?: SecurityPatternScannerPort;
|
|
47
52
|
private readonly performanceScannerPort?: PerformanceScannerPort;
|
|
53
|
+
private readonly acBoundStories: readonly string[];
|
|
48
54
|
private readonly languageCapabilityService = new ValidatorLanguageCapabilityService();
|
|
49
55
|
|
|
50
56
|
constructor(deps: RunL3ValidatorsUseCaseDeps) {
|
|
@@ -53,9 +59,11 @@ export class RunL3ValidatorsUseCase {
|
|
|
53
59
|
this.configPort = deps.validatorConfigPort;
|
|
54
60
|
this.mapper = deps.contractMapper;
|
|
55
61
|
this.acCoveragePolicyPort = deps.acCoveragePolicyPort;
|
|
62
|
+
this.acBoundCoveragePolicyPort = deps.acBoundCoveragePolicyPort;
|
|
56
63
|
this.coverageReportPort = deps.coverageReportPort;
|
|
57
64
|
this.securityScannerPort = deps.securityScannerPort;
|
|
58
65
|
this.performanceScannerPort = deps.performanceScannerPort;
|
|
66
|
+
this.acBoundStories = deps.acBoundStories ?? [];
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
async execute(input: RunL3ValidatorsInput): Promise<readonly ValidationResultContract[]> {
|
|
@@ -195,6 +203,28 @@ export class RunL3ValidatorsUseCase {
|
|
|
195
203
|
}
|
|
196
204
|
}
|
|
197
205
|
|
|
206
|
+
// L3-005: AC-bound coverage(fail-closed, default-OFF)。
|
|
207
|
+
// override map に unskipped な L3-005 がある場合のみ policy を呼ぶ(L3-004 と同じ方式)。
|
|
208
|
+
if (this.acBoundCoveragePolicyPort) {
|
|
209
|
+
const l3005Result = overrideMap.get('L3-005');
|
|
210
|
+
if (l3005Result && !l3005Result.skipped) {
|
|
211
|
+
const policyResult = await this.acBoundCoveragePolicyPort.checkAcBoundCoverage({
|
|
212
|
+
matrixFilePath: input.requirementMatrixPath,
|
|
213
|
+
acBoundStories: input.acBoundStories ?? this.acBoundStories,
|
|
214
|
+
});
|
|
215
|
+
if (!policyResult.passed) {
|
|
216
|
+
overrideMap.set(
|
|
217
|
+
'L3-005',
|
|
218
|
+
ValidationResult.fail(
|
|
219
|
+
ValidatorId.create('L3-005'),
|
|
220
|
+
[...policyResult.errors],
|
|
221
|
+
0,
|
|
222
|
+
),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
198
228
|
const finalResults = definitions.map(
|
|
199
229
|
(definition) => overrideMap.get(definition.validatorId.value) ?? ValidationResult.skip(definition.validatorId),
|
|
200
230
|
);
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
import { ValidatorId } from '../../domain/value-objects/validator-id.js';
|
|
11
11
|
import { ValidationResult } from '../../domain/value-objects/validation-result.js';
|
|
12
12
|
import { LayerConfig } from '../../domain/value-objects/layer-config.js';
|
|
13
|
-
import { ValidatorRegistry } from '../../domain/services/validator-registry.js';
|
|
14
|
-
import { ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
|
|
13
|
+
import type { ValidatorRegistry } from '../../domain/services/validator-registry.js';
|
|
14
|
+
import { type ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
|
|
15
15
|
import { ValidatorLanguageCapabilityService } from '../../domain/services/validator-language-capability-service.js';
|
|
16
|
-
import { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
16
|
+
import type { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
17
17
|
import type { ValidationResultContract } from '../dto/validation-result-contract.js';
|
|
18
18
|
import type { RunL4ValidatorsInput } from '../dto/run-l4-validators-input.js';
|
|
19
19
|
import type { ValidatorConfigPort } from '../../domain/ports/validator-config-port.js';
|
|
@@ -23,6 +23,8 @@ import type { DeadCodeDetectionService } from '../../domain/services/l4/dead-cod
|
|
|
23
23
|
import type { ArchitectureSemanticAnalysisService } from '../../domain/services/l4/architecture-semantic-analysis-service.js';
|
|
24
24
|
import { SkillCatalogDriftService } from '../../domain/services/l4/skill-catalog-drift-service.js';
|
|
25
25
|
import type { SkillCatalogDriftPort } from '../../domain/ports/skill-catalog-drift-port.js';
|
|
26
|
+
import { AcLevelTraceabilityService } from '../../domain/services/l4/ac-level-traceability-service.js';
|
|
27
|
+
import type { AcLevelTraceabilityPort } from '../../domain/ports/ac-level-traceability-port.js';
|
|
26
28
|
|
|
27
29
|
interface ScheduledHarnessErrorContract {
|
|
28
30
|
readonly severity: string;
|
|
@@ -73,6 +75,7 @@ export interface RunL4ValidatorsUseCaseDeps {
|
|
|
73
75
|
deadCodeDetectionService?: DeadCodeDetectionService;
|
|
74
76
|
architectureSemanticAnalysisService?: ArchitectureSemanticAnalysisService;
|
|
75
77
|
skillCatalogDriftPort?: SkillCatalogDriftPort;
|
|
78
|
+
acLevelTraceabilityPort?: AcLevelTraceabilityPort;
|
|
76
79
|
pathRoots?: {
|
|
77
80
|
readonly inceptionRoot: string;
|
|
78
81
|
readonly designRoot: string;
|
|
@@ -92,6 +95,8 @@ export class RunL4ValidatorsUseCase {
|
|
|
92
95
|
private readonly architectureSemanticAnalysisService?: ArchitectureSemanticAnalysisService;
|
|
93
96
|
private readonly skillCatalogDriftPort?: SkillCatalogDriftPort;
|
|
94
97
|
private readonly skillCatalogDriftService = new SkillCatalogDriftService();
|
|
98
|
+
private readonly acLevelTraceabilityPort?: AcLevelTraceabilityPort;
|
|
99
|
+
private readonly acLevelTraceabilityService = new AcLevelTraceabilityService();
|
|
95
100
|
private readonly pathRoots: { readonly inceptionRoot: string; readonly designRoot: string };
|
|
96
101
|
private readonly checkDocFreshnessUseCase?: CheckDocFreshnessUseCasePort;
|
|
97
102
|
private readonly validateDocPointersUseCase?: ValidateDocPointersUseCasePort;
|
|
@@ -107,6 +112,7 @@ export class RunL4ValidatorsUseCase {
|
|
|
107
112
|
this.deadCodeDetectionService = deps.deadCodeDetectionService;
|
|
108
113
|
this.architectureSemanticAnalysisService = deps.architectureSemanticAnalysisService;
|
|
109
114
|
this.skillCatalogDriftPort = deps.skillCatalogDriftPort;
|
|
115
|
+
this.acLevelTraceabilityPort = deps.acLevelTraceabilityPort;
|
|
110
116
|
this.pathRoots = deps.pathRoots ?? {
|
|
111
117
|
inceptionRoot: 'docs/inception',
|
|
112
118
|
designRoot: 'docs/product/construction',
|
|
@@ -263,6 +269,23 @@ export class RunL4ValidatorsUseCase {
|
|
|
263
269
|
}
|
|
264
270
|
}
|
|
265
271
|
|
|
272
|
+
if (this.acLevelTraceabilityPort) {
|
|
273
|
+
const l4007Result = overrideMap.get('L4-007');
|
|
274
|
+
// default-OFF: L4-007 が enabled validator set に含まれず skip される場合は上書きしない。
|
|
275
|
+
if (l4007Result && !l4007Result.skipped) {
|
|
276
|
+
const snapshot = await this.acLevelTraceabilityPort.collect();
|
|
277
|
+
const report = this.acLevelTraceabilityService.check(snapshot);
|
|
278
|
+
// advisory-only: finding があっても severity は必ず warning。overall gate は
|
|
279
|
+
// failOnWarning=false(既定)で PASS のまま(ADR-019 §5)。finding が無ければ PASS。
|
|
280
|
+
overrideMap.set(
|
|
281
|
+
'L4-007',
|
|
282
|
+
report.hasFindings()
|
|
283
|
+
? ValidationResult.fail(ValidatorId.create('L4-007'), report.toHarnessErrors(), 0)
|
|
284
|
+
: ValidationResult.pass(ValidatorId.create('L4-007'), 0),
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
266
289
|
const finalResults = definitions.map(
|
|
267
290
|
(definition) => overrideMap.get(definition.validatorId.value) ?? ValidationResult.skip(definition.validatorId),
|
|
268
291
|
);
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* RunQuickModeUseCase — H08-04: Quickモード緩和実行
|
|
6
6
|
*/
|
|
7
7
|
import { ValidatorId } from '../../domain/value-objects/validator-id.js';
|
|
8
|
-
import { ValidatorRegistry } from '../../domain/services/validator-registry.js';
|
|
9
|
-
import { ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
|
|
10
|
-
import { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
8
|
+
import type { ValidatorRegistry } from '../../domain/services/validator-registry.js';
|
|
9
|
+
import { type ValidatorExecutionService, ValidatorExecutionError } from '../../domain/services/validator-execution-service.js';
|
|
10
|
+
import type { ValidationResultContractMapper } from '../mappers/validation-result-contract-mapper.js';
|
|
11
11
|
import type { ValidationResultContract } from '../dto/validation-result-contract.js';
|
|
12
12
|
import type { RunQuickModeInput } from '../dto/run-quick-mode-input.js';
|
|
13
13
|
import type { ValidatorConfigPort } from '../../domain/ports/validator-config-port.js';
|
|
@@ -29,6 +29,7 @@ import { FileSystemContractTraceabilityPolicyAdapter } from './infrastructure/ad
|
|
|
29
29
|
import { PhaseDependencyPhaseGatePolicyAdapter } from './infrastructure/adapters/phase-dependency-phase-gate-policy-adapter.js';
|
|
30
30
|
import { TraceabilityMetadataPolicyAdapter } from './infrastructure/adapters/traceability-metadata-policy-adapter.js';
|
|
31
31
|
import { NyquistAcCoveragePolicyAdapter } from './infrastructure/adapters/nyquist-ac-coverage-policy-adapter.js';
|
|
32
|
+
import { NyquistAcBoundCoveragePolicyAdapter } from './infrastructure/adapters/nyquist-ac-bound-coverage-policy-adapter.js';
|
|
32
33
|
import { JsonCoverageReportAdapter } from './infrastructure/adapters/json-coverage-report-adapter.js';
|
|
33
34
|
import { BiomeAstTestQualityAnalyzerAdapter } from './infrastructure/adapters/biome-ast-test-quality-analyzer-adapter.js';
|
|
34
35
|
import { FileSystemSecurityPatternScannerAdapter } from './infrastructure/adapters/file-system-security-pattern-scanner-adapter.js';
|
|
@@ -39,6 +40,7 @@ import { AdrFoundationReferenceAdapter } from './infrastructure/adapters/adr-fou
|
|
|
39
40
|
import { ImportGraphSourceAnalysisAdapter } from './infrastructure/adapters/import-graph-source-analysis-adapter.js';
|
|
40
41
|
import { FileSystemArchitectureSemanticSourceAdapter } from './infrastructure/adapters/file-system-architecture-semantic-source-adapter.js';
|
|
41
42
|
import { FileSystemSkillCatalogDriftAdapter } from './infrastructure/adapters/file-system-skill-catalog-drift-adapter.js';
|
|
43
|
+
import { NyquistAcLevelTraceabilityAdapter } from './infrastructure/adapters/nyquist-ac-level-traceability-adapter.js';
|
|
42
44
|
import { FileSystemWorkItemReflectionAdapter } from './infrastructure/adapters/file-system-work-item-reflection-adapter.js';
|
|
43
45
|
import { DriftDetectionService } from './domain/services/l4/drift-detection-service.js';
|
|
44
46
|
import { ConsistencyCheckService } from './domain/services/l4/consistency-check-service.js';
|
|
@@ -111,12 +113,18 @@ export function buildDefaultRegistry(): ValidatorRegistry {
|
|
|
111
113
|
createDef('L3-002', 'L3', 'strictOnly'),
|
|
112
114
|
createDef('L3-003', 'L3', 'always'),
|
|
113
115
|
createDef('L3-004', 'L3', 'always', 'AcCoveragePolicyPort'),
|
|
116
|
+
// WI-227 / H16-03: L3-005 (ac-bound-coverage) は registry には登録するが
|
|
117
|
+
// default-OFF(DEFAULT_CONFIG.layers.L3.validators に含めない)。fail-closed / opt-in。
|
|
118
|
+
createDef('L3-005', 'L3', 'always', 'AcBoundCoveragePolicyPort'),
|
|
114
119
|
createDef('L4-001', 'L4', 'always'),
|
|
115
120
|
createDef('L4-002', 'L4', 'always'),
|
|
116
121
|
createDef('L4-003', 'L4', 'strictOnly'),
|
|
117
122
|
createDef('L4-004', 'L4', 'always'),
|
|
118
123
|
createDef('L4-005', 'L4', 'always'),
|
|
119
124
|
createDef('L4-006', 'L4', 'always', 'SkillCatalogDriftPort'),
|
|
125
|
+
// WI-222 / HF2-05: L4-007 (ac-level-traceability) は registry には登録するが
|
|
126
|
+
// default-OFF(DEFAULT_CONFIG.layers.L4.validators に含めない)。advisory-only。
|
|
127
|
+
createDef('L4-007', 'L4', 'always', 'AcLevelTraceabilityPort'),
|
|
120
128
|
];
|
|
121
129
|
|
|
122
130
|
return new ValidatorRegistry(definitions);
|
|
@@ -150,6 +158,8 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
150
158
|
const phaseGatePolicyPort = new PhaseDependencyPhaseGatePolicyAdapter();
|
|
151
159
|
const metadataPolicyPort = new TraceabilityMetadataPolicyAdapter();
|
|
152
160
|
const acCoveragePolicyPort = new NyquistAcCoveragePolicyAdapter();
|
|
161
|
+
// WI-227 / H16-03: L3-005 (ac-bound-coverage, fail-closed, default-OFF) 用の adapter。
|
|
162
|
+
const acBoundCoveragePolicyPort = new NyquistAcBoundCoveragePolicyAdapter();
|
|
153
163
|
// L3-003: テストカバレッジレポート(vitest --coverage の json-summary 出力)を読み取る。
|
|
154
164
|
// 未配線だと L3-003 は装飾的な pass になり 90% 閾値が形骸化するため必ず配線する。
|
|
155
165
|
const coverageReportPort = new JsonCoverageReportAdapter(
|
|
@@ -189,15 +199,21 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
189
199
|
contractTraceabilityPolicyPort,
|
|
190
200
|
});
|
|
191
201
|
|
|
202
|
+
// WI-227 / H16-03: L3-005 のスコープ対象 story-id を config から取得(既定 [])。
|
|
203
|
+
const acBoundStories =
|
|
204
|
+
(configData.layers?.L3 as { acBoundStories?: readonly string[] } | undefined)?.acBoundStories ?? [];
|
|
205
|
+
|
|
192
206
|
const runL3ValidatorsUseCase = new RunL3ValidatorsUseCase({
|
|
193
207
|
validatorRegistry: registry,
|
|
194
208
|
validatorExecutionService: executionService,
|
|
195
209
|
validatorConfigPort: configPort,
|
|
196
210
|
contractMapper,
|
|
197
211
|
acCoveragePolicyPort,
|
|
212
|
+
acBoundCoveragePolicyPort,
|
|
198
213
|
coverageReportPort,
|
|
199
214
|
securityScannerPort,
|
|
200
215
|
performanceScannerPort,
|
|
216
|
+
acBoundStories,
|
|
201
217
|
});
|
|
202
218
|
|
|
203
219
|
const markdownDesignDocumentPort = new MarkdownDesignDocumentAdapter(docsRoot);
|
|
@@ -206,6 +222,11 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
206
222
|
const sourceAnalysisPort = new ImportGraphSourceAnalysisAdapter();
|
|
207
223
|
const architectureSemanticSourcePort = new FileSystemArchitectureSemanticSourceAdapter();
|
|
208
224
|
const skillCatalogDriftPort = new FileSystemSkillCatalogDriftAdapter(cwd);
|
|
225
|
+
// WI-222 / HF2-05: L4-007 (advisory) 用の AC 単位トレーサビリティ port。
|
|
226
|
+
// matrix path は L3-004 と同じ config キーを参照する。
|
|
227
|
+
const acLevelTraceabilityPort = new NyquistAcLevelTraceabilityAdapter({
|
|
228
|
+
matrixFilePath: configData.layers?.L3?.requirementMatrixPath ?? '.harness/requirement-test-matrix.json',
|
|
229
|
+
});
|
|
209
230
|
const workItemReflectionPort = new FileSystemWorkItemReflectionAdapter(cwd);
|
|
210
231
|
|
|
211
232
|
const driftDetectionService = new DriftDetectionService({
|
|
@@ -236,6 +257,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
236
257
|
deadCodeDetectionService,
|
|
237
258
|
architectureSemanticAnalysisService,
|
|
238
259
|
skillCatalogDriftPort,
|
|
260
|
+
acLevelTraceabilityPort,
|
|
239
261
|
pathRoots: {
|
|
240
262
|
inceptionRoot: inceptionDocsRoot,
|
|
241
263
|
designRoot: designDocsRoot,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @layer domain
|
|
3
|
+
* @unit validator-system
|
|
4
|
+
* @work-item-id WI-227
|
|
5
|
+
*
|
|
6
|
+
* AcBoundCoveragePolicyPort — L3-005(AC-bound coverage, fail-closed, default-OFF)
|
|
7
|
+
*
|
|
8
|
+
* L3-004(story-level の AC 網羅ゲート)とは独立した per-AC binding ゲート。
|
|
9
|
+
* `acBoundStories`(スコープ)内の各 story について、全 linked AC が
|
|
10
|
+
* ≥1 の `binding:"ac"` テスト参照(fileFallbackOnly===0)を持つことを検査する。
|
|
11
|
+
*/
|
|
12
|
+
import type { HarnessErrorLike } from '../value-objects/validation-result.js';
|
|
13
|
+
|
|
14
|
+
export interface AcBoundCoveragePolicyPort {
|
|
15
|
+
checkAcBoundCoverage(context: {
|
|
16
|
+
matrixFilePath?: string;
|
|
17
|
+
acBoundStories: readonly string[];
|
|
18
|
+
}): Promise<{
|
|
19
|
+
passed: boolean;
|
|
20
|
+
errors: readonly HarnessErrorLike[];
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @layer domain
|
|
3
|
+
* @unit validator-system
|
|
4
|
+
* @work-item-id WI-222
|
|
5
|
+
*
|
|
6
|
+
* HF2-05 / L4-007: nyquist-validation のマトリクス生成レポートを AC 単位トレーサビリティの
|
|
7
|
+
* snapshot へ橋渡しする port。実装(infrastructure adapter)が nyquist の generate-matrix
|
|
8
|
+
* usecase を実行し、acLevelCoverage / fileFallbackOnlyAcs / orphanAcTags を収集する。
|
|
9
|
+
*/
|
|
10
|
+
import type { AcLevelTraceabilitySnapshot } from '../services/l4/ac-level-traceability-service.js';
|
|
11
|
+
|
|
12
|
+
export interface AcLevelTraceabilityPort {
|
|
13
|
+
collect(): Promise<AcLevelTraceabilitySnapshot>;
|
|
14
|
+
}
|