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.
Files changed (65) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.ja.md +6 -3
  3. package/README.md +6 -3
  4. package/docs/contracts/attestation-v2.schema.json +110 -0
  5. package/docs/guide/cli-reference.md +12 -1
  6. package/docs/guide/configuration.md +56 -0
  7. package/docs/templates/ci/aidlc-gate.yml +42 -2
  8. package/package.json +1 -1
  9. package/scripts/harness/agent-integration/application/dto/open-world-obligations-context-dto.ts +30 -0
  10. package/scripts/harness/agent-integration/application/ports/world-obligations-query-port.ts +30 -0
  11. package/scripts/harness/agent-integration/application/usecases/get-open-world-obligations-context-usecase.ts +66 -0
  12. package/scripts/harness/agent-integration/infrastructure/adapters/world-model-open-obligations-query-adapter.ts +58 -0
  13. package/scripts/harness/agent-integration/presentation/session-start-hook.ts +37 -1
  14. package/scripts/harness/agent-integration/presentation/world-obligations-session-context.ts +60 -0
  15. package/scripts/harness/attestation/application/dto/attestation-document.ts +17 -4
  16. package/scripts/harness/attestation/application/mappers/attestation-record-mapper.ts +55 -4
  17. package/scripts/harness/attestation/application/ports/world-snapshot-root-provider.ts +10 -0
  18. package/scripts/harness/attestation/application/usecases/produce-attestation-usecase.ts +33 -7
  19. package/scripts/harness/attestation/composition-root.ts +5 -0
  20. package/scripts/harness/attestation/domain/entities/attestation-record.ts +37 -2
  21. package/scripts/harness/attestation/index.ts +7 -1
  22. package/scripts/harness/attestation/presentation/handlers/attest-handler.ts +5 -2
  23. package/scripts/harness/config-foundation/application/mappers/validator-system-config-mapper.ts +35 -8
  24. package/scripts/harness/config-foundation/application/mappers/world-model-config-mapper.ts +15 -0
  25. package/scripts/harness/config-foundation/domain/harness-config.ts +67 -87
  26. package/scripts/harness/config-foundation/domain/services/preset-resolution-service.ts +77 -88
  27. package/scripts/harness/config-foundation/domain/value-objects/world-config.ts +198 -0
  28. package/scripts/harness/config-foundation/index.ts +14 -15
  29. package/scripts/harness/config-foundation/infrastructure/presets/minimal.json +24 -0
  30. package/scripts/harness/config-foundation/infrastructure/presets/standard.json +24 -0
  31. package/scripts/harness/config-foundation/infrastructure/presets/strict.json +24 -0
  32. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v2.schema.json +83 -0
  33. package/scripts/harness/config-foundation/infrastructure/schemas/harness-config-v3.schema.json +83 -0
  34. package/scripts/harness/harness-api/domain/value-objects/ci-check-result.ts +18 -4
  35. package/scripts/harness/integrations/pre-commit.ts +169 -27
  36. package/scripts/harness/main.ts +174 -130
  37. package/scripts/harness/traceability-model/application/dto/changed-design-fragment-dto.ts +31 -0
  38. package/scripts/harness/traceability-model/application/facades/design-change-read-facade.ts +14 -0
  39. package/scripts/harness/traceability-model/application/ports/staged-design-change-source-port.ts +9 -0
  40. package/scripts/harness/traceability-model/composition-root.ts +5 -0
  41. package/scripts/harness/traceability-model/index.ts +9 -0
  42. package/scripts/harness/traceability-model/infrastructure/adapters/git-staged-design-change-adapter.ts +155 -0
  43. package/scripts/harness/validator-system/application/use-cases/run-l2-validators-usecase.ts +31 -0
  44. package/scripts/harness/validator-system/application/use-cases/run-l3-validators-usecase.ts +34 -0
  45. package/scripts/harness/validator-system/composition-root.ts +21 -6
  46. package/scripts/harness/validator-system/domain/ports/world-constraint-admission-policy-port.ts +28 -0
  47. package/scripts/harness/validator-system/domain/ports/world-constraint-rederivation-policy-port.ts +11 -0
  48. package/scripts/harness/validator-system/domain/services/design-change-declaration-policy.ts +75 -0
  49. package/scripts/harness/validator-system/domain/services/world-constraint-admission-service.ts +78 -0
  50. package/scripts/harness/validator-system/domain/services/world-constraint-rederivation-service.ts +76 -0
  51. package/scripts/harness/validator-system/domain/value-objects/validator-id.ts +4 -0
  52. package/scripts/harness/validator-system/infrastructure/adapters/harness-config-validator-config-adapter.ts +38 -16
  53. package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-admission-adapter.ts +56 -0
  54. package/scripts/harness/validator-system/infrastructure/adapters/world-model-constraint-rederivation-adapter.ts +56 -0
  55. package/scripts/harness/world-model/application/dto/pinned-design-endpoint-dto.ts +19 -0
  56. package/scripts/harness/world-model/application/dto/world-resolved-config-input.ts +92 -27
  57. package/scripts/harness/world-model/application/dto/world-snapshot-root-dto.ts +8 -0
  58. package/scripts/harness/world-model/application/facades/pinned-design-endpoint-facade.ts +63 -0
  59. package/scripts/harness/world-model/application/facades/world-snapshot-root-facade.ts +19 -0
  60. package/scripts/harness/world-model/application/usecases/derive-world-obligations-use-case.ts +3 -1
  61. package/scripts/harness/world-model/composition-root.ts +62 -33
  62. package/scripts/harness/world-model/index.ts +11 -0
  63. package/scripts/harness/world-model/infrastructure/adapters/attestation-fact-extractor.ts +48 -13
  64. package/scripts/harness/world-model/infrastructure/adapters/file-system-world-control-repository-adapters.ts +6 -4
  65. 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
+ }
@@ -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
  }
@@ -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
+ }
@@ -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
+ }