import type { AgentResult, TaskEnvelope } from "../types.js"; import { fitEnvelope } from "../context/envelope.js"; export type ReviewRole = "reviewer" | "verifier" | "arbiter"; export function reviewEnvelope(envelope: TaskEnvelope, role: ReviewRole, hardCapTokens = 8_000): TaskEnvelope { return fitEnvelope({ ...envelope, trace: { runId: envelope.trace.runId, nodeId: role, parentNodeId: envelope.trace.nodeId }, taskSynopsis: `Independently ${role === "reviewer" ? "review" : role === "verifier" ? "verify" : "adjudicate"} the writer result within the declared scope.`, lens: role, evidenceTarget: "Material correctness, security, regression, scope, or acceptance defects that must block integration", knownFacts: [], openQuestions: ["Does the current writer result contain a material integration blocker?"], constraints: [ "Read only; do not edit files or invoke shell commands", "No recursive orchestration or delegation", "Inspect only the declared writer scope", "Do not invent a finding; approve only with the exact sentinel", ], outputContract: { schemaName: "AgentResult", maxOutputTokens: Math.min(600, envelope.outputContract.maxOutputTokens), maxFacts: Math.min(4, envelope.outputContract.maxFacts), maxHypotheses: 0, maxUnknowns: Math.min(2, envelope.outputContract.maxUnknowns) }, }, hardCapTokens); } function boundedFindings(result: AgentResult | undefined) { return result?.facts.slice(0, 4).map((fact) => ({ id: fact.id, claim: fact.claim.slice(0, 1_000), evidence: fact.evidence.slice(0, 2).map((entry) => ({ ...(entry.path ? { path: entry.path.slice(0, 500) } : {}), ...(entry.lines ? { lines: entry.lines.slice(0, 128) } : {}), ...(entry.commandId ? { commandId: entry.commandId.slice(0, 128) } : {}), observation: entry.observation.slice(0, 1_000) })), })) ?? []; } export function reviewPrompt(envelope: TaskEnvelope, role: ReviewRole, reviewerResult?: AgentResult, patchContext = ""): string { const findings = boundedFindings(reviewerResult); return [ `Act as the independent ${role}. Review the current isolated worktree from first principles; do not assume another review is correct.`, "Use only the scoped read tools. Do not edit, run shell commands, delegate, or orchestrate.", role === "verifier" ? `Independently verify only these bounded reviewer findings: ${JSON.stringify(findings)}. For each confirmed finding, return a fact whose claim is exactly CONFIRMED: and repeat at least one supplied evidence object exactly.` : role === "arbiter" ? `Two independent reviewers have confirmed material findings: ${JSON.stringify(findings)}. Re-inspect the isolated worktree and return an AgentResult with summary exactly BLOCK_INTEGRATION, no facts, hypotheses, unknowns, or dependencies.` : "Report only material integration blockers supported by concrete evidence; do not invent a finding.", ...(patchContext ? [patchContext] : []), role === "arbiter" ? "Return exactly one bounded JSON AgentResult and no prose." : "Return exactly one bounded JSON AgentResult and no prose. When there is no material finding to report or confirm, return {\"schemaVersion\":1,\"status\":\"complete\",\"summary\":\"NO_MATERIAL_FINDINGS\",\"facts\":[],\"hypotheses\":[],\"unknowns\":[],\"dependencies\":[]}.", `Finding IDs must use F:${envelope.trace.runId}:${envelope.trace.nodeId}:.`, JSON.stringify(envelope), ].join("\n\n"); } function reviewApproved(result: AgentResult): boolean { return result.status === "complete" && result.summary === "NO_MATERIAL_FINDINGS" && result.facts.length === 0 && result.hypotheses.length === 0 && result.unknowns.length === 0 && result.dependencies.length === 0; } function evidenceKey(evidence: AgentResult["facts"][number]["evidence"][number]): string { return JSON.stringify([evidence.path ?? "", evidence.lines ?? "", evidence.commandId ?? "", evidence.observation]); } export function reviewQuorum(results: readonly AgentResult[]): { approved: boolean; approvals: number; disagreement: boolean; confirmedFindings: number; failed: boolean; reviewers: number } { const reviewer = results[0]; const verifier = results[1]; if (!reviewer) return { approved: false, approvals: 0, disagreement: false, confirmedFindings: 0, failed: true, reviewers: 0 }; if (reviewApproved(reviewer)) return { approved: true, approvals: 1, disagreement: false, confirmedFindings: 0, failed: false, reviewers: 1 }; if (reviewer.status !== "complete" || reviewer.facts.length === 0 || !verifier || verifier.status !== "complete") return { approved: false, approvals: 0, disagreement: false, confirmedFindings: 0, failed: true, reviewers: results.length }; const confirmedFindings = reviewer.facts.filter((finding) => finding.evidence.length > 0 && verifier.facts.some((confirmation) => confirmation.claim === `CONFIRMED:${finding.id}` && confirmation.evidence.some((evidence) => finding.evidence.some((candidate) => evidenceKey(candidate) === evidenceKey(evidence))))).length; const falsePositive = confirmedFindings === 0 && reviewApproved(verifier); return { approved: falsePositive, approvals: falsePositive ? 1 : 0, disagreement: confirmedFindings !== reviewer.facts.length, confirmedFindings, failed: false, reviewers: 2 }; } export function hasQuorum(results: AgentResult[], claim: string, needed = 2): boolean { return results.filter((result) => result.facts.some((fact) => fact.claim === claim)).length >= needed; }