phasegate 0.229.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 +73 -1
- package/README.ja.md +31 -1
- package/README.md +30 -0
- package/docs/ADR/031-world-model-ownership-and-corpus-lifecycle.md +155 -0
- package/docs/ADR/032-world-node-identity.md +198 -0
- package/docs/ADR/033-world-snapshot-canonicalization.md +246 -0
- package/docs/ADR/034-world-constraint-semantics.md +218 -0
- package/docs/ADR/035-world-adoption-baseline-and-waiver.md +341 -0
- package/docs/ADR/036-world-model-and-doc-freshness.md +169 -0
- package/docs/ADR/037-world-cli-and-output-contract.md +398 -0
- package/docs/contracts/attestation-v2.schema.json +110 -0
- package/docs/contracts/requirement-test-matrix.schema.json +15 -0
- package/docs/contracts/world-baseline.schema.json +35 -0
- package/docs/contracts/world-constraints.schema.json +56 -0
- package/docs/contracts/world-debts.schema.json +32 -0
- package/docs/contracts/world-obligation-report.schema.json +259 -0
- package/docs/contracts/world-waivers.schema.json +32 -0
- package/docs/guide/cli-reference.md +45 -0
- 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/sha256-capability.ts +25 -0
- 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 +19 -4
- package/scripts/harness/attestation/domain/entities/attestation-record.ts +37 -2
- package/scripts/harness/attestation/index.ts +13 -2
- package/scripts/harness/attestation/infrastructure/adapters/node-crypto-content-hasher-adapter.ts +6 -6
- package/scripts/harness/attestation/infrastructure/adapters/node-crypto-sha256-capability.ts +19 -0
- 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/harness-api/domain/value-objects/known-harness-commands.ts +4 -1
- package/scripts/harness/integrations/pre-commit.ts +169 -27
- package/scripts/harness/main.ts +276 -126
- package/scripts/harness/nyquist-validation/application/dto/generate-matrix-output.ts +11 -0
- package/scripts/harness/nyquist-validation/application/usecases/check-ac-coverage-gate-usecase.ts +6 -0
- package/scripts/harness/nyquist-validation/application/usecases/generate-requirement-test-matrix-usecase.ts +8 -4
- package/scripts/harness/nyquist-validation/domain/entities/story-mapping.ts +29 -2
- package/scripts/harness/nyquist-validation/domain/services/ac-coverage-gate-policy.ts +28 -0
- package/scripts/harness/nyquist-validation/infrastructure/adapters/markdown-requirement-source-adapter.ts +71 -4
- package/scripts/harness/nyquist-validation/infrastructure/schema/matrix-schema-loader.ts +4 -0
- package/scripts/harness/traceability-model/application/dto/changed-design-fragment-dto.ts +31 -0
- package/scripts/harness/traceability-model/application/dto/traceability-world-read-dto.ts +67 -0
- package/scripts/harness/traceability-model/application/facades/design-change-read-facade.ts +14 -0
- package/scripts/harness/traceability-model/application/facades/traceability-world-read-facade.ts +372 -0
- package/scripts/harness/traceability-model/application/ports/staged-design-change-source-port.ts +9 -0
- package/scripts/harness/traceability-model/application/ports/traceability-world-read-source-port.ts +61 -0
- package/scripts/harness/traceability-model/composition-root.ts +26 -5
- package/scripts/harness/traceability-model/index.ts +26 -6
- package/scripts/harness/traceability-model/infrastructure/adapters/file-system-traceability-world-read-adapter.ts +223 -0
- package/scripts/harness/traceability-model/infrastructure/adapters/git-staged-design-change-adapter.ts +155 -0
- package/scripts/harness/traceability-model/infrastructure/parsers/story-catalog-parser.ts +86 -8
- 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-inspection-dto.ts +43 -0
- package/scripts/harness/world-model/application/dto/world-obligation-report-dto.ts +54 -0
- package/scripts/harness/world-model/application/dto/world-resolved-config-input.ts +127 -0
- 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/ports/obligation-report-writer-port.ts +7 -0
- package/scripts/harness/world-model/application/ports/world-control-declaration-repository-port.ts +57 -0
- package/scripts/harness/world-model/application/ports/world-fact-source-port.ts +17 -0
- package/scripts/harness/world-model/application/usecases/build-snapshot-use-case.ts +111 -0
- package/scripts/harness/world-model/application/usecases/derive-obligations-use-case.ts +155 -0
- package/scripts/harness/world-model/application/usecases/derive-world-obligations-use-case.ts +146 -0
- package/scripts/harness/world-model/application/usecases/inspect-world-use-case.ts +74 -0
- package/scripts/harness/world-model/application/usecases/pin-constraint-endpoint-use-case.ts +139 -0
- package/scripts/harness/world-model/composition-root.ts +247 -0
- package/scripts/harness/world-model/domain/entities/constraint-record.ts +148 -0
- package/scripts/harness/world-model/domain/entities/control-declarations.ts +274 -0
- package/scripts/harness/world-model/domain/entities/edge.ts +41 -0
- package/scripts/harness/world-model/domain/entities/extraction-diagnostic.ts +60 -0
- package/scripts/harness/world-model/domain/entities/snapshot.ts +75 -0
- package/scripts/harness/world-model/domain/entities/world-node.ts +210 -0
- package/scripts/harness/world-model/domain/ports/world-hashing-port.ts +8 -0
- package/scripts/harness/world-model/domain/services/canonical-json-serializer.ts +113 -0
- package/scripts/harness/world-model/domain/services/constraint-evaluator.ts +486 -0
- package/scripts/harness/world-model/domain/services/obligation-derivation-service.ts +199 -0
- package/scripts/harness/world-model/domain/services/policy-inputs-digest-deriver.ts +66 -0
- package/scripts/harness/world-model/domain/services/snapshot-root-deriver.ts +218 -0
- package/scripts/harness/world-model/domain/services/text-content-normalizer.ts +30 -0
- package/scripts/harness/world-model/domain/services/violation-fingerprint-deriver.ts +183 -0
- package/scripts/harness/world-model/domain/value-objects/artifact-kind.ts +58 -0
- package/scripts/harness/world-model/domain/value-objects/change-provenance.ts +137 -0
- package/scripts/harness/world-model/domain/value-objects/corpus-role.ts +57 -0
- package/scripts/harness/world-model/domain/value-objects/declared-key.ts +35 -0
- package/scripts/harness/world-model/domain/value-objects/evaluation-id.ts +41 -0
- package/scripts/harness/world-model/domain/value-objects/explicit-constraint-relation.ts +53 -0
- package/scripts/harness/world-model/domain/value-objects/explicit-node-alias.ts +30 -0
- package/scripts/harness/world-model/domain/value-objects/node-pin.ts +34 -0
- package/scripts/harness/world-model/domain/value-objects/path-key.ts +103 -0
- package/scripts/harness/world-model/domain/value-objects/sha256-digest.ts +39 -0
- package/scripts/harness/world-model/domain/value-objects/violation-fingerprint.ts +36 -0
- package/scripts/harness/world-model/domain/value-objects/wcr-rule-id.ts +59 -0
- package/scripts/harness/world-model/domain/value-objects/world-node-id.ts +222 -0
- package/scripts/harness/world-model/index.ts +33 -0
- package/scripts/harness/world-model/infrastructure/adapters/adr-fact-extractor.ts +27 -0
- package/scripts/harness/world-model/infrastructure/adapters/assembled-world-fact-source.ts +17 -0
- package/scripts/harness/world-model/infrastructure/adapters/attestation-fact-extractor.ts +323 -0
- package/scripts/harness/world-model/infrastructure/adapters/attestation-sha256-world-hashing-adapter.ts +15 -0
- package/scripts/harness/world-model/infrastructure/adapters/composite-design-fact-source.ts +23 -0
- package/scripts/harness/world-model/infrastructure/adapters/design-corpus-fact-extractor.ts +285 -0
- package/scripts/harness/world-model/infrastructure/adapters/design-fact-extraction.ts +63 -0
- package/scripts/harness/world-model/infrastructure/adapters/file-system-obligation-report-writer-adapter.ts +37 -0
- package/scripts/harness/world-model/infrastructure/adapters/file-system-world-control-repository-adapters.ts +332 -0
- package/scripts/harness/world-model/infrastructure/adapters/integrity-manifest-fact-extractor.ts +101 -0
- package/scripts/harness/world-model/infrastructure/adapters/json-fact-extractor-support.ts +151 -0
- package/scripts/harness/world-model/infrastructure/adapters/markdown-design-fact-extractor.ts +493 -0
- package/scripts/harness/world-model/infrastructure/adapters/matrix-fact-extractor.ts +283 -0
- package/scripts/harness/world-model/infrastructure/adapters/product-fact-extractor.ts +29 -0
- package/scripts/harness/world-model/infrastructure/adapters/proposal-fact-extractor.ts +29 -0
- package/scripts/harness/world-model/infrastructure/adapters/runtime-fact-extraction.ts +19 -0
- package/scripts/harness/world-model/infrastructure/adapters/source-metadata-fact-extractor.ts +22 -0
- package/scripts/harness/world-model/infrastructure/adapters/test-reference-source-fact-extractor.ts +22 -0
- package/scripts/harness/world-model/infrastructure/adapters/traceability-design-fact-adapter.ts +112 -0
- package/scripts/harness/world-model/infrastructure/adapters/traceability-world-read-facade-merger.ts +38 -0
- package/scripts/harness/world-model/infrastructure/adapters/type-script-source-fact-extractor.ts +236 -0
- package/scripts/harness/world-model/infrastructure/adapters/unit-fact-extractor.ts +71 -0
- package/scripts/harness/world-model/infrastructure/adapters/world-control-declaration-mapper.ts +383 -0
- package/scripts/harness/world-model/presentation/cli/world-command-support.ts +60 -0
- package/scripts/harness/world-model/presentation/cli/world-derive-command-handler.ts +109 -0
- package/scripts/harness/world-model/presentation/cli/world-inspect-command-handler.ts +194 -0
- package/scripts/harness/world-model/presentation/cli/world-pin-command-handler.ts +100 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* @work-item-id WI-141
|
|
5
5
|
* @work-item-id WI-109
|
|
6
6
|
* @work-item-id WI-189
|
|
7
|
+
* @work-item-id WI-305
|
|
7
8
|
*
|
|
8
9
|
* Pre-commit CLI entry.
|
|
9
10
|
* Runs L2 validators against staged TypeScript files AND design-document
|
|
@@ -18,14 +19,16 @@
|
|
|
18
19
|
|
|
19
20
|
import { execFileSync, execSync } from "node:child_process";
|
|
20
21
|
import { access, readFile } from "node:fs/promises";
|
|
21
|
-
import { createConfigFoundationModule } from "../config-foundation/composition-root.js";
|
|
22
22
|
import { toValidatorSystemConfig } from "../config-foundation/application/mappers/validator-system-config-mapper.js";
|
|
23
|
+
import { createConfigFoundationModule } from "../config-foundation/composition-root.js";
|
|
24
|
+
import { toWorldModelConfig, type WorldConfigDocument } from "../config-foundation/index.js";
|
|
23
25
|
import { createTraceabilityModelModule } from "../traceability-model/composition-root.js";
|
|
24
26
|
import type { ValidateMetadataCommandOutput } from "../traceability-model/presentation/cli/validate-metadata-command-handler.js";
|
|
25
27
|
import type { AggregatedValidationReport } from "../validator-system/application/dto/aggregated-validation-report.js";
|
|
26
28
|
import type { ValidationResultContract } from "../validator-system/application/dto/validation-result-contract.js";
|
|
27
29
|
import { createValidatorSystemModule } from "../validator-system/composition-root.js";
|
|
28
30
|
import { HumanValidationResultFormatter } from "../validator-system/presentation/formatters/human-validation-result-formatter.js";
|
|
31
|
+
import { createWorldModelModule } from "../world-model/index.js";
|
|
29
32
|
|
|
30
33
|
const GREEN = "\x1b[32m";
|
|
31
34
|
const RED = "\x1b[31m";
|
|
@@ -81,6 +84,17 @@ async function loadPreCommitImplementationExtensions(): Promise<readonly string[
|
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
|
|
87
|
+
async function loadWorldConfig(): Promise<WorldConfigDocument | undefined> {
|
|
88
|
+
const configMod = createConfigFoundationModule();
|
|
89
|
+
try {
|
|
90
|
+
const resolvedConfig = await configMod.usecases.loadResolvedConfigUseCase.execute();
|
|
91
|
+
return toWorldModelConfig(resolvedConfig.config);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
if (isConfigNotFoundError(err)) return undefined;
|
|
94
|
+
throw err;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
84
98
|
function isTestFile(path: string): boolean {
|
|
85
99
|
return TEST_FILE_SUFFIXES.some((suffix) => path.endsWith(suffix));
|
|
86
100
|
}
|
|
@@ -184,6 +198,29 @@ interface ValidateMetadataHandlerLike {
|
|
|
184
198
|
export interface PreCommitDeps {
|
|
185
199
|
readonly runL2ValidatorsUseCase: RunL2UseCaseLike;
|
|
186
200
|
readonly validateMetadataCommandHandler: ValidateMetadataHandlerLike;
|
|
201
|
+
readonly validateDesignChangeDeclaration?: (
|
|
202
|
+
input: DesignChangeDeclarationCheckInput,
|
|
203
|
+
) => Promise<DesignChangeDeclarationCheckResult>;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export interface DesignChangeDeclarationCheckInput {
|
|
207
|
+
readonly stagedFiles: readonly string[];
|
|
208
|
+
readonly commitMessage: string;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface DesignChangeDeclarationCheckFinding {
|
|
212
|
+
readonly code: string;
|
|
213
|
+
readonly path: string;
|
|
214
|
+
readonly declaredKey: string;
|
|
215
|
+
readonly expectedWorkItemIds: readonly string[];
|
|
216
|
+
readonly constraintIds: readonly string[];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface DesignChangeDeclarationCheckResult {
|
|
220
|
+
readonly status: "skipped" | "passed" | "warning" | "failed";
|
|
221
|
+
readonly checkedFragmentCount: number;
|
|
222
|
+
readonly findings: readonly DesignChangeDeclarationCheckFinding[];
|
|
223
|
+
readonly warningCodes: readonly string[];
|
|
187
224
|
}
|
|
188
225
|
|
|
189
226
|
export interface PreCommitResult {
|
|
@@ -202,6 +239,8 @@ export interface PreCommitOptions {
|
|
|
202
239
|
readonly implementationExtensions?: readonly string[];
|
|
203
240
|
readonly allowConditionalBypass?: boolean;
|
|
204
241
|
readonly evidenceRoot?: string;
|
|
242
|
+
/** Files observed by the commit-msg design declaration path, including deletions. */
|
|
243
|
+
readonly designChangeFiles?: readonly string[];
|
|
205
244
|
}
|
|
206
245
|
|
|
207
246
|
export interface BypassBlockerClass {
|
|
@@ -239,6 +278,21 @@ function getStagedFiles(): string[] {
|
|
|
239
278
|
}
|
|
240
279
|
}
|
|
241
280
|
|
|
281
|
+
function getStagedDesignChangeFiles(): string[] {
|
|
282
|
+
try {
|
|
283
|
+
const output = execFileSync("git", ["diff", "--cached", "--name-only", "--diff-filter=ACDMR"], {
|
|
284
|
+
encoding: "utf-8",
|
|
285
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
286
|
+
});
|
|
287
|
+
return output
|
|
288
|
+
.split("\n")
|
|
289
|
+
.map((filePath) => filePath.trim())
|
|
290
|
+
.filter((filePath) => filePath.length > 0);
|
|
291
|
+
} catch {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
242
296
|
function buildReport(results: readonly ValidationResultContract[]): AggregatedValidationReport {
|
|
243
297
|
const passed = results.filter((r) => r.passed && !r.skipped).length;
|
|
244
298
|
const failed = results.filter((r) => !r.passed && !r.skipped).length;
|
|
@@ -276,6 +330,56 @@ function hasWorkItemTrailer(commitMessage: string): boolean {
|
|
|
276
330
|
return WORK_ITEM_TRAILER_PATTERN.test(commitMessage);
|
|
277
331
|
}
|
|
278
332
|
|
|
333
|
+
function getWorkItemTrailerIds(commitMessage: string): readonly string[] {
|
|
334
|
+
return Object.freeze(
|
|
335
|
+
[...new Set([...commitMessage.matchAll(/^Work-Item:\s*(WI-\d+)\s*$/gm)].map((match) => match[1]))].sort(),
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function createDesignChangeDeclarationValidator(
|
|
340
|
+
worldConfig: WorldConfigDocument | undefined,
|
|
341
|
+
traceabilityMod: ReturnType<typeof createTraceabilityModelModule>,
|
|
342
|
+
policy: ReturnType<typeof createValidatorSystemModule>["designChangeDeclarationPolicy"],
|
|
343
|
+
): NonNullable<PreCommitDeps["validateDesignChangeDeclaration"]> {
|
|
344
|
+
return async ({ stagedFiles, commitMessage }) => {
|
|
345
|
+
if (worldConfig?.enabled !== true) {
|
|
346
|
+
return { status: "skipped", checkedFragmentCount: 0, findings: [], warningCodes: [] };
|
|
347
|
+
}
|
|
348
|
+
const changed = await traceabilityMod.designChangeReadFacade.observe(stagedFiles);
|
|
349
|
+
if (changed.state === "unavailable") {
|
|
350
|
+
return {
|
|
351
|
+
status: "warning",
|
|
352
|
+
checkedFragmentCount: 0,
|
|
353
|
+
findings: [],
|
|
354
|
+
warningCodes: changed.diagnostics.map((item) => item.code).sort(),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
const pinned = await createWorldModelModule({
|
|
358
|
+
rootDir: process.cwd(),
|
|
359
|
+
resolvedConfig: worldConfig,
|
|
360
|
+
}).pinnedDesignEndpointFacade.read();
|
|
361
|
+
if (pinned.state === "unavailable") {
|
|
362
|
+
return {
|
|
363
|
+
status: "warning",
|
|
364
|
+
checkedFragmentCount: 0,
|
|
365
|
+
findings: [],
|
|
366
|
+
warningCodes: pinned.diagnosticCodes.map((code) => `constraint-${code}`).sort(),
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const evaluation = policy.evaluate({
|
|
370
|
+
changedFragments: changed.fragments,
|
|
371
|
+
pinnedEndpoints: pinned.endpoints,
|
|
372
|
+
trailerWorkItemIds: getWorkItemTrailerIds(commitMessage),
|
|
373
|
+
});
|
|
374
|
+
return {
|
|
375
|
+
status: evaluation.findings.length > 0 ? "failed" : "passed",
|
|
376
|
+
checkedFragmentCount: evaluation.checkedFragmentCount,
|
|
377
|
+
findings: evaluation.findings,
|
|
378
|
+
warningCodes: [],
|
|
379
|
+
};
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
279
383
|
function extractTrailer(commitMessage: string, trailerName: string): string | undefined {
|
|
280
384
|
const pattern = new RegExp(`^${trailerName}:\\s*(.+?)\\s*$`, "m");
|
|
281
385
|
return pattern.exec(commitMessage)?.[1]?.trim();
|
|
@@ -366,10 +470,9 @@ function hasNonBypassableBlocker(blockers: readonly BypassBlockerClass[]): boole
|
|
|
366
470
|
}
|
|
367
471
|
|
|
368
472
|
function normalizeImplementationExtensions(extensions: readonly string[] | undefined): readonly string[] {
|
|
369
|
-
const rawExtensions =
|
|
370
|
-
? DEFAULT_IMPLEMENTATION_EXTENSIONS
|
|
371
|
-
|
|
372
|
-
return rawExtensions.map((extension) => extension.startsWith(".") ? extension : `.${extension}`);
|
|
473
|
+
const rawExtensions =
|
|
474
|
+
extensions === undefined || extensions.length === 0 ? DEFAULT_IMPLEMENTATION_EXTENSIONS : extensions;
|
|
475
|
+
return rawExtensions.map((extension) => (extension.startsWith(".") ? extension : `.${extension}`));
|
|
373
476
|
}
|
|
374
477
|
|
|
375
478
|
function hasAnyExtension(filePath: string, extensions: readonly string[]): boolean {
|
|
@@ -430,10 +533,12 @@ export async function runPreCommit(
|
|
|
430
533
|
}
|
|
431
534
|
|
|
432
535
|
const merged = mergePerUnitResults(runs);
|
|
433
|
-
blockerClasses.push(
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
536
|
+
blockerClasses.push(
|
|
537
|
+
...merged.flatMap((result) => {
|
|
538
|
+
const blocker = classifyValidatorFailure(result);
|
|
539
|
+
return blocker === undefined ? [] : [blocker];
|
|
540
|
+
}),
|
|
541
|
+
);
|
|
437
542
|
const report = buildReport(merged);
|
|
438
543
|
sections.push("");
|
|
439
544
|
sections.push(`${BOLD}== 実装ファイル (${implementationFiles.length} file(s)) ==${RESET}`);
|
|
@@ -469,6 +574,42 @@ export async function runPreCommit(
|
|
|
469
574
|
}
|
|
470
575
|
}
|
|
471
576
|
|
|
577
|
+
if (options.commitMessage !== undefined && deps.validateDesignChangeDeclaration !== undefined) {
|
|
578
|
+
const designResult = await deps.validateDesignChangeDeclaration({
|
|
579
|
+
stagedFiles: options.designChangeFiles ?? stagedFiles,
|
|
580
|
+
commitMessage: options.commitMessage,
|
|
581
|
+
});
|
|
582
|
+
if (designResult.status !== "skipped") {
|
|
583
|
+
sections.push("");
|
|
584
|
+
sections.push(`${BOLD}== Design change declaration ==${RESET}`);
|
|
585
|
+
if (designResult.status === "failed") {
|
|
586
|
+
for (const finding of designResult.findings) {
|
|
587
|
+
sections.push(
|
|
588
|
+
`${RED}FAIL${RESET} ${finding.code}: ${finding.path}#${finding.declaredKey} ` +
|
|
589
|
+
`(expected ${finding.expectedWorkItemIds.join(", ") || "an explicit Work Item"}; ` +
|
|
590
|
+
`constraints ${finding.constraintIds.join(", ")})`,
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
sections.push(`${DIM}Local commit-msg is forgeable; L3-008 remains authoritative.${RESET}`);
|
|
594
|
+
blockerClasses.push({
|
|
595
|
+
code: "design-change-declaration",
|
|
596
|
+
label: "design change declaration",
|
|
597
|
+
bypassable: false,
|
|
598
|
+
});
|
|
599
|
+
exitCode = maxExitCode(exitCode, 1);
|
|
600
|
+
} else if (designResult.status === "warning") {
|
|
601
|
+
sections.push(
|
|
602
|
+
`${DIM}WARN ${designResult.warningCodes.join(", ")}; local fast-path continues fail-open. ` +
|
|
603
|
+
`L3-008 remains authoritative.${RESET}`,
|
|
604
|
+
);
|
|
605
|
+
} else {
|
|
606
|
+
sections.push(
|
|
607
|
+
`${GREEN}PASS${RESET} ${designResult.checkedFragmentCount} pinned fragment(s) have matching Work-Item declarations.`,
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
472
613
|
if (options.commitMessage !== undefined) {
|
|
473
614
|
const bypassValidation = await validateBypassTrailers(options.commitMessage, options.evidenceRoot);
|
|
474
615
|
if (bypassValidation.hasAnyBypassTrailer) {
|
|
@@ -512,7 +653,10 @@ function getChangedFilesInRange(baseRef: string, headRef: string): string[] {
|
|
|
512
653
|
encoding: "utf-8",
|
|
513
654
|
stdio: ["ignore", "pipe", "ignore"],
|
|
514
655
|
});
|
|
515
|
-
return output
|
|
656
|
+
return output
|
|
657
|
+
.split("\n")
|
|
658
|
+
.map((line) => line.trim())
|
|
659
|
+
.filter((line) => line.length > 0);
|
|
516
660
|
} catch {
|
|
517
661
|
return [];
|
|
518
662
|
}
|
|
@@ -524,7 +668,10 @@ function getCommitMessagesInRange(baseRef: string, headRef: string): string[] {
|
|
|
524
668
|
encoding: "utf-8",
|
|
525
669
|
stdio: ["ignore", "pipe", "ignore"],
|
|
526
670
|
});
|
|
527
|
-
return output
|
|
671
|
+
return output
|
|
672
|
+
.split("\x1e")
|
|
673
|
+
.map((message) => message.trim())
|
|
674
|
+
.filter((message) => message.length > 0);
|
|
528
675
|
} catch {
|
|
529
676
|
return [];
|
|
530
677
|
}
|
|
@@ -539,10 +686,7 @@ function toBypassAuditStdout(stdout: string, changedFiles: readonly string[]): s
|
|
|
539
686
|
return stdout.replace("No staged files to check. Skipping.", "No changed files in range to check. Skipping.");
|
|
540
687
|
}
|
|
541
688
|
|
|
542
|
-
export async function runBypassAudit(
|
|
543
|
-
deps: PreCommitDeps,
|
|
544
|
-
options: BypassAuditOptions = {},
|
|
545
|
-
): Promise<PreCommitResult> {
|
|
689
|
+
export async function runBypassAudit(deps: PreCommitDeps, options: BypassAuditOptions = {}): Promise<PreCommitResult> {
|
|
546
690
|
const baseRef = options.baseRef ?? "origin/main";
|
|
547
691
|
const headRef = options.headRef ?? "HEAD";
|
|
548
692
|
const changedFiles = options.changedFiles ?? getChangedFilesInRange(baseRef, headRef);
|
|
@@ -580,10 +724,7 @@ export async function runPreCommitCli(): Promise<void> {
|
|
|
580
724
|
try {
|
|
581
725
|
const stagedFiles = getStagedFiles();
|
|
582
726
|
const validatorMod = createValidatorSystemModule(await loadValidatorSystemConfig());
|
|
583
|
-
const traceabilityMod = createTraceabilityModelModule(
|
|
584
|
-
process.cwd(),
|
|
585
|
-
await loadTraceabilityModelOptions(),
|
|
586
|
-
);
|
|
727
|
+
const traceabilityMod = createTraceabilityModelModule(process.cwd(), await loadTraceabilityModelOptions());
|
|
587
728
|
|
|
588
729
|
const result = await runPreCommit(
|
|
589
730
|
stagedFiles,
|
|
@@ -616,19 +757,23 @@ export async function runCommitMsgCli(commitMessagePath: string | undefined): Pr
|
|
|
616
757
|
const stagedFiles = getStagedFiles();
|
|
617
758
|
const commitMessage = await readFile(commitMessagePath, "utf-8");
|
|
618
759
|
const validatorMod = createValidatorSystemModule(await loadValidatorSystemConfig());
|
|
619
|
-
const traceabilityMod = createTraceabilityModelModule(
|
|
620
|
-
|
|
621
|
-
await loadTraceabilityModelOptions(),
|
|
622
|
-
);
|
|
760
|
+
const traceabilityMod = createTraceabilityModelModule(process.cwd(), await loadTraceabilityModelOptions());
|
|
761
|
+
const worldConfig = await loadWorldConfig();
|
|
623
762
|
|
|
624
763
|
const result = await runPreCommit(
|
|
625
764
|
stagedFiles,
|
|
626
765
|
{
|
|
627
766
|
runL2ValidatorsUseCase: validatorMod.runL2ValidatorsUseCase,
|
|
628
767
|
validateMetadataCommandHandler: traceabilityMod.validateMetadataCommandHandler,
|
|
768
|
+
validateDesignChangeDeclaration: createDesignChangeDeclarationValidator(
|
|
769
|
+
worldConfig,
|
|
770
|
+
traceabilityMod,
|
|
771
|
+
validatorMod.designChangeDeclarationPolicy,
|
|
772
|
+
),
|
|
629
773
|
},
|
|
630
774
|
{
|
|
631
775
|
commitMessage,
|
|
776
|
+
designChangeFiles: getStagedDesignChangeFiles(),
|
|
632
777
|
implementationExtensions: await loadPreCommitImplementationExtensions(),
|
|
633
778
|
evidenceRoot: process.cwd(),
|
|
634
779
|
},
|
|
@@ -652,10 +797,7 @@ function parseCliFlag(args: readonly string[], flag: string): string | undefined
|
|
|
652
797
|
export async function runBypassAuditCli(args: readonly string[] = []): Promise<void> {
|
|
653
798
|
try {
|
|
654
799
|
const validatorMod = createValidatorSystemModule(await loadValidatorSystemConfig());
|
|
655
|
-
const traceabilityMod = createTraceabilityModelModule(
|
|
656
|
-
process.cwd(),
|
|
657
|
-
await loadTraceabilityModelOptions(),
|
|
658
|
-
);
|
|
800
|
+
const traceabilityMod = createTraceabilityModelModule(process.cwd(), await loadTraceabilityModelOptions());
|
|
659
801
|
const result = await runBypassAudit(
|
|
660
802
|
{
|
|
661
803
|
runL2ValidatorsUseCase: validatorMod.runL2ValidatorsUseCase,
|