Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
STARTER_MODULE_LIMITS = {
# Legacy command owners are frozen at their current baseline while each
# cohesive extraction lands; the default budget still catches new growth.
"todo.py": 1098,
"starter.py": 180,
"starter_bootstrap.py": 220,
"starter_bootstrap_registration.py": 240,
Expand Down
255 changes: 21 additions & 234 deletions loopx/cli_commands/todo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@

from ..control_plane.todos.contract import (
TODO_CONTINUATION_POLICY_VALUES,
TODO_TASK_CLASS_ADVANCEMENT,
normalize_todo_continuation_policy,
normalize_todo_task_class,
replan_successor_semantic_binding,
)
from ..control_plane.capability_hooks import PostWritebackHookRegistration
Expand All @@ -18,11 +15,6 @@
load_task_lease_runtime_shadow_records,
resolve_coordination_runtime_shadow_config,
)
from ..control_plane.quota.settlement import (
QuotaSettlementReadback,
read_heartbeat_settlement,
settlement_result_payload,
)
from ..control_plane.todos.markdown import render_todo_markdown
from ..history import load_index, load_registry
from ..paths import resolve_runtime_root
Expand All @@ -41,7 +33,6 @@
ARCHIVE_COMPLETED_DEFAULT_MAX_ACTIVE_DONE,
add_goal_todo,
archive_completed_todos,
complete_goal_todo,
list_goal_todos,
resolve_todo_state,
supersede_goal_todo,
Expand All @@ -56,7 +47,6 @@
validate_todo_archive_completed_options,
validate_todo_capture_followups_options,
validate_todo_claim_options,
validate_todo_complete_options,
validate_todo_list_options,
validate_todo_suggest_options,
validate_todo_supersede_options,
Expand All @@ -68,9 +58,11 @@
append_todo_rollout_event,
todo_error_payload,
)
from .post_writeback import (
PostWritebackProjectionBuilder,
dispatch_committed_cli_post_writeback_hooks,
from .post_writeback import PostWritebackProjectionBuilder
from .todo_complete import (
TodoCompletionOutcome,
finalize_committed_todo_completion,
run_todo_complete,
)

PrintPayload = Callable[
Expand Down Expand Up @@ -160,48 +152,6 @@ def _mirror_committed_todo_runtime_shadow(
)


def _completion_settlement_requirement(
todo: dict[str, object],
*,
no_follow_up: bool,
) -> str | None:
if no_follow_up:
return "terminal no-follow-up closeout"
task_class = normalize_todo_task_class(
todo.get("task_class"),
text=str(todo.get("text") or ""),
action_kind=todo.get("action_kind"),
)
continuation_policy = normalize_todo_continuation_policy(
todo.get("continuation_policy")
)
if (
str(todo.get("role") or "") == "agent"
and task_class == TODO_TASK_CLASS_ADVANCEMENT
and continuation_policy != "same_agent_non_delivery"
):
return "turn-scoped advancement completion"
return None


def _completion_settlement_error(
todo: dict[str, object],
settlement_readback: QuotaSettlementReadback,
*,
no_follow_up: bool,
) -> str | None:
requirement = _completion_settlement_requirement(
todo,
no_follow_up=no_follow_up,
)
if requirement is None or settlement_readback.settlement.failure is None:
return None
return (
f"{requirement} requires matching writeback and quota spend receipts: "
+ settlement_readback.settlement.failure.reason
)


def _validated_replan_successor_obligation(
args: argparse.Namespace,
*,
Expand Down Expand Up @@ -747,6 +697,7 @@ def handle_todo_command(
if args.todo_command == "suggest"
else render_todo_markdown
)
completion: TodoCompletionOutcome | None = None
try:
if args.todo_command is None:
raise ValueError(
Expand Down Expand Up @@ -910,128 +861,13 @@ def handle_todo_command(
dry_run=bool(args.dry_run),
)
elif args.todo_command == "complete":
validate_todo_complete_options(args)
settlement_result = None
settlement_identity = None
settlement_readback = None
completion_requires_settlement = False
completion_error = None
completion_turn_key = None
completion_identity_source = None
if getattr(args, "turn_instance_id", None):
runtime_root = resolve_runtime_root(
load_registry(registry_path),
runtime_root_arg,
)
settlement_readback = read_heartbeat_settlement(
runtime_root,
goal_id=args.goal_id,
agent_id=args.agent_id,
todo_id=args.todo_id,
turn_instance_id=getattr(args, "turn_instance_id", None),
)
if settlement_readback is None:
raise RuntimeError(
"exact settlement readback unexpectedly returned not-found"
)
settlement_result = settlement_readback.identity
if settlement_result.failure is not None:
raise ValueError(settlement_result.failure.reason)
if settlement_result.value is None:
raise ValueError("turn-scoped Todo completion has no identity")
identity = settlement_result.value
settlement_identity = identity
todo_payload = list_goal_todos(
registry_path=registry_path,
goal_id=args.goal_id,
todo_id=args.todo_id,
project=Path(args.project).expanduser() if args.project else None,
state_file=(
Path(args.state_file).expanduser()
if args.state_file
else None
),
runtime_root_arg=runtime_root_arg,
)
todo = (
todo_payload.get("todo")
if isinstance(todo_payload.get("todo"), dict)
else None
)
if todo is None:
raise ValueError(
"turn-scoped Todo completion requires one durable Todo"
)
completion_requirement = _completion_settlement_requirement(
todo,
no_follow_up=bool(args.no_follow_up),
)
completion_requires_settlement = completion_requirement is not None
completion_error = _completion_settlement_error(
todo,
settlement_readback=settlement_readback,
no_follow_up=bool(args.no_follow_up),
)
if completion_error is not None:
settlement_result = settlement_readback.settlement
payload = {
"ok": False,
"dry_run": bool(args.dry_run),
"completed": False,
"changed": False,
"goal_id": args.goal_id,
"todo_id": args.todo_id,
"settlement_blocked_completion": True,
"settlement_identity": identity.as_dict(),
"settlement_result": settlement_result_payload(
settlement_result
),
"error": completion_error,
}
completion_turn_key = identity.effect_id
completion_identity_source = "turn_settlement"
elif getattr(args, "completion_identity_key", None):
completion_turn_key = str(args.completion_identity_key)
completion_identity_source = "lifecycle_reentry"
if completion_error is None:
payload = complete_goal_todo(
registry_path=registry_path,
runtime_root_arg=runtime_root_arg,
goal_id=args.goal_id,
todo_id=args.todo_id,
role=args.role,
decision_outcome=args.decision_outcome,
evidence=args.evidence,
completion_turn_key=completion_turn_key,
completion_identity_source=completion_identity_source,
task_lease_idempotency_key=args.task_lease_idempotency_key,
task_lease_expected_version=args.task_lease_expected_version,
note=args.note,
no_followup=bool(args.no_follow_up),
successor_todo_ids=args.successor_todo_ids,
claimed_by=args.claimed_by,
clear_claim=bool(args.clear_claim),
next_agent_todo=args.next_agent_todo,
next_user_todo=args.next_user_todo,
next_user_task_class=args.next_user_task_class,
next_claimed_by=args.next_claimed_by,
next_task_class=args.next_task_class,
next_action_kind=args.next_action_kind,
next_task_repository=args.next_task_repository,
next_required_capabilities=args.next_required_capabilities,
next_continuation_policy=args.next_continuation_policy,
next_excluded_agents=args.next_excluded_agents,
self_merged=bool(args.self_merged),
agent_id=args.agent_id,
authority_reason=args.authority_reason,
**_todo_path_args(args),
dry_run=bool(args.dry_run),
)
if settlement_identity is not None:
payload["settlement_identity"] = settlement_identity.as_dict()
payload["settlement_result"] = settlement_result_payload(
settlement_result
)
completion = run_todo_complete(
args,
registry_path=registry_path,
runtime_root_arg=runtime_root_arg,
path_args=_todo_path_args(args),
)
payload = completion.payload
elif args.todo_command == "supersede":
validate_todo_supersede_options(args)
payload = supersede_goal_todo(
Expand Down Expand Up @@ -1119,64 +955,15 @@ def handle_todo_command(
)
if runtime_shadow is not None:
payload["coordination_runtime_shadow"] = runtime_shadow
if (
args.todo_command == "complete"
and getattr(args, "turn_instance_id", None)
and payload.get("ok")
and not payload.get("dry_run")
):
runtime_root = resolve_runtime_root(
load_registry(registry_path),
runtime_root_arg,
)
settlement_readback = read_heartbeat_settlement(
runtime_root,
goal_id=args.goal_id,
agent_id=args.agent_id,
todo_id=args.todo_id,
turn_instance_id=getattr(args, "turn_instance_id", None),
)
if settlement_readback is None:
raise RuntimeError("exact settlement readback unexpectedly returned not-found")
settlement_result = (
settlement_readback.terminal_settlement
if args.no_follow_up and settlement_identity is not None
else settlement_readback.settlement
if completion_requires_settlement
else settlement_readback.identity
)
payload["settlement_result"] = settlement_result_payload(
settlement_result
if completion is not None:
finalize_committed_todo_completion(
completion,
args=args,
registry_path=registry_path,
runtime_root_arg=runtime_root_arg,
post_writeback_hooks=post_writeback_hooks,
post_writeback_projection_builder=post_writeback_projection_builder,
)
if settlement_result.failure is not None:
payload["ok"] = False
payload["receipt_repair_required"] = True
payload["error"] = settlement_result.failure.reason
if (
args.todo_command == "complete"
and payload.get("ok")
and payload.get("completed")
and not payload.get("dry_run")
and post_writeback_hooks
and settlement_identity is not None
):
identity = settlement_identity.as_dict()
committed_at = str(payload.get("updated_at") or "").strip()
if committed_at:
payload["post_writeback_hooks"] = (
dispatch_committed_cli_post_writeback_hooks(
payload=payload,
registry_path=registry_path,
runtime_root_arg=runtime_root_arg,
goal_id=args.goal_id,
event_kind="todo_complete",
identity=identity,
state_version=committed_at,
committed_at=committed_at,
hooks=post_writeback_hooks,
projection_builder=post_writeback_projection_builder,
)
)
print_payload(
payload,
format_name or str(getattr(args, "format", None) or "markdown"),
Expand Down
Loading
Loading