fix(native): scope governed waits to one run

Clear settled wait authority when rebinding a provider session to a new run. Reject duplicate approval requests that reference a resolved action through an unknown completion criterion.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-07 10:38:12 -05:00
1 parent 7ad54e8305
commit ba9b0b4610
5 files changed
+19 -2

No files matched your search

+2
View File
@@ -1373,6 +1373,8 @@ settling their usage and terminal evidence before detaching. Recovery verifies
the trigger against the retained event ledger and settles that same turn, even
if the user has already answered the interaction. It replays retained accounting
through the ordinary control-plane observers without starting another model turn.
When a later heartbeat run reuses the provider session, it clears that prior
run's wait marker along with its terminal, result and pending-request authority.
A timeout, missing accounting, or an unproven provider terminal remains a failure;
the saved wait does not certify successful provider execution.
@@ -77,6 +77,11 @@ describe("native final-response feedback", () => {
completionClaim: { ...report.completionClaim, criteria: [{ criterionId: "objective", status: "not_satisfied", evidenceRefs: [`approval:${actionRequestId}`] }] },
};
await expect(nativeCompletionFeedback(db, value.runId, criterionOnly)).rejects.toThrow("already resolved");
// A provider can mark the approval criterion unknown while citing the exact
// declined interaction; that still is not a new review target.
await expect(nativeCompletionFeedback(db, value.runId, {
...criterionOnly, completionClaim: { ...criterionOnly.completionClaim, criteria: [{ criterionId: "objective", status: "unknown", evidenceRefs: [`interaction:${interactionId}`] }] },
})).rejects.toThrow("already resolved");
// Satisfied historical evidence does not bind the independent review target.
if (disposition !== "yielded") await expect(nativeCompletionFeedback(db, value.runId, {
...criterionOnly, completionClaim: { ...criterionOnly.completionClaim, criteria: [{ criterionId: "past-action", status: "satisfied", evidenceRefs: [`approval:${actionRequestId}`] }] },
@@ -186,7 +186,7 @@ export async function nativeCompletionFeedback(
blocker: result.blocker,
// An unmet criterion can name the action still being requested. Completed
// evidence elsewhere in the report is not authority to suppress a review.
unmetCriteria: result.completionClaim.criteria.filter(criterion => criterion.status === "not_satisfied"),
unmetCriteria: result.completionClaim.criteria.filter(criterion => criterion.status !== "satisfied"),
continuation: result.continuation,
// The existing response-wake contract also names its card through evidence.
evidence: result.reportedWorkDisposition === "yielded" && result.continuation?.kind === "response_wake" ? result.evidence : [],
@@ -2125,10 +2125,17 @@ describe("rebindNativeSessionCheckpoint", () => {
});
it("retains provider identity but clears prior turn and event state", () => {
const prior = previousRun();
const profile = prior.runnerProfileJson as Record<string, unknown>;
const checkpoint = profile.sessionCheckpoint as Record<string, unknown>;
checkpoint.governedWait = { sourceEvent: { runId: previousRunId, turnId: "old-turn" }, result: { reportedWorkDisposition: "yielded" } };
const before = structuredClone(prior);
const rebound = rebindNativeSessionCheckpoint({
previousRun: previousRun(),
previousRun: prior,
currentExecution: execution(currentRunId),
});
expect(rebound?.governedWait).toBeUndefined();
expect(prior).toEqual(before);
expect(rebound).toMatchObject({
sessionId: "provider-thread-123",
providerSessionId: "provider-thread-123",
@@ -568,6 +568,9 @@ export function rebindNativeSessionCheckpoint(input: {
activeTurnId: null,
terminalTurns: [],
pendingRuntimeRequests: [],
// Settlement evidence belongs to the prior heartbeat run, even when the
// provider session is reused for the user's response.
governedWait: undefined,
providerRecoveryPolicy,
};
}