Skip to content

Commit 181eac2

Browse files
committed
refactor(replan): localize refresh settlement qualification
Signed-off-by: huangruiteng <huangrt01@163.com>
1 parent 7d8cff6 commit 181eac2

3 files changed

Lines changed: 142 additions & 82 deletions

File tree

‎loopx/control_plane/work_items/semantic_replan_writeback.py‎

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import shlex
66
from collections.abc import Mapping
7+
from dataclasses import dataclass
78
from typing import Any
89

910
from ...agent_registry import registered_agent_ids_for_goal
@@ -22,17 +23,36 @@
2223
select_quota_todo_summary,
2324
)
2425
from ..todos.succession_warning import todo_succession_gap_items
26+
from .autonomous_replan_ack import (
27+
latest_monitor_replan_frontier_identity,
28+
watch_lane_continuation_todo_ids,
29+
)
2530
from .autonomous_replan_obligation import (
2631
build_autonomous_replan_cli_actions,
2732
project_todo_lifecycle_settlement_reentry,
2833
)
34+
from .delivery_outcome import ACCOUNTABLE_DELIVERY_OUTCOMES
2935
from .progress_observation import semantic_delta_from_writeback
36+
from .repair_delta import (
37+
build_repair_delta_contract,
38+
repair_delta_kinds_have_accountable_progress,
39+
)
3040
from .work_lane_context import build_work_lane_context_contract
3141

3242

3343
REPLAN_WRITEBACK_REJECTION_SCHEMA_VERSION = "replan_writeback_rejection_v0"
3444

3545

46+
@dataclass(frozen=True)
47+
class RefreshReplanQualification:
48+
repair_delta_contract: dict[str, Any] | None
49+
semantic_delta: dict[str, Any] | None
50+
frontier_identity: str | None
51+
classification: str
52+
delivery_outcome: str | None
53+
autonomous_replan_recorded: bool
54+
55+
3656
class ReplanWritebackRejected(ValueError):
3757
"""A strict writeback rejection with its actionable obligation attached."""
3858

@@ -344,3 +364,102 @@ def enforce_open_replan_writeback(
344364
obligation=obligation,
345365
semantic_delta=semantic_delta,
346366
)
367+
368+
369+
def qualify_refresh_replan_writeback(
370+
*,
371+
autonomous_replan_recorded: bool,
372+
requested_delta_kinds: list[str],
373+
active_state_next_action_update: dict[str, Any] | None,
374+
agent_vision: dict[str, Any] | None,
375+
existing_agent_vision: dict[str, Any] | None,
376+
agent_id: str,
377+
dry_run: bool,
378+
settlement_todo_id: str | None,
379+
settlement_bound: bool,
380+
newest_first_runs: list[dict[str, Any]],
381+
state_text: str,
382+
goal_id: str,
383+
progress_observation: dict[str, Any] | None,
384+
registry_goal: dict[str, Any] | None,
385+
completion_todo_id: str | None,
386+
completion_turn_key: str | None,
387+
classification: str,
388+
delivery_outcome: str | None,
389+
) -> RefreshReplanQualification:
390+
"""Qualify one refresh's replan delta and accountable settlement outcome."""
391+
392+
requested_classification = classification
393+
requested_delivery_outcome = delivery_outcome
394+
repair_delta_contract = None
395+
frontier_identity = None
396+
effective_recorded = bool(autonomous_replan_recorded)
397+
if autonomous_replan_recorded:
398+
repair_delta_contract = build_repair_delta_contract(
399+
requested_delta_kinds=requested_delta_kinds,
400+
active_state_next_action_update=active_state_next_action_update,
401+
agent_vision=agent_vision,
402+
existing_agent_vision=existing_agent_vision,
403+
agent_todo_summary=parse_active_state_todos(
404+
state_text, item_limit=None
405+
).get("agent_todos"),
406+
agent_id=agent_id or None,
407+
dry_run=dry_run,
408+
selected_todo_id=settlement_todo_id,
409+
newest_first_runs=newest_first_runs,
410+
)
411+
validated_delta_kinds = list(repair_delta_contract.get("delta_kinds") or [])
412+
if not repair_delta_contract["delta_present"]:
413+
normalized = str(classification or "").strip().lower()
414+
classification = (
415+
"repair_noop"
416+
if "repair" in normalized and "replan" not in normalized
417+
else "replan_noop"
418+
)
419+
effective_recorded = False
420+
if delivery_outcome in {"outcome_progress", "primary_goal_outcome"}:
421+
delivery_outcome = "outcome_gap"
422+
elif (
423+
delivery_outcome in {"outcome_progress", "primary_goal_outcome"}
424+
and not repair_delta_kinds_have_accountable_progress(
425+
validated_delta_kinds
426+
)
427+
):
428+
delivery_outcome = "outcome_gap"
429+
if effective_recorded and agent_id:
430+
frontier_identity = latest_monitor_replan_frontier_identity(
431+
newest_first_runs,
432+
agent_id=agent_id,
433+
watch_todo_ids=watch_lane_continuation_todo_ids(
434+
repair_delta_contract
435+
),
436+
)
437+
438+
semantic_delta = enforce_open_replan_writeback(
439+
newest_first_runs=newest_first_runs,
440+
state_text=state_text,
441+
agent_id=agent_id,
442+
goal_id=goal_id,
443+
progress_observation=progress_observation,
444+
registry_goal=registry_goal,
445+
agent_vision=agent_vision,
446+
completion_todo_id=completion_todo_id,
447+
completion_turn_key=completion_turn_key,
448+
)
449+
if semantic_delta:
450+
effective_recorded = True
451+
classification = requested_classification
452+
delivery_outcome = requested_delivery_outcome
453+
if settlement_bound and delivery_outcome not in ACCOUNTABLE_DELIVERY_OUTCOMES:
454+
raise ValueError(
455+
"turn-scoped refresh-state produced no accountable semantic delta; "
456+
"no state or settlement receipt was written"
457+
)
458+
return RefreshReplanQualification(
459+
repair_delta_contract=repair_delta_contract,
460+
semantic_delta=semantic_delta,
461+
frontier_identity=frontier_identity,
462+
classification=classification,
463+
delivery_outcome=delivery_outcome,
464+
autonomous_replan_recorded=effective_recorded,
465+
)

‎loopx/state_refresh.py‎

Lines changed: 21 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,13 @@
3131
from .control_plane.work_items.repair_delta import (
3232
REPAIR_DELTA_CONTRACT_SCHEMA_VERSION as REPAIR_DELTA_CONTRACT_SCHEMA_VERSION,
3333
REPAIR_DELTA_KIND_CHOICES as REPAIR_DELTA_KIND_CHOICES,
34-
build_repair_delta_contract,
3534
normalize_repair_delta_kinds,
36-
repair_delta_kinds_have_accountable_progress,
37-
)
38-
from .control_plane.work_items.autonomous_replan_ack import (
39-
latest_monitor_replan_frontier_identity,
40-
watch_lane_continuation_todo_ids,
4135
)
4236
from .control_plane.work_items.progress_observation import (
4337
normalize_progress_observation,
4438
)
4539
from .control_plane.work_items.semantic_replan_writeback import (
46-
enforce_open_replan_writeback,
40+
qualify_refresh_replan_writeback,
4741
)
4842
from .control_plane.runtime.shared_runtime_refresh_projection import (
4943
build_shared_runtime_projection,
@@ -84,7 +78,6 @@
8478
normalize_todo_claimed_by,
8579
normalize_todo_replan_obligation_id,
8680
)
87-
from .control_plane.todos.active_state_todo_parser import parse_active_state_todos
8881
from .control_plane.todos.completion_validation_accountability import (
8982
require_accountable_completion_validation,
9083
)
@@ -232,13 +225,6 @@ def normalize_progress_scope(value: str | None) -> str:
232225
return normalized
233226

234227

235-
def _noop_classification_for(classification: str) -> str:
236-
normalized = str(classification or "").strip().lower()
237-
if "repair" in normalized and "replan" not in normalized:
238-
return "repair_noop"
239-
return "replan_noop"
240-
241-
242228
def next_action_section_bounds(lines: list[str]) -> tuple[int, int] | None:
243229
for index, line in enumerate(lines):
244230
if line.strip() != "## Next Action":
@@ -1148,78 +1134,35 @@ def refresh_state_run(
11481134
else:
11491135
action, recommended_action_source = derive_recommended_action_with_source(state_text)
11501136
validate_local_control_text("recommended_action", action)
1151-
repair_delta_contract: dict[str, Any] | None = None
1152-
validated_repair_delta_kinds: list[str] = []
11531137
requested_classification = classification
1154-
requested_delivery_outcome = normalized_delivery_outcome
1155-
effective_autonomous_replan_recorded = bool(autonomous_replan_recorded)
1156-
if autonomous_replan_recorded:
1157-
repair_delta_contract = build_repair_delta_contract(
1158-
requested_delta_kinds=normalized_repair_delta_kinds,
1159-
active_state_next_action_update=active_state_next_action_update,
1160-
agent_vision=agent_vision,
1161-
existing_agent_vision=existing_agent_vision,
1162-
agent_todo_summary=parse_active_state_todos(
1163-
state_text, item_limit=None
1164-
).get("agent_todos"),
1165-
agent_id=normalized_agent_id or None,
1166-
dry_run=dry_run,
1167-
selected_todo_id=(settlement_identity.todo_id if settlement_identity else None),
1168-
newest_first_runs=newest_first_runs,
1169-
)
1170-
validated_repair_delta_kinds = list(
1171-
repair_delta_contract.get("delta_kinds") or []
1172-
)
1173-
if not repair_delta_contract["delta_present"]:
1174-
classification = _noop_classification_for(classification)
1175-
effective_autonomous_replan_recorded = False
1176-
if normalized_delivery_outcome in {"outcome_progress", "primary_goal_outcome"}:
1177-
normalized_delivery_outcome = "outcome_gap"
1178-
elif (
1179-
normalized_delivery_outcome in {"outcome_progress", "primary_goal_outcome"}
1180-
and not repair_delta_kinds_have_accountable_progress(
1181-
validated_repair_delta_kinds
1182-
)
1183-
):
1184-
normalized_delivery_outcome = "outcome_gap"
1185-
if effective_autonomous_replan_recorded and normalized_agent_id:
1186-
autonomous_replan_frontier_identity = (
1187-
latest_monitor_replan_frontier_identity(
1188-
newest_first_runs,
1189-
agent_id=normalized_agent_id,
1190-
watch_todo_ids=watch_lane_continuation_todo_ids(
1191-
repair_delta_contract
1192-
),
1193-
)
1194-
)
1195-
replan_semantic_delta = enforce_open_replan_writeback(
1138+
replan_qualification = qualify_refresh_replan_writeback(
1139+
autonomous_replan_recorded=autonomous_replan_recorded,
1140+
requested_delta_kinds=normalized_repair_delta_kinds,
1141+
active_state_next_action_update=active_state_next_action_update,
1142+
agent_vision=agent_vision,
1143+
existing_agent_vision=existing_agent_vision,
1144+
agent_id=normalized_agent_id,
1145+
dry_run=dry_run,
1146+
settlement_todo_id=(settlement_identity.todo_id if settlement_identity else None),
1147+
settlement_bound=settlement_identity is not None,
11961148
newest_first_runs=newest_first_runs,
11971149
state_text=state_text,
1198-
agent_id=normalized_agent_id,
11991150
goal_id=safe_goal_id,
12001151
progress_observation=normalized_progress_observation,
12011152
registry_goal=registry_goal,
1202-
agent_vision=agent_vision,
12031153
completion_todo_id=completion_todo_id,
12041154
completion_turn_key=completion_turn_key,
1155+
classification=classification,
1156+
delivery_outcome=normalized_delivery_outcome,
1157+
)
1158+
repair_delta_contract = replan_qualification.repair_delta_contract
1159+
replan_semantic_delta = replan_qualification.semantic_delta
1160+
autonomous_replan_frontier_identity = replan_qualification.frontier_identity
1161+
classification = replan_qualification.classification
1162+
normalized_delivery_outcome = replan_qualification.delivery_outcome
1163+
effective_autonomous_replan_recorded = (
1164+
replan_qualification.autonomous_replan_recorded
12051165
)
1206-
if replan_semantic_delta:
1207-
effective_autonomous_replan_recorded = True
1208-
# The semantic gate is authoritative for an open replan obligation.
1209-
# A repair-delta label may fail to describe the state change while the
1210-
# same writeback still carries a fresh accepted typed observation. In
1211-
# that case this is not a noop: preserve the caller's accountable
1212-
# settlement outcome so the durable run and receipt remain one chain.
1213-
classification = requested_classification
1214-
normalized_delivery_outcome = requested_delivery_outcome
1215-
if (
1216-
settlement_identity is not None
1217-
and normalized_delivery_outcome not in ACCOUNTABLE_DELIVERY_OUTCOMES
1218-
):
1219-
raise ValueError(
1220-
"turn-scoped refresh-state produced no accountable semantic delta; "
1221-
"no state or settlement receipt was written"
1222-
)
12231166
vision_checkpoint = build_vision_checkpoint(
12241167
agent_id=normalized_agent_id or None,
12251168
agent_vision=agent_vision,

‎tests/control_plane/test_refresh_state_replan_gate.py‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,11 @@
1616
from loopx.control_plane.work_items.semantic_replan_writeback import (
1717
ReplanWritebackRejected,
1818
_obligation_was_created_by_current_completion,
19+
enforce_open_replan_writeback,
1920
qualify_replan_writeback,
2021
project_replan_writeback_rejection,
2122
)
22-
from loopx.state_refresh import (
23-
enforce_open_replan_writeback,
24-
refresh_state_run,
25-
)
23+
from loopx.state_refresh import refresh_state_run
2624
from loopx.todos import add_goal_todo
2725

2826
GOAL_ID = "replan-gate-fixture"

0 commit comments

Comments
 (0)