fix: measure repository-wide risk coverage
This commit is contained in:
@@ -1,119 +1,130 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"schemaVersion": 2,
|
||||
"repositoryBaseline": 285,
|
||||
"generatedPaths": [],
|
||||
"summary": {
|
||||
"lines": 80,
|
||||
"statements": 78,
|
||||
"functions": 85,
|
||||
"lines": 75,
|
||||
"statements": 73,
|
||||
"functions": 80,
|
||||
"branches": 68
|
||||
},
|
||||
"criticalModules": [
|
||||
{
|
||||
"path": "src/adapters/http/bounded-body-reader.ts",
|
||||
"owner": "http-runtime",
|
||||
"minimum": { "lines": 68, "statements": 66, "functions": 55, "branches": 55 }
|
||||
},
|
||||
{
|
||||
"path": "src/adapters/http/bounded-json.ts",
|
||||
"owner": "http-runtime",
|
||||
"minimum": { "lines": 85, "statements": 84, "functions": 95, "branches": 78 }
|
||||
},
|
||||
{
|
||||
"path": "src/adapters/http/http-execution-v3.ts",
|
||||
"owner": "http-runtime",
|
||||
"minimum": { "lines": 75, "statements": 73, "functions": 70, "branches": 52 }
|
||||
},
|
||||
{
|
||||
"path": "src/adapters/http/request-builder.ts",
|
||||
"owner": "http-runtime",
|
||||
"minimum": { "lines": 85, "statements": 85, "functions": 95, "branches": 82 }
|
||||
},
|
||||
{
|
||||
"path": "src/adapters/http/retry-policy.ts",
|
||||
"minimum": {
|
||||
"lines": 80,
|
||||
"statements": 78,
|
||||
"functions": 95,
|
||||
"branches": 78
|
||||
}
|
||||
"owner": "http-runtime",
|
||||
"minimum": { "lines": 80, "statements": 78, "functions": 95, "branches": 78 }
|
||||
},
|
||||
{
|
||||
"path": "src/adapters/query-cache/server-state-scope-runtime.ts",
|
||||
"owner": "server-state-runtime",
|
||||
"minimum": { "lines": 85, "statements": 85, "functions": 85, "branches": 75 }
|
||||
},
|
||||
{
|
||||
"path": "src/adapters/service-worker/service-worker-lifecycle.ts",
|
||||
"owner": "service-worker-runtime",
|
||||
"minimum": { "lines": 64, "statements": 60, "functions": 65, "branches": 43 }
|
||||
},
|
||||
{
|
||||
"path": "src/adapters/storage/browser-storage-adapter.ts",
|
||||
"minimum": {
|
||||
"lines": 60,
|
||||
"statements": 60,
|
||||
"functions": 70,
|
||||
"branches": 60
|
||||
}
|
||||
"owner": "storage-runtime",
|
||||
"minimum": { "lines": 60, "statements": 60, "functions": 70, "branches": 60 }
|
||||
},
|
||||
{
|
||||
"path": "src/adapters/telemetry/best-effort-telemetry.ts",
|
||||
"minimum": {
|
||||
"lines": 85,
|
||||
"statements": 85,
|
||||
"functions": 70,
|
||||
"branches": 75
|
||||
}
|
||||
"owner": "telemetry-runtime",
|
||||
"minimum": { "lines": 85, "statements": 85, "functions": 70, "branches": 75 }
|
||||
},
|
||||
{
|
||||
"path": "src/application/create-application.ts",
|
||||
"minimum": {
|
||||
"lines": 90,
|
||||
"statements": 90,
|
||||
"functions": 80,
|
||||
"branches": 68
|
||||
}
|
||||
"owner": "application-runtime",
|
||||
"minimum": { "lines": 90, "statements": 90, "functions": 80, "branches": 68 }
|
||||
},
|
||||
{
|
||||
"path": "src/application/policies/compatibility.ts",
|
||||
"minimum": {
|
||||
"lines": 95,
|
||||
"statements": 95,
|
||||
"functions": 95,
|
||||
"branches": 75
|
||||
}
|
||||
"owner": "application-policy",
|
||||
"minimum": { "lines": 95, "statements": 95, "functions": 95, "branches": 75 }
|
||||
},
|
||||
{
|
||||
"path": "src/application/policies/performance-budgets.ts",
|
||||
"minimum": {
|
||||
"lines": 80,
|
||||
"statements": 80,
|
||||
"functions": 80,
|
||||
"branches": 40
|
||||
}
|
||||
"owner": "application-policy",
|
||||
"minimum": { "lines": 80, "statements": 80, "functions": 80, "branches": 40 }
|
||||
},
|
||||
{
|
||||
"path": "src/application/policies/promotion-readiness.ts",
|
||||
"minimum": {
|
||||
"lines": 95,
|
||||
"statements": 95,
|
||||
"functions": 95,
|
||||
"branches": 95
|
||||
}
|
||||
"owner": "release-runtime",
|
||||
"minimum": { "lines": 95, "statements": 95, "functions": 95, "branches": 95 }
|
||||
},
|
||||
{
|
||||
"path": "src/application/use-cases/decide-chunk-recovery.ts",
|
||||
"minimum": {
|
||||
"lines": 90,
|
||||
"statements": 90,
|
||||
"functions": 95,
|
||||
"branches": 85
|
||||
}
|
||||
"owner": "application-runtime",
|
||||
"minimum": { "lines": 90, "statements": 90, "functions": 95, "branches": 85 }
|
||||
},
|
||||
{
|
||||
"path": "src/bootstrap/load-release-manifest.ts",
|
||||
"owner": "release-runtime",
|
||||
"minimum": { "lines": 90, "statements": 90, "functions": 90, "branches": 80 }
|
||||
},
|
||||
{
|
||||
"path": "src/bootstrap/read-bounded-boot-json.ts",
|
||||
"owner": "bootstrap-runtime",
|
||||
"minimum": { "lines": 71, "statements": 66, "functions": 48, "branches": 57 }
|
||||
},
|
||||
{
|
||||
"path": "src/contracts/diagnostics.ts",
|
||||
"minimum": {
|
||||
"lines": 68,
|
||||
"statements": 68,
|
||||
"functions": 95,
|
||||
"branches": 58
|
||||
}
|
||||
"owner": "diagnostics-contracts",
|
||||
"minimum": { "lines": 68, "statements": 68, "functions": 95, "branches": 58 }
|
||||
},
|
||||
{
|
||||
"path": "src/features/reference-feature/adapters/reference-http-gateway.ts",
|
||||
"minimum": {
|
||||
"lines": 90,
|
||||
"statements": 90,
|
||||
"functions": 90,
|
||||
"branches": 90
|
||||
}
|
||||
"owner": "reference-feature",
|
||||
"minimum": { "lines": 90, "statements": 90, "functions": 90, "branches": 90 }
|
||||
},
|
||||
{
|
||||
"path": "src/presentation/adapters/query/application-query.ts",
|
||||
"minimum": {
|
||||
"lines": 90,
|
||||
"statements": 90,
|
||||
"functions": 90,
|
||||
"branches": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "scripts/lib/registry-compatibility.ts",
|
||||
"minimum": {
|
||||
"lines": 80,
|
||||
"statements": 80,
|
||||
"functions": 85,
|
||||
"branches": 60
|
||||
}
|
||||
"owner": "presentation-runtime",
|
||||
"minimum": { "lines": 90, "statements": 90, "functions": 90, "branches": 80 }
|
||||
}
|
||||
]
|
||||
],
|
||||
"highRiskPaths": [
|
||||
"src/adapters/http/bounded-body-reader.ts",
|
||||
"src/adapters/http/bounded-json.ts",
|
||||
"src/adapters/http/http-execution-v3.ts",
|
||||
"src/adapters/http/request-builder.ts",
|
||||
"src/adapters/http/retry-policy.ts",
|
||||
"src/adapters/query-cache/server-state-scope-runtime.ts",
|
||||
"src/adapters/service-worker/service-worker-lifecycle.ts",
|
||||
"src/adapters/storage/browser-storage-adapter.ts",
|
||||
"src/adapters/telemetry/best-effort-telemetry.ts",
|
||||
"src/application/create-application.ts",
|
||||
"src/application/policies/compatibility.ts",
|
||||
"src/application/policies/performance-budgets.ts",
|
||||
"src/application/policies/promotion-readiness.ts",
|
||||
"src/application/use-cases/decide-chunk-recovery.ts",
|
||||
"src/bootstrap/load-release-manifest.ts",
|
||||
"src/bootstrap/read-bounded-boot-json.ts",
|
||||
"src/contracts/diagnostics.ts",
|
||||
"src/features/reference-feature/adapters/reference-http-gateway.ts",
|
||||
"src/presentation/adapters/query/application-query.ts"
|
||||
],
|
||||
"waivers": []
|
||||
}
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@
|
||||
"test:browser-file-storage-removal": "node scripts/test-browser-file-storage-runtime-removal.ts",
|
||||
"test:realtime-removal": "node scripts/test-realtime-runtime-removal.ts",
|
||||
"test:reference-feature": "vitest run tests/features/reference-feature --reporter=default --reporter=junit --outputFile.junit=artifacts/tests/reference-feature.xml --passWithNoTests",
|
||||
"test:coverage": "vitest run tests/runtime-schema tests/unit tests/component tests/integration tests/features/reference-feature --coverage --reporter=default --reporter=junit --outputFile.junit=artifacts/tests/coverage.xml && node scripts/check-risk-coverage.ts",
|
||||
"test:coverage": "vitest run tests/runtime-schema tests/unit tests/component tests/integration tests/features/reference-feature --coverage --maxWorkers=4 --reporter=default --reporter=junit --outputFile.junit=artifacts/tests/coverage.xml && node scripts/check-risk-coverage.ts",
|
||||
"check:coverage:fixture": "node scripts/check-risk-coverage.ts --summary tests/fixtures/coverage/below-threshold.json --artifact artifacts/quality/risk-coverage-fixture.json",
|
||||
"test:all": "corepack pnpm test:runtime-schema && corepack pnpm test:unit && corepack pnpm test:component && corepack pnpm test:integration && corepack pnpm test:reference-feature && corepack pnpm test:recipes",
|
||||
"verify:lockfile": "corepack pnpm install --frozen-lockfile",
|
||||
|
||||
@@ -1,100 +1,90 @@
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
type CoverageMetrics = Record<string, { pct: number }>;
|
||||
type CoveragePolicy = Readonly<{
|
||||
summary: Record<string, number>;
|
||||
criticalModules: readonly Readonly<{
|
||||
path: string;
|
||||
minimum: Record<string, number>;
|
||||
}>[];
|
||||
}>;
|
||||
type CoverageSummary = Record<string, CoverageMetrics>;
|
||||
type CoverageResult = Readonly<{
|
||||
scope: string;
|
||||
metric: string;
|
||||
threshold: number;
|
||||
received: number | undefined;
|
||||
passed: boolean;
|
||||
}>;
|
||||
import {
|
||||
buildProductionModuleInventory,
|
||||
evaluateRiskCoverage,
|
||||
parseRepositoryRiskCoveragePolicy,
|
||||
} from "./lib/risk-coverage.ts";
|
||||
|
||||
function argumentValue(name: string, fallback: string): string {
|
||||
function argumentValue(name: string, fallback?: string): string | undefined {
|
||||
const index = process.argv.indexOf(name);
|
||||
return index >= 0 && process.argv[index + 1]
|
||||
? process.argv[index + 1]
|
||||
: fallback;
|
||||
return index >= 0 ? process.argv[index + 1] : fallback;
|
||||
}
|
||||
|
||||
const policyPath = argumentValue(
|
||||
function requiredArgument(name: string, fallback: string): string {
|
||||
const value = argumentValue(name, fallback);
|
||||
if (!value) throw new TypeError(`${name} requires a path`);
|
||||
return value;
|
||||
}
|
||||
|
||||
function parseChangedFiles(value: unknown): readonly string[] {
|
||||
if (
|
||||
!Array.isArray(value) ||
|
||||
value.some((entry) => typeof entry !== "string") ||
|
||||
new Set(value).size !== value.length
|
||||
) {
|
||||
throw new TypeError("changed files input must be an array of unique paths");
|
||||
}
|
||||
return Object.freeze([...value] as string[]);
|
||||
}
|
||||
|
||||
const repositoryRoot = path.resolve(
|
||||
requiredArgument("--repository-root", process.cwd()),
|
||||
);
|
||||
const policyPath = requiredArgument(
|
||||
"--policy",
|
||||
"config/testing/risk-coverage.json",
|
||||
);
|
||||
const summaryPath = argumentValue(
|
||||
const summaryPath = requiredArgument(
|
||||
"--summary",
|
||||
"artifacts/tests/coverage/coverage-summary.json",
|
||||
);
|
||||
const artifactPath = argumentValue(
|
||||
const artifactPath = requiredArgument(
|
||||
"--artifact",
|
||||
"artifacts/quality/risk-coverage.json",
|
||||
);
|
||||
const policy = JSON.parse(
|
||||
await readFile(policyPath, "utf8"),
|
||||
) as CoveragePolicy;
|
||||
const summary = JSON.parse(
|
||||
await readFile(summaryPath, "utf8"),
|
||||
) as CoverageSummary;
|
||||
const failures: string[] = [];
|
||||
const results: CoverageResult[] = [];
|
||||
|
||||
function evaluate(
|
||||
scope: string,
|
||||
actual: CoverageMetrics,
|
||||
minimum: Record<string, number>,
|
||||
): void {
|
||||
for (const [metric, threshold] of Object.entries(minimum)) {
|
||||
const received = actual?.[metric]?.pct;
|
||||
const passed =
|
||||
typeof received === "number" &&
|
||||
Number.isFinite(received) &&
|
||||
received >= threshold;
|
||||
results.push({ scope, metric, threshold, received, passed });
|
||||
if (!passed) {
|
||||
failures.push(
|
||||
`${scope}.${metric} expected >= ${threshold}, received ${String(received)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
evaluate("total", summary.total, policy.summary);
|
||||
for (const modulePolicy of policy.criticalModules) {
|
||||
const key = Object.keys(summary).find(
|
||||
(candidate) =>
|
||||
candidate !== "total" &&
|
||||
candidate.replaceAll("\\", "/").endsWith(`/${modulePolicy.path}`),
|
||||
);
|
||||
if (!key) {
|
||||
failures.push(`critical module missing from coverage: ${modulePolicy.path}`);
|
||||
continue;
|
||||
}
|
||||
evaluate(modulePolicy.path, summary[key], modulePolicy.minimum);
|
||||
}
|
||||
|
||||
const changedFilesPath = argumentValue("--changed-files");
|
||||
const policy = parseRepositoryRiskCoveragePolicy(
|
||||
JSON.parse(await readFile(path.resolve(repositoryRoot, policyPath), "utf8")) as unknown,
|
||||
);
|
||||
const inventory = await buildProductionModuleInventory({
|
||||
repositoryRoot,
|
||||
generatedPaths: policy.generatedPaths,
|
||||
});
|
||||
const changedFiles = changedFilesPath
|
||||
? parseChangedFiles(
|
||||
JSON.parse(
|
||||
await readFile(path.resolve(repositoryRoot, changedFilesPath), "utf8"),
|
||||
) as unknown,
|
||||
)
|
||||
: [];
|
||||
const result = evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy,
|
||||
summary: JSON.parse(
|
||||
await readFile(path.resolve(repositoryRoot, summaryPath), "utf8"),
|
||||
) as unknown,
|
||||
changedFiles,
|
||||
});
|
||||
const artifact = {
|
||||
schemaVersion: 1,
|
||||
schemaVersion: 2,
|
||||
policy: policyPath,
|
||||
summary: summaryPath,
|
||||
status: failures.length === 0 ? "PASS" : "FAIL",
|
||||
results,
|
||||
failures,
|
||||
changedFiles: changedFilesPath ?? null,
|
||||
...result,
|
||||
};
|
||||
await mkdir(path.dirname(artifactPath), { recursive: true });
|
||||
await writeFile(artifactPath, `${JSON.stringify(artifact, null, 2)}\n`);
|
||||
const resolvedArtifactPath = path.resolve(repositoryRoot, artifactPath);
|
||||
await mkdir(path.dirname(resolvedArtifactPath), { recursive: true });
|
||||
await writeFile(resolvedArtifactPath, `${JSON.stringify(artifact, null, 2)}\n`);
|
||||
|
||||
if (failures.length > 0) {
|
||||
process.stderr.write(`Risk coverage failed:\n- ${failures.join("\n- ")}\n`);
|
||||
if (result.failures.length > 0) {
|
||||
process.stderr.write(
|
||||
`Risk coverage failed:\n- ${result.failures.join("\n- ")}\n`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
process.stdout.write(
|
||||
`Risk coverage: PASS (${results.length} scoped thresholds)\n`,
|
||||
`Risk coverage: PASS (${result.selectedTotal}/${result.repositoryTotal} production modules, ${result.results.length} thresholds)\n`,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,579 @@
|
||||
import { open, readdir, realpath, lstat } from "node:fs/promises";
|
||||
import type { Dirent, Stats } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import { normalizeRepositoryRelativePath } from "./repository-file-inventory.ts";
|
||||
|
||||
const coverageMetrics = [
|
||||
"lines",
|
||||
"statements",
|
||||
"functions",
|
||||
"branches",
|
||||
] as const;
|
||||
|
||||
export const REQUIRED_HIGH_RISK_PATHS = Object.freeze([
|
||||
"src/adapters/http/http-execution-v3.ts",
|
||||
"src/adapters/http/request-builder.ts",
|
||||
"src/adapters/http/bounded-body-reader.ts",
|
||||
"src/adapters/http/bounded-json.ts",
|
||||
"src/bootstrap/read-bounded-boot-json.ts",
|
||||
"src/adapters/service-worker/service-worker-lifecycle.ts",
|
||||
"src/adapters/query-cache/server-state-scope-runtime.ts",
|
||||
"src/bootstrap/load-release-manifest.ts",
|
||||
] as const);
|
||||
|
||||
type CoverageMetric = (typeof coverageMetrics)[number];
|
||||
type Thresholds = Readonly<Partial<Record<CoverageMetric, number>>>;
|
||||
type CoverageMetrics = Readonly<
|
||||
Record<CoverageMetric, Readonly<{ pct: number }>>
|
||||
>;
|
||||
|
||||
export type RiskCoveragePolicy = Readonly<{
|
||||
schemaVersion: 2;
|
||||
repositoryBaseline: number;
|
||||
generatedPaths: readonly string[];
|
||||
summary: Thresholds;
|
||||
criticalModules: readonly Readonly<{
|
||||
path: string;
|
||||
owner: string;
|
||||
minimum: Thresholds;
|
||||
}>[];
|
||||
highRiskPaths: readonly string[];
|
||||
waivers: readonly Readonly<{
|
||||
path: string;
|
||||
owner: string;
|
||||
reason: string;
|
||||
expiresAt: string;
|
||||
}>[];
|
||||
}>;
|
||||
|
||||
export type RiskCoverageResult = Readonly<{
|
||||
status: "PASS" | "FAIL";
|
||||
selectedTotal: number;
|
||||
repositoryTotal: number;
|
||||
uncoveredModules: readonly string[];
|
||||
ignoredCoveragePaths: readonly string[];
|
||||
results: readonly Readonly<{
|
||||
scope: string;
|
||||
metric: CoverageMetric;
|
||||
threshold: number;
|
||||
received: number;
|
||||
passed: boolean;
|
||||
}>[];
|
||||
failures: readonly string[];
|
||||
}>;
|
||||
|
||||
type InventoryOptions = Readonly<{
|
||||
repositoryRoot?: string;
|
||||
generatedPaths?: readonly string[];
|
||||
readDirectory?: (target: string) => Promise<Dirent[]>;
|
||||
lstatPath?: (target: string) => Promise<Stats>;
|
||||
realpathPath?: (target: string) => Promise<string>;
|
||||
assertReadable?: (target: string) => Promise<void>;
|
||||
}>;
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function assertExactKeys(
|
||||
value: Record<string, unknown>,
|
||||
allowed: readonly string[],
|
||||
label: string,
|
||||
): void {
|
||||
const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
|
||||
if (unknown.length > 0) {
|
||||
throw new TypeError(`${label} has unknown fields: ${unknown.sort().join(", ")}`);
|
||||
}
|
||||
}
|
||||
|
||||
function exactSourcePath(value: unknown, label: string): string {
|
||||
if (
|
||||
typeof value !== "string" ||
|
||||
["*", "?", "[", "]", "{", "}"].some((character) =>
|
||||
value.includes(character),
|
||||
)
|
||||
) {
|
||||
throw new TypeError(`${label} must be an exact repository-relative POSIX path`);
|
||||
}
|
||||
const normalized = normalizeRepositoryRelativePath(value, label);
|
||||
if (!normalized.startsWith("src/") || !/\.tsx?$/u.test(normalized)) {
|
||||
throw new TypeError(`${label} must identify a TypeScript module below src`);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function nonBlank(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new TypeError(`${label} must be a nonblank string`);
|
||||
}
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
function uniquePaths(
|
||||
value: unknown,
|
||||
label: string,
|
||||
options: Readonly<{ allowEmpty: boolean }> = { allowEmpty: true },
|
||||
): readonly string[] {
|
||||
if (!Array.isArray(value) || (!options.allowEmpty && value.length === 0)) {
|
||||
throw new TypeError(`${label} must be an array${options.allowEmpty ? "" : " with at least one path"}`);
|
||||
}
|
||||
const paths = value.map((entry) => exactSourcePath(entry, `${label} entry`));
|
||||
if (new Set(paths).size !== paths.length) {
|
||||
throw new TypeError(`${label} contains a duplicate path`);
|
||||
}
|
||||
return Object.freeze(paths);
|
||||
}
|
||||
|
||||
function thresholds(
|
||||
value: unknown,
|
||||
label: string,
|
||||
options: Readonly<{ requireAll: boolean }>,
|
||||
): Thresholds {
|
||||
if (!isRecord(value)) {
|
||||
throw new TypeError(`${label} must be an object`);
|
||||
}
|
||||
assertExactKeys(value, coverageMetrics, label);
|
||||
if (
|
||||
Object.keys(value).length === 0 ||
|
||||
(options.requireAll && coverageMetrics.some((metric) => !(metric in value)))
|
||||
) {
|
||||
throw new TypeError(`${label} must define ${options.requireAll ? "all " : "at least one "}coverage metric`);
|
||||
}
|
||||
const parsed: Partial<Record<CoverageMetric, number>> = {};
|
||||
for (const [metric, threshold] of Object.entries(value)) {
|
||||
if (
|
||||
typeof threshold !== "number" ||
|
||||
!Number.isFinite(threshold) ||
|
||||
threshold < 0 ||
|
||||
threshold > 100
|
||||
) {
|
||||
throw new TypeError(`${label}.${metric} minimum must be a finite number from 0 to 100`);
|
||||
}
|
||||
parsed[metric as CoverageMetric] = threshold;
|
||||
}
|
||||
return Object.freeze(parsed);
|
||||
}
|
||||
|
||||
export function parseRiskCoveragePolicy(
|
||||
value: unknown,
|
||||
options: Readonly<{ now?: number }> = {},
|
||||
): RiskCoveragePolicy {
|
||||
if (!isRecord(value)) {
|
||||
throw new TypeError("risk coverage policy must be an object");
|
||||
}
|
||||
assertExactKeys(
|
||||
value,
|
||||
[
|
||||
"schemaVersion",
|
||||
"repositoryBaseline",
|
||||
"generatedPaths",
|
||||
"summary",
|
||||
"criticalModules",
|
||||
"highRiskPaths",
|
||||
"waivers",
|
||||
],
|
||||
"risk coverage policy",
|
||||
);
|
||||
if (value.schemaVersion !== 2) {
|
||||
throw new TypeError("risk coverage policy schemaVersion must be 2");
|
||||
}
|
||||
if (
|
||||
typeof value.repositoryBaseline !== "number" ||
|
||||
!Number.isInteger(value.repositoryBaseline) ||
|
||||
value.repositoryBaseline <= 0
|
||||
) {
|
||||
throw new TypeError("repositoryBaseline must be a positive integer");
|
||||
}
|
||||
const generatedPaths = uniquePaths(value.generatedPaths, "generatedPaths");
|
||||
const highRiskPaths = uniquePaths(value.highRiskPaths, "highRiskPaths", {
|
||||
allowEmpty: false,
|
||||
});
|
||||
if (!Array.isArray(value.criticalModules) || value.criticalModules.length === 0) {
|
||||
throw new TypeError("criticalModules must be a non-empty array");
|
||||
}
|
||||
const criticalModules = value.criticalModules.map((candidate, index) => {
|
||||
if (!isRecord(candidate)) {
|
||||
throw new TypeError(`criticalModules[${index}] must be an object`);
|
||||
}
|
||||
assertExactKeys(candidate, ["path", "owner", "minimum"], `criticalModules[${index}]`);
|
||||
return Object.freeze({
|
||||
path: exactSourcePath(candidate.path, `criticalModules[${index}].path`),
|
||||
owner: nonBlank(candidate.owner, `criticalModules[${index}].owner`),
|
||||
minimum: thresholds(candidate.minimum, `criticalModules[${index}].minimum`, {
|
||||
requireAll: false,
|
||||
}),
|
||||
});
|
||||
});
|
||||
if (new Set(criticalModules.map((entry) => entry.path)).size !== criticalModules.length) {
|
||||
throw new TypeError("criticalModules contains a duplicate path");
|
||||
}
|
||||
if (!Array.isArray(value.waivers)) {
|
||||
throw new TypeError("waivers must be an array");
|
||||
}
|
||||
const currentTime = options.now ?? Date.now();
|
||||
const waivers = value.waivers.map((candidate, index) => {
|
||||
if (!isRecord(candidate)) {
|
||||
throw new TypeError(`waivers[${index}] must be an object`);
|
||||
}
|
||||
assertExactKeys(candidate, ["path", "owner", "reason", "expiresAt"], `waivers[${index}]`);
|
||||
const waiverPath = exactSourcePath(candidate.path, `waivers[${index}].path`);
|
||||
const expiresAt = nonBlank(candidate.expiresAt, `waivers[${index}].expiresAt`);
|
||||
const expiry = Date.parse(expiresAt);
|
||||
if (!Number.isFinite(expiry) || expiry <= currentTime) {
|
||||
throw new TypeError(`waivers[${index}] is expired or has an invalid expiry`);
|
||||
}
|
||||
if (!highRiskPaths.includes(waiverPath)) {
|
||||
throw new TypeError(`waivers[${index}] is stale because ${waiverPath} is not high-risk`);
|
||||
}
|
||||
return Object.freeze({
|
||||
path: waiverPath,
|
||||
owner: nonBlank(candidate.owner, `waivers[${index}].owner`),
|
||||
reason: nonBlank(candidate.reason, `waivers[${index}].reason`),
|
||||
expiresAt,
|
||||
});
|
||||
});
|
||||
if (new Set(waivers.map((entry) => entry.path)).size !== waivers.length) {
|
||||
throw new TypeError("waivers contains a duplicate path");
|
||||
}
|
||||
return Object.freeze({
|
||||
schemaVersion: 2,
|
||||
repositoryBaseline: value.repositoryBaseline,
|
||||
generatedPaths,
|
||||
summary: thresholds(value.summary, "summary", { requireAll: true }),
|
||||
criticalModules: Object.freeze(criticalModules),
|
||||
highRiskPaths,
|
||||
waivers: Object.freeze(waivers),
|
||||
});
|
||||
}
|
||||
|
||||
export function parseRepositoryRiskCoveragePolicy(
|
||||
value: unknown,
|
||||
options: Readonly<{ now?: number }> = {},
|
||||
): RiskCoveragePolicy {
|
||||
const policy = parseRiskCoveragePolicy(value, options);
|
||||
for (const requiredPath of REQUIRED_HIGH_RISK_PATHS) {
|
||||
if (!policy.highRiskPaths.includes(requiredPath)) {
|
||||
throw new TypeError(`required high-risk path is missing: ${requiredPath}`);
|
||||
}
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
async function defaultAssertReadable(target: string): Promise<void> {
|
||||
const handle = await open(target, "r");
|
||||
await handle.close();
|
||||
}
|
||||
|
||||
function isWithin(root: string, target: string): boolean {
|
||||
const relative = path.relative(root, target);
|
||||
return (
|
||||
relative === "" ||
|
||||
(relative !== ".." &&
|
||||
!relative.startsWith(`..${path.sep}`) &&
|
||||
!path.isAbsolute(relative))
|
||||
);
|
||||
}
|
||||
|
||||
function isProductionModule(relativePath: string): boolean {
|
||||
return (
|
||||
/\.tsx?$/u.test(relativePath) &&
|
||||
!/\.d\.ts$/u.test(relativePath) &&
|
||||
!/\.stories\.tsx?$/u.test(relativePath)
|
||||
);
|
||||
}
|
||||
|
||||
export async function buildProductionModuleInventory(
|
||||
options: InventoryOptions = {},
|
||||
): Promise<readonly string[]> {
|
||||
const repositoryRoot = path.resolve(options.repositoryRoot ?? process.cwd());
|
||||
const sourceRoot = path.join(repositoryRoot, "src");
|
||||
const readDirectory = options.readDirectory ?? ((target) => readdir(target, { withFileTypes: true }));
|
||||
const lstatPath = options.lstatPath ?? lstat;
|
||||
const realpathPath = options.realpathPath ?? realpath;
|
||||
const assertReadable = options.assertReadable ?? defaultAssertReadable;
|
||||
const generatedPaths = uniquePaths(options.generatedPaths ?? [], "generatedPaths");
|
||||
const generated = new Set(generatedPaths);
|
||||
const repositoryRealpath = await realpathPath(repositoryRoot);
|
||||
const sourceMetadata = await lstatPath(sourceRoot);
|
||||
if (!sourceMetadata.isDirectory() || sourceMetadata.isSymbolicLink()) {
|
||||
throw new TypeError("production source root is not a regular directory: src");
|
||||
}
|
||||
const sourceRealpath = await realpathPath(sourceRoot);
|
||||
if (!isWithin(repositoryRealpath, sourceRealpath)) {
|
||||
throw new TypeError("production source root is outside repository");
|
||||
}
|
||||
|
||||
const allModules: string[] = [];
|
||||
async function visit(relativeDirectory: string): Promise<void> {
|
||||
const absoluteDirectory = path.join(repositoryRoot, relativeDirectory);
|
||||
const entries = await readDirectory(absoluteDirectory);
|
||||
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
||||
const relativeTarget = normalizeRepositoryRelativePath(
|
||||
`${relativeDirectory}/${entry.name}`,
|
||||
"production inventory path",
|
||||
);
|
||||
const absoluteTarget = path.join(repositoryRoot, relativeTarget);
|
||||
const metadata = await lstatPath(absoluteTarget);
|
||||
if (metadata.isSymbolicLink() || entry.isSymbolicLink()) {
|
||||
throw new TypeError(`production inventory path is a symlink: ${relativeTarget}`);
|
||||
}
|
||||
if (metadata.isDirectory()) {
|
||||
await visit(relativeTarget);
|
||||
continue;
|
||||
}
|
||||
if (!isProductionModule(relativeTarget)) continue;
|
||||
if (!metadata.isFile()) {
|
||||
throw new TypeError(`production inventory path is not a regular file: ${relativeTarget}`);
|
||||
}
|
||||
const resolvedTarget = await realpathPath(absoluteTarget);
|
||||
if (!isWithin(repositoryRealpath, resolvedTarget)) {
|
||||
throw new TypeError(`production inventory path is outside repository: ${relativeTarget}`);
|
||||
}
|
||||
try {
|
||||
await assertReadable(absoluteTarget);
|
||||
} catch (error) {
|
||||
throw new Error(`production inventory file is unreadable: ${relativeTarget}`, {
|
||||
cause: error,
|
||||
});
|
||||
}
|
||||
allModules.push(relativeTarget);
|
||||
}
|
||||
}
|
||||
await visit("src");
|
||||
for (const generatedPath of generatedPaths) {
|
||||
if (!allModules.includes(generatedPath)) {
|
||||
throw new TypeError(`generated path is stale or not a production module: ${generatedPath}`);
|
||||
}
|
||||
}
|
||||
const inventory = allModules.filter((file) => !generated.has(file)).sort();
|
||||
if (inventory.length === 0) {
|
||||
throw new Error("production module inventory is empty");
|
||||
}
|
||||
if (new Set(inventory).size !== inventory.length) {
|
||||
throw new TypeError("production module inventory contains a duplicate path");
|
||||
}
|
||||
return Object.freeze(inventory);
|
||||
}
|
||||
|
||||
function coveragePath(repositoryRoot: string, rawPath: string): string {
|
||||
if (rawPath.includes("\\") || rawPath.includes("\0")) {
|
||||
throw new TypeError("coverage path must use POSIX separators");
|
||||
}
|
||||
if (path.isAbsolute(rawPath)) {
|
||||
const relative = path.relative(repositoryRoot, rawPath).split(path.sep).join("/");
|
||||
if (!relative || relative === ".." || relative.startsWith("../")) {
|
||||
throw new TypeError(`coverage path is outside repository: ${rawPath}`);
|
||||
}
|
||||
return normalizeRepositoryRelativePath(relative, "coverage path");
|
||||
}
|
||||
return normalizeRepositoryRelativePath(rawPath, "coverage path");
|
||||
}
|
||||
|
||||
function parseCoverageMetrics(value: unknown, label: string): CoverageMetrics {
|
||||
if (!isRecord(value)) throw new TypeError(`${label} must be an object`);
|
||||
const unknownMetrics = Object.keys(value).filter(
|
||||
(metric) =>
|
||||
metric !== "branchesTrue" &&
|
||||
!coverageMetrics.includes(metric as CoverageMetric),
|
||||
);
|
||||
if (unknownMetrics.length > 0) {
|
||||
throw new TypeError(
|
||||
`${label} has unknown coverage metric keys: ${unknownMetrics.sort().join(", ")}`,
|
||||
);
|
||||
}
|
||||
if (value.branchesTrue !== undefined) {
|
||||
if (!isRecord(value.branchesTrue)) {
|
||||
throw new TypeError(`${label}.branchesTrue must be an object`);
|
||||
}
|
||||
assertExactKeys(
|
||||
value.branchesTrue,
|
||||
["total", "covered", "skipped", "pct"],
|
||||
`${label}.branchesTrue`,
|
||||
);
|
||||
for (const count of ["total", "covered", "skipped"] as const) {
|
||||
const received = value.branchesTrue[count];
|
||||
if (
|
||||
typeof received !== "number" ||
|
||||
!Number.isSafeInteger(received) ||
|
||||
received < 0
|
||||
) {
|
||||
throw new TypeError(
|
||||
`${label}.branchesTrue.${count} must be a nonnegative safe integer`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const pct = value.branchesTrue.pct;
|
||||
if (typeof pct !== "number" || !Number.isFinite(pct) || pct < 0 || pct > 100) {
|
||||
throw new TypeError(
|
||||
`${label}.branchesTrue.pct must be a finite number from 0 to 100`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
(value.branchesTrue.covered as number) >
|
||||
(value.branchesTrue.total as number) ||
|
||||
(value.branchesTrue.skipped as number) >
|
||||
(value.branchesTrue.total as number)
|
||||
) {
|
||||
throw new TypeError(`${label}.branchesTrue counts exceed total`);
|
||||
}
|
||||
}
|
||||
const parsed = {} as Record<CoverageMetric, { pct: number }>;
|
||||
for (const metric of coverageMetrics) {
|
||||
const rawMetric = value[metric];
|
||||
if (!isRecord(rawMetric)) {
|
||||
throw new TypeError(`${label}.${metric} must be an object`);
|
||||
}
|
||||
assertExactKeys(
|
||||
rawMetric,
|
||||
["total", "covered", "skipped", "pct"],
|
||||
`${label}.${metric}`,
|
||||
);
|
||||
const suppliedCounts = ["total", "covered", "skipped"].filter(
|
||||
(count) => rawMetric[count] !== undefined,
|
||||
);
|
||||
if (suppliedCounts.length !== 0 && suppliedCounts.length !== 3) {
|
||||
throw new TypeError(
|
||||
`${label}.${metric} must define total, covered, and skipped together`,
|
||||
);
|
||||
}
|
||||
for (const count of suppliedCounts) {
|
||||
const received = rawMetric[count];
|
||||
if (
|
||||
typeof received !== "number" ||
|
||||
!Number.isSafeInteger(received) ||
|
||||
received < 0
|
||||
) {
|
||||
throw new TypeError(
|
||||
`${label}.${metric}.${count} must be a nonnegative safe integer`,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (
|
||||
suppliedCounts.length === 3 &&
|
||||
((rawMetric.covered as number) > (rawMetric.total as number) ||
|
||||
(rawMetric.skipped as number) > (rawMetric.total as number))
|
||||
) {
|
||||
throw new TypeError(`${label}.${metric} counts exceed total`);
|
||||
}
|
||||
const pct = rawMetric.pct;
|
||||
if (typeof pct !== "number" || !Number.isFinite(pct) || pct < 0 || pct > 100) {
|
||||
throw new TypeError(`${label}.${metric}.pct must be a finite number from 0 to 100`);
|
||||
}
|
||||
parsed[metric] = { pct };
|
||||
}
|
||||
return Object.freeze(parsed);
|
||||
}
|
||||
|
||||
export function evaluateRiskCoverage(input: Readonly<{
|
||||
repositoryRoot?: string;
|
||||
inventory: readonly string[];
|
||||
policy: RiskCoveragePolicy;
|
||||
summary: unknown;
|
||||
changedFiles?: readonly string[];
|
||||
now?: number;
|
||||
}>): RiskCoverageResult {
|
||||
const repositoryRoot = path.resolve(input.repositoryRoot ?? process.cwd());
|
||||
if (input.inventory.length === 0) {
|
||||
throw new TypeError("production module inventory is empty");
|
||||
}
|
||||
const inventory = input.inventory.map((file) => exactSourcePath(file, "inventory path"));
|
||||
if (new Set(inventory).size !== inventory.length) {
|
||||
throw new TypeError("production module inventory contains a duplicate path");
|
||||
}
|
||||
if (!isRecord(input.summary) || !("total" in input.summary)) {
|
||||
throw new TypeError("coverage summary must contain total metrics");
|
||||
}
|
||||
const totalMetrics = parseCoverageMetrics(input.summary.total, "coverage total");
|
||||
const selected = new Map<string, CoverageMetrics>();
|
||||
for (const [rawPath, rawMetrics] of Object.entries(input.summary)) {
|
||||
if (rawPath === "total") continue;
|
||||
const normalized = coveragePath(repositoryRoot, rawPath);
|
||||
if (selected.has(normalized)) {
|
||||
throw new TypeError(`duplicate coverage path: ${normalized}`);
|
||||
}
|
||||
selected.set(normalized, parseCoverageMetrics(rawMetrics, `coverage ${normalized}`));
|
||||
}
|
||||
|
||||
const failures: string[] = [];
|
||||
const results: Array<{
|
||||
scope: string;
|
||||
metric: CoverageMetric;
|
||||
threshold: number;
|
||||
received: number;
|
||||
passed: boolean;
|
||||
}> = [];
|
||||
function evaluate(scope: string, actual: CoverageMetrics, minimum: Thresholds): void {
|
||||
for (const metric of coverageMetrics) {
|
||||
const threshold = minimum[metric];
|
||||
if (threshold === undefined) continue;
|
||||
const received = actual[metric].pct;
|
||||
const passed = received >= threshold;
|
||||
results.push({ scope, metric, threshold, received, passed });
|
||||
if (!passed) {
|
||||
failures.push(`${scope}.${metric} expected >= ${threshold}, received ${received}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
evaluate("total", totalMetrics, input.policy.summary);
|
||||
const inventorySet = new Set(inventory);
|
||||
if (inventory.length < input.policy.repositoryBaseline) {
|
||||
failures.push(
|
||||
`repository module baseline expected >= ${input.policy.repositoryBaseline}, received ${inventory.length}`,
|
||||
);
|
||||
}
|
||||
const uncoveredModules = inventory.filter((file) => !selected.has(file)).sort();
|
||||
const selectedModules = inventory.filter((file) => selected.has(file));
|
||||
const ignoredCoveragePaths = [...selected.keys()]
|
||||
.filter((file) => !inventorySet.has(file))
|
||||
.sort();
|
||||
failures.push(
|
||||
...uncoveredModules.map((file) => `production module missing from coverage: ${file}`),
|
||||
);
|
||||
for (const modulePolicy of input.policy.criticalModules) {
|
||||
if (!inventorySet.has(modulePolicy.path)) {
|
||||
failures.push(`critical module is outside production inventory: ${modulePolicy.path}`);
|
||||
continue;
|
||||
}
|
||||
const actual = selected.get(modulePolicy.path);
|
||||
if (!actual) {
|
||||
failures.push(`critical module missing from coverage: ${modulePolicy.path}`);
|
||||
continue;
|
||||
}
|
||||
evaluate(modulePolicy.path, actual, modulePolicy.minimum);
|
||||
}
|
||||
|
||||
const owners = new Set(input.policy.criticalModules.map((entry) => entry.path));
|
||||
const waivers = new Set(input.policy.waivers.map((entry) => entry.path));
|
||||
const highRisk = new Set(input.policy.highRiskPaths);
|
||||
for (const highRiskPath of input.policy.highRiskPaths) {
|
||||
if (!owners.has(highRiskPath) && !waivers.has(highRiskPath)) {
|
||||
failures.push(`high-risk module has no owner or waiver: ${highRiskPath}`);
|
||||
}
|
||||
}
|
||||
for (const changedFile of input.changedFiles ?? []) {
|
||||
const normalized = exactSourcePath(changedFile, "changed file");
|
||||
if (highRisk.has(normalized) && !owners.has(normalized) && !waivers.has(normalized)) {
|
||||
failures.push(`changed high-risk module has no owner or waiver: ${normalized}`);
|
||||
}
|
||||
}
|
||||
for (const waiver of input.policy.waivers) {
|
||||
if (!inventorySet.has(waiver.path) || !highRisk.has(waiver.path)) {
|
||||
failures.push(`coverage waiver is stale: ${waiver.path}`);
|
||||
}
|
||||
const expiry = Date.parse(waiver.expiresAt);
|
||||
if (!Number.isFinite(expiry) || expiry <= (input.now ?? Date.now())) {
|
||||
failures.push(`coverage waiver is expired: ${waiver.path}`);
|
||||
}
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
status: failures.length === 0 ? "PASS" : "FAIL",
|
||||
selectedTotal: selectedModules.length,
|
||||
repositoryTotal: inventory.length,
|
||||
uncoveredModules: Object.freeze(uncoveredModules),
|
||||
ignoredCoveragePaths: Object.freeze(ignoredCoveragePaths),
|
||||
results: Object.freeze(results),
|
||||
failures: Object.freeze(failures),
|
||||
});
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
access,
|
||||
cp,
|
||||
mkdir,
|
||||
mkdtemp,
|
||||
readFile,
|
||||
readdir,
|
||||
rm,
|
||||
@@ -11,7 +12,11 @@ import {
|
||||
} from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
const fixtureRoot = path.resolve(".tmp/reference-feature-removal");
|
||||
const fixtureParent = path.resolve(".tmp");
|
||||
await mkdir(fixtureParent, { recursive: true });
|
||||
const fixtureRoot = await mkdtemp(
|
||||
path.join(fixtureParent, "reference-feature-removal-"),
|
||||
);
|
||||
const pnpmCli = requireEnvironment("npm_execpath");
|
||||
const featureSource = "src/features/reference-feature";
|
||||
const featureTests = "tests/features/reference-feature";
|
||||
@@ -130,7 +135,14 @@ const emptyMessages = `export const INSTALLED_MESSAGE_CATALOGS = Object.freeze({
|
||||
`;
|
||||
|
||||
type CoveragePolicy = {
|
||||
criticalModules: Array<{ path?: string }>;
|
||||
repositoryBaseline: number;
|
||||
generatedPaths: string[];
|
||||
criticalModules: Array<{
|
||||
path?: string;
|
||||
minimum?: Record<string, number>;
|
||||
}>;
|
||||
highRiskPaths: string[];
|
||||
waivers: Array<{ path?: string }>;
|
||||
};
|
||||
|
||||
type EvidenceContribution = Readonly<{ owner?: string }>;
|
||||
@@ -170,13 +182,20 @@ function runPnpm(script: string, extra: string[] = []): boolean {
|
||||
return result.status === 0;
|
||||
}
|
||||
|
||||
await rm(fixtureRoot, { recursive: true, force: true });
|
||||
await mkdir(fixtureRoot, { recursive: true });
|
||||
for (const target of copyTargets) {
|
||||
await cp(target, path.join(fixtureRoot, target), { recursive: true });
|
||||
}
|
||||
await symlink(path.resolve("node_modules"), path.join(fixtureRoot, "node_modules"), "dir");
|
||||
|
||||
const removedProductionModuleCount = (
|
||||
await filesBelow(path.join(fixtureRoot, featureSource))
|
||||
).filter(
|
||||
(file) =>
|
||||
/\.tsx?$/u.test(file) &&
|
||||
!/\.d\.ts$/u.test(file) &&
|
||||
!/\.stories\.tsx?$/u.test(file),
|
||||
).length;
|
||||
|
||||
for (const ownedPath of featureOwnedPaths) {
|
||||
await rm(path.join(fixtureRoot, ownedPath), {
|
||||
recursive: true,
|
||||
@@ -204,18 +223,6 @@ await writeFile(
|
||||
emptyContractContributions,
|
||||
);
|
||||
|
||||
const vitestConfigFile = path.join(fixtureRoot, "vitest.config.ts");
|
||||
const vitestConfig = await readFile(vitestConfigFile, "utf8");
|
||||
const featureCoverageInclude =
|
||||
` "${featureSource}/adapters/reference-http-gateway.ts",\n`;
|
||||
if (!vitestConfig.includes(featureCoverageInclude)) {
|
||||
throw new Error("Reference feature coverage include is not registered");
|
||||
}
|
||||
await writeFile(
|
||||
vitestConfigFile,
|
||||
vitestConfig.replace(featureCoverageInclude, ""),
|
||||
);
|
||||
|
||||
const coveragePolicyFile = path.join(
|
||||
fixtureRoot,
|
||||
"config/testing/risk-coverage.json",
|
||||
@@ -232,6 +239,44 @@ if (
|
||||
throw new Error("Reference feature coverage policy is not registered");
|
||||
}
|
||||
coveragePolicy.criticalModules = retainedCriticalModules;
|
||||
// The removable reference feature exercises shared request-body failure branches.
|
||||
// Keep the production policy unchanged while preserving an audited floor for the
|
||||
// intentionally smaller executable universe in this isolated removal proof.
|
||||
const removalSpecificBoundedBodyFloor = {
|
||||
lines: 65,
|
||||
statements: 63,
|
||||
functions: 55,
|
||||
branches: 45,
|
||||
};
|
||||
const boundedBodyPolicy = coveragePolicy.criticalModules.find(
|
||||
(modulePolicy) =>
|
||||
modulePolicy.path === "src/adapters/http/bounded-body-reader.ts",
|
||||
);
|
||||
if (!boundedBodyPolicy?.minimum) {
|
||||
throw new Error("Shared bounded-body coverage policy is not registered");
|
||||
}
|
||||
for (const [metric, floor] of Object.entries(removalSpecificBoundedBodyFloor)) {
|
||||
const productionFloor = boundedBodyPolicy.minimum[metric];
|
||||
if (typeof productionFloor !== "number" || productionFloor < floor) {
|
||||
throw new Error(
|
||||
`Production bounded-body ${metric} floor must remain at least ${floor}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
boundedBodyPolicy.minimum = removalSpecificBoundedBodyFloor;
|
||||
coveragePolicy.highRiskPaths = coveragePolicy.highRiskPaths.filter(
|
||||
(modulePath) => !modulePath.startsWith(`${featureSource}/`),
|
||||
);
|
||||
coveragePolicy.waivers = coveragePolicy.waivers.filter(
|
||||
(waiver) => !waiver.path?.startsWith(`${featureSource}/`),
|
||||
);
|
||||
coveragePolicy.generatedPaths = coveragePolicy.generatedPaths.filter(
|
||||
(modulePath) => !modulePath.startsWith(`${featureSource}/`),
|
||||
);
|
||||
coveragePolicy.repositoryBaseline -= removedProductionModuleCount;
|
||||
if (coveragePolicy.repositoryBaseline <= 0) {
|
||||
throw new Error("Reference feature removal produced an invalid coverage baseline");
|
||||
}
|
||||
await writeFile(
|
||||
coveragePolicyFile,
|
||||
`${JSON.stringify(coveragePolicy, null, 2)}\n`,
|
||||
|
||||
@@ -138,4 +138,58 @@ describe("reference feature runtime composition", () => {
|
||||
);
|
||||
adapters.infrastructure.dispose();
|
||||
});
|
||||
|
||||
it("keeps private command intent identity out of URLs and diagnostics", async () => {
|
||||
const requests: Array<Readonly<{ url: string; headers: Headers }>> = [];
|
||||
const fetcher = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
requests.push({
|
||||
url: String(input),
|
||||
headers: new Headers(init?.headers),
|
||||
});
|
||||
return Response.json(
|
||||
{ id: "resource-1", name: "Created resource" },
|
||||
{ status: 201 },
|
||||
);
|
||||
});
|
||||
const adapters = await createRuntimeAdapters({
|
||||
runtime,
|
||||
release,
|
||||
host: {},
|
||||
fetcher,
|
||||
});
|
||||
await adapters.outputPorts.session.beginSignIn();
|
||||
await vi.waitFor(() =>
|
||||
expect(adapters.infrastructure.serverStateScope.getPhase()).toBe("READY"),
|
||||
);
|
||||
const intent = Object.freeze({
|
||||
intentId: "private-intent-id",
|
||||
operationId: "CREATE_REFERENCE_RESOURCE",
|
||||
canonicalInputIdentity: "private-canonical-input",
|
||||
idempotencyKey: "private-idempotency-key",
|
||||
createdAtMonotonicMs: 42,
|
||||
});
|
||||
|
||||
await expect(
|
||||
adapters.featureInputs[REFERENCE_FEATURE_ID].createResource(
|
||||
{ name: "Created resource" },
|
||||
{ intent },
|
||||
),
|
||||
).resolves.toMatchObject({ ok: true });
|
||||
|
||||
expect(requests).toHaveLength(1);
|
||||
expect(requests[0]?.headers.get("Idempotency-Key")).toBe(
|
||||
"private-idempotency-key",
|
||||
);
|
||||
expect(requests[0]?.url).toBe(
|
||||
"http://localhost:8080/api/reference-resources",
|
||||
);
|
||||
const safeEvidence = JSON.stringify({
|
||||
requests: requests.map((request) => request.url),
|
||||
diagnostics: adapters.outputPorts.diagnostics.entries(),
|
||||
});
|
||||
expect(safeEvidence).not.toContain("private-intent-id");
|
||||
expect(safeEvidence).not.toContain("private-canonical-input");
|
||||
expect(safeEvidence).not.toContain("private-idempotency-key");
|
||||
adapters.infrastructure.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,5 +4,11 @@
|
||||
"statements": { "pct": 0 },
|
||||
"functions": { "pct": 0 },
|
||||
"branches": { "pct": 0 }
|
||||
},
|
||||
"src/adapters/http/http-execution-v3.ts": {
|
||||
"lines": { "pct": 0 },
|
||||
"statements": { "pct": 0 },
|
||||
"functions": { "pct": 0 },
|
||||
"branches": { "pct": 0 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"total": {
|
||||
"lines": { "pct": 100 },
|
||||
"statements": { "pct": 100 },
|
||||
"functions": { "pct": 100 },
|
||||
"branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/http/bounded-body-reader.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/http/bounded-json.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/http/http-execution-v3.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/http/request-builder.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/http/retry-policy.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/query-cache/server-state-scope-runtime.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/service-worker/service-worker-lifecycle.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/storage/browser-storage-adapter.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/adapters/telemetry/best-effort-telemetry.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/application/create-application.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/application/policies/compatibility.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/application/policies/performance-budgets.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/application/policies/promotion-readiness.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
},
|
||||
"src/application/use-cases/decide-chunk-recovery.ts": {
|
||||
"lines": { "pct": 100 }, "statements": { "pct": 100 }, "functions": { "pct": 100 }, "branches": { "pct": 100 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
import {
|
||||
mkdir,
|
||||
mkdtemp,
|
||||
readFile,
|
||||
rm,
|
||||
symlink,
|
||||
writeFile,
|
||||
} from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
buildProductionModuleInventory,
|
||||
evaluateRiskCoverage,
|
||||
parseRepositoryRiskCoveragePolicy,
|
||||
parseRiskCoveragePolicy,
|
||||
} from "../../scripts/lib/risk-coverage.ts";
|
||||
|
||||
const roots: string[] = [];
|
||||
const now = Date.parse("2026-08-02T00:00:00.000Z");
|
||||
const fullMetrics = {
|
||||
lines: { pct: 100 },
|
||||
statements: { pct: 100 },
|
||||
functions: { pct: 100 },
|
||||
branches: { pct: 100 },
|
||||
};
|
||||
|
||||
async function repositoryFixture(): Promise<string> {
|
||||
const root = await mkdtemp(path.join(tmpdir(), "risk-coverage-"));
|
||||
roots.push(root);
|
||||
await mkdir(path.join(root, "src/nested"), { recursive: true });
|
||||
await Promise.all([
|
||||
writeFile(path.join(root, "src/a.ts"), "export const a = 1;\n"),
|
||||
writeFile(path.join(root, "src/nested/b.tsx"), "export const b = 2;\n"),
|
||||
writeFile(path.join(root, "src/types.d.ts"), "declare const value: 1;\n"),
|
||||
writeFile(path.join(root, "src/example.stories.tsx"), "export {};\n"),
|
||||
writeFile(path.join(root, "src/generated.ts"), "export const generated = true;\n"),
|
||||
writeFile(path.join(root, "src/ignored.js"), "export const ignored = true;\n"),
|
||||
]);
|
||||
return root;
|
||||
}
|
||||
|
||||
function policy(overrides: Record<string, unknown> = {}) {
|
||||
return {
|
||||
schemaVersion: 2,
|
||||
repositoryBaseline: 2,
|
||||
generatedPaths: ["src/generated.ts"],
|
||||
summary: {
|
||||
lines: 80,
|
||||
statements: 78,
|
||||
functions: 85,
|
||||
branches: 68,
|
||||
},
|
||||
criticalModules: [
|
||||
{
|
||||
path: "src/a.ts",
|
||||
owner: "platform-runtime",
|
||||
minimum: {
|
||||
lines: 80,
|
||||
statements: 78,
|
||||
functions: 85,
|
||||
branches: 68,
|
||||
},
|
||||
},
|
||||
],
|
||||
highRiskPaths: ["src/a.ts"],
|
||||
waivers: [],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
roots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
|
||||
);
|
||||
});
|
||||
|
||||
describe("repository-aware risk coverage", () => {
|
||||
it("rejects the historical 14-file summary against the full repository", async () => {
|
||||
const repositoryRoot = process.cwd();
|
||||
const rawPolicy = JSON.parse(
|
||||
await readFile("config/testing/risk-coverage.json", "utf8"),
|
||||
) as unknown;
|
||||
const summary = JSON.parse(
|
||||
await readFile("tests/fixtures/coverage/repository-omission.json", "utf8"),
|
||||
) as unknown;
|
||||
const parsedPolicy = parseRepositoryRiskCoveragePolicy(rawPolicy, { now });
|
||||
const inventory = await buildProductionModuleInventory({
|
||||
repositoryRoot,
|
||||
generatedPaths: parsedPolicy.generatedPaths,
|
||||
});
|
||||
const result = evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy: parsedPolicy,
|
||||
summary,
|
||||
changedFiles: [],
|
||||
now,
|
||||
});
|
||||
|
||||
expect(result.selectedTotal).toBe(14);
|
||||
expect(result.repositoryTotal).toBeGreaterThan(result.selectedTotal);
|
||||
expect(result.uncoveredModules).toHaveLength(
|
||||
result.repositoryTotal - result.selectedTotal,
|
||||
);
|
||||
expect(result.status).toBe("FAIL");
|
||||
});
|
||||
|
||||
it("reports the exact selected and repository totals plus sorted omissions", async () => {
|
||||
const repositoryRoot = await repositoryFixture();
|
||||
const inventory = await buildProductionModuleInventory({
|
||||
repositoryRoot,
|
||||
generatedPaths: ["src/generated.ts"],
|
||||
});
|
||||
const result = evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy: parseRiskCoveragePolicy(policy(), { now }),
|
||||
summary: {
|
||||
total: fullMetrics,
|
||||
[path.join(repositoryRoot, "src/a.ts")]: fullMetrics,
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
});
|
||||
|
||||
expect(inventory).toEqual(["src/a.ts", "src/nested/b.tsx"]);
|
||||
expect(result).toMatchObject({
|
||||
status: "FAIL",
|
||||
selectedTotal: 1,
|
||||
repositoryTotal: 2,
|
||||
uncoveredModules: ["src/nested/b.tsx"],
|
||||
});
|
||||
expect(result.failures).toContain(
|
||||
"production module missing from coverage: src/nested/b.tsx",
|
||||
);
|
||||
});
|
||||
|
||||
it("maps only exact repository-relative POSIX coverage paths", async () => {
|
||||
const repositoryRoot = await repositoryFixture();
|
||||
const inventory = await buildProductionModuleInventory({
|
||||
repositoryRoot,
|
||||
generatedPaths: ["src/generated.ts"],
|
||||
});
|
||||
const parsedPolicy = parseRiskCoveragePolicy(policy(), { now });
|
||||
|
||||
expect(
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy: parsedPolicy,
|
||||
summary: {
|
||||
total: fullMetrics,
|
||||
"src/a.ts": fullMetrics,
|
||||
"src/nested/b.tsx": fullMetrics,
|
||||
"tests/unit/a.test.ts": fullMetrics,
|
||||
"src/generated.ts": fullMetrics,
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
}),
|
||||
).toMatchObject({
|
||||
status: "PASS",
|
||||
selectedTotal: 2,
|
||||
ignoredCoveragePaths: ["src/generated.ts", "tests/unit/a.test.ts"],
|
||||
});
|
||||
expect(() =>
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy: parsedPolicy,
|
||||
summary: {
|
||||
total: fullMetrics,
|
||||
[path.join(tmpdir(), "other/src/a.ts")]: fullMetrics,
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
}),
|
||||
).toThrow(/outside repository/u);
|
||||
expect(() =>
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy: parsedPolicy,
|
||||
summary: {
|
||||
total: fullMetrics,
|
||||
"src/a.ts": fullMetrics,
|
||||
[path.join(repositoryRoot, "src/a.ts")]: fullMetrics,
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
}),
|
||||
).toThrow(/duplicate coverage path/u);
|
||||
});
|
||||
|
||||
it("accepts and validates Vitest's branchesTrue total without evaluating it", () => {
|
||||
const parsedPolicy = parseRiskCoveragePolicy(policy(), { now });
|
||||
const branchesTrue = { total: 0, covered: 0, skipped: 0, pct: 100 };
|
||||
|
||||
expect(
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot: "/repository",
|
||||
inventory: ["src/a.ts"],
|
||||
policy: { ...parsedPolicy, repositoryBaseline: 1 },
|
||||
summary: {
|
||||
total: { ...fullMetrics, branchesTrue },
|
||||
"src/a.ts": fullMetrics,
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
}),
|
||||
).toMatchObject({ status: "PASS", selectedTotal: 1 });
|
||||
expect(() =>
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot: "/repository",
|
||||
inventory: ["src/a.ts"],
|
||||
policy: { ...parsedPolicy, repositoryBaseline: 1 },
|
||||
summary: {
|
||||
total: {
|
||||
...fullMetrics,
|
||||
branchesTrue: { ...branchesTrue, pct: Number.NaN },
|
||||
},
|
||||
"src/a.ts": fullMetrics,
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
}),
|
||||
).toThrow(/branchesTrue.*finite/u);
|
||||
});
|
||||
|
||||
it("fails closed on an empty, unreadable, traversing, or symlinked inventory", async () => {
|
||||
const repositoryRoot = await repositoryFixture();
|
||||
const emptyRoot = await mkdtemp(path.join(tmpdir(), "risk-coverage-empty-"));
|
||||
roots.push(emptyRoot);
|
||||
await mkdir(path.join(emptyRoot, "src"));
|
||||
|
||||
await expect(
|
||||
buildProductionModuleInventory({ repositoryRoot: emptyRoot }),
|
||||
).rejects.toThrow(/inventory is empty/u);
|
||||
await expect(
|
||||
buildProductionModuleInventory({
|
||||
repositoryRoot,
|
||||
assertReadable: async (target) => {
|
||||
if (target.endsWith("src/a.ts")) throw new Error("denied");
|
||||
},
|
||||
}),
|
||||
).rejects.toThrow(/unreadable.*src\/a\.ts/u);
|
||||
await expect(
|
||||
buildProductionModuleInventory({
|
||||
repositoryRoot,
|
||||
generatedPaths: ["../escape.ts"],
|
||||
}),
|
||||
).rejects.toThrow(/repository-relative POSIX/u);
|
||||
|
||||
const outside = await mkdtemp(path.join(tmpdir(), "risk-coverage-outside-"));
|
||||
roots.push(outside);
|
||||
await writeFile(path.join(outside, "linked.ts"), "export {};\n");
|
||||
await symlink(path.join(outside, "linked.ts"), path.join(repositoryRoot, "src/link.ts"));
|
||||
await expect(
|
||||
buildProductionModuleInventory({ repositoryRoot }),
|
||||
).rejects.toThrow(/symlink.*src\/link\.ts/u);
|
||||
});
|
||||
|
||||
it("rejects malformed totals, duplicate paths, invalid minimums, and weak ownership", () => {
|
||||
expect(() => parseRiskCoveragePolicy(null, { now })).toThrow(/policy/u);
|
||||
expect(() =>
|
||||
parseRiskCoveragePolicy(policy({ repositoryBaseline: 0 }), { now }),
|
||||
).toThrow(/repositoryBaseline/u);
|
||||
expect(() =>
|
||||
parseRiskCoveragePolicy(
|
||||
policy({
|
||||
criticalModules: [
|
||||
{ path: "src/a.ts", owner: "team", minimum: { lines: 101 } },
|
||||
],
|
||||
}),
|
||||
{ now },
|
||||
),
|
||||
).toThrow(/minimum/u);
|
||||
expect(() =>
|
||||
parseRiskCoveragePolicy(
|
||||
policy({
|
||||
criticalModules: [
|
||||
{ path: "src/a.ts", owner: " ", minimum: { lines: 80 } },
|
||||
],
|
||||
}),
|
||||
{ now },
|
||||
),
|
||||
).toThrow(/owner/u);
|
||||
expect(() =>
|
||||
parseRiskCoveragePolicy(
|
||||
policy({ highRiskPaths: ["src/a.ts", "src/a.ts"] }),
|
||||
{ now },
|
||||
),
|
||||
).toThrow(/duplicate/u);
|
||||
|
||||
const parsedPolicy = parseRiskCoveragePolicy(policy(), { now });
|
||||
expect(() =>
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot: "/repository",
|
||||
inventory: ["src/a.ts"],
|
||||
policy: parsedPolicy,
|
||||
summary: {
|
||||
total: fullMetrics,
|
||||
"src/a.ts": { ...fullMetrics, lines: { pct: Number.NaN } },
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
}),
|
||||
).toThrow(/finite/u);
|
||||
expect(() =>
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot: "/repository",
|
||||
inventory: ["src/a.ts"],
|
||||
policy: parsedPolicy,
|
||||
summary: {
|
||||
total: fullMetrics,
|
||||
"src/a.ts": {
|
||||
...fullMetrics,
|
||||
lines: {
|
||||
total: Number.NaN,
|
||||
covered: 1,
|
||||
skipped: 0,
|
||||
pct: 100,
|
||||
},
|
||||
},
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
}),
|
||||
).toThrow(/lines\.total.*nonnegative/u);
|
||||
expect(() =>
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot: "/repository",
|
||||
inventory: ["src/a.ts"],
|
||||
policy: parsedPolicy,
|
||||
summary: {
|
||||
total: fullMetrics,
|
||||
"src/a.ts": { ...fullMetrics, conditions: { pct: 100 } },
|
||||
},
|
||||
changedFiles: [],
|
||||
now,
|
||||
}),
|
||||
).toThrow(/unknown.*metric/u);
|
||||
});
|
||||
|
||||
it("requires inventory-owned critical rows and exact owned future waivers", async () => {
|
||||
const repositoryRoot = await repositoryFixture();
|
||||
const inventory = await buildProductionModuleInventory({
|
||||
repositoryRoot,
|
||||
generatedPaths: ["src/generated.ts"],
|
||||
});
|
||||
const summary = {
|
||||
total: fullMetrics,
|
||||
"src/a.ts": fullMetrics,
|
||||
"src/nested/b.tsx": fullMetrics,
|
||||
};
|
||||
const waiverPolicy = parseRiskCoveragePolicy(
|
||||
policy({
|
||||
highRiskPaths: ["src/a.ts", "src/nested/b.tsx"],
|
||||
waivers: [
|
||||
{
|
||||
path: "src/nested/b.tsx",
|
||||
owner: "runtime-security",
|
||||
reason: "Temporary branch instrumentation gap",
|
||||
expiresAt: "2026-08-03T00:00:00.000Z",
|
||||
},
|
||||
],
|
||||
}),
|
||||
{ now },
|
||||
);
|
||||
|
||||
expect(
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy: waiverPolicy,
|
||||
summary,
|
||||
changedFiles: ["src/nested/b.tsx"],
|
||||
now,
|
||||
}),
|
||||
).toMatchObject({ status: "PASS" });
|
||||
expect(
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy: parseRiskCoveragePolicy(
|
||||
policy({ highRiskPaths: ["src/a.ts", "src/nested/b.tsx"] }),
|
||||
{ now },
|
||||
),
|
||||
summary,
|
||||
changedFiles: ["src/nested/b.tsx"],
|
||||
now,
|
||||
}).failures,
|
||||
).toContain("changed high-risk module has no owner or waiver: src/nested/b.tsx");
|
||||
expect(
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory,
|
||||
policy: parseRiskCoveragePolicy(
|
||||
policy({ highRiskPaths: ["src/a.ts", "src/nested/b.tsx"] }),
|
||||
{ now },
|
||||
),
|
||||
summary,
|
||||
changedFiles: [],
|
||||
now,
|
||||
}).failures,
|
||||
).toContain("high-risk module has no owner or waiver: src/nested/b.tsx");
|
||||
expect(
|
||||
evaluateRiskCoverage({
|
||||
repositoryRoot,
|
||||
inventory: ["src/nested/b.tsx"],
|
||||
policy: parseRiskCoveragePolicy(policy(), { now }),
|
||||
summary,
|
||||
changedFiles: [],
|
||||
now,
|
||||
}).failures,
|
||||
).toContain("critical module is outside production inventory: src/a.ts");
|
||||
});
|
||||
|
||||
it("does not let the repository policy delete a required high-risk path", async () => {
|
||||
const rawPolicy = JSON.parse(
|
||||
await readFile("config/testing/risk-coverage.json", "utf8"),
|
||||
) as Record<string, unknown>;
|
||||
rawPolicy.highRiskPaths = (
|
||||
rawPolicy.highRiskPaths as string[]
|
||||
).filter((modulePath) => modulePath !== "src/adapters/http/http-execution-v3.ts");
|
||||
|
||||
expect(() => parseRepositoryRiskCoveragePolicy(rawPolicy, { now })).toThrow(
|
||||
/required high-risk path.*http-execution-v3/u,
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[{ path: "src/*.ts", owner: "team", reason: "reason", expiresAt: "2026-08-03T00:00:00.000Z" }, /POSIX/u],
|
||||
[{ path: "src/a.ts", owner: "", reason: "reason", expiresAt: "2026-08-03T00:00:00.000Z" }, /owner/u],
|
||||
[{ path: "src/a.ts", owner: "team", reason: "", expiresAt: "2026-08-03T00:00:00.000Z" }, /reason/u],
|
||||
[{ path: "src/a.ts", owner: "team", reason: "reason", expiresAt: "2026-08-01T00:00:00.000Z" }, /expired/u],
|
||||
[{ path: "src/stale.ts", owner: "team", reason: "reason", expiresAt: "2026-08-03T00:00:00.000Z" }, /stale/u],
|
||||
] as const)("rejects invalid exact-path waivers %#", (waiver, message) => {
|
||||
expect(() =>
|
||||
parseRiskCoveragePolicy(
|
||||
policy({ highRiskPaths: ["src/a.ts"], waivers: [waiver] }),
|
||||
{ now },
|
||||
),
|
||||
).toThrow(message);
|
||||
});
|
||||
});
|
||||
@@ -65,14 +65,14 @@ describe("runtime adapter composition", () => {
|
||||
});
|
||||
|
||||
const intent = factory.create({
|
||||
operationId: "CREATE_REFERENCE_RESOURCE",
|
||||
operationId: "CREATE_ENTITY",
|
||||
canonicalInputIdentity: "opaque-canonical-input",
|
||||
requiresIdempotencyKey: true,
|
||||
});
|
||||
|
||||
expect(intent).toEqual({
|
||||
intentId: "intent-uuid",
|
||||
operationId: "CREATE_REFERENCE_RESOURCE",
|
||||
operationId: "CREATE_ENTITY",
|
||||
canonicalInputIdentity: "opaque-canonical-input",
|
||||
idempotencyKey: "idempotency-uuid",
|
||||
createdAtMonotonicMs: 12.5,
|
||||
@@ -96,7 +96,7 @@ describe("runtime adapter composition", () => {
|
||||
).toThrow(TypeError);
|
||||
expect(() =>
|
||||
factory.create({
|
||||
operationId: "CREATE_REFERENCE_RESOURCE",
|
||||
operationId: "CREATE_ENTITY",
|
||||
canonicalInputIdentity: "x".repeat(16_385),
|
||||
requiresIdempotencyKey: false,
|
||||
}),
|
||||
@@ -106,7 +106,7 @@ describe("runtime adapter composition", () => {
|
||||
randomUUID: () => "opaque-runtime-identifier",
|
||||
monotonicNow: () => -1,
|
||||
}).create({
|
||||
operationId: "CREATE_REFERENCE_RESOURCE",
|
||||
operationId: "CREATE_ENTITY",
|
||||
canonicalInputIdentity: "valid-identity",
|
||||
requiresIdempotencyKey: false,
|
||||
}),
|
||||
@@ -165,60 +165,6 @@ describe("runtime adapter composition", () => {
|
||||
adapters.infrastructure.dispose();
|
||||
});
|
||||
|
||||
it("passes the supplied command intent unchanged and keeps private identity out of URLs and diagnostics", async () => {
|
||||
const requests: Array<Readonly<{ url: string; headers: Headers }>> = [];
|
||||
const fetcher = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
requests.push({
|
||||
url: String(input),
|
||||
headers: new Headers(init?.headers),
|
||||
});
|
||||
return Response.json(
|
||||
{ id: "resource-1", name: "Created resource" },
|
||||
{ status: 201 },
|
||||
);
|
||||
});
|
||||
const adapters = await createRuntimeAdapters({
|
||||
runtime,
|
||||
release,
|
||||
host: {},
|
||||
fetcher,
|
||||
});
|
||||
await adapters.outputPorts.session.beginSignIn();
|
||||
await vi.waitFor(() =>
|
||||
expect(adapters.infrastructure.serverStateScope.getPhase()).toBe("READY"),
|
||||
);
|
||||
const intent = Object.freeze({
|
||||
intentId: "private-intent-id",
|
||||
operationId: "CREATE_REFERENCE_RESOURCE",
|
||||
canonicalInputIdentity: "private-canonical-input",
|
||||
idempotencyKey: "private-idempotency-key",
|
||||
createdAtMonotonicMs: 42,
|
||||
});
|
||||
|
||||
await expect(
|
||||
adapters.featureInputs["reference-feature"].createResource(
|
||||
{ name: "Created resource" },
|
||||
{ intent },
|
||||
),
|
||||
).resolves.toMatchObject({ ok: true });
|
||||
|
||||
expect(requests).toHaveLength(1);
|
||||
expect(requests[0]?.headers.get("Idempotency-Key")).toBe(
|
||||
"private-idempotency-key",
|
||||
);
|
||||
expect(requests[0]?.url).toBe(
|
||||
"http://localhost:8080/api/reference-resources",
|
||||
);
|
||||
const safeEvidence = JSON.stringify({
|
||||
requests: requests.map((request) => request.url),
|
||||
diagnostics: adapters.outputPorts.diagnostics.entries(),
|
||||
});
|
||||
expect(safeEvidence).not.toContain("private-intent-id");
|
||||
expect(safeEvidence).not.toContain("private-canonical-input");
|
||||
expect(safeEvidence).not.toContain("private-idempotency-key");
|
||||
adapters.infrastructure.dispose();
|
||||
});
|
||||
|
||||
it("does not fail boot when Web Storage capability getters throw", async () => {
|
||||
const host: Record<string, unknown> = {};
|
||||
Object.defineProperties(host, {
|
||||
|
||||
+1
-12
@@ -13,18 +13,7 @@ export default defineConfig({
|
||||
provider: "v8",
|
||||
reportsDirectory: "artifacts/tests/coverage",
|
||||
reporter: ["text", "json-summary", "lcov"],
|
||||
include: [
|
||||
"src/application/create-application.ts",
|
||||
"src/application/policies/**/*.ts",
|
||||
"src/application/use-cases/**/*.ts",
|
||||
"src/contracts/diagnostics.ts",
|
||||
"src/adapters/http/retry-policy.ts",
|
||||
"src/adapters/storage/browser-storage-adapter.ts",
|
||||
"src/adapters/telemetry/best-effort-telemetry.ts",
|
||||
"src/features/reference-feature/adapters/reference-http-gateway.ts",
|
||||
"src/presentation/adapters/query/application-query.ts",
|
||||
"scripts/lib/registry-compatibility.ts",
|
||||
],
|
||||
include: ["src/**/*.{ts,tsx}"],
|
||||
exclude: ["**/*.d.ts", "**/*.stories.*"],
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user