phasegate 0.254.0 → 0.264.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 +22 -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/templates/ci/aidlc-gate.yml +42 -2
- package/package.json +1 -1
- 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/world-model-open-obligations-query-adapter.ts +58 -0
- package/scripts/harness/agent-integration/presentation/session-start-hook.ts +37 -1
- 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 +35 -8
- package/scripts/harness/config-foundation/application/mappers/world-model-config-mapper.ts +15 -0
- package/scripts/harness/config-foundation/domain/harness-config.ts +67 -87
- package/scripts/harness/config-foundation/domain/services/preset-resolution-service.ts +77 -88
- 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/schemas/harness-config-v2.schema.json +83 -0
- package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +83 -0
- package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +18 -4
- package/scripts/harness/integrations/pre-commit.ts +169 -27
- package/scripts/harness/main.ts +174 -130
- 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 +34 -0
- package/scripts/harness/validator-system/composition-root.ts +21 -6
- 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 +38 -16
- 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,7 @@
|
|
|
2
2
|
* @layer application
|
|
3
3
|
* @unit validator-system
|
|
4
4
|
* @work-item-id WI-212
|
|
5
|
+
* @work-item-id WI-302
|
|
5
6
|
*
|
|
6
7
|
* RunL3ValidatorsUseCase — H08-02: L3バリデータ実行
|
|
7
8
|
*/
|
|
@@ -13,6 +14,7 @@ import type { InjectionScanPolicyPort } from "../../domain/ports/injection-scan-
|
|
|
13
14
|
import type { PerformanceScannerPort } from "../../domain/ports/performance-scanner-port.js";
|
|
14
15
|
import type { SecurityPatternScannerPort } from "../../domain/ports/security-pattern-scanner-port.js";
|
|
15
16
|
import type { ValidatorConfigPort } from "../../domain/ports/validator-config-port.js";
|
|
17
|
+
import type { WorldConstraintRederivationPolicyPort } from "../../domain/ports/world-constraint-rederivation-policy-port.js";
|
|
16
18
|
import { CoverageAttestationVerificationService } from "../../domain/services/coverage-attestation-verification-service.js";
|
|
17
19
|
import { InjectionPatternScanService } from "../../domain/services/injection-pattern-scan-service.js";
|
|
18
20
|
import {
|
|
@@ -20,6 +22,7 @@ import {
|
|
|
20
22
|
type ValidatorExecutionService,
|
|
21
23
|
} from "../../domain/services/validator-execution-service.js";
|
|
22
24
|
import { ValidatorLanguageCapabilityService } from "../../domain/services/validator-language-capability-service.js";
|
|
25
|
+
import { WorldConstraintRederivationService } from "../../domain/services/world-constraint-rederivation-service.js";
|
|
23
26
|
import type { ValidatorRegistry } from "../../domain/services/validator-registry.js";
|
|
24
27
|
import type { HarnessErrorLike } from "../../domain/value-objects/validation-result.js";
|
|
25
28
|
import { ValidationResult } from "../../domain/value-objects/validation-result.js";
|
|
@@ -54,6 +57,8 @@ export interface RunL3ValidatorsUseCaseDeps {
|
|
|
54
57
|
injectionScanPolicyPort?: InjectionScanPolicyPort;
|
|
55
58
|
/** WI-268 / ADR-030 §Decision.1・§Decision.3.② 第2段: L3-007 (coverage-attestation-verification, fail-closed) 用ポート。 */
|
|
56
59
|
coverageAttestationVerificationPolicyPort?: CoverageAttestationVerificationPolicyPort;
|
|
60
|
+
/** WI-302: L3-008 authoritative World clean-corpus re-derivation port. */
|
|
61
|
+
worldConstraintRederivationPolicyPort?: WorldConstraintRederivationPolicyPort;
|
|
57
62
|
/** L3-005 のスコープ対象 story-id(config layers.L3.acBoundStories 由来。既定 [])。 */
|
|
58
63
|
acBoundStories?: readonly string[];
|
|
59
64
|
}
|
|
@@ -70,10 +75,12 @@ export class RunL3ValidatorsUseCase {
|
|
|
70
75
|
private readonly performanceScannerPort?: PerformanceScannerPort;
|
|
71
76
|
private readonly injectionScanPolicyPort?: InjectionScanPolicyPort;
|
|
72
77
|
private readonly coverageAttestationVerificationPolicyPort?: CoverageAttestationVerificationPolicyPort;
|
|
78
|
+
private readonly worldConstraintRederivationPolicyPort?: WorldConstraintRederivationPolicyPort;
|
|
73
79
|
private readonly acBoundStories: readonly string[];
|
|
74
80
|
private readonly languageCapabilityService = new ValidatorLanguageCapabilityService();
|
|
75
81
|
private readonly injectionScanService = new InjectionPatternScanService();
|
|
76
82
|
private readonly coverageAttestationVerificationService = new CoverageAttestationVerificationService();
|
|
83
|
+
private readonly worldConstraintRederivationService = new WorldConstraintRederivationService();
|
|
77
84
|
|
|
78
85
|
constructor(deps: RunL3ValidatorsUseCaseDeps) {
|
|
79
86
|
this.registry = deps.validatorRegistry;
|
|
@@ -87,6 +94,7 @@ export class RunL3ValidatorsUseCase {
|
|
|
87
94
|
this.performanceScannerPort = deps.performanceScannerPort;
|
|
88
95
|
this.injectionScanPolicyPort = deps.injectionScanPolicyPort;
|
|
89
96
|
this.coverageAttestationVerificationPolicyPort = deps.coverageAttestationVerificationPolicyPort;
|
|
97
|
+
this.worldConstraintRederivationPolicyPort = deps.worldConstraintRederivationPolicyPort;
|
|
90
98
|
this.acBoundStories = deps.acBoundStories ?? [];
|
|
91
99
|
}
|
|
92
100
|
|
|
@@ -305,6 +313,32 @@ export class RunL3ValidatorsUseCase {
|
|
|
305
313
|
}
|
|
306
314
|
}
|
|
307
315
|
|
|
316
|
+
// WI-302 / ADR-030 trust root: L3-008 independently re-derives World obligations from the
|
|
317
|
+
// current corpus and versioned control declarations. The adapter has no persisted-report input.
|
|
318
|
+
if (this.worldConstraintRederivationPolicyPort) {
|
|
319
|
+
const l3008Result = overrideMap.get("L3-008");
|
|
320
|
+
if (l3008Result && !l3008Result.skipped) {
|
|
321
|
+
const observation = await this.worldConstraintRederivationPolicyPort.collect();
|
|
322
|
+
const findings = this.worldConstraintRederivationService.evaluate(observation);
|
|
323
|
+
if (findings.length > 0) {
|
|
324
|
+
const errors: HarnessErrorLike[] = findings.map((finding) => ({
|
|
325
|
+
code: { value: "L3-008", toString: () => "L3-008" },
|
|
326
|
+
severity: { value: finding.severity, toString: () => finding.severity },
|
|
327
|
+
message: finding.message,
|
|
328
|
+
suggestion: finding.suggestion,
|
|
329
|
+
sourcePath: finding.sourcePath,
|
|
330
|
+
ruleId: finding.ruleId,
|
|
331
|
+
violationFingerprint: finding.violationFingerprint,
|
|
332
|
+
constraintId: finding.constraintId,
|
|
333
|
+
classification: finding.classification,
|
|
334
|
+
}));
|
|
335
|
+
overrideMap.set("L3-008", ValidationResult.fail(ValidatorId.create("L3-008"), errors, 0));
|
|
336
|
+
} else {
|
|
337
|
+
overrideMap.set("L3-008", ValidationResult.pass(ValidatorId.create("L3-008"), 0));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
308
342
|
const finalResults = definitions.map(
|
|
309
343
|
(definition) => overrideMap.get(definition.validatorId.value) ?? ValidationResult.skip(definition.validatorId),
|
|
310
344
|
);
|
|
@@ -5,6 +5,9 @@
|
|
|
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
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
import { join } from "node:path";
|
|
@@ -17,6 +20,7 @@ import { RunL2ValidatorsUseCase } from "./application/use-cases/run-l2-validator
|
|
|
17
20
|
import { RunL3ValidatorsUseCase } from "./application/use-cases/run-l3-validators-usecase.js";
|
|
18
21
|
import { RunL4ValidatorsUseCase } from "./application/use-cases/run-l4-validators-usecase.js";
|
|
19
22
|
import { RunQuickModeUseCase } from "./application/use-cases/run-quick-mode-usecase.js";
|
|
23
|
+
import { DesignChangeDeclarationPolicy } from "./domain/services/design-change-declaration-policy.js";
|
|
20
24
|
import {
|
|
21
25
|
ArchitectureSemanticAnalysisService,
|
|
22
26
|
type ArchitectureSemanticPolicy,
|
|
@@ -55,6 +59,8 @@ import { PhaseDependencyPhaseGatePolicyAdapter } from "./infrastructure/adapters
|
|
|
55
59
|
import { SourceFileTextScannerAdapter } from "./infrastructure/adapters/source-file-text-scanner-adapter.js";
|
|
56
60
|
import { TraceabilityMetadataPolicyAdapter } from "./infrastructure/adapters/traceability-metadata-policy-adapter.js";
|
|
57
61
|
import { TraceabilityWorkItemStatusPolicyAdapter } from "./infrastructure/adapters/traceability-work-item-status-policy-adapter.js";
|
|
62
|
+
import { WorldModelConstraintAdmissionAdapter } from "./infrastructure/adapters/world-model-constraint-admission-adapter.js";
|
|
63
|
+
import { WorldModelConstraintRederivationAdapter } from "./infrastructure/adapters/world-model-constraint-rederivation-adapter.js";
|
|
58
64
|
import { ReportValidationResultsHandler } from "./presentation/handlers/report-validation-results-handler.js";
|
|
59
65
|
import { RunQuickModeHandler } from "./presentation/handlers/run-quick-mode-handler.js";
|
|
60
66
|
import { RunValidatorsHandler } from "./presentation/handlers/run-validators-handler.js";
|
|
@@ -99,12 +105,6 @@ const DEFAULT_CONFIG = {
|
|
|
99
105
|
|
|
100
106
|
/** バリデータ定義カタログ */
|
|
101
107
|
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
108
|
const createDef = (
|
|
109
109
|
id: string,
|
|
110
110
|
layer: "L2" | "L3" | "L4",
|
|
@@ -134,6 +134,7 @@ export function buildDefaultRegistry(): ValidatorRegistry {
|
|
|
134
134
|
createDef("L2-015", "L2", "always", "ContractTraceabilityPolicyPort"),
|
|
135
135
|
// WI-258 / ADR-030 §Decision.3.②: L2-016 (coverage-attestation-gating, fail-closed, default-ON)。
|
|
136
136
|
createDef("L2-016", "L2", "always", "CoverageAttestationGatingPolicyPort"),
|
|
137
|
+
createDef("L2-017", "L2", "always", "WorldConstraintAdmissionPolicyPort"),
|
|
137
138
|
createDef("L3-001", "L3", "always"),
|
|
138
139
|
createDef("L3-002", "L3", "strictOnly"),
|
|
139
140
|
createDef("L3-003", "L3", "always"),
|
|
@@ -146,6 +147,7 @@ export function buildDefaultRegistry(): ValidatorRegistry {
|
|
|
146
147
|
// WI-268 / ADR-030 §Decision.1・§Decision.3.② 第2段: L3-007 (coverage-attestation-verification)
|
|
147
148
|
// は fail-closed / default-ON。L2-016 の authoritative 相棒。
|
|
148
149
|
createDef("L3-007", "L3", "always", "CoverageAttestationVerificationPolicyPort"),
|
|
150
|
+
createDef("L3-008", "L3", "always", "WorldConstraintRederivationPolicyPort"),
|
|
149
151
|
createDef("L4-001", "L4", "always"),
|
|
150
152
|
createDef("L4-002", "L4", "always"),
|
|
151
153
|
createDef("L4-003", "L4", "strictOnly"),
|
|
@@ -170,6 +172,7 @@ export interface ValidatorSystemModule {
|
|
|
170
172
|
aggregateValidationResultsUseCase: AggregateValidationResultsUseCase;
|
|
171
173
|
runFullValidationUseCase: RunFullValidationUseCase;
|
|
172
174
|
driftDetectionService: DriftDetectionService;
|
|
175
|
+
designChangeDeclarationPolicy: DesignChangeDeclarationPolicy;
|
|
173
176
|
handlers: {
|
|
174
177
|
runValidators: RunValidatorsHandler;
|
|
175
178
|
runQuickMode: RunQuickModeHandler;
|
|
@@ -184,6 +187,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
184
187
|
const defaultFailOnWarning = configData.validate?.failOnWarning ?? false;
|
|
185
188
|
const registry = buildDefaultRegistry();
|
|
186
189
|
const executionService = new ValidatorExecutionService({ configPort });
|
|
190
|
+
const designChangeDeclarationPolicy = new DesignChangeDeclarationPolicy();
|
|
187
191
|
const contractMapper = new ValidationResultContractMapper();
|
|
188
192
|
const phaseGatePolicyPort = new PhaseDependencyPhaseGatePolicyAdapter();
|
|
189
193
|
const metadataPolicyPort = new TraceabilityMetadataPolicyAdapter();
|
|
@@ -201,6 +205,14 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
201
205
|
// WI-258 / ADR-030 §Decision.3.②: L2-016 (coverage-attestation-gating) 用アダプタ。
|
|
202
206
|
// docs/product/construction/*/coverage_report.md を cwd 起点で走査する(targetPaths 非依存)。
|
|
203
207
|
const coverageAttestationGatingPolicyPort = new FileSystemCoverageAttestationGatingAdapter(process.cwd());
|
|
208
|
+
const worldConstraintAdmissionPolicyPort = new WorldModelConstraintAdmissionAdapter({
|
|
209
|
+
rootDir: process.cwd(),
|
|
210
|
+
resolvedConfig: (configData as { world?: import("../world-model/index.js").WorldResolvedConfigInput }).world,
|
|
211
|
+
});
|
|
212
|
+
const worldConstraintRederivationPolicyPort = new WorldModelConstraintRederivationAdapter({
|
|
213
|
+
rootDir: process.cwd(),
|
|
214
|
+
resolvedConfig: (configData as { world?: import("../world-model/index.js").WorldResolvedConfigInput }).world,
|
|
215
|
+
});
|
|
204
216
|
// WI-259 / ADR-030 §Decision.3.④: L3-006 (injection-scan, advisory) 用アダプタ。
|
|
205
217
|
// 指示搭載ファイル群(skills/**/SKILL.md / CLAUDE.md / AGENTS.md / agent-context / .claude/settings.json)を
|
|
206
218
|
// cwd 起点で走査する(targetPaths 非依存)。
|
|
@@ -249,6 +261,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
249
261
|
workItemStatusPolicyPort,
|
|
250
262
|
contractTraceabilityPolicyPort,
|
|
251
263
|
coverageAttestationGatingPolicyPort,
|
|
264
|
+
worldConstraintAdmissionPolicyPort,
|
|
252
265
|
});
|
|
253
266
|
|
|
254
267
|
// WI-227 / H16-03: L3-005 のスコープ対象 story-id を config から取得(既定 [])。
|
|
@@ -267,6 +280,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
267
280
|
performanceScannerPort,
|
|
268
281
|
injectionScanPolicyPort,
|
|
269
282
|
coverageAttestationVerificationPolicyPort,
|
|
283
|
+
worldConstraintRederivationPolicyPort,
|
|
270
284
|
acBoundStories,
|
|
271
285
|
});
|
|
272
286
|
|
|
@@ -367,6 +381,7 @@ export function createValidatorSystemModule(config?: object): ValidatorSystemMod
|
|
|
367
381
|
aggregateValidationResultsUseCase,
|
|
368
382
|
runFullValidationUseCase,
|
|
369
383
|
driftDetectionService,
|
|
384
|
+
designChangeDeclarationPolicy,
|
|
370
385
|
handlers,
|
|
371
386
|
};
|
|
372
387
|
}
|
package/scripts/harness/validator-system/domain/ports/world-constraint-admission-policy-port.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @unit validator-system
|
|
2
|
+
// @layer domain
|
|
3
|
+
// @work-item-id WI-301
|
|
4
|
+
|
|
5
|
+
export type WorldAdmissionClassification = "adopted-legacy" | "new-structural" | "invalid-declaration" | "waived";
|
|
6
|
+
|
|
7
|
+
export interface WorldConstraintAdmissionObligation {
|
|
8
|
+
readonly ruleId: string;
|
|
9
|
+
readonly violationFingerprint: string;
|
|
10
|
+
readonly constraintId: string | null;
|
|
11
|
+
readonly classification: WorldAdmissionClassification;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WorldConstraintAdmissionDiagnostic {
|
|
15
|
+
readonly code: string;
|
|
16
|
+
readonly path: string;
|
|
17
|
+
readonly message: string;
|
|
18
|
+
readonly scope: "constraint" | "other";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface WorldConstraintAdmissionObservation {
|
|
22
|
+
readonly obligations: readonly WorldConstraintAdmissionObligation[];
|
|
23
|
+
readonly diagnostics: readonly WorldConstraintAdmissionDiagnostic[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface WorldConstraintAdmissionPolicyPort {
|
|
27
|
+
collect(): Promise<WorldConstraintAdmissionObservation>;
|
|
28
|
+
}
|
package/scripts/harness/validator-system/domain/ports/world-constraint-rederivation-policy-port.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// @unit validator-system
|
|
2
|
+
// @layer domain
|
|
3
|
+
// @work-item-id WI-302
|
|
4
|
+
|
|
5
|
+
import type { WorldConstraintAdmissionObservation } from "./world-constraint-admission-policy-port.js";
|
|
6
|
+
|
|
7
|
+
export type WorldConstraintRederivationObservation = WorldConstraintAdmissionObservation;
|
|
8
|
+
|
|
9
|
+
export interface WorldConstraintRederivationPolicyPort {
|
|
10
|
+
collect(): Promise<WorldConstraintRederivationObservation>;
|
|
11
|
+
}
|