fix(e2e): configure supported rolling agents with warm policy

The warm environment was overridden by each profile’s explicit per-turn agent policy. Use the production managed warm capability to select supported profiles, set their agent policy to warm, and retain per-turn coverage for every qualified native profile.

The effective-policy regression fails on the old catalog; 39 affected catalog and controller checks pass. Shared-package type declarations need a fresh build for the broad local typecheck.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-11-04 11:56:31 -06:00
1 parent 8f06bd4e17
commit 5dfe1d4b29
4 files changed
+42 -9

No files matched your search

+3
View File
@@ -191,6 +191,9 @@ Postgres. Each controller has an independent compiled build and cache. The copie
app retains the checkout's `cli/` and `packages/` dependency links, including the
development Runner vendor entry. Shared workspace dependencies mean this is
not released-container or Railway evidence.
The warm lane selects providers through the production managed warm-session
capability and explicitly sets the agent policy to warm. The per-turn lane
retains every registered provider's per-turn policy.
The read-only recovery observer captures the live predecessor's identity just
before handoff, then requires a new controller generation, authenticated Runner
attachment, and new canonical events for the original execution. No fixture
+21 -3
View File
@@ -33,6 +33,24 @@ import {
} from "./selectors.js";
describe("runner E2E catalog", () => {
it("uses effective warm agent policy only for supported rolling warm providers", () => {
const warm = runnerMatrix.filter(cell => cell.suite.id === "rolling-web-deployment-warm");
const perTurn = runnerMatrix.filter(cell => cell.suite.id === "rolling-web-deployment");
expect(warm.some(cell => cell.profile.id === "runner-codex")).toBe(true);
expect(warm.some(cell => ["runner-opencode", "runner-acpx-claude", "runner-acpx-grok"].includes(cell.profile.id))).toBe(false);
expect(perTurn.length).toBeGreaterThan(warm.length);
for (const cell of [...warm, ...perTurn]) {
const secretRefs = Object.fromEntries([cell.profile.credential, "DAYTONA_API_KEY"].map(key => [key,
{ type: "secret_ref" as const, secretId: "22222222-2222-4222-8222-222222222222", version: "latest" as const }]));
const input = { executionId: cell.id, secretRefs, daytonaImage: `fixture@sha256:${"a".repeat(64)}` };
const agent = cell.profile.buildAgent({ ...input, environmentId: "env-1", environmentFixtureId: "daytona", workspacePath: "/workspace" });
const environment = cell.environment.buildEnvironment(input);
const expected = cell.suite.id === "rolling-web-deployment-warm" ? "warm" : "per_turn";
expect(agent.adapterConfig).toMatchObject({ lifecycleMode: expected });
expect(environment.config).toMatchObject({ runnerLifecycleMode: expected, reuseLease: expected === "warm" });
expect(cell.suite.expectedMatrixSize).toBe(cell.suite.profiles.length * cell.suite.tasks.length);
}
});
it("keeps verified artifact transfer a single explicit Daytona run", () => {
const id = "api-artifact-transfer.runner-codex.daytona.verified-artifact-copy";
const cells = selectRunnerExecutions(parseRunnerSelectors(["--id", id]));
@@ -312,11 +330,11 @@ describe("runner E2E catalog", () => {
expect(localIntegrityTasks).toHaveLength(2);
expect(openRouterBreadthTasks).toHaveLength(3);
expect(runnerSuites.map((suite) => suite.expectedMatrixSize)).toEqual([
1, 9, 9, 9, 9, 4, 2, 1, 3, 2, 2, 4, 4, 4, 4, 4, 4, 8, 10, 6, 63, 12, 6, 4, 2, 4, 2, 30, 3, 16, 16, 20, 2, 1, 6, 8, 46, 2, 23, 15, 52, 6, 6, 20, 26, 52, 5, 28, 18, 2, 6, 6, 13, 10, 4, 48, 16, 10, 2, 1, 1, 4, 116, 2, 1, 2,
1, 9, 2, 9, 9, 4, 2, 1, 3, 2, 2, 4, 4, 4, 4, 4, 4, 8, 10, 6, 63, 12, 6, 4, 2, 4, 2, 30, 3, 16, 16, 20, 2, 1, 6, 8, 46, 2, 23, 15, 52, 6, 6, 20, 26, 52, 5, 28, 18, 2, 6, 6, 13, 10, 4, 48, 16, 10, 2, 1, 1, 4, 116, 2, 1, 2,
]);
expect(validateRunnerCatalog()).toHaveLength(837);
expect(new Set(runnerMatrix.map((entry) => entry.id)).size).toBe(837);
expect(validateRunnerCatalog()).toHaveLength(830);
expect(new Set(runnerMatrix.map((entry) => entry.id)).size).toBe(830);
expect(
runnerMatrix.filter((entry) => entry.suite.id === "core-compatibility"),
).toHaveLength(48);
+13 -3
View File
@@ -1,4 +1,5 @@
import { ROLLING_WEB_DEPLOYMENT_SUITE, ROLLING_WEB_DEPLOYMENT_WARM_SUITE } from "./controller-rolling-deployment.js";
import { supportsManagedNativeWarmSession } from "../../server/src/services/native-runtime/native-warm-capability.js";
import { FEEDBACK_PERSISTENCE_SUITE, feedbackPersistenceTask, feedbackPersistenceDigest } from "./feedback-persistence.js";
import { followupStopTask, followupStopDigest } from "./followup-stop-resume.js";
import { finalizationRecoveryTask, finalizationRecoveryDigest } from "./finalization-recovery.js";
@@ -1252,15 +1253,24 @@ const rollingDeploymentProfiles = [...runnerProfiles, ...extendedHarnessProfiles
return { ...agent, adapterConfig };
} };
});
const rollingWarmDeploymentProfiles = rollingDeploymentProfiles.filter(profile => {
const backend = profile.provider === "codex" ? "codex_app_server" : profile.provider === "opencode" ? "opencode_server" : "acpx_runtime";
return supportsManagedNativeWarmSession({ backend, acpxAgent: "acpxAgent" in profile ? profile.acpxAgent : undefined },
profile.credential === "COPILOT_GITHUB_TOKEN" ? { provider: "github", method: "api_key" } : undefined);
}).map(profile => ({ ...profile, buildAgent(input: AgentFixtureBuildInput) {
const agent = profile.buildAgent(input);
return { ...agent, adapterConfig: { ...(agent.adapterConfig as Record<string, unknown>), lifecycleMode: "warm" } };
} }));
const rollingDeploymentSuites: RunnerSuiteFixture[] = [
{ id: ROLLING_WEB_DEPLOYMENT_SUITE, environment: runnerEnvironments.find(environment => environment.id === "daytona")! },
{ id: ROLLING_WEB_DEPLOYMENT_WARM_SUITE, environment: daytonaControllerOutageEnvironment },
].map(({ id, environment }) => ({
...remoteWorkspaceStorageSuite, id, label: `Rolling control-plane web deployment (${environment.configurationKey ? "warm" : "per-turn"})`,
description: "Overlap independent ephemeral web servers while a remote execution stays active; keep ordinary reads, saves, files and a later native continuation working.",
profiles: rollingDeploymentProfiles, environments: [environment],
expectedMatrixSize: rollingDeploymentProfiles.length * remoteWorkspaceStorageSuite.tasks.length,
definitionMetadata: { ...remoteWorkspaceStorageSuite.definitionMetadata, version: 4, controllerDowntimeMs: 0,
profiles: id === ROLLING_WEB_DEPLOYMENT_WARM_SUITE ? rollingWarmDeploymentProfiles : rollingDeploymentProfiles, environments: [environment],
expectedMatrixSize: (id === ROLLING_WEB_DEPLOYMENT_WARM_SUITE ? rollingWarmDeploymentProfiles : rollingDeploymentProfiles).length * remoteWorkspaceStorageSuite.tasks.length,
definitionMetadata: { ...remoteWorkspaceStorageSuite.definitionMetadata, version: 5, controllerDowntimeMs: 0,
activeWorkBoundary: "foreground-180-second-cli-reliability-soak-and-live-owner-recheck",
workspaceFileSource: environment.configurationKey ? "live" : "saved-exact-snapshot-after-per-turn-retirement",
lifecycleCoverage: environment.configurationKey ? "warm-reusable" : "per-turn-disposable", providerCoverage: "registered-native-daytona-profiles",
@@ -57,7 +57,7 @@ describe("rolling controller qualification", () => {
const [outage] = selectRunnerExecutions(parseRunnerSelectors(["--suite", "remote-workspace-storage"]));
expect(controllerOutageForExecution(outage!, {})).toEqual({ signal: "SIGKILL", holdMs: 300_000 });
});
it("requires both lifecycle modes for every production-qualified native sandbox profile", () => {
it("covers every qualified native profile per turn and each supported warm profile", () => {
const executions = ["rolling-web-deployment", "rolling-web-deployment-warm"]
.flatMap(suite => selectRunnerExecutions(parseRunnerSelectors(["--suite", suite])));
const native = [...runnerProfiles, ...extendedHarnessProfiles, kimiRunnerProfile]
@@ -74,12 +74,14 @@ describe("rolling controller qualification", () => {
&& (!profile.qualificationCandidate || QUALIFIED_ACPX_PROFILES[profile.qualificationCandidate].qualificationStatus !== "pending"))
.map(kind));
expect(new Set(native.map(kind))).toEqual(registeredKinds);
const warmIds = new Set(runnerSuites.find(suite => suite.id === "rolling-web-deployment-warm")!.profiles.map(profile => profile.id));
for (const profile of native) {
const cells = executions.filter(execution => execution.profile.id === profile.id);
expect(cells).toHaveLength(2);
expect(cells.filter(cell => cell.suite.id === "rolling-web-deployment")).toHaveLength(1);
expect(cells).toHaveLength(warmIds.has(profile.id) ? 2 : 1);
expect(cells.every(cell => !cell.profile.qualificationCandidate)).toBe(true);
expect(new Set(cells.map(cell => cell.environment.configurationKey ?? "per_turn")))
.toEqual(new Set(["per_turn", "warm-controller-outage-v1"]));
.toEqual(new Set(warmIds.has(profile.id) ? ["per_turn", "warm-controller-outage-v1"] : ["per_turn"]));
}
expect(executions.every(execution => execution.suite.definitionMetadata?.retainedControllerContinuation === true)).toBe(true);
});