loopx 0.4.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (811) hide show
  1. loopx/__init__.py +5 -0
  2. loopx/agent_onboarding.py +654 -0
  3. loopx/agent_registry.py +112 -0
  4. loopx/ark_managed_agent_host.py +59 -0
  5. loopx/authority.py +805 -0
  6. loopx/benchmark.py +2875 -0
  7. loopx/benchmark_adapters/__init__.py +1 -0
  8. loopx/benchmark_adapters/agentissue.py +2644 -0
  9. loopx/benchmark_adapters/agents_last_exam.py +3998 -0
  10. loopx/benchmark_adapters/edgebench.py +322 -0
  11. loopx/benchmark_adapters/skillsbench.py +5978 -0
  12. loopx/benchmark_adapters/skillsbench_acp_failure_policy.py +143 -0
  13. loopx/benchmark_adapters/skillsbench_acp_process.py +31 -0
  14. loopx/benchmark_adapters/skillsbench_acp_relay.py +4832 -0
  15. loopx/benchmark_adapters/skillsbench_batch.py +124 -0
  16. loopx/benchmark_adapters/skillsbench_bridge_guard.py +209 -0
  17. loopx/benchmark_adapters/skillsbench_bridge_summary.py +203 -0
  18. loopx/benchmark_adapters/skillsbench_codex_goal_recovery.py +271 -0
  19. loopx/benchmark_adapters/skillsbench_codex_goal_trace.py +81 -0
  20. loopx/benchmark_adapters/skillsbench_codex_runtime.py +339 -0
  21. loopx/benchmark_adapters/skillsbench_dockerfile_runtime.py +467 -0
  22. loopx/benchmark_adapters/skillsbench_failure_signals.py +652 -0
  23. loopx/benchmark_adapters/skillsbench_proxy_runtime.py +327 -0
  24. loopx/benchmark_adapters/skillsbench_remote_bridge.py +402 -0
  25. loopx/benchmark_adapters/skillsbench_result_discovery.py +143 -0
  26. loopx/benchmark_adapters/skillsbench_runner_profile.py +436 -0
  27. loopx/benchmark_adapters/skillsbench_runner_source.py +99 -0
  28. loopx/benchmark_adapters/skillsbench_setup_preflight.py +771 -0
  29. loopx/benchmark_adapters/skillsbench_signals.py +15 -0
  30. loopx/benchmark_adapters/skillsbench_task_source.py +141 -0
  31. loopx/benchmark_adapters/skillsbench_turn_route.py +723 -0
  32. loopx/benchmark_adapters/skillsbench_turn_runtime.py +1069 -0
  33. loopx/benchmark_adapters/skillsbench_typed_repair.py +689 -0
  34. loopx/benchmark_adapters/skillsbench_uv_cache.py +111 -0
  35. loopx/benchmark_adapters/skillsbench_verifier_bootstrap.py +227 -0
  36. loopx/benchmark_adapters/skillsbench_verifier_cache.py +138 -0
  37. loopx/benchmark_adapters/terminal_bench.py +10078 -0
  38. loopx/benchmark_case_analysis.py +1276 -0
  39. loopx/benchmark_case_state.py +1079 -0
  40. loopx/benchmark_core/__init__.py +239 -0
  41. loopx/benchmark_core/adapter.py +84 -0
  42. loopx/benchmark_core/artifacts.py +517 -0
  43. loopx/benchmark_core/attempts.py +199 -0
  44. loopx/benchmark_core/container_exec.py +216 -0
  45. loopx/benchmark_core/io.py +68 -0
  46. loopx/benchmark_core/lifecycle.py +211 -0
  47. loopx/benchmark_core/loop_protocol.py +689 -0
  48. loopx/benchmark_core/observable_handles.py +348 -0
  49. loopx/benchmark_core/parity.py +256 -0
  50. loopx/benchmark_core/remote_closeout.py +482 -0
  51. loopx/benchmark_core/rounds.py +215 -0
  52. loopx/benchmark_core/route_profile.py +509 -0
  53. loopx/benchmark_core/run_permissions.py +206 -0
  54. loopx/benchmark_core/split_control.py +925 -0
  55. loopx/benchmark_core/turn_fidelity.py +326 -0
  56. loopx/benchmark_ledger.py +3793 -0
  57. loopx/benchmark_ledger_countability.py +372 -0
  58. loopx/benchmark_ledger_current.py +724 -0
  59. loopx/benchmark_trajectory.py +405 -0
  60. loopx/benchmarks/__init__.py +1 -0
  61. loopx/benchmarks/qualification/__init__.py +1 -0
  62. loopx/benchmarks/qualification/release_outcome_baseline.py +360 -0
  63. loopx/benchmarks/read_models/__init__.py +1 -0
  64. loopx/benchmarks/read_models/benchmark_attempt_accounting.py +53 -0
  65. loopx/benchmarks/read_models/benchmark_comparison.py +414 -0
  66. loopx/benchmarks/read_models/benchmark_event_timeline.py +113 -0
  67. loopx/benchmarks/read_models/benchmark_experiment_report.py +475 -0
  68. loopx/benchmarks/read_models/benchmark_learning_ledger.py +137 -0
  69. loopx/benchmarks/read_models/benchmark_lifecycle_contracts.py +228 -0
  70. loopx/benchmarks/read_models/benchmark_projection.py +723 -0
  71. loopx/benchmarks/read_models/benchmark_result.py +146 -0
  72. loopx/benchmarks/read_models/benchmark_run_execution_contract.py +116 -0
  73. loopx/benchmarks/read_models/benchmark_run_failure.py +157 -0
  74. loopx/benchmarks/read_models/benchmark_run_metrics.py +213 -0
  75. loopx/benchmarks/read_models/benchmark_run_post_execution.py +635 -0
  76. loopx/benchmarks/read_models/benchmark_run_pre_execution.py +541 -0
  77. loopx/benchmarks/read_models/benchmark_status_compaction.py +1255 -0
  78. loopx/benchmarks/read_models/benchmark_status_runner.py +780 -0
  79. loopx/benchmarks/read_models/goal_start_control_score.py +857 -0
  80. loopx/benchmarks/read_models/skillsbench_post_run_debug.py +746 -0
  81. loopx/benchmarks/read_models/skillsbench_verifier_attribution.py +269 -0
  82. loopx/bootstrap.py +1116 -0
  83. loopx/bootstrap_command_pack.py +2167 -0
  84. loopx/boundary_authority.py +199 -0
  85. loopx/canary/__init__.py +1 -0
  86. loopx/canary/maintainability_ratchet.py +800 -0
  87. loopx/canary/planner.py +1984 -0
  88. loopx/canary/premerge.py +1130 -0
  89. loopx/canary/qualification_profiles.py +309 -0
  90. loopx/canary/quality_surface_catalog.py +838 -0
  91. loopx/canary/release_profiles.py +51 -0
  92. loopx/canary/runner.py +1107 -0
  93. loopx/canary/smoke_health.py +581 -0
  94. loopx/canary/smoke_profiles.py +212 -0
  95. loopx/capabilities/__init__.py +0 -0
  96. loopx/capabilities/agent_turn_recall/__init__.py +17 -0
  97. loopx/capabilities/agent_turn_recall/cli.py +369 -0
  98. loopx/capabilities/agent_turn_recall/core.py +296 -0
  99. loopx/capabilities/auto_research/__init__.py +16 -0
  100. loopx/capabilities/auto_research/bootstrap_contract.py +157 -0
  101. loopx/capabilities/auto_research/cli.py +1468 -0
  102. loopx/capabilities/auto_research/core.py +11 -0
  103. loopx/capabilities/auto_research/defaults.py +79 -0
  104. loopx/capabilities/auto_research/demo_e2e.py +1848 -0
  105. loopx/capabilities/auto_research/demo_supervisor.py +186 -0
  106. loopx/capabilities/auto_research/evidence_packet.py +767 -0
  107. loopx/capabilities/auto_research/human_view.py +794 -0
  108. loopx/capabilities/auto_research/kernel.py +191 -0
  109. loopx/capabilities/auto_research/knn_demo_workspace.py +322 -0
  110. loopx/capabilities/auto_research/live_evidence.py +248 -0
  111. loopx/capabilities/auto_research/preset.py +176 -0
  112. loopx/capabilities/auto_research/research_state.py +1085 -0
  113. loopx/capabilities/auto_research/role_profiles.py +394 -0
  114. loopx/capabilities/auto_research/rollout_append.py +97 -0
  115. loopx/capabilities/auto_research/terminal_result_contract.py +422 -0
  116. loopx/capabilities/auto_research/terminal_result_projection.py +171 -0
  117. loopx/capabilities/auto_research/terminal_result_query.py +233 -0
  118. loopx/capabilities/auto_research/terminal_results.py +349 -0
  119. loopx/capabilities/auto_research/user_contract.py +190 -0
  120. loopx/capabilities/auto_research/worker_loop.py +163 -0
  121. loopx/capabilities/auto_research/worker_runtime.py +777 -0
  122. loopx/capabilities/auto_research/worker_skill/SKILL.md +343 -0
  123. loopx/capabilities/benchmark_toolkit/__init__.py +19 -0
  124. loopx/capabilities/benchmark_toolkit/integrity.py +387 -0
  125. loopx/capabilities/catalog.py +1875 -0
  126. loopx/capabilities/change_quality/__init__.py +19 -0
  127. loopx/capabilities/change_quality/cli.py +171 -0
  128. loopx/capabilities/change_quality/context.py +156 -0
  129. loopx/capabilities/change_quality/oracles.py +269 -0
  130. loopx/capabilities/change_quality/policy.py +34 -0
  131. loopx/capabilities/change_quality/receipt.py +482 -0
  132. loopx/capabilities/change_quality/result.py +493 -0
  133. loopx/capabilities/change_quality/scope.py +171 -0
  134. loopx/capabilities/change_quality/shadow.py +680 -0
  135. loopx/capabilities/content_ops/__init__.py +0 -0
  136. loopx/capabilities/content_ops/cli.py +649 -0
  137. loopx/capabilities/content_ops/connector_packets.py +164 -0
  138. loopx/capabilities/content_ops/item_lifecycle.py +1000 -0
  139. loopx/capabilities/content_ops/layout.py +451 -0
  140. loopx/capabilities/content_ops/markdown.py +456 -0
  141. loopx/capabilities/content_ops/schemas.py +51 -0
  142. loopx/capabilities/content_ops/social_browser_x.py +107 -0
  143. loopx/capabilities/content_ops/surface.py +1956 -0
  144. loopx/capabilities/content_ops/templates/layout-catalog-v0.json +72 -0
  145. loopx/capabilities/context_providers/__init__.py +36 -0
  146. loopx/capabilities/context_providers/base.py +189 -0
  147. loopx/capabilities/context_providers/factory.py +32 -0
  148. loopx/capabilities/context_providers/openviking.py +702 -0
  149. loopx/capabilities/context_providers/service_ownership.py +185 -0
  150. loopx/capabilities/decision_context/__init__.py +129 -0
  151. loopx/capabilities/decision_context/architecture.py +83 -0
  152. loopx/capabilities/decision_context/assembler.py +849 -0
  153. loopx/capabilities/decision_context/catalog_entry.py +195 -0
  154. loopx/capabilities/decision_context/cli.py +310 -0
  155. loopx/capabilities/decision_context/cursor_commit.py +535 -0
  156. loopx/capabilities/decision_context/outcome_feedback.py +352 -0
  157. loopx/capabilities/decision_context/packets.py +654 -0
  158. loopx/capabilities/decision_context/private_state.py +189 -0
  159. loopx/capabilities/decision_context/profile.py +453 -0
  160. loopx/capabilities/decision_context/providers.py +228 -0
  161. loopx/capabilities/decision_context/review_settlement.py +136 -0
  162. loopx/capabilities/decision_context/runtime.py +273 -0
  163. loopx/capabilities/decision_context/sources.py +415 -0
  164. loopx/capabilities/explore/__init__.py +1 -0
  165. loopx/capabilities/explore/activation.py +198 -0
  166. loopx/capabilities/explore/adaptive_replay_planner.py +221 -0
  167. loopx/capabilities/explore/child_replay_runtime.py +463 -0
  168. loopx/capabilities/explore/composition_frontier.py +291 -0
  169. loopx/capabilities/explore/counterfactual_runtime.py +578 -0
  170. loopx/capabilities/explore/episode_runtime.py +647 -0
  171. loopx/capabilities/explore/harness_checkpoint.py +171 -0
  172. loopx/capabilities/explore/harness_gate.py +115 -0
  173. loopx/capabilities/explore/harness_runtime.py +1124 -0
  174. loopx/capabilities/explore/replay_metrics.py +206 -0
  175. loopx/capabilities/explore/replay_runtime.py +1271 -0
  176. loopx/capabilities/explore/resource_portfolio.py +173 -0
  177. loopx/capabilities/explore/result_log.py +974 -0
  178. loopx/capabilities/explore/router_state.py +432 -0
  179. loopx/capabilities/explore/source_history_reconcile.py +255 -0
  180. loopx/capabilities/explore/speculative_scheduler.py +498 -0
  181. loopx/capabilities/explore/todo_branch_plan.py +650 -0
  182. loopx/capabilities/explore/todo_evidence.py +141 -0
  183. loopx/capabilities/explore/trace_runtime.py +284 -0
  184. loopx/capabilities/explore/worker_branch_plan.py +1257 -0
  185. loopx/capabilities/integration_branch/__init__.py +13 -0
  186. loopx/capabilities/integration_branch/cli.py +148 -0
  187. loopx/capabilities/integration_branch/core.py +916 -0
  188. loopx/capabilities/issue_fix/__init__.py +19 -0
  189. loopx/capabilities/issue_fix/acceptance_loop.py +1050 -0
  190. loopx/capabilities/issue_fix/candidate_evidence.py +503 -0
  191. loopx/capabilities/issue_fix/candidate_preflight.py +676 -0
  192. loopx/capabilities/issue_fix/cli.py +1822 -0
  193. loopx/capabilities/issue_fix/cli_input.py +87 -0
  194. loopx/capabilities/issue_fix/content_ops_cli.py +148 -0
  195. loopx/capabilities/issue_fix/discovered_issue_promotion.py +947 -0
  196. loopx/capabilities/issue_fix/explore_projection.py +710 -0
  197. loopx/capabilities/issue_fix/feasibility.py +542 -0
  198. loopx/capabilities/issue_fix/github_public.py +661 -0
  199. loopx/capabilities/issue_fix/intake_surface.py +832 -0
  200. loopx/capabilities/issue_fix/metadata_preview.py +218 -0
  201. loopx/capabilities/issue_fix/metrics_projection.py +1340 -0
  202. loopx/capabilities/issue_fix/metrics_supplement.py +634 -0
  203. loopx/capabilities/issue_fix/metrics_supplement_cli.py +127 -0
  204. loopx/capabilities/issue_fix/outcome_projection.py +1235 -0
  205. loopx/capabilities/issue_fix/periodic_report.py +189 -0
  206. loopx/capabilities/issue_fix/pr_description.py +418 -0
  207. loopx/capabilities/issue_fix/pr_gate_reconcile.py +496 -0
  208. loopx/capabilities/issue_fix/pr_gate_reconcile_cli.py +464 -0
  209. loopx/capabilities/issue_fix/pr_lifecycle.py +1327 -0
  210. loopx/capabilities/issue_fix/pr_lifecycle_rollout.py +85 -0
  211. loopx/capabilities/issue_fix/pr_monitor_materialization.py +257 -0
  212. loopx/capabilities/issue_fix/pr_review_ack.py +439 -0
  213. loopx/capabilities/issue_fix/provider_hooks.py +24 -0
  214. loopx/capabilities/issue_fix/repository_commit_evidence.py +186 -0
  215. loopx/capabilities/issue_fix/repository_context.py +457 -0
  216. loopx/capabilities/issue_fix/repository_memory.py +459 -0
  217. loopx/capabilities/issue_fix/repository_memory_provider.py +1454 -0
  218. loopx/capabilities/issue_fix/repository_snapshot.py +454 -0
  219. loopx/capabilities/issue_fix/reviewer_cli.py +917 -0
  220. loopx/capabilities/issue_fix/reviewer_notification.py +882 -0
  221. loopx/capabilities/issue_fix/reviewer_notification_drain.py +942 -0
  222. loopx/capabilities/issue_fix/reviewer_recommendation.py +1057 -0
  223. loopx/capabilities/issue_fix/reviewer_request.py +1282 -0
  224. loopx/capabilities/issue_fix/reward_memory.py +879 -0
  225. loopx/capabilities/issue_fix/workflow_plan.py +1286 -0
  226. loopx/capabilities/material_lifecycle/__init__.py +161 -0
  227. loopx/capabilities/material_lifecycle/_validation.py +183 -0
  228. loopx/capabilities/material_lifecycle/apply.py +672 -0
  229. loopx/capabilities/material_lifecycle/architecture.py +122 -0
  230. loopx/capabilities/material_lifecycle/cli.py +161 -0
  231. loopx/capabilities/material_lifecycle/decision_planning.py +470 -0
  232. loopx/capabilities/material_lifecycle/explore_execution.py +306 -0
  233. loopx/capabilities/material_lifecycle/intake.py +869 -0
  234. loopx/capabilities/material_lifecycle/inventory.py +147 -0
  235. loopx/capabilities/material_lifecycle/lifecycle.py +98 -0
  236. loopx/capabilities/material_lifecycle/preparation.py +147 -0
  237. loopx/capabilities/material_lifecycle/project_skill.py +83 -0
  238. loopx/capabilities/material_lifecycle/ranking.py +267 -0
  239. loopx/capabilities/material_lifecycle/readable_projection.py +500 -0
  240. loopx/capabilities/material_lifecycle/rebuild.py +480 -0
  241. loopx/capabilities/material_lifecycle/settlement.py +238 -0
  242. loopx/capabilities/periodic_report/__init__.py +71 -0
  243. loopx/capabilities/periodic_report/adapters.py +939 -0
  244. loopx/capabilities/periodic_report/archive.py +422 -0
  245. loopx/capabilities/periodic_report/bindings.py +705 -0
  246. loopx/capabilities/periodic_report/cli.py +277 -0
  247. loopx/capabilities/periodic_report/core.py +691 -0
  248. loopx/capabilities/periodic_report/extension_envelope.py +66 -0
  249. loopx/capabilities/periodic_report/presets.py +103 -0
  250. loopx/capabilities/periodic_report/profile.py +235 -0
  251. loopx/capabilities/periodic_report/project_progress.py +179 -0
  252. loopx/capabilities/periodic_report/triggers.py +452 -0
  253. loopx/capabilities/pr_review_queue/__init__.py +17 -0
  254. loopx/capabilities/pr_review_queue/core.py +506 -0
  255. loopx/capabilities/pr_review_queue/review_contract.py +506 -0
  256. loopx/capabilities/registry.py +192 -0
  257. loopx/capabilities/reward_memory/__init__.py +75 -0
  258. loopx/capabilities/reward_memory/application.py +819 -0
  259. loopx/capabilities/reward_memory/architecture.py +572 -0
  260. loopx/capabilities/reward_memory/candidate_review.py +511 -0
  261. loopx/capabilities/reward_memory/cli.py +469 -0
  262. loopx/capabilities/reward_memory/dogfood.py +574 -0
  263. loopx/capabilities/reward_memory/evaluation.py +296 -0
  264. loopx/capabilities/reward_memory/evaluation_fixtures.py +362 -0
  265. loopx/capabilities/reward_memory/experiment.py +567 -0
  266. loopx/capabilities/reward_memory/health.py +222 -0
  267. loopx/capabilities/reward_memory/ingestion.py +519 -0
  268. loopx/capabilities/reward_memory/registry.py +600 -0
  269. loopx/capabilities/reward_memory/runtime_hooks.py +312 -0
  270. loopx/capabilities/reward_memory/scoped_feedback.py +173 -0
  271. loopx/capabilities/semantic_preference/__init__.py +12 -0
  272. loopx/capabilities/semantic_preference/cli.py +189 -0
  273. loopx/capabilities/semantic_preference/contract.py +592 -0
  274. loopx/capabilities/semantic_preference/reward_memory.py +62 -0
  275. loopx/capabilities/value_connectors/__init__.py +1 -0
  276. loopx/capabilities/value_connectors/cli.py +401 -0
  277. loopx/capabilities/value_connectors/finance_extension_migration.py +108 -0
  278. loopx/capabilities/value_connectors/install_check.py +147 -0
  279. loopx/capabilities/value_connectors/planner.py +733 -0
  280. loopx/capabilities/value_connectors/source_map.py +446 -0
  281. loopx/claude_goal_baseline.py +138 -0
  282. loopx/claude_goal_mode/__init__.py +23 -0
  283. loopx/claude_goal_mode/hooks/goal_policy.py +212 -0
  284. loopx/claude_goal_mode/hooks/goal_state.py +139 -0
  285. loopx/claude_goal_mode/mcp/loopx_mcp.py +167 -0
  286. loopx/claude_goal_mode/scripts/connect.py +103 -0
  287. loopx/claude_goal_mode/scripts/goalmode_cmd.py +241 -0
  288. loopx/claude_goal_mode/scripts/install.py +328 -0
  289. loopx/claude_goal_mode/statusline/goal_status.py +97 -0
  290. loopx/cli.py +836 -0
  291. loopx/cli_commands/__init__.py +334 -0
  292. loopx/cli_commands/_host_thread.py +13 -0
  293. loopx/cli_commands/agentissue_runner_flow.py +447 -0
  294. loopx/cli_commands/agents_last_exam.py +160 -0
  295. loopx/cli_commands/agents_last_exam_baked_input.py +302 -0
  296. loopx/cli_commands/agents_last_exam_host_codex.py +374 -0
  297. loopx/cli_commands/agents_last_exam_launch_dry_run.py +372 -0
  298. loopx/cli_commands/agents_last_exam_local_plan.py +322 -0
  299. loopx/cli_commands/agents_last_exam_runner_source.py +352 -0
  300. loopx/cli_commands/agents_last_exam_task_material.py +335 -0
  301. loopx/cli_commands/agents_last_exam_validation_gate.py +236 -0
  302. loopx/cli_commands/benchmark_boundary.py +499 -0
  303. loopx/cli_commands/benchmark_dispatch.py +161 -0
  304. loopx/cli_commands/benchmark_release_outcome.py +123 -0
  305. loopx/cli_commands/benchmark_review_lifecycle.py +1275 -0
  306. loopx/cli_commands/benchmark_run_ledger.py +763 -0
  307. loopx/cli_commands/benchmark_run_ledger_case_analysis.py +249 -0
  308. loopx/cli_commands/benchmark_run_ledger_classification.py +45 -0
  309. loopx/cli_commands/benchmark_run_ledger_maintenance.py +486 -0
  310. loopx/cli_commands/benchmark_run_ledger_maintenance_registration.py +342 -0
  311. loopx/cli_commands/benchmark_run_ledger_maintenance_rendering.py +233 -0
  312. loopx/cli_commands/benchmark_run_ledger_parity.py +92 -0
  313. loopx/cli_commands/bootstrap_connect.py +238 -0
  314. loopx/cli_commands/canary.py +707 -0
  315. loopx/cli_commands/canary_release_qualification.py +79 -0
  316. loopx/cli_commands/capability.py +96 -0
  317. loopx/cli_commands/doctor.py +43 -0
  318. loopx/cli_commands/dreaming.py +143 -0
  319. loopx/cli_commands/edgebench.py +205 -0
  320. loopx/cli_commands/evidence_log.py +275 -0
  321. loopx/cli_commands/explore.py +989 -0
  322. loopx/cli_commands/explore_planning_commands.py +157 -0
  323. loopx/cli_commands/extension.py +271 -0
  324. loopx/cli_commands/first_run_report.py +73 -0
  325. loopx/cli_commands/goal_channel.py +656 -0
  326. loopx/cli_commands/handoff_mode.py +158 -0
  327. loopx/cli_commands/history.py +622 -0
  328. loopx/cli_commands/host_mode_plan.py +113 -0
  329. loopx/cli_commands/lark_inbox.py +431 -0
  330. loopx/cli_commands/lark_kanban.py +629 -0
  331. loopx/cli_commands/ml_experiment.py +321 -0
  332. loopx/cli_commands/multi_agent.py +211 -0
  333. loopx/cli_commands/opencode2_goal_worker.py +217 -0
  334. loopx/cli_commands/pr_review.py +167 -0
  335. loopx/cli_commands/presentation.py +218 -0
  336. loopx/cli_commands/preset.py +96 -0
  337. loopx/cli_commands/project.py +150 -0
  338. loopx/cli_commands/project_lifecycle.py +915 -0
  339. loopx/cli_commands/quota.py +859 -0
  340. loopx/cli_commands/quota_registration.py +241 -0
  341. loopx/cli_commands/quota_request.py +113 -0
  342. loopx/cli_commands/ready_score.py +110 -0
  343. loopx/cli_commands/registry_admin.py +975 -0
  344. loopx/cli_commands/registry_admin_configure.py +344 -0
  345. loopx/cli_commands/registry_admin_peer.py +84 -0
  346. loopx/cli_commands/registry_authority.py +218 -0
  347. loopx/cli_commands/review_batch.py +146 -0
  348. loopx/cli_commands/slash_commands.py +145 -0
  349. loopx/cli_commands/start_goal.py +251 -0
  350. loopx/cli_commands/starter.py +175 -0
  351. loopx/cli_commands/starter_bootstrap.py +179 -0
  352. loopx/cli_commands/starter_bootstrap_registration.py +198 -0
  353. loopx/cli_commands/starter_runtime_idle.py +107 -0
  354. loopx/cli_commands/starter_scheduler.py +207 -0
  355. loopx/cli_commands/starter_session_runtime.py +152 -0
  356. loopx/cli_commands/starter_visible_common.py +54 -0
  357. loopx/cli_commands/starter_visible_driver.py +161 -0
  358. loopx/cli_commands/starter_visible_pilot.py +278 -0
  359. loopx/cli_commands/status.py +867 -0
  360. loopx/cli_commands/status_registration.py +239 -0
  361. loopx/cli_commands/summary_all.py +222 -0
  362. loopx/cli_commands/support_control.py +809 -0
  363. loopx/cli_commands/support_control_registry.py +68 -0
  364. loopx/cli_commands/support_control_supervisor.py +289 -0
  365. loopx/cli_commands/task_lease.py +306 -0
  366. loopx/cli_commands/terminal_bench_adapter.py +717 -0
  367. loopx/cli_commands/terminal_bench_environment_result.py +1246 -0
  368. loopx/cli_commands/todo.py +940 -0
  369. loopx/cli_commands/todo_argument_validation.py +572 -0
  370. loopx/cli_commands/todo_event.py +114 -0
  371. loopx/cli_commands/turn.py +804 -0
  372. loopx/cli_commands/version.py +46 -0
  373. loopx/cli_commands/worker_bridge.py +659 -0
  374. loopx/cli_rollout.py +314 -0
  375. loopx/codex_cli_goal_tui.py +672 -0
  376. loopx/codex_cli_probe.py +1530 -0
  377. loopx/codex_cli_probe_markdown.py +935 -0
  378. loopx/codex_cli_runtime_probe.py +733 -0
  379. loopx/codex_cli_scheduler.py +564 -0
  380. loopx/codex_goal_baseline.py +620 -0
  381. loopx/configuration_catalog.py +617 -0
  382. loopx/configure_goal.py +1375 -0
  383. loopx/contract.py +996 -0
  384. loopx/control_plane/__init__.py +71 -0
  385. loopx/control_plane/agents/__init__.py +1 -0
  386. loopx/control_plane/agents/agent_lane_recommendation.py +516 -0
  387. loopx/control_plane/agents/agent_scope.py +1578 -0
  388. loopx/control_plane/agents/agent_scope_frontier.py +60 -0
  389. loopx/control_plane/agents/capability_gate.py +531 -0
  390. loopx/control_plane/agents/identity.py +140 -0
  391. loopx/control_plane/agents/legacy_migration.py +169 -0
  392. loopx/control_plane/agents/management_projection.py +658 -0
  393. loopx/control_plane/agents/material_frontier.py +608 -0
  394. loopx/control_plane/agents/material_handoff.py +156 -0
  395. loopx/control_plane/agents/multi_agent/__init__.py +1 -0
  396. loopx/control_plane/agents/multi_agent/codex_executable.py +207 -0
  397. loopx/control_plane/agents/multi_agent/collective_round_ledger.py +387 -0
  398. loopx/control_plane/agents/multi_agent/contract.py +474 -0
  399. loopx/control_plane/agents/multi_agent/recipe.py +110 -0
  400. loopx/control_plane/agents/multi_agent/role_successor.py +297 -0
  401. loopx/control_plane/agents/multi_agent/runtime_scripts.py +426 -0
  402. loopx/control_plane/agents/multi_agent/visible_launch_policy.py +149 -0
  403. loopx/control_plane/agents/multi_agent/visible_wake_scheduler.py +392 -0
  404. loopx/control_plane/agents/profile.py +216 -0
  405. loopx/control_plane/agents/runtime_model.py +73 -0
  406. loopx/control_plane/agents/subagent_activity.py +164 -0
  407. loopx/control_plane/agents/supervisor.py +544 -0
  408. loopx/control_plane/agents/supervisor_events.py +462 -0
  409. loopx/control_plane/agents/supervisor_inject.py +204 -0
  410. loopx/control_plane/agents/work_mode.py +56 -0
  411. loopx/control_plane/agents/workspace_guard.py +364 -0
  412. loopx/control_plane/effect_program.py +644 -0
  413. loopx/control_plane/goals/__init__.py +1 -0
  414. loopx/control_plane/goals/active_state_event_projection.py +103 -0
  415. loopx/control_plane/goals/active_state_metadata.py +47 -0
  416. loopx/control_plane/goals/active_state_sections.py +58 -0
  417. loopx/control_plane/goals/configure_goal_service.py +354 -0
  418. loopx/control_plane/goals/contract_health.py +132 -0
  419. loopx/control_plane/goals/dreaming.py +152 -0
  420. loopx/control_plane/goals/global_registry_health.py +199 -0
  421. loopx/control_plane/goals/global_registry_shadow.py +33 -0
  422. loopx/control_plane/goals/goal_channel.py +34 -0
  423. loopx/control_plane/goals/goal_channel_projection.py +560 -0
  424. loopx/control_plane/goals/goal_frontier/__init__.py +1917 -0
  425. loopx/control_plane/goals/goal_frontier/ack_policy.py +149 -0
  426. loopx/control_plane/goals/goal_frontier/outcome_continuity.py +437 -0
  427. loopx/control_plane/goals/goal_frontier/replan_rules.py +210 -0
  428. loopx/control_plane/goals/goal_frontier/semantic_history.py +314 -0
  429. loopx/control_plane/goals/goal_frontier/terminal.py +180 -0
  430. loopx/control_plane/goals/goal_vision.py +443 -0
  431. loopx/control_plane/goals/goal_vision_policy.py +36 -0
  432. loopx/control_plane/goals/goal_vision_state.py +62 -0
  433. loopx/control_plane/goals/goal_vision_wait.py +290 -0
  434. loopx/control_plane/goals/path_resolution.py +20 -0
  435. loopx/control_plane/goals/start_contract.py +206 -0
  436. loopx/control_plane/goals/vision_checkpoint.py +92 -0
  437. loopx/control_plane/handoff/__init__.py +1 -0
  438. loopx/control_plane/handoff/cross_runtime_impl_review.py +311 -0
  439. loopx/control_plane/handoff/delivery_contract.py +161 -0
  440. loopx/control_plane/handoff/handoff_runs.py +71 -0
  441. loopx/control_plane/handoff/project_handoff.py +155 -0
  442. loopx/control_plane/handoff/review_batch.py +463 -0
  443. loopx/control_plane/handoff/review_packet_context.py +216 -0
  444. loopx/control_plane/heartbeat/agent.py +173 -0
  445. loopx/control_plane/heartbeat/budget.py +66 -0
  446. loopx/control_plane/heartbeat/builder.py +501 -0
  447. loopx/control_plane/heartbeat/host.py +64 -0
  448. loopx/control_plane/heartbeat/rules.py +68 -0
  449. loopx/control_plane/heartbeat/task_body.py +759 -0
  450. loopx/control_plane/heartbeat/visible_goal.py +86 -0
  451. loopx/control_plane/projects/__init__.py +1 -0
  452. loopx/control_plane/projects/contract.py +25 -0
  453. loopx/control_plane/projects/registry.py +663 -0
  454. loopx/control_plane/quota/__init__.py +1 -0
  455. loopx/control_plane/quota/cli_projection.py +704 -0
  456. loopx/control_plane/quota/decision_summary.py +431 -0
  457. loopx/control_plane/quota/effect_program.py +152 -0
  458. loopx/control_plane/quota/error_codes.py +19 -0
  459. loopx/control_plane/quota/goal_boundary.py +464 -0
  460. loopx/control_plane/quota/heartbeat_receipt.py +277 -0
  461. loopx/control_plane/quota/heartbeat_recommendation.py +718 -0
  462. loopx/control_plane/quota/host_poll_receipts.py +162 -0
  463. loopx/control_plane/quota/live_decision.py +142 -0
  464. loopx/control_plane/quota/monitor_poll.py +786 -0
  465. loopx/control_plane/quota/policy_constants.py +40 -0
  466. loopx/control_plane/quota/projection_repair.py +262 -0
  467. loopx/control_plane/quota/recent_runs.py +210 -0
  468. loopx/control_plane/quota/scheduler_ack.py +490 -0
  469. loopx/control_plane/quota/selected_todo_projection.py +139 -0
  470. loopx/control_plane/quota/settlement.py +437 -0
  471. loopx/control_plane/quota/settlement_cli.py +246 -0
  472. loopx/control_plane/quota/settlement_validation.py +64 -0
  473. loopx/control_plane/quota/settlement_workspace_causality.py +180 -0
  474. loopx/control_plane/quota/should_run.py +249 -0
  475. loopx/control_plane/quota/should_run_packet.py +1165 -0
  476. loopx/control_plane/quota/should_run_prepare.py +675 -0
  477. loopx/control_plane/quota/slot_accounting.py +1123 -0
  478. loopx/control_plane/quota/spend_sources.py +11 -0
  479. loopx/control_plane/quota/stall_repair.py +397 -0
  480. loopx/control_plane/quota/states.py +29 -0
  481. loopx/control_plane/quota/task_orchestration.py +448 -0
  482. loopx/control_plane/quota/task_orchestration_admission.py +497 -0
  483. loopx/control_plane/quota/turn_envelope.py +889 -0
  484. loopx/control_plane/quota/usage_summary.py +140 -0
  485. loopx/control_plane/reward_memory.py +43 -0
  486. loopx/control_plane/runtime/__init__.py +2 -0
  487. loopx/control_plane/runtime/active_user_assisted_pilot.py +275 -0
  488. loopx/control_plane/runtime/agent_scoped_evidence_log.py +435 -0
  489. loopx/control_plane/runtime/decision_freshness.py +203 -0
  490. loopx/control_plane/runtime/event_ledger.py +197 -0
  491. loopx/control_plane/runtime/event_store_migration_bridge.py +196 -0
  492. loopx/control_plane/runtime/goal_project_route.py +70 -0
  493. loopx/control_plane/runtime/local_state_write_correctness.py +242 -0
  494. loopx/control_plane/runtime/promotion_readiness.py +152 -0
  495. loopx/control_plane/runtime/public_safety.py +120 -0
  496. loopx/control_plane/runtime/run_artifacts.py +78 -0
  497. loopx/control_plane/runtime/run_compaction.py +397 -0
  498. loopx/control_plane/runtime/run_context_retention.py +241 -0
  499. loopx/control_plane/runtime/run_history.py +132 -0
  500. loopx/control_plane/runtime/run_index_duplicates.py +205 -0
  501. loopx/control_plane/runtime/run_index_rebuild.py +263 -0
  502. loopx/control_plane/runtime/run_ingest_health.py +336 -0
  503. loopx/control_plane/runtime/runtime_projection_route.py +624 -0
  504. loopx/control_plane/runtime/runtime_projection_writer.py +98 -0
  505. loopx/control_plane/runtime/session_runtime.py +339 -0
  506. loopx/control_plane/runtime/shared_runtime_material_projection.py +332 -0
  507. loopx/control_plane/runtime/shared_runtime_refresh_projection.py +183 -0
  508. loopx/control_plane/runtime/stale_latest_run.py +90 -0
  509. loopx/control_plane/runtime/status_classifications.py +49 -0
  510. loopx/control_plane/runtime/status_projection_cache.py +235 -0
  511. loopx/control_plane/runtime/stride_observation.py +144 -0
  512. loopx/control_plane/runtime/time.py +39 -0
  513. loopx/control_plane/runtime/trajectory_hygiene.py +149 -0
  514. loopx/control_plane/runtime/validation_command.py +69 -0
  515. loopx/control_plane/scheduler/__init__.py +1 -0
  516. loopx/control_plane/scheduler/ack.py +329 -0
  517. loopx/control_plane/scheduler/arbitration.py +188 -0
  518. loopx/control_plane/scheduler/automation_liveness.py +183 -0
  519. loopx/control_plane/scheduler/execution_context.py +555 -0
  520. loopx/control_plane/scheduler/external_evidence_observation.py +428 -0
  521. loopx/control_plane/scheduler/monitor_display.py +143 -0
  522. loopx/control_plane/scheduler/monitor_poll_policy.py +161 -0
  523. loopx/control_plane/scheduler/monitor_poll_writeback.py +351 -0
  524. loopx/control_plane/scheduler/monitor_target.py +64 -0
  525. loopx/control_plane/scheduler/monitor_todo.py +146 -0
  526. loopx/control_plane/scheduler/monitor_wait.py +237 -0
  527. loopx/control_plane/scheduler/scheduler_hint.py +1284 -0
  528. loopx/control_plane/scheduler/state.py +354 -0
  529. loopx/control_plane/scheduler/state_transition_rules.py +179 -0
  530. loopx/control_plane/scheduler/time.py +10 -0
  531. loopx/control_plane/settlement_driver.py +293 -0
  532. loopx/control_plane/status/__init__.py +6 -0
  533. loopx/control_plane/status/active_state_projection.py +105 -0
  534. loopx/control_plane/status/agent_lane_projection.py +375 -0
  535. loopx/control_plane/status/attention_projection.py +74 -0
  536. loopx/control_plane/status/autonomous_replan_projection.py +103 -0
  537. loopx/control_plane/status/collection.py +140 -0
  538. loopx/control_plane/status/contract_projection.py +31 -0
  539. loopx/control_plane/status/dreaming_projection.py +52 -0
  540. loopx/control_plane/status/goal_attention_projection.py +157 -0
  541. loopx/control_plane/status/lifecycle_projection.py +110 -0
  542. loopx/control_plane/status/monitor_display_projection.py +69 -0
  543. loopx/control_plane/status/registry_health_projection.py +75 -0
  544. loopx/control_plane/status/run_projection.py +70 -0
  545. loopx/control_plane/status/runtime_summaries.py +161 -0
  546. loopx/control_plane/testing/__init__.py +1 -0
  547. loopx/control_plane/testing/actual_default_model_behavior_portfolio.py +1371 -0
  548. loopx/control_plane/testing/canary_harness.py +182 -0
  549. loopx/control_plane/testing/capability_monitor_repair_tool_behavior.py +674 -0
  550. loopx/control_plane/testing/cli_output_budget.py +807 -0
  551. loopx/control_plane/testing/cli_output_differential.py +250 -0
  552. loopx/control_plane/testing/cli_output_semantics.py +87 -0
  553. loopx/control_plane/testing/control_plane_composition_scenarios.py +225 -0
  554. loopx/control_plane/testing/decision_replay.py +268 -0
  555. loopx/control_plane/testing/doubao_model_behavior_actor.py +559 -0
  556. loopx/control_plane/testing/model_behavior_corpus.py +344 -0
  557. loopx/control_plane/testing/model_behavior_qualification.py +769 -0
  558. loopx/control_plane/testing/model_behavior_retained_cases.py +235 -0
  559. loopx/control_plane/testing/model_tool_behavior.py +536 -0
  560. loopx/control_plane/testing/onboarding_model_behavior_qualification.py +642 -0
  561. loopx/control_plane/testing/quota_fixtures.py +208 -0
  562. loopx/control_plane/testing/quota_should_run_parity.py +57 -0
  563. loopx/control_plane/testing/release_commit_qualification.py +671 -0
  564. loopx/control_plane/testing/replan_semantic_action_behavior.py +1302 -0
  565. loopx/control_plane/testing/scoped_gate_successor_tool_behavior.py +527 -0
  566. loopx/control_plane/testing/selected_todo_tool_behavior.py +1002 -0
  567. loopx/control_plane/testing/terminal_settlement_tool_behavior.py +656 -0
  568. loopx/control_plane/todos/__init__.py +1 -0
  569. loopx/control_plane/todos/active_state_editing.py +296 -0
  570. loopx/control_plane/todos/active_state_todo_parser.py +138 -0
  571. loopx/control_plane/todos/active_state_todos.py +175 -0
  572. loopx/control_plane/todos/addition.py +103 -0
  573. loopx/control_plane/todos/claim_visibility.py +253 -0
  574. loopx/control_plane/todos/completed_archive.py +139 -0
  575. loopx/control_plane/todos/completion_fence.py +49 -0
  576. loopx/control_plane/todos/completion_policy.py +153 -0
  577. loopx/control_plane/todos/completion_validation.py +248 -0
  578. loopx/control_plane/todos/completion_validation_accountability.py +27 -0
  579. loopx/control_plane/todos/completion_validation_projection.py +57 -0
  580. loopx/control_plane/todos/contract.py +1476 -0
  581. loopx/control_plane/todos/decision_scope.py +554 -0
  582. loopx/control_plane/todos/deferred_resume.py +546 -0
  583. loopx/control_plane/todos/durable_completion.py +201 -0
  584. loopx/control_plane/todos/event_writeback.py +484 -0
  585. loopx/control_plane/todos/frontier_deadline.py +132 -0
  586. loopx/control_plane/todos/handoff_gate.py +283 -0
  587. loopx/control_plane/todos/handoff_mode.py +444 -0
  588. loopx/control_plane/todos/handoff_note.py +202 -0
  589. loopx/control_plane/todos/line_update.py +361 -0
  590. loopx/control_plane/todos/list_projection.py +205 -0
  591. loopx/control_plane/todos/markdown.py +199 -0
  592. loopx/control_plane/todos/monitor_metadata.py +88 -0
  593. loopx/control_plane/todos/mutation_authority.py +299 -0
  594. loopx/control_plane/todos/projection.py +655 -0
  595. loopx/control_plane/todos/quota_summary.py +1138 -0
  596. loopx/control_plane/todos/route_continuation.py +267 -0
  597. loopx/control_plane/todos/succession_warning.py +174 -0
  598. loopx/control_plane/todos/summary_item.py +223 -0
  599. loopx/control_plane/todos/text.py +30 -0
  600. loopx/control_plane/todos/todo_index.py +226 -0
  601. loopx/control_plane/todos/todo_summary.py +1458 -0
  602. loopx/control_plane/todos/unblock_resume.py +326 -0
  603. loopx/control_plane/todos/user_gate.py +263 -0
  604. loopx/control_plane/todos/write_hint.py +63 -0
  605. loopx/control_plane/todos/write_policy.py +135 -0
  606. loopx/control_plane/turn_driver/__init__.py +85 -0
  607. loopx/control_plane/turn_driver/codex_cli.py +502 -0
  608. loopx/control_plane/turn_driver/driver.py +355 -0
  609. loopx/control_plane/turn_driver/executor.py +1468 -0
  610. loopx/control_plane/turn_driver/loop_controller.py +669 -0
  611. loopx/control_plane/turn_driver/settlement.py +318 -0
  612. loopx/control_plane/turn_driver/transaction.py +375 -0
  613. loopx/control_plane/work_items/__init__.py +1 -0
  614. loopx/control_plane/work_items/attention_fields.py +56 -0
  615. loopx/control_plane/work_items/attention_item.py +77 -0
  616. loopx/control_plane/work_items/attention_queue.py +322 -0
  617. loopx/control_plane/work_items/attention_routing.py +213 -0
  618. loopx/control_plane/work_items/autonomous_candidates.py +135 -0
  619. loopx/control_plane/work_items/autonomous_replan_ack.py +276 -0
  620. loopx/control_plane/work_items/autonomous_replan_obligation.py +786 -0
  621. loopx/control_plane/work_items/backlog_hygiene.py +59 -0
  622. loopx/control_plane/work_items/capability_monitor_fallback.py +221 -0
  623. loopx/control_plane/work_items/delivery_batch_scale.py +66 -0
  624. loopx/control_plane/work_items/delivery_outcome.py +152 -0
  625. loopx/control_plane/work_items/delivery_signals.py +113 -0
  626. loopx/control_plane/work_items/execution_obligation.py +235 -0
  627. loopx/control_plane/work_items/goal_route_hint.py +320 -0
  628. loopx/control_plane/work_items/interaction_contract.py +1540 -0
  629. loopx/control_plane/work_items/issue_meta_surface.py +159 -0
  630. loopx/control_plane/work_items/lifecycle.py +139 -0
  631. loopx/control_plane/work_items/operator_inbox.py +266 -0
  632. loopx/control_plane/work_items/outcome_followthrough.py +69 -0
  633. loopx/control_plane/work_items/primary_action.py +326 -0
  634. loopx/control_plane/work_items/progress_observation.py +630 -0
  635. loopx/control_plane/work_items/project_asset.py +675 -0
  636. loopx/control_plane/work_items/repair_delta.py +693 -0
  637. loopx/control_plane/work_items/runtime_capability_reentry.py +168 -0
  638. loopx/control_plane/work_items/semantic_replan_writeback.py +177 -0
  639. loopx/control_plane/work_items/status_contract.py +49 -0
  640. loopx/control_plane/work_items/task_graph.py +1046 -0
  641. loopx/control_plane/work_items/task_lease.py +1254 -0
  642. loopx/control_plane/work_items/task_lease_settlement.py +422 -0
  643. loopx/control_plane/work_items/work_lane.py +510 -0
  644. loopx/control_plane/work_items/work_lane_context.py +161 -0
  645. loopx/demo.py +247 -0
  646. loopx/diagnose.py +633 -0
  647. loopx/doctor.py +1251 -0
  648. loopx/domain_packs/__init__.py +1 -0
  649. loopx/domain_packs/issue_fix.py +571 -0
  650. loopx/domain_packs/ml_experiment.py +854 -0
  651. loopx/domain_state.py +137 -0
  652. loopx/dreaming.py +706 -0
  653. loopx/entrypoint.py +16 -0
  654. loopx/event_sourced_state.py +981 -0
  655. loopx/execution_profile.py +286 -0
  656. loopx/experiments/__init__.py +1 -0
  657. loopx/experiments/planner_worker/__init__.py +1 -0
  658. loopx/experiments/planner_worker/contract.py +523 -0
  659. loopx/experiments/planner_worker/runtime.py +391 -0
  660. loopx/experiments/planner_worker/traex.py +461 -0
  661. loopx/explore_graph.py +11 -0
  662. loopx/extensions/__init__.py +1 -0
  663. loopx/extensions/bundled.py +28 -0
  664. loopx/extensions/execution_envelope.py +126 -0
  665. loopx/extensions/lark/__init__.py +11 -0
  666. loopx/extensions/lark/event_collector.py +478 -0
  667. loopx/extensions/lark/event_collector_runtime.py +506 -0
  668. loopx/extensions/lark/event_inbox.py +454 -0
  669. loopx/extensions/lark/extension.toml +88 -0
  670. loopx/extensions/lark/goal_channel.py +44 -0
  671. loopx/extensions/lark/goal_channel_contracts.py +388 -0
  672. loopx/extensions/lark/goal_channel_lifecycle.py +218 -0
  673. loopx/extensions/lark/goal_channel_runtime.py +792 -0
  674. loopx/extensions/lark/goal_channel_setup.py +805 -0
  675. loopx/extensions/lark/goal_channel_targets.py +215 -0
  676. loopx/extensions/lark/goal_channel_transport.py +281 -0
  677. loopx/extensions/lark/inbox_reactions.py +650 -0
  678. loopx/extensions/lark/inbox_reply.py +430 -0
  679. loopx/extensions/lark/presentation/__init__.py +11 -0
  680. loopx/extensions/lark/presentation/explore_results.py +2276 -0
  681. loopx/extensions/lark/presentation/explore_singleflight.py +127 -0
  682. loopx/extensions/lark/presentation/explore_source_guard.py +121 -0
  683. loopx/extensions/lark/presentation/explore_stage_document.py +703 -0
  684. loopx/extensions/lark/presentation/explore_visual_integrity.py +122 -0
  685. loopx/extensions/lark/presentation/explore_visual_readback.py +452 -0
  686. loopx/extensions/lark/presentation/explore_visual_styles.py +156 -0
  687. loopx/extensions/lark/presentation/issue_fix_surface.py +612 -0
  688. loopx/extensions/lark/presentation/kanban.py +2791 -0
  689. loopx/extensions/lark/presentation/message_card.py +112 -0
  690. loopx/extensions/lark/presentation/periodic_report.py +261 -0
  691. loopx/extensions/lark/presentation/projection_rows.py +600 -0
  692. loopx/extensions/lark/presentation/record_io.py +95 -0
  693. loopx/extensions/lark/presentation/sync_receipt.py +145 -0
  694. loopx/extensions/lark/private_json.py +40 -0
  695. loopx/extensions/lark/provider.py +86 -0
  696. loopx/extensions/lark/reviewer_notification.py +604 -0
  697. loopx/extensions/manifest.py +385 -0
  698. loopx/extensions/openviking_periodic_report/__init__.py +17 -0
  699. loopx/extensions/openviking_periodic_report/activation.py +173 -0
  700. loopx/extensions/openviking_periodic_report/extension.toml +17 -0
  701. loopx/extensions/openviking_periodic_report/provider.py +355 -0
  702. loopx/extensions/openviking_periodic_report/sink.py +117 -0
  703. loopx/extensions/openviking_semantic_preference/__init__.py +5 -0
  704. loopx/extensions/openviking_semantic_preference/extension.toml +16 -0
  705. loopx/extensions/openviking_semantic_preference/history_export.py +484 -0
  706. loopx/extensions/openviking_semantic_preference/project_peer.py +68 -0
  707. loopx/extensions/openviking_semantic_preference/provider.py +312 -0
  708. loopx/extensions/presentation.py +979 -0
  709. loopx/extensions/process_runtime.py +204 -0
  710. loopx/extensions/readiness.py +168 -0
  711. loopx/extensions/runtime.py +931 -0
  712. loopx/extensions/scaffold.py +335 -0
  713. loopx/feedback.py +581 -0
  714. loopx/file_lock.py +382 -0
  715. loopx/global_registry.py +842 -0
  716. loopx/global_risks.py +970 -0
  717. loopx/global_todos.py +568 -0
  718. loopx/handoff_budget.py +28 -0
  719. loopx/heartbeat_prequota.py +80 -0
  720. loopx/heartbeat_prompt.py +159 -0
  721. loopx/help_surface.py +516 -0
  722. loopx/history.py +1507 -0
  723. loopx/host_loop_activation.py +1311 -0
  724. loopx/host_mode_planner.py +991 -0
  725. loopx/install_contract.py +1 -0
  726. loopx/interface_budget.py +196 -0
  727. loopx/long_task_cadence.py +208 -0
  728. loopx/materials.py +185 -0
  729. loopx/ml_experiment.py +3 -0
  730. loopx/onboarding.py +214 -0
  731. loopx/opencode2_goal_mode/README.md +81 -0
  732. loopx/opencode2_goal_mode/__init__.py +9 -0
  733. loopx/opencode2_goal_mode/opencode2-goal-worker.mjs +1018 -0
  734. loopx/opencode_goal_mode/README.md +99 -0
  735. loopx/opencode_goal_mode/__init__.py +13 -0
  736. loopx/opencode_goal_mode/goal-bridge-runtime.mjs +858 -0
  737. loopx/opencode_goal_mode/loopx-goal.js +8 -0
  738. loopx/operator_gate.py +420 -0
  739. loopx/orchestration.py +127 -0
  740. loopx/paths.py +59 -0
  741. loopx/pi_goal_mode/README.md +67 -0
  742. loopx/pi_goal_mode/__init__.py +13 -0
  743. loopx/pi_goal_mode/loopx-goal.ts +254 -0
  744. loopx/pi_goal_mode/pi-goal-loop-runtime.mjs +574 -0
  745. loopx/pr_review.py +1206 -0
  746. loopx/presentation/__init__.py +1 -0
  747. loopx/presentation/explore_views.py +1334 -0
  748. loopx/presentation/markdown.py +61 -0
  749. loopx/presentation/projection_source_reconcile.py +140 -0
  750. loopx/presentation/public_safety.py +42 -0
  751. loopx/presentation/renderers/__init__.py +17 -0
  752. loopx/presentation/renderers/goal_channel_html.py +269 -0
  753. loopx/presentation/renderers/periodic_report_html.py +786 -0
  754. loopx/presentation/renderers/periodic_report_markdown.py +184 -0
  755. loopx/presentation/renderers/quota_event_markdown.py +116 -0
  756. loopx/presentation/renderers/quota_markdown.py +1112 -0
  757. loopx/presentation/renderers/status_markdown.py +1570 -0
  758. loopx/presentation/renderers/trajectory_hygiene_markdown.py +39 -0
  759. loopx/presentation/renderers/turn_envelope_markdown.py +33 -0
  760. loopx/presentation/sinks/__init__.py +5 -0
  761. loopx/presentation/sinks/openviking_periodic_report.py +7 -0
  762. loopx/presentation/static_site.py +691 -0
  763. loopx/presets.py +369 -0
  764. loopx/project_alias.py +217 -0
  765. loopx/project_map.py +589 -0
  766. loopx/project_prompt.py +1153 -0
  767. loopx/project_skill_cli.py +125 -0
  768. loopx/project_skill_delivery.py +470 -0
  769. loopx/project_uninstall.py +462 -0
  770. loopx/promotion_gate.py +197 -0
  771. loopx/quota.py +1197 -0
  772. loopx/ready_score.py +413 -0
  773. loopx/registry.py +621 -0
  774. loopx/registry_writability.py +64 -0
  775. loopx/release_candidate.py +148 -0
  776. loopx/release_manifest.py +316 -0
  777. loopx/repository_identity.py +100 -0
  778. loopx/review_packet.py +1024 -0
  779. loopx/rollout_event_log.py +505 -0
  780. loopx/runtime.py +112 -0
  781. loopx/self_update.py +750 -0
  782. loopx/session_runtime.py +418 -0
  783. loopx/skill_install_readback.py +500 -0
  784. loopx/slash_command_install.py +1393 -0
  785. loopx/slash_commands.py +264 -0
  786. loopx/state_backup.py +573 -0
  787. loopx/state_migration.py +350 -0
  788. loopx/state_projection.py +809 -0
  789. loopx/state_refresh.py +1416 -0
  790. loopx/status.py +1383 -0
  791. loopx/status_server.py +935 -0
  792. loopx/summary_all.py +725 -0
  793. loopx/terminal_bench_agent.py +2056 -0
  794. loopx/thread_agent_binding.py +408 -0
  795. loopx/todo_followups.py +168 -0
  796. loopx/todo_suggestion_prompt.py +204 -0
  797. loopx/todos.py +2229 -0
  798. loopx/turn_identity.py +17 -0
  799. loopx/upgrade.py +1083 -0
  800. loopx/visible_governance.py +667 -0
  801. loopx/visible_multi_agent_launcher.py +1253 -0
  802. loopx/visible_multi_agent_tmux.py +429 -0
  803. loopx/worker_bridge.py +1574 -0
  804. loopx-0.4.8.dist-info/METADATA +708 -0
  805. loopx-0.4.8.dist-info/RECORD +811 -0
  806. loopx-0.4.8.dist-info/WHEEL +5 -0
  807. loopx-0.4.8.dist-info/entry_points.txt +5 -0
  808. loopx-0.4.8.dist-info/licenses/LICENSE +202 -0
  809. loopx-0.4.8.dist-info/licenses/LICENSE-MIT +21 -0
  810. loopx-0.4.8.dist-info/licenses/NOTICE +6 -0
  811. loopx-0.4.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,669 @@
1
+ """Pure Turn Loop Controller transition contract.
2
+
3
+ This module decides the next disposition of a governed loop from one validated
4
+ Turn receipt plus a fresh quota/scheduler decision. It is a pure function: it
5
+ never invokes a model, sleeps, mutates a host scheduler, writes state, or
6
+ spends quota. `loopx turn run-once` remains the only delivery transaction;
7
+ scheduler process management, host wake APIs, and operator presentation belong
8
+ to later adapters (see the Turn Loop Controller plan in CONTRIBUTOR_TASKS).
9
+
10
+ The transition output space is exactly six dispositions:
11
+ ``run_now | wait | user_action_required | repair | replan | terminal``.
12
+
13
+ Input validity is enforced at the typed-input boundary, not encoded as a
14
+ seventh disposition. ``decide_loop_disposition`` raises ``ValueError`` when a
15
+ receipt, envelope, or budget cannot be proven against the shared Turn
16
+ contracts, so the caller is responsible for feeding only validated, fresh
17
+ inputs.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ from collections.abc import Mapping
23
+ from enum import Enum
24
+ from typing import Any
25
+
26
+ from ..effect_program import SettlementStepKind
27
+ from .driver import LoopXTurnRoute, _typed_route, selected_turn_todo
28
+ from .transaction import (
29
+ LOOPX_TURN_EXECUTION_SCHEMA_VERSION,
30
+ LOOPX_TURN_RECEIPT_VALIDATION_SCHEMA_VERSION,
31
+ LoopXTurnResultKind,
32
+ require_loopx_turn_completion_outcome,
33
+ )
34
+
35
+ LOOP_CONTROLLER_DISPOSITION_SCHEMA_VERSION = "loop_turn_loop_disposition_v0"
36
+ BOUNDED_TURN_BUDGET_SCHEMA_VERSION = "loop_bounded_turn_budget_v0"
37
+ VALIDATED_TURN_RECEIPT_SCHEMA_VERSION = "loop_validated_turn_receipt_v0"
38
+
39
+ # Material result kinds that prove a durable delivery effect and may therefore
40
+ # drive a terminal or progress transition. They require a fully committed
41
+ # transaction (all seven phases), not a validation-only intermediate.
42
+ _MATERIAL_PROGRESS_KINDS = {
43
+ LoopXTurnResultKind.VALIDATED_COMPLETION,
44
+ LoopXTurnResultKind.VALIDATED_PROGRESS,
45
+ }
46
+ _MATERIAL_RECEIPT_ORDER = (
47
+ SettlementStepKind.VALIDATION.value,
48
+ SettlementStepKind.DURABLE_WRITEBACK.value,
49
+ SettlementStepKind.QUOTA_SPEND.value,
50
+ )
51
+
52
+
53
+ class LoopDisposition(str, Enum):
54
+ RUN_NOW = "run_now"
55
+ WAIT = "wait"
56
+ USER_ACTION_REQUIRED = "user_action_required"
57
+ REPAIR = "repair"
58
+ REPLAN = "replan"
59
+ TERMINAL = "terminal"
60
+
61
+
62
+ def _mapping(value: Any) -> dict[str, Any]:
63
+ return dict(value) if isinstance(value, Mapping) else {}
64
+
65
+
66
+ def _disposition(
67
+ disposition: LoopDisposition,
68
+ *,
69
+ reason: str,
70
+ lineage: Mapping[str, str] | None = None,
71
+ extra: Mapping[str, Any] | None = None,
72
+ ) -> dict[str, Any]:
73
+ payload: dict[str, Any] = {
74
+ "schema_version": LOOP_CONTROLLER_DISPOSITION_SCHEMA_VERSION,
75
+ "disposition": disposition.value,
76
+ "reason": reason,
77
+ "spends_quota": False,
78
+ "launches_host": False,
79
+ "writes_state": False,
80
+ }
81
+ if lineage:
82
+ payload["lineage"] = dict(lineage)
83
+ if extra:
84
+ payload.update(dict(extra))
85
+ return payload
86
+
87
+
88
+ def _decision_lineage(decision: Mapping[str, Any]) -> dict[str, str]:
89
+ selected_todo = selected_turn_todo(decision)
90
+ return {
91
+ "goal_id": str(decision.get("goal_id") or ""),
92
+ "agent_id": str(decision.get("agent_id") or ""),
93
+ "todo_id": str(selected_todo.get("todo_id") or ""),
94
+ }
95
+
96
+
97
+ def _envelope_route(decision: Mapping[str, Any]) -> LoopXTurnRoute:
98
+ """Return the shared typed route for a fresh quota/scheduler decision.
99
+
100
+ Reuses the Turn plan driver's ``_typed_route`` contract, which requires a
101
+ matching action signature with non-empty equal hashes and an in-budget
102
+ compaction. A projected user action outranks delivery, so it is resolved
103
+ before the typed delivery route. Raises ``ValueError`` when the envelope
104
+ fails the shared contract instead of accepting a forged or truncated
105
+ decision.
106
+ """
107
+
108
+ route = _typed_route(decision)
109
+ if route is LoopXTurnRoute.CONTRACT_ERROR:
110
+ raise ValueError(
111
+ "quota decision failed the shared envelope contract "
112
+ "(schema, signature hashes, or compaction budget)"
113
+ )
114
+ user = _mapping(decision.get("user"))
115
+ if user.get("action_required") is True:
116
+ return LoopXTurnRoute.USER_ACTION_REQUIRED
117
+ return route
118
+
119
+
120
+ def _route_to_disposition(route: LoopXTurnRoute) -> LoopDisposition:
121
+ return {
122
+ LoopXTurnRoute.READY_FOR_HOST: LoopDisposition.RUN_NOW,
123
+ LoopXTurnRoute.REPLAN_REQUIRED: LoopDisposition.REPLAN,
124
+ LoopXTurnRoute.REPAIR_REQUIRED: LoopDisposition.REPAIR,
125
+ LoopXTurnRoute.USER_ACTION_REQUIRED: LoopDisposition.USER_ACTION_REQUIRED,
126
+ LoopXTurnRoute.WAIT: LoopDisposition.WAIT,
127
+ LoopXTurnRoute.BLOCKED: LoopDisposition.WAIT,
128
+ }[route]
129
+
130
+
131
+ class ValidatedTurnReceipt:
132
+ """A controller view qualified from one complete Turn execution.
133
+
134
+ Material results are admitted only when the public execution proves the
135
+ M7 typed settlement receipt sequence, one stable effect identity, durable
136
+ writeback and spend, and a completed scheduler handoff. Todo completion
137
+ additionally retains its durable continuation outcome so a local Todo
138
+ completion cannot be confused with Goal terminal closure.
139
+ """
140
+
141
+ __slots__ = (
142
+ "lineage",
143
+ "result_kind",
144
+ "settlement_effect_id",
145
+ "status",
146
+ "todo_completion",
147
+ "turn_key",
148
+ )
149
+
150
+ def __init__(
151
+ self,
152
+ *,
153
+ result_kind: LoopXTurnResultKind,
154
+ status: str,
155
+ lineage: Mapping[str, str],
156
+ turn_key: str | None,
157
+ settlement_effect_id: str | None = None,
158
+ todo_completion: Mapping[str, Any] | None = None,
159
+ ) -> None:
160
+ self.result_kind = result_kind
161
+ self.status = status
162
+ self.lineage = {
163
+ "goal_id": str(lineage.get("goal_id") or ""),
164
+ "agent_id": str(lineage.get("agent_id") or ""),
165
+ "todo_id": str(lineage.get("todo_id") or ""),
166
+ }
167
+ self.turn_key = turn_key
168
+ self.settlement_effect_id = settlement_effect_id
169
+ self.todo_completion = dict(todo_completion or {}) or None
170
+
171
+ @classmethod
172
+ def from_execution(
173
+ cls, execution_payload: Mapping[str, Any]
174
+ ) -> ValidatedTurnReceipt:
175
+ execution = _mapping(execution_payload)
176
+ if execution.get("schema_version") != LOOPX_TURN_EXECUTION_SCHEMA_VERSION:
177
+ raise ValueError(
178
+ "validated turn receipt requires schema_version="
179
+ f"{LOOPX_TURN_EXECUTION_SCHEMA_VERSION}"
180
+ )
181
+ receipt = _mapping(execution.get("receipt"))
182
+ if receipt.get("schema_version") != LOOPX_TURN_RECEIPT_VALIDATION_SCHEMA_VERSION:
183
+ raise ValueError(
184
+ "validated turn receipt requires schema_version="
185
+ f"{LOOPX_TURN_RECEIPT_VALIDATION_SCHEMA_VERSION}"
186
+ )
187
+ if receipt.get("ok") is not True:
188
+ raise ValueError("validated turn receipt requires ok=true")
189
+ raw_kind = receipt.get("result_kind")
190
+ try:
191
+ result_kind = LoopXTurnResultKind(str(raw_kind or ""))
192
+ except ValueError:
193
+ raise ValueError(
194
+ f"validated turn receipt has unsupported result_kind {raw_kind!r}"
195
+ ) from None
196
+ if execution.get("result_kind") != result_kind.value:
197
+ raise ValueError("execution result_kind does not match its receipt")
198
+ status = str(receipt.get("status") or "")
199
+ if result_kind in _MATERIAL_PROGRESS_KINDS and (
200
+ status != "committed" or execution.get("status") != "committed"
201
+ ):
202
+ raise ValueError(
203
+ f"material result {result_kind.value} requires a fully committed "
204
+ "Turn execution and receipt"
205
+ )
206
+ lineage = _mapping(receipt.get("lineage"))
207
+ if not all(lineage.get(k) for k in ("goal_id", "agent_id", "todo_id")):
208
+ raise ValueError(
209
+ "validated turn receipt is missing goal/agent/todo lineage"
210
+ )
211
+ turn_key = str(receipt.get("turn_key") or "") or None
212
+ if not turn_key:
213
+ raise ValueError("validated turn receipt is missing turn_key")
214
+ settlement_effect_id = str(receipt.get("settlement_effect_id") or "") or None
215
+ todo_completion = _mapping(execution.get("todo_completion"))
216
+ if result_kind in _MATERIAL_PROGRESS_KINDS:
217
+ settlement_effect_id = _qualified_material_effect_id(
218
+ execution,
219
+ expected_effect_id=settlement_effect_id,
220
+ )
221
+ if result_kind is LoopXTurnResultKind.VALIDATED_COMPLETION:
222
+ todo_completion = require_loopx_turn_completion_outcome(
223
+ todo_completion,
224
+ expected_todo_id=str(lineage["todo_id"]),
225
+ )
226
+ return cls(
227
+ result_kind=result_kind,
228
+ status=status,
229
+ lineage=lineage,
230
+ turn_key=turn_key,
231
+ settlement_effect_id=settlement_effect_id,
232
+ todo_completion=todo_completion,
233
+ )
234
+
235
+ def to_mapping(self) -> dict[str, Any]:
236
+ return {
237
+ "schema_version": VALIDATED_TURN_RECEIPT_SCHEMA_VERSION,
238
+ "result_kind": self.result_kind.value,
239
+ "status": self.status,
240
+ "lineage": dict(self.lineage),
241
+ "turn_key": self.turn_key,
242
+ "settlement_effect_id": self.settlement_effect_id,
243
+ **(
244
+ {"todo_completion": dict(self.todo_completion)}
245
+ if self.todo_completion
246
+ else {}
247
+ ),
248
+ }
249
+
250
+
251
+ def _qualified_material_effect_id(
252
+ execution: Mapping[str, Any],
253
+ *,
254
+ expected_effect_id: str | None,
255
+ ) -> str:
256
+ settlement = _mapping(execution.get("settlement_result"))
257
+ if settlement.get("ok") is not True or settlement.get("failure") is not None:
258
+ raise ValueError("material Turn execution requires a successful settlement")
259
+ raw_receipts = settlement.get("receipts")
260
+ if not isinstance(raw_receipts, list):
261
+ raise TypeError("material Turn execution is missing settlement receipts")
262
+ receipts = [_mapping(item) for item in raw_receipts]
263
+ if [str(item.get("step_kind") or "") for item in receipts] != list(
264
+ _MATERIAL_RECEIPT_ORDER
265
+ ):
266
+ raise ValueError(
267
+ "material Turn execution requires ordered validation/writeback/spend receipts"
268
+ )
269
+ effect_ids = {str(item.get("effect_id") or "") for item in receipts}
270
+ if "" in effect_ids or len(effect_ids) != 1:
271
+ raise ValueError("material Turn settlement receipts must share one effect identity")
272
+ effect_id = next(iter(effect_ids))
273
+ if not expected_effect_id or expected_effect_id != effect_id:
274
+ raise ValueError(
275
+ "material Turn settlement identity does not match the transaction receipt"
276
+ )
277
+ if any(item.get("status") != "committed" for item in receipts):
278
+ raise ValueError("material Turn settlement receipts must be committed")
279
+ effects = _mapping(execution.get("effects"))
280
+ if effects.get("state_written") is not True or effects.get("quota_spent") is not True:
281
+ raise ValueError("material Turn execution is missing durable effect evidence")
282
+ scheduler = _mapping(execution.get("scheduler"))
283
+ if scheduler.get("completed") is not True:
284
+ raise ValueError("material Turn execution is missing completed scheduler handoff")
285
+ return effect_id
286
+
287
+
288
+ class BoundedTurnBudget:
289
+ """A provider-neutral bounded Turn budget tied to one lineage.
290
+
291
+ Construction enforces strict integer domains (booleans are rejected) and a
292
+ sane range, so the transition never guesses an unbounded continuation.
293
+ """
294
+
295
+ __slots__ = ("completed_turns", "lineage", "max_turns")
296
+
297
+ def __init__(
298
+ self,
299
+ *,
300
+ lineage: Mapping[str, str],
301
+ max_turns: int,
302
+ completed_turns: int,
303
+ ) -> None:
304
+ if type(max_turns) is not int:
305
+ raise ValueError("bounded turn budget max_turns must be an int")
306
+ if type(completed_turns) is not int:
307
+ raise ValueError("bounded turn budget completed_turns must be an int")
308
+ if max_turns <= 0:
309
+ raise ValueError("bounded turn budget max_turns must be > 0")
310
+ if completed_turns < 0:
311
+ raise ValueError("bounded turn budget completed_turns must be >= 0")
312
+ if completed_turns > max_turns:
313
+ raise ValueError(
314
+ "bounded turn budget completed_turns must be <= max_turns"
315
+ )
316
+ self.lineage = {
317
+ "goal_id": str(lineage.get("goal_id") or ""),
318
+ "agent_id": str(lineage.get("agent_id") or ""),
319
+ "todo_id": str(lineage.get("todo_id") or ""),
320
+ }
321
+ if not all(self.lineage.values()):
322
+ raise ValueError("bounded turn budget is missing goal/agent/todo lineage")
323
+ self.max_turns = max_turns
324
+ self.completed_turns = completed_turns
325
+
326
+ def to_mapping(self) -> dict[str, Any]:
327
+ return {
328
+ "schema_version": BOUNDED_TURN_BUDGET_SCHEMA_VERSION,
329
+ "lineage": dict(self.lineage),
330
+ "max_turns": self.max_turns,
331
+ "completed_turns": self.completed_turns,
332
+ }
333
+
334
+ @property
335
+ def remaining(self) -> int:
336
+ return self.max_turns - self.completed_turns
337
+
338
+
339
+ def _assert_goal_agent_match(
340
+ *,
341
+ receipt_lineage: Mapping[str, str],
342
+ decision_lineage: Mapping[str, str],
343
+ ) -> None:
344
+ for key in ("goal_id", "agent_id"):
345
+ if receipt_lineage.get(key) != decision_lineage.get(key):
346
+ raise ValueError(
347
+ "stale_receipt: receipt lineage does not match the fresh decision "
348
+ f"on {key} (receipt={receipt_lineage.get(key)!r}, "
349
+ f"decision={decision_lineage.get(key)!r})"
350
+ )
351
+
352
+
353
+ def _assert_same_todo(
354
+ *,
355
+ receipt_lineage: Mapping[str, str],
356
+ decision_lineage: Mapping[str, str],
357
+ ) -> None:
358
+ if receipt_lineage.get("todo_id") != decision_lineage.get("todo_id"):
359
+ raise ValueError(
360
+ "stale_receipt: receipt Todo does not match the fresh decision "
361
+ f"(receipt={receipt_lineage.get('todo_id')!r}, "
362
+ f"decision={decision_lineage.get('todo_id')!r})"
363
+ )
364
+
365
+
366
+ def _assert_budget_lineage_match(
367
+ *,
368
+ budget_lineage: Mapping[str, str],
369
+ decision_lineage: Mapping[str, str],
370
+ ) -> None:
371
+ for key in ("goal_id", "agent_id", "todo_id"):
372
+ if budget_lineage.get(key) != decision_lineage.get(key):
373
+ raise ValueError(
374
+ "stale_budget: budget lineage does not match the fresh decision "
375
+ f"on {key} (budget={budget_lineage.get(key)!r}, "
376
+ f"decision={decision_lineage.get(key)!r})"
377
+ )
378
+
379
+
380
+ def _assert_predecessor_binding(
381
+ *,
382
+ receipt: ValidatedTurnReceipt,
383
+ predecessor_turn_key: str | None,
384
+ ) -> None:
385
+ """Prove the fresh envelope causally succeeds the receipt.
386
+
387
+ The outer adapter must bind the fresh decision to the receipt's
388
+ ``turn_key``. The causal assertion stays beside the envelope instead of
389
+ adding an unsigned field to ``loopx_turn_envelope_v0``.
390
+ """
391
+
392
+ predecessor = str(predecessor_turn_key or "")
393
+ if not predecessor:
394
+ raise ValueError(
395
+ "stale_receipt: continuation is missing predecessor_turn_key; "
396
+ "cannot prove causal succession from the receipt"
397
+ )
398
+ if predecessor != receipt.turn_key:
399
+ raise ValueError(
400
+ "stale_receipt: fresh decision predecessor_turn_key "
401
+ f"({predecessor!r}) does not match the receipt turn_key "
402
+ f"({receipt.turn_key!r})"
403
+ )
404
+
405
+
406
+ def _completion_disposition(
407
+ *,
408
+ receipt: ValidatedTurnReceipt,
409
+ decision: Mapping[str, Any],
410
+ decision_lineage: Mapping[str, str],
411
+ route: LoopXTurnRoute,
412
+ ) -> dict[str, Any]:
413
+ completion = dict(receipt.todo_completion or {})
414
+ continuation = str(completion.get("continuation") or "")
415
+ if continuation == "no_followup":
416
+ if (
417
+ decision.get("effective_action") != "terminal_no_followup"
418
+ or decision.get("state") != "terminal_no_followup"
419
+ ):
420
+ raise ValueError(
421
+ "no_followup completion requires fresh terminal Goal frontier evidence"
422
+ )
423
+ return _disposition(
424
+ LoopDisposition.TERMINAL,
425
+ reason="durable no-follow-up and fresh Goal frontier prove terminal closure",
426
+ lineage=receipt.lineage,
427
+ )
428
+
429
+ selected_todo_id = str(decision_lineage.get("todo_id") or "")
430
+ if not selected_todo_id:
431
+ raise ValueError("Todo completion continuation requires a fresh selected Todo")
432
+ if continuation == "successor":
433
+ successor_ids = completion.get("successor_todo_ids")
434
+ if not isinstance(successor_ids, list) or selected_todo_id not in successor_ids:
435
+ raise ValueError(
436
+ "stale_receipt: fresh decision is not a declared completion successor"
437
+ )
438
+ elif continuation == "active_goal" and selected_todo_id == receipt.lineage["todo_id"]:
439
+ raise ValueError(
440
+ "stale_receipt: active Goal continuation reselected the completed Todo"
441
+ )
442
+
443
+ if route is LoopXTurnRoute.USER_ACTION_REQUIRED:
444
+ return _disposition(
445
+ LoopDisposition.USER_ACTION_REQUIRED,
446
+ reason="fresh decision projects a concrete user action after Todo completion",
447
+ lineage=decision_lineage,
448
+ )
449
+ disposition = _route_to_disposition(route)
450
+ if disposition is LoopDisposition.REPLAN:
451
+ return _replan_disposition(
452
+ reason="fresh decision requires replan after Todo completion",
453
+ decision_lineage=decision_lineage,
454
+ )
455
+ return _disposition(
456
+ disposition,
457
+ reason=(
458
+ "durable Todo completion continues through its declared successor"
459
+ if continuation == "successor"
460
+ else "durable Todo completion continues through the fresh Goal frontier"
461
+ ),
462
+ lineage=decision_lineage,
463
+ )
464
+
465
+
466
+ def decide_loop_disposition(
467
+ *,
468
+ turn_receipt: ValidatedTurnReceipt | None,
469
+ quota_decision: Mapping[str, Any],
470
+ predecessor_turn_key: str | None = None,
471
+ bounded_turn_budget: BoundedTurnBudget | None = None,
472
+ ) -> dict[str, Any]:
473
+ """Decide the next loop disposition from one validated receipt and a fresh decision.
474
+
475
+ ``turn_receipt`` is a :class:`ValidatedTurnReceipt` (or ``None`` when no
476
+ prior Turn has committed). ``quota_decision`` is a fresh
477
+ ``loopx_turn_envelope_v0``. The outer adapter supplies a separate
478
+ ``predecessor_turn_key`` matching the receipt when one is present; this
479
+ keeps causal continuation out of the signed quota envelope schema.
480
+ ``bounded_turn_budget`` is required for ``validated_progress``.
481
+
482
+ The function is pure: it launches no host, writes no state, and spends no
483
+ quota. Invalid or stale input raises ``ValueError`` at the typed-input
484
+ boundary; the transition output space is always one of the six
485
+ :class:`LoopDisposition` values.
486
+ """
487
+
488
+ route = _envelope_route(quota_decision)
489
+ decision_lineage = _decision_lineage(quota_decision)
490
+ if not decision_lineage["goal_id"] or not decision_lineage["agent_id"]:
491
+ raise ValueError(
492
+ "fresh quota decision is missing goal/agent lineage"
493
+ )
494
+
495
+ if turn_receipt is None:
496
+ if str(quota_decision.get("effective_action") or "") == "terminal_no_followup":
497
+ if quota_decision.get("state") != "terminal_no_followup":
498
+ raise ValueError(
499
+ "terminal no-follow-up requires fresh Goal frontier state"
500
+ )
501
+ return _disposition(
502
+ LoopDisposition.TERMINAL,
503
+ reason="fresh Goal frontier proves terminal no-follow-up",
504
+ lineage=decision_lineage,
505
+ )
506
+ disposition = _route_to_disposition(route)
507
+ if not decision_lineage["todo_id"] and disposition not in {
508
+ LoopDisposition.WAIT,
509
+ LoopDisposition.USER_ACTION_REQUIRED,
510
+ }:
511
+ raise ValueError("executable quota decision is missing selected Todo lineage")
512
+ if disposition is LoopDisposition.REPLAN:
513
+ return _replan_disposition(
514
+ reason="fresh decision requires replan",
515
+ decision_lineage=decision_lineage,
516
+ )
517
+ return _disposition(
518
+ disposition,
519
+ reason=_no_receipt_reason(disposition),
520
+ lineage=decision_lineage,
521
+ )
522
+
523
+ # Prove the envelope causally succeeds this exact receipt before any
524
+ # disposition is considered. This closes the stale-replay gap: an old
525
+ # receipt for the same todo cannot be replayed against a later envelope.
526
+ _assert_predecessor_binding(
527
+ receipt=turn_receipt,
528
+ predecessor_turn_key=predecessor_turn_key,
529
+ )
530
+ _assert_goal_agent_match(
531
+ receipt_lineage=turn_receipt.lineage,
532
+ decision_lineage=decision_lineage,
533
+ )
534
+
535
+ result_kind = turn_receipt.result_kind
536
+
537
+ if result_kind is LoopXTurnResultKind.VALIDATED_COMPLETION:
538
+ return _completion_disposition(
539
+ receipt=turn_receipt,
540
+ decision=quota_decision,
541
+ decision_lineage=decision_lineage,
542
+ route=route,
543
+ )
544
+
545
+ effective_lineage = dict(decision_lineage)
546
+ if decision_lineage["todo_id"]:
547
+ _assert_same_todo(
548
+ receipt_lineage=turn_receipt.lineage,
549
+ decision_lineage=decision_lineage,
550
+ )
551
+ elif (
552
+ result_kind is LoopXTurnResultKind.VALIDATED_PROGRESS
553
+ and route
554
+ not in {LoopXTurnRoute.USER_ACTION_REQUIRED, LoopXTurnRoute.WAIT}
555
+ ):
556
+ raise ValueError("receipt-backed executable decision is missing selected Todo lineage")
557
+ else:
558
+ # A valid user gate or quiet wait may intentionally have no runnable
559
+ # selected Todo. Preserve the committed predecessor lineage for that
560
+ # no-spend disposition instead of rejecting the envelope.
561
+ effective_lineage["todo_id"] = turn_receipt.lineage["todo_id"]
562
+
563
+ # Decision user action outranks every non-terminal disposition.
564
+ if route is LoopXTurnRoute.USER_ACTION_REQUIRED:
565
+ return _disposition(
566
+ LoopDisposition.USER_ACTION_REQUIRED,
567
+ reason="fresh decision projects a concrete user action",
568
+ lineage=effective_lineage,
569
+ )
570
+
571
+ if result_kind is LoopXTurnResultKind.VALIDATED_PROGRESS:
572
+ if bounded_turn_budget is None:
573
+ raise ValueError(
574
+ "validated progress cannot continue without a proven bounded turn budget"
575
+ )
576
+ _assert_budget_lineage_match(
577
+ budget_lineage=bounded_turn_budget.lineage,
578
+ decision_lineage=effective_lineage,
579
+ )
580
+ if bounded_turn_budget.remaining <= 0:
581
+ return _replan_disposition(
582
+ reason="bounded turn budget exhausted; replan before another Turn",
583
+ decision_lineage=effective_lineage,
584
+ )
585
+ disposition = _route_to_disposition(route)
586
+ if disposition is LoopDisposition.REPLAN:
587
+ return _replan_disposition(
588
+ reason="fresh decision requires replan after progress",
589
+ decision_lineage=effective_lineage,
590
+ )
591
+ return _disposition(
592
+ disposition,
593
+ reason=_progress_reason(disposition),
594
+ lineage=effective_lineage,
595
+ )
596
+
597
+ if result_kind is LoopXTurnResultKind.REPLAN_REQUIRED:
598
+ return _replan_disposition(
599
+ reason="turn receipt requires replan",
600
+ decision_lineage=effective_lineage,
601
+ )
602
+
603
+ if result_kind is LoopXTurnResultKind.REPAIR_REQUIRED:
604
+ return _disposition(
605
+ LoopDisposition.REPAIR,
606
+ reason="turn receipt requires repair",
607
+ lineage=effective_lineage,
608
+ )
609
+
610
+ if result_kind is LoopXTurnResultKind.USER_ACTION_REQUIRED:
611
+ return _disposition(
612
+ LoopDisposition.USER_ACTION_REQUIRED,
613
+ reason="turn receipt projects a concrete user action",
614
+ lineage=effective_lineage,
615
+ )
616
+
617
+ if result_kind is LoopXTurnResultKind.WAIT:
618
+ return _disposition(
619
+ LoopDisposition.WAIT,
620
+ reason="turn receipt is a typed no-spend wait",
621
+ lineage=effective_lineage,
622
+ )
623
+
624
+ # host_failure, validation_failed, writeback_failed, quota_spend_failed:
625
+ # the loop must not guess recovery on its own; hold for repair routing.
626
+ return _disposition(
627
+ LoopDisposition.REPAIR,
628
+ reason=(
629
+ f"turn receipt ended in {result_kind.value}; "
630
+ "route to repair before any successor turn"
631
+ ),
632
+ lineage=effective_lineage,
633
+ )
634
+
635
+
636
+ def _no_receipt_reason(disposition: LoopDisposition) -> str:
637
+ return {
638
+ LoopDisposition.RUN_NOW: "no prior receipt and fresh decision allows delivery",
639
+ LoopDisposition.WAIT: "fresh decision is a quiet no-spend wait",
640
+ LoopDisposition.REPAIR: "fresh decision requires repair",
641
+ LoopDisposition.USER_ACTION_REQUIRED: "fresh decision projects a concrete user action",
642
+ }[disposition]
643
+
644
+
645
+ def _progress_reason(disposition: LoopDisposition) -> str:
646
+ return {
647
+ LoopDisposition.RUN_NOW: "validated progress with fresh decision allowing the next turn",
648
+ LoopDisposition.WAIT: "validated progress but fresh decision does not allow the next turn yet",
649
+ LoopDisposition.REPAIR: "fresh decision requires repair after progress",
650
+ LoopDisposition.USER_ACTION_REQUIRED: "fresh decision projects a concrete user action",
651
+ }[disposition]
652
+
653
+
654
+ def _replan_disposition(
655
+ *, reason: str, decision_lineage: Mapping[str, str]
656
+ ) -> dict[str, Any]:
657
+ return _disposition(
658
+ LoopDisposition.REPLAN,
659
+ reason=reason,
660
+ lineage=decision_lineage,
661
+ extra={
662
+ "replan_continuation": {
663
+ "requires_bounded_delta": True,
664
+ "delta_kinds": ["todo_delta", "vision_delta"],
665
+ "stale_todo_rerun_allowed": False,
666
+ "fresh_envelope_required": True,
667
+ }
668
+ },
669
+ )