import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { collectSkillAvailability, collectSkillSyncPreflight } from "../src/components/microservices/code-queue/src/skill-availability"; import { codexPrPreflightQueryForTest } from "./src/code-queue"; import { summarizeMicroserviceObservation } from "./src/microservices"; type JsonRecord = Record; function assertCondition(condition: unknown, message: string, detail: unknown = {}): void { if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`); } function asRecord(value: unknown, label: string): JsonRecord { assertCondition(typeof value === "object" && value !== null && !Array.isArray(value), `${label} must be an object`, value); return value as JsonRecord; } function countOccurrences(haystack: string, needle: string): number { return haystack.split(needle).length - 1; } function createSkillSet(root: string, skills: string[]): void { for (const skill of skills) { const dir = join(root, skill); mkdirSync(dir, { recursive: true }); writeFileSync(join(dir, "SKILL.md"), `---\nname: ${skill}\n---\n# ${skill}\n`); } } const productionManifest = readFileSync("src/components/microservices/k3sctl-adapter/k3s/code-queue.k8s.yaml", "utf8"); const devManifest = readFileSync("src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml", "utf8"); const runtimePreflight = readFileSync("src/components/microservices/code-queue/src/runtime-preflight.ts", "utf8"); const indexSource = readFileSync("src/components/microservices/code-queue/src/index.ts", "utf8"); const skillModule = readFileSync("src/components/microservices/code-queue/src/skill-availability.ts", "utf8"); const codeQueueCli = readFileSync("scripts/src/code-queue.ts", "utf8"); const microserviceCli = readFileSync("scripts/src/microservices.ts", "utf8"); const helpSource = readFileSync("scripts/src/help.ts", "utf8"); const promptSource = readFileSync("src/components/microservices/code-queue/src/prompts.ts", "utf8"); const docsReference = readFileSync("docs/reference/code-queue-supervision.md", "utf8"); const forbiddenPathLiteral = [".ag", "nets/skills"].join(""); const forbiddenTargetPath = [`/root/${[".ag", "nets"].join("")}`, "skills"].join("/"); const forbiddenSourcePath = [`/home/ubuntu/${[".ag", "nets"].join("")}`, "skills"].join("/"); assertCondition(!productionManifest.includes(forbiddenPathLiteral), "production manifest must not propagate misspelled skills path"); assertCondition(!devManifest.includes(forbiddenPathLiteral), "dev manifest must not propagate misspelled skills path"); assertCondition(!promptSource.includes(forbiddenPathLiteral), "runner prompt must not mention misspelled skills path"); assertCondition(!skillModule.includes(forbiddenPathLiteral), "skill availability implementation must not propagate misspelled skills path literal"); assertCondition(!docsReference.includes(forbiddenPathLiteral), "reference docs must not propagate misspelled skills path literal"); assertCondition(countOccurrences(productionManifest, "name: UNIDESK_SKILLS_PATH") === 3, "production read/write/scheduler must set UNIDESK_SKILLS_PATH", { count: countOccurrences(productionManifest, "name: UNIDESK_SKILLS_PATH"), }); assertCondition(countOccurrences(productionManifest, "mountPath: /root/.agents/skills") === 3, "production read/write/scheduler must mount skills target", { count: countOccurrences(productionManifest, "mountPath: /root/.agents/skills"), }); assertCondition(countOccurrences(productionManifest, "path: /home/ubuntu/.agents/skills") === 3, "production read/write/scheduler must use hostPath source of truth", { count: countOccurrences(productionManifest, "path: /home/ubuntu/.agents/skills"), }); assertCondition(countOccurrences(productionManifest, "name: skills-dir") >= 6, "production manifest must define skills-dir mounts and volumes", { count: countOccurrences(productionManifest, "name: skills-dir"), }); assertCondition(devManifest.includes("path: /home/ubuntu/.agents/skills"), "dev manifest should keep the same hostPath source of truth"); const available = collectSkillAvailability({ source: "/home/ubuntu/.agents/skills", target: "/home/ubuntu/.agents/skills", requiredSkills: ["docs-spec", "cli-spec", "frontend-design", "playwright-cli"], }); assertCondition(available.source === "/home/ubuntu/.agents/skills", "skill report must expose source"); assertCondition(available.target === "/home/ubuntu/.agents/skills", "skill report must expose target"); assertCondition(typeof available.resolvedPath === "string" && available.resolvedPath.length > 0, "skill report must expose resolved path", available); assertCondition(asRecord(available.resolution, "available.resolution").passesToRunnerEnv === true, "skill report must expose runner env path resolution", available.resolution); assertCondition(Array.isArray(available.requiredSkills) && available.requiredSkills.includes("docs-spec"), "skill report must expose requiredSkills"); assertCondition(Array.isArray(available.missingSkills), "skill report must expose missingSkills"); assertCondition(available.valuesPrinted === false, "skill report must declare valuesPrinted=false"); assertCondition(asRecord(available.pathSpelling, "pathSpelling").forbiddenPathMustNotBeUsed === true, "skill report must flag misspelled path risk without spreading the literal path"); assertCondition(!JSON.stringify(available).includes(forbiddenPathLiteral), "skill report must not propagate misspelled path literal"); assertCondition(!JSON.stringify(available).includes("GH_TOKEN"), "skill report must not include secret environment names unrelated to skills"); const tmpRoot = mkdtempSync(join(tmpdir(), "unidesk-codequeue-skills-")); const fixtureSource = join(tmpRoot, "source"); const fixtureMissingTarget = join(tmpRoot, "target-missing"); const fixtureSymlinkTarget = join(tmpRoot, "target-symlink"); const fixtureMissingSource = join(tmpRoot, "source-missing"); mkdirSync(fixtureSource, { recursive: true }); createSkillSet(fixtureSource, ["docs-spec", "cli-spec"]); symlinkSync(fixtureSource, fixtureSymlinkTarget, "dir"); const sourceFallback = collectSkillAvailability({ source: fixtureSource, target: fixtureMissingTarget, requiredSkills: ["docs-spec", "cli-spec"], }); assertCondition(sourceFallback.ok === true, "source exists target missing should keep runner usable", sourceFallback); assertCondition(sourceFallback.runnerUsable === true, "source fallback should mark runner usable", sourceFallback); assertCondition(sourceFallback.contractOk === false, "source fallback should still mark target projection contract degraded", sourceFallback); assertCondition(sourceFallback.degraded === true, "source fallback should remain degraded for host rollout", sourceFallback); assertCondition(sourceFallback.blocker === "skills-target-missing", "source fallback should preserve target missing degraded reason", sourceFallback); assertCondition(sourceFallback.degradedReason === "skills-target-missing", "source fallback should expose bounded degraded reason", sourceFallback); assertCondition(sourceFallback.resolvedPath === fixtureSource, "source fallback should resolve to source path", sourceFallback); assertCondition(sourceFallback.resolvedPathSource === "source-fallback", "source fallback should expose resolved path source", sourceFallback); assertCondition(sourceFallback.skillCount === 2 && sourceFallback.sourceSkillCount === 2 && sourceFallback.targetSkillCount === 0, "source fallback should expose bounded counts", sourceFallback); assertCondition(asRecord(sourceFallback.resolution, "sourceFallback.resolution").runnerEnvValue === fixtureSource, "source fallback should pass resolved path to runner env", sourceFallback.resolution); assertCondition(asRecord(sourceFallback.resolution, "sourceFallback.resolution").hostRolloutRequired === true, "source fallback should require host rollout repair", sourceFallback.resolution); const symlinkOk = collectSkillAvailability({ source: fixtureSource, target: fixtureSymlinkTarget, requiredSkills: ["docs-spec", "cli-spec"], }); assertCondition(symlinkOk.ok === true && symlinkOk.contractOk === true, "target symlink to source should satisfy runner and contract", symlinkOk); assertCondition(symlinkOk.resolvedPath === fixtureSymlinkTarget, "target symlink should keep target as runner path", symlinkOk); assertCondition(symlinkOk.resolvedPathSource === "target-symlink", "target symlink should expose target-symlink source", symlinkOk); assertCondition(symlinkOk.targetSymlink === true, "target symlink should be reported", symlinkOk); assertCondition(asRecord(symlinkOk.resolution, "symlinkOk.resolution").hostRolloutRequired === false, "target symlink should not require rollout repair", symlinkOk.resolution); const missingBoth = collectSkillAvailability({ source: fixtureMissingSource, target: fixtureMissingTarget, requiredSkills: ["docs-spec", "cli-spec"], }); assertCondition(missingBoth.ok === false && missingBoth.runnerUsable === false, "missing source and target should fail runner availability", missingBoth); assertCondition(missingBoth.blocker === "skills-source-and-target-missing", "missing both should expose dedicated blocker", missingBoth); assertCondition(missingBoth.resolvedPathSource === "missing", "missing both should expose missing resolution", missingBoth); const redactionProbe = collectSkillAvailability({ source: fixtureSource, target: fixtureMissingTarget, requiredSkills: ["docs-spec", "cli-spec"], }); assertCondition(!JSON.stringify(redactionProbe).includes("ghp_"), "skill report must not include token-like values", redactionProbe); assertCondition(!JSON.stringify(redactionProbe).includes("github_pat_"), "skill report must not include GitHub PAT-like values", redactionProbe); rmSync(tmpRoot, { recursive: true, force: true }); const missing = collectSkillAvailability({ source: "/home/ubuntu/.agents/skills", target: "/path/that/does/not/exist/for-code-queue-skills-test", requiredSkills: ["docs-spec", "cli-spec"], }); assertCondition(missing.ok === true, "approved source should keep missing-target runner usable"); assertCondition(missing.runnerUsable === true, "missing target with approved source should expose runner usable"); assertCondition(missing.contractOk === false, "missing target with approved source should expose hostPath contract degraded"); assertCondition(missing.degraded === true, "missing target should be degraded"); assertCondition(missing.blocker === "skills-target-missing", "missing target should expose blocker", missing); assertCondition(missing.targetMissingSkills.includes("docs-spec") && missing.targetMissingSkills.includes("cli-spec"), "missing target should list target missing skills", missing); assertCondition(missing.resolvedPath === "/home/ubuntu/.agents/skills", "missing target should resolve to approved source", missing); assertCondition(missing.resolvedPathSource === "source-fallback", "missing target should expose source fallback", missing); assertCondition(missing.valuesPrinted === false, "missing report must also declare valuesPrinted=false"); const typoTarget = collectSkillAvailability({ source: "/home/ubuntu/.agents/skills", target: forbiddenTargetPath, requiredSkills: ["docs-spec", "cli-spec"], }); assertCondition(typoTarget.ok === false, "misspelled target should fail", typoTarget); assertCondition(typoTarget.degraded === true, "misspelled target should be degraded", typoTarget); assertCondition(typoTarget.blocker === "forbidden-skills-path-configured", "misspelled target should expose dedicated blocker", typoTarget); assertCondition(asRecord(typoTarget.pathSpelling, "typoTarget.pathSpelling").forbiddenPathConfigured === true, "misspelled target should mark configured typo", typoTarget.pathSpelling); assertCondition(JSON.stringify(asRecord(typoTarget.pathSpelling, "typoTarget.pathSpelling").forbiddenPathRoles).includes("target"), "misspelled target should classify target role", typoTarget.pathSpelling); assertCondition(typoTarget.valuesPrinted === false, "misspelled target report must declare valuesPrinted=false"); const syncDryRun = collectSkillSyncPreflight({ source: "/home/ubuntu/.agents/skills", target: "/path/that/does/not/exist/for-code-queue-skills-test", requiredSkills: ["docs-spec", "cli-spec"], }); assertCondition(syncDryRun.dryRun === true && syncDryRun.mutation === false, "skills sync contract must be dry-run and non-mutating", syncDryRun); assertCondition(syncDryRun.syncMode === "hostPath-read-only-projection", "skills sync must describe the hostPath projection lifecycle", syncDryRun); assertCondition(syncDryRun.source.path === "/home/ubuntu/.agents/skills", "skills sync must expose source", syncDryRun.source); assertCondition(syncDryRun.target.path === "/path/that/does/not/exist/for-code-queue-skills-test", "skills sync must expose target", syncDryRun.target); assertCondition(syncDryRun.expected.source === "/home/ubuntu/.agents/skills", "skills sync must expose stable expected source", syncDryRun.expected); assertCondition(syncDryRun.expected.target === "/root/.agents/skills", "skills sync must expose stable expected target", syncDryRun.expected); assertCondition(syncDryRun.expected.env === "UNIDESK_SKILLS_PATH" && syncDryRun.expected.envValue === "/root/.agents/skills", "skills sync must expose env contract", syncDryRun.expected); assertCondition(syncDryRun.counts.requiredSkills === 2, "skills sync must expose required skill count", syncDryRun.counts); assertCondition(syncDryRun.counts.targetSkills === 0 && syncDryRun.counts.missingTargetSkills === 2, "skills sync must expose target counts and missing count", syncDryRun.counts); assertCondition(syncDryRun.missing.targetSkills.includes("docs-spec") && syncDryRun.missing.targetSkills.includes("cli-spec"), "skills sync must expose missing target skills", syncDryRun.missing); assertCondition(syncDryRun.blocker === "unapproved-target", "arbitrary target paths must be blocked before silent copying", syncDryRun); assertCondition(syncDryRun.plannedActions.copy === false && syncDryRun.plannedActions.copyFromArbitraryPath === false, "skills sync dry-run must not plan arbitrary copy", syncDryRun.plannedActions); assertCondition(syncDryRun.plannedActions.restartRequired === false && syncDryRun.plannedActions.readsSecrets === false, "skills sync dry-run must not require restart or read secrets", syncDryRun.plannedActions); assertCondition(Array.isArray(syncDryRun.instructions) && syncDryRun.instructions.some((item) => item.includes("read-only hostPath projection")), "skills sync must include lifecycle instructions", syncDryRun.instructions); assertCondition(syncDryRun.valuesPrinted === false, "skills sync must declare valuesPrinted=false", syncDryRun); assertCondition(!JSON.stringify(syncDryRun).includes(forbiddenPathLiteral), "skills sync report must not propagate misspelled path literal"); const missingTargetSync = collectSkillSyncPreflight({ target: "/path/that/does/not/exist/for-code-queue-skills-test" }); assertCondition(missingTargetSync.blocker === "unapproved-target", "non-default target must be rejected as unapproved", missingTargetSync); const typoTargetSync = collectSkillSyncPreflight({ target: forbiddenTargetPath }); assertCondition(typoTargetSync.blocker === "forbidden-skills-path-configured", "misspelled sync target must be rejected as a typo before generic target approval", typoTargetSync); assertCondition(asRecord(typoTargetSync.pathSpelling, "typoTargetSync.pathSpelling").forbiddenPathConfigured === true, "misspelled sync target should mark configured typo", typoTargetSync.pathSpelling); assertCondition(JSON.stringify(asRecord(typoTargetSync.pathSpelling, "typoTargetSync.pathSpelling").forbiddenPathRoles).includes("target"), "misspelled sync target should classify target role", typoTargetSync.pathSpelling); assertCondition(typoTargetSync.valuesPrinted === false, "misspelled sync target must declare valuesPrinted=false"); const typoSourceSync = collectSkillSyncPreflight({ source: forbiddenSourcePath }); assertCondition(typoSourceSync.blocker === "forbidden-skills-path-configured", "misspelled sync source must be rejected as a typo before generic source approval", typoSourceSync); assertCondition(asRecord(typoSourceSync.pathSpelling, "typoSourceSync.pathSpelling").forbiddenPathConfigured === true, "misspelled sync source should mark configured typo", typoSourceSync.pathSpelling); assertCondition(JSON.stringify(asRecord(typoSourceSync.pathSpelling, "typoSourceSync.pathSpelling").forbiddenPathRoles).includes("source"), "misspelled sync source should classify source role", typoSourceSync.pathSpelling); assertCondition(runtimePreflight.includes("skills: SkillAvailabilityReport"), "runtime preflight type must include skills report"); assertCondition(runtimePreflight.includes("skillsSync: SkillSyncPreflightReport"), "runtime preflight type must include skills sync report"); assertCondition(runtimePreflight.includes("collectSkillAvailability"), "runtime preflight must collect skills availability"); assertCondition(runtimePreflight.includes("collectSkillSyncPreflight"), "runtime preflight must collect skills sync preflight"); assertCondition(runtimePreflight.includes("skills.runnerUsable && ports.codex.ok"), "runtime preflight ok must depend on runner usable skills without blocking on host rollout contract drift"); assertCondition(indexSource.includes("skills.runnerUsable === true"), "dev-ready must gate on structured runner usable skills"); assertCondition(indexSource.includes("resolvedRunnerSkillsPath"), "runtime must pass resolved skills path to code agents"); assertCondition(indexSource.includes("collectSkillsSyncPreflight"), "runtime index must expose skills sync preflight"); assertCondition(indexSource.includes("/api/skills-sync"), "runtime must expose a dry-run skills sync endpoint"); assertCondition(indexSource.includes("pass dryRun=1"), "skills sync endpoint must reject non-dry-run calls"); assertCondition(codeQueueCli.includes("failureKind: \"dry-run-required\""), "codex skills-sync CLI must require --dry-run with structured output"); assertCondition(codeQueueCli.includes("codex skills-sync is dry-run only; pass --dry-run"), "codex skills-sync CLI must explain the dry-run requirement"); assertCondition(codeQueueCli.includes("Code Queue skills sync dry-run could not reach the control plane"), "codex skills-sync CLI must return structured control-plane failure output"); assertCondition(codeQueueCli.includes("compact-skills-sync-control-plane-failure"), "codex skills-sync CLI must keep control-plane failure output compact"); assertCondition(codeQueueCli.includes("compactSkillsSyncStatus"), "codex CLI must compact skills sync output"); assertCondition(codeQueueCli.includes("runner-skills-blocker"), "codex preflight must classify skill lifecycle blockers"); assertCondition(codeQueueCli.includes("forbiddenPathConfigured"), "codex CLI must preserve configured typo classification in compact output"); assertCondition(microserviceCli.includes("compactSkillSync"), "microservice health summary must compact skills sync output"); assertCondition(microserviceCli.includes("forbiddenPathConfigured"), "microservice health summary must preserve configured typo classification"); assertCondition(helpSource.includes("codex skills-sync --dry-run"), "CLI help must document the skills sync dry-run command"); assertCondition(docsReference.includes("codex skills-sync --dry-run"), "reference docs must document the skills sync dry-run command"); assertCondition(docsReference.includes("forbidden-skills-path-configured"), "reference docs must document configured typo blocker"); const skillsPreflightTransport = { config: null, coreFetch: () => ({ ok: true, status: 200, body: { runtimePreflight: { ok: false, checkedAt: "2026-05-23T00:00:00.000Z", cwd: "/workspace/unidesk", pid: 601, skills: missing, skillsSync: syncDryRun, ports: {}, pullRequestDelivery: { ok: true, checkedAt: "2026-05-23T00:00:00.000Z", tools: {}, unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true }, authBroker: { ok: true, configured: true, source: "auth-broker" }, credentials: { ghTokenPresent: false, githubTokenPresent: false, ghHostsConfigPresent: false, gitCredentialsPresent: false, }, git: { insideWorktree: true, branch: "code-queue/issue-68-runner-skills-lifecycle", 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: 68, }, egress: { proxy: {} }, remote: null, limitations: [], risks: [], }, }, }, }), }; const defaultPreflightSummary = asRecord(codexPrPreflightQueryForTest(["--remote"], skillsPreflightTransport), "default preflight summary"); assertCondition(defaultPreflightSummary.failureKind !== "runner-skills-blocker", "source fallback should not classify as runner skills blocker", defaultPreflightSummary); assertCondition(asRecord(defaultPreflightSummary.skillsContract, "defaultPreflightSummary.skillsContract").hostRolloutRequired === true, "default preflight should expose host rollout blocker separately", defaultPreflightSummary); assertCondition(defaultPreflightSummary.preflight === undefined, "default PR preflight should omit detailed preflight internals", defaultPreflightSummary); assertCondition(asRecord(defaultPreflightSummary.disclosure, "defaultPreflightSummary.disclosure").fullDetailOmitted === true, "default PR preflight should disclose full detail omission", defaultPreflightSummary.disclosure); assertCondition(String(asRecord(defaultPreflightSummary.disclosure, "defaultPreflightSummary.disclosure").expandWith ?? "").includes("--full"), "default PR preflight should point to --full expansion", defaultPreflightSummary.disclosure); const preflightSummary = asRecord(codexPrPreflightQueryForTest(["--remote", "--full"], skillsPreflightTransport), "full preflight summary"); const preflight = asRecord(preflightSummary.preflight, "preflight"); const preflightSkills = asRecord(preflight.skills, "preflight.skills"); const preflightSkillsSync = asRecord(preflight.skillsSync, "preflight.skillsSync"); assertCondition(preflightSummary.failureKind !== "runner-skills-blocker", "full preflight should keep source fallback out of runner blocker classification", preflightSummary); assertCondition(asRecord(preflightSummary.skillsContract, "preflightSummary.skillsContract").degradedReason === "skills-target-missing", "full preflight should expose target missing as contract degraded reason", preflightSummary); assertCondition(preflightSkills.target === "/path/that/does/not/exist/for-code-queue-skills-test", "full preflight must show skills target", preflightSkills); assertCondition(preflightSkills.resolvedPath === "/home/ubuntu/.agents/skills", "full preflight must show resolved source fallback path", preflightSkills); assertCondition(preflightSkills.resolvedPathSource === "source-fallback", "full preflight must show source fallback resolution", preflightSkills); assertCondition(preflightSkillsSync.dryRun === true && preflightSkillsSync.mutation === false, "full preflight must show non-mutating skills sync dry-run", preflightSkillsSync); assertCondition(asRecord(preflightSkillsSync.counts, "preflight.skillsSync.counts").missingTargetSkills === 2, "full preflight must show missing target count", preflightSkillsSync); assertCondition(asRecord(preflightSkillsSync.plannedActions, "preflight.skillsSync.plannedActions").copy === false, "full preflight must show no copy action", preflightSkillsSync); assertCondition(preflightSkillsSync.valuesPrinted === false, "full preflight skills sync must declare valuesPrinted=false", preflightSkillsSync); assertCondition(!JSON.stringify(preflightSkillsSync).includes(forbiddenPathLiteral), "full preflight must not propagate misspelled path literal"); const typoPreflightTransport = { config: null, coreFetch: () => ({ ok: true, status: 200, body: { runtimePreflight: { ok: false, checkedAt: "2026-05-23T00:00:00.000Z", cwd: "/workspace/unidesk", pid: 601, skills: typoTarget, skillsSync: typoTargetSync, ports: {}, pullRequestDelivery: { ok: true, checkedAt: "2026-05-23T00:00:00.000Z", tools: {}, unideskGhCli: { ok: true, path: "/workspace/unidesk/scripts/cli.ts", present: true }, authBroker: { ok: true, configured: true, source: "auth-broker" }, credentials: { ghTokenPresent: true, githubTokenPresent: false, ghHostsConfigPresent: false, gitCredentialsPresent: false, }, git: { insideWorktree: true, branch: "code-queue/issue-68-runner-skills-lifecycle", 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: 68, }, egress: { proxy: {} }, remote: null, limitations: [], risks: [], }, }, }, }), }; const typoPreflightSummary = asRecord(codexPrPreflightQueryForTest(["--remote"], typoPreflightTransport), "typo preflight summary"); assertCondition(typoPreflightSummary.failureKind === "runner-skills-blocker", "typo preflight should classify configured typo as runner skills blocker", typoPreflightSummary); assertCondition(typoPreflightSummary.degradedReason === "forbidden-skills-path-configured", "typo preflight degraded reason should preserve configured typo blocker", typoPreflightSummary); assertCondition(typoPreflightSummary.preflight === undefined, "typo default preflight should remain bounded", typoPreflightSummary); const typoFullPreflightSummary = asRecord(codexPrPreflightQueryForTest(["--remote", "--full"], typoPreflightTransport), "typo full preflight summary"); const typoFullPreflight = asRecord(typoFullPreflightSummary.preflight, "typoFullPreflightSummary.preflight"); const typoPreflightSkills = asRecord(typoFullPreflight.skills, "typoFullPreflight.skills"); const typoPreflightPathSpelling = asRecord(typoPreflightSkills.pathSpelling, "typoFullPreflight.skills.pathSpelling"); assertCondition(typoPreflightPathSpelling.forbiddenPathConfigured === true, "typo full preflight output must expose configured typo classification", typoPreflightPathSpelling); const healthSummary = asRecord(summarizeMicroserviceObservation("health", "code-queue", { ok: true, status: 200, body: { ok: false, service: "code-queue", skills: missing, skillsSync: syncDryRun, }, }, []), "microservice health summary"); const microservice = asRecord(healthSummary.microservice, "microservice"); const healthCompact = asRecord(microservice.summary, "microservice.summary"); const healthSkills = asRecord(healthCompact.skills, "microservice.summary.skills"); const healthSkillsSync = asRecord(healthCompact.skillsSync, "microservice.summary.skillsSync"); assertCondition(healthSkills.target === "/path/that/does/not/exist/for-code-queue-skills-test", "compact health must show skills target", healthSkills); assertCondition(healthSkillsSync.dryRun === true && healthSkillsSync.mutation === false, "compact health must show dry-run skills sync", healthSkillsSync); assertCondition(asRecord(healthSkillsSync.counts, "microservice.summary.skillsSync.counts").missingTargetSkills === 2, "compact health must show missing target count", healthSkillsSync); assertCondition(asRecord(healthSkillsSync.plannedActions, "microservice.summary.skillsSync.plannedActions").copyFromArbitraryPath === false, "compact health must show arbitrary copy is blocked", healthSkillsSync); assertCondition(!JSON.stringify(healthSkillsSync).includes(forbiddenPathLiteral), "compact health must not propagate misspelled path literal"); const typoHealthSummary = asRecord(summarizeMicroserviceObservation("health", "code-queue", { ok: true, status: 200, body: { ok: false, service: "code-queue", skills: typoTarget, skillsSync: typoTargetSync, }, }, []), "microservice typo health summary"); const typoHealthSkills = asRecord(asRecord(asRecord(typoHealthSummary.microservice, "typoHealthSummary.microservice").summary, "typoHealthSummary.microservice.summary").skills, "typoHealthSummary.skills"); const typoHealthPathSpelling = asRecord(typoHealthSkills.pathSpelling, "typoHealthSummary.skills.pathSpelling"); assertCondition(typoHealthSkills.blocker === "forbidden-skills-path-configured", "compact health must preserve configured typo blocker", typoHealthSkills); assertCondition(typoHealthPathSpelling.forbiddenPathConfigured === true, "compact health must expose configured typo classification", typoHealthPathSpelling); process.stdout.write(`${JSON.stringify({ ok: true, checks: [ "production Code Queue mounts /home/ubuntu/.agents/skills read-only at /root/.agents/skills", "skill availability report exposes source, target, requiredSkills, missingSkills, degraded/blocker and valuesPrinted=false", "skills sync dry-run reports source, target, counts, missing skills, permission failures, instructions and no-copy actions", "runtime-preflight, dev-ready, health and PR preflight use the same structured skill and sync reports", "default health/preflight summaries expose bounded skills lifecycle evidence and --full expansion", "misspelled skills paths are rejected with forbidden-skills-path-configured before generic missing/unapproved path blockers", ], observedRunner: { source: available.source, target: available.target, ok: available.ok, missingSkills: available.missingSkills, syncDryRunOk: syncDryRun.ok, syncDryRunBlocker: syncDryRun.blocker, valuesPrinted: available.valuesPrinted, }, }, null, 2)}\n`);