Skip to content

Commit 13b9c89

Browse files
committed
fix(selection): share canonical admission across quota readers
Signed-off-by: song <liusongstep@gmail.com>
1 parent 43173c0 commit 13b9c89

14 files changed

Lines changed: 446 additions & 106 deletions

‎loopx/cli_commands/quota_action_selection.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,13 @@ def _requested_quota_action_selection_preflight(
161161
# which side of the delivery boundary refused it without re-deriving it from
162162
# prose.
163163
agent_must_attempt = agent_channel.get("must_attempt") is True
164-
agent_delivery_allowed = agent_channel.get("delivery_allowed") is not False
164+
delivery = agent_channel.get("delivery_allowed")
165+
agent_delivery_allowed = delivery if isinstance(delivery, bool) else None
165166
selected_todo_id, admitted = current_action_selection_admission(
166167
payload,
167168
requested_todo_id=requested_todo_id,
168169
agent_must_attempt=agent_must_attempt,
169-
agent_delivery_refused=not agent_delivery_allowed,
170+
agent_delivery_allowed=agent_delivery_allowed,
170171
)
171172
if receipt_bound_replan_obligation_id:
172173
if not receipt_identity_upgraded:

‎loopx/control_plane/effect_program.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {assertActionSelectionConsistency} from "./work_items/action_selection_admission.ts";
12
import { EffectRuntimeRequestError } from "./effect_runtime_errors.ts";
23
import { isStringLiteral } from "./runtime_decode.ts";
34
import { decodeInteractionContract } from "./work_items/interaction_contract.ts";
@@ -305,6 +306,7 @@ export function interpretQuotaShouldRunPacket(
305306
): EffectTurn<JsonObject, string> {
306307
const packet = asObject(packetValue);
307308
const interaction = decodeInteractionContract(packet.interaction_contract);
309+
assertActionSelectionConsistency(packet, interaction);
308310
const lane = asObject(packet.work_lane_contract);
309311
const scheduler = asObject(packet.scheduler_hint);
310312
const codexApp = asObject(scheduler.codex_app);

‎loopx/control_plane/effect_runtime_handlers.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ export function createEffectRuntimeHandlers(
337337
["turn.delivery_route.evaluate", lazyHandler(() => import("./turn_driver/delivery_continuity.ts"), ({evaluateDeliveryRoute}) => evaluateDeliveryRoute)],
338338
["work_item.action_portfolio.project", lazyHandler(() => import("./work_items/action_portfolio.ts"), ({projectQuotaActionPortfolio}) => projectQuotaActionPortfolio)],
339339
["work_item.action_selection.qualify", lazyHandler(() => import("./work_items/action_portfolio.ts"), ({qualifyActionSelection}) => qualifyActionSelection)],
340+
["work_item.action_selection.admission.project", lazyHandler(() => import("./work_items/action_selection_admission.ts"), ({projectCurrentActionSelectionAdmission}) => projectCurrentActionSelectionAdmission)],
341+
["work_item.action_selection.recovery.project", lazyHandler(() => import("./work_items/action_selection_admission.ts"), ({projectActionSelectionRecovery}) => projectActionSelectionRecovery)],
340342
[
341343
"work_item.action_selection.reconcile_retained",
342344
lazyHandler(() => import("./work_items/action_portfolio.ts"), ({reconcileRetainedActionSelection}) => reconcileRetainedActionSelection),

‎loopx/control_plane/quota/scoped_override.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import type { JsonObject } from "../effect_program.ts";
22
import { requireJsonObject, requireNonEmptyString } from "../runtime_decode.ts";
33
import { decodeInteractionContract } from "../work_items/interaction_contract.ts";
4+
import {assertActionSelectionConsistency} from "../work_items/action_selection_admission.ts";
45

56
/** Project diagnostics after selection, guards, settlement and notification overlays.
67
* Gate admission metadata is historical context; it cannot select another Todo.
78
*/
89
export function projectScopedOverride(params: JsonObject): JsonObject {
910
const override = { ...requireJsonObject(params.override, "override") };
1011
const interaction = decodeInteractionContract(params.interaction_contract);
12+
if (params.selection_context !== undefined) {
13+
assertActionSelectionConsistency(requireJsonObject(params.selection_context, "selection_context"), interaction);
14+
}
1115
delete override.selected_action;
1216
if (interaction.agent_channel.delivery_allowed && params.selected_todo != null) {
1317
const selected = requireJsonObject(params.selected_todo, "selected_todo");

‎loopx/control_plane/quota/should_run_packet.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
)
113113
from ..work_items.execution_obligation import build_execution_obligation
114114
from ..work_items.action_selection_contract import (
115+
action_selection_context,
115116
apply_action_selection_recovery_projection,
116117
)
117118
from ..work_items.goal_route_hint import build_goal_route_hint
@@ -1643,6 +1644,7 @@ def _build_quota_should_run_payload(
16431644
"override": payload[kind],
16441645
"selected_todo": payload.get("selected_todo"),
16451646
"interaction_contract": payload["interaction_contract"],
1647+
"selection_context": action_selection_context(payload),
16461648
})
16471649
return payload
16481650

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/** Canonical grammar only: existing callers retain normalization and error policy. */
2+
export function isCanonicalTodoId(value: string): boolean {
3+
return /^todo_[a-z0-9_-]{3,64}$/u.test(value);
4+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/** Final selected-work admission, shared by CLI recovery and packet readers.
2+
* Receipt labels are reconciliation facts, never proof of current lease authority. */
3+
import type {JsonObject} from "../effect_program.ts";
4+
import {EffectRuntimeRequestError} from "../effect_runtime_errors.ts";
5+
import {jsonObject, requireBoolean, requireJsonObject} from "../runtime_decode.ts";
6+
import {EffectiveAction} from "../quota/effective_action.generated.ts";
7+
import {isCanonicalTodoId} from "../todos/identity.ts";
8+
9+
interface AgentAdmissionFacts {must_attempt: boolean; delivery_allowed: boolean | null}
10+
interface SelectionAdmission {selected_todo_id: string | null; admitted: boolean}
11+
12+
function selectionTodoId(value: unknown): string | null {
13+
if (typeof value !== "string") return null;
14+
// Preserve the Python selection reader's strip, not JS trim's BOM policy.
15+
const whitespace = /[\p{White_Space}\u001c-\u001f]/u;
16+
let start = 0, end = value.length;
17+
while (start < end && whitespace.test(value[start]!)) start++;
18+
while (end > start && whitespace.test(value[end - 1]!)) end--;
19+
const candidate = value.slice(start, end).toLowerCase();
20+
return isCanonicalTodoId(candidate) ? candidate : null;
21+
}
22+
23+
export function currentActionSelectionAdmission(
24+
packet: JsonObject, requestedTodoId: string, agent: AgentAdmissionFacts,
25+
): SelectionAdmission {
26+
const selected = jsonObject(packet.selected_todo) ?? {};
27+
const qualification = jsonObject(packet.action_selection_qualification) ?? {};
28+
let selectedId = selectionTodoId(selected.todo_id);
29+
if (selectedId === null && qualification.state === "qualified") {
30+
selectedId = selectionTodoId(jsonObject(qualification.selected_todo)?.todo_id);
31+
}
32+
const pending = selected.selection_binding === "pending_action_selection";
33+
const delivery = pending && packet.normal_delivery_allowed === true
34+
&& agent.must_attempt && agent.delivery_allowed === true;
35+
const workspaceRepair = pending && packet.workspace_repair_allowed === true
36+
&& packet.effective_action === EffectiveAction.AGENT_WORKSPACE_REPAIR
37+
&& agent.must_attempt && agent.delivery_allowed === false;
38+
const currentWork = !pending && agent.must_attempt;
39+
return {selected_todo_id: selectedId,
40+
admitted: selectedId !== null && selectedId === requestedTodoId
41+
&& packet.ok === true && packet.should_run === true && (delivery || workspaceRepair || currentWork)};
42+
}
43+
44+
export function actionSelectionNeedsRecovery(packet: JsonObject, agent: AgentAdmissionFacts): boolean {
45+
const qualification = jsonObject(packet.action_selection_qualification);
46+
if (qualification === null) return false;
47+
if (qualification.state !== null && typeof qualification.state === "object") {
48+
throw new EffectRuntimeRequestError("action selection qualification state must be scalar");
49+
}
50+
if (qualification.state !== "deferred" && qualification.state !== "rejected") return false;
51+
const selected = jsonObject(packet.selected_todo), replan = jsonObject(packet.autonomous_replan_obligation);
52+
if (selected?.selection_binding === "heartbeat_receipt" || replan?.selection_binding === "heartbeat_receipt") return false;
53+
const requested = typeof qualification.requested_todo_id === "string" ? qualification.requested_todo_id : "";
54+
if (currentActionSelectionAdmission(packet, requested, agent).admitted) return false;
55+
if (qualification.recovery_action !== "reenter_guard_without_selection") {
56+
throw new EffectRuntimeRequestError("rejected action selection omitted its typed recovery action");
57+
}
58+
return true;
59+
}
60+
61+
function admissionRequest(request: JsonObject) {
62+
return {packet: requireJsonObject(request.packet, "selection admission packet"), agent: {
63+
must_attempt: requireBoolean(request.agent_must_attempt, "agent_must_attempt"),
64+
delivery_allowed: request.agent_delivery_allowed === null ? null
65+
: requireBoolean(request.agent_delivery_allowed, "agent_delivery_allowed"),
66+
}};
67+
}
68+
69+
export function projectCurrentActionSelectionAdmission(request: JsonObject): JsonObject {
70+
const {packet, agent} = admissionRequest(request);
71+
if (typeof request.requested_todo_id !== "string") throw new EffectRuntimeRequestError("requested_todo_id must be a string");
72+
return {...currentActionSelectionAdmission(packet, request.requested_todo_id, agent)};
73+
}
74+
75+
export function projectActionSelectionRecovery(request: JsonObject): JsonObject {
76+
const {packet, agent} = admissionRequest(request);
77+
return {required: actionSelectionNeedsRecovery(packet, agent)};
78+
}
79+
80+
const ROOT_EXECUTION_FLAGS = ["should_run", "normal_delivery_allowed", "recovery_delivery_allowed",
81+
"self_repair_allowed", "capability_repair_allowed", "workspace_repair_allowed", "safe_bypass_allowed",
82+
"actionable_by_codex", "spend_allowed_now", "spend_after_validation"] as const;
83+
84+
/** Reject stale grants without inspecting command prose or consuming receipts. */
85+
export function assertActionSelectionConsistency(packet: JsonObject, interaction: JsonObject): void {
86+
const agent = jsonObject(interaction.agent_channel) ?? {}, cli = jsonObject(interaction.cli_channel) ?? {};
87+
if (!actionSelectionNeedsRecovery(packet, {
88+
must_attempt: agent.must_attempt === true,
89+
delivery_allowed: typeof agent.delivery_allowed === "boolean" ? agent.delivery_allowed : null,
90+
})) return;
91+
const granted = (value: unknown) => value !== undefined && value !== null && value !== false;
92+
if (ROOT_EXECUTION_FLAGS.some(field => granted(packet[field]))
93+
|| granted(agent.must_attempt) || granted(agent.delivery_allowed)
94+
|| granted(cli.spend_allowed_now) || granted(cli.spend_after_validation) || granted(cli.selection_required)
95+
|| ["settlement_plan", "replan_settlement_contract", "selection_command", "selection_policy_ref"]
96+
.some(field => cli[field] !== undefined && cli[field] !== null)) {
97+
throw new EffectRuntimeRequestError("unadmitted action selection cannot carry execution or settlement authority");
98+
}
99+
}

‎loopx/control_plane/work_items/action_selection_contract.py‎

Lines changed: 53 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -157,102 +157,68 @@ def delivery_spend_allowed(
157157
)
158158

159159

160+
def action_selection_context(payload: Mapping[str, Any]) -> dict[str, Any]:
161+
"""Transport bounded current facts; TypeScript owns every admission decision."""
162+
fields = ("ok", "should_run", "effective_action", "normal_delivery_allowed", "recovery_delivery_allowed",
163+
"self_repair_allowed", "capability_repair_allowed", "workspace_repair_allowed", "safe_bypass_allowed",
164+
"actionable_by_codex", "spend_allowed_now", "spend_after_validation")
165+
result = {key: payload[key] for key in fields if key in payload}
166+
for field, keys in (
167+
("selected_todo", ("todo_id", "selection_binding")),
168+
("autonomous_replan_obligation", ("selection_binding",)),
169+
("action_selection_qualification", ("state", "requested_todo_id", "recovery_action")),
170+
):
171+
raw = payload.get(field)
172+
if isinstance(raw, Mapping):
173+
result[field] = {key: raw[key] for key in keys if key in raw}
174+
if field == "selected_todo":
175+
result[field]["todo_id"] = normalize_todo_id(raw.get("todo_id"))
176+
if field == "action_selection_qualification" and isinstance(raw.get("selected_todo"), Mapping):
177+
result[field]["selected_todo"] = {"todo_id": normalize_todo_id(raw["selected_todo"].get("todo_id"))}
178+
return result
179+
180+
181+
def _selection_projection(method: str, payload: Mapping[str, Any], *,
182+
agent_must_attempt: bool, agent_delivery_allowed: bool | None,
183+
requested_todo_id: str | None = None) -> dict[str, Any]:
184+
from ..effect_runtime import effect_runtime_result
185+
186+
request = {"packet": action_selection_context(payload), "agent_must_attempt": agent_must_attempt,
187+
"agent_delivery_allowed": agent_delivery_allowed}
188+
if requested_todo_id is not None:
189+
request["requested_todo_id"] = requested_todo_id
190+
result = effect_runtime_result(method, request)
191+
if not isinstance(result, dict):
192+
raise TypeError("typed action selection returned an invalid projection")
193+
return result
194+
195+
160196
def current_action_selection_admission(
161197
payload: Mapping[str, Any], *, requested_todo_id: str,
162-
agent_must_attempt: bool, agent_delivery_refused: bool,
198+
agent_must_attempt: bool, agent_delivery_allowed: bool | None,
163199
) -> tuple[str | None, bool]:
164-
"""Read current obligation admission, including repair and monitor positives."""
165-
selected_todo = payload.get("selected_todo")
166-
selected_todo_id = (
167-
normalize_todo_id(selected_todo.get("todo_id"))
168-
if isinstance(selected_todo, Mapping)
169-
else None
170-
)
171-
qualification_value = payload.get("action_selection_qualification")
172-
qualification: Mapping[str, object] = (
173-
qualification_value if isinstance(qualification_value, Mapping) else {}
174-
)
175-
if selected_todo_id is None and str(qualification.get("state") or "") == (
176-
"qualified"
177-
):
178-
# An unsettled-host-turn recovery decision carries no top-level
179-
# `selected_todo`: its qualification names the Todo that prior Turn
180-
# has to settle, and binding the guard to that Todo is the documented
181-
# closeout path rather than a conflict with the projection.
182-
qualification_selected = qualification.get("selected_todo")
183-
selected_todo_id = (
184-
normalize_todo_id(qualification_selected.get("todo_id"))
185-
if isinstance(qualification_selected, Mapping)
186-
else None
187-
)
188-
selection_binding = (
189-
selected_todo.get("selection_binding")
190-
if isinstance(selected_todo, Mapping)
191-
else None
192-
)
193-
execution_obligation_value = payload.get("execution_obligation")
194-
execution_obligation: Mapping[str, object] = (
195-
execution_obligation_value
196-
if isinstance(execution_obligation_value, Mapping)
197-
else {}
198-
)
199-
pending_selection_delivery_qualified = (
200-
selection_binding == "pending_action_selection"
201-
and payload.get("normal_delivery_allowed") is True
202-
)
203-
pending_selection_workspace_repair_qualified = (
204-
selection_binding == "pending_action_selection"
205-
and payload.get("workspace_repair_allowed") is True
206-
and payload.get("effective_action") == EffectiveAction.AGENT_WORKSPACE_REPAIR.value
207-
and execution_obligation.get("kind") == "agent_workspace_repair"
208-
and execution_obligation.get("must_attempt_work") is True
209-
and agent_must_attempt
210-
and agent_delivery_refused
211-
)
212-
exact_current_obligation_qualified = (
213-
selection_binding != "pending_action_selection"
214-
and execution_obligation.get("must_attempt_work") is True
215-
and agent_must_attempt
216-
)
217-
if (
218-
selected_todo_id == requested_todo_id
219-
and payload.get("ok") is True
220-
and payload.get("should_run") is True
221-
and (
222-
pending_selection_delivery_qualified
223-
or pending_selection_workspace_repair_qualified
224-
or exact_current_obligation_qualified
225-
)
226-
):
227-
return selected_todo_id, True
228-
229-
return selected_todo_id, False
200+
result = _selection_projection("work_item.action_selection.admission.project", payload,
201+
requested_todo_id=requested_todo_id, agent_must_attempt=agent_must_attempt,
202+
agent_delivery_allowed=agent_delivery_allowed)
203+
selected, admitted = result.get("selected_todo_id"), result.get("admitted")
204+
if (selected is not None and not isinstance(selected, str)) or type(admitted) is not bool:
205+
raise TypeError("typed action selection returned invalid admission facts")
206+
return selected, admitted
230207

231208

232209
def action_selection_needs_recovery(
233210
payload: Mapping[str, Any], *, agent_must_attempt: bool = False,
234-
agent_delivery_refused: bool = False,
211+
agent_delivery_allowed: bool | None = None,
235212
) -> bool:
236-
"""Read the typed qualifier's result without reimplementing admission."""
237-
qualification = payload.get("action_selection_qualification")
238-
if not isinstance(qualification, Mapping) or qualification.get("state") not in {"deferred", "rejected"}:
213+
# No selected-request input means there is no recovery projection to read.
214+
if not isinstance(payload.get("action_selection_qualification"), Mapping):
239215
return False
240-
# A committed binding is reconciled by the receipt owner, not by pending
241-
# selection recovery. Preserve the same exemption as CLI preflight.
242-
selected = payload.get("selected_todo")
243-
replan = payload.get("autonomous_replan_obligation")
244-
if any(isinstance(value, Mapping) and value.get("selection_binding") == "heartbeat_receipt"
245-
for value in (selected, replan)):
246-
return False
247-
_, admitted = current_action_selection_admission(
248-
payload, requested_todo_id=str(qualification.get("requested_todo_id") or ""),
249-
agent_must_attempt=agent_must_attempt, agent_delivery_refused=agent_delivery_refused,
250-
)
251-
if admitted:
252-
return False
253-
if qualification.get("recovery_action") != "reenter_guard_without_selection":
254-
raise RuntimeError("rejected action selection omitted its typed recovery action")
255-
return True
216+
result = _selection_projection("work_item.action_selection.recovery.project", payload,
217+
agent_must_attempt=agent_must_attempt, agent_delivery_allowed=agent_delivery_allowed)
218+
required = result.get("required")
219+
if type(required) is not bool:
220+
raise TypeError("typed action selection returned an invalid recovery decision")
221+
return required
256222

257223

258224
def action_selection_recovery_fields(

0 commit comments

Comments
 (0)