feat: add codex stdio code agent session gate

This commit is contained in:
Code Queue Review
2026-05-23 13:29:22 +00:00
parent ad1383ecf7
commit f42d8d121d
20 changed files with 2105 additions and 322 deletions
+50 -24
View File
@@ -1,5 +1,6 @@
const trustedLiveProviders = new Set(["openai-responses", "codex-cli", "codex-readonly-runner"]);
const trustedRunnerProviders = new Set(["codex-readonly-runner"]);
const trustedLiveProviders = new Set(["openai-responses", "codex-cli", "codex-readonly-runner", "codex-stdio"]);
const trustedRunnerProviders = new Set(["codex-stdio"]);
const partialRunnerProviders = new Set(["codex-readonly-runner"]);
const readonlySessionCapabilityLevels = new Set(["read-only-tools", "read-only-session-tools"]);
const untrustedProviderPattern = /\b(?:echo|mock|fixture|stub|sample)\b/iu;
const blockedCodeAgentUiLabels = new Set([
@@ -115,27 +116,38 @@ export function classifyCodexRunnerCapability(payload, { httpStatus = null } = {
const missing = [];
if (payload?.status !== "completed") missing.push("completed status");
if (!trustedRunnerProviders.has(provider)) missing.push("runner provider");
if (runnerKind !== "hwlab-readonly-runner") missing.push("runner.kind");
if (!readonlySessionCapabilityLevels.has(capabilityLevel)) missing.push("capabilityLevel=read-only-session-tools");
if (runnerKind !== "codex-mcp-stdio-runner") missing.push("runner.kind=codex-mcp-stdio-runner");
if (capabilityLevel !== "long-lived-codex-stdio-session") missing.push("capabilityLevel=long-lived-codex-stdio-session");
if (!workspace) missing.push("workspace");
if (sandbox !== "read-only") missing.push("sandbox=read-only");
if (sessionMode !== "controlled-readonly-session-registry") missing.push("sessionMode=controlled-readonly-session-registry");
if (implementationType !== "controlled-readonly-session-registry") missing.push("implementationType=controlled-readonly-session-registry");
if (sandbox !== "workspace-write") missing.push("sandbox=workspace-write");
if (sessionMode !== "codex-mcp-stdio-long-lived") missing.push("sessionMode=codex-mcp-stdio-long-lived");
if (implementationType !== "repo-owned-codex-mcp-stdio-session") missing.push("implementationType=repo-owned-codex-mcp-stdio-session");
if (!session) missing.push("session");
if (session && !["idle", "ready", "busy"].includes(session.status)) missing.push("session.status active/idle");
if (session && typeof session.idleTimeoutMs !== "number") missing.push("session.idleTimeoutMs");
if (session && !session.lastTraceId) missing.push("session.lastTraceId");
if (session && session.longLivedSession !== true) missing.push("session.longLivedSession=true");
if (session && session.codexStdio !== true) missing.push("session.codexStdio=true");
if (!sessionReuse) missing.push("sessionReuse");
if (toolCalls.length === 0) missing.push("toolCalls");
if (!runnerTrace) missing.push("runnerTrace");
if (!skills) missing.push("skills");
if (!runnerLimitations.includes("not-codex-stdio")) missing.push("runnerLimitations.not-codex-stdio");
if (payload?.runner?.codexStdio !== false) missing.push("runner.codexStdio=false");
if (payload?.runner?.writeCapable !== false) missing.push("runner.writeCapable=false");
if (payload?.runner?.durableSession !== false) missing.push("runner.durableSession=false");
if (payload?.runner?.codexStdio !== true) missing.push("runner.codexStdio=true");
if (payload?.runner?.writeCapable !== true) missing.push("runner.writeCapable=true");
if (payload?.runner?.durableSession !== true) missing.push("runner.durableSession=true");
if (!longLivedSessionGate) missing.push("longLivedSessionGate");
if (longLivedSessionGate?.status !== "pass" || longLivedSessionGate?.pass !== true) missing.push("longLivedSessionGate=pass");
if (missing.length > 0) {
if (partialRunnerProviders.has(provider) && runnerKind === "hwlab-readonly-runner") {
return {
status: "blocked",
level: "BLOCKED/controlled-readonly-session-registry",
blocker: "controlled-readonly-not-long-lived",
capabilityPass: false,
reason: "controlled-readonly-session-registry can expose bounded read-only tools, but it cannot pass the long-lived Codex stdio capability gate."
};
}
return {
status: "blocked",
level: "BLOCKED/runner-capability",
@@ -145,16 +157,6 @@ export function classifyCodexRunnerCapability(payload, { httpStatus = null } = {
};
}
if (longLivedSessionGate?.status === "pass") {
return {
status: "blocked",
level: "BLOCKED/runner-gate",
blocker: "unexpected-long-lived-green",
capabilityPass: false,
reason: "read-only session registry responses must not claim the full long-lived Codex stdio gate."
};
}
if (toolCalls.some((tool) => tool.status !== "completed")) {
return {
status: "blocked",
@@ -167,11 +169,11 @@ export function classifyCodexRunnerCapability(payload, { httpStatus = null } = {
return {
status: "pass",
level: "#317 read-only session registry partial pass",
level: "#275 long-lived Codex stdio session skeleton pass",
blocker: null,
capabilityPass: true,
longLivedSession: false,
reason: "completed read-only session-registry response includes session, workspace, sandbox, toolCalls, skills, runnerTrace, and a blocked long-lived Codex stdio gate"
longLivedSession: true,
reason: "completed repo-owned Codex stdio response includes reusable session, workspace-write sandbox, toolCalls, skills, runnerTrace, and a passed long-lived session gate"
};
}
@@ -538,6 +540,15 @@ export function inspectRealCompletionEvidence(payload) {
if (provider === "codex-readonly-runner" && payload?.longLivedSessionGate?.status === "pass") {
return { ok: false, reason: "read-only runner cannot claim long-lived session gate pass" };
}
if (provider === "codex-readonly-runner") {
return { ok: false, reason: "controlled read-only runner is partial capability only and cannot be reported as full Code Agent completion" };
}
if (provider === "openai-responses" && payload?.longLivedSessionGate?.status !== "pass") {
return { ok: false, reason: "OpenAI Responses fallback is text-chat-only and cannot be reported as full Code Agent completion" };
}
if (provider === "codex-stdio" && payload?.longLivedSessionGate?.status !== "pass") {
return { ok: false, reason: "codex-stdio completion is missing long-lived session gate pass" };
}
if (untrustedProviderPattern.test(`${provider} ${backend}`)) {
return { ok: false, reason: `provider/backend looks non-real: ${payload.provider}/${payload.backend}` };
}
@@ -675,6 +686,7 @@ function summarizeSession(value) {
turn: typeof value.turn === "number" ? value.turn : null,
longLivedSession: value.longLivedSession === true,
codexStdio: value.codexStdio === true,
writeCapable: value.writeCapable === true,
secretMaterialStored: value.secretMaterialStored === true
};
}
@@ -687,6 +699,20 @@ function summarizeCodexStdioFeasibility(value) {
currentImplementation: stringOrNull(value.currentImplementation),
implementationRequired: stringOrNull(value.implementationRequired),
binaryOnPath: value.binaryOnPath === true,
workspace: stringOrNull(value.workspace),
sandbox: stringOrNull(value.sandbox),
ready: value.ready === true,
sessionLifecycle: value.sessionLifecycle && typeof value.sessionLifecycle === "object"
? {
create: value.sessionLifecycle.create === true,
reuse: value.sessionLifecycle.reuse === true,
cancel: value.sessionLifecycle.cancel === true,
reap: value.sessionLifecycle.reap === true,
idleTimeout: value.sessionLifecycle.idleTimeout === true,
traceCapture: value.sessionLifecycle.traceCapture === true,
idleTimeoutMs: typeof value.sessionLifecycle.idleTimeoutMs === "number" ? value.sessionLifecycle.idleTimeoutMs : null
}
: null,
blockers: Array.isArray(value.blockers)
? value.blockers.map((blocker) => ({
code: stringOrNull(blocker.code),