Skip to content

Commit 7177554

Browse files
authored
Merge pull request #6331 from loopx-project/codex/monitor-target-replay-20261013
2 parents db5a298 + 7d2604b commit 7177554

4 files changed

Lines changed: 530 additions & 16 deletions

File tree

‎docs/reference/protocols/quota-monitor-observation-receipt-v0.md‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ advancement work remains active.
4848
replay that observation; changed content conflicts only with the same monitor
4949
identity; another due monitor receives an independent no-spend receipt.
5050
Shipped turn-only receipts remain replayable for their original monitor.
51+
- A target-only, turn-scoped executed retry retains the resolved Todo identity of an existing
52+
poll transaction when that same active Monitor is no longer due. Current
53+
target selection and the existing receipt path locate the operation; only the
54+
typed transaction owner may verify its scope, fingerprint and frozen admission.
55+
The transport rechecks that Todo-scoped operation's presence under the same
56+
quota admission as the native receipt read. A prior no-effect abort cannot turn
57+
this recovery route into a new poll. Committed replay and provider-committed
58+
pending recovery grant no admission to a new not-due observation. Caller target, hash, intent and lease proof
59+
remain unchanged. Explicit Todo retries and historical target-only wire shapes
60+
retain their existing paths; current replacement selection is not evidence of
61+
an archived Monitor's original identity.
5162
- A receipt-bound monitor remains strict: another monitor cannot be substituted
5263
for the Turn's settlement Todo. Multiple auxiliary receipts never change the
5364
already-bound settlement identity.
@@ -319,6 +330,14 @@ using a complete read-only snapshot with disposable File/SQLite/PostgreSQL arms.
319330
`target_key` 摘要建立身份。精确重试只重放该观察;同一 monitor 下内容变化
320331
只与该 monitor 冲突;另一个到期 monitor 获得独立的不计费回执。已发布的
321332
Turn-only 旧回执仍可对原 monitor 重放。
333+
- 仅用 target 的 turn-scoped 执行重试,在同一个 active Monitor 已不再到期时保留已有 poll
334+
事务解析出的 Todo 身份。当前 target 选择和既有回执路径只定位原操作;作用域、
335+
指纹与冻结准入仍由 typed 事务 owner 校验。transport 在 native 回执读取的同一
336+
quota admission 内重查 Todo-scoped 操作仍存在;之前的 no-effect abort 不能把
337+
恢复路由转成新 poll。重放已提交操作或恢复 provider 已提交的 pending 操作,
338+
不提供新的未到期观察准入。调用者的 target、hash、intent
339+
和租约证明保持原样。显式 Todo 重试及历史 target-only wire 保留原路径;当前
340+
replacement 选择不能证明已归档 Monitor 的原身份。
322341
- 若 heartbeat 本身绑定的是 monitor,仍保持严格身份,不能把另一个 monitor
323342
替换为本 Turn 的结算 Todo;多个辅助回执也绝不改变既有结算身份。
324343
- 辅助观察无变化后,原 advancement Todo 继续保持选中;若观察发生重大变化,

‎loopx/control_plane/quota/monitor_poll.py‎

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,44 @@ def resolve_due_monitor_candidate(
142142
}
143143

144144

145+
def _monitor_poll_receipt_path(runtime_root: Path, goal_id: str, effect_id: str) -> Path:
146+
return (runtime_root / "goals" / goal_id / "runs" / ".transactions" /
147+
"quota-monitor-poll" / f"{hashlib.sha256(effect_id.encode()).hexdigest()[:24]}.json")
148+
149+
150+
def resolve_monitor_poll_target(
151+
*, registry_path: Path | None, runtime_root: Path | None, goal_id: str,
152+
target_key: str | None, before: dict[str, Any], turn_instance_id: str | None,
153+
execute: bool, goal_ref: Mapping[str, Any] | None,
154+
) -> tuple[str | None, str | None]:
155+
due = resolve_due_monitor_candidate(registry_path=registry_path, runtime_root=runtime_root,
156+
goal_id=goal_id, todo_id=None, target_key=target_key)
157+
if due:
158+
return normalize_todo_id(due["todo_id"]), None
159+
if not execute or runtime_root is None or not turn_instance_id or not target_key or registry_path is None:
160+
return None, None
161+
try:
162+
item = resolve_monitor_todo_item(registry_path=registry_path, runtime_root=runtime_root,
163+
goal_id=goal_id, target_key=target_key)
164+
except ValueError:
165+
return None, None
166+
todo_id = normalize_todo_id(item.get("todo_id"))
167+
effect_id = _monitor_poll_effect_id(runtime_root=runtime_root, goal_id=goal_id,
168+
agent_id=quota_decision_agent_id(before), turn_instance_id=normalize_turn_instance_id(turn_instance_id),
169+
todo_id=todo_id, target_key=target_key, goal_ref=goal_ref)
170+
expected_effect = f"quota-monitor-poll:{goal_id}:{quota_decision_agent_id(before)}:{normalize_turn_instance_id(turn_instance_id)}:todo:{todo_id}"
171+
if effect_id != expected_effect:
172+
# Historical target/turn-only effects can have a null Todo on the wire.
173+
# The provider's resolved Todo cannot rewrite their frozen fingerprint.
174+
return None, None
175+
# Existence is only a transport route to the original operation. TypeScript
176+
# validates scope, fingerprint and frozen admission before replay/recovery.
177+
# Without that operation, retain current due admission and the original wire.
178+
if _monitor_poll_receipt_path(runtime_root, goal_id, effect_id).exists():
179+
return todo_id, effect_id
180+
return None, None
181+
182+
145183
def _decision_packet(
146184
before: dict[str, Any],
147185
*,
@@ -739,6 +777,7 @@ def record_quota_monitor_poll_for_decision(
739777
_index_lock_held: bool = False,
740778
status_reloader: Callable[[], dict[str, Any]] | None = None,
741779
goal_ref: Mapping[str, Any] | None = None,
780+
recovery_effect_id: str | None = None,
742781
) -> dict[str, Any]:
743782
del render_markdown
744783
normalized_turn_id = normalize_turn_instance_id(turn_instance_id)
@@ -855,6 +894,14 @@ def failure(
855894
def transact(
856895
source_admission: Mapping[str, Any] | None,
857896
) -> tuple[dict[str, Any], dict[str, Any]]:
897+
# Recheck the transport precondition inside the same quota admission as
898+
# the native receipt read. A legal no-effect abort may have removed it
899+
# since target selection; that must never turn recovery into a new poll.
900+
if recovery_effect_id is not None and (
901+
effect_id != recovery_effect_id or
902+
not _monitor_poll_receipt_path(runtime_root, goal_id, effect_id).exists()
903+
):
904+
raise ValueError("original Monitor poll transaction is unavailable; reconcile its original operation before retrying")
858905
common = {
859906
"effect_id": effect_id,
860907
"runtime_root": runtime_root,
@@ -876,8 +923,7 @@ def transact(
876923

877924
# Validate explicit claim routing before quota reserves a pending effect.
878925
# Exact retries keep their frozen admission if registry membership changed.
879-
receipt_path = (runtime_root / "goals" / goal_id / "runs" / ".transactions" /
880-
"quota-monitor-poll" / f"{hashlib.sha256(effect_id.encode()).hexdigest()[:24]}.json")
926+
receipt_path = _monitor_poll_receipt_path(runtime_root, goal_id, effect_id)
881927
if next_claimed_by and registry_path is not None and not receipt_path.exists():
882928
plan_todo_authoring_scope(
883929
command="create", role="agent", goal_id=goal_id,

‎loopx/quota.py‎

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
QUOTA_MONITOR_POLL_CLASSIFICATION as QUOTA_MONITOR_POLL_CLASSIFICATION,
3939
build_quota_monitor_poll_event as build_quota_monitor_poll_event,
4040
record_quota_monitor_poll_for_decision,
41-
resolve_due_monitor_candidate,
41+
resolve_monitor_poll_target,
4242
)
4343
from .control_plane.quota.blocked_retry import overlay_active_turn_retries
4444
from .control_plane.quota.recent_runs import (
@@ -1177,19 +1177,6 @@ def record_quota_monitor_poll(
11771177
runtime_root = (
11781178
Path(str(raw_runtime_root)).expanduser() if raw_runtime_root else None
11791179
)
1180-
resolved_monitor = resolve_due_monitor_candidate(
1181-
registry_path=registry_path,
1182-
runtime_root=runtime_root,
1183-
goal_id=safe_goal_id,
1184-
todo_id=normalized_requested_todo_id,
1185-
target_key=target_key,
1186-
)
1187-
normalized_observation_todo_id = normalized_requested_todo_id or (
1188-
normalize_todo_id(resolved_monitor.get("todo_id"))
1189-
if resolved_monitor
1190-
else None
1191-
)
1192-
11931180
def should_run(current_status: dict[str, Any]) -> dict[str, Any]:
11941181
decision_status = current_status
11951182
if bounded_research_frontier_projector is not None:
@@ -1225,6 +1212,14 @@ def should_run(current_status: dict[str, Any]) -> dict[str, Any]:
12251212
)
12261213

12271214
before = should_run(status_payload)
1215+
recovery_effect_id = None
1216+
normalized_observation_todo_id = normalized_requested_todo_id
1217+
if normalized_observation_todo_id is None:
1218+
normalized_observation_todo_id, recovery_effect_id = resolve_monitor_poll_target(
1219+
registry_path=registry_path, runtime_root=runtime_root, goal_id=safe_goal_id,
1220+
target_key=target_key, before=before, turn_instance_id=turn_instance_id,
1221+
execute=execute, goal_ref=goal_ref,
1222+
)
12281223
auxiliary_settlement_todo = None
12291224
if (
12301225
normalized_receipt_todo_id
@@ -1282,6 +1277,7 @@ def should_run(current_status: dict[str, Any]) -> dict[str, Any]:
12821277
turn_instance_id=turn_instance_id,
12831278
status_reloader=status_reloader,
12841279
goal_ref=goal_ref,
1280+
recovery_effect_id=recovery_effect_id,
12851281
)
12861282
continuation = result.get("turn_continuation") or {}
12871283
if (

0 commit comments

Comments
 (0)