Skip to content

Commit ab0f8a0

Browse files
committed
Preserve other wait routes during bound Todo recovery
Signed-off-by: huangruiteng <huangrt01@163.com>
1 parent 21d6349 commit ab0f8a0

2 files changed

Lines changed: 25 additions & 2 deletions

File tree

‎loopx/control_plane/quota/blocked_wait.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,12 @@ export function projectReceiptBoundWait(value: unknown): JsonObject {
152152
todo.resume_ready !== false || (todo.claimed_by && todo.claimed_by !== request.agent_id)) {
153153
return {status: "none"};
154154
}
155-
// Share the same validation as the real writeback, including target
156-
// existence, monitor generation and bounded timer checks.
155+
// This projection repairs registered Todo dependencies. Other wait kinds
156+
// retain their existing route: in particular, a valid long timer must not
157+
// be rejected by the separate 1–30 minute blocked-retry writeback budget.
158+
const kind = jsonObject(todo.resume_condition)?.kind;
159+
if (kind !== "monitor_changed" && kind !== "todo_done") return {status: "none"};
160+
// Share the real writeback validation of target existence and generation.
157161
const wait = prepareBlockedWait({...request, schema_version: BLOCKED_WAIT_REQUEST_SCHEMA,
158162
allow_turn_settlement_retry: false});
159163
const reason = "The Todo bound to this Turn now waits on a dependency. Record its verified blocked closeout without spending quota; select independent work on the next host Turn.";

‎tests/control_plane_ts/receipt_bound_wait.test.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import assert from "node:assert/strict";
22
import test from "node:test";
33
import {projectReceiptBoundWait, RECEIPT_BOUND_WAIT_REQUEST_SCHEMA} from "../../loopx/control_plane/quota/blocked_wait.ts";
4+
import {evaluateTodoResumeConditions, TODO_RESUME_EVALUATION_REQUEST_SCHEMA_VERSION} from "../../loopx/control_plane/todos/resume_condition.ts";
45

56
function request() {
67
return {schema_version: RECEIPT_BOUND_WAIT_REQUEST_SCHEMA, agent_id: "agent-a",
@@ -45,3 +46,21 @@ test("a fabricated, missing, or changed dependency cannot qualify blocked closeo
4546
input.todos[1]!.material_change_generation = 3;
4647
assert.throws(() => projectReceiptBoundWait(input), /registered pending/);
4748
});
49+
50+
for (const resume_when of ["resume_at:2026-01-01T00:10:00Z", "resume_at:2026-01-01T02:00:00Z",
51+
"pr_merged:example/project#1", "capacity_available:git_push"]) {
52+
test(`${resume_when} keeps its existing route instead of entering Todo-dependency recovery`, () => {
53+
const input = request();
54+
const waiting = {...input.todos[0]!, resume_when};
55+
const projection = evaluateTodoResumeConditions({
56+
schema_version: TODO_RESUME_EVALUATION_REQUEST_SCHEMA_VERSION,
57+
items: [waiting], source_items: [waiting], evaluated_at: input.observed_at,
58+
available_capabilities: [],
59+
});
60+
const condition = (projection.conditions as {condition: Record<string, unknown>}[])[0]!.condition;
61+
assert.equal(condition.satisfied, false);
62+
assert.deepEqual(projectReceiptBoundWait({...input, todos: [
63+
{...waiting, resume_condition: condition, resume_ready: false},
64+
]}), {status: "none"});
65+
});
66+
}

0 commit comments

Comments
 (0)