mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
ci: add daemon UI P0 capability shadow (#6112)
This commit is contained in:
@@ -776,6 +776,47 @@ test("merge-queue threshold escalates medium-confidence files to the full radius
|
||||
});
|
||||
});
|
||||
|
||||
test("runtime-definition changes produce only a three-domain UI P0 shadow candidate", async () => {
|
||||
const { evaluateUiP0Shadow } = await import("../../../scripts/scopes.ts");
|
||||
const decision = evaluateUiP0Shadow([
|
||||
"apps/daemon/src/runtimes/defs/atomcode.ts",
|
||||
"apps/daemon/src/runtimes/metadata.ts",
|
||||
"apps/daemon/tests/runtimes/atomcode.test.ts",
|
||||
]);
|
||||
assert.equal(decision.mode, "candidate");
|
||||
assert.equal(decision.capability, "daemon-runtime-definition");
|
||||
assert.deepEqual(
|
||||
decision.matrix.map((entry) => entry.name),
|
||||
["entry-settings", "project-workspace", "project-runtime"],
|
||||
);
|
||||
assert.deepEqual(decision.outsideCapabilityFiles, []);
|
||||
});
|
||||
|
||||
test("runtime-definition shadow fails closed for mixed, unknown, empty, and unresolved changes", async () => {
|
||||
const { evaluateUiP0Shadow } = await import("../../../scripts/scopes.ts");
|
||||
for (const files of [
|
||||
["apps/daemon/src/runtimes/defs/atomcode.ts", "apps/daemon/src/server.ts"],
|
||||
["apps/daemon/src/runtimes/detection.ts"],
|
||||
["mystery.xyz"],
|
||||
[],
|
||||
]) {
|
||||
const decision = evaluateUiP0Shadow(files);
|
||||
assert.equal(decision.mode, "full-fallback", files.join(", "));
|
||||
assert.deepEqual(
|
||||
decision.matrix.map((entry) => entry.name),
|
||||
["entry-settings", "project-workspace", "project-runtime", "workspace-restoration"],
|
||||
);
|
||||
}
|
||||
assert.equal(evaluateUiP0Shadow([], false).reason, "files-unresolved");
|
||||
});
|
||||
|
||||
test("UI P0 shadow guard pins full applied coverage and closed fallbacks", async () => {
|
||||
const { uiP0ShadowContractErrors } = await import(
|
||||
"../../../scripts/check-ui-p0-shadow.ts"
|
||||
);
|
||||
assert.deepEqual(uiP0ShadowContractErrors(), []);
|
||||
});
|
||||
|
||||
test("plan command evaluates offline at the pr threshold", () => {
|
||||
const stdout = execFileSync(
|
||||
process.execPath,
|
||||
@@ -789,6 +830,33 @@ test("plan command evaluates offline at the pr threshold", () => {
|
||||
assert.deepEqual(result.trace["escalations"], []);
|
||||
});
|
||||
|
||||
test("plan trace reports the runtime-definition UI P0 shadow without changing the applied plan", () => {
|
||||
const stdout = execFileSync(
|
||||
process.execPath,
|
||||
[
|
||||
"--experimental-strip-types",
|
||||
scopesScript,
|
||||
"plan",
|
||||
"--context",
|
||||
"pr",
|
||||
"--files",
|
||||
"apps/daemon/src/runtimes/defs/atomcode.ts",
|
||||
"apps/daemon/tests/runtimes/atomcode.test.ts",
|
||||
],
|
||||
{ cwd: repoRoot, encoding: "utf8" },
|
||||
);
|
||||
const result = JSON.parse(stdout) as {
|
||||
plan: Record<string, unknown>;
|
||||
trace: { uiP0Shadow: { mode: string; matrix: Array<{ name: string }> } };
|
||||
};
|
||||
assert.equal(result.plan["ui_p0_matrix"], UI_P0_MATRIX_JSON);
|
||||
assert.equal(result.trace.uiP0Shadow.mode, "candidate");
|
||||
assert.deepEqual(
|
||||
result.trace.uiP0Shadow.matrix.map((entry) => entry.name),
|
||||
["entry-settings", "project-workspace", "project-runtime"],
|
||||
);
|
||||
});
|
||||
|
||||
test("plan command surfaces queue-tier escalation and the trust-all shadow column", () => {
|
||||
const stdout = execFileSync(
|
||||
process.execPath,
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { uiP0CiMatrix } from "../e2e/lib/playwright/suites.ts";
|
||||
import {
|
||||
DAEMON_RUNTIME_DEFINITION_EXACT,
|
||||
DAEMON_RUNTIME_DEFINITION_PREFIXES,
|
||||
evaluateUiP0Shadow,
|
||||
} from "./scopes.ts";
|
||||
|
||||
const fullMatrixNames = [
|
||||
"entry-settings",
|
||||
"project-workspace",
|
||||
"project-runtime",
|
||||
"workspace-restoration",
|
||||
] as const;
|
||||
const candidateMatrixNames = [
|
||||
"entry-settings",
|
||||
"project-workspace",
|
||||
"project-runtime",
|
||||
] as const;
|
||||
|
||||
function matrixNames(matrix: readonly { name: string }[]): string[] {
|
||||
return matrix.map((entry) => entry.name);
|
||||
}
|
||||
|
||||
function sameValues(actual: readonly string[], expected: readonly string[]): boolean {
|
||||
return actual.length === expected.length && actual.every((value, index) => value === expected[index]);
|
||||
}
|
||||
|
||||
export function uiP0ShadowContractErrors(): string[] {
|
||||
const errors: string[] = [];
|
||||
if (!sameValues(matrixNames(uiP0CiMatrix), fullMatrixNames)) {
|
||||
errors.push("the applied UI P0 matrix is no longer the guarded full four-domain matrix");
|
||||
}
|
||||
|
||||
const sourceSample = `${DAEMON_RUNTIME_DEFINITION_PREFIXES[0]}example.ts`;
|
||||
const testSample = DAEMON_RUNTIME_DEFINITION_EXACT.find((file) => file.includes("/tests/"));
|
||||
const candidate = evaluateUiP0Shadow(testSample == null ? [sourceSample] : [sourceSample, testSample]);
|
||||
if (
|
||||
candidate.mode !== "candidate" ||
|
||||
candidate.capability !== "daemon-runtime-definition" ||
|
||||
!sameValues(matrixNames(candidate.matrix), candidateMatrixNames)
|
||||
) {
|
||||
errors.push("the runtime-definition shadow no longer resolves to the guarded three-domain candidate");
|
||||
}
|
||||
|
||||
for (const outsideFile of [
|
||||
"apps/daemon/src/server.ts",
|
||||
"apps/daemon/src/runtimes/detection.ts",
|
||||
"apps/web/src/App.tsx",
|
||||
]) {
|
||||
const fallback = evaluateUiP0Shadow([sourceSample, outsideFile]);
|
||||
if (
|
||||
fallback.mode !== "full-fallback" ||
|
||||
fallback.reason !== "outside-capability" ||
|
||||
!sameValues(matrixNames(fallback.matrix), fullMatrixNames)
|
||||
) {
|
||||
errors.push(`${outsideFile} no longer forces the runtime-definition shadow to the full matrix`);
|
||||
}
|
||||
}
|
||||
|
||||
const unresolved = evaluateUiP0Shadow([], false);
|
||||
if (
|
||||
unresolved.mode !== "full-fallback" ||
|
||||
unresolved.reason !== "files-unresolved" ||
|
||||
!sameValues(matrixNames(unresolved.matrix), fullMatrixNames)
|
||||
) {
|
||||
errors.push("unresolved changed files no longer force the UI P0 shadow to the full matrix");
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
export async function checkUiP0ShadowContract(): Promise<boolean> {
|
||||
const errors = uiP0ShadowContractErrors();
|
||||
if (errors.length > 0) {
|
||||
console.error("UI P0 shadow-contract violations found:");
|
||||
for (const error of errors) console.error(`- ${error}`);
|
||||
return false;
|
||||
}
|
||||
console.log("UI P0 shadow contract check passed: applied coverage stays full and fallbacks stay closed.");
|
||||
return true;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { checkCertainExemptConsumption } from "./check-certain-exempt-consumptio
|
||||
import { checkCrossAppImports } from "./check-cross-app-imports.ts";
|
||||
import { checkPackagedLeafBoundary } from "./check-packaged-leaf-boundary.ts";
|
||||
import { checkTsNocheckImports } from "./check-ts-nocheck-imports.ts";
|
||||
import { checkUiP0ShadowContract } from "./check-ui-p0-shadow.ts";
|
||||
import { checkDesignSystemManifests } from "./check-design-system-manifests.ts";
|
||||
import { checkDesignSystemPackageQuality } from "./check-design-system-package-quality.ts";
|
||||
import { checkDesignSystemComponentFixtureReport } from "./check-components-fixtures.ts";
|
||||
@@ -1328,6 +1329,7 @@ const checks: GuardCheck[] = [
|
||||
{ name: "residual JavaScript", run: checkResidualJavaScript },
|
||||
{ name: "certain-exempt surface consumption", run: checkCertainExemptConsumption },
|
||||
{ name: "packaged leaf boundary", run: checkPackagedLeafBoundary },
|
||||
{ name: "UI P0 shadow contract", run: checkUiP0ShadowContract },
|
||||
{ name: "package dependency specs", run: checkPackageDependencySpecs },
|
||||
{ name: "product neutrality", run: checkProductNeutrality },
|
||||
{ name: "cross-app imports", run: checkCrossAppImports },
|
||||
|
||||
+93
-1
@@ -3,6 +3,7 @@ import { appendFileSync, readFileSync } from "node:fs";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { uiP0CiMatrix, visualCiMatrix } from "../e2e/lib/playwright/suites.ts";
|
||||
import type { UiP0CiMatrixEntry } from "../e2e/lib/playwright/suites.ts";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Scope model
|
||||
@@ -47,6 +48,35 @@ export type Confidence = "medium" | "certain";
|
||||
|
||||
export type TrustThreshold = "medium" | "certain";
|
||||
|
||||
export const DAEMON_RUNTIME_DEFINITION_PREFIXES = [
|
||||
"apps/daemon/src/runtimes/defs/",
|
||||
] as const;
|
||||
|
||||
export const DAEMON_RUNTIME_DEFINITION_EXACT = [
|
||||
"apps/daemon/src/runtimes/capabilities.ts",
|
||||
"apps/daemon/src/runtimes/local-profiles.ts",
|
||||
"apps/daemon/src/runtimes/metadata.ts",
|
||||
"apps/daemon/src/runtimes/registry.ts",
|
||||
"apps/daemon/tests/runtimes/agent-args.test.ts",
|
||||
"apps/daemon/tests/runtimes/antigravity-model-lock.test.ts",
|
||||
"apps/daemon/tests/runtimes/atomcode.test.ts",
|
||||
"apps/daemon/tests/runtimes/byok-opencode.test.ts",
|
||||
"apps/daemon/tests/runtimes/chat-run-inactivity-timeout.test.ts",
|
||||
"apps/daemon/tests/runtimes/claude-resume-args.test.ts",
|
||||
"apps/daemon/tests/runtimes/codebuddy.test.ts",
|
||||
"apps/daemon/tests/runtimes/codex-resume-args.test.ts",
|
||||
"apps/daemon/tests/runtimes/detection-resilience.test.ts",
|
||||
"apps/daemon/tests/runtimes/opencode-resume-args.test.ts",
|
||||
"apps/daemon/tests/runtimes/registry-and-args.test.ts",
|
||||
"apps/daemon/tests/runtimes/trae-cli.test.ts",
|
||||
] as const;
|
||||
|
||||
const DAEMON_RUNTIME_DEFINITION_MATRIX_NAMES = [
|
||||
"entry-settings",
|
||||
"project-workspace",
|
||||
"project-runtime",
|
||||
] as const;
|
||||
|
||||
export type RuleMatch = {
|
||||
prefixes?: readonly string[];
|
||||
exact?: readonly string[];
|
||||
@@ -518,6 +548,63 @@ function buildScopePlan(outputs: ScopeOutputs, ciMode: CiMode, fullLanes?: boole
|
||||
// Decision trace
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export type UiP0ShadowDecision = {
|
||||
mode: "candidate" | "full-fallback";
|
||||
capability: "daemon-runtime-definition" | null;
|
||||
matrix: readonly UiP0CiMatrixEntry[];
|
||||
reason: "capability-match" | "empty-change-set" | "files-unresolved" | "outside-capability";
|
||||
outsideCapabilityFiles: readonly string[];
|
||||
};
|
||||
|
||||
function isDaemonRuntimeDefinitionFile(file: string): boolean {
|
||||
return (
|
||||
DAEMON_RUNTIME_DEFINITION_PREFIXES.some((prefix) => file.startsWith(prefix)) ||
|
||||
DAEMON_RUNTIME_DEFINITION_EXACT.includes(file as (typeof DAEMON_RUNTIME_DEFINITION_EXACT)[number])
|
||||
);
|
||||
}
|
||||
|
||||
export function evaluateUiP0Shadow(
|
||||
files: readonly string[],
|
||||
filesResolved: boolean = true,
|
||||
): UiP0ShadowDecision {
|
||||
if (!filesResolved) {
|
||||
return {
|
||||
mode: "full-fallback",
|
||||
capability: null,
|
||||
matrix: uiP0CiMatrix,
|
||||
reason: "files-unresolved",
|
||||
outsideCapabilityFiles: [],
|
||||
};
|
||||
}
|
||||
if (files.length === 0) {
|
||||
return {
|
||||
mode: "full-fallback",
|
||||
capability: null,
|
||||
matrix: uiP0CiMatrix,
|
||||
reason: "empty-change-set",
|
||||
outsideCapabilityFiles: [],
|
||||
};
|
||||
}
|
||||
const outsideCapabilityFiles = files.filter((file) => !isDaemonRuntimeDefinitionFile(file));
|
||||
if (outsideCapabilityFiles.length > 0) {
|
||||
return {
|
||||
mode: "full-fallback",
|
||||
capability: null,
|
||||
matrix: uiP0CiMatrix,
|
||||
reason: "outside-capability",
|
||||
outsideCapabilityFiles,
|
||||
};
|
||||
}
|
||||
const candidateNames = new Set<string>(DAEMON_RUNTIME_DEFINITION_MATRIX_NAMES);
|
||||
return {
|
||||
mode: "candidate",
|
||||
capability: "daemon-runtime-definition",
|
||||
matrix: uiP0CiMatrix.filter((entry) => candidateNames.has(entry.name)),
|
||||
reason: "capability-match",
|
||||
outsideCapabilityFiles: [],
|
||||
};
|
||||
}
|
||||
|
||||
export type ScopeTrace = {
|
||||
source: string;
|
||||
threshold: TrustThreshold | "none";
|
||||
@@ -525,6 +612,7 @@ export type ScopeTrace = {
|
||||
fileCount: number;
|
||||
ruleHits: Record<string, number>;
|
||||
escalations: readonly { file: string; reason: string }[];
|
||||
uiP0Shadow: UiP0ShadowDecision;
|
||||
plans: {
|
||||
applied: ScopePlan;
|
||||
/**
|
||||
@@ -539,6 +627,7 @@ export type ScopeTrace = {
|
||||
|
||||
function buildTrace(
|
||||
source: string,
|
||||
files: readonly string[],
|
||||
threshold: TrustThreshold,
|
||||
evaluation: ScopeEvaluation,
|
||||
appliedPlan: ScopePlan,
|
||||
@@ -559,6 +648,7 @@ function buildTrace(
|
||||
escalations: evaluation.decisions
|
||||
.filter((decision) => decision.escalated)
|
||||
.map((decision) => ({ file: decision.file, reason: decision.reason ?? "unknown" })),
|
||||
uiP0Shadow: evaluateUiP0Shadow(files),
|
||||
plans: { applied: appliedPlan, ifTrustAll: ifTrustAllPlan },
|
||||
};
|
||||
}
|
||||
@@ -571,6 +661,7 @@ function buildEverythingTrace(source: string, appliedPlan: ScopePlan): ScopeTrac
|
||||
fileCount: 0,
|
||||
ruleHits: {},
|
||||
escalations: [],
|
||||
uiP0Shadow: evaluateUiP0Shadow([], false),
|
||||
plans: { applied: appliedPlan },
|
||||
};
|
||||
}
|
||||
@@ -652,7 +743,7 @@ function evaluateChangedFilesPlan(
|
||||
const plan = buildScopePlan(evaluation.outputs, options.ciMode, fullLanes);
|
||||
const trustAll = evaluateScopeOutputs(files, "medium", options.evaluate);
|
||||
const trustAllPlan = buildScopePlan(trustAll.outputs, options.ciMode, fullLanes);
|
||||
return { plan, trace: buildTrace(source, options.threshold, evaluation, plan, trustAllPlan) };
|
||||
return { plan, trace: buildTrace(source, files, options.threshold, evaluation, plan, trustAllPlan) };
|
||||
}
|
||||
|
||||
function resolveManualCiMode(): CiMode {
|
||||
@@ -757,6 +848,7 @@ function emitTraceStepSummary(trace: ScopeTrace): void {
|
||||
"",
|
||||
`- source: \`${trace.source}\`, trust threshold: \`${trace.threshold}\``,
|
||||
`- files: ${trace.filesResolved ? trace.fileCount : "not resolved"}, escalated: ${trace.escalations.length}`,
|
||||
`- UI P0 shadow: \`${trace.uiP0Shadow.mode}\` (${trace.uiP0Shadow.matrix.map((entry) => entry.name).join(", ")})`,
|
||||
];
|
||||
const hits = Object.entries(trace.ruleHits);
|
||||
if (hits.length > 0) {
|
||||
|
||||
@@ -162,6 +162,38 @@ Current evidence:
|
||||
- Expected savings are about 7.5 elapsed minutes and 60 runner-minutes per
|
||||
qualifying single-PR group, before queue batching discounts.
|
||||
|
||||
## Daemon UI P0 capability shadow
|
||||
|
||||
The UI P0 capability shadow is evidence-only. The applied `ui_p0_matrix`
|
||||
remains the full four-domain matrix in PR and merge-queue plans; no job reads
|
||||
the shadow candidate as an execution input.
|
||||
|
||||
The `daemon-runtime-definition` capability matches changes confined to:
|
||||
|
||||
- `apps/daemon/src/runtimes/defs/`;
|
||||
- `capabilities.ts`, `local-profiles.ts`, `metadata.ts`, and `registry.ts`
|
||||
directly under `apps/daemon/src/runtimes/`;
|
||||
- the explicit companion-test list in
|
||||
`DAEMON_RUNTIME_DEFINITION_EXACT` (`scripts/scopes.ts`).
|
||||
|
||||
Its candidate keeps `entry-settings`, `project-workspace`, and
|
||||
`project-runtime`, and omits only `workspace-restoration`. The project
|
||||
workspace remains included because its P0 coverage contains the local-agent
|
||||
and model selector. Any empty, unresolved, mixed, unknown, or out-of-surface
|
||||
change falls back to the full four-domain matrix and records the reason in
|
||||
`trace.uiP0Shadow`.
|
||||
|
||||
Guard: `UI P0 shadow contract` (`scripts/check-ui-p0-shadow.ts`). It pins the
|
||||
applied full matrix, the candidate group set, representative in-bound
|
||||
resolution, and full fallback for shared daemon, runtime-composition, web, and
|
||||
unresolved inputs. The shadow must accumulate successful paired runs before it
|
||||
can become an execution input under the certain-tier requirements.
|
||||
|
||||
The latest-400 first-parent replay contains three matching groups. The
|
||||
candidate would avoid one UI P0 worker per matching group, currently about
|
||||
8.5–9.2 runner-minutes, but the shadow produces no execution savings until its
|
||||
paired evidence satisfies the promotion requirements.
|
||||
|
||||
## Zero-effect merge-queue policy floor
|
||||
|
||||
A merge-queue plan that trusts every changed file at `certain` and receives no
|
||||
|
||||
Reference in New Issue
Block a user