From fc8121294505c542427eefb7543c7c4e54e2526f Mon Sep 17 00:00:00 2001 From: hhyykk <4408344+hhyykk@users.noreply.github.com> Date: Mon, 2 Nov 2026 15:55:08 +0800 Subject: [PATCH] refactor(control-plane): remove unused legacy Todo, write-preview and trace helpers Delete Python helpers that no production code, test or example calls: - todos/update_source.py (todo_update_snapshot) - mutation_response.serialize_todo_update_result - completion_validation.prepare_user_todo_update_completion and locked_todo_completion_source - active_state_editing.set_todo_text - local_state_write_correctness.shadow_validate_local_state_write_correctness_packet and its private lease helper - worker_bridge trace file loader and counter reducer - primary_action.protocol_monitor_action Correct the migration RFC and the primary-action ledger entry (EN and zh-CN) that still described the removed helpers as retained. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> Signed-off-by: hhyykk <4408344+hhyykk@users.noreply.github.com> --- ...27-primary-action-instruction-selection.md | 3 + ...mary-action-instruction-selection.zh-CN.md | 3 + .../typescript-control-plane-migration-v0.md | 5 +- ...script-control-plane-migration-v0.zh-CN.md | 5 +- .../runtime/local_state_write_correctness.py | 73 ----------- .../todos/active_state_editing.py | 31 ----- .../todos/completion_validation.py | 57 --------- .../control_plane/todos/mutation_response.py | 115 ------------------ loopx/control_plane/todos/update_source.py | 43 ------- .../work_items/primary_action.py | 26 ---- loopx/worker_bridge.py | 57 --------- 11 files changed, 12 insertions(+), 406 deletions(-) delete mode 100644 loopx/control_plane/todos/update_source.py diff --git a/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.md b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.md index 32776904e6..e6f1b9d49d 100644 --- a/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.md +++ b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.md @@ -51,6 +51,9 @@ scalar/label codecs and facts carrier only after the last Python text/label consumer exits and a complete typed compatibility codec proves Python coercion, Unicode, truncation and trace parity. This slice does not retire those owners. +Correction (2026-11-02): `protocol_monitor_action` had no remaining caller +and is removed. The resolution trace remains live. + ## Vocabulary budget The registry's `meaning` says "module_budget counts modules under loopx/ whose text carries the standalone field token" and "the token count stays until Q11 decides whether the syntactic metric replaces it"; this deliberately conservative lexical proxy protects against unexplained growth in potential field readers. diff --git a/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.zh-CN.md b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.zh-CN.md index e2453db3d6..de960dddba 100644 --- a/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.zh-CN.md +++ b/docs/architecture/rfcs/ledger/typescript-control-plane-migration-v0/2026-10-27-primary-action-instruction-selection.zh-CN.md @@ -43,6 +43,9 @@ facade。仅当最后一个 Python text/label 消费者退出,且完整 typed Python coercion、Unicode、截断及 trace 等价时,才删除 scalar/label codec 和 facts carrier。本切片不宣称这些 owner 已退役。 +更正(2026-11-02):`protocol_monitor_action` 已无剩余调用方,现已删除。 +resolution trace 仍在使用。 + ## 词汇预算 registry 的 `meaning` 写明 "module_budget counts modules under loopx/ whose text carries the standalone field token" 和 "the token count stays until Q11 decides whether the syntactic metric replaces it";这一刻意保守的词法代理用于防止潜在字段 reader 数量出现无解释增长。 diff --git a/docs/architecture/rfcs/typescript-control-plane-migration-v0.md b/docs/architecture/rfcs/typescript-control-plane-migration-v0.md index 11916426e9..5c5bb44d64 100644 --- a/docs/architecture/rfcs/typescript-control-plane-migration-v0.md +++ b/docs/architecture/rfcs/typescript-control-plane-migration-v0.md @@ -1118,8 +1118,9 @@ closure, not completion of all Todo fields or Goal promotion. Bounded prerequisite: `todos/public_update.ts` now composes authoring scope, external-wait topology and Monitor/field planning over one locked source. The public Python writer no longer sequences their leaf RPCs or derives the -Monitor wait baseline. `update_source.py` supplies complete compact active/archive -facts, never a display-limited inventory. A partial topology edit validates its +Monitor wait baseline. Correction (2026-11-02): `update_source.py` had no +remaining caller and is removed; planning still requires complete compact +active/archive facts, never a display-limited inventory. A partial topology edit validates its retained wait; copy-only edits preserve the original fence without re-arming it. Explicitly clearing the condition still permits changing its former topology. Locked completion proof is checked before this pure plan, so a stale proof wins diff --git a/docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md b/docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md index 7fbae148e1..05f6c11210 100644 --- a/docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md +++ b/docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md @@ -844,8 +844,9 @@ promotion 的 Goal 继续使用旧 writer。这是有边界的 T1 闭合,不 已闭合的前置项:`todos/public_update.ts` 在同一锁内快照上组合 authoring scope、 external-wait 拓扑和 Monitor/field 规划。公开 Python writer 不再逐个调用这些 -leaf RPC,也不推导 Monitor 等待基线。`update_source.py` 只输送完整、紧凑的 -active/archive 事实,不使用受展示条数限制的 inventory。局部拓扑修改必须验证 +leaf RPC,也不推导 Monitor 等待基线。更正(2026-11-02):`update_source.py` +已无剩余调用方,现已删除;规划仍要求完整、紧凑的 active/archive 事实, +不使用受展示条数限制的 inventory。局部拓扑修改必须验证 保留的等待条件;纯文案修改保留原 fence,不重新设置等待。显式清除条件后,仍可 修改原来的拓扑。锁内 completion proof 先于纯规划检查,因此 proof 已过期时, 优先返回该失败而非其他非法字段诊断;两种失败均不写入。 diff --git a/loopx/control_plane/runtime/local_state_write_correctness.py b/loopx/control_plane/runtime/local_state_write_correctness.py index 4fd72cd17f..dfa2f91213 100644 --- a/loopx/control_plane/runtime/local_state_write_correctness.py +++ b/loopx/control_plane/runtime/local_state_write_correctness.py @@ -100,79 +100,6 @@ def build_local_state_write_correctness_dry_run_packet( } -def shadow_validate_local_state_write_correctness_packet( - packet: dict[str, Any], - *, - current_state_text: str, - observed_lease_ref: dict[str, Any] | None = None, -) -> dict[str, Any]: - """Preview revision and lease conflicts without changing write behavior.""" - - validated = json.loads(json.dumps(packet, ensure_ascii=False)) - intent = validated.get("write_intent") if isinstance(validated, dict) else {} - if not isinstance(intent, dict): - return validated - apply_result = validated.setdefault("apply_result", {}) - if not isinstance(apply_result, dict): - apply_result = {} - validated["apply_result"] = apply_result - apply_result.setdefault("status", "preview_only") - apply_result.setdefault("applied_revision", None) - apply_result.setdefault("duplicate_of", None) - apply_result.setdefault("conflict", None) - - expected_revision = intent.get("expected_revision") - current_revision = active_state_revision(current_state_text) - if ( - isinstance(expected_revision, dict) - and expected_revision.get("value") - and expected_revision.get("value") != current_revision["value"] - ): - apply_result.update( - { - "status": "revision_conflict", - "applied_revision": None, - "duplicate_of": None, - "conflict": { - "kind": "revision_conflict", - "expected_revision": expected_revision, - "current_revision": current_revision, - }, - } - ) - return validated - - expected_lease_ref = intent.get("lease_ref") - if _lease_refs_conflict(expected_lease_ref, observed_lease_ref): - apply_result.update( - { - "status": "lease_conflict", - "applied_revision": None, - "duplicate_of": None, - "conflict": { - "kind": "lease_conflict", - "expected_lease_ref": expected_lease_ref, - "observed_lease_ref": observed_lease_ref, - }, - } - ) - return validated - - -def _lease_refs_conflict(expected: Any, observed: Any) -> bool: - if not isinstance(expected, dict) or not isinstance(observed, dict): - return False - if str(expected.get("kind") or "") != str(observed.get("kind") or ""): - return False - if str(expected.get("goal_id") or "") != str(observed.get("goal_id") or ""): - return False - if str(expected.get("todo_id") or "") != str(observed.get("todo_id") or ""): - return False - expected_holder = str(expected.get("claimed_by") or "") - observed_holder = str(observed.get("claimed_by") or "") - return bool(expected_holder and observed_holder and expected_holder != observed_holder) - - def _todo_lease_ref( *, goal_id: str, diff --git a/loopx/control_plane/todos/active_state_editing.py b/loopx/control_plane/todos/active_state_editing.py index b24c27b3e9..4d943ee363 100644 --- a/loopx/control_plane/todos/active_state_editing.py +++ b/loopx/control_plane/todos/active_state_editing.py @@ -12,8 +12,6 @@ todo_done_for_status, todo_marker_for_status, ) -from .text import normalize_new_todo -from .todo_summary import normalize_todo_text from .machine_region import find_todo_source_regions, visible_markdown_lines from .todo_block_codec import decode_todo_blocks @@ -86,35 +84,6 @@ def set_todo_marker(lines: list[str], block: dict[str, Any], status: str) -> boo return True -def set_todo_text( - lines: list[str], - block: dict[str, Any], - text: str, - *, - status: str, -) -> bool: - normalized = normalize_new_todo(text) - if normalize_todo_text(str(block.get("text") or "")) == normalized: - return False - - start = int(block["start"]) - end = int(block["end"]) - marker = todo_marker_for_status(status) - replacement = f"- [{marker}] {normalized}" - continuation_indexes = [ - index - for index in range(start + 1, end) - if lines[index].startswith((" ", "\t")) - and parse_todo_metadata_line(lines[index]) is None - ] - lines[start] = replacement - for index in reversed(continuation_indexes): - del lines[index] - block["text"] = normalized - block["end"] = end - len(continuation_indexes) - return True - - def heading_index(lines: list[str], heading: str) -> int | None: needle = f"## {heading}" for index in sorted(visible_markdown_lines(lines)): diff --git a/loopx/control_plane/todos/completion_validation.py b/loopx/control_plane/todos/completion_validation.py index 1284b96972..085ce563ab 100644 --- a/loopx/control_plane/todos/completion_validation.py +++ b/loopx/control_plane/todos/completion_validation.py @@ -34,7 +34,6 @@ persist_completion_validation_declaration, read_completion_validation_declaration, ) -from .contract import TODO_STATUS_DONE, normalize_todo_status from ..content_digest import BARE_SHA256_PATTERN # Kept safely under the 30s outer CLI/MCP subprocess budget so a timed-out @@ -639,62 +638,6 @@ def completion_policy_source_from_state( ) -def prepare_user_todo_update_completion( - *, - status: str | None, - state_file: Path, - todo_id: str, - role: str | None, - registry_path: Path, - goal_id: str, - dry_run: bool, - no_followup: bool, - requested_has_successor: bool, -) -> dict[str, Any] | None: - """Prepare the coarse transaction for a direct user-Todo completion.""" - - if normalize_todo_status(status) != TODO_STATUS_DONE: - return None - match = find_todo_block( - state_file.read_text(encoding="utf-8").splitlines(), - todo_id=todo_id, - role=role, - ) - if match is None or (role or match[0]) == "agent": - return None - return run_completion_validation_gate_with_source( - state_file=state_file, - todo_id=todo_id, - role=role, - registry_path=registry_path, - goal_id=goal_id, - dry_run=dry_run, - no_followup=no_followup, - requested_has_successor=requested_has_successor, - ) - - -def locked_todo_completion_source( - *, - lines: list[str], - state_file: Path, - project: Path | None, - registry_path: Path, - goal_id: str, - todo_id: str, - role: str | None, -) -> tuple[Any, dict[str, Any] | None]: - """Resolve the materialized Todo under the write lock.""" - - match = find_todo_block(lines, todo_id=todo_id, role=role) - if match: - item_role, _section, _start, _end, block = match - todo = dict(block) - todo["role"] = item_role - return match, todo - return None, None - - def execute_completion_validation_effects( result: Mapping[str, Any], *, registry_path: Path, goal_id: str, delivery_workspace: Mapping[str, Any] | None = None, diff --git a/loopx/control_plane/todos/mutation_response.py b/loopx/control_plane/todos/mutation_response.py index 2875c62cc1..1fe52756d3 100644 --- a/loopx/control_plane/todos/mutation_response.py +++ b/loopx/control_plane/todos/mutation_response.py @@ -5,20 +5,6 @@ from pathlib import Path from typing import Any -from .contract import ( - normalize_explore_result_node_refs, normalize_required_capabilities, - normalize_target_capabilities, normalize_todo_blocks_agent, - normalize_todo_bound_agent, normalize_todo_claimed_by, - normalize_todo_continuation_policy, normalize_todo_decision_scope, - normalize_todo_decision_scope_outcomes, normalize_todo_excluded_agents, - normalize_todo_global_gate, normalize_todo_goal_bound, normalize_todo_id, - normalize_todo_id_list, normalize_todo_no_followup, - normalize_todo_required_decision_scopes, normalize_todo_resume_when, - normalize_todo_task_domain, normalize_todo_task_repository, -) -from .completion_state import ( - normalize_todo_completion_continuation, normalize_todo_completion_recovery, -) from .todo_semantics import todo_priority_label def serialize_added_todo_payload( @@ -78,104 +64,3 @@ def serialize_added_todo_payload( "updated_at": updated_at if changed else None, **handoff_gate, } - -def serialize_todo_update_result( - *, role: str, section: str, todo: str | None, todo_id: str, - status: str, priority: str | None, status_changed: bool, - text_changed: bool, metadata_updated: bool, metadata: Mapping[str, Any], - monitor_poll_transition: Mapping[str, Any] | None = None, - external_wait_transition: Mapping[str, Any] | None = None, -) -> dict[str, Any]: - """Project the public update result from already decided Todo facts.""" - effective_metadata = metadata - return { - **({"monitor_poll_transition": dict(monitor_poll_transition)} - if monitor_poll_transition is not None else {}), - **({"external_wait_transition": dict(external_wait_transition)} - if external_wait_transition is not None else {}), - "role": role, - "section": section, - "todo": todo, - "todo_id": todo_id, - "status": status, - "status_changed": status_changed, - "text_changed": text_changed, - "priority": priority, - "metadata_updated": metadata_updated, - "changed": status_changed or text_changed or metadata_updated, - "claimed_by": normalize_todo_claimed_by(effective_metadata.get("claimed_by")), - "bound_agent": normalize_todo_bound_agent( - effective_metadata.get("bound_agent") - ), - "goal_bound": normalize_todo_goal_bound(effective_metadata.get("goal_bound")), - "task_class": effective_metadata.get("task_class"), - "action_kind": effective_metadata.get("action_kind"), - "task_domain": normalize_todo_task_domain( - effective_metadata.get("task_domain") - ), - "capability_binding_ref": effective_metadata.get("capability_binding_ref"), - "task_repository": normalize_todo_task_repository( - effective_metadata.get("task_repository") - ), - "continuation_policy": normalize_todo_continuation_policy( - effective_metadata.get("continuation_policy") - ), - "required_capabilities": normalize_required_capabilities( - effective_metadata.get("required_capabilities") - ), - "target_capabilities": normalize_target_capabilities( - effective_metadata.get("target_capabilities") - ), - "explore_result_node_refs": normalize_explore_result_node_refs( - effective_metadata.get("explore_result_node_refs") - ), - "decision_scope": normalize_todo_decision_scope( - effective_metadata.get("decision_scope") - ), - "required_decision_scopes": normalize_todo_required_decision_scopes( - effective_metadata.get("required_decision_scopes") - ), - "decision_outcome": effective_metadata.get("decision_outcome"), - "decision_scope_outcomes": normalize_todo_decision_scope_outcomes( - effective_metadata.get("decision_scope_outcomes") - ), - "blocks_agent": normalize_todo_blocks_agent( - effective_metadata.get("blocks_agent") - ), - "excluded_agents": normalize_todo_excluded_agents( - effective_metadata.get("excluded_agents") - ), - "global_gate": normalize_todo_global_gate( - effective_metadata.get("global_gate") - ), - "unblocks_todo_id": normalize_todo_id( - effective_metadata.get("unblocks_todo_id") - ), - "successor_todo_ids": normalize_todo_id_list( - effective_metadata.get("successor_todo_ids") - ), - "completion_continuation": normalize_todo_completion_continuation( - effective_metadata.get("completion_continuation") - ), - "completion_recovery": normalize_todo_completion_recovery( - effective_metadata.get("completion_recovery") - ), - "completion_receipt_id": effective_metadata.get("completion_receipt_id"), - "resume_when": normalize_todo_resume_when( - effective_metadata.get("resume_when") - ), - "resume_monitor_generation": effective_metadata.get( - "resume_monitor_generation" - ), - "no_followup": normalize_todo_no_followup( - effective_metadata.get("no_followup") - ), - "target_key": effective_metadata.get("target_key"), - "cadence": effective_metadata.get("cadence"), - "next_due_at": effective_metadata.get("next_due_at"), - "expires_at": effective_metadata.get("expires_at"), - "watch_only": effective_metadata.get("watch_only"), - "material_change_generation": effective_metadata.get( - "material_change_generation" - ), - } diff --git a/loopx/control_plane/todos/update_source.py b/loopx/control_plane/todos/update_source.py deleted file mode 100644 index 2bafe1f034..0000000000 --- a/loopx/control_plane/todos/update_source.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Complete locked Todo facts for public update planning; no state decisions.""" -from typing import Any - -from .active_state_editing import archive_section_bounds, section_bounds, todo_blocks -from .resume_condition import compact_todo_resume_items - - -def todo_update_snapshot(lines: list[str]) -> list[dict[str, Any]]: - """Collect complete active/archive Todo metadata under the caller's lock.""" - - collected: list[dict[str, Any]] = [] - archive_bounds = archive_section_bounds(lines) - if archive_bounds: - collected.extend( - { - **item, - "role": "agent", - } - for item in todo_blocks( - lines, - archive_bounds[0], - archive_bounds[1], - role="agent", - source_section="Completed Work Archive", - ) - ) - for role in ("user", "agent"): - bounds = section_bounds(lines, role) - if bounds: - collected.extend( - { - **item, - "role": role, - } - for item in todo_blocks( - lines, - bounds[0], - bounds[1], - role=role, - source_section=bounds[2], - ) - ) - return compact_todo_resume_items(collected) diff --git a/loopx/control_plane/work_items/primary_action.py b/loopx/control_plane/work_items/primary_action.py index e4c4f59a12..7e90e98dc3 100644 --- a/loopx/control_plane/work_items/primary_action.py +++ b/loopx/control_plane/work_items/primary_action.py @@ -109,32 +109,6 @@ def address(item: dict[str, Any], *, limit: int = 80) -> dict[str, Any]: } -def protocol_monitor_action(payload: dict[str, Any]) -> str | None: - goal_id = str(payload.get("goal_id") or "") - work_lane = ( - payload.get("work_lane_contract") - if isinstance(payload.get("work_lane_contract"), dict) - else {} - ) - if work_lane.get("obligation") == "quiet_until_material_monitor_transition": - return "quiet until a material monitor transition, regression, or concrete blocker appears" - monitors = ( - payload.get("autonomous_monitor_candidates") - if isinstance(payload.get("autonomous_monitor_candidates"), dict) - else {} - ) - items = monitors.get("items") if isinstance(monitors.get("items"), list) else [] - for item in items: - if not isinstance(item, dict): - continue - if goal_id and str(item.get("goal_id") or "") != goal_id: - continue - text = protocol_action_label(item.get("text"), limit=160) - if text: - return text - return None - - def build_primary_action_projection( payload: dict[str, Any], *, mode: str, primary_action: str | None, ) -> dict[str, Any]: diff --git a/loopx/worker_bridge.py b/loopx/worker_bridge.py index a8a5411393..35ef758086 100644 --- a/loopx/worker_bridge.py +++ b/loopx/worker_bridge.py @@ -714,63 +714,6 @@ def append_worker_bridge_counter_trace_row( return True -def load_worker_bridge_counter_trace_file(path: str | Path | None) -> list[dict[str, Any]]: - """Load compact worker-side counter trace rows, ignoring malformed rows.""" - - if not path: - return [] - trace_path = Path(path) - if not trace_path.exists(): - return [] - rows: list[dict[str, Any]] = [] - try: - for line in trace_path.read_text(encoding="utf-8").splitlines(): - text = line.strip() - if not text: - continue - try: - row = json.loads(text) - except json.JSONDecodeError: - continue - if isinstance(row, dict): - rows.append(row) - except OSError: - return [] - return rows - - -def build_worker_bridge_interaction_counters_from_trace( - trace_rows: list[dict[str, Any]] | None, -) -> dict[str, Any]: - """Build generic compact interaction counters from worker bridge trace rows.""" - - loopx_cli_calls: dict[str, int] = {} - total = 0 - for row in trace_rows or []: - if not isinstance(row, dict): - continue - kind = _compact_counter_trace_label( - row.get("kind") or row.get("type") or row.get("event") - ) - command = _compact_counter_trace_label(row.get("command") or row.get("call")) - if kind and kind != "loopx_cli_call": - continue - if not command: - continue - total += 1 - loopx_cli_calls[command] = loopx_cli_calls.get(command, 0) + 1 - loopx_cli_calls["total"] = total - return { - "schema_version": "loopx_worker_bridge_interaction_counters_v0", - "loopx_cli_calls": loopx_cli_calls, - "trace_row_count": len(trace_rows or []), - "state_reads": loopx_cli_calls.get("active_user_observe", 0), - "state_writes": 0, - "raw_trace_recorded": False, - "raw_paths_recorded": False, - } - - def build_worker_bridge_install_contract( *, project_root: str = LOOPX_PROJECT_ROOT_PLACEHOLDER,