import type { StoryComment } from "./everyday-observations.js"; type Decision = { id: string; kind: string; status: string; resolvedAt?: string | null; result?: { answers?: Array<{ questionId: string; optionIds?: string[] }> }; }; type Reply = Pick; type Run = { id: string; nativeIssueId?: string | null; agentId?: string | null; status: string; finishedAt?: string | null }; // Additional oracle for the new neutral-prompt suite only. Historical Everyday // grades remain intact. This proves attributed saved output, not cognition. export type ConnectionGuidanceDeclineInput = { caseId: "service-decline" | "connection-decline" | "provider-decline"; decisionId: string; decisions: Decision[]; leadAgentId: string; issueId: string; replies: Reply[]; runs: Run[]; calls?: number; marker: string; sameConnections: boolean; }; function declineReplyEvidence(input: ConnectionGuidanceDeclineInput) { const decision = input.decisions.find(row => row.id === input.decisionId); const resolvedAt = Date.parse(decision?.resolvedAt ?? ""); const provider = input.caseId === "provider-decline"; const expectedKind = provider ? "ask_user_questions" : input.caseId === "connection-decline" ? "connection_intent" : "request_confirmation"; const options = decision?.result?.answers?.find(answer => answer.questionId === "connection-provider:hubspot")?.optionIds; const validDecision = Number.isFinite(resolvedAt) && decision?.kind === expectedKind && (provider ? decision.status === "answered" && options?.length === 1 && options[0] === "none" : decision?.status === "rejected"); const afterDecision = input.replies.filter(reply => validDecision && reply.authorAgentId === input.leadAgentId && Number.isFinite(Date.parse(reply.createdAt ?? "")) && Date.parse(reply.createdAt!) >= resolvedAt); const finalRunTime = Math.max(...input.runs.filter(run => run.agentId === input.leadAgentId && run.nativeIssueId === input.issueId && run.status === "succeeded") .map(run => Date.parse(run.finishedAt ?? "")).filter(Number.isFinite)); const attributed = afterDecision.filter(reply => input.runs.some(run => Boolean(reply.createdByRunId) && run.id === reply.createdByRunId && run.agentId === input.leadAgentId && run.nativeIssueId === input.issueId && run.status === "succeeded" && Date.parse(run.finishedAt ?? "") >= resolvedAt && Date.parse(run.finishedAt ?? "") === finalRunTime)); return { validDecision, afterDecision, attributed }; } /** Readiness waits for storage, not a passing explanation. Wrong wording must still fail grading. */ export function hasConnectionGuidanceDeclineReply(input: ConnectionGuidanceDeclineInput): boolean { return declineReplyEvidence(input).attributed.some(reply => typeof reply.body === "string" && reply.body.trim().length > 0); } /** Bounded textual evidence, not a claim about model reasoning or native skill activation. */ export function explainsConnectionUnavailable(text: string): boolean { const normalized = text.replaceAll("’", "'"); return /(? typeof reply.body === "string" && explainsConnectionUnavailable(reply.body)), detail: "A saved explanation follows the decision and joins by run ID to the lead's final successful execution on this task." }, { id: "guidance-decline-no-use", passed: (input.caseId === "connection-decline" || input.calls === 0) && input.sameConnections && afterDecision.every(reply => (typeof reply.body !== "string" || !reply.body.includes(input.marker))), detail: "No connection changes or unread marker in replies. Installed-service/provider declines also require an observed zero fixture-call count; Notion setup does not execute a service." }, ]; }