phasegate 0.167.0 → 0.172.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 +44 -0
- package/docs/ADR/021-severity-contract.md +46 -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/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/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/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/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 +3 -3
- package/scripts/harness/validator-system/application/use-cases/run-quick-mode-usecase.ts +3 -3
- package/scripts/harness/validator-system/composition-root.ts +12 -0
- package/scripts/harness/validator-system/domain/ports/ac-bound-coverage-policy-port.ts +22 -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 +2 -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/presentation/handlers/report-validation-results-handler.ts +4 -4
package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts
CHANGED
|
@@ -15,6 +15,7 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
|
|
|
15
15
|
performance: 'L3-002',
|
|
16
16
|
coverage: 'L3-003',
|
|
17
17
|
nyquist: 'L3-004',
|
|
18
|
+
'ac-bound-coverage': 'L3-005',
|
|
18
19
|
}, /^L3-\d{3}$/);
|
|
19
20
|
const l4Validators = normalizeValidators(resolvedConfig.layers.L4.validators, {
|
|
20
21
|
'drift-detect': 'L4-001',
|
|
@@ -49,6 +50,8 @@ export function toValidatorSystemConfig(resolvedConfig: HarnessConfigV2 | undefi
|
|
|
49
50
|
validators: l3Validators.length > 0 ? l3Validators : ['L3-001', 'L3-002', 'L3-003', 'L3-004'],
|
|
50
51
|
coverageThreshold: resolvedConfig.layers.L3.coverageThreshold,
|
|
51
52
|
requirementMatrixPath: resolvedConfig.layers.L3.requirementMatrixPath,
|
|
53
|
+
// WI-227 / H16-03: L3-005 のスコープ(additive-safe。未設定は [])
|
|
54
|
+
acBoundStories: resolvedConfig.layers.L3.acBoundStories ?? [],
|
|
52
55
|
},
|
|
53
56
|
L4: {
|
|
54
57
|
enabled: resolvedConfig.layers.L4.enabled,
|
|
@@ -11,6 +11,7 @@ interface L3ConfigProps {
|
|
|
11
11
|
readonly validators: string[];
|
|
12
12
|
readonly coverageThreshold: number;
|
|
13
13
|
readonly requirementMatrixPath?: string;
|
|
14
|
+
readonly acBoundStories?: readonly string[];
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export class L3Config {
|
|
@@ -18,6 +19,7 @@ export class L3Config {
|
|
|
18
19
|
readonly validators: readonly string[];
|
|
19
20
|
readonly coverageThreshold: number;
|
|
20
21
|
readonly requirementMatrixPath?: string;
|
|
22
|
+
readonly acBoundStories?: readonly string[];
|
|
21
23
|
|
|
22
24
|
constructor(props: L3ConfigProps) {
|
|
23
25
|
if (props.coverageThreshold < 0) {
|
|
@@ -40,6 +42,7 @@ export class L3Config {
|
|
|
40
42
|
this.validators = Object.freeze([...props.validators]);
|
|
41
43
|
this.coverageThreshold = props.coverageThreshold;
|
|
42
44
|
this.requirementMatrixPath = props.requirementMatrixPath;
|
|
45
|
+
this.acBoundStories = props.acBoundStories ? Object.freeze([...props.acBoundStories]) : undefined;
|
|
43
46
|
Object.freeze(this);
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -48,6 +51,7 @@ export class L3Config {
|
|
|
48
51
|
validators: string[];
|
|
49
52
|
coverageThreshold: number;
|
|
50
53
|
requirementMatrixPath?: string;
|
|
54
|
+
acBoundStories?: readonly string[];
|
|
51
55
|
}): L3Config {
|
|
52
56
|
return new L3Config(raw);
|
|
53
57
|
}
|
|
@@ -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; requirementMatrixPath?: string };
|
|
16
|
+
L3: { enabled: boolean; validators: string[]; coverageThreshold: number; requirementMatrixPath?: string; acBoundStories?: readonly string[] };
|
|
17
17
|
L4: { enabled: boolean; validators: string[]; schedule: string };
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -6,7 +6,7 @@ import { HarnessErrorDomainError } from './harness-error-domain-error.js';
|
|
|
6
6
|
export class SeverityDowngradeViolationError extends HarnessErrorDomainError {
|
|
7
7
|
constructor(requested: string, defaultSeverity: string) {
|
|
8
8
|
super(
|
|
9
|
-
`severity の格下げは禁止されています: default="${defaultSeverity}" に対して "${requested}"
|
|
9
|
+
`severity の格下げは禁止されています: default="${defaultSeverity}" に対して "${requested}" が要求されました。根拠: ADR-021`
|
|
10
10
|
);
|
|
11
11
|
this.name = 'SeverityDowngradeViolationError';
|
|
12
12
|
}
|
|
@@ -7,19 +7,17 @@
|
|
|
7
7
|
import type { CoverageResult } from '../../domain/value-objects/coverage-result.js';
|
|
8
8
|
import type { CalculateCoverageOutput } from '../dto/calculate-coverage-output.js';
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
meetsThreshold:
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
}
|
|
10
|
+
export function toCalculateCoverageOutput(
|
|
11
|
+
result: CoverageResult,
|
|
12
|
+
threshold: { active: number } | null
|
|
13
|
+
): CalculateCoverageOutput {
|
|
14
|
+
return {
|
|
15
|
+
coveredAcCount: result.coveredAcCount,
|
|
16
|
+
totalAcCount: result.totalAcCount,
|
|
17
|
+
ratePercent: result.toPercentage(),
|
|
18
|
+
uncoveredAcIds: result.uncoveredAcIds,
|
|
19
|
+
threshold: threshold?.active ?? null,
|
|
20
|
+
meetsThreshold:
|
|
21
|
+
threshold !== null ? result.meetsThreshold(threshold.active) : null,
|
|
22
|
+
};
|
|
25
23
|
}
|
package/scripts/harness/nyquist-validation/application/mappers/impact-analysis-result-mapper.ts
CHANGED
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
import type { ImpactAnalysisResult } from '../../domain/value-objects/impact-analysis-result.js';
|
|
8
8
|
import type { AnalyzeImpactOutput } from '../dto/analyze-impact-output.js';
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
10
|
+
export function toAnalyzeImpactOutput(
|
|
11
|
+
result: ImpactAnalysisResult
|
|
12
|
+
): AnalyzeImpactOutput {
|
|
13
|
+
return {
|
|
14
|
+
storyId: result.storyId,
|
|
15
|
+
directTests: result.directTests.map((ref) => ({
|
|
16
|
+
filePath: ref.filePath,
|
|
17
|
+
testType: ref.testType,
|
|
18
|
+
})),
|
|
19
|
+
directMappingOnly: true,
|
|
20
|
+
found: !result.isEmpty(),
|
|
21
|
+
};
|
|
22
22
|
}
|
|
@@ -12,7 +12,7 @@ import { RequirementTestMatrix } from '../../domain/aggregates/requirement-test-
|
|
|
12
12
|
import { StoryMapping } from '../../domain/entities/story-mapping.js';
|
|
13
13
|
import { AcMapping } from '../../domain/value-objects/ac-mapping.js';
|
|
14
14
|
import { TestReference } from '../../domain/value-objects/test-reference.js';
|
|
15
|
-
import {
|
|
15
|
+
import { toAnalyzeImpactOutput } from '../mappers/impact-analysis-result-mapper.js';
|
|
16
16
|
import type { AnalyzeImpactInput } from '../dto/analyze-impact-input.js';
|
|
17
17
|
import type { AnalyzeImpactOutput } from '../dto/analyze-impact-output.js';
|
|
18
18
|
|
|
@@ -25,29 +25,29 @@ export interface AnalyzeImpactUseCaseDeps {
|
|
|
25
25
|
|
|
26
26
|
function buildMatrix(data: unknown): RequirementTestMatrix {
|
|
27
27
|
const obj = data as Record<string, unknown>;
|
|
28
|
-
const rawStories = Array.isArray(obj
|
|
28
|
+
const rawStories = Array.isArray(obj.stories) ? obj.stories : (Array.isArray(obj.storyMappings) ? obj.storyMappings : []);
|
|
29
29
|
|
|
30
30
|
const storyMappings = (rawStories as unknown[]).map((s) => {
|
|
31
31
|
const story = s as Record<string, unknown>;
|
|
32
|
-
const rawAcMappings = Array.isArray(story
|
|
33
|
-
? story
|
|
34
|
-
: (Array.isArray(story
|
|
32
|
+
const rawAcMappings = Array.isArray(story.storyMappings)
|
|
33
|
+
? story.storyMappings
|
|
34
|
+
: (Array.isArray(story.acMappings) ? story.acMappings : []);
|
|
35
35
|
|
|
36
36
|
const acMappings = (rawAcMappings as unknown[]).map((a) => {
|
|
37
37
|
const acm = a as Record<string, unknown>;
|
|
38
|
-
const rawRefs = Array.isArray(acm
|
|
38
|
+
const rawRefs = Array.isArray(acm.testReferences) ? acm.testReferences : [];
|
|
39
39
|
const testReferences = (rawRefs as unknown[]).map((r) => {
|
|
40
40
|
const ref = r as Record<string, unknown>;
|
|
41
41
|
return TestReference.create({
|
|
42
|
-
filePath: String(ref
|
|
43
|
-
testType: String(ref
|
|
42
|
+
filePath: String(ref.filePath ?? ''),
|
|
43
|
+
testType: String(ref.testType ?? ''),
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
|
-
return AcMapping.create({ acId: String(acm
|
|
46
|
+
return AcMapping.create({ acId: String(acm.acId ?? ''), testReferences });
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
return StoryMapping.create({
|
|
50
|
-
storyId: String(story
|
|
50
|
+
storyId: String(story.storyId ?? ''),
|
|
51
51
|
acMappings,
|
|
52
52
|
});
|
|
53
53
|
});
|
|
@@ -77,6 +77,6 @@ export class AnalyzeImpactUseCase {
|
|
|
77
77
|
const matrix = buildMatrix(rawData);
|
|
78
78
|
const result = this.impactAnalysisService.analyze(matrix, input.storyId);
|
|
79
79
|
|
|
80
|
-
return
|
|
80
|
+
return toAnalyzeImpactOutput(result);
|
|
81
81
|
}
|
|
82
82
|
}
|
package/scripts/harness/nyquist-validation/application/usecases/calculate-coverage-usecase.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { RequirementTestMatrix } from '../../domain/aggregates/requirement-test-
|
|
|
13
13
|
import { StoryMapping } from '../../domain/entities/story-mapping.js';
|
|
14
14
|
import { AcMapping } from '../../domain/value-objects/ac-mapping.js';
|
|
15
15
|
import { TestReference } from '../../domain/value-objects/test-reference.js';
|
|
16
|
-
import {
|
|
16
|
+
import { toCalculateCoverageOutput } from '../mappers/coverage-result-mapper.js';
|
|
17
17
|
import type { CalculateCoverageInput } from '../dto/calculate-coverage-input.js';
|
|
18
18
|
import type { CalculateCoverageOutput } from '../dto/calculate-coverage-output.js';
|
|
19
19
|
|
|
@@ -27,29 +27,29 @@ export interface CalculateCoverageUseCaseDeps {
|
|
|
27
27
|
|
|
28
28
|
function buildMatrix(data: unknown): RequirementTestMatrix {
|
|
29
29
|
const obj = data as Record<string, unknown>;
|
|
30
|
-
const rawStories = Array.isArray(obj
|
|
30
|
+
const rawStories = Array.isArray(obj.stories) ? obj.stories : (Array.isArray(obj.storyMappings) ? obj.storyMappings : []);
|
|
31
31
|
|
|
32
32
|
const storyMappings = (rawStories as unknown[]).map((s) => {
|
|
33
33
|
const story = s as Record<string, unknown>;
|
|
34
|
-
const rawAcMappings = Array.isArray(story
|
|
35
|
-
? story
|
|
36
|
-
: (Array.isArray(story
|
|
34
|
+
const rawAcMappings = Array.isArray(story.storyMappings)
|
|
35
|
+
? story.storyMappings
|
|
36
|
+
: (Array.isArray(story.acMappings) ? story.acMappings : []);
|
|
37
37
|
|
|
38
38
|
const acMappings = (rawAcMappings as unknown[]).map((a) => {
|
|
39
39
|
const acm = a as Record<string, unknown>;
|
|
40
|
-
const rawRefs = Array.isArray(acm
|
|
40
|
+
const rawRefs = Array.isArray(acm.testReferences) ? acm.testReferences : [];
|
|
41
41
|
const testReferences = (rawRefs as unknown[]).map((r) => {
|
|
42
42
|
const ref = r as Record<string, unknown>;
|
|
43
43
|
return TestReference.create({
|
|
44
|
-
filePath: String(ref
|
|
45
|
-
testType: String(ref
|
|
44
|
+
filePath: String(ref.filePath ?? ''),
|
|
45
|
+
testType: String(ref.testType ?? ''),
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
|
-
return AcMapping.create({ acId: String(acm
|
|
48
|
+
return AcMapping.create({ acId: String(acm.acId ?? ''), testReferences });
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
return StoryMapping.create({
|
|
52
|
-
storyId: String(story
|
|
52
|
+
storyId: String(story.storyId ?? ''),
|
|
53
53
|
acMappings,
|
|
54
54
|
});
|
|
55
55
|
});
|
|
@@ -86,6 +86,6 @@ export class CalculateCoverageUseCase {
|
|
|
86
86
|
threshold = await this.coverageThresholdPort.getThreshold();
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
return
|
|
89
|
+
return toCalculateCoverageOutput(coverageResult, threshold);
|
|
90
90
|
}
|
|
91
91
|
}
|
package/scripts/harness/nyquist-validation/application/usecases/check-ac-coverage-gate-usecase.ts
CHANGED
|
@@ -24,29 +24,29 @@ export interface CheckAcCoverageGateUseCaseDeps {
|
|
|
24
24
|
|
|
25
25
|
function buildMatrix(data: unknown): RequirementTestMatrix {
|
|
26
26
|
const obj = data as Record<string, unknown>;
|
|
27
|
-
const rawStories = Array.isArray(obj
|
|
27
|
+
const rawStories = Array.isArray(obj.stories) ? obj.stories : (Array.isArray(obj.storyMappings) ? obj.storyMappings : []);
|
|
28
28
|
|
|
29
29
|
const storyMappings = (rawStories as unknown[]).map((s) => {
|
|
30
30
|
const story = s as Record<string, unknown>;
|
|
31
|
-
const rawAcMappings = Array.isArray(story
|
|
32
|
-
? story
|
|
33
|
-
: (Array.isArray(story
|
|
31
|
+
const rawAcMappings = Array.isArray(story.storyMappings)
|
|
32
|
+
? story.storyMappings
|
|
33
|
+
: (Array.isArray(story.acMappings) ? story.acMappings : []);
|
|
34
34
|
|
|
35
35
|
const acMappings = (rawAcMappings as unknown[]).map((a) => {
|
|
36
36
|
const acm = a as Record<string, unknown>;
|
|
37
|
-
const rawRefs = Array.isArray(acm
|
|
37
|
+
const rawRefs = Array.isArray(acm.testReferences) ? acm.testReferences : [];
|
|
38
38
|
const testReferences = (rawRefs as unknown[]).map((r) => {
|
|
39
39
|
const ref = r as Record<string, unknown>;
|
|
40
40
|
return TestReference.create({
|
|
41
|
-
filePath: String(ref
|
|
42
|
-
testType: String(ref
|
|
41
|
+
filePath: String(ref.filePath ?? ''),
|
|
42
|
+
testType: String(ref.testType ?? ''),
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
|
-
return AcMapping.create({ acId: String(acm
|
|
45
|
+
return AcMapping.create({ acId: String(acm.acId ?? ''), testReferences });
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
return StoryMapping.create({
|
|
49
|
-
storyId: String(story
|
|
49
|
+
storyId: String(story.storyId ?? ''),
|
|
50
50
|
acMappings,
|
|
51
51
|
});
|
|
52
52
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* requirement-test-matrix の集約ルート
|
|
6
6
|
*/
|
|
7
7
|
import { DuplicateStoryMappingError } from '../errors/duplicate-story-mapping-error.js';
|
|
8
|
-
import { StoryMapping } from '../entities/story-mapping.js';
|
|
8
|
+
import type { StoryMapping } from '../entities/story-mapping.js';
|
|
9
9
|
|
|
10
10
|
export interface RequirementTestMatrixCreateProps {
|
|
11
11
|
readonly storyMappings: readonly StoryMapping[];
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* ストーリー単位のAC→テスト参照マッピングエンティティ
|
|
6
6
|
*/
|
|
7
|
-
import { AcMapping,
|
|
7
|
+
import type { AcMapping, RawAcMapping } from '../value-objects/ac-mapping.js';
|
|
8
8
|
|
|
9
9
|
export interface StoryMappingCreateProps {
|
|
10
10
|
readonly storyId: string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* AC網羅ゲート判定ポリシー
|
|
6
6
|
* validator-system の L3-004 が実行主体として呼び出す公開ポリシー
|
|
7
7
|
*/
|
|
8
|
-
import { RequirementTestMatrix } from '../aggregates/requirement-test-matrix.js';
|
|
8
|
+
import type { RequirementTestMatrix } from '../aggregates/requirement-test-matrix.js';
|
|
9
9
|
|
|
10
10
|
export interface NyquistHarnessError {
|
|
11
11
|
readonly code: string;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* AC網羅率算出サービス(純粋な算出ロジック)
|
|
6
6
|
*/
|
|
7
|
-
import { RequirementTestMatrix } from '../aggregates/requirement-test-matrix.js';
|
|
7
|
+
import type { RequirementTestMatrix } from '../aggregates/requirement-test-matrix.js';
|
|
8
8
|
import { CoverageResult } from '../value-objects/coverage-result.js';
|
|
9
9
|
|
|
10
10
|
export class CoverageCalculationService {
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* テストケース逆引きサービス(v1: 直接マッピングのみ)
|
|
6
6
|
*/
|
|
7
|
-
import { RequirementTestMatrix } from '../aggregates/requirement-test-matrix.js';
|
|
7
|
+
import type { RequirementTestMatrix } from '../aggregates/requirement-test-matrix.js';
|
|
8
8
|
import { ImpactAnalysisResult } from '../value-objects/impact-analysis-result.js';
|
|
9
|
-
import { TestReference } from '../value-objects/test-reference.js';
|
|
9
|
+
import type { TestReference } from '../value-objects/test-reference.js';
|
|
10
10
|
|
|
11
11
|
export class ImpactAnalysisService {
|
|
12
12
|
analyze(matrix: RequirementTestMatrix, storyId: string): ImpactAnalysisResult {
|
|
@@ -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
|
}
|
|
@@ -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';
|
|
@@ -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';
|