Files
pikasTech-unidesk/scripts/code-queue-pr-preflight-contract-test.ts
T

1081 lines
67 KiB
TypeScript

import { codexPrPreflightQueryForTest } from "./src/code-queue";
import type { UniDeskConfig } from "./src/config";
type JsonRecord = Record<string, unknown>;
function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}
function asRecord(value: unknown): JsonRecord {
assertCondition(typeof value === "object" && value !== null && !Array.isArray(value), "expected JSON object", { value });
return value as JsonRecord;
}
function localBackendCoreMissingFixture(): JsonRecord {
return {
ok: false,
failureKind: "target-stack-not-running",
degradedReason: "backend-core-container-missing",
runnerDisposition: "infra-blocked",
message: "backend-core/database target containers are not running; only verify-only containers were observed.",
targetStack: {
expectedContainers: ["unidesk-backend-core", "unidesk-database", "baidu-netdisk-backend"],
missingContainers: ["unidesk-backend-core", "unidesk-database", "baidu-netdisk-backend"],
verifyOnlyObserved: true,
},
readOnlyCommands: [
"bun scripts/cli.ts server status",
"bun scripts/cli.ts schedule list",
"bun scripts/cli.ts schedule runs --limit 20",
],
authorizationRequiredForRecovery: ["restore runtime secret coverage", "start the target stack"],
};
}
function remoteControlPlaneResult(overrides: Partial<JsonRecord> = {}): JsonRecord {
return {
ok: true,
runnerDisposition: "ready",
failureKind: null,
degradedReason: null,
upstream: { ok: true, status: 200 },
controlPlane: {
mode: "remote-frontend",
host: "74.48.78.17",
frontendUrl: "http://74.48.78.17:18081",
localBackendCoreMissing: true,
remoteFallbackUsed: true,
},
preflight: {
ok: true,
runnerDisposition: "ready",
failureKind: null,
degradedReason: null,
checkedAt: "2026-05-20T00:00:00.000Z",
runner: {
serviceId: "code-queue",
plane: "D601 k3s scheduler/runner",
queueScope: "all queues executed by the scheduler, including default",
cwd: "/workspace/unidesk",
pid: 123,
},
tokenCoverage: {
ok: true,
source: "GH_TOKEN",
ghTokenPresent: true,
githubTokenPresent: false,
ghCredentialStorePresent: false,
runnerDisposition: "ready",
missing: [],
scope: "scheduler-runner-env",
},
authBroker: {
ok: true,
source: "GH_TOKEN",
needed: false,
configured: false,
runnerDisposition: "ready",
failureKind: null,
degradedReason: null,
runnerEnvTokenRequiredWithoutBroker: true,
brokerCredentialSource: null,
valuesPrinted: false,
evidence: {
envTokenMissing: false,
missing: [],
systemGhBinaryOk: true,
systemGhBinaryRequiredForWrites: false,
unideskGhCliObserved: true,
unideskGhCliOk: true,
unideskGhCliRequiresSystemGhBinary: false,
systemGhMissingMisclassifiedAsUniDeskCliMissing: false,
},
next: [],
reference: "docs/reference/auth-broker.md#post-v1githubpr-preflight",
},
prCapabilityContract: {
targetBranch: "master",
tokenSource: "GH_TOKEN",
systemGhBinaryRequiredForWrites: false,
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true, role: "repo-native REST GitHub CLI used by bun scripts/cli.ts gh", requiresSystemGhBinary: false },
pushDryRun: { requested: false, ref: "refs/heads/probe/code-queue-pr-capability-dryrun", writesRemote: false, commandShape: "git push --dry-run origin HEAD:refs/heads/probe/code-queue-pr-capability-dryrun" },
prCreateDryRun: { requested: false, headBranch: "feature/code-queue-pr-preflight", writesRemote: false, commandShape: "bun scripts/cli.ts gh pr create --repo pikasTech/unidesk --base master --head feature/code-queue-pr-preflight --dry-run" },
expectedPrHandoff: {
sourceBranch: "feature/code-queue-pr-preflight",
targetBranch: "master",
runnerCreatesPrAfterAuthorization: true,
commanderReviewsAndMerges: true,
preflightCreatesPr: false,
preflightMergesPr: false,
},
mergeBoundary: {
supported: true,
command: "bun scripts/cli.ts gh pr merge <number> --repo pikasTech/unidesk",
preflightRequired: true,
dryRunCommand: "bun scripts/cli.ts gh pr merge <number> --repo pikasTech/unidesk --dry-run",
note: "UniDesk CLI can merge PRs only after explicit task authorization and a ready closeout preflight; runner handoff still starts with PR creation and evidence.",
},
},
controlPlane: {
mode: "local-backend-core",
localBackendCoreMissing: false,
remoteFallbackUsed: false,
},
tools: {
git: { ok: true, path: "/usr/bin/git", version: "git version 2.43.0" },
gh: { ok: true, path: "/usr/bin/gh", version: "gh version 2.45.0" },
systemGhBinary: { ok: true, path: "/usr/bin/gh", version: "gh version 2.45.0" },
hub: { ok: false, path: null, version: null },
jq: { ok: true, path: "/usr/bin/jq", version: "jq-1.7" },
ssh: { ok: true, path: "/usr/bin/ssh", version: "OpenSSH_9.6" },
curl: { ok: true, path: "/usr/bin/curl", version: "curl 8.5.0" },
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true, role: "repo-native REST GitHub CLI used by bun scripts/cli.ts gh", requiresSystemGhBinary: false },
},
agentPorts: {
codex: { ok: true, commandPath: "/usr/local/bin/codex", version: "codex 0.128.0", errors: [] },
opencode: { ok: true, commandPath: "/usr/local/bin/opencode", version: "opencode 1.14.48", errors: [] },
},
git: {
insideWorktree: true,
branch: "feature/code-queue-pr-preflight",
head: "abc1234",
originMaster: "def5678",
remoteOrigin: "git@github.com:pikasTech/unidesk.git",
home: "/root",
homeWritable: true,
knownHostsPresent: true,
privateKeyPresent: true,
},
githubContext: {
host: "github.com",
apiBaseUrl: "https://api.github.com",
repo: "pikasTech/unidesk",
issueProbeNumber: 35,
},
egress: {
proxy: {
selectedProxyHost: "d601-provider-egress-proxy.unidesk.svc.cluster.local",
selectedProxyPort: "18789",
selectedProxyHostResolvable: true,
},
githubDefault: { command: "curl", args: ["-IsS", "https://github.com"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
apiDefault: { command: "curl", args: ["-IsS", "https://api.github.com"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
issueApi: null,
},
remote: {
gitLsRemote: { command: "git", args: ["ls-remote", "--heads", "origin", "master"], ok: true, exitCode: 0, signal: null, error: null, stdout: "abc1234\trefs/heads/master\n", stderr: "" },
gitHttpsLsRemote: null,
githubSshAuthenticated: true,
ghAuthStatus: { command: "gh", args: ["auth", "status"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghRepoView: { command: "gh", args: ["repo", "view", "pikasTech/unidesk"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghIssueView: { command: "gh", args: ["issue", "view", "35"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghPrReadOnly: { command: "gh", args: ["pr", "list"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
},
pushDryRun: null,
prCreateDryRun: null,
limitations: [],
risks: [],
recoveryHint: "Runner PR workflow has env-token coverage for the scheduler.",
commands: {
local: "bun scripts/cli.ts gh auth status --repo pikasTech/unidesk",
runner: "bun scripts/cli.ts codex pr-preflight --remote",
runnerPushDryRun: "bun scripts/cli.ts codex pr-preflight --remote --push-dry-run --push-dry-run-ref refs/heads/probe/code-queue-pr-capability",
runnerPrCreateDryRun: "bun scripts/cli.ts codex pr-preflight --remote --pr-create-dry-run --pr-create-dry-run-head <head-branch>",
rawProxy: "bun scripts/cli.ts microservice proxy code-queue /api/runtime-preflight?remote=1 --raw",
},
},
...overrides,
};
}
function rawRuntimePreflightFixture(overrides: Partial<JsonRecord> = {}): JsonRecord {
return {
ok: true,
checkedAt: "2026-05-20T00:00:00.000Z",
cwd: "/workspace/unidesk",
pid: 123,
pullRequestDelivery: {
ok: true,
checkedAt: "2026-05-20T00:00:00.000Z",
tools: {
git: { ok: true, path: "/usr/bin/git", version: "git version 2.43.0" },
gh: { ok: false, path: null, version: null },
hub: { ok: false, path: null, version: null },
jq: { ok: true, path: "/usr/bin/jq", version: "jq-1.7" },
ssh: { ok: true, path: "/usr/bin/ssh", version: "OpenSSH_9.6" },
curl: { ok: true, path: "/usr/bin/curl", version: "curl 8.5.0" },
},
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true },
credentials: {
ghTokenPresent: false,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
authBroker: {
ok: false,
configured: false,
source: "broker/auth-broker-needed",
endpointEnvKey: null,
runnerEnvTokenRequired: false,
credentialSource: null,
failureKind: "auth-missing",
degradedReason: "auth-broker-needed",
capability: {
source: "missing-token",
githubRestAuth: false,
operations: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"],
systemGhBinaryRequiredForWrites: false,
preflightWritesRemote: false,
preflightCreatesPr: false,
preflightMergesPr: false,
realPrCreateRequiresCommanderAuthorization: true,
valuesPrinted: false,
},
nextAction: "configure-auth-broker-or-env-token",
next: ["configure UNIDESK_AUTH_BROKER_URL or AUTH_BROKER_URL for broker-backed runner auth"],
valuesRead: false,
valuesPrinted: false,
},
git: {
insideWorktree: true,
branch: "code-queue/issue-35-pr-dry-run-probe",
head: "abc1234",
originMaster: "def5678",
remoteOrigin: "git@github.com:pikasTech/unidesk.git",
home: "/root",
homeWritable: true,
knownHostsPresent: true,
privateKeyPresent: true,
},
githubContext: {
host: "github.com",
apiBaseUrl: "https://api.github.com",
repo: "pikasTech/unidesk",
issueProbeNumber: 20,
},
egress: {
proxy: {
selectedProxyHost: "d601-provider-egress-proxy.unidesk.svc.cluster.local",
selectedProxyPort: "18789",
selectedProxyHostResolvable: true,
},
githubDefault: { command: "curl", args: ["-IsS", "https://github.com"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
apiDefault: { command: "curl", args: ["-IsS", "https://api.github.com"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
issueApi: null,
},
remote: {
gitLsRemote: { command: "git", args: ["ls-remote", "--heads", "origin", "master"], ok: true, exitCode: 0, signal: null, error: null, stdout: "abc1234\trefs/heads/master\n", stderr: "" },
gitHttpsLsRemote: null,
githubSshAuthenticated: true,
ghAuthStatus: null,
ghRepoView: null,
ghIssueView: null,
ghPrReadOnly: null,
},
limitations: [],
risks: [
"system gh binary is missing; UniDesk REST gh CLI remains the supported PR create/comment path when scripts/cli.ts and GH_TOKEN/GITHUB_TOKEN or auth-broker are available",
],
},
ports: {},
...overrides,
};
}
async function main(): Promise<void> {
let observedLocalPath = "";
const remoteFallback = await codexPrPreflightQueryForTest(["--remote", "--issue", "35"], {
config: {
project: { name: "unidesk", timezone: "Etc/UTC" },
runtime: { typescript: "bun", bunVersion: "1.3.13" },
network: {
host: "0.0.0.0",
publicHost: "74.48.78.17",
core: { port: 18080, containerPort: 8080 },
frontend: { port: 18081, containerPort: 8080 },
devFrontend: { port: 18083, containerPort: 8080 },
database: { port: 15432, containerPort: 5432 },
providerIngress: { port: 18082, containerPort: 8081 },
},
database: { user: "unidesk", password: "<redacted-test-password>", name: "unidesk", volume: "unidesk_pgdata_10gb", volumeSize: "15GB" },
providerGateway: {
id: "main-server",
name: "Main Server Provider",
token: "<redacted-test-token>",
labels: { host: "main-server", role: "self-provider", docker: true },
heartbeatIntervalMs: 15000,
reconnectBaseMs: 1000,
reconnectMaxMs: 30000,
metrics: { diskPath: "/" },
upgrade: { hostProjectRoot: "/root/unidesk", workspacePath: "/workspace", composeFile: "docker-compose.yml", composeEnvFile: ".state/docker-compose.env", composeProject: "unidesk", service: "provider-gateway", runnerImage: "unidesk_provider-gateway" },
},
docker: { composeFile: "docker-compose.yml", projectName: "unidesk" },
microservices: [],
paths: { stateDir: ".state", logsDir: "logs", docsReferenceDir: "docs/reference" },
sshForwarding: { mode: "ws", keyDir: "/root/.ssh", host: "main-server", port: 22, user: "root" },
auth: { username: "admin", password: "<redacted-test-password>", sessionSecret: "<redacted-test-session-secret>", sessionTtlSeconds: 86400 },
},
coreFetch: (path) => {
observedLocalPath = path;
return localBackendCoreMissingFixture();
},
remoteMainServerPrPreflight: () => remoteControlPlaneResult({
controlPlane: {
mode: "remote-frontend",
host: "74.48.78.17",
frontendUrl: "http://74.48.78.17:18081",
localBackendCoreMissing: true,
remoteFallbackUsed: true,
},
failureKind: null,
degradedReason: null,
}),
});
assertCondition(observedLocalPath === "/api/microservices/code-queue/proxy/api/runtime-preflight?remote=1&issue=35", "runner-like local path should stay on the stable proxy", { observedLocalPath });
const fallback = asRecord(remoteFallback);
assertCondition(fallback.ok === true, "remote fallback should succeed", fallback);
assertCondition(fallback.runnerDisposition === "ready", "remote fallback should stay ready", fallback);
assertCondition(fallback.controlPlane && asRecord(fallback.controlPlane).remoteFallbackUsed === true, "remote fallback should be marked", fallback.controlPlane);
assertCondition(fallback.failureKind === null, "remote fallback should not invent a failure kind when remote control plane is healthy", fallback);
const fallbackLocalGap = asRecord(fallback.localObservationGap);
assertCondition(fallbackLocalGap.kind === "runner-local-observation-gap", "healthy remote fallback should classify local backend-core absence as runner-local observation gap", fallbackLocalGap);
assertCondition(fallbackLocalGap.schedulerStoppage === false, "local observation gap must not imply scheduler stoppage", fallbackLocalGap);
assertCondition(fallback.localObservation === undefined, "healthy remote fallback default output should omit full local observation", fallback);
assertCondition(fallback.remoteObservation === undefined, "healthy remote fallback default output should omit full remote observation", fallback);
assertCondition(asRecord(fallback.disclosure).fullObservationsOmitted === true, "healthy remote fallback should disclose omitted full observations", fallback.disclosure);
assertCondition(asRecord(fallback.localObservationSummary).failureKind === "target-stack-not-running", "healthy remote fallback should keep bounded local observation summary", fallback.localObservationSummary);
assertCondition(asRecord(fallback.remoteObservationSummary).ok === true, "healthy remote fallback should keep bounded remote observation summary", fallback.remoteObservationSummary);
assertCondition(fallback.preflight === undefined, "remote fallback default output should omit detailed preflight", fallback);
const fallbackSchedulerPreflight = asRecord(fallback.schedulerPreflight);
assertCondition(fallbackSchedulerPreflight.authReady === true, "remote fallback scheduler summary should stay ready", fallbackSchedulerPreflight);
assertCondition(fallbackSchedulerPreflight.authSource === "GH_TOKEN", "token source should be GH_TOKEN", fallbackSchedulerPreflight);
assertCondition(asRecord(fallback.prCapability).targetBranch === "master", "target branch should stay master", fallback.prCapability);
const authMissing = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => localBackendCoreMissingFixture(),
});
const remoteControlPlaneMissingRecord = asRecord(authMissing);
assertCondition(remoteControlPlaneMissingRecord.ok === false, "missing control plane should fail", remoteControlPlaneMissingRecord);
assertCondition(remoteControlPlaneMissingRecord.failureKind === "control-plane-missing", "missing control plane should classify as control-plane-missing", remoteControlPlaneMissingRecord);
assertCondition(remoteControlPlaneMissingRecord.degradedReason === "remote-control-plane-unreachable", "missing control plane should classify as remote-control-plane-unreachable", remoteControlPlaneMissingRecord);
assertCondition(remoteControlPlaneMissingRecord.runnerDisposition === "infra-blocked", "missing remote control plane keeps legacy runnerDisposition compatibility", remoteControlPlaneMissingRecord);
assertCondition(remoteControlPlaneMissingRecord.blockingDisposition === "control-plane-observation-gap", "missing remote control plane should expose observation gap blocking disposition", remoteControlPlaneMissingRecord);
const remoteControlPlaneGap = asRecord(remoteControlPlaneMissingRecord.observationGap);
assertCondition(remoteControlPlaneGap.kind === "control-plane-observation-gap", "missing remote control plane should expose control-plane observation gap", remoteControlPlaneGap);
assertCondition(remoteControlPlaneGap.schedulerStoppage === false, "control-plane observation gap must not imply scheduler stoppage", remoteControlPlaneGap);
assertCondition(asRecord(remoteControlPlaneMissingRecord.controlPlane).localBackendCoreMissing === true, "local backend-core absence should remain evidence only", remoteControlPlaneMissingRecord.controlPlane);
const directAuthMissing = await codexPrPreflightQueryForTest(["--remote"], {
config: { network: { publicHost: "74.48.78.17", frontend: { port: 18081 } } } as unknown as UniDeskConfig,
coreFetch: () => localBackendCoreMissingFixture(),
remoteMainServerPrPreflight: () => remoteControlPlaneResult({
ok: false,
failureKind: "auth-missing",
degradedReason: "GH_TOKEN/GITHUB_TOKEN missing",
runnerDisposition: "infra-blocked",
message: "GH_TOKEN/GITHUB_TOKEN missing in remote control plane",
tokenCoverage: {
ok: false,
source: null,
ghTokenPresent: false,
githubTokenPresent: false,
ghCredentialStorePresent: false,
runnerDisposition: "infra-blocked",
missing: ["GH_TOKEN", "GITHUB_TOKEN"],
scope: "scheduler-runner-env",
},
prCapabilityContract: {
targetBranch: "master",
tokenSource: null,
systemGhBinaryRequiredForWrites: false,
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true, role: "repo-native REST GitHub CLI used by bun scripts/cli.ts gh", requiresSystemGhBinary: false },
pushDryRun: { requested: false, ref: "refs/heads/probe/code-queue-pr-capability-dryrun", writesRemote: false, commandShape: "git push --dry-run origin HEAD:refs/heads/probe/code-queue-pr-capability-dryrun" },
prCreateDryRun: { requested: false, headBranch: "feature/code-queue-pr-preflight", writesRemote: false, commandShape: "bun scripts/cli.ts gh pr create --repo pikasTech/unidesk --base master --head feature/code-queue-pr-preflight --dry-run" },
expectedPrHandoff: { sourceBranch: "feature/code-queue-pr-preflight", targetBranch: "master", runnerCreatesPrAfterAuthorization: true, commanderReviewsAndMerges: true, preflightCreatesPr: false, preflightMergesPr: false },
mergeBoundary: { supported: true, command: "bun scripts/cli.ts gh pr merge <number> --repo pikasTech/unidesk", preflightRequired: true, dryRunCommand: "bun scripts/cli.ts gh pr merge <number> --repo pikasTech/unidesk --dry-run", note: "UniDesk CLI can merge PRs only after explicit task authorization and a ready closeout preflight; runner handoff still starts with PR creation and evidence." },
},
}),
});
const directAuthMissingRecord = asRecord(directAuthMissing);
assertCondition(directAuthMissingRecord.ok === false, "auth-missing remote result should fail", directAuthMissingRecord);
assertCondition(directAuthMissingRecord.failureKind === "auth-missing", "missing token should classify as auth-missing", directAuthMissingRecord);
assertCondition(directAuthMissingRecord.degradedReason === "GH_TOKEN/GITHUB_TOKEN missing", "auth missing should state token gap", directAuthMissingRecord);
const directAuthObservationGap = asRecord(directAuthMissingRecord.observationGap);
assertCondition(directAuthObservationGap.kind === "runner-local-observation-gap", "auth missing after remote fallback should keep local backend-core absence scoped as runner-local observation gap", directAuthObservationGap);
const directAuthSummary = asRecord(directAuthMissingRecord.authScopeSummary);
const directAuthScopeBoundary = asRecord(directAuthMissingRecord.scopeBoundary);
const directAuthActiveRunner = asRecord(directAuthMissingRecord.activeRunnerPrCapability);
const directAuthRecommendedActions = Array.isArray(directAuthMissingRecord.recommendedActions) ? directAuthMissingRecord.recommendedActions : [];
assertCondition(directAuthSummary.schedulerAuthMissingIsScoped === true, "remote auth-missing should lead with scheduler-scoped auth summary", directAuthSummary);
assertCondition(String(directAuthSummary.interpretation ?? "").includes("does not prove"), "remote auth summary must not imply active runner PR incapability", directAuthSummary);
assertCondition(directAuthScopeBoundary.scopesAreIndependent === true, "remote auth-missing must distinguish scheduler env from active runner dev container", directAuthScopeBoundary);
assertCondition(directAuthScopeBoundary.schedulerAuthMissingDoesNotMeanActiveRunnerCannotCreatePr === true, "remote auth-missing should expose the explicit PR capability boundary", directAuthScopeBoundary);
assertCondition(String(directAuthScopeBoundary.authMissingInterpretation ?? "").includes("do not simplify"), "remote auth-missing must warn against overbroad interpretation", directAuthScopeBoundary);
assertCondition(directAuthActiveRunner.independentOfSchedulerPreflight === true, "active runner token capability must be a separate scope", directAuthActiveRunner);
assertCondition(Array.isArray(directAuthMissingRecord.recommendedActions), "remote auth-missing should expose bounded recommended actions", directAuthMissingRecord.recommendedActions);
assertCondition(directAuthRecommendedActions.length === 3, "remote auth-missing recommended actions should stay bounded", directAuthRecommendedActions);
assertCondition(directAuthRecommendedActions.some((action) => asRecord(action).action === "verify-current-runner-auth"), "remote auth-missing should recommend active runner auth status first", directAuthRecommendedActions);
assertCondition(directAuthRecommendedActions.some((action) => String(asRecord(action).command ?? "").includes("gh pr create") && asRecord(action).writesRemote === false), "remote auth-missing should recommend PR create dry-run", directAuthRecommendedActions);
assertCondition(directAuthMissingRecord.localObservation === undefined, "auth-missing remote fallback default output should omit full local observation", directAuthMissingRecord);
assertCondition(directAuthMissingRecord.remoteObservation === undefined, "auth-missing remote fallback default output should omit full remote observation", directAuthMissingRecord);
assertCondition(directAuthMissingRecord.preflight === undefined, "auth-missing remote fallback default output should omit detailed preflight", directAuthMissingRecord);
assertCondition(asRecord(directAuthMissingRecord.disclosure).fullObservationsOmitted === true, "auth-missing remote fallback should disclose omitted full observations", directAuthMissingRecord.disclosure);
assertCondition(asRecord(directAuthMissingRecord.disclosure).fullDetailOmitted === true, "auth-missing remote fallback should disclose omitted full detail", directAuthMissingRecord.disclosure);
assertCondition(asRecord(directAuthMissingRecord.localObservationSummary).failureKind === "target-stack-not-running", "auth-missing remote fallback should keep bounded local observation summary", directAuthMissingRecord.localObservationSummary);
assertCondition(asRecord(asRecord(directAuthMissingRecord.remoteObservationSummary).tokenCoverage).scope === "scheduler-runner-env", "auth-missing remote fallback should keep bounded remote token scope", directAuthMissingRecord.remoteObservationSummary);
assertCondition(JSON.stringify(directAuthMissingRecord).length < 12000, "auth-missing remote fallback default output should stay compact", { chars: JSON.stringify(directAuthMissingRecord).length });
const directAuthMissingFull = await codexPrPreflightQueryForTest(["--remote", "--full"], {
config: { network: { publicHost: "74.48.78.17", frontend: { port: 18081 } } } as unknown as UniDeskConfig,
coreFetch: () => localBackendCoreMissingFixture(),
remoteMainServerPrPreflight: () => remoteControlPlaneResult({
ok: false,
failureKind: "auth-missing",
degradedReason: "GH_TOKEN/GITHUB_TOKEN missing",
runnerDisposition: "infra-blocked",
tokenCoverage: {
ok: false,
source: null,
missing: ["GH_TOKEN", "GITHUB_TOKEN"],
scope: "scheduler-runner-env",
},
}),
});
const directAuthMissingFullRecord = asRecord(directAuthMissingFull);
assertCondition(directAuthMissingFullRecord.localObservation !== undefined, "--full should retain full local observation", directAuthMissingFullRecord);
assertCondition(directAuthMissingFullRecord.remoteObservation !== undefined, "--full should retain full remote observation", directAuthMissingFullRecord);
const gitRemoteGap = remoteControlPlaneResult({
ok: false,
failureKind: "git-remote-gap",
degradedReason: "git remote probe failed",
runnerDisposition: "infra-blocked",
message: "git ls-remote probe failed",
});
const gitRemoteGapRecord = asRecord(gitRemoteGap);
assertCondition(gitRemoteGapRecord.failureKind === "git-remote-gap", "git probe failures should stay structured", gitRemoteGapRecord);
const localOnlyObservationGap = await codexPrPreflightQueryForTest([], {
config: null,
coreFetch: () => localBackendCoreMissingFixture(),
});
const localOnlyObservationGapRecord = asRecord(localOnlyObservationGap);
assertCondition(localOnlyObservationGapRecord.ok === false, "local-only backend-core absence should fail the preflight", localOnlyObservationGapRecord);
assertCondition(localOnlyObservationGapRecord.failureKind === "target-stack-not-running", "local-only backend-core absence should preserve target-stack evidence", localOnlyObservationGapRecord);
assertCondition(localOnlyObservationGapRecord.runnerDisposition === "infra-blocked", "local-only backend-core absence keeps legacy runnerDisposition compatibility", localOnlyObservationGapRecord);
assertCondition(localOnlyObservationGapRecord.blockingDisposition === "runner-local-observation-gap", "local-only backend-core absence should expose runner-local blocking disposition", localOnlyObservationGapRecord);
const localOnlyGap = asRecord(localOnlyObservationGapRecord.observationGap);
assertCondition(localOnlyGap.kind === "runner-local-observation-gap", "local-only backend-core absence should include observationGap detail", localOnlyGap);
assertCondition(localOnlyGap.schedulerStoppage === false, "local-only backend-core absence must not imply scheduler stoppage", localOnlyGap);
const proxyGap = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: {
runtimePreflight: {
ok: false,
checkedAt: "2026-05-20T00:00:00.000Z",
cwd: "/workspace/unidesk",
pid: 123,
pullRequestDelivery: {
ok: false,
checkedAt: "2026-05-20T00:00:00.000Z",
tools: {
git: { ok: true, path: "/usr/bin/git", version: "git version 2.43.0" },
gh: { ok: true, path: "/usr/bin/gh", version: "gh version 2.45.0" },
jq: { ok: true, path: "/usr/bin/jq", version: "jq-1.7" },
ssh: { ok: true, path: "/usr/bin/ssh", version: "OpenSSH_9.6" },
curl: { ok: true, path: "/usr/bin/curl", version: "curl 8.5.0" },
},
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true },
credentials: {
ghTokenPresent: true,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
git: {
insideWorktree: true,
branch: "feature/code-queue-pr-preflight",
head: "abc1234",
originMaster: "def5678",
remoteOrigin: "git@github.com:pikasTech/unidesk.git",
home: "/root",
homeWritable: true,
knownHostsPresent: true,
privateKeyPresent: true,
},
githubContext: {
host: "github.com",
apiBaseUrl: "https://api.github.com",
repo: "pikasTech/unidesk",
issueProbeNumber: 20,
},
egress: {
proxy: {
selectedProxyHost: "missing-egress-proxy.unidesk.svc.cluster.local",
selectedProxyPort: "18789",
selectedProxyHostResolvable: false,
},
githubDefault: { command: "curl", args: ["-IsS", "https://github.com"], ok: false, exitCode: 6, signal: null, error: null, stdout: "", stderr: "Could not resolve proxy" },
apiDefault: { command: "curl", args: ["-IsS", "https://api.github.com"], ok: false, exitCode: 6, signal: null, error: null, stdout: "", stderr: "Could not resolve proxy" },
issueApi: null,
},
remote: {
gitLsRemote: { command: "git", args: ["ls-remote", "--heads", "origin", "master"], ok: true, exitCode: 0, signal: null, error: null, stdout: "abc1234\trefs/heads/master\n", stderr: "" },
gitHttpsLsRemote: null,
githubSshAuthenticated: true,
ghAuthStatus: { command: "gh", args: ["auth", "status"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghRepoView: { command: "gh", args: ["repo", "view", "pikasTech/unidesk"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghIssueView: { command: "gh", args: ["issue", "view", "20"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
ghPrReadOnly: { command: "gh", args: ["pr", "list"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
},
limitations: [
"configured GitHub egress proxy host is not resolvable: missing-egress-proxy.unidesk.svc.cluster.local",
"GitHub HTTPS probe failed with the default environment/proxy",
],
risks: [],
},
ports: {},
},
},
}),
});
const proxyGapRecord = asRecord(proxyGap);
assertCondition(proxyGapRecord.failureKind === "proxy-gap", "proxy failures should classify as proxy-gap", proxyGapRecord);
assertCondition(proxyGapRecord.degradedReason === "configured GitHub egress proxy host is not resolvable: missing-egress-proxy.unidesk.svc.cluster.local", "proxy degraded reason should point at the proxy", proxyGapRecord);
const githubTransientContract = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: {
runtimePreflight: rawRuntimePreflightFixture({
ok: false,
pullRequestDelivery: {
...asRecord(rawRuntimePreflightFixture().pullRequestDelivery),
ok: false,
credentials: {
ghTokenPresent: true,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
egress: {
proxy: {
selectedProxyHost: "d601-provider-egress-proxy.unidesk.svc.cluster.local",
selectedProxyPort: "18789",
selectedProxyHostResolvable: true,
},
githubDefault: { command: "curl", args: ["-IsS", "https://github.com"], ok: false, exitCode: 6, signal: null, error: null, stdout: "", stderr: "curl: (6) Could not resolve host: github.com" },
apiDefault: { command: "curl", args: ["-IsS", "https://api.github.com"], ok: false, exitCode: 6, signal: null, error: null, stdout: "", stderr: "curl: (6) Could not resolve host: api.github.com" },
issueApi: null,
},
remote: {
gitLsRemote: { command: "git", args: ["ls-remote", "--heads", "origin", "master"], ok: false, exitCode: 128, signal: null, error: null, stdout: "", stderr: "ssh: Could not resolve hostname github.com: Temporary failure in name resolution" },
gitHttpsLsRemote: null,
githubSshAuthenticated: false,
ghAuthStatus: { command: "gh", args: ["auth", "status"], ok: false, exitCode: 1, signal: null, error: null, stdout: "", stderr: "error connecting to api.github.com" },
ghRepoView: null,
ghIssueView: null,
ghPrReadOnly: null,
},
limitations: [
"GitHub HTTPS probe failed with the default environment/proxy",
"GitHub API probe failed with the default environment/proxy",
"git ls-remote origin master failed",
],
risks: [],
},
}),
},
}),
});
const githubTransientRecord = asRecord(githubTransientContract);
assertCondition(githubTransientRecord.failureKind === "github-transient", "GitHub DNS/API failures should classify separately from auth and semantic failures", githubTransientRecord);
assertCondition(githubTransientRecord.degradedReason === "github-dns-api-transient", "GitHub transient degraded reason should be stable", githubTransientRecord);
assertCondition(githubTransientRecord.runnerDisposition === "infra-blocked", "GitHub transient keeps infra-blocked disposition for legacy callers", githubTransientRecord);
assertCondition(githubTransientRecord.retryable === true, "GitHub transient should expose top-level retryable=true", githubTransientRecord);
assertCondition(githubTransientRecord.commanderAction === "retry-backoff-or-keep-running-if-heartbeat-fresh", "GitHub transient should expose top-level commander action", githubTransientRecord);
assertCondition(githubTransientRecord.preflight === undefined, "GitHub transient default output should omit detailed preflight", githubTransientRecord);
const githubTransient = asRecord(githubTransientRecord.githubTransient);
assertCondition(githubTransient.kind === "github-transient", "GitHub transient evidence should identify kind", githubTransient);
assertCondition(githubTransient.notAuthMissing === true, "GitHub transient must not be auth-missing", githubTransient);
assertCondition(githubTransient.notPrSemanticFailure === true, "GitHub transient must not be PR semantic failure", githubTransient);
assertCondition(Array.isArray(githubTransient.failedProbes) && githubTransient.failedProbes.length <= 4, "GitHub transient evidence should stay bounded", githubTransient);
assertCondition(String(githubTransient.commanderAction ?? "").includes("keep the task running"), "GitHub transient action should preserve fresh-heartbeat tasks", githubTransient);
const githubTransientFullRecord = asRecord(await codexPrPreflightQueryForTest(["--remote", "--full"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: {
runtimePreflight: rawRuntimePreflightFixture({
ok: false,
pullRequestDelivery: {
...asRecord(rawRuntimePreflightFixture().pullRequestDelivery),
ok: false,
credentials: {
ghTokenPresent: true,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
egress: {
proxy: {
selectedProxyHost: "d601-provider-egress-proxy.unidesk.svc.cluster.local",
selectedProxyPort: "18789",
selectedProxyHostResolvable: true,
},
githubDefault: { command: "curl", args: ["-IsS", "https://github.com"], ok: false, exitCode: 6, signal: null, error: null, stdout: "", stderr: "curl: (6) Could not resolve host: github.com" },
apiDefault: { command: "curl", args: ["-IsS", "https://api.github.com"], ok: false, exitCode: 6, signal: null, error: null, stdout: "", stderr: "curl: (6) Could not resolve host: api.github.com" },
issueApi: null,
},
remote: {
gitLsRemote: { command: "git", args: ["ls-remote", "--heads", "origin", "master"], ok: false, exitCode: 128, signal: null, error: null, stdout: "", stderr: "ssh: Could not resolve hostname github.com: Temporary failure in name resolution" },
gitHttpsLsRemote: null,
githubSshAuthenticated: false,
ghAuthStatus: { command: "gh", args: ["auth", "status"], ok: false, exitCode: 1, signal: null, error: null, stdout: "", stderr: "error connecting to api.github.com" },
ghRepoView: null,
ghIssueView: null,
ghPrReadOnly: null,
},
limitations: [
"GitHub HTTPS probe failed with the default environment/proxy",
"GitHub API probe failed with the default environment/proxy",
"git ls-remote origin master failed",
],
risks: [],
},
}),
},
}),
}));
const githubTransientPreflight = asRecord(githubTransientFullRecord.preflight);
assertCondition(githubTransientPreflight.retryable === true, "GitHub transient full preflight should be retryable", githubTransientPreflight);
assertCondition(githubTransientPreflight.commanderAction === "retry-backoff-or-keep-running-if-heartbeat-fresh", "GitHub transient full preflight should expose bounded commander action", githubTransientPreflight);
const k3sTunnelTimeout = {
ok: false,
status: 504,
body: {
ok: false,
error: "provider HTTP tunnel timed out or disconnected",
stage: "http-tunnel-wait",
serviceId: "k3sctl-adapter",
providerId: "D601",
requestId: "req-k3s-timeout",
detail: { retryable: true },
},
};
const fallbackRuntime = rawRuntimePreflightFixture({
pullRequestDelivery: {
...asRecord(rawRuntimePreflightFixture().pullRequestDelivery),
ok: true,
credentials: {
ghTokenPresent: true,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
},
});
const fallbackCalls: string[] = [];
const k3sFallbackRecord = asRecord(await codexPrPreflightQueryForTest(["--remote", "--issue", "20"], {
coreFetch: (path) => {
fallbackCalls.push(path);
if (path.includes("remote=1")) return k3sTunnelTimeout;
return { ok: true, status: 200, body: { runtimePreflight: fallbackRuntime } };
},
}));
assertCondition(fallbackCalls.length === 2, "k3s tunnel timeout should trigger exactly one fallback runtime-preflight fetch", fallbackCalls);
assertCondition(fallbackCalls[0] === "/api/microservices/code-queue/proxy/api/runtime-preflight?remote=1&issue=20", "primary path should request remote runtime probes", fallbackCalls);
assertCondition(fallbackCalls[1] === "/api/microservices/code-queue/proxy/api/runtime-preflight?issue=20", "fallback path should omit remote=1 but keep issue query", fallbackCalls);
assertCondition(k3sFallbackRecord.ok === true, "transport-degraded fallback should preserve observed runtime preflight result", k3sFallbackRecord);
assertCondition(k3sFallbackRecord.failureKind === null, "healthy fallback runtime should not be misclassified as infra-blocked", k3sFallbackRecord);
const k3sFallbackSummary = asRecord(k3sFallbackRecord.summary);
const k3sFallbackTransport = asRecord(k3sFallbackRecord.transportObservation);
const k3sFallbackRuntime = asRecord(k3sFallbackRecord.runtimeObservation);
assertCondition(k3sFallbackSummary.transportState === "transport-degraded", "summary should distinguish degraded transport from runtime observation", k3sFallbackSummary);
assertCondition(k3sFallbackSummary.runtimePreflightState === "runtime-preflight-observed", "summary should expose observed runtime preflight after fallback", k3sFallbackSummary);
assertCondition(k3sFallbackTransport.fallbackUsed === true && k3sFallbackTransport.state === "transport-degraded", "transport observation should mark fallback used", k3sFallbackTransport);
assertCondition(asRecord(k3sFallbackTransport.primary).stage === "http-tunnel-wait", "primary transport summary should retain bounded tunnel stage", k3sFallbackTransport.primary);
assertCondition(asRecord(k3sFallbackTransport.primary).serviceId === "k3sctl-adapter", "primary transport summary should retain service id", k3sFallbackTransport.primary);
assertCondition(k3sFallbackRuntime.source === "fallback-runtime-preflight" && k3sFallbackRuntime.observed === true, "runtime observation should identify fallback source", k3sFallbackRuntime);
assertCondition(k3sFallbackRecord.preflight === undefined, "transport fallback default output should omit detailed preflight", k3sFallbackRecord);
assertCondition(JSON.stringify(k3sFallbackRecord).length < 14000, "transport fallback default output should stay compact", { chars: JSON.stringify(k3sFallbackRecord).length });
const bothPathsFailed = asRecord(await codexPrPreflightQueryForTest(["--remote"], {
coreFetch: (path) => path.includes("remote=1")
? k3sTunnelTimeout
: {
ok: false,
status: 503,
body: {
ok: false,
error: "code-queue runtime unavailable",
stage: "runtime-preflight",
serviceId: "code-queue",
},
},
}));
assertCondition(bothPathsFailed.ok === false, "both unavailable paths should fail", bothPathsFailed);
assertCondition(bothPathsFailed.failureKind === "proxy-gap", "both unavailable paths should remain an infra/proxy observation gap", bothPathsFailed);
assertCondition(bothPathsFailed.degradedReason === "runtime-preflight-transport-unavailable", "both unavailable paths should expose stable degraded reason", bothPathsFailed);
assertCondition(bothPathsFailed.runnerDisposition === "infra-blocked", "both unavailable paths remain infra-blocked", bothPathsFailed);
assertCondition(bothPathsFailed.blockingDisposition === "control-plane-observation-gap", "both unavailable paths should not pretend runner capability was observed", bothPathsFailed);
const bothSummary = asRecord(bothPathsFailed.summary);
const bothTransport = asRecord(bothPathsFailed.transportObservation);
const bothRuntime = asRecord(bothPathsFailed.runtimeObservation);
const bothScheduler = asRecord(bothPathsFailed.schedulerPreflight);
assertCondition(bothSummary.transportState === "transport-blocked", "both paths failed summary should report transport-blocked", bothSummary);
assertCondition(bothSummary.runtimePreflightState === "runtime-preflight-unobserved", "both paths failed summary should report runtime unobserved", bothSummary);
assertCondition(bothSummary.schedulerPreflightAuthReady === null, "transport-blocked should not infer scheduler auth missing", bothSummary);
assertCondition(bothTransport.fallbackUsed === false && bothRuntime.observed === false, "both paths failed should expose fallback attempted but runtime unobserved", { bothTransport, bothRuntime });
assertCondition(bothScheduler.authReady === null && Array.isArray(bothScheduler.missing) && bothScheduler.missing.length === 0, "transport-blocked scheduler preflight should be unknown, not auth-missing", bothScheduler);
const skillsFallbackRecord = asRecord(await codexPrPreflightQueryForTest(["--remote"], {
coreFetch: (path) => path.includes("remote=1")
? k3sTunnelTimeout
: {
ok: true,
status: 200,
body: {
runtimePreflight: rawRuntimePreflightFixture({
ok: false,
skills: {
ok: false,
runnerUsable: false,
contractOk: false,
blocker: "skills-target-missing",
degradedReason: "skills-target-missing",
resolution: { hostRolloutRequired: true },
valuesPrinted: false,
},
skillsSync: {
ok: false,
degraded: true,
blocker: "skills-target-missing",
dryRun: true,
mutation: false,
valuesPrinted: false,
},
pullRequestDelivery: {
...asRecord(rawRuntimePreflightFixture().pullRequestDelivery),
ok: true,
credentials: {
ghTokenPresent: true,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
},
}),
},
},
}));
assertCondition(skillsFallbackRecord.ok === false, "skills blocker observed through fallback should fail preflight", skillsFallbackRecord);
assertCondition(skillsFallbackRecord.failureKind === "runner-skills-blocker", "skills-target-missing should classify as runner capability degraded, not proxy failure", skillsFallbackRecord);
assertCondition(skillsFallbackRecord.degradedReason === "skills-target-missing", "skills degraded reason should preserve skills-target-missing", skillsFallbackRecord);
assertCondition(skillsFallbackRecord.blockingDisposition === "runner-capability-degraded", "skills blocker should expose runner capability degraded disposition", skillsFallbackRecord);
assertCondition(asRecord(skillsFallbackRecord.summary).transportState === "transport-degraded", "skills fallback should still expose degraded transport", skillsFallbackRecord.summary);
assertCondition(asRecord(skillsFallbackRecord.summary).status === "runner-capability-degraded", "skills fallback summary should separate runner capability degradation", skillsFallbackRecord.summary);
assertCondition(asRecord(skillsFallbackRecord.transportObservation).fallbackUsed === true, "skills fallback should mark transport fallback used", skillsFallbackRecord.transportObservation);
assertCondition(asRecord(skillsFallbackRecord.runtimeObservation).observed === true, "skills fallback should report runtime observed", skillsFallbackRecord.runtimeObservation);
assertCondition(asRecord(skillsFallbackRecord.skillsContract).degradedReason === "skills-target-missing", "skills contract should expose missing target", skillsFallbackRecord.skillsContract);
let observedDryRunPath = "";
const dryRunContract = await codexPrPreflightQueryForTest([
"--remote",
"--push-dry-run",
"--push-dry-run-ref",
"refs/heads/probe/code-queue-pr-capability",
"--pr-create-dry-run",
"--pr-create-dry-run-head",
"code-queue/issue-35-pr-dry-run-probe",
"--issue",
"20",
], {
config: null,
coreFetch: (path) => {
observedDryRunPath = path;
return {
ok: true,
status: 200,
body: {
runtimePreflight: {
ok: false,
checkedAt: "2026-05-20T00:00:00.000Z",
cwd: "/workspace/unidesk",
pid: 123,
pullRequestDelivery: {
ok: false,
checkedAt: "2026-05-20T00:00:00.000Z",
tools: {
git: { ok: true, path: "/usr/bin/git", version: "git version 2.43.0" },
gh: { ok: false, path: null, version: null },
hub: { ok: false, path: null, version: null },
jq: { ok: true, path: "/usr/bin/jq", version: "jq-1.7" },
ssh: { ok: true, path: "/usr/bin/ssh", version: "OpenSSH_9.6" },
curl: { ok: true, path: "/usr/bin/curl", version: "curl 8.5.0" },
},
unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true },
credentials: {
ghTokenPresent: false,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
git: {
insideWorktree: true,
branch: "code-queue/issue-35-pr-dry-run-probe",
head: "abc1234",
originMaster: "def5678",
remoteOrigin: "git@github.com:pikasTech/unidesk.git",
home: "/root",
homeWritable: true,
knownHostsPresent: true,
privateKeyPresent: false,
},
githubContext: {
host: "github.com",
apiBaseUrl: "https://api.github.com",
repo: "pikasTech/unidesk",
issueProbeNumber: 20,
},
egress: {
proxy: {
selectedProxyHost: "d601-provider-egress-proxy.unidesk.svc.cluster.local",
selectedProxyPort: "18789",
selectedProxyHostResolvable: true,
},
githubDefault: { command: "curl", args: ["-IsS", "https://github.com"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
apiDefault: { command: "curl", args: ["-IsS", "https://api.github.com"], ok: true, exitCode: 0, signal: null, error: null, stdout: "", stderr: "" },
issueApi: { command: "sh", args: ["-lc", "curl issue"], ok: false, exitCode: 1, signal: null, error: null, stdout: "http_status=404", stderr: "" },
},
remote: {
gitLsRemote: { command: "git", args: ["ls-remote", "--heads", "origin", "master"], ok: true, exitCode: 0, signal: null, error: null, stdout: "abc1234\trefs/heads/master\n", stderr: "" },
gitHttpsLsRemote: { command: "git", args: ["ls-remote", "--heads", "https://github.com/pikasTech/unidesk.git", "master"], ok: false, exitCode: 128, signal: null, error: null, stdout: "", stderr: "Authentication failed" },
githubSshAuthenticated: true,
ghAuthStatus: null,
ghRepoView: null,
ghIssueView: null,
ghPrReadOnly: null,
},
pushDryRun: { command: "git", args: ["push", "--dry-run", "origin", "HEAD:refs/heads/probe/code-queue-pr-capability"], ok: false, exitCode: 128, signal: null, error: null, stdout: "", stderr: "Permission denied" },
prCreateDryRun: { command: "sh", args: ["-lc", "bun scripts/cli.ts gh pr create --dry-run"], ok: false, exitCode: 1, signal: null, error: null, stdout: "", stderr: "GH_TOKEN/GITHUB_TOKEN missing" },
limitations: [
"GH_TOKEN/GITHUB_TOKEN is not present; gh cannot create PRs unless another gh credential store is mounted",
"git push --dry-run failed for probe branch",
"PR create dry-run body/command guard failed",
],
risks: [
"system gh binary is missing; UniDesk REST gh CLI remains the supported PR create/comment path when scripts/cli.ts and GH_TOKEN/GITHUB_TOKEN are available",
],
},
ports: {},
},
},
};
},
});
assertCondition(observedDryRunPath === "/api/microservices/code-queue/proxy/api/runtime-preflight?remote=1&pushDryRun=1&pushDryRunRef=refs%2Fheads%2Fprobe%2Fcode-queue-pr-capability&prCreateDryRun=1&prCreateDryRunHead=code-queue%2Fissue-35-pr-dry-run-probe&issue=20", "combined dry-run query should pass all requested guards", { observedDryRunPath });
const dryRunRecord = asRecord(dryRunContract);
assertCondition(dryRunRecord.failureKind === "auth-missing", "missing runner token should remain auth-missing even when system gh is absent", dryRunRecord);
assertCondition(dryRunRecord.preflight === undefined, "combined dry-run default output should omit detailed preflight", dryRunRecord);
const dryRunSchedulerPreflight = asRecord(dryRunRecord.schedulerPreflight);
const dryRunAuthBroker = asRecord(dryRunSchedulerPreflight.authBroker);
const dryRunScopeBoundary = asRecord(dryRunRecord.scopeBoundary);
const dryRunActiveRunner = asRecord(dryRunRecord.activeRunnerPrCapability);
assertCondition(dryRunAuthBroker.source === "broker/auth-broker-needed", "missing runner token should expose broker/auth-broker-needed", dryRunAuthBroker);
assertCondition(dryRunSchedulerPreflight.degradedReason === "auth-broker-needed", "auth broker degraded reason should be explicit", dryRunSchedulerPreflight);
assertCondition(dryRunScopeBoundary.scopesAreIndependent === true, "local compact preflight should expose independent auth scopes", dryRunScopeBoundary);
assertCondition(dryRunActiveRunner.scope === "current-cli-process", "compact default should expose current CLI process capability", dryRunActiveRunner);
const dryRunPrContract = asRecord(dryRunRecord.prCapability);
assertCondition(dryRunPrContract.systemGhBinaryRequiredForWrites === false, "system gh absence must not be required for UniDesk REST gh writes", dryRunPrContract);
assertCondition(dryRunPrContract.unideskGhCliOk === true, "UniDesk REST gh CLI should not be marked unavailable because system gh is missing", dryRunPrContract);
assertCondition(asRecord(dryRunPrContract.pushDryRun).requested === true, "push dry-run should be requested", dryRunPrContract);
assertCondition(asRecord(dryRunPrContract.pushDryRun).writesRemote === false, "push dry-run must be marked non-writing", dryRunPrContract);
assertCondition(asRecord(dryRunPrContract.prCreateDryRun).requested === true, "PR create dry-run should be requested", dryRunPrContract);
assertCondition(asRecord(dryRunPrContract.prCreateDryRun).writesRemote === false, "PR create dry-run must be marked non-writing", dryRunPrContract);
assertCondition(dryRunPrContract.sourceBranch === "code-queue/issue-35-pr-dry-run-probe", "PR dry-run head should come from the option", dryRunPrContract);
const brokerIssuedContract = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: {
runtimePreflight: rawRuntimePreflightFixture({
pullRequestDelivery: {
...asRecord(rawRuntimePreflightFixture().pullRequestDelivery),
ok: true,
authBroker: {
ok: true,
configured: true,
source: "auth-broker",
endpointEnvKey: "UNIDESK_AUTH_BROKER_URL",
runnerEnvTokenRequired: false,
credentialSource: "broker-held-github-credential",
failureKind: null,
degradedReason: null,
capability: {
source: "broker-issued-token",
githubRestAuth: true,
operations: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"],
systemGhBinaryRequiredForWrites: false,
preflightWritesRemote: false,
preflightCreatesPr: false,
preflightMergesPr: false,
realPrCreateRequiresCommanderAuthorization: true,
valuesPrinted: false,
},
nextAction: "use-auth-broker",
next: ["keep PR preflight read-only; create a real PR only after commander authorization"],
valuesRead: false,
valuesPrinted: false,
},
},
}),
},
}),
});
const brokerIssuedRecord = asRecord(brokerIssuedContract);
assertCondition(brokerIssuedRecord.ok === true, "broker-issued token branch should be ready", brokerIssuedRecord);
assertCondition(brokerIssuedRecord.preflight === undefined, "broker-issued default output should omit detailed preflight", brokerIssuedRecord);
const brokerIssuedScheduler = asRecord(brokerIssuedRecord.schedulerPreflight);
const brokerIssuedAuthBroker = asRecord(brokerIssuedScheduler.authBroker);
const brokerIssuedPrContract = asRecord(brokerIssuedRecord.prCapability);
assertCondition(brokerIssuedScheduler.authSource === "auth-broker", "broker-issued branch should use auth-broker token coverage", brokerIssuedScheduler);
assertCondition(brokerIssuedScheduler.credentialSource === "broker-issued-token", "broker-issued branch should expose broker-issued-token capability", brokerIssuedScheduler);
assertCondition(brokerIssuedAuthBroker.source === "auth-broker", "broker-issued branch should expose authBroker.source", brokerIssuedAuthBroker);
assertCondition(brokerIssuedAuthBroker.nextAction === "use-auth-broker", "broker-issued branch should expose nextAction", brokerIssuedAuthBroker);
assertCondition(brokerIssuedAuthBroker.capabilitySource === "broker-issued-token", "broker-issued branch should expose broker-issued capability", brokerIssuedAuthBroker);
assertCondition(brokerIssuedPrContract.systemGhBinaryRequiredForWrites === false, "broker-issued branch should not require system gh binary", brokerIssuedPrContract);
assertCondition(brokerIssuedPrContract.realPrCreateRequiresCommanderAuthorization === true, "real PR creation should still require commander authorization", brokerIssuedPrContract);
const envTokenContract = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: {
runtimePreflight: rawRuntimePreflightFixture({
pullRequestDelivery: {
...asRecord(rawRuntimePreflightFixture().pullRequestDelivery),
ok: true,
credentials: {
ghTokenPresent: true,
githubTokenPresent: false,
ghHostsConfigPresent: false,
gitCredentialsPresent: false,
},
authBroker: {
ok: false,
configured: false,
source: "broker/auth-broker-needed",
endpointEnvKey: null,
runnerEnvTokenRequired: false,
credentialSource: null,
failureKind: "auth-missing",
degradedReason: "auth-broker-needed",
capability: {
source: "missing-token",
githubRestAuth: false,
operations: ["github.auth.status", "github.issue.read", "github.pr.read", "github.pr.create"],
systemGhBinaryRequiredForWrites: false,
preflightWritesRemote: false,
preflightCreatesPr: false,
preflightMergesPr: false,
realPrCreateRequiresCommanderAuthorization: true,
valuesPrinted: false,
},
nextAction: "configure-auth-broker-or-env-token",
next: ["configure UNIDESK_AUTH_BROKER_URL or AUTH_BROKER_URL for broker-backed runner auth"],
valuesRead: false,
valuesPrinted: false,
},
},
}),
},
}),
});
const envTokenRecord = asRecord(envTokenContract);
assertCondition(envTokenRecord.ok === true, "env token branch should be ready", envTokenRecord);
assertCondition(envTokenRecord.preflight === undefined, "env-token default output should omit detailed preflight", envTokenRecord);
const envTokenScheduler = asRecord(envTokenRecord.schedulerPreflight);
const envTokenAuthBroker = asRecord(envTokenScheduler.authBroker);
assertCondition(envTokenScheduler.authSource === "GH_TOKEN", "env token branch should expose GH_TOKEN source", envTokenScheduler);
assertCondition(envTokenScheduler.credentialSource === "env-token", "env token branch should expose env-token capability", envTokenScheduler);
assertCondition(envTokenAuthBroker.source === "GH_TOKEN", "env token branch should not pretend broker is configured", envTokenAuthBroker);
assertCondition(envTokenAuthBroker.nextAction === "use-env-token-until-auth-broker-live", "env token branch should still point at broker migration", envTokenAuthBroker);
const missingTokenContract = await codexPrPreflightQueryForTest(["--remote"], {
config: null,
coreFetch: () => ({
ok: true,
status: 200,
body: { runtimePreflight: rawRuntimePreflightFixture() },
}),
});
const missingTokenRecord = asRecord(missingTokenContract);
assertCondition(missingTokenRecord.ok === false, "missing-token branch should fail", missingTokenRecord);
assertCondition(missingTokenRecord.failureKind === "auth-missing", "missing-token branch should classify auth-missing", missingTokenRecord);
assertCondition(missingTokenRecord.degradedReason === "auth-broker-needed", "missing-token branch should expose broker-needed degraded reason", missingTokenRecord);
const missingTokenTopSummary = asRecord(missingTokenRecord.authScopeSummary);
const missingTokenTopScopeBoundary = asRecord(missingTokenRecord.scopeBoundary);
const missingTokenTopActions = Array.isArray(missingTokenRecord.recommendedActions) ? missingTokenRecord.recommendedActions : [];
assertCondition(missingTokenRecord.preflight === undefined, "missing-token default output should omit detailed preflight", missingTokenRecord);
const missingTokenScheduler = asRecord(missingTokenRecord.schedulerPreflight);
const missingTokenAuthBroker = asRecord(missingTokenScheduler.authBroker);
const missingTokenScopeBoundary = asRecord(missingTokenRecord.scopeBoundary);
const missingTokenActiveRunner = asRecord(missingTokenRecord.activeRunnerPrCapability);
const missingTokenActions = Array.isArray(missingTokenRecord.recommendedActions) ? missingTokenRecord.recommendedActions : [];
const missingTokenPrCapability = asRecord(missingTokenRecord.prCapability);
assertCondition(missingTokenTopSummary.schedulerAuthMissingIsScoped === true, "missing-token top-level summary should expose scoped scheduler auth missing", missingTokenTopSummary);
assertCondition(missingTokenTopScopeBoundary.schedulerAuthMissingDoesNotMeanActiveRunnerCannotCreatePr === true, "missing-token top-level boundary should be prominent", missingTokenTopScopeBoundary);
assertCondition(Array.isArray(missingTokenRecord.recommendedActions) && missingTokenTopActions.length === 3, "missing-token top-level recommended actions should stay bounded", missingTokenRecord.recommendedActions);
assertCondition(missingTokenAuthBroker.source === "broker/auth-broker-needed", "missing-token branch should expose broker/auth-broker-needed", missingTokenAuthBroker);
assertCondition(missingTokenAuthBroker.nextAction === "configure-auth-broker-or-env-token", "missing-token branch should expose nextAction", missingTokenAuthBroker);
assertCondition(missingTokenAuthBroker.capabilitySource === "missing-token", "missing-token branch should expose missing-token capability", missingTokenAuthBroker);
assertCondition(missingTokenPrCapability.systemGhBinaryRequiredForWrites === false, "missing-token branch should still not require system gh binary for UniDesk gh CLI", missingTokenPrCapability);
assertCondition(missingTokenTopSummary.schedulerAuthMissingIsScoped === true, "missing-token compact summary should expose scoped scheduler auth missing", missingTokenTopSummary);
assertCondition(String(missingTokenScopeBoundary.currentRunnerCheck ?? "").includes("gh auth status"), "missing-token branch should point to active runner auth check", missingTokenScopeBoundary);
assertCondition(String(missingTokenScopeBoundary.currentRunnerCheck ?? "").includes("gh pr create --dry-run"), "missing-token branch should point to active runner PR create dry-run", missingTokenScopeBoundary);
assertCondition(missingTokenActiveRunner.independentOfSchedulerPreflight === true, "missing-token branch should not overstate active runner PR capability", missingTokenActiveRunner);
assertCondition(Array.isArray(missingTokenRecord.recommendedActions) && missingTokenActions.length === 3, "missing-token compact recommended actions should stay bounded", missingTokenRecord.recommendedActions);
assertCondition(missingTokenActions.some((action) => String(asRecord(action).command ?? "").includes("gh auth status")), "missing-token branch should recommend gh auth status", missingTokenActions);
assertCondition(missingTokenActions.some((action) => String(asRecord(action).command ?? "").includes("gh pr create") && asRecord(action).writesRemote === false), "missing-token branch should recommend PR create dry-run without writes", missingTokenActions);
process.stdout.write(`${JSON.stringify({
ok: true,
checks: [
"runner-like local target-stack absence does not block remote fallback",
"remote control plane fallback preserves ready preflight",
"missing remote control plane returns control-plane-observation-gap",
"local backend-core absence returns runner-local-observation-gap",
"auth missing returns auth-missing with broker/auth-broker-needed",
"proxy failures return proxy-gap",
"GitHub DNS/API failures return github-transient with retry/backoff guidance",
"k3sctl HTTP tunnel 504 falls back to lightweight runtime-preflight observation",
"double runtime-preflight transport failure remains infra-blocked without inferring auth gaps",
"skills-target-missing fallback is runner-capability-degraded, not proxy unavailable",
"git remote failures return git-remote-gap",
"combined push/PR create dry-run contract stays read-only and separates system gh from UniDesk gh CLI",
"broker-issued token, env-token, and missing-token branches expose authBroker source/capability/nextAction",
],
observedLocalPath,
observedDryRunPath,
}, null, 2)}\n`);
}
if (import.meta.main) {
await main();
}