phasegate 0.254.0 → 0.283.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 +60 -0
- package/README.ja.md +6 -3
- package/README.md +6 -3
- package/docs/contracts/attestation-v2.schema.json +110 -0
- package/docs/guide/cli-reference.md +12 -1
- package/docs/guide/configuration.md +56 -0
- package/docs/guide/installation.md +1 -1
- package/docs/templates/ci/aidlc-gate.yml +60 -2
- package/package.json +2 -2
- package/scripts/harness/agent-integration/application/dto/open-world-obligations-context-dto.ts +30 -0
- package/scripts/harness/agent-integration/application/ports/world-obligations-query-port.ts +30 -0
- package/scripts/harness/agent-integration/application/usecases/get-open-world-obligations-context-usecase.ts +66 -0
- package/scripts/harness/agent-integration/infrastructure/adapters/harness-config-config-query-adapter.ts +30 -27
- package/scripts/harness/agent-integration/infrastructure/adapters/world-model-open-obligations-query-adapter.ts +58 -0
- package/scripts/harness/agent-integration/presentation/post-tool-use-hook.ts +29 -16
- package/scripts/harness/agent-integration/presentation/session-start-hook.ts +37 -1
- package/scripts/harness/agent-integration/presentation/stop-hook.ts +35 -26
- package/scripts/harness/agent-integration/presentation/world-obligations-session-context.ts +60 -0
- package/scripts/harness/attestation/application/dto/attestation-document.ts +17 -4
- package/scripts/harness/attestation/application/mappers/attestation-record-mapper.ts +55 -4
- package/scripts/harness/attestation/application/ports/world-snapshot-root-provider.ts +10 -0
- package/scripts/harness/attestation/application/usecases/produce-attestation-usecase.ts +33 -7
- package/scripts/harness/attestation/composition-root.ts +5 -0
- package/scripts/harness/attestation/domain/entities/attestation-record.ts +37 -2
- package/scripts/harness/attestation/index.ts +7 -1
- package/scripts/harness/attestation/presentation/handlers/attest-handler.ts +5 -2
- package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +40 -9
- package/scripts/harness/config-foundation/application/mappers/world-model-config-mapper.ts +15 -0
- package/scripts/harness/config-foundation/domain/harness-config.ts +70 -87
- package/scripts/harness/config-foundation/domain/services/preset-resolution-service.ts +80 -88
- package/scripts/harness/config-foundation/domain/value-objects/project-config.ts +34 -18
- package/scripts/harness/config-foundation/domain/value-objects/world-config.ts +198 -0
- package/scripts/harness/config-foundation/index.ts +14 -15
- package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +24 -0
- package/scripts/harness/config-foundation/infrastructure/presets/standard.json +24 -0
- package/scripts/harness/config-foundation/infrastructure/presets/strict.json +24 -0
- package/scripts/harness/config-foundation/infrastructure/repositories/file-system-config-repository.ts +27 -18
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +84 -8
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +84 -8
- package/scripts/harness/harness-api/domain/ports/config-query-port.ts +11 -1
- package/scripts/harness/harness-api/domain/services/command-dispatch-service.ts +125 -86
- package/scripts/harness/harness-api/domain/services/status-derivation-service.ts +31 -21
- package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +18 -4
- package/scripts/harness/harness-api/domain/value-objects/harness-status-summary.ts +23 -8
- package/scripts/harness/harness-api/infrastructure/adapters/biome-ast-engine-lint-adapter.ts +4 -4
- package/scripts/harness/harness-api/infrastructure/adapters/harness-config-query-adapter.ts +79 -34
- package/scripts/harness/installation/application/usecases/run-install.ts +199 -51
- package/scripts/harness/installation/application/usecases/run-reconcile.ts +277 -69
- package/scripts/harness/installation/domain/deployment-manifest.ts +43 -0
- package/scripts/harness/integrations/pre-commit.ts +169 -27
- package/scripts/harness/main.ts +200 -136
- package/scripts/harness/traceability-model/application/dto/changed-design-fragment-dto.ts +31 -0
- package/scripts/harness/traceability-model/application/facades/design-change-read-facade.ts +14 -0
- package/scripts/harness/traceability-model/application/ports/staged-design-change-source-port.ts +9 -0
- package/scripts/harness/traceability-model/composition-root.ts +5 -0
- package/scripts/harness/traceability-model/index.ts +9 -0
- package/scripts/harness/traceability-model/infrastructure/adapters/git-staged-design-change-adapter.ts +155 -0
- package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +31 -0
- package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +57 -6
- package/scripts/harness/validator-system/composition-root.ts +25 -7
- package/scripts/harness/validator-system/domain/ports/ac-coverage-policy-port.ts +10 -1
- package/scripts/harness/validator-system/domain/ports/world-constraint-admission-policy-port.ts +28 -0
- package/scripts/harness/validator-system/domain/ports/world-constraint-rederivation-policy-port.ts +11 -0
- package/scripts/harness/validator-system/domain/services/design-change-declaration-policy.ts +75 -0
- package/scripts/harness/validator-system/domain/services/world-constraint-admission-service.ts +78 -0
- package/scripts/harness/validator-system/domain/services/world-constraint-rederivation-service.ts +76 -0
- package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +4 -0
- package/scripts/harness/validator-system/infrastructure/adapters/harness-config-validator-config-adapter.ts +126 -18
- package/scripts/harness/validator-system/infrastructure/adapters/nyquist-ac-coverage-policy-adapter.ts +49 -20
- package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-admission-adapter.ts +56 -0
- package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-rederivation-adapter.ts +56 -0
- package/scripts/harness/world-model/application/dto/pinned-design-endpoint-dto.ts +19 -0
- package/scripts/harness/world-model/application/dto/world-resolved-config-input.ts +92 -27
- package/scripts/harness/world-model/application/dto/world-snapshot-root-dto.ts +8 -0
- package/scripts/harness/world-model/application/facades/pinned-design-endpoint-facade.ts +63 -0
- package/scripts/harness/world-model/application/facades/world-snapshot-root-facade.ts +19 -0
- package/scripts/harness/world-model/application/usecases/derive-world-obligations-use-case.ts +3 -1
- package/scripts/harness/world-model/composition-root.ts +62 -33
- package/scripts/harness/world-model/index.ts +11 -0
- package/scripts/harness/world-model/infrastructure/adapters/attestation-fact-extractor.ts +48 -13
- package/scripts/harness/world-model/infrastructure/adapters/file-system-world-control-repository-adapters.ts +6 -4
- package/scripts/harness/world-model/presentation/cli/world-derive-command-handler.ts +6 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// @unit traceability-model
|
|
2
|
+
// @layer application
|
|
3
|
+
// @work-item-id WI-305
|
|
4
|
+
|
|
5
|
+
export type DesignFragmentCorpusRole = "product" | "inception";
|
|
6
|
+
export type DesignFragmentChangeKind = "added" | "modified" | "deleted";
|
|
7
|
+
|
|
8
|
+
export interface ChangedDesignFragmentDto {
|
|
9
|
+
readonly corpusRole: DesignFragmentCorpusRole;
|
|
10
|
+
readonly declaredKey: string;
|
|
11
|
+
readonly path: string;
|
|
12
|
+
readonly changeKind: DesignFragmentChangeKind;
|
|
13
|
+
readonly workItemIds: readonly string[];
|
|
14
|
+
readonly reflectionTargets: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface DesignChangeReadDiagnosticDto {
|
|
18
|
+
readonly code: string;
|
|
19
|
+
readonly path: string | null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type DesignChangeReadResultDto =
|
|
23
|
+
| {
|
|
24
|
+
readonly state: "available";
|
|
25
|
+
readonly fragments: readonly ChangedDesignFragmentDto[];
|
|
26
|
+
readonly diagnostics: readonly DesignChangeReadDiagnosticDto[];
|
|
27
|
+
}
|
|
28
|
+
| {
|
|
29
|
+
readonly state: "unavailable";
|
|
30
|
+
readonly diagnostics: readonly DesignChangeReadDiagnosticDto[];
|
|
31
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @unit traceability-model
|
|
2
|
+
// @layer application
|
|
3
|
+
// @work-item-id WI-305
|
|
4
|
+
|
|
5
|
+
import type { DesignChangeReadResultDto } from "../dto/changed-design-fragment-dto.js";
|
|
6
|
+
import type { StagedDesignChangeSourcePort } from "../ports/staged-design-change-source-port.js";
|
|
7
|
+
|
|
8
|
+
export class DesignChangeReadFacade {
|
|
9
|
+
constructor(private readonly source: StagedDesignChangeSourcePort) {}
|
|
10
|
+
|
|
11
|
+
observe(stagedFiles: readonly string[]): Promise<DesignChangeReadResultDto> {
|
|
12
|
+
return this.source.observe(stagedFiles);
|
|
13
|
+
}
|
|
14
|
+
}
|
package/scripts/harness/traceability-model/application/ports/staged-design-change-source-port.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// @unit traceability-model
|
|
2
|
+
// @layer application
|
|
3
|
+
// @work-item-id WI-305
|
|
4
|
+
|
|
5
|
+
import type { DesignChangeReadResultDto } from "../dto/changed-design-fragment-dto.js";
|
|
6
|
+
|
|
7
|
+
export interface StagedDesignChangeSourcePort {
|
|
8
|
+
observe(stagedFiles: readonly string[]): Promise<DesignChangeReadResultDto>;
|
|
9
|
+
}
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
* @layer application
|
|
3
3
|
* @unit traceability-model
|
|
4
4
|
* @work-item-id WI-093
|
|
5
|
+
* @work-item-id WI-305
|
|
5
6
|
*
|
|
6
7
|
* traceability-model ユニットの Composition Root。
|
|
7
8
|
* 全コンポーネントを生成・配線し、外部に公開するハンドラー群を返す。
|
|
8
9
|
*/
|
|
9
10
|
|
|
11
|
+
import { DesignChangeReadFacade } from "./application/facades/design-change-read-facade.js";
|
|
10
12
|
import { TraceabilityWorldReadFacade } from "./application/facades/traceability-world-read-facade.js";
|
|
11
13
|
import { ApplyWorkItemMigrationUseCase } from "./application/usecases/apply-work-item-migration-usecase.js";
|
|
12
14
|
import { ApplyWorkItemStatusUseCase } from "./application/usecases/apply-work-item-status-usecase.js";
|
|
@@ -21,6 +23,7 @@ import { TraceabilityChainBuilder } from "./domain/services/traceability-chain-b
|
|
|
21
23
|
import { WorkItemStatusDerivationService } from "./domain/services/work-item-status-derivation-service.js";
|
|
22
24
|
import { ProjectRelativePath } from "./domain/value-objects/project-relative-path.js";
|
|
23
25
|
import { FileSystemTraceabilityWorldReadAdapter } from "./infrastructure/adapters/file-system-traceability-world-read-adapter.js";
|
|
26
|
+
import { GitStagedDesignChangeAdapter } from "./infrastructure/adapters/git-staged-design-change-adapter.js";
|
|
24
27
|
import { FileSystemInceptionPlanGateway } from "./infrastructure/gateways/file-system-inception-plan-gateway.js";
|
|
25
28
|
import { FileSystemMetadataReader } from "./infrastructure/gateways/file-system-metadata-reader.js";
|
|
26
29
|
import { FileSystemWorkItemIdentityGateway } from "./infrastructure/gateways/file-system-work-item-identity-gateway.js";
|
|
@@ -101,6 +104,7 @@ export function createTraceabilityModelModule(rootDir: string, options: Traceabi
|
|
|
101
104
|
const worldReadFacade = new TraceabilityWorldReadFacade({
|
|
102
105
|
sourcePort: worldReadSource,
|
|
103
106
|
});
|
|
107
|
+
const designChangeReadFacade = new DesignChangeReadFacade(new GitStagedDesignChangeAdapter(rootDir));
|
|
104
108
|
|
|
105
109
|
// Usecases
|
|
106
110
|
const validateImplementationMetadataUseCase = new ValidateImplementationMetadataUseCase({
|
|
@@ -157,5 +161,6 @@ export function createTraceabilityModelModule(rootDir: string, options: Traceabi
|
|
|
157
161
|
traceabilityChainBuilder,
|
|
158
162
|
storyIdAliasResolver,
|
|
159
163
|
worldReadFacade,
|
|
164
|
+
designChangeReadFacade,
|
|
160
165
|
} as const;
|
|
161
166
|
}
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @layer public-api
|
|
3
3
|
* @unit traceability-model
|
|
4
|
+
* @work-item-id WI-305
|
|
4
5
|
*
|
|
5
6
|
* traceability-model ユニットのバレルエクスポート。
|
|
6
7
|
*/
|
|
7
8
|
|
|
9
|
+
export type {
|
|
10
|
+
ChangedDesignFragmentDto,
|
|
11
|
+
DesignChangeReadDiagnosticDto,
|
|
12
|
+
DesignChangeReadResultDto,
|
|
13
|
+
DesignFragmentChangeKind,
|
|
14
|
+
DesignFragmentCorpusRole,
|
|
15
|
+
} from "./application/dto/changed-design-fragment-dto.js";
|
|
8
16
|
export type {
|
|
9
17
|
TraceabilityAcceptanceCriterionDto,
|
|
10
18
|
TraceabilityReadDiagnosticDto,
|
|
@@ -16,6 +24,7 @@ export type {
|
|
|
16
24
|
TraceabilityWorldReadDto,
|
|
17
25
|
} from "./application/dto/traceability-world-read-dto.js";
|
|
18
26
|
export { TRACEABILITY_WORLD_READ_SCHEMA_VERSION } from "./application/dto/traceability-world-read-dto.js";
|
|
27
|
+
export { DesignChangeReadFacade } from "./application/facades/design-change-read-facade.js";
|
|
19
28
|
// Application — public World read facade and plain DTO contract
|
|
20
29
|
export { TraceabilityWorldReadFacade } from "./application/facades/traceability-world-read-facade.js";
|
|
21
30
|
// Composition Root
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// @unit traceability-model
|
|
2
|
+
// @layer infrastructure
|
|
3
|
+
// @work-item-id WI-305
|
|
4
|
+
|
|
5
|
+
import { execFileSync } from "node:child_process";
|
|
6
|
+
import type {
|
|
7
|
+
ChangedDesignFragmentDto,
|
|
8
|
+
DesignChangeReadDiagnosticDto,
|
|
9
|
+
DesignChangeReadResultDto,
|
|
10
|
+
DesignFragmentCorpusRole,
|
|
11
|
+
} from "../../application/dto/changed-design-fragment-dto.js";
|
|
12
|
+
import type { StagedDesignChangeSourcePort } from "../../application/ports/staged-design-change-source-port.js";
|
|
13
|
+
|
|
14
|
+
const FRAGMENT = /^\s*<!--\s*@world-fragment-id\s+(\S+)\s*-->\s*$/;
|
|
15
|
+
const WORK_ITEM = /^\s*<!--\s*@work-item-id\s+(.+?)\s*-->\s*$/;
|
|
16
|
+
const REFLECTS = /^\s*<!--\s*@world-reflects\s+(\S+)\s*-->\s*$/;
|
|
17
|
+
const HEADING = /^#{1,6}\s+/;
|
|
18
|
+
const FENCE = /^\s*(`{3,}|~{3,})/;
|
|
19
|
+
const compare = (left: string, right: string): number => (left < right ? -1 : left > right ? 1 : 0);
|
|
20
|
+
|
|
21
|
+
interface ParsedFragment {
|
|
22
|
+
readonly declaredKey: string;
|
|
23
|
+
readonly content: string;
|
|
24
|
+
readonly workItemIds: readonly string[];
|
|
25
|
+
readonly reflectionTargets: readonly string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface ParsedFragmentSet {
|
|
29
|
+
readonly fragments: readonly ParsedFragment[];
|
|
30
|
+
readonly validPrelude: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const corpusRoleOf = (filePath: string): DesignFragmentCorpusRole | null => {
|
|
34
|
+
if (filePath.startsWith("docs/product/")) return "product";
|
|
35
|
+
if (filePath.startsWith("docs/inception/")) return "inception";
|
|
36
|
+
return null;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const uniqueSorted = (values: readonly string[]): readonly string[] =>
|
|
40
|
+
Object.freeze([...new Set(values)].sort(compare));
|
|
41
|
+
|
|
42
|
+
const parseFragments = (text: string): ParsedFragmentSet => {
|
|
43
|
+
const lines = text.replace(/\r\n?/g, "\n").split("\n");
|
|
44
|
+
const markers: { readonly index: number; readonly key: string }[] = [];
|
|
45
|
+
let activeFence: string | null = null;
|
|
46
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
47
|
+
const fence = FENCE.exec(lines[index]);
|
|
48
|
+
if (fence) {
|
|
49
|
+
const character = fence[1][0];
|
|
50
|
+
activeFence = activeFence === null ? character : activeFence === character ? null : activeFence;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (activeFence !== null) continue;
|
|
54
|
+
const marker = FRAGMENT.exec(lines[index]);
|
|
55
|
+
if (marker) markers.push({ index, key: marker[1] });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let validPrelude = true;
|
|
59
|
+
const fragments = markers.flatMap((marker, markerIndex): readonly ParsedFragment[] => {
|
|
60
|
+
const end = markers[markerIndex + 1]?.index ?? lines.length;
|
|
61
|
+
let headingIndex = marker.index + 1;
|
|
62
|
+
while (headingIndex < end && (WORK_ITEM.test(lines[headingIndex]) || REFLECTS.test(lines[headingIndex]))) {
|
|
63
|
+
headingIndex += 1;
|
|
64
|
+
}
|
|
65
|
+
if (headingIndex >= end || !HEADING.test(lines[headingIndex])) {
|
|
66
|
+
validPrelude = false;
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
const metadata = lines.slice(marker.index, headingIndex);
|
|
70
|
+
return [
|
|
71
|
+
Object.freeze({
|
|
72
|
+
declaredKey: marker.key,
|
|
73
|
+
content: lines.slice(marker.index, end).join("\n"),
|
|
74
|
+
workItemIds: uniqueSorted(metadata.flatMap((line) => WORK_ITEM.exec(line)?.[1].match(/\bWI-\d+\b/g) ?? [])),
|
|
75
|
+
reflectionTargets: uniqueSorted(metadata.flatMap((line) => REFLECTS.exec(line)?.[1] ?? [])),
|
|
76
|
+
}),
|
|
77
|
+
];
|
|
78
|
+
});
|
|
79
|
+
return Object.freeze({ fragments: Object.freeze(fragments), validPrelude });
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const indexByKey = (fragments: readonly ParsedFragment[]): Map<string, ParsedFragment> | null => {
|
|
83
|
+
const result = new Map<string, ParsedFragment>();
|
|
84
|
+
for (const fragment of fragments) {
|
|
85
|
+
if (result.has(fragment.declaredKey)) return null;
|
|
86
|
+
result.set(fragment.declaredKey, fragment);
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export class GitStagedDesignChangeAdapter implements StagedDesignChangeSourcePort {
|
|
92
|
+
constructor(private readonly rootDir: string) {}
|
|
93
|
+
|
|
94
|
+
async observe(stagedFiles: readonly string[]): Promise<DesignChangeReadResultDto> {
|
|
95
|
+
const fragments: ChangedDesignFragmentDto[] = [];
|
|
96
|
+
const diagnostics: DesignChangeReadDiagnosticDto[] = [];
|
|
97
|
+
for (const filePath of [...new Set(stagedFiles)].sort(compare)) {
|
|
98
|
+
const corpusRole = corpusRoleOf(filePath);
|
|
99
|
+
if (corpusRole === null || !filePath.endsWith(".md")) continue;
|
|
100
|
+
const beforeText = this.readBlob(`HEAD:${filePath}`);
|
|
101
|
+
const afterText = this.readBlob(`:${filePath}`);
|
|
102
|
+
if (beforeText === null && afterText === null) {
|
|
103
|
+
diagnostics.push(Object.freeze({ code: "staged-design-content-unavailable", path: filePath }));
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const beforeParsed = parseFragments(beforeText ?? "");
|
|
107
|
+
const afterParsed = parseFragments(afterText ?? "");
|
|
108
|
+
if (!beforeParsed.validPrelude || !afterParsed.validPrelude) {
|
|
109
|
+
diagnostics.push(Object.freeze({ code: "invalid-staged-fragment-prelude", path: filePath }));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const before = indexByKey(beforeParsed.fragments);
|
|
113
|
+
const after = indexByKey(afterParsed.fragments);
|
|
114
|
+
if (before === null || after === null) {
|
|
115
|
+
diagnostics.push(Object.freeze({ code: "duplicate-staged-fragment-key", path: filePath }));
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const keys = uniqueSorted([...before.keys(), ...after.keys()]);
|
|
119
|
+
for (const key of keys) {
|
|
120
|
+
const oldFragment = before.get(key);
|
|
121
|
+
const newFragment = after.get(key);
|
|
122
|
+
if (oldFragment?.content === newFragment?.content) continue;
|
|
123
|
+
const observed = newFragment ?? oldFragment;
|
|
124
|
+
if (!observed) continue;
|
|
125
|
+
fragments.push(
|
|
126
|
+
Object.freeze({
|
|
127
|
+
corpusRole,
|
|
128
|
+
declaredKey: key,
|
|
129
|
+
path: filePath,
|
|
130
|
+
changeKind: oldFragment === undefined ? "added" : newFragment === undefined ? "deleted" : "modified",
|
|
131
|
+
workItemIds: observed.workItemIds,
|
|
132
|
+
reflectionTargets: observed.reflectionTargets,
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (diagnostics.length > 0) {
|
|
138
|
+
return Object.freeze({ state: "unavailable", diagnostics: Object.freeze(diagnostics) });
|
|
139
|
+
}
|
|
140
|
+
return Object.freeze({ state: "available", fragments: Object.freeze(fragments), diagnostics: Object.freeze([]) });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private readBlob(spec: string): string | null {
|
|
144
|
+
try {
|
|
145
|
+
return execFileSync("git", ["show", spec], {
|
|
146
|
+
cwd: this.rootDir,
|
|
147
|
+
encoding: "utf8",
|
|
148
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
149
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
150
|
+
});
|
|
151
|
+
} catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* RunL2ValidatorsUseCase — H08-01: L2バリデータ実行
|
|
6
6
|
* @work-item-id WI-110 / WI-111 / WI-140 / WI-132 / WI-133 / WI-136 / WI-137 / WI-138
|
|
7
|
+
* @work-item-id WI-301
|
|
7
8
|
*/
|
|
8
9
|
import { readFile } from "node:fs/promises";
|
|
9
10
|
import type { CliCommandRegistryPort } from "../../domain/ports/cli-command-registry-port.js";
|
|
@@ -15,6 +16,7 @@ import type { PhaseGatePolicyPort } from "../../domain/ports/phase-gate-policy-p
|
|
|
15
16
|
import type { TestQualityAnalyzerPort } from "../../domain/ports/test-quality-analyzer-port.js";
|
|
16
17
|
import type { ValidatorConfigPort } from "../../domain/ports/validator-config-port.js";
|
|
17
18
|
import type { WorkItemStatusPolicyPort } from "../../domain/ports/work-item-status-policy-port.js";
|
|
19
|
+
import type { WorldConstraintAdmissionPolicyPort } from "../../domain/ports/world-constraint-admission-policy-port.js";
|
|
18
20
|
import { CliE2eTestExistenceService } from "../../domain/services/cli-e2e-test-existence-service.js";
|
|
19
21
|
import { ContractTraceabilityCoverageService } from "../../domain/services/contract-traceability-coverage-service.js";
|
|
20
22
|
import { CoverageAttestationGatingService } from "../../domain/services/coverage-attestation-gating-service.js";
|
|
@@ -23,6 +25,7 @@ import {
|
|
|
23
25
|
type ValidatorExecutionService,
|
|
24
26
|
} from "../../domain/services/validator-execution-service.js";
|
|
25
27
|
import type { ValidatorRegistry } from "../../domain/services/validator-registry.js";
|
|
28
|
+
import { WorldConstraintAdmissionService } from "../../domain/services/world-constraint-admission-service.js";
|
|
26
29
|
import { type HarnessErrorLike, ValidationResult } from "../../domain/value-objects/validation-result.js";
|
|
27
30
|
import { ValidatorId } from "../../domain/value-objects/validator-id.js";
|
|
28
31
|
import type { RunL2ValidatorsInput } from "../dto/run-l2-validators-input.js";
|
|
@@ -42,6 +45,7 @@ export interface RunL2ValidatorsUseCaseDeps {
|
|
|
42
45
|
workItemStatusPolicyPort?: WorkItemStatusPolicyPort;
|
|
43
46
|
contractTraceabilityPolicyPort?: ContractTraceabilityPolicyPort;
|
|
44
47
|
coverageAttestationGatingPolicyPort?: CoverageAttestationGatingPolicyPort;
|
|
48
|
+
worldConstraintAdmissionPolicyPort?: WorldConstraintAdmissionPolicyPort;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
export class RunL2ValidatorsUseCase {
|
|
@@ -57,9 +61,11 @@ export class RunL2ValidatorsUseCase {
|
|
|
57
61
|
private readonly workItemStatusPolicyPort?: WorkItemStatusPolicyPort;
|
|
58
62
|
private readonly contractTraceabilityPolicyPort?: ContractTraceabilityPolicyPort;
|
|
59
63
|
private readonly coverageAttestationGatingPolicyPort?: CoverageAttestationGatingPolicyPort;
|
|
64
|
+
private readonly worldConstraintAdmissionPolicyPort?: WorldConstraintAdmissionPolicyPort;
|
|
60
65
|
private readonly cliE2eTestExistenceService = new CliE2eTestExistenceService();
|
|
61
66
|
private readonly contractTraceabilityCoverageService = new ContractTraceabilityCoverageService();
|
|
62
67
|
private readonly coverageAttestationGatingService = new CoverageAttestationGatingService();
|
|
68
|
+
private readonly worldConstraintAdmissionService = new WorldConstraintAdmissionService();
|
|
63
69
|
|
|
64
70
|
constructor(deps: RunL2ValidatorsUseCaseDeps) {
|
|
65
71
|
this.registry = deps.validatorRegistry;
|
|
@@ -74,6 +80,7 @@ export class RunL2ValidatorsUseCase {
|
|
|
74
80
|
this.workItemStatusPolicyPort = deps.workItemStatusPolicyPort;
|
|
75
81
|
this.contractTraceabilityPolicyPort = deps.contractTraceabilityPolicyPort;
|
|
76
82
|
this.coverageAttestationGatingPolicyPort = deps.coverageAttestationGatingPolicyPort;
|
|
83
|
+
this.worldConstraintAdmissionPolicyPort = deps.worldConstraintAdmissionPolicyPort;
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
async execute(input: RunL2ValidatorsInput): Promise<readonly ValidationResultContract[]> {
|
|
@@ -241,6 +248,30 @@ export class RunL2ValidatorsUseCase {
|
|
|
241
248
|
}
|
|
242
249
|
}
|
|
243
250
|
|
|
251
|
+
if (this.worldConstraintAdmissionPolicyPort) {
|
|
252
|
+
const l2017Result = overrideMap.get("L2-017");
|
|
253
|
+
if (l2017Result && !l2017Result.skipped) {
|
|
254
|
+
const observation = await this.worldConstraintAdmissionPolicyPort.collect();
|
|
255
|
+
const findings = this.worldConstraintAdmissionService.evaluate(observation);
|
|
256
|
+
if (findings.length > 0) {
|
|
257
|
+
const errors: HarnessErrorLike[] = findings.map((finding) => ({
|
|
258
|
+
code: { value: "L2-017", toString: () => "L2-017" },
|
|
259
|
+
severity: { value: finding.severity, toString: () => finding.severity },
|
|
260
|
+
message: finding.message,
|
|
261
|
+
suggestion: finding.suggestion,
|
|
262
|
+
ruleId: finding.ruleId,
|
|
263
|
+
violationFingerprint: finding.violationFingerprint,
|
|
264
|
+
constraintId: finding.constraintId,
|
|
265
|
+
classification: finding.classification,
|
|
266
|
+
sourcePath: finding.sourcePath,
|
|
267
|
+
}));
|
|
268
|
+
overrideMap.set("L2-017", ValidationResult.fail(ValidatorId.create("L2-017"), errors, 0));
|
|
269
|
+
} else {
|
|
270
|
+
overrideMap.set("L2-017", ValidationResult.pass(ValidatorId.create("L2-017"), 0));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
244
275
|
const finalResults = definitions.map(
|
|
245
276
|
(definition) => overrideMap.get(definition.validatorId.value) ?? ValidationResult.skip(definition.validatorId),
|
|
246
277
|
);
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* @layer application
|
|
3
3
|
* @unit validator-system
|
|
4
4
|
* @work-item-id WI-212
|
|
5
|
+
* @work-item-id WI-302
|
|
6
|
+
* @work-item-id WI-317
|
|
7
|
+
* @work-item-id WI-324
|
|
5
8
|
*
|
|
6
9
|
* RunL3ValidatorsUseCase — H08-02: L3バリデータ実行
|
|
7
10
|
*/
|
|
@@ -13,6 +16,7 @@ import type { InjectionScanPolicyPort } from "../../domain/ports/injection-scan-
|
|
|
13
16
|
import type { PerformanceScannerPort } from "../../domain/ports/performance-scanner-port.js";
|
|
14
17
|
import type { SecurityPatternScannerPort } from "../../domain/ports/security-pattern-scanner-port.js";
|
|
15
18
|
import type { ValidatorConfigPort } from "../../domain/ports/validator-config-port.js";
|
|
19
|
+
import type { WorldConstraintRederivationPolicyPort } from "../../domain/ports/world-constraint-rederivation-policy-port.js";
|
|
16
20
|
import { CoverageAttestationVerificationService } from "../../domain/services/coverage-attestation-verification-service.js";
|
|
17
21
|
import { InjectionPatternScanService } from "../../domain/services/injection-pattern-scan-service.js";
|
|
18
22
|
import {
|
|
@@ -21,6 +25,7 @@ import {
|
|
|
21
25
|
} from "../../domain/services/validator-execution-service.js";
|
|
22
26
|
import { ValidatorLanguageCapabilityService } from "../../domain/services/validator-language-capability-service.js";
|
|
23
27
|
import type { ValidatorRegistry } from "../../domain/services/validator-registry.js";
|
|
28
|
+
import { WorldConstraintRederivationService } from "../../domain/services/world-constraint-rederivation-service.js";
|
|
24
29
|
import type { HarnessErrorLike } from "../../domain/value-objects/validation-result.js";
|
|
25
30
|
import { ValidationResult } from "../../domain/value-objects/validation-result.js";
|
|
26
31
|
import { ValidatorId } from "../../domain/value-objects/validator-id.js";
|
|
@@ -54,6 +59,8 @@ export interface RunL3ValidatorsUseCaseDeps {
|
|
|
54
59
|
injectionScanPolicyPort?: InjectionScanPolicyPort;
|
|
55
60
|
/** WI-268 / ADR-030 §Decision.1・§Decision.3.② 第2段: L3-007 (coverage-attestation-verification, fail-closed) 用ポート。 */
|
|
56
61
|
coverageAttestationVerificationPolicyPort?: CoverageAttestationVerificationPolicyPort;
|
|
62
|
+
/** WI-302: L3-008 authoritative World clean-corpus re-derivation port. */
|
|
63
|
+
worldConstraintRederivationPolicyPort?: WorldConstraintRederivationPolicyPort;
|
|
57
64
|
/** L3-005 のスコープ対象 story-id(config layers.L3.acBoundStories 由来。既定 [])。 */
|
|
58
65
|
acBoundStories?: readonly string[];
|
|
59
66
|
}
|
|
@@ -70,10 +77,12 @@ export class RunL3ValidatorsUseCase {
|
|
|
70
77
|
private readonly performanceScannerPort?: PerformanceScannerPort;
|
|
71
78
|
private readonly injectionScanPolicyPort?: InjectionScanPolicyPort;
|
|
72
79
|
private readonly coverageAttestationVerificationPolicyPort?: CoverageAttestationVerificationPolicyPort;
|
|
80
|
+
private readonly worldConstraintRederivationPolicyPort?: WorldConstraintRederivationPolicyPort;
|
|
73
81
|
private readonly acBoundStories: readonly string[];
|
|
74
82
|
private readonly languageCapabilityService = new ValidatorLanguageCapabilityService();
|
|
75
83
|
private readonly injectionScanService = new InjectionPatternScanService();
|
|
76
84
|
private readonly coverageAttestationVerificationService = new CoverageAttestationVerificationService();
|
|
85
|
+
private readonly worldConstraintRederivationService = new WorldConstraintRederivationService();
|
|
77
86
|
|
|
78
87
|
constructor(deps: RunL3ValidatorsUseCaseDeps) {
|
|
79
88
|
this.registry = deps.validatorRegistry;
|
|
@@ -87,6 +96,7 @@ export class RunL3ValidatorsUseCase {
|
|
|
87
96
|
this.performanceScannerPort = deps.performanceScannerPort;
|
|
88
97
|
this.injectionScanPolicyPort = deps.injectionScanPolicyPort;
|
|
89
98
|
this.coverageAttestationVerificationPolicyPort = deps.coverageAttestationVerificationPolicyPort;
|
|
99
|
+
this.worldConstraintRederivationPolicyPort = deps.worldConstraintRederivationPolicyPort;
|
|
90
100
|
this.acBoundStories = deps.acBoundStories ?? [];
|
|
91
101
|
}
|
|
92
102
|
|
|
@@ -125,8 +135,10 @@ export class RunL3ValidatorsUseCase {
|
|
|
125
135
|
);
|
|
126
136
|
|
|
127
137
|
// L3-003: カバレッジ判定(カバレッジゲートはオプトイン)
|
|
128
|
-
// - coverageThreshold 未設定 → SKIP(透過的に判定をスキップ。getCoverage() は呼ばない)
|
|
129
|
-
// -
|
|
138
|
+
// - coverageThreshold 未設定 or 0 → SKIP(透過的に判定をスキップ。getCoverage() は呼ばない)
|
|
139
|
+
// 0 は正規の opt-out(ドメイン VO L3Config.hasCoverageGate() の「threshold > 0 でのみ有効」と整合。
|
|
140
|
+
// minimal preset の coverageThreshold: 0 もこの opt-out 意図。WI-317 / github#37)
|
|
141
|
+
// - coverageThreshold > 0 → getCoverage() を try/catch で包み FAIL-CLOSED で判定する
|
|
130
142
|
// - 閾値未満 → FAIL / 閾値以上 → PASS
|
|
131
143
|
// - レポート不在などで getCoverage() が失敗 → FAIL(合格扱いにしない)
|
|
132
144
|
// このブロックは例外を送出せず、L3-003 の per-validator 結果のみを差し替える。
|
|
@@ -137,12 +149,12 @@ export class RunL3ValidatorsUseCase {
|
|
|
137
149
|
const l3003Id = ValidatorId.create("L3-003");
|
|
138
150
|
const threshold = layerConfig.getThreshold("coverageThreshold");
|
|
139
151
|
|
|
140
|
-
if (threshold === null) {
|
|
152
|
+
if (threshold === null || threshold === 0) {
|
|
141
153
|
overrideMap.set(
|
|
142
154
|
"L3-003",
|
|
143
155
|
ValidationResult.skipWithReason(
|
|
144
156
|
l3003Id,
|
|
145
|
-
"coverageThreshold
|
|
157
|
+
"coverageThreshold が未設定/0 のためカバレッジ判定をスキップ(カバレッジゲートはオプトイン。0 で opt-out)",
|
|
146
158
|
),
|
|
147
159
|
);
|
|
148
160
|
} else {
|
|
@@ -178,7 +190,8 @@ export class RunL3ValidatorsUseCase {
|
|
|
178
190
|
code: "L3-003",
|
|
179
191
|
severity: "error",
|
|
180
192
|
message: `coverageThreshold=${threshold}% が設定されていますがカバレッジレポートが見つかりません(テストをカバレッジ付きで実行してください)`,
|
|
181
|
-
suggestion:
|
|
193
|
+
suggestion:
|
|
194
|
+
'次のいずれかで解消してください: (a) テストをカバレッジ付きで実行してレポートを生成する(例: vitest --coverage)、(b) カバレッジゲートを opt-out するなら config の layers.L3.coverageThreshold を 0 に設定する、(c) 非 JS/TS プロジェクトなら project.languages を宣言する(例: ["python"]。L3-003 自体が unsupported-language SKIP になる)',
|
|
182
195
|
},
|
|
183
196
|
],
|
|
184
197
|
0,
|
|
@@ -216,7 +229,19 @@ export class RunL3ValidatorsUseCase {
|
|
|
216
229
|
const policyResult = await this.acCoveragePolicyPort.checkCoverage({
|
|
217
230
|
matrixFilePath: input.requirementMatrixPath,
|
|
218
231
|
});
|
|
219
|
-
|
|
232
|
+
// WI-324: フレッシュプロジェクト(story 未作成・matrix 未生成)は policy adapter が
|
|
233
|
+
// skipped=true を返すので、L3-003 の opt-out と同じ表現で skipWithReason に変換する。
|
|
234
|
+
// story が存在するのに matrix が不在の場合は従来どおり fail-closed(下の分岐)。
|
|
235
|
+
if (policyResult.skipped) {
|
|
236
|
+
overrideMap.set(
|
|
237
|
+
"L3-004",
|
|
238
|
+
ValidationResult.skipWithReason(
|
|
239
|
+
ValidatorId.create("L3-004"),
|
|
240
|
+
policyResult.skipReason ??
|
|
241
|
+
"story 未作成のため L3-004 をスキップ(story 作成後に requirement-test-matrix を生成すると有効化されます)",
|
|
242
|
+
),
|
|
243
|
+
);
|
|
244
|
+
} else if (!policyResult.passed) {
|
|
220
245
|
overrideMap.set("L3-004", ValidationResult.fail(ValidatorId.create("L3-004"), [...policyResult.errors], 0));
|
|
221
246
|
}
|
|
222
247
|
}
|
|
@@ -305,6 +330,32 @@ export class RunL3ValidatorsUseCase {
|
|
|
305
330
|
}
|
|
306
331
|
}
|
|
307
332
|
|
|
333
|
+
// WI-302 / ADR-030 trust root: L3-008 independently re-derives World obligations from the
|
|
334
|
+
// current corpus and versioned control declarations. The adapter has no persisted-report input.
|
|
335
|
+
if (this.worldConstraintRederivationPolicyPort) {
|
|
336
|
+
const l3008Result = overrideMap.get("L3-008");
|
|
337
|
+
if (l3008Result && !l3008Result.skipped) {
|
|
338
|
+
const observation = await this.worldConstraintRederivationPolicyPort.collect();
|
|
339
|
+
const findings = this.worldConstraintRederivationService.evaluate(observation);
|
|
340
|
+
if (findings.length > 0) {
|
|
341
|
+
const errors: HarnessErrorLike[] = findings.map((finding) => ({
|
|
342
|
+
code: { value: "L3-008", toString: () => "L3-008" },
|
|
343
|
+
severity: { value: finding.severity, toString: () => finding.severity },
|
|
344
|
+
message: finding.message,
|
|
345
|
+
suggestion: finding.suggestion,
|
|
346
|
+
sourcePath: finding.sourcePath,
|
|
347
|
+
ruleId: finding.ruleId,
|
|
348
|
+
violationFingerprint: finding.violationFingerprint,
|
|
349
|
+
constraintId: finding.constraintId,
|
|
350
|
+
classification: finding.classification,
|
|
351
|
+
}));
|
|
352
|
+
overrideMap.set("L3-008", ValidationResult.fail(ValidatorId.create("L3-008"), errors, 0));
|
|
353
|
+
} else {
|
|
354
|
+
overrideMap.set("L3-008", ValidationResult.pass(ValidatorId.create("L3-008"), 0));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
308
359
|
const finalResults = definitions.map(
|
|
309
360
|
(definition) => overrideMap.get(definition.validatorId.value) ?? ValidationResult.skip(definition.validatorId),
|
|
310
361
|
);
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* DI 組み立て — validator-system の全依存関係を構築する
|
|
6
6
|
* @work-item-id WI-110 / WI-111 / WI-132 / WI-133 / WI-136 / WI-137 / WI-138 / WI-156
|
|
7
7
|
* @work-item-id WI-217
|
|
8
|
+
* @work-item-id WI-301
|
|
9
|
+
* @work-item-id WI-302
|
|
10
|
+
* @work-item-id WI-305
|
|
11
|
+
* @work-item-id WI-322
|
|
8
12
|
*/
|
|
9
13
|
|
|
10
14
|
import { join } from "node:path";
|
|
@@ -17,6 +21,7 @@ import { RunL2ValidatorsUseCase } from "./application/use-cases/run-l2-validator
|
|
|
17
21
|
import { RunL3ValidatorsUseCase } from "./application/use-cases/run-l3-validators-usecase.js";
|
|
18
22
|
import { RunL4ValidatorsUseCase } from "./application/use-cases/run-l4-validators-usecase.js";
|
|
19
23
|
import { RunQuickModeUseCase } from "./application/use-cases/run-quick-mode-usecase.js";
|
|
24
|
+
import { DesignChangeDeclarationPolicy } from "./domain/services/design-change-declaration-policy.js";
|
|
20
25
|
import {
|
|
21
26
|
ArchitectureSemanticAnalysisService,
|
|
22
27
|
type ArchitectureSemanticPolicy,
|
|
@@ -55,6 +60,8 @@ import { PhaseDependencyPhaseGatePolicyAdapter } from "./infrastructure/adapters
|
|
|
55
60
|
import { SourceFileTextScannerAdapter } from "./infrastructure/adapters/source-file-text-scanner-adapter.js";
|
|
56
61
|
import { TraceabilityMetadataPolicyAdapter } from "./infrastructure/adapters/traceability-metadata-policy-adapter.js";
|
|
57
62
|
import { TraceabilityWorkItemStatusPolicyAdapter } from "./infrastructure/adapters/traceability-work-item-status-policy-adapter.js";
|
|
63
|
+
import { WorldModelConstraintAdmissionAdapter } from "./infrastructure/adapters/world-model-constraint-admission-adapter.js";
|
|
64
|
+
import { WorldModelConstraintRederivationAdapter } from "./infrastructure/adapters/world-model-constraint-rederivation-adapter.js";
|
|
58
65
|
import { ReportValidationResultsHandler } from "./presentation/handlers/report-validation-results-handler.js";
|
|
59
66
|
import { RunQuickModeHandler } from "./presentation/handlers/run-quick-mode-handler.js";
|
|
60
67
|
import { RunValidatorsHandler } from "./presentation/handlers/run-validators-handler.js";
|
|
@@ -67,7 +74,9 @@ const DEFAULT_CONFIG = {
|
|
|
67
74
|
L3: {
|
|
68
75
|
enabled: true,
|
|
69
76
|
validators: ["L3-001", "L3-002", "L3-003", "L3-004", "L3-006", "L3-007"],
|
|
70
|
-
|
|
77
|
+
// WI-322 (github#37 残課題): カバレッジゲートはオプトイン(WI-317)。config なし環境の
|
|
78
|
+
// fallback で 90% を強制しない。0 = 正規の opt-out(L3-003 は透過 SKIP になる)。
|
|
79
|
+
coverageThreshold: 0,
|
|
71
80
|
bundleSizeLimit: 512000,
|
|
72
81
|
requirementMatrixPath: ".harness/requirement-test-matrix.json",
|
|
73
82
|
},
|
|
@@ -99,12 +108,6 @@ const DEFAULT_CONFIG = {
|
|
|
99
108
|
|
|
100
109
|
/** バリデータ定義カタログ */
|
|
101
110
|
export function buildDefaultRegistry(): ValidatorRegistry {
|
|
102
|
-
const defaultRule = ValidationRule.create({
|
|
103
|
-
ruleName: "default-rule",
|
|
104
|
-
errorTemplate: { code: "L2-001", severity: "error", messageTemplate: "{{message}}" },
|
|
105
|
-
fixExample: null,
|
|
106
|
-
});
|
|
107
|
-
|
|
108
111
|
const createDef = (
|
|
109
112
|
id: string,
|
|
110
113
|
layer: "L2" | "L3" | "L4",
|
|
@@ -134,6 +137,7 @@ export function buildDefaultRegistry(): ValidatorRegistry {
|
|
|
134
137
|
createDef("L2-015", "L2", "always", "ContractTraceabilityPolicyPort"),
|
|
135
138
|
// WI-258 / ADR-030 §Decision.3.②: L2-016 (coverage-attestation-gating, fail-closed, default-ON)。
|
|
136
139
|
createDef("L2-016", "L2", "always", "CoverageAttestationGatingPolicyPort"),
|
|
140
|
+
createDef("L2-017", "L2", "always", "WorldConstraintAdmissionPolicyPort"),
|
|
137
141
|
createDef("L3-001", "L3", "always"),
|
|
138
142
|
createDef("L3-002", "L3", "strictOnly"),
|
|
139
143
|
createDef("L3-003", "L3", "always"),
|
|
@@ -146,6 +150,7 @@ export function buildDefaultRegistry(): ValidatorRegistry {
|
|
|
146
150
|
// WI-268 / ADR-030 §Decision.1・§Decision.3.② 第2段: L3-007 (coverage-attestation-verification)
|
|
147
151
|
// は fail-closed / default-ON。L2-016 の authoritative 相棒。
|
|
148
152
|
createDef("L3-007", "L3", "always", "CoverageAttestationVerificationPolicyPort"),
|
|
153
|
+
createDef("L3-008", "L3", "always", "WorldConstraintRederivationPolicyPort"),
|
|
149
154
|
createDef("L4-001", "L4", "always"),
|
|
150
155
|
createDef("L4-002", "L4", "always"),
|
|
151
156
|
createDef("L4-003", "L4", "strictOnly"),
|
|
@@ -170,6 +175,7 @@ export interface ValidatorSystemModule {
|
|
|
170
175
|
aggregateValidationResultsUseCase: AggregateValidationResultsUseCase;
|
|
171
176
|
runFullValidationUseCase: RunFullValidationUseCase;
|
|
172
177
|
driftDetectionService: DriftDetectionService;
|
|
178
|
+
designChangeDeclarationPolicy: DesignChangeDeclarationPolicy;
|
|
173
179
|
handlers: {
|
|
174
180
|
runValidators: RunValidatorsHandler;
|
|
175
181
|
runQuickMode: RunQuickModeHandler;
|
|
@@ -184,6 +190,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
184
190
|
const defaultFailOnWarning = configData.validate?.failOnWarning ?? false;
|
|
185
191
|
const registry = buildDefaultRegistry();
|
|
186
192
|
const executionService = new ValidatorExecutionService({ configPort });
|
|
193
|
+
const designChangeDeclarationPolicy = new DesignChangeDeclarationPolicy();
|
|
187
194
|
const contractMapper = new ValidationResultContractMapper();
|
|
188
195
|
const phaseGatePolicyPort = new PhaseDependencyPhaseGatePolicyAdapter();
|
|
189
196
|
const metadataPolicyPort = new TraceabilityMetadataPolicyAdapter();
|
|
@@ -201,6 +208,14 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
201
208
|
// WI-258 / ADR-030 §Decision.3.②: L2-016 (coverage-attestation-gating) 用アダプタ。
|
|
202
209
|
// docs/product/construction/*/coverage_report.md を cwd 起点で走査する(targetPaths 非依存)。
|
|
203
210
|
const coverageAttestationGatingPolicyPort = new FileSystemCoverageAttestationGatingAdapter(process.cwd());
|
|
211
|
+
const worldConstraintAdmissionPolicyPort = new WorldModelConstraintAdmissionAdapter({
|
|
212
|
+
rootDir: process.cwd(),
|
|
213
|
+
resolvedConfig: (configData as { world?: import("../world-model/index.js").WorldResolvedConfigInput }).world,
|
|
214
|
+
});
|
|
215
|
+
const worldConstraintRederivationPolicyPort = new WorldModelConstraintRederivationAdapter({
|
|
216
|
+
rootDir: process.cwd(),
|
|
217
|
+
resolvedConfig: (configData as { world?: import("../world-model/index.js").WorldResolvedConfigInput }).world,
|
|
218
|
+
});
|
|
204
219
|
// WI-259 / ADR-030 §Decision.3.④: L3-006 (injection-scan, advisory) 用アダプタ。
|
|
205
220
|
// 指示搭載ファイル群(skills/**/SKILL.md / CLAUDE.md / AGENTS.md / agent-context / .claude/settings.json)を
|
|
206
221
|
// cwd 起点で走査する(targetPaths 非依存)。
|
|
@@ -249,6 +264,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
249
264
|
workItemStatusPolicyPort,
|
|
250
265
|
contractTraceabilityPolicyPort,
|
|
251
266
|
coverageAttestationGatingPolicyPort,
|
|
267
|
+
worldConstraintAdmissionPolicyPort,
|
|
252
268
|
});
|
|
253
269
|
|
|
254
270
|
// WI-227 / H16-03: L3-005 のスコープ対象 story-id を config から取得(既定 [])。
|
|
@@ -267,6 +283,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
267
283
|
performanceScannerPort,
|
|
268
284
|
injectionScanPolicyPort,
|
|
269
285
|
coverageAttestationVerificationPolicyPort,
|
|
286
|
+
worldConstraintRederivationPolicyPort,
|
|
270
287
|
acBoundStories,
|
|
271
288
|
});
|
|
272
289
|
|
|
@@ -367,6 +384,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
367
384
|
aggregateValidationResultsUseCase,
|
|
368
385
|
runFullValidationUseCase,
|
|
369
386
|
driftDetectionService,
|
|
387
|
+
designChangeDeclarationPolicy,
|
|
370
388
|
handlers,
|
|
371
389
|
};
|
|
372
390
|
}
|
|
@@ -4,11 +4,20 @@
|
|
|
4
4
|
*
|
|
5
5
|
* AcCoveragePolicyPort — nyquist-validation AcCoverageGatePolicy(L3-004)
|
|
6
6
|
*/
|
|
7
|
-
import type { HarnessErrorLike } from
|
|
7
|
+
import type { HarnessErrorLike } from "../value-objects/validation-result.js";
|
|
8
8
|
|
|
9
9
|
export interface AcCoveragePolicyPort {
|
|
10
10
|
checkCoverage(context: { matrixFilePath?: string }): Promise<{
|
|
11
11
|
passed: boolean;
|
|
12
12
|
errors: readonly HarnessErrorLike[];
|
|
13
|
+
/**
|
|
14
|
+
* WI-324: フレッシュプロジェクト(story 未作成・matrix 未生成)では L3-004 を
|
|
15
|
+
* fail-closed ではなく SKIP として扱う。true の場合、上位(RunL3ValidatorsUseCase)は
|
|
16
|
+
* skipReason 付きの skipWithReason 結果へ変換する。省略時(既存実装・既存モック)は
|
|
17
|
+
* 従来どおり passed/errors のみで判定される(後方互換 optional)。
|
|
18
|
+
*/
|
|
19
|
+
skipped?: boolean;
|
|
20
|
+
/** skipped=true のときの人間可読なスキップ理由。 */
|
|
21
|
+
skipReason?: string;
|
|
13
22
|
}>;
|
|
14
23
|
}
|