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
loopx/quota.py ADDED
@@ -0,0 +1,1197 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Callable, Mapping
4
+ from datetime import datetime, timedelta, timezone
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from .control_plane import compact_control_plane_policy
9
+ from .execution_profile import (
10
+ execution_profile_outcome_floor,
11
+ outcome_floor_threshold,
12
+ )
13
+ from .control_plane.quota.heartbeat_recommendation import (
14
+ HEARTBEAT_HANDOFF_READINESS_COMPACT_FIELDS as HANDOFF_READINESS_COMPACT_FIELDS,
15
+ HEARTBEAT_POST_HANDOFF_RUN_COMPACT_FIELDS as POST_HANDOFF_RUN_COMPACT_FIELDS,
16
+ )
17
+ from .control_plane.quota.decision_summary import (
18
+ goal_status_health_ok as _goal_status_health_ok,
19
+ )
20
+ from .control_plane.quota.goal_boundary import registry_goal_by_id as _registry_goal_by_id
21
+ from .control_plane.quota.policy_constants import (
22
+ AUTONOMOUS_CANDIDATE_CONTEXT_FIELDS, # noqa: F401
23
+ MONITOR_DUE_ITEM_LIMIT, # noqa: F401
24
+ )
25
+ from .control_plane.quota.monitor_poll import (
26
+ QUOTA_MONITOR_POLL_CLASSIFICATION as QUOTA_MONITOR_POLL_CLASSIFICATION,
27
+ build_quota_monitor_poll_event as build_quota_monitor_poll_event,
28
+ record_quota_monitor_poll_for_decision,
29
+ )
30
+ from .control_plane.quota.recent_runs import (
31
+ goal_latest_run as _goal_latest_run,
32
+ )
33
+ from .presentation.renderers.quota_event_markdown import render_quota_monitor_poll_markdown as _render_quota_monitor_poll_markdown, render_quota_slot_preview_markdown as _render_quota_slot_preview_markdown, render_quota_slot_preview_markdown as render_quota_slot_preview_markdown
34
+ from .presentation.renderers.quota_markdown import render_quota_markdown as render_quota_markdown, render_quota_scheduler_ack_markdown as render_quota_scheduler_ack_markdown, render_quota_should_run_markdown as render_quota_should_run_markdown
35
+ from .control_plane.quota.scheduler_ack import (
36
+ QUOTA_SCHEDULER_ACK_CLASSIFICATION,
37
+ record_quota_scheduler_ack_for_decision,
38
+ )
39
+ from .control_plane.quota.settlement import (
40
+ find_settlement_spend_run,
41
+ infer_persisted_heartbeat_settlement_identity,
42
+ require_settlement_spend,
43
+ require_settlement_writeback,
44
+ resolve_heartbeat_settlement_identity,
45
+ settlement_result_payload,
46
+ )
47
+ from .control_plane.quota.slot_accounting import (
48
+ QUOTA_SLOT_SPENT_CLASSIFICATION,
49
+ QUOTA_SLOT_VOIDED_CLASSIFICATION,
50
+ build_quota_slot_preview_for_decision,
51
+ build_quota_slot_spend_event as _build_quota_slot_spend_event,
52
+ build_quota_slot_void_event as build_quota_slot_void_event,
53
+ build_quota_slot_void_preview_for_decision,
54
+ load_quota_event_from_run,
55
+ record_quota_slot_spend_from_preview,
56
+ record_quota_slot_void_from_preview,
57
+ )
58
+ from .control_plane.quota.spend_sources import (
59
+ DEFAULT_SLOT_SPEND_SOURCE,
60
+ )
61
+ from .control_plane.quota.states import QUOTA_STATE_ORDER
62
+ from .control_plane.quota.policy_constants import (
63
+ DEFAULT_COMPUTE_QUOTA,
64
+ DEFAULT_SLOT_MINUTES,
65
+ DEFAULT_WINDOW_HOURS,
66
+ FOCUS_WAIT_LIFECYCLE_MARKERS,
67
+ FOCUS_WAIT_REASON,
68
+ SELF_REPAIR_SPEND_ACTIONS,
69
+ )
70
+ from .control_plane.runtime.time import parse_timestamp as _parse_timestamp
71
+ from .control_plane.scheduler.execution_context import (
72
+ SchedulerExecutionContextResolution,
73
+ )
74
+ from .control_plane.scheduler.state import (
75
+ CODEX_APP_STATEFUL_BACKOFF_STATE_KEY,
76
+ CODEX_APP_SURFACE,
77
+ )
78
+ from .control_plane.todos.contract import (
79
+ normalize_todo_claimed_by,
80
+ )
81
+ from .control_plane.todos.projection import (
82
+ todo_index_rank as projection_todo_index_rank,
83
+ todo_item_expires_at as projection_todo_item_expires_at,
84
+ todo_item_is_due_monitor as projection_todo_item_is_due_monitor,
85
+ todo_item_is_expired_monitor as projection_todo_item_is_expired_monitor,
86
+ todo_item_missing_monitor_schedule as projection_todo_item_missing_monitor_schedule,
87
+ todo_item_next_due_at as projection_todo_item_next_due_at,
88
+ todo_priority_label as projection_todo_priority_label,
89
+ todo_priority_rank as projection_todo_priority_rank,
90
+ todo_projection_sort_key as projection_todo_projection_sort_key,
91
+ todo_summary_claim_scope_agent_id as projection_todo_summary_claim_scope_agent_id,
92
+ )
93
+
94
+
95
+ _PUBLIC_COMPAT_REEXPORTS = {
96
+ "AUTONOMOUS_CANDIDATE_CONTEXT_FIELDS": "loopx.control_plane.quota.policy_constants",
97
+ "MONITOR_DUE_ITEM_LIMIT": "loopx.control_plane.quota.policy_constants",
98
+ "QUOTA_MONITOR_POLL_CLASSIFICATION": "loopx.control_plane.quota.monitor_poll",
99
+ "build_quota_monitor_poll_event": "loopx.control_plane.quota.monitor_poll",
100
+ "render_quota_markdown": "loopx.presentation.renderers.quota_markdown",
101
+ "render_quota_scheduler_ack_markdown": "loopx.presentation.renderers.quota_markdown",
102
+ "render_quota_should_run_markdown": "loopx.presentation.renderers.quota_markdown",
103
+ "build_quota_slot_void_event": "loopx.control_plane.quota.slot_accounting",
104
+ "render_quota_slot_preview_markdown": "loopx.presentation.renderers.quota_event_markdown",
105
+ }
106
+
107
+
108
+ AUTONOMOUS_REPLAN_ACK_NEUTRAL_CLASSIFICATIONS = {
109
+ QUOTA_SLOT_SPENT_CLASSIFICATION,
110
+ QUOTA_SLOT_VOIDED_CLASSIFICATION,
111
+ QUOTA_SCHEDULER_ACK_CLASSIFICATION,
112
+ "delivery_completion_spend_accounted_v0",
113
+ }
114
+
115
+ def _validate_goal_id_path_segment(goal_id: str) -> str:
116
+ value = goal_id.strip()
117
+ if not value:
118
+ raise ValueError("goal id is required")
119
+ if value in {".", ".."} or "/" in value or "\\" in value:
120
+ raise ValueError("goal id must be a single path segment")
121
+ if Path(value).name != value:
122
+ raise ValueError("goal id must not include path traversal")
123
+ return value
124
+
125
+
126
+ def _resolve_reward_memory_experiment_from_status(
127
+ status_payload: Mapping[str, Any],
128
+ *,
129
+ goal_id: str,
130
+ agent_id: str | None,
131
+ ) -> dict[str, Any] | None:
132
+ from .capabilities.reward_memory.experiment import (
133
+ resolve_reward_memory_experiment_from_status as _impl,
134
+ )
135
+
136
+ return _impl(
137
+ status_payload,
138
+ goal_id=goal_id,
139
+ agent_id=agent_id,
140
+ )
141
+
142
+
143
+ def _number(value: Any, *, default: float) -> float:
144
+ if isinstance(value, bool):
145
+ return default
146
+ if isinstance(value, (int, float)):
147
+ return float(value)
148
+ if isinstance(value, str):
149
+ try:
150
+ return float(value.strip())
151
+ except ValueError:
152
+ return default
153
+ return default
154
+
155
+
156
+ def _int_number(value: Any, *, default: int) -> int:
157
+ if isinstance(value, bool):
158
+ return default
159
+ if isinstance(value, int):
160
+ return value
161
+ if isinstance(value, float):
162
+ return int(value)
163
+ if isinstance(value, str):
164
+ try:
165
+ return int(float(value.strip()))
166
+ except ValueError:
167
+ return default
168
+ return default
169
+
170
+
171
+ def _clamp_compute(value: float) -> float:
172
+ return round(min(1.0, max(0.0, value)), 2)
173
+
174
+
175
+ def _text_values(value: Any) -> list[str]:
176
+ if value is None:
177
+ return []
178
+ if isinstance(value, str):
179
+ return [value]
180
+ if isinstance(value, (list, tuple, set)):
181
+ values: list[str] = []
182
+ for item in value:
183
+ values.extend(_text_values(item))
184
+ return values
185
+ return [str(value)]
186
+
187
+
188
+ def _has_focus_wait_marker(*values: Any) -> bool:
189
+ for value in values:
190
+ for text in _text_values(value):
191
+ marker = text.strip().lower()
192
+ if marker in FOCUS_WAIT_LIFECYCLE_MARKERS:
193
+ return True
194
+ return False
195
+
196
+
197
+ def _focus_wait_quota(payload: dict[str, Any]) -> dict[str, Any]:
198
+ quota = dict(payload)
199
+ quota["state"] = "focus_wait"
200
+ quota["reason"] = FOCUS_WAIT_REASON
201
+ quota["blocked_action_scope"] = "delivery_focus"
202
+ quota["focus_wait"] = True
203
+ return quota
204
+
205
+
206
+ def quota_with_handoff_outcome_floor(
207
+ quota: dict[str, Any],
208
+ *,
209
+ waiting_on: str | None = None,
210
+ project_asset: dict[str, Any] | None = None,
211
+ handoff_readiness: dict[str, Any] | None = None,
212
+ ) -> dict[str, Any]:
213
+ if waiting_on != "codex":
214
+ return quota
215
+ if not isinstance(handoff_readiness, dict) or not handoff_readiness:
216
+ return quota
217
+ profile = (
218
+ project_asset.get("execution_profile")
219
+ if isinstance(project_asset, dict) and isinstance(project_asset.get("execution_profile"), dict)
220
+ else None
221
+ )
222
+ outcome_gap_streak = handoff_readiness.get("post_handoff_outcome_gap_streak")
223
+ if not isinstance(outcome_gap_streak, int) or outcome_gap_streak <= 0:
224
+ return quota
225
+ threshold = outcome_floor_threshold(profile)
226
+ if outcome_gap_streak < threshold:
227
+ return quota
228
+ state = str(quota.get("state") or "eligible")
229
+ if state in {"blocked_health", "operator_gate", "waiting", "paused", "throttled"}:
230
+ return quota
231
+
232
+ floor = execution_profile_outcome_floor(profile)
233
+ must_advance = [
234
+ str(value).strip()
235
+ for value in (floor.get("must_advance") if isinstance(floor.get("must_advance"), list) else [])
236
+ if str(value).strip()
237
+ ]
238
+ avoid = [
239
+ str(value).strip()
240
+ for value in (floor.get("avoid") if isinstance(floor.get("avoid"), list) else [])
241
+ if str(value).strip()
242
+ ]
243
+ reason_parts = [
244
+ f"handoff outcome floor not met: outcome_gap_streak={outcome_gap_streak}/{threshold}",
245
+ "report blocker without spend or return with outcome-scale evidence",
246
+ ]
247
+ if must_advance:
248
+ reason_parts.append(f"must_advance={'+'.join(must_advance)}")
249
+ if avoid:
250
+ reason_parts.append(f"avoid={'+'.join(avoid)}")
251
+
252
+ blocked = dict(quota)
253
+ blocked["state"] = "focus_wait"
254
+ blocked["reason"] = "; ".join(reason_parts)
255
+ blocked["blocked_action_scope"] = "delivery_outcome_floor"
256
+ blocked["focus_wait"] = True
257
+ blocked["handoff_outcome_floor_block"] = True
258
+ blocked["post_handoff_outcome_gap_streak"] = outcome_gap_streak
259
+ blocked["outcome_gap_threshold"] = threshold
260
+ if must_advance:
261
+ blocked["must_advance"] = must_advance
262
+ blocked["safe_bypass_allowed"] = True
263
+ blocked["safe_bypass_kind"] = "outcome_floor_recovery"
264
+ blocked["safe_bypass_policy"] = (
265
+ "Outcome-floor recovery only: attempt one bounded "
266
+ f"{'+'.join(must_advance)} evidence segment or write back a concrete blocker; "
267
+ "avoid surface-only work; spend only after validated evidence/blocker writeback."
268
+ )
269
+ if avoid:
270
+ blocked["avoid"] = avoid
271
+ return blocked
272
+
273
+
274
+ def _quota_with_focus_wait_override(
275
+ quota: dict[str, Any],
276
+ *,
277
+ waiting_on: str | None = None,
278
+ lifecycle_phase: Any = None,
279
+ lifecycle_flags: Any = None,
280
+ status: Any = None,
281
+ ) -> dict[str, Any]:
282
+ if waiting_on != "codex":
283
+ return quota
284
+ if not _has_focus_wait_marker(lifecycle_phase, lifecycle_flags, status):
285
+ return quota
286
+ state = str(quota.get("state") or "eligible")
287
+ if state in {"blocked_health", "operator_gate", "waiting", "paused"}:
288
+ return quota
289
+ return _focus_wait_quota(quota)
290
+
291
+
292
+ def goal_quota_config(goal: dict[str, Any] | None) -> dict[str, Any]:
293
+ raw = goal.get("quota") if goal and isinstance(goal.get("quota"), dict) else {}
294
+ if goal and "compute_quota" in goal and "compute" not in raw:
295
+ raw = {**raw, "compute": goal.get("compute_quota")}
296
+ compute = _clamp_compute(_number(raw.get("compute"), default=DEFAULT_COMPUTE_QUOTA))
297
+ window_hours = max(1, _int_number(raw.get("window_hours"), default=DEFAULT_WINDOW_HOURS))
298
+ slot_minutes = max(1, _int_number(raw.get("slot_minutes"), default=DEFAULT_SLOT_MINUTES))
299
+ spent_slots = max(0, _int_number(raw.get("spent_slots"), default=0))
300
+ default_allowed_slots = round((window_hours * 60 / slot_minutes) * compute)
301
+ allowed_slots = max(0, _int_number(raw.get("allowed_slots"), default=default_allowed_slots))
302
+ payload: dict[str, Any] = {
303
+ "compute": compute,
304
+ "window_hours": window_hours,
305
+ "slot_minutes": slot_minutes,
306
+ "allowed_slots": allowed_slots,
307
+ "spent_slots": spent_slots,
308
+ }
309
+ if raw.get("next_eligible_at"):
310
+ payload["next_eligible_at"] = str(raw.get("next_eligible_at"))
311
+ return payload
312
+
313
+
314
+ def _quota_event_run_key(run: dict[str, Any], event: dict[str, Any]) -> str:
315
+ return str(event.get("run_generated_at") or run.get("generated_at") or "")
316
+
317
+
318
+ def goal_quota_with_spend_ledger(
319
+ goal: dict[str, Any] | None,
320
+ runs: list[dict[str, Any]],
321
+ *,
322
+ now: datetime | None = None,
323
+ ) -> dict[str, Any]:
324
+ payload = goal_quota_config(goal)
325
+ goal_id = str(goal.get("id") or "") if goal else ""
326
+ current_time = now or datetime.now(timezone.utc).astimezone()
327
+ if current_time.tzinfo is None:
328
+ current_time = current_time.replace(tzinfo=timezone.utc)
329
+ window_start = current_time - timedelta(hours=int(payload["window_hours"]))
330
+ spent_by_run: dict[str, int] = {}
331
+ voided_by_run: dict[str, int] = {}
332
+ spend_event_count = 0
333
+ void_event_count = 0
334
+
335
+ for run in runs:
336
+ if not isinstance(run, dict):
337
+ continue
338
+ if str(run.get("goal_id") or goal_id) != goal_id:
339
+ continue
340
+ generated_at = _parse_timestamp(run.get("generated_at"))
341
+ if generated_at is None or generated_at < window_start or generated_at > current_time:
342
+ continue
343
+ event = load_quota_event_from_run(run)
344
+ if not event:
345
+ continue
346
+ event_type = str(event.get("event_type") or "")
347
+ slots = max(0, _int_number(event.get("slots"), default=0))
348
+ if slots <= 0:
349
+ continue
350
+ if event_type == QUOTA_SLOT_SPENT_CLASSIFICATION:
351
+ run_key = _quota_event_run_key(run, event)
352
+ if not run_key:
353
+ continue
354
+ spent_by_run[run_key] = spent_by_run.get(run_key, 0) + slots
355
+ spend_event_count += 1
356
+ elif event_type == QUOTA_SLOT_VOIDED_CLASSIFICATION:
357
+ voided_run_generated_at = str(event.get("voided_run_generated_at") or "")
358
+ if not voided_run_generated_at:
359
+ continue
360
+ voided_by_run[voided_run_generated_at] = voided_by_run.get(voided_run_generated_at, 0) + slots
361
+ void_event_count += 1
362
+
363
+ spent_slots = 0
364
+ for run_key, slots in spent_by_run.items():
365
+ spent_slots += max(0, slots - voided_by_run.get(run_key, 0))
366
+ payload["spent_slots"] = spent_slots
367
+ payload["spend_source"] = "runtime_events"
368
+ payload["spend_event_count"] = spend_event_count
369
+ if void_event_count:
370
+ payload["void_event_count"] = void_event_count
371
+ return payload
372
+
373
+
374
+ def quota_status(
375
+ goal: dict[str, Any] | None,
376
+ *,
377
+ waiting_on: str | None = None,
378
+ severity: str | None = None,
379
+ lifecycle_phase: Any = None,
380
+ lifecycle_flags: Any = None,
381
+ status: Any = None,
382
+ ) -> dict[str, Any]:
383
+ payload = goal_quota_config(goal)
384
+ compute = float(payload["compute"])
385
+ spent_slots = int(payload["spent_slots"])
386
+ allowed_slots = int(payload["allowed_slots"])
387
+
388
+ if compute <= 0:
389
+ state = "paused"
390
+ reason = "compute quota is 0; automatic agent turns are paused"
391
+ elif severity == "high":
392
+ state = "blocked_health"
393
+ reason = "health or contract blocker must clear before compute is spent"
394
+ elif waiting_on in {"user_or_controller", "controller"}:
395
+ state = "operator_gate"
396
+ reason = "operator gate blocks gated delivery; safe non-gated steering may continue"
397
+ payload["blocked_action_scope"] = "gated_delivery"
398
+ payload["safe_bypass_allowed"] = True
399
+ payload["safe_bypass_policy"] = (
400
+ "Do not execute agent_command, adapter work, write-control, production actions, "
401
+ "or the gated path. A heartbeat may spend one bounded turn on read-only steering, "
402
+ "analysis, documentation, or another priority-stack item that does not depend on this gate."
403
+ )
404
+ elif waiting_on == "external_evidence":
405
+ state = "waiting"
406
+ reason = "external evidence is still pending; do not spend delivery compute yet"
407
+ elif waiting_on == "codex" and _has_focus_wait_marker(lifecycle_phase, lifecycle_flags, status):
408
+ state = "focus_wait"
409
+ reason = FOCUS_WAIT_REASON
410
+ payload["blocked_action_scope"] = "delivery_focus"
411
+ payload["focus_wait"] = True
412
+ elif waiting_on == "codex":
413
+ if spent_slots >= allowed_slots:
414
+ state = "throttled"
415
+ reason = f"{compute:g} compute quota spent {spent_slots}/{allowed_slots} slots in this window"
416
+ else:
417
+ state = "eligible"
418
+ reason = f"{compute:g} compute quota; eligible for the next automatic agent turn"
419
+ else:
420
+ state = "waiting"
421
+ reason = "no active Codex-ready work is currently selected"
422
+
423
+ payload["state"] = state
424
+ payload["reason"] = reason
425
+ return payload
426
+
427
+
428
+ def _quota_sort_key(item: dict[str, Any]) -> tuple[int, float, int, str]:
429
+ quota = item.get("quota") if isinstance(item.get("quota"), dict) else {}
430
+ state = str(quota.get("state") or "waiting")
431
+ state_index = QUOTA_STATE_ORDER.index(state) if state in QUOTA_STATE_ORDER else len(QUOTA_STATE_ORDER)
432
+ compute = _number(quota.get("compute"), default=DEFAULT_COMPUTE_QUOTA)
433
+ spent_slots = _int_number(quota.get("spent_slots"), default=0)
434
+ return (state_index, -compute, spent_slots, str(item.get("goal_id") or ""))
435
+
436
+
437
+ def _todo_priority_label(item: dict[str, Any]) -> str | None:
438
+ return projection_todo_priority_label(item)
439
+
440
+
441
+ def _todo_priority_rank(item: dict[str, Any]) -> int:
442
+ return projection_todo_priority_rank(item)
443
+
444
+
445
+ def _todo_index_rank(item: dict[str, Any]) -> int:
446
+ return projection_todo_index_rank(item)
447
+
448
+
449
+ def _todo_projection_sort_key(item: dict[str, Any]) -> tuple[int, int]:
450
+ return projection_todo_projection_sort_key(item)
451
+
452
+
453
+
454
+
455
+
456
+
457
+ def _compact_handoff_readiness(value: Any) -> dict[str, Any] | None:
458
+ if not isinstance(value, dict):
459
+ return None
460
+ compact = {field: value[field] for field in HANDOFF_READINESS_COMPACT_FIELDS if field in value}
461
+ latest_run = (
462
+ value.get("post_handoff_latest_run")
463
+ if isinstance(value.get("post_handoff_latest_run"), dict)
464
+ else {}
465
+ )
466
+ if latest_run:
467
+ compact["post_handoff_latest_run"] = {
468
+ field: latest_run[field]
469
+ for field in POST_HANDOFF_RUN_COMPACT_FIELDS
470
+ if field in latest_run
471
+ }
472
+ recent_runs = (
473
+ value.get("post_handoff_recent_runs")
474
+ if isinstance(value.get("post_handoff_recent_runs"), list)
475
+ else []
476
+ )
477
+ compact_recent_runs: list[dict[str, Any]] = []
478
+ for run in recent_runs:
479
+ if not isinstance(run, dict):
480
+ continue
481
+ compact_run = {
482
+ field: run[field]
483
+ for field in POST_HANDOFF_RUN_COMPACT_FIELDS
484
+ if field in run
485
+ }
486
+ if compact_run:
487
+ compact_recent_runs.append(compact_run)
488
+ if compact_recent_runs:
489
+ compact["post_handoff_recent_runs"] = compact_recent_runs[:3]
490
+ return compact or None
491
+
492
+
493
+
494
+
495
+
496
+
497
+
498
+
499
+
500
+
501
+
502
+
503
+
504
+
505
+ def _todo_item_next_due_at(item: dict[str, Any]) -> datetime | None:
506
+ return projection_todo_item_next_due_at(item)
507
+
508
+
509
+ def _todo_item_expires_at(item: dict[str, Any]) -> datetime | None:
510
+ return projection_todo_item_expires_at(item)
511
+
512
+
513
+ def _todo_item_is_expired_monitor(item: dict[str, Any], *, now: datetime | None = None) -> bool:
514
+ return projection_todo_item_is_expired_monitor(item, now=now)
515
+
516
+
517
+ def _todo_item_is_due_monitor(item: dict[str, Any], *, now: datetime | None = None) -> bool:
518
+ return projection_todo_item_is_due_monitor(item, now=now)
519
+
520
+
521
+ def _todo_item_missing_monitor_schedule(
522
+ item: dict[str, Any],
523
+ *,
524
+ now: datetime | None = None,
525
+ ) -> bool:
526
+ return projection_todo_item_missing_monitor_schedule(item, now=now)
527
+
528
+
529
+ def _todo_summary_claim_scope_agent_id(summary: dict[str, Any]) -> str | None:
530
+ return projection_todo_summary_claim_scope_agent_id(summary)
531
+
532
+
533
+
534
+
535
+
536
+
537
+ def _quota_plan_goal_quota(
538
+ *,
539
+ attention: dict[str, Any],
540
+ project_asset: dict[str, Any],
541
+ goal: dict[str, Any],
542
+ waiting_on: str,
543
+ lifecycle_phase: Any,
544
+ lifecycle_flags: Any,
545
+ status: Any,
546
+ ) -> dict[str, Any]:
547
+ project_asset_quota = (
548
+ project_asset.get("quota")
549
+ if isinstance(project_asset.get("quota"), dict)
550
+ else {}
551
+ )
552
+ raw_quota = (
553
+ attention.get("quota")
554
+ if isinstance(attention.get("quota"), dict)
555
+ else goal.get("quota")
556
+ )
557
+ if project_asset_quota:
558
+ raw_quota_base = raw_quota if isinstance(raw_quota, dict) else {}
559
+ quota = {**raw_quota_base, **project_asset_quota}
560
+ elif isinstance(raw_quota, dict):
561
+ quota = _quota_with_focus_wait_override(
562
+ raw_quota,
563
+ waiting_on=waiting_on,
564
+ lifecycle_phase=lifecycle_phase,
565
+ lifecycle_flags=lifecycle_flags,
566
+ status=status,
567
+ )
568
+ else:
569
+ quota = quota_status(
570
+ goal,
571
+ waiting_on=waiting_on,
572
+ severity=str(attention.get("severity") or ""),
573
+ lifecycle_phase=lifecycle_phase,
574
+ lifecycle_flags=lifecycle_flags,
575
+ status=status,
576
+ )
577
+ return quota_with_handoff_outcome_floor(
578
+ quota,
579
+ waiting_on=waiting_on,
580
+ project_asset=project_asset,
581
+ handoff_readiness=attention.get("handoff_readiness")
582
+ if isinstance(attention.get("handoff_readiness"), dict)
583
+ else None,
584
+ )
585
+
586
+
587
+ def build_quota_plan(status_payload: dict[str, Any], *, mode: str = "status") -> dict[str, Any]:
588
+ queue = status_payload.get("attention_queue") if isinstance(status_payload.get("attention_queue"), dict) else {}
589
+ queue_items = queue.get("items") if isinstance(queue.get("items"), list) else []
590
+ queue_by_goal = {
591
+ str(item.get("goal_id")): item
592
+ for item in queue_items
593
+ if isinstance(item, dict) and item.get("goal_id")
594
+ }
595
+ health_items = [
596
+ item
597
+ for item in queue_items
598
+ if isinstance(item, dict) and not isinstance(item.get("quota"), dict)
599
+ ]
600
+
601
+ run_history = (
602
+ status_payload.get("run_history")
603
+ if isinstance(status_payload.get("run_history"), dict)
604
+ else {}
605
+ )
606
+ run_goals = run_history.get("goals") if isinstance(run_history.get("goals"), list) else []
607
+ status_goals = status_payload.get("goals") if isinstance(status_payload.get("goals"), list) else []
608
+ status_goal_by_id = {
609
+ str(goal.get("id") or ""): goal
610
+ for goal in status_goals
611
+ if isinstance(goal, dict) and goal.get("id")
612
+ }
613
+ registry_goal_by_id = _registry_goal_by_id(status_payload)
614
+ groups: dict[str, list[dict[str, Any]]] = {state: [] for state in QUOTA_STATE_ORDER}
615
+ groups["unknown"] = []
616
+
617
+ for goal in run_goals:
618
+ if not isinstance(goal, dict) or not goal.get("registry_member"):
619
+ continue
620
+ goal_id = str(goal.get("id") or "")
621
+ status_goal = status_goal_by_id.get(goal_id) or registry_goal_by_id.get(goal_id) or {}
622
+ attention = queue_by_goal.get(goal_id, {})
623
+ project_asset = (
624
+ attention.get("project_asset")
625
+ if isinstance(attention.get("project_asset"), dict)
626
+ else {}
627
+ )
628
+ latest = _goal_latest_run(goal)
629
+ waiting_on = attention.get("waiting_on") or "none"
630
+ lifecycle_phase = attention.get("lifecycle_phase") or goal.get("lifecycle_phase")
631
+ lifecycle_flags = attention.get("lifecycle_flags") or goal.get("lifecycle_flags")
632
+ status = attention.get("status") or goal.get("status")
633
+ control_plane = (
634
+ compact_control_plane_policy(attention.get("control_plane"))
635
+ or compact_control_plane_policy(project_asset.get("control_plane"))
636
+ or compact_control_plane_policy(goal.get("control_plane"))
637
+ )
638
+ quota = _quota_plan_goal_quota(
639
+ attention=attention,
640
+ project_asset=project_asset,
641
+ goal=goal,
642
+ waiting_on=str(waiting_on or ""),
643
+ lifecycle_phase=lifecycle_phase,
644
+ lifecycle_flags=lifecycle_flags,
645
+ status=status,
646
+ )
647
+ state = str(quota.get("state") or "waiting")
648
+ item: dict[str, Any] = {
649
+ "goal_id": goal_id,
650
+ "status": status,
651
+ "lifecycle_phase": lifecycle_phase,
652
+ "lifecycle_flags": lifecycle_flags,
653
+ "waiting_on": waiting_on,
654
+ "severity": attention.get("severity") or "info",
655
+ "source": attention.get("source") or "run_history",
656
+ "recommended_action": project_asset.get("next_action")
657
+ or attention.get("recommended_action")
658
+ or latest.get("recommended_action"),
659
+ "adapter_kind": goal.get("adapter_kind"),
660
+ "adapter_status": goal.get("adapter_status"),
661
+ "repo": (
662
+ goal.get("repo")
663
+ or goal.get("project")
664
+ or goal.get("root")
665
+ or status_goal.get("repo")
666
+ or status_goal.get("project")
667
+ or status_goal.get("root")
668
+ ),
669
+ "coordination": goal.get("coordination") if isinstance(goal.get("coordination"), dict) else None,
670
+ "explore_graph": goal.get("explore_graph")
671
+ if isinstance(goal.get("explore_graph"), dict)
672
+ else None,
673
+ "spawn_policy": goal.get("spawn_policy") if isinstance(goal.get("spawn_policy"), dict) else None,
674
+ "guards": goal.get("guards") if isinstance(goal.get("guards"), list) else [],
675
+ "next_probe": goal.get("next_probe"),
676
+ "latest_run_generated_at": latest.get("generated_at"),
677
+ "quota": quota,
678
+ }
679
+ workspace_guard_policy = (
680
+ goal.get("workspace_guard_policy")
681
+ if isinstance(goal.get("workspace_guard_policy"), dict)
682
+ else status_goal.get("workspace_guard_policy")
683
+ if isinstance(status_goal.get("workspace_guard_policy"), dict)
684
+ else None
685
+ )
686
+ if workspace_guard_policy:
687
+ item["workspace_guard_policy"] = workspace_guard_policy
688
+ if control_plane:
689
+ item["control_plane"] = control_plane
690
+ if project_asset:
691
+ item["project_asset"] = project_asset
692
+ item["project_asset_source"] = "project_asset"
693
+ else:
694
+ item["project_asset_source"] = "legacy_raw_fallback"
695
+ for optional_field in (
696
+ "operator_question",
697
+ "agent_command",
698
+ "controller_stage",
699
+ "missing_gates",
700
+ "next_handoff_condition",
701
+ "handoff_readiness",
702
+ "user_todos",
703
+ "agent_todos",
704
+ "active_state_next_action",
705
+ "active_state_next_action_entries",
706
+ "standing_decision_authority",
707
+ "long_task_cadence_hint",
708
+ "stale_latest_run_warning",
709
+ "backlog_hygiene_warning",
710
+ "completed_todo_archive_warning",
711
+ "dreaming_proposal",
712
+ "dreaming_lane_badge",
713
+ ):
714
+ if optional_field in attention:
715
+ if optional_field == "handoff_readiness":
716
+ compact_handoff = _compact_handoff_readiness(attention[optional_field])
717
+ if compact_handoff:
718
+ item[optional_field] = compact_handoff
719
+ else:
720
+ item[optional_field] = attention[optional_field]
721
+ groups.setdefault(state, []).append(item)
722
+
723
+ for state_items in groups.values():
724
+ state_items.sort(key=_quota_sort_key)
725
+
726
+ ordered_items = [
727
+ item
728
+ for state in QUOTA_STATE_ORDER
729
+ for item in groups.get(state, [])
730
+ ] + groups.get("unknown", [])
731
+ next_automatic_turn = (groups.get("eligible") or [None])[0]
732
+ summary = {
733
+ "registered_goals": len(ordered_items),
734
+ "health_blockers": len(health_items),
735
+ "next_automatic_turn": next_automatic_turn.get("goal_id") if next_automatic_turn else None,
736
+ "states": {state: len(groups.get(state, [])) for state in QUOTA_STATE_ORDER},
737
+ }
738
+ if groups.get("unknown"):
739
+ summary["states"]["unknown"] = len(groups["unknown"])
740
+
741
+ return {
742
+ "ok": status_payload.get("ok"),
743
+ "mode": mode,
744
+ "registry": status_payload.get("registry"),
745
+ "runtime_root": status_payload.get("runtime_root"),
746
+ "goal_count": status_payload.get("goal_count"),
747
+ "run_count": status_payload.get("run_count"),
748
+ "summary": summary,
749
+ "next_automatic_turn": next_automatic_turn,
750
+ "groups": groups,
751
+ "health_items": health_items,
752
+ }
753
+
754
+
755
+
756
+
757
+
758
+
759
+
760
+
761
+
762
+
763
+
764
+
765
+
766
+
767
+
768
+
769
+ def _build_quota_plan_for_goal(
770
+ status_payload: dict[str, Any],
771
+ *,
772
+ goal_id: str,
773
+ ) -> tuple[dict[str, Any], bool]:
774
+ plan = build_quota_plan(status_payload, mode="should-run")
775
+ return plan, _goal_status_health_ok(
776
+ status_payload,
777
+ goal_id=goal_id,
778
+ fallback=bool(plan.get("ok")),
779
+ )
780
+
781
+
782
+
783
+
784
+
785
+ def build_quota_should_run(
786
+ status_payload: dict[str, Any],
787
+ *,
788
+ goal_id: str,
789
+ agent_id: str | None = None,
790
+ available_capabilities: Any = None,
791
+ include_scheduler_detail: bool = False,
792
+ codex_app_current_rrule: Any = None,
793
+ codex_app_automation_id: Any = None,
794
+ scheduler_execution_context: (
795
+ Mapping[str, Any] | SchedulerExecutionContextResolution | None
796
+ ) = None,
797
+ operator_inbox_urgency_projector: Callable[..., dict[str, Any]] | None = None,
798
+ ) -> dict[str, Any]:
799
+ from .control_plane.quota.should_run import (
800
+ build_quota_should_run as _build_quota_should_run,
801
+ )
802
+
803
+ return _build_quota_should_run(
804
+ status_payload,
805
+ goal_id=goal_id,
806
+ agent_id=agent_id,
807
+ available_capabilities=available_capabilities,
808
+ include_scheduler_detail=include_scheduler_detail,
809
+ codex_app_current_rrule=codex_app_current_rrule,
810
+ codex_app_automation_id=codex_app_automation_id,
811
+ scheduler_execution_context=scheduler_execution_context,
812
+ operator_inbox_urgency_projector=operator_inbox_urgency_projector,
813
+ )
814
+
815
+
816
+ def build_quota_slot_preview(
817
+ status_payload: dict[str, Any],
818
+ *,
819
+ goal_id: str,
820
+ slots: int = 1,
821
+ agent_id: str | None = None,
822
+ workspace_path: Path | None = None,
823
+ available_capabilities: Any = None,
824
+ operator_inbox_urgency_projector: Callable[..., dict[str, Any]] | None = None,
825
+ todo_id: str | None = None,
826
+ turn_instance_id: str | None = None,
827
+ source: str = DEFAULT_SLOT_SPEND_SOURCE,
828
+ ) -> dict[str, Any]:
829
+ safe_goal_id = str(goal_id or "").strip()
830
+ before = build_quota_should_run(
831
+ status_payload,
832
+ goal_id=safe_goal_id,
833
+ agent_id=agent_id,
834
+ available_capabilities=available_capabilities, operator_inbox_urgency_projector=operator_inbox_urgency_projector,
835
+ )
836
+ return build_quota_slot_preview_for_decision(
837
+ status_payload,
838
+ goal_id=safe_goal_id,
839
+ slots=slots,
840
+ agent_id=agent_id,
841
+ workspace_path=workspace_path,
842
+ before=before,
843
+ after_decision=lambda after_status: build_quota_should_run(
844
+ after_status,
845
+ goal_id=safe_goal_id,
846
+ agent_id=agent_id,
847
+ available_capabilities=available_capabilities, operator_inbox_urgency_projector=operator_inbox_urgency_projector,
848
+ ),
849
+ quota_status_builder=quota_status,
850
+ self_repair_spend_actions=SELF_REPAIR_SPEND_ACTIONS,
851
+ todo_id=todo_id,
852
+ turn_instance_id=turn_instance_id,
853
+ source=source,
854
+ )
855
+
856
+
857
+
858
+
859
+ def record_quota_scheduler_ack(
860
+ status_payload: dict[str, Any],
861
+ *,
862
+ goal_id: str,
863
+ execute: bool = False,
864
+ agent_id: str | None = None,
865
+ available_capabilities: Any = None,
866
+ surface: str = CODEX_APP_SURFACE,
867
+ state_key: str = CODEX_APP_STATEFUL_BACKOFF_STATE_KEY,
868
+ applied_rrule: str | None = None,
869
+ reset_token: str | None = None,
870
+ identity_signature: str | None = None,
871
+ reason_summary: str | None = None, use_current_hint: bool = False, host_match_observed: bool = False,
872
+ scheduler_execution_context: Mapping[str, Any] | SchedulerExecutionContextResolution | None = None, operator_inbox_urgency_projector: Callable[..., dict[str, Any]] | None = None,
873
+ ) -> dict[str, Any]:
874
+ safe_goal_id = _validate_goal_id_path_segment(str(goal_id or ""))
875
+ safe_agent_id = normalize_todo_claimed_by(agent_id)
876
+ before = build_quota_should_run(
877
+ status_payload,
878
+ goal_id=safe_goal_id,
879
+ agent_id=safe_agent_id,
880
+ available_capabilities=available_capabilities, codex_app_current_rrule=applied_rrule if host_match_observed else None,
881
+ scheduler_execution_context=scheduler_execution_context, operator_inbox_urgency_projector=operator_inbox_urgency_projector,
882
+ )
883
+ raw_runtime_root = status_payload.get("runtime_root")
884
+ if not raw_runtime_root:
885
+ raise ValueError("status payload does not include runtime_root")
886
+ runtime_root = Path(str(raw_runtime_root)).expanduser()
887
+ return record_quota_scheduler_ack_for_decision(
888
+ before,
889
+ runtime_root=runtime_root,
890
+ goal_id=safe_goal_id,
891
+ agent_id=safe_agent_id,
892
+ execute=execute,
893
+ surface=str(surface or CODEX_APP_SURFACE).strip() or CODEX_APP_SURFACE,
894
+ state_key=str(state_key or CODEX_APP_STATEFUL_BACKOFF_STATE_KEY).strip(),
895
+ applied_rrule=applied_rrule,
896
+ reset_token=reset_token,
897
+ identity_signature=identity_signature,
898
+ reason_summary=reason_summary, use_current_hint=use_current_hint, host_match_observed=host_match_observed,
899
+ )
900
+
901
+
902
+ def build_quota_slot_spend_event(
903
+ preview: dict[str, Any],
904
+ *,
905
+ source: str = DEFAULT_SLOT_SPEND_SOURCE,
906
+ generated_at: str | None = None,
907
+ ) -> dict[str, Any]:
908
+ return _build_quota_slot_spend_event(
909
+ preview,
910
+ self_repair_spend_actions=SELF_REPAIR_SPEND_ACTIONS,
911
+ source=source,
912
+ generated_at=generated_at,
913
+ )
914
+
915
+
916
+ def record_quota_monitor_poll(
917
+ status_payload: dict[str, Any],
918
+ *,
919
+ goal_id: str,
920
+ registry_path: Path | None = None,
921
+ execute: bool = False,
922
+ source: str = DEFAULT_SLOT_SPEND_SOURCE,
923
+ reason_summary: str | None = None,
924
+ agent_id: str | None = None,
925
+ available_capabilities: Any = None,
926
+ todo_id: str | None = None,
927
+ target_key: str | None = None,
928
+ result_hash: str | None = None,
929
+ material_change: bool = False,
930
+ cadence: str | None = None,
931
+ next_due_at: str | None = None,
932
+ next_agent_todo: str | None = None,
933
+ next_action_kind: str | None = None,
934
+ next_task_repository: str | None = None,
935
+ next_required_capabilities: list[str] | None = None,
936
+ next_continuation_policy: str | None = None,
937
+ next_target_key: str | None = None,
938
+ next_user_todo: str | None = None,
939
+ next_user_task_class: str | None = None,
940
+ next_claimed_by: str | None = None,
941
+ turn_instance_id: str | None = None,
942
+ scheduler_execution_context: Mapping[str, Any] | SchedulerExecutionContextResolution | None = None,
943
+ operator_inbox_urgency_projector: Callable[..., dict[str, Any]] | None = None,
944
+ bounded_research_frontier_projector: (
945
+ Callable[..., Mapping[str, Any] | None] | None
946
+ ) = None,
947
+ status_reloader: Callable[[], dict[str, Any]] | None = None,
948
+ ) -> dict[str, Any]:
949
+ safe_goal_id = _validate_goal_id_path_segment(str(goal_id or ""))
950
+
951
+ def should_run(current_status: dict[str, Any]) -> dict[str, Any]:
952
+ decision_status = current_status
953
+ if bounded_research_frontier_projector is not None:
954
+ raw_runtime_root = current_status.get("runtime_root")
955
+ if raw_runtime_root:
956
+ frontier = bounded_research_frontier_projector(
957
+ runtime_root=Path(str(raw_runtime_root)).expanduser(),
958
+ goal_id=safe_goal_id,
959
+ agent_id=agent_id,
960
+ status_payload=current_status,
961
+ )
962
+ if isinstance(frontier, Mapping):
963
+ decision_status = {
964
+ **current_status,
965
+ "bounded_research_frontier": dict(frontier),
966
+ }
967
+ return build_quota_should_run(
968
+ decision_status,
969
+ goal_id=safe_goal_id,
970
+ agent_id=agent_id,
971
+ available_capabilities=available_capabilities,
972
+ scheduler_execution_context=scheduler_execution_context,
973
+ operator_inbox_urgency_projector=operator_inbox_urgency_projector,
974
+ )
975
+
976
+ before = should_run(status_payload)
977
+ return record_quota_monitor_poll_for_decision(
978
+ before,
979
+ status_payload,
980
+ goal_id=safe_goal_id,
981
+ render_markdown=_render_quota_monitor_poll_markdown,
982
+ after_decision=should_run,
983
+ registry_path=registry_path,
984
+ execute=execute,
985
+ source=source,
986
+ reason_summary=reason_summary,
987
+ agent_id=agent_id,
988
+ todo_id=todo_id,
989
+ target_key=target_key,
990
+ result_hash=result_hash,
991
+ material_change=material_change,
992
+ cadence=cadence,
993
+ next_due_at=next_due_at,
994
+ next_agent_todo=next_agent_todo,
995
+ next_action_kind=next_action_kind,
996
+ next_task_repository=next_task_repository,
997
+ next_required_capabilities=next_required_capabilities,
998
+ next_continuation_policy=next_continuation_policy,
999
+ next_target_key=next_target_key,
1000
+ next_user_todo=next_user_todo,
1001
+ next_user_task_class=next_user_task_class,
1002
+ next_claimed_by=next_claimed_by,
1003
+ turn_instance_id=turn_instance_id,
1004
+ status_reloader=status_reloader,
1005
+ )
1006
+
1007
+
1008
+ def build_quota_slot_void_preview(
1009
+ status_payload: dict[str, Any],
1010
+ *,
1011
+ goal_id: str,
1012
+ voided_run_generated_at: str,
1013
+ agent_id: str | None = None, operator_inbox_urgency_projector: Callable[..., dict[str, Any]] | None = None,
1014
+ ) -> dict[str, Any]:
1015
+ safe_goal_id = _validate_goal_id_path_segment(str(goal_id or ""))
1016
+ before = build_quota_should_run(status_payload, goal_id=safe_goal_id, agent_id=agent_id, operator_inbox_urgency_projector=operator_inbox_urgency_projector)
1017
+ return build_quota_slot_void_preview_for_decision(
1018
+ status_payload,
1019
+ goal_id=safe_goal_id,
1020
+ voided_run_generated_at=voided_run_generated_at,
1021
+ before=before,
1022
+ )
1023
+
1024
+
1025
+ def void_quota_slot(
1026
+ status_payload: dict[str, Any],
1027
+ *,
1028
+ goal_id: str,
1029
+ voided_run_generated_at: str,
1030
+ execute: bool = False,
1031
+ source: str = DEFAULT_SLOT_SPEND_SOURCE,
1032
+ reason_summary: str | None = None,
1033
+ agent_id: str | None = None, operator_inbox_urgency_projector: Callable[..., dict[str, Any]] | None = None,
1034
+ ) -> dict[str, Any]:
1035
+ safe_goal_id = _validate_goal_id_path_segment(str(goal_id or ""))
1036
+ preview = build_quota_slot_void_preview(
1037
+ status_payload,
1038
+ goal_id=safe_goal_id,
1039
+ voided_run_generated_at=voided_run_generated_at,
1040
+ agent_id=agent_id, operator_inbox_urgency_projector=operator_inbox_urgency_projector,
1041
+ )
1042
+ if not preview.get("ok"):
1043
+ return preview
1044
+
1045
+ return record_quota_slot_void_from_preview(
1046
+ preview,
1047
+ status_payload,
1048
+ goal_id=safe_goal_id,
1049
+ render_markdown=_render_quota_slot_preview_markdown,
1050
+ execute=execute,
1051
+ source=source,
1052
+ reason_summary=reason_summary,
1053
+ )
1054
+
1055
+
1056
+ def spend_quota_slot(
1057
+ status_payload: dict[str, Any],
1058
+ *,
1059
+ goal_id: str,
1060
+ slots: int = 1,
1061
+ execute: bool = False,
1062
+ source: str = DEFAULT_SLOT_SPEND_SOURCE,
1063
+ agent_id: str | None = None,
1064
+ workspace_path: Path | None = None,
1065
+ available_capabilities: Any = None,
1066
+ operator_inbox_urgency_projector: Callable[..., dict[str, Any]] | None = None,
1067
+ todo_id: str | None = None,
1068
+ turn_instance_id: str | None = None,
1069
+ ) -> dict[str, Any]:
1070
+ safe_goal_id = _validate_goal_id_path_segment(str(goal_id or ""))
1071
+ if turn_instance_id and source != DEFAULT_SLOT_SPEND_SOURCE:
1072
+ return {
1073
+ "ok": False,
1074
+ "mode": "spend-slot",
1075
+ "dry_run": not execute,
1076
+ "appended": False,
1077
+ "goal_id": safe_goal_id,
1078
+ "reason": "turn-scoped settlement is valid only for heartbeat spend",
1079
+ }
1080
+ raw_runtime_root = status_payload.get("runtime_root")
1081
+ if (
1082
+ not turn_instance_id
1083
+ and source == DEFAULT_SLOT_SPEND_SOURCE
1084
+ and raw_runtime_root
1085
+ ):
1086
+ inferred_result = infer_persisted_heartbeat_settlement_identity(
1087
+ Path(str(raw_runtime_root)).expanduser(),
1088
+ goal_id=safe_goal_id,
1089
+ agent_id=agent_id,
1090
+ todo_id=todo_id,
1091
+ )
1092
+ if inferred_result is not None:
1093
+ if inferred_result.failure is not None or inferred_result.value is None:
1094
+ return {
1095
+ "ok": False,
1096
+ "mode": "spend-slot",
1097
+ "dry_run": not execute,
1098
+ "appended": False,
1099
+ "goal_id": safe_goal_id,
1100
+ "reason": (
1101
+ inferred_result.failure.reason
1102
+ if inferred_result.failure is not None
1103
+ else "persisted heartbeat settlement has no identity"
1104
+ ),
1105
+ "settlement_result": settlement_result_payload(inferred_result),
1106
+ }
1107
+ turn_instance_id = inferred_result.value.turn_instance_id
1108
+ if turn_instance_id and raw_runtime_root:
1109
+ runtime_root = Path(str(raw_runtime_root)).expanduser()
1110
+ guard_result = resolve_heartbeat_settlement_identity(
1111
+ runtime_root,
1112
+ goal_id=safe_goal_id,
1113
+ agent_id=agent_id,
1114
+ todo_id=todo_id,
1115
+ turn_instance_id=turn_instance_id,
1116
+ )
1117
+ if guard_result.failure is not None or guard_result.value is None:
1118
+ return {
1119
+ "ok": False,
1120
+ "mode": "spend-slot",
1121
+ "dry_run": not execute,
1122
+ "appended": False,
1123
+ "goal_id": safe_goal_id,
1124
+ "reason": (
1125
+ guard_result.failure.reason
1126
+ if guard_result.failure is not None
1127
+ else "turn-scoped spend has no settlement identity"
1128
+ ),
1129
+ "settlement_result": settlement_result_payload(guard_result),
1130
+ }
1131
+ identity = guard_result.value
1132
+ spent_result = guard_result.bind(
1133
+ lambda resolved: require_settlement_writeback(
1134
+ runtime_root,
1135
+ resolved,
1136
+ )
1137
+ ).bind(
1138
+ lambda _writeback: require_settlement_spend(
1139
+ runtime_root,
1140
+ identity,
1141
+ )
1142
+ )
1143
+ if spent_result.failure is None:
1144
+ return {
1145
+ "ok": True,
1146
+ "mode": "spend-slot",
1147
+ "dry_run": not execute,
1148
+ "appended": False,
1149
+ "idempotent_replay": True,
1150
+ "goal_id": safe_goal_id,
1151
+ "agent_id": identity.agent_id,
1152
+ "todo_id": identity.todo_id,
1153
+ "turn_instance_id": identity.turn_instance_id,
1154
+ "settlement_identity": identity.as_dict(),
1155
+ "settlement_result": settlement_result_payload(spent_result),
1156
+ "reason": "quota spend receipt replayed for the same settlement identity",
1157
+ }
1158
+ prior_spend_run = find_settlement_spend_run(runtime_root, identity)
1159
+ if prior_spend_run is not None:
1160
+ return {
1161
+ "ok": True,
1162
+ "mode": "spend-slot",
1163
+ "dry_run": not execute,
1164
+ "appended": False,
1165
+ "receipt_repair_required": bool(execute),
1166
+ "goal_id": safe_goal_id,
1167
+ "agent_id": identity.agent_id,
1168
+ "todo_id": identity.todo_id,
1169
+ "turn_instance_id": identity.turn_instance_id,
1170
+ "settlement_identity": identity.as_dict(),
1171
+ "settlement_result": settlement_result_payload(spent_result),
1172
+ "reason": "quota spend run exists; repair its missing settlement receipt",
1173
+ }
1174
+ preview = build_quota_slot_preview(
1175
+ status_payload,
1176
+ goal_id=safe_goal_id,
1177
+ slots=slots,
1178
+ agent_id=agent_id,
1179
+ workspace_path=workspace_path,
1180
+ available_capabilities=available_capabilities,
1181
+ operator_inbox_urgency_projector=operator_inbox_urgency_projector,
1182
+ todo_id=todo_id,
1183
+ turn_instance_id=turn_instance_id,
1184
+ source=source,
1185
+ )
1186
+ if not preview.get("ok"):
1187
+ return preview
1188
+
1189
+ return record_quota_slot_spend_from_preview(
1190
+ preview,
1191
+ status_payload,
1192
+ goal_id=safe_goal_id,
1193
+ self_repair_spend_actions=SELF_REPAIR_SPEND_ACTIONS,
1194
+ render_markdown=_render_quota_slot_preview_markdown,
1195
+ execute=execute,
1196
+ source=source,
1197
+ )