import { GatekeeperDecisionError, ParentQueueReaskError, WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError, } from "./submission-errors.ts"; import { errorText } from "./unknown-value.ts"; /** Shared, unforgeable identity for submission errors that the same session may correct. */ const correctableSubmissionErrorBrand = Symbol("ak-roles.correctable-submission-error"); export abstract class CorrectableSubmissionError extends Error { readonly [correctableSubmissionErrorBrand] = true; } export function isCorrectableSubmissionError(error: unknown): error is CorrectableSubmissionError { return error instanceof CorrectableSubmissionError; } /** * Execute-path throws the same session may correct: branded correctable errors plus * gatekeeper bounce/no_receipt and worker reminder classes (ledger + Grok MCP catch). * One predicate — do not re-list instanceof chains at each catch. */ export function isCorrectableExecuteError(error: unknown): boolean { return ( isCorrectableSubmissionError(error) || error instanceof GatekeeperDecisionError || error instanceof ParentQueueReaskError || error instanceof WorkerCommitReminderError || error instanceof WorkerPrefixReminderError || error instanceof WorkerUnfinishedReasonReminderError ); } /** * Durable projection for correctable execute errors. * The ACP envelope consumes it on every correctable catch. The Pi adapter * consumes it for the one-shot commit and prefix reminders and the * unfinished-reason reminder, returned as an isError tool result. Other Pi * correctable errors stay native throws. */ export type CorrectableExecuteRejectionProjection = { readonly diagnostic: string; readonly details: Record; }; /** * One authority for correctable execute → diagnostic text + structured details. * Consumed by the ACP envelope tool catch; host adapters wrap transport shape only. */ export function projectCorrectableExecuteRejection( error: unknown, ): CorrectableExecuteRejectionProjection { const diagnostic = errorText(error); if (error instanceof GatekeeperDecisionError) { return { diagnostic, details: { ...(error.result as Record) } }; } if ( error instanceof WorkerCommitReminderError || error instanceof WorkerPrefixReminderError || error instanceof WorkerUnfinishedReasonReminderError ) { return { diagnostic, details: { code: error.code } }; } if (typeof (error as { code?: unknown }).code === "string") { return { diagnostic, details: { code: (error as { code: string }).code } }; } return { diagnostic, details: { code: error instanceof Error && error.name ? error.name : "correctable-submission-error", }, }; }