Files
PaperClipAI/tests/runner-e2e/non-execution-wake.ts
T
DottaandPaperclip 8c9dd1e444 test(runner): qualify Kimi Code lifecycle and recovery (#18029)
Add the Kimi lifecycle and recovery qualification harness. Preserve original grades and cleanup evidence, strict native ownership audits, bounded startup and cleanup, and early rejection of unsupported local fault execution before credentials or resources.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-30 22:54:37 -05:00

181 lines
13 KiB
TypeScript

import { createHash } from "node:crypto";
/** A queued parent wake can be suppressed while its child still runs. This is
* not a provider failure: admission never started. Keep it in the evidence. */
export function isBlockedUnstartedWake(run: Record<string, unknown>) {
return run.status === "cancelled" && run.errorCode === "issue_dependencies_blocked" && run.startedAt === null;
}
/** The dispatch gate retired an obsolete assignment before any provider work. */
export function isReassignedUnstartedWake(run: {
status?: unknown; errorCode?: unknown; startedAt?: unknown; nativeIssueId?: unknown;
resultJson?: Record<string, unknown>;
}) {
return run.status === "cancelled" && run.errorCode === "issue_assignee_changed" && run.startedAt === null
&& run.nativeIssueId == null && run.resultJson?.stopReason === "issue_assignee_changed"
&& run.resultJson.timeoutSource === "stale_queued_run_gate" && run.resultJson.timeoutFired === false;
}
/** A terminal issue may make a queued wake obsolete before provider admission. */
export function isTerminalUnstartedWake(
run: Record<string, unknown>,
tasks: Array<{ id: string; status?: unknown }>,
) {
const context = run.contextSnapshot;
const issueId = context && typeof context === "object" && "issueId" in context ? context.issueId : undefined;
return run.status === "cancelled" && run.errorCode === "issue_terminal_status" &&
run.startedAt === null && tasks.some(task =>
task.id === issueId && ["done", "cancelled"].includes(String(task.status)),
);
}
type Row = Record<string, unknown>;
const object = (value: unknown): Row | null => value !== null && typeof value === "object" && !Array.isArray(value)
? value as Row : null;
const uuid = (value: unknown): value is string => typeof value === "string" &&
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
const time = (value: unknown) => typeof value === "string" ? Date.parse(value) : Number.NaN;
const keys = (value: Row, expected: string[]) => Object.keys(value).sort().join(",") === expected.sort().join(",");
const one = (value: unknown, expected: unknown) => Array.isArray(value) && value.length === 1 && value[0] === expected;
export interface ChatAdmissionWait {
runId: string;
kind: "pre_dispatch_execution_wait";
companyId: string;
agentId: string;
issueId: string;
recoveryActionId: string;
wakeupRequestId: string;
commentId: string;
}
export function classifyPreDispatchExecutionWait(run: unknown, events: unknown): ChatAdmissionWait | null {
const row = object(run), context = object(row?.contextSnapshot), result = object(row?.resultJson);
const wait = object(result?.executionWait);
if (!row || !context || !result || !wait || !Array.isArray(events) || events.length !== 1) return null;
for (const field of ["id", "companyId", "agentId", "wakeupRequestId"]) if (!uuid(row[field])) return null;
if (!uuid(context.issueId) || !uuid(context.wakeCommentId) || !uuid(wait.recoveryActionId) ||
wait.issueId !== context.issueId || row.issueId !== context.issueId ||
context.source !== "issue.comment" || context.wakeReason !== "issue_commented" ||
!one(context.wakeCommentIds, context.wakeCommentId)) return null;
if (row.runtimeMode !== "legacy" || row.status !== "cancelled" ||
row.invocationSource !== "on_demand" || row.triggerDetail !== "manual" ||
row.errorCode !== "execution_reconciliation_required" || row.runnerProfileJson !== null ||
!keys(result, ["stopReason", "timeoutSource", "timeoutFired", "timeoutConfigured", "effectiveTimeoutSec", "executionWait"]) ||
!keys(wait, ["issueId", "recoveryActionId"]) || result.stopReason !== row.errorCode ||
result.timeoutSource !== "stale_queued_run_gate" || result.timeoutFired !== false ||
result.timeoutConfigured !== false || result.effectiveTimeoutSec !== 0 ||
row.nextEventSeq !== 2 || row.logCompressed !== false ||
!(row.sessionIdBefore === null || (typeof row.sessionIdBefore === "string" && row.sessionIdBefore.length > 0)) ||
!Number.isFinite(time(row.createdAt)) || !Number.isFinite(time(row.finishedAt)) ||
time(row.finishedAt) < time(row.createdAt)) return null;
for (const field of ["startedAt", "runtimeModeResolvedAt", "runtimeModeReason", "runtimeModeResolverVersion",
"runnerInstanceId", "nativeSessionId", "nativeIssueId", "driverKind", "driverVersion", "completionContractId",
"completionContractSha256", "nativePhase", "sessionIdAfter", "controllerBootId",
"controllerLeaseExpiresAt", "executionStage", "processPid", "processGroupId", "processStartedAt", "logStore",
"logRef", "logBytes", "logSha256", "stdoutExcerpt", "stderrExcerpt", "usageJson", "exitCode", "signal", "externalRunId"])
if (row[field] !== null) return null;
const event = object(events[0]), payload = object(event?.payload);
if (!event || !payload || event.seq !== 1 || event.runId !== row.id || event.companyId !== row.companyId ||
event.agentId !== row.agentId || event.eventType !== "lifecycle" || event.stream !== "system" || event.level !== "warn" ||
typeof row.error !== "string" || !row.error || event.message !== row.error ||
!keys(payload, ["issueId", "recoveryActionId"]) || payload.issueId !== wait.issueId ||
payload.recoveryActionId !== wait.recoveryActionId) return null;
for (const field of ["sourceInstanceId", "sourceEventId", "sourceSeq", "sourcePayloadSha256", "protocolSchemaVersion"])
if (event[field] !== null) return null;
return { runId: String(row.id), kind: "pre_dispatch_execution_wait", companyId: String(row.companyId),
agentId: String(row.agentId), issueId: context.issueId, recoveryActionId: wait.recoveryActionId,
wakeupRequestId: String(row.wakeupRequestId), commentId: context.wakeCommentId };
}
export function chatProviderRuns<T extends { id: string; contextSnapshot?: Record<string, unknown>; resultJson?: Record<string, unknown> }>(
runs: T[], admissionWaits: readonly ChatAdmissionWait[] = [],
) {
const waiting = new Set(admissionWaits.map(wait => wait.runId));
return runs.filter(run => run.contextSnapshot?.conversationReset !== true &&
run.resultJson?.conversationReset !== true && !waiting.has(run.id));
}
export function verifyChatAdmissionWaitCoverage(input: {
runs: unknown[]; runEvidence: unknown[]; comments: unknown[]; issue: unknown;
companyId: string; agentId: string; stoppedRunId: string | undefined;
recoverySources: Array<{ runId: string; recoveryActionId: string; response: unknown }>;
}): ChatAdmissionWait[] {
function require(condition: unknown, code: string): asserts condition {
if (!condition) throw new Error(`Chat admission wait: ${code}`);
}
const rows = input.runs.map(object), issue = object(input.issue);
require(rows.every(Boolean) && issue, "missing_rows");
require(new Set(rows.map(row => row!.id)).size === rows.length, "duplicate_rows");
const candidates = rows.filter(row => row!.errorCode === "execution_reconciliation_required");
require(candidates.length <= 1, "repeated_admission");
if (!candidates.length) return [];
require(issue.companyId === input.companyId && issue.assigneeAgentId === input.agentId &&
issue.conversationSessionGeneration === 1, "issue_scope");
const stopped = rows.find(row => row!.id === input.stoppedRunId), cancellation = object(object(stopped?.resultJson)?.nativeCancellation);
require(stopped && stopped.runtimeMode === "native" && stopped.status === "cancelled" &&
stopped.companyId === input.companyId && stopped.agentId === input.agentId && stopped.nativeIssueId === issue.id &&
cancellation?.schema === "paperclip.native-cancellation.v1" && cancellation.runId === stopped.id &&
cancellation.companyId === input.companyId && cancellation.issueId === issue.id && cancellation.scope === "run" &&
cancellation.reasonCode === "cancellation_run_only" && cancellation.dispatchState === "acknowledged" &&
cancellation.dispatched === true, "stopped_native_source");
const waits: ChatAdmissionWait[] = [];
for (const row of candidates) {
const evidence = input.runEvidence.map(object).filter(value => value?.runId === row!.id);
require(evidence.length === 1 && evidence[0]!.log === null &&
evidence[0]!.logOmissionReason === "pre_dispatch_execution_wait", "complete_event_receipt");
const wait = classifyPreDispatchExecutionWait(row, evidence[0]!.events);
require(wait && wait.companyId === input.companyId && wait.agentId === input.agentId && wait.issueId === issue.id, "wait_scope");
const comment = input.comments.map(object).filter(value => value?.id === wait.commentId);
require(comment.length === 1 && comment[0]!.companyId === input.companyId && comment[0]!.issueId === issue.id &&
comment[0]!.body === "/new" && comment[0]!.authorType === "user" && comment[0]!.deletedAt === null &&
typeof comment[0]!.authorUserId === "string" && comment[0]!.authorUserId &&
comment[0]!.authorAgentId === null && comment[0]!.createdByRunId === null &&
row!.responsibleUserId === comment[0]!.authorUserId && time(stopped.finishedAt) < time(comment[0]!.createdAt) &&
time(comment[0]!.createdAt) <= time(row!.createdAt), "saved_human_new");
if (row!.sessionIdBefore !== null) {
const seed = rows.filter(value => value!.runtimeMode === "native" && value!.status === "succeeded" &&
object(value!.contextSnapshot)?.conversationSessionGeneration !== 1);
require(seed.length === 1 && seed[0]!.sessionIdAfter === row!.sessionIdBefore &&
stopped.sessionIdBefore === row!.sessionIdBefore, "historical_session_hint");
}
const reset = rows.filter(value => object(value!.contextSnapshot)?.conversationReset === true);
require(reset.length === 1, "single_authored_reset");
const resetContext = object(reset[0]!.contextSnapshot)!;
require(reset[0]!.status === "succeeded" && resetContext.wakeCommentId === wait.commentId &&
resetContext.commentId === wait.commentId && resetContext.conversationSessionGeneration === 1 &&
object(reset[0]!.resultJson)?.conversationReset === true && issue.conversationBoundaryCommentId === wait.commentId &&
time(row!.finishedAt) <= time(reset[0]!.startedAt), "same_saved_reset");
const sources = input.recoverySources.filter(value => value.runId === stopped.id && value.recoveryActionId === wait.recoveryActionId);
require(sources.length === 1, "selected_recovery");
const response = object(sources[0]!.response), actions = response?.actions;
require(Array.isArray(actions) && actions.length === 1, "exact_recovery_action");
const action = object(actions[0]), facts = object(action?.evidence), recovery = object(facts?.systemRecovery),
preservation = object(facts?.workspaceRecovery), automatic = object(facts?.automaticRecovery),
authorization = object(facts?.explicitUserContinuation), inspection = object(response?.sourceInspection);
require(action?.id === wait.recoveryActionId && action.companyId === input.companyId && action.sourceIssueId === issue.id &&
action.status === "resolved" && action.outcome === "cancelled" && Number.isFinite(time(action.resolvedAt)) &&
action.fingerprint === `native-workspace:${stopped.id}` && facts?.runId === stopped.id &&
automatic?.policy === "preserve_without_replay_v1" && automatic.replay === "explicit_user_continuation" && automatic.runId === stopped.id &&
authorization && authorization.previousRunId === stopped.id && authorization.commentId === wait.commentId &&
authorization.actorId === comment[0]!.authorUserId && authorization.runId === reset[0]!.id &&
authorization.queuedCommentRequestId === wait.wakeupRequestId &&
authorization.commentBodyHash === createHash("sha256").update("/new").digest("hex") &&
recovery?.schema === "paperclip.system-recovery.v1" && recovery.sourceRunId === stopped.id && recovery.state === "complete" &&
recovery.phase === "reconcile_effects" && Array.isArray(recovery.preservationOperationIds) && recovery.preservationOperationIds.length > 0 &&
recovery.preservationOperationIds.every(uuid) && new Set(recovery.preservationOperationIds).size === recovery.preservationOperationIds.length &&
preservation?.schema === "paperclip.workspace-recovery.v1" && preservation.runId === stopped.id && preservation.status === "recovered" &&
inspection?.schema === "paperclip.workspace-source-inspection.v1" && inspection.actionId === wait.recoveryActionId &&
inspection.runId === stopped.id && inspection.scope === "recorded_source_identity" && inspection.status === "verified", "preserved_native_source");
waits.push(wait);
}
const providers = chatProviderRuns(rows as Array<Row & { id: string }>, waits);
require(providers.length === 3 && providers.every(row => row.runtimeMode === "native" && row.companyId === input.companyId && row.agentId === input.agentId &&
row.nativeIssueId === issue.id && object(row.contextSnapshot)?.issueId === issue.id) &&
providers.filter(row => row.status === "cancelled").length === 1 && providers.filter(row => row.status === "succeeded").length === 2, "three_native_providers");
const fresh = providers.filter(row => row.status === "succeeded" && object(row.contextSnapshot)?.conversationSessionGeneration === 1);
require(fresh.length === 1 && fresh[0]!.sessionIdBefore === null &&
time(fresh[0]!.startedAt) >= time(rows.find(row => object(row!.contextSnapshot)?.conversationReset === true)!.finishedAt), "fresh_native_after_reset");
return waits;
}