UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

148 lines (147 loc) • 14.7 kB
import { persistedReadDenyEntryProblem } from "../../tools/fs/read-deny.js"; import { validatePath } from "../effective-path-target.js"; import { isAskOrigin } from "../ask-origin.js"; import { CHECKPOINT_FEATURES, CheckpointError, checkpointVersionOf, MAX_SUPPORTED_CHECKPOINT_VERSION, realApprovalOrgFact } from "../checkpoint-store.js"; import { judgeCheckpointRequirements } from "../checkpoint-requirements.js"; import { constraintChainDigest, constraintChainEntryOfSuppliedLayer } from "../tool-policy.js"; import { readFrozenSkillGrants } from "../skill-grant.js"; import { chainInstallationGaps, chainInstallationRefusal } from "./child-tree.js"; import { screeningInstallationsOf, unraisableGuardsOf } from "../mods/stations.js"; import { refusePersistedToolNames, refuseRenamedDelegationMounts } from "./sub-agent-deny-lists.js"; import { asResumeConfigRefusal } from "../mode-policy.js"; export function resumeCheckpointScreen(input) { const { cp, resumeSignal, internals, tools, runner } = input; const { realApproval: realApprovalRow, face: faceRow, f012: f012Row } = CHECKPOINT_FEATURES; if (checkpointVersionOf(cp) > MAX_SUPPORTED_CHECKPOINT_VERSION) { throw new CheckpointError("checkpoint.unsupported_version", `checkpoint requires reader capabilities this worker lacks (row format v${checkpointVersionOf(cp)}; this worker reads up to v${MAX_SUPPORTED_CHECKPOINT_VERSION}) — resume it on a worker at or above the version that parked it`, { reason: "version_newer" }); } const requirements = judgeCheckpointRequirements(cp); if (requirements.kind === "lacking") throw new CheckpointError("checkpoint.unsupported_version", `checkpoint requires reader capabilities this worker lacks (${requirements.words.join(", ")}) — resume it on a worker at or above the version that parked it`, { reason: "version_newer", requires: requirements.words }); if (requirements.kind === "damaged") throw new CheckpointError("checkpoint.invalid_outcome", `this checkpoint's reader-requirement list does not match the row (${requirements.why}) — refusing to resume a damaged row (corruption guard), the checkpoint stays pending; no worker can resume it: start the task again`, { reason: "requirements_damaged" }); const preCasGateBit = cp.gate.kind === "irreversible_ask" ? cp.gate.realApproval : undefined; const preCasBitWellFormed = preCasGateBit !== undefined && typeof preCasGateBit === "object" && isAskOrigin(preCasGateBit.origin); const faceSaysGoverned = (cp.state.readFace?.realApproval) === true; const preCasBitViolation = checkpointVersionOf(cp) === realApprovalRow.version ? !preCasBitWellFormed : checkpointVersionOf(cp) < realApprovalRow.version ? preCasGateBit !== undefined : faceSaysGoverned ? !preCasBitWellFormed : preCasGateBit !== undefined && !preCasBitWellFormed; if (preCasBitViolation) { throw new CheckpointError("checkpoint.invalid_outcome", checkpointVersionOf(cp) >= realApprovalRow.version ? `a v${checkpointVersionOf(cp)} checkpoint's realApproval gate bit must be well-formed (origin a member of the closed ask-origin set)${checkpointVersionOf(cp) === realApprovalRow.version ? " and present on an irreversible_ask gate" : ""} — this row's is not; refusing to resume a damaged real-approval row (corruption / downgrade guard), the checkpoint stays pending` : `a v${checkpointVersionOf(cp)} checkpoint carries a realApproval gate bit no release of that version ever minted — refusing to honor a fabricated origin (corruption / forgery guard), the checkpoint stays pending`, { reason: checkpointVersionOf(cp) >= realApprovalRow.version ? "real_approval_damaged" : "real_approval_forged" }); } { const faceSectionRaw = cp.state.readFace; const faceCandidate = faceSectionRaw !== undefined && typeof faceSectionRaw === "object" && faceSectionRaw !== null ? faceSectionRaw : undefined; const faceWellFormed = faceCandidate !== undefined && (faceCandidate.face === "open" || faceCandidate.face === "roots") && (faceCandidate.realApproval === undefined || faceCandidate.realApproval === true) && (faceCandidate.denyEntries === undefined || (Array.isArray(faceCandidate.denyEntries) && faceCandidate.denyEntries.every((e) => persistedReadDenyEntryProblem(e) === null))); const v = checkpointVersionOf(cp); if (v === faceRow.version ? !faceWellFormed : v < faceRow.version ? faceSectionRaw !== undefined : faceSectionRaw !== undefined && !faceWellFormed) { throw new CheckpointError("checkpoint.invalid_outcome", checkpointVersionOf(cp) >= faceRow.version ? `a v${checkpointVersionOf(cp)} checkpoint must carry a well-formed read-face section (state.readFace) — this row's is missing or malformed; refusing to resume a damaged read-face row (corruption / downgrade guard), the checkpoint stays pending` : `a v${checkpointVersionOf(cp)} checkpoint carries a read-face section no release of that version ever minted — refusing to honor a fabricated read-face state (corruption / forgery guard), the checkpoint stays pending`, { reason: checkpointVersionOf(cp) >= faceRow.version ? "read_face_damaged" : "read_face_forged" }); } const writeFaceSectionRaw = cp.state.writeFace; if (writeFaceSectionRaw !== undefined) { const c = typeof writeFaceSectionRaw === "object" && writeFaceSectionRaw !== null ? writeFaceSectionRaw : undefined; if (c === undefined || !(c.face === "open" || c.face === "roots")) { throw new CheckpointError("checkpoint.invalid_outcome", `this checkpoint carries a write-face section (state.writeFace) that is not well-formed — refusing to resume a damaged write-face row (corruption guard), the checkpoint stays pending`, { reason: "write_face_damaged" }); } } if (readFrozenSkillGrants(cp.state.skillGrants) === undefined) throw new CheckpointError("checkpoint.invalid_outcome", "this checkpoint carries a skill-grant section (state.skillGrants) that does not read as grant rows under this engine — a damaged section, or a row an earlier release wrote whose entry this release reads as nothing (an entry with a surrounding space, say) — refusing to resume without the grant rows and refusals it carries; the checkpoint stays pending: finish it on a worker of the release that parked it, or expire it", { reason: "skill_grants_damaged" }); for (const field of ["handsRoot", "handsHome", "handsCwd"]) { const coordinate = cp.state[field]; if (coordinate !== undefined && validatePath(coordinate, { intent: "validate-coordinate" }) === undefined) throw new CheckpointError("checkpoint.invalid_outcome", `this checkpoint's state.${field} is not an absolute path — refusing to resume a row whose hands' coordinates are damaged (corruption guard), the checkpoint stays pending`, { reason: "hands_coordinates_damaged" }); } } if (realApprovalOrgFact(preCasGateBit) !== undefined && runner.deps.permissionRuleStore?.partitions.org !== true) { throw new CheckpointError("checkpoint.unsupported_version", `this checkpoint's approval was minted under organization governance (org ${String(realApprovalOrgFact(preCasGateBit))}, routed as ${String(preCasGateBit?.origin)}) and this worker has no org adjudication wiring (its permission-rule store carries no org partition) — a governed approval may only be redeemed where governance can be enforced; the checkpoint stays pending, resume it on an org-wired worker`, { reason: "governed_unwired" }); } const retiredWalltimeTotal = cp.resourceLedger?.totalWalltimeSec; if (retiredWalltimeTotal !== undefined) { throw new CheckpointError("checkpoint.walltime_axis_retired", "this checkpoint's ledger carries a cross-slice WALL-CLOCK allocation (resourceLedger.totalWalltimeSec), an axis this engine version retired — " + "resuming here would run the leg with that ceiling unenforced. Rejected pre-CAS (the checkpoint stays pending): finish it on a worker of the " + "previous release, or start a fresh task bounded by resourceSuspend.totalTokens / totalBudgetUsd."); } if (resumeSignal?.aborted === true && cp.status === "pending") { throw new CheckpointError("checkpoint.resume_aborted", "the resume was handed an ALREADY-ABORTED signal — refusing to consume the approval on a leg that cannot run it (the checkpoint stays pending and is resumable with a live signal)"); } if (cp.state.workspaceHandle !== undefined && runner.deps.executionEnvFactory === undefined) { throw new CheckpointError("checkpoint.unsupported_version", "checkpoint has a remote workspaceHandle but no RunnerDeps.executionEnvFactory is wired to rebuild the env", { reason: "env_factory_missing" }); } if (cp.state.workspaceHandle !== undefined && internals?.requestedCwd !== undefined) { throw new CheckpointError("checkpoint.cwd_conflicts_restore", `internals.requestedCwd ("${internals.requestedCwd}") cannot be combined with a checkpoint workspace restore — ` + "the restored workspace's own mount path is authoritative for the task root. Drop requestedCwd on resume legs " + "(the checkpoint stays pending and is resumable without it)."); } asResumeConfigRefusal("inheritedGate", () => refusePersistedToolNames((internals?.toolCeiling ?? undefined) === undefined ? cp.state.toolCeiling : undefined, cp.state.inheritedGate?.constraintChain, (internals?.ownToolLists ?? undefined) === undefined ? cp.state.ownToolLists : undefined)); asResumeConfigRefusal("taskConfig", () => refuseRenamedDelegationMounts(tools)); if (cp.state.inheritedGate?.requiresParentConstraint === true) { const supplied = internals?.inheritedGate?.parentConstraints?.length ?? 0; if (supplied === 0) { throw new CheckpointError("resume.parent_constraint_missing", "this checkpoint's task ran under inherited parent-policy constraints (state.inheritedGate.requiresParentConstraint) " + "— the live policy/onAsk closures cannot be persisted, so the resume must re-supply them via " + "resumeStream(token, outcome, taskConfig, internals) with internals.inheritedGate.parentConstraints; " + "rejected pre-CAS (the checkpoint stays pending) rather than silently dropping the ancestors' gate"); } const expected = cp.state.inheritedGate.parentConstraintCount; if (expected !== undefined && supplied !== expected) { throw new CheckpointError("resume.parent_constraint_mismatch", `re-supplied ${supplied} parent constraint(s) but the checkpoint recorded ${expected} — a partial/mismatched ` + "re-supply would run the resumed leg under a different ancestor chain than it suspended with; " + "rejected pre-CAS (the checkpoint stays pending) — re-resume with the full original chain"); } if (checkpointVersionOf(cp) >= f012Row.version && (cp.state.inheritedGate.constraintChain === undefined || cp.state.inheritedGate.constraintDigest === undefined)) { throw new CheckpointError("checkpoint.invalid_outcome", `a v${checkpointVersionOf(cp)} checkpoint that requires parent constraints must carry BOTH the frozen constraintChain and its constraintDigest (they are minted in one write with the version stamp) — this row carries neither or only one; refusing to fall back to the count-only contract on a damaged row (corruption / downgrade guard), the checkpoint stays pending`, { reason: "constraint_chain_missing" }); } const expectedDigest = cp.state.inheritedGate.constraintDigest; if (expectedDigest !== undefined) { const persistedChain = cp.state.inheritedGate.constraintChain; if (persistedChain === undefined || constraintChainDigest(persistedChain) !== expectedDigest) { throw new CheckpointError("resume.parent_constraint_mismatch", "the checkpoint's OWN recorded constraint chain does not match its recorded digest " + "(corrupt / inconsistently-minted row) — the frozen deny data the resume would execute is not the data the " + "digest authenticates; rejected pre-CAS (the checkpoint stays pending)"); } const suppliedDigest = constraintChainDigest((internals?.inheritedGate?.parentConstraints ?? []).map((pc, i) => constraintChainEntryOfSuppliedLayer(pc, persistedChain[i]))); if (suppliedDigest !== expectedDigest) { throw new CheckpointError("resume.parent_constraint_mismatch", "the re-supplied parent-constraint chain's projection content does not match what the checkpoint recorded " + `(recorded ${expectedDigest}, re-supplied ${suppliedDigest}) — a same-shape chain with different frozen ` + "deny data would run the resumed leg under a different ancestor gate than it suspended with; " + "rejected pre-CAS (the checkpoint stays pending) — re-resume with the original chain's policies " + "(including, when the row recorded one, the ancestor's auto-mode arming recipe verbatim)"); } } } const resupplied = (internals?.inheritedGate?.parentConstraints ?? []).map((pc) => pc.policy); if (resupplied.length > 0) { const gaps = chainInstallationGaps(resupplied, { live: internals?.inheritedGate?.pathRuleInstallations, seed: cp.state.inheritedGate?.pathRuleInstallations }, (p) => p); if (gaps.length > 0) throw chainInstallationRefusal(gaps, true); } const unraisable = unraisableGuardsOf(screeningInstallationsOf(internals?.inheritedGate?.parentConstraints ?? [])); if (unraisable !== undefined) throw new CheckpointError("resume.parent_constraint_mismatch", `${unraisable}; rejected pre-CAS (the checkpoint stays pending)`); const resumeInternals = internals?.inheritedGate?.parentConstraints !== undefined ? { ...internals, inheritedGate: { ...internals.inheritedGate, parentConstraints: Object.freeze(internals.inheritedGate.parentConstraints.map((e) => ({ ...e }))), }, } : internals; return { resumeInternals }; }