{"version":3,"file":"verification-decision.d.ts","sourceRoot":"","sources":["../../src/evolve/verification-decision.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAuC,MAAM,aAAa,CAAC;AAE1G,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAA+B,KAAK,sBAAsB,EAA6B,MAAM,cAAc,CAAC;AAKnH;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,CAAC,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,0BAA0B,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1G;AAED,wBAAsB,uBAAuB,CAC5C,KAAK,EAAE,QAAQ,EACf,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAI1C;AAED,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F;AAoBD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACtD,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAiClC;AAED,mFAAmF;AACnF,wBAAsB,yBAAyB,CAAC,OAAO,EAAE;IACxD,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhB","sourcesContent":["import { readFile, rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { EvoPaths } from \"../paths.ts\";\nimport { loadProposal } from \"../proposal.ts\";\nimport type { EvoService } from \"../service.ts\";\nimport { atomicWriteJson, readJsonIfExists } from \"../storage.ts\";\nimport type { EvoCheckProfile, EvoControlConfig, EvolutionResearchPlan, EvolutionRun } from \"../types.ts\";\nimport { readProfileReceipts } from \"./check-profiles.ts\";\nimport type { EvolutionEvaluationVerdict } from \"./evaluator.ts\";\nimport { applyEvolutionReleasePolicy, type EvolutionReleaseResult, RELEASE_ACTION_RUN_STATUS } from \"./release.ts\";\nimport { evolutionRunDirectory, readEvolutionRun, updateEvolutionRun } from \"./run.ts\";\n\nconst PENDING_VERIFICATION_FILE = \"pending-verification.json\";\n\n/**\n * A researcher-recommended verification the harness deferred so the user can\n * decide execute, skip, or reject. The stored verdict is the evaluation result\n * computed without the recommended evidence; skipping releases against it.\n */\nexport interface PendingVerification {\n\tschemaVersion: 1;\n\trunId: string;\n\tproposalId: string;\n\tprofiles: EvoCheckProfile[];\n\tdatasets: string[];\n\tminimumSamples: number;\n\treason: string;\n\tverdict: EvolutionEvaluationVerdict;\n\tevaluatedAt: string;\n}\n\nfunction pendingVerificationPath(paths: EvoPaths, runId: string): string {\n\treturn join(evolutionRunDirectory(paths, runId), PENDING_VERIFICATION_FILE);\n}\n\nexport async function writePendingVerification(paths: EvoPaths, record: PendingVerification): Promise<void> {\n\tawait atomicWriteJson(pendingVerificationPath(paths, record.runId), record);\n}\n\nexport async function readPendingVerification(\n\tpaths: EvoPaths,\n\trunId: string,\n): Promise<PendingVerification | undefined> {\n\tconst record = await readJsonIfExists<PendingVerification>(pendingVerificationPath(paths, runId));\n\tif (!record || record.schemaVersion !== 1 || record.runId !== runId) return undefined;\n\treturn record;\n}\n\nexport async function clearPendingVerification(paths: EvoPaths, runId: string): Promise<void> {\n\tawait rm(pendingVerificationPath(paths, runId), { force: true });\n}\n\nasync function readRunPlan(paths: EvoPaths, runId: string): Promise<EvolutionResearchPlan> {\n\tconst raw = await readFile(join(evolutionRunDirectory(paths, runId), \"plan.json\"), \"utf8\");\n\treturn JSON.parse(raw) as EvolutionResearchPlan;\n}\n\nasync function requirePendingVerification(\n\tpaths: EvoPaths,\n\trunId: string,\n): Promise<{ run: EvolutionRun; pending: PendingVerification }> {\n\tconst run = await readEvolutionRun(paths, runId);\n\tif (run.status !== \"awaiting-evidence\") {\n\t\tthrow new Error(`Evolution run ${runId} is ${run.status}, not awaiting a verification decision`);\n\t}\n\tconst pending = await readPendingVerification(paths, runId);\n\tif (!pending) throw new Error(`Evolution run ${runId} has no pending verification decision`);\n\treturn { run, pending };\n}\n\n/**\n * Release the candidate on the already-computed verdict without executing the\n * recommended verification. The frozen recommendation was never a release\n * blocker, so the standing release policy applies unchanged.\n */\nexport async function skipPendingVerification(options: {\n\tpaths: EvoPaths;\n\tservice: EvoService;\n\tconfig: EvoControlConfig;\n\trunId: string;\n}): Promise<EvolutionReleaseResult> {\n\tconst { pending } = await requirePendingVerification(options.paths, options.runId);\n\tconst plan = await readRunPlan(options.paths, options.runId);\n\tconst proposal = await loadProposal(options.paths, pending.proposalId);\n\tconst directory = evolutionRunDirectory(options.paths, options.runId);\n\tawait atomicWriteJson(join(directory, \"release-intent.json\"), {\n\t\tschemaVersion: 1,\n\t\tproposalId: proposal.id,\n\t\tverdict: pending.verdict,\n\t\tintendedAt: new Date().toISOString(),\n\t});\n\tconst release = await applyEvolutionReleasePolicy({\n\t\tservice: options.service,\n\t\tconfig: options.config,\n\t\tproposal,\n\t\tverdict: pending.verdict,\n\t\tevidenceStrategy: plan.experiment.evidenceStrategy,\n\t\treceipts: await readProfileReceipts(options.paths, options.runId),\n\t});\n\tawait updateEvolutionRun(options.paths, options.runId, {\n\t\tstatus: RELEASE_ACTION_RUN_STATUS[release.action],\n\t\tproposalId: release.proposal.id,\n\t\t...(release.action === \"awaiting-canary-approval\"\n\t\t\t? {\n\t\t\t\t\tcanaryCandidateDigest: release.proposal.candidateDigest,\n\t\t\t\t\tcanaryParentDigest: release.proposal.parentBundleDigest,\n\t\t\t\t\tcanaryTargetAbi: release.proposal.targetAbi,\n\t\t\t\t}\n\t\t\t: {}),\n\t});\n\tawait clearPendingVerification(options.paths, options.runId);\n\tawait rm(join(directory, \"release-intent.json\"), { force: true });\n\treturn release;\n}\n\n/** Reject the candidate outright instead of spending verification budget on it. */\nexport async function rejectPendingVerification(options: {\n\tpaths: EvoPaths;\n\tservice: EvoService;\n\trunId: string;\n}): Promise<void> {\n\tconst { pending } = await requirePendingVerification(options.paths, options.runId);\n\tawait options.service.reject(pending.proposalId, \"User declined the recommended verification and the candidate\");\n\tawait updateEvolutionRun(options.paths, options.runId, { status: \"completed\" });\n\tawait clearPendingVerification(options.paths, options.runId);\n}\n"]}