loopx 0.4.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (811) hide show
  1. loopx/__init__.py +5 -0
  2. loopx/agent_onboarding.py +654 -0
  3. loopx/agent_registry.py +112 -0
  4. loopx/ark_managed_agent_host.py +59 -0
  5. loopx/authority.py +805 -0
  6. loopx/benchmark.py +2875 -0
  7. loopx/benchmark_adapters/__init__.py +1 -0
  8. loopx/benchmark_adapters/agentissue.py +2644 -0
  9. loopx/benchmark_adapters/agents_last_exam.py +3998 -0
  10. loopx/benchmark_adapters/edgebench.py +322 -0
  11. loopx/benchmark_adapters/skillsbench.py +5978 -0
  12. loopx/benchmark_adapters/skillsbench_acp_failure_policy.py +143 -0
  13. loopx/benchmark_adapters/skillsbench_acp_process.py +31 -0
  14. loopx/benchmark_adapters/skillsbench_acp_relay.py +4832 -0
  15. loopx/benchmark_adapters/skillsbench_batch.py +124 -0
  16. loopx/benchmark_adapters/skillsbench_bridge_guard.py +209 -0
  17. loopx/benchmark_adapters/skillsbench_bridge_summary.py +203 -0
  18. loopx/benchmark_adapters/skillsbench_codex_goal_recovery.py +271 -0
  19. loopx/benchmark_adapters/skillsbench_codex_goal_trace.py +81 -0
  20. loopx/benchmark_adapters/skillsbench_codex_runtime.py +339 -0
  21. loopx/benchmark_adapters/skillsbench_dockerfile_runtime.py +467 -0
  22. loopx/benchmark_adapters/skillsbench_failure_signals.py +652 -0
  23. loopx/benchmark_adapters/skillsbench_proxy_runtime.py +327 -0
  24. loopx/benchmark_adapters/skillsbench_remote_bridge.py +402 -0
  25. loopx/benchmark_adapters/skillsbench_result_discovery.py +143 -0
  26. loopx/benchmark_adapters/skillsbench_runner_profile.py +436 -0
  27. loopx/benchmark_adapters/skillsbench_runner_source.py +99 -0
  28. loopx/benchmark_adapters/skillsbench_setup_preflight.py +771 -0
  29. loopx/benchmark_adapters/skillsbench_signals.py +15 -0
  30. loopx/benchmark_adapters/skillsbench_task_source.py +141 -0
  31. loopx/benchmark_adapters/skillsbench_turn_route.py +723 -0
  32. loopx/benchmark_adapters/skillsbench_turn_runtime.py +1069 -0
  33. loopx/benchmark_adapters/skillsbench_typed_repair.py +689 -0
  34. loopx/benchmark_adapters/skillsbench_uv_cache.py +111 -0
  35. loopx/benchmark_adapters/skillsbench_verifier_bootstrap.py +227 -0
  36. loopx/benchmark_adapters/skillsbench_verifier_cache.py +138 -0
  37. loopx/benchmark_adapters/terminal_bench.py +10078 -0
  38. loopx/benchmark_case_analysis.py +1276 -0
  39. loopx/benchmark_case_state.py +1079 -0
  40. loopx/benchmark_core/__init__.py +239 -0
  41. loopx/benchmark_core/adapter.py +84 -0
  42. loopx/benchmark_core/artifacts.py +517 -0
  43. loopx/benchmark_core/attempts.py +199 -0
  44. loopx/benchmark_core/container_exec.py +216 -0
  45. loopx/benchmark_core/io.py +68 -0
  46. loopx/benchmark_core/lifecycle.py +211 -0
  47. loopx/benchmark_core/loop_protocol.py +689 -0
  48. loopx/benchmark_core/observable_handles.py +348 -0
  49. loopx/benchmark_core/parity.py +256 -0
  50. loopx/benchmark_core/remote_closeout.py +482 -0
  51. loopx/benchmark_core/rounds.py +215 -0
  52. loopx/benchmark_core/route_profile.py +509 -0
  53. loopx/benchmark_core/run_permissions.py +206 -0
  54. loopx/benchmark_core/split_control.py +925 -0
  55. loopx/benchmark_core/turn_fidelity.py +326 -0
  56. loopx/benchmark_ledger.py +3793 -0
  57. loopx/benchmark_ledger_countability.py +372 -0
  58. loopx/benchmark_ledger_current.py +724 -0
  59. loopx/benchmark_trajectory.py +405 -0
  60. loopx/benchmarks/__init__.py +1 -0
  61. loopx/benchmarks/qualification/__init__.py +1 -0
  62. loopx/benchmarks/qualification/release_outcome_baseline.py +360 -0
  63. loopx/benchmarks/read_models/__init__.py +1 -0
  64. loopx/benchmarks/read_models/benchmark_attempt_accounting.py +53 -0
  65. loopx/benchmarks/read_models/benchmark_comparison.py +414 -0
  66. loopx/benchmarks/read_models/benchmark_event_timeline.py +113 -0
  67. loopx/benchmarks/read_models/benchmark_experiment_report.py +475 -0
  68. loopx/benchmarks/read_models/benchmark_learning_ledger.py +137 -0
  69. loopx/benchmarks/read_models/benchmark_lifecycle_contracts.py +228 -0
  70. loopx/benchmarks/read_models/benchmark_projection.py +723 -0
  71. loopx/benchmarks/read_models/benchmark_result.py +146 -0
  72. loopx/benchmarks/read_models/benchmark_run_execution_contract.py +116 -0
  73. loopx/benchmarks/read_models/benchmark_run_failure.py +157 -0
  74. loopx/benchmarks/read_models/benchmark_run_metrics.py +213 -0
  75. loopx/benchmarks/read_models/benchmark_run_post_execution.py +635 -0
  76. loopx/benchmarks/read_models/benchmark_run_pre_execution.py +541 -0
  77. loopx/benchmarks/read_models/benchmark_status_compaction.py +1255 -0
  78. loopx/benchmarks/read_models/benchmark_status_runner.py +780 -0
  79. loopx/benchmarks/read_models/goal_start_control_score.py +857 -0
  80. loopx/benchmarks/read_models/skillsbench_post_run_debug.py +746 -0
  81. loopx/benchmarks/read_models/skillsbench_verifier_attribution.py +269 -0
  82. loopx/bootstrap.py +1116 -0
  83. loopx/bootstrap_command_pack.py +2167 -0
  84. loopx/boundary_authority.py +199 -0
  85. loopx/canary/__init__.py +1 -0
  86. loopx/canary/maintainability_ratchet.py +800 -0
  87. loopx/canary/planner.py +1984 -0
  88. loopx/canary/premerge.py +1130 -0
  89. loopx/canary/qualification_profiles.py +309 -0
  90. loopx/canary/quality_surface_catalog.py +838 -0
  91. loopx/canary/release_profiles.py +51 -0
  92. loopx/canary/runner.py +1107 -0
  93. loopx/canary/smoke_health.py +581 -0
  94. loopx/canary/smoke_profiles.py +212 -0
  95. loopx/capabilities/__init__.py +0 -0
  96. loopx/capabilities/agent_turn_recall/__init__.py +17 -0
  97. loopx/capabilities/agent_turn_recall/cli.py +369 -0
  98. loopx/capabilities/agent_turn_recall/core.py +296 -0
  99. loopx/capabilities/auto_research/__init__.py +16 -0
  100. loopx/capabilities/auto_research/bootstrap_contract.py +157 -0
  101. loopx/capabilities/auto_research/cli.py +1468 -0
  102. loopx/capabilities/auto_research/core.py +11 -0
  103. loopx/capabilities/auto_research/defaults.py +79 -0
  104. loopx/capabilities/auto_research/demo_e2e.py +1848 -0
  105. loopx/capabilities/auto_research/demo_supervisor.py +186 -0
  106. loopx/capabilities/auto_research/evidence_packet.py +767 -0
  107. loopx/capabilities/auto_research/human_view.py +794 -0
  108. loopx/capabilities/auto_research/kernel.py +191 -0
  109. loopx/capabilities/auto_research/knn_demo_workspace.py +322 -0
  110. loopx/capabilities/auto_research/live_evidence.py +248 -0
  111. loopx/capabilities/auto_research/preset.py +176 -0
  112. loopx/capabilities/auto_research/research_state.py +1085 -0
  113. loopx/capabilities/auto_research/role_profiles.py +394 -0
  114. loopx/capabilities/auto_research/rollout_append.py +97 -0
  115. loopx/capabilities/auto_research/terminal_result_contract.py +422 -0
  116. loopx/capabilities/auto_research/terminal_result_projection.py +171 -0
  117. loopx/capabilities/auto_research/terminal_result_query.py +233 -0
  118. loopx/capabilities/auto_research/terminal_results.py +349 -0
  119. loopx/capabilities/auto_research/user_contract.py +190 -0
  120. loopx/capabilities/auto_research/worker_loop.py +163 -0
  121. loopx/capabilities/auto_research/worker_runtime.py +777 -0
  122. loopx/capabilities/auto_research/worker_skill/SKILL.md +343 -0
  123. loopx/capabilities/benchmark_toolkit/__init__.py +19 -0
  124. loopx/capabilities/benchmark_toolkit/integrity.py +387 -0
  125. loopx/capabilities/catalog.py +1875 -0
  126. loopx/capabilities/change_quality/__init__.py +19 -0
  127. loopx/capabilities/change_quality/cli.py +171 -0
  128. loopx/capabilities/change_quality/context.py +156 -0
  129. loopx/capabilities/change_quality/oracles.py +269 -0
  130. loopx/capabilities/change_quality/policy.py +34 -0
  131. loopx/capabilities/change_quality/receipt.py +482 -0
  132. loopx/capabilities/change_quality/result.py +493 -0
  133. loopx/capabilities/change_quality/scope.py +171 -0
  134. loopx/capabilities/change_quality/shadow.py +680 -0
  135. loopx/capabilities/content_ops/__init__.py +0 -0
  136. loopx/capabilities/content_ops/cli.py +649 -0
  137. loopx/capabilities/content_ops/connector_packets.py +164 -0
  138. loopx/capabilities/content_ops/item_lifecycle.py +1000 -0
  139. loopx/capabilities/content_ops/layout.py +451 -0
  140. loopx/capabilities/content_ops/markdown.py +456 -0
  141. loopx/capabilities/content_ops/schemas.py +51 -0
  142. loopx/capabilities/content_ops/social_browser_x.py +107 -0
  143. loopx/capabilities/content_ops/surface.py +1956 -0
  144. loopx/capabilities/content_ops/templates/layout-catalog-v0.json +72 -0
  145. loopx/capabilities/context_providers/__init__.py +36 -0
  146. loopx/capabilities/context_providers/base.py +189 -0
  147. loopx/capabilities/context_providers/factory.py +32 -0
  148. loopx/capabilities/context_providers/openviking.py +702 -0
  149. loopx/capabilities/context_providers/service_ownership.py +185 -0
  150. loopx/capabilities/decision_context/__init__.py +129 -0
  151. loopx/capabilities/decision_context/architecture.py +83 -0
  152. loopx/capabilities/decision_context/assembler.py +849 -0
  153. loopx/capabilities/decision_context/catalog_entry.py +195 -0
  154. loopx/capabilities/decision_context/cli.py +310 -0
  155. loopx/capabilities/decision_context/cursor_commit.py +535 -0
  156. loopx/capabilities/decision_context/outcome_feedback.py +352 -0
  157. loopx/capabilities/decision_context/packets.py +654 -0
  158. loopx/capabilities/decision_context/private_state.py +189 -0
  159. loopx/capabilities/decision_context/profile.py +453 -0
  160. loopx/capabilities/decision_context/providers.py +228 -0
  161. loopx/capabilities/decision_context/review_settlement.py +136 -0
  162. loopx/capabilities/decision_context/runtime.py +273 -0
  163. loopx/capabilities/decision_context/sources.py +415 -0
  164. loopx/capabilities/explore/__init__.py +1 -0
  165. loopx/capabilities/explore/activation.py +198 -0
  166. loopx/capabilities/explore/adaptive_replay_planner.py +221 -0
  167. loopx/capabilities/explore/child_replay_runtime.py +463 -0
  168. loopx/capabilities/explore/composition_frontier.py +291 -0
  169. loopx/capabilities/explore/counterfactual_runtime.py +578 -0
  170. loopx/capabilities/explore/episode_runtime.py +647 -0
  171. loopx/capabilities/explore/harness_checkpoint.py +171 -0
  172. loopx/capabilities/explore/harness_gate.py +115 -0
  173. loopx/capabilities/explore/harness_runtime.py +1124 -0
  174. loopx/capabilities/explore/replay_metrics.py +206 -0
  175. loopx/capabilities/explore/replay_runtime.py +1271 -0
  176. loopx/capabilities/explore/resource_portfolio.py +173 -0
  177. loopx/capabilities/explore/result_log.py +974 -0
  178. loopx/capabilities/explore/router_state.py +432 -0
  179. loopx/capabilities/explore/source_history_reconcile.py +255 -0
  180. loopx/capabilities/explore/speculative_scheduler.py +498 -0
  181. loopx/capabilities/explore/todo_branch_plan.py +650 -0
  182. loopx/capabilities/explore/todo_evidence.py +141 -0
  183. loopx/capabilities/explore/trace_runtime.py +284 -0
  184. loopx/capabilities/explore/worker_branch_plan.py +1257 -0
  185. loopx/capabilities/integration_branch/__init__.py +13 -0
  186. loopx/capabilities/integration_branch/cli.py +148 -0
  187. loopx/capabilities/integration_branch/core.py +916 -0
  188. loopx/capabilities/issue_fix/__init__.py +19 -0
  189. loopx/capabilities/issue_fix/acceptance_loop.py +1050 -0
  190. loopx/capabilities/issue_fix/candidate_evidence.py +503 -0
  191. loopx/capabilities/issue_fix/candidate_preflight.py +676 -0
  192. loopx/capabilities/issue_fix/cli.py +1822 -0
  193. loopx/capabilities/issue_fix/cli_input.py +87 -0
  194. loopx/capabilities/issue_fix/content_ops_cli.py +148 -0
  195. loopx/capabilities/issue_fix/discovered_issue_promotion.py +947 -0
  196. loopx/capabilities/issue_fix/explore_projection.py +710 -0
  197. loopx/capabilities/issue_fix/feasibility.py +542 -0
  198. loopx/capabilities/issue_fix/github_public.py +661 -0
  199. loopx/capabilities/issue_fix/intake_surface.py +832 -0
  200. loopx/capabilities/issue_fix/metadata_preview.py +218 -0
  201. loopx/capabilities/issue_fix/metrics_projection.py +1340 -0
  202. loopx/capabilities/issue_fix/metrics_supplement.py +634 -0
  203. loopx/capabilities/issue_fix/metrics_supplement_cli.py +127 -0
  204. loopx/capabilities/issue_fix/outcome_projection.py +1235 -0
  205. loopx/capabilities/issue_fix/periodic_report.py +189 -0
  206. loopx/capabilities/issue_fix/pr_description.py +418 -0
  207. loopx/capabilities/issue_fix/pr_gate_reconcile.py +496 -0
  208. loopx/capabilities/issue_fix/pr_gate_reconcile_cli.py +464 -0
  209. loopx/capabilities/issue_fix/pr_lifecycle.py +1327 -0
  210. loopx/capabilities/issue_fix/pr_lifecycle_rollout.py +85 -0
  211. loopx/capabilities/issue_fix/pr_monitor_materialization.py +257 -0
  212. loopx/capabilities/issue_fix/pr_review_ack.py +439 -0
  213. loopx/capabilities/issue_fix/provider_hooks.py +24 -0
  214. loopx/capabilities/issue_fix/repository_commit_evidence.py +186 -0
  215. loopx/capabilities/issue_fix/repository_context.py +457 -0
  216. loopx/capabilities/issue_fix/repository_memory.py +459 -0
  217. loopx/capabilities/issue_fix/repository_memory_provider.py +1454 -0
  218. loopx/capabilities/issue_fix/repository_snapshot.py +454 -0
  219. loopx/capabilities/issue_fix/reviewer_cli.py +917 -0
  220. loopx/capabilities/issue_fix/reviewer_notification.py +882 -0
  221. loopx/capabilities/issue_fix/reviewer_notification_drain.py +942 -0
  222. loopx/capabilities/issue_fix/reviewer_recommendation.py +1057 -0
  223. loopx/capabilities/issue_fix/reviewer_request.py +1282 -0
  224. loopx/capabilities/issue_fix/reward_memory.py +879 -0
  225. loopx/capabilities/issue_fix/workflow_plan.py +1286 -0
  226. loopx/capabilities/material_lifecycle/__init__.py +161 -0
  227. loopx/capabilities/material_lifecycle/_validation.py +183 -0
  228. loopx/capabilities/material_lifecycle/apply.py +672 -0
  229. loopx/capabilities/material_lifecycle/architecture.py +122 -0
  230. loopx/capabilities/material_lifecycle/cli.py +161 -0
  231. loopx/capabilities/material_lifecycle/decision_planning.py +470 -0
  232. loopx/capabilities/material_lifecycle/explore_execution.py +306 -0
  233. loopx/capabilities/material_lifecycle/intake.py +869 -0
  234. loopx/capabilities/material_lifecycle/inventory.py +147 -0
  235. loopx/capabilities/material_lifecycle/lifecycle.py +98 -0
  236. loopx/capabilities/material_lifecycle/preparation.py +147 -0
  237. loopx/capabilities/material_lifecycle/project_skill.py +83 -0
  238. loopx/capabilities/material_lifecycle/ranking.py +267 -0
  239. loopx/capabilities/material_lifecycle/readable_projection.py +500 -0
  240. loopx/capabilities/material_lifecycle/rebuild.py +480 -0
  241. loopx/capabilities/material_lifecycle/settlement.py +238 -0
  242. loopx/capabilities/periodic_report/__init__.py +71 -0
  243. loopx/capabilities/periodic_report/adapters.py +939 -0
  244. loopx/capabilities/periodic_report/archive.py +422 -0
  245. loopx/capabilities/periodic_report/bindings.py +705 -0
  246. loopx/capabilities/periodic_report/cli.py +277 -0
  247. loopx/capabilities/periodic_report/core.py +691 -0
  248. loopx/capabilities/periodic_report/extension_envelope.py +66 -0
  249. loopx/capabilities/periodic_report/presets.py +103 -0
  250. loopx/capabilities/periodic_report/profile.py +235 -0
  251. loopx/capabilities/periodic_report/project_progress.py +179 -0
  252. loopx/capabilities/periodic_report/triggers.py +452 -0
  253. loopx/capabilities/pr_review_queue/__init__.py +17 -0
  254. loopx/capabilities/pr_review_queue/core.py +506 -0
  255. loopx/capabilities/pr_review_queue/review_contract.py +506 -0
  256. loopx/capabilities/registry.py +192 -0
  257. loopx/capabilities/reward_memory/__init__.py +75 -0
  258. loopx/capabilities/reward_memory/application.py +819 -0
  259. loopx/capabilities/reward_memory/architecture.py +572 -0
  260. loopx/capabilities/reward_memory/candidate_review.py +511 -0
  261. loopx/capabilities/reward_memory/cli.py +469 -0
  262. loopx/capabilities/reward_memory/dogfood.py +574 -0
  263. loopx/capabilities/reward_memory/evaluation.py +296 -0
  264. loopx/capabilities/reward_memory/evaluation_fixtures.py +362 -0
  265. loopx/capabilities/reward_memory/experiment.py +567 -0
  266. loopx/capabilities/reward_memory/health.py +222 -0
  267. loopx/capabilities/reward_memory/ingestion.py +519 -0
  268. loopx/capabilities/reward_memory/registry.py +600 -0
  269. loopx/capabilities/reward_memory/runtime_hooks.py +312 -0
  270. loopx/capabilities/reward_memory/scoped_feedback.py +173 -0
  271. loopx/capabilities/semantic_preference/__init__.py +12 -0
  272. loopx/capabilities/semantic_preference/cli.py +189 -0
  273. loopx/capabilities/semantic_preference/contract.py +592 -0
  274. loopx/capabilities/semantic_preference/reward_memory.py +62 -0
  275. loopx/capabilities/value_connectors/__init__.py +1 -0
  276. loopx/capabilities/value_connectors/cli.py +401 -0
  277. loopx/capabilities/value_connectors/finance_extension_migration.py +108 -0
  278. loopx/capabilities/value_connectors/install_check.py +147 -0
  279. loopx/capabilities/value_connectors/planner.py +733 -0
  280. loopx/capabilities/value_connectors/source_map.py +446 -0
  281. loopx/claude_goal_baseline.py +138 -0
  282. loopx/claude_goal_mode/__init__.py +23 -0
  283. loopx/claude_goal_mode/hooks/goal_policy.py +212 -0
  284. loopx/claude_goal_mode/hooks/goal_state.py +139 -0
  285. loopx/claude_goal_mode/mcp/loopx_mcp.py +167 -0
  286. loopx/claude_goal_mode/scripts/connect.py +103 -0
  287. loopx/claude_goal_mode/scripts/goalmode_cmd.py +241 -0
  288. loopx/claude_goal_mode/scripts/install.py +328 -0
  289. loopx/claude_goal_mode/statusline/goal_status.py +97 -0
  290. loopx/cli.py +836 -0
  291. loopx/cli_commands/__init__.py +334 -0
  292. loopx/cli_commands/_host_thread.py +13 -0
  293. loopx/cli_commands/agentissue_runner_flow.py +447 -0
  294. loopx/cli_commands/agents_last_exam.py +160 -0
  295. loopx/cli_commands/agents_last_exam_baked_input.py +302 -0
  296. loopx/cli_commands/agents_last_exam_host_codex.py +374 -0
  297. loopx/cli_commands/agents_last_exam_launch_dry_run.py +372 -0
  298. loopx/cli_commands/agents_last_exam_local_plan.py +322 -0
  299. loopx/cli_commands/agents_last_exam_runner_source.py +352 -0
  300. loopx/cli_commands/agents_last_exam_task_material.py +335 -0
  301. loopx/cli_commands/agents_last_exam_validation_gate.py +236 -0
  302. loopx/cli_commands/benchmark_boundary.py +499 -0
  303. loopx/cli_commands/benchmark_dispatch.py +161 -0
  304. loopx/cli_commands/benchmark_release_outcome.py +123 -0
  305. loopx/cli_commands/benchmark_review_lifecycle.py +1275 -0
  306. loopx/cli_commands/benchmark_run_ledger.py +763 -0
  307. loopx/cli_commands/benchmark_run_ledger_case_analysis.py +249 -0
  308. loopx/cli_commands/benchmark_run_ledger_classification.py +45 -0
  309. loopx/cli_commands/benchmark_run_ledger_maintenance.py +486 -0
  310. loopx/cli_commands/benchmark_run_ledger_maintenance_registration.py +342 -0
  311. loopx/cli_commands/benchmark_run_ledger_maintenance_rendering.py +233 -0
  312. loopx/cli_commands/benchmark_run_ledger_parity.py +92 -0
  313. loopx/cli_commands/bootstrap_connect.py +238 -0
  314. loopx/cli_commands/canary.py +707 -0
  315. loopx/cli_commands/canary_release_qualification.py +79 -0
  316. loopx/cli_commands/capability.py +96 -0
  317. loopx/cli_commands/doctor.py +43 -0
  318. loopx/cli_commands/dreaming.py +143 -0
  319. loopx/cli_commands/edgebench.py +205 -0
  320. loopx/cli_commands/evidence_log.py +275 -0
  321. loopx/cli_commands/explore.py +989 -0
  322. loopx/cli_commands/explore_planning_commands.py +157 -0
  323. loopx/cli_commands/extension.py +271 -0
  324. loopx/cli_commands/first_run_report.py +73 -0
  325. loopx/cli_commands/goal_channel.py +656 -0
  326. loopx/cli_commands/handoff_mode.py +158 -0
  327. loopx/cli_commands/history.py +622 -0
  328. loopx/cli_commands/host_mode_plan.py +113 -0
  329. loopx/cli_commands/lark_inbox.py +431 -0
  330. loopx/cli_commands/lark_kanban.py +629 -0
  331. loopx/cli_commands/ml_experiment.py +321 -0
  332. loopx/cli_commands/multi_agent.py +211 -0
  333. loopx/cli_commands/opencode2_goal_worker.py +217 -0
  334. loopx/cli_commands/pr_review.py +167 -0
  335. loopx/cli_commands/presentation.py +218 -0
  336. loopx/cli_commands/preset.py +96 -0
  337. loopx/cli_commands/project.py +150 -0
  338. loopx/cli_commands/project_lifecycle.py +915 -0
  339. loopx/cli_commands/quota.py +859 -0
  340. loopx/cli_commands/quota_registration.py +241 -0
  341. loopx/cli_commands/quota_request.py +113 -0
  342. loopx/cli_commands/ready_score.py +110 -0
  343. loopx/cli_commands/registry_admin.py +975 -0
  344. loopx/cli_commands/registry_admin_configure.py +344 -0
  345. loopx/cli_commands/registry_admin_peer.py +84 -0
  346. loopx/cli_commands/registry_authority.py +218 -0
  347. loopx/cli_commands/review_batch.py +146 -0
  348. loopx/cli_commands/slash_commands.py +145 -0
  349. loopx/cli_commands/start_goal.py +251 -0
  350. loopx/cli_commands/starter.py +175 -0
  351. loopx/cli_commands/starter_bootstrap.py +179 -0
  352. loopx/cli_commands/starter_bootstrap_registration.py +198 -0
  353. loopx/cli_commands/starter_runtime_idle.py +107 -0
  354. loopx/cli_commands/starter_scheduler.py +207 -0
  355. loopx/cli_commands/starter_session_runtime.py +152 -0
  356. loopx/cli_commands/starter_visible_common.py +54 -0
  357. loopx/cli_commands/starter_visible_driver.py +161 -0
  358. loopx/cli_commands/starter_visible_pilot.py +278 -0
  359. loopx/cli_commands/status.py +867 -0
  360. loopx/cli_commands/status_registration.py +239 -0
  361. loopx/cli_commands/summary_all.py +222 -0
  362. loopx/cli_commands/support_control.py +809 -0
  363. loopx/cli_commands/support_control_registry.py +68 -0
  364. loopx/cli_commands/support_control_supervisor.py +289 -0
  365. loopx/cli_commands/task_lease.py +306 -0
  366. loopx/cli_commands/terminal_bench_adapter.py +717 -0
  367. loopx/cli_commands/terminal_bench_environment_result.py +1246 -0
  368. loopx/cli_commands/todo.py +940 -0
  369. loopx/cli_commands/todo_argument_validation.py +572 -0
  370. loopx/cli_commands/todo_event.py +114 -0
  371. loopx/cli_commands/turn.py +804 -0
  372. loopx/cli_commands/version.py +46 -0
  373. loopx/cli_commands/worker_bridge.py +659 -0
  374. loopx/cli_rollout.py +314 -0
  375. loopx/codex_cli_goal_tui.py +672 -0
  376. loopx/codex_cli_probe.py +1530 -0
  377. loopx/codex_cli_probe_markdown.py +935 -0
  378. loopx/codex_cli_runtime_probe.py +733 -0
  379. loopx/codex_cli_scheduler.py +564 -0
  380. loopx/codex_goal_baseline.py +620 -0
  381. loopx/configuration_catalog.py +617 -0
  382. loopx/configure_goal.py +1375 -0
  383. loopx/contract.py +996 -0
  384. loopx/control_plane/__init__.py +71 -0
  385. loopx/control_plane/agents/__init__.py +1 -0
  386. loopx/control_plane/agents/agent_lane_recommendation.py +516 -0
  387. loopx/control_plane/agents/agent_scope.py +1578 -0
  388. loopx/control_plane/agents/agent_scope_frontier.py +60 -0
  389. loopx/control_plane/agents/capability_gate.py +531 -0
  390. loopx/control_plane/agents/identity.py +140 -0
  391. loopx/control_plane/agents/legacy_migration.py +169 -0
  392. loopx/control_plane/agents/management_projection.py +658 -0
  393. loopx/control_plane/agents/material_frontier.py +608 -0
  394. loopx/control_plane/agents/material_handoff.py +156 -0
  395. loopx/control_plane/agents/multi_agent/__init__.py +1 -0
  396. loopx/control_plane/agents/multi_agent/codex_executable.py +207 -0
  397. loopx/control_plane/agents/multi_agent/collective_round_ledger.py +387 -0
  398. loopx/control_plane/agents/multi_agent/contract.py +474 -0
  399. loopx/control_plane/agents/multi_agent/recipe.py +110 -0
  400. loopx/control_plane/agents/multi_agent/role_successor.py +297 -0
  401. loopx/control_plane/agents/multi_agent/runtime_scripts.py +426 -0
  402. loopx/control_plane/agents/multi_agent/visible_launch_policy.py +149 -0
  403. loopx/control_plane/agents/multi_agent/visible_wake_scheduler.py +392 -0
  404. loopx/control_plane/agents/profile.py +216 -0
  405. loopx/control_plane/agents/runtime_model.py +73 -0
  406. loopx/control_plane/agents/subagent_activity.py +164 -0
  407. loopx/control_plane/agents/supervisor.py +544 -0
  408. loopx/control_plane/agents/supervisor_events.py +462 -0
  409. loopx/control_plane/agents/supervisor_inject.py +204 -0
  410. loopx/control_plane/agents/work_mode.py +56 -0
  411. loopx/control_plane/agents/workspace_guard.py +364 -0
  412. loopx/control_plane/effect_program.py +644 -0
  413. loopx/control_plane/goals/__init__.py +1 -0
  414. loopx/control_plane/goals/active_state_event_projection.py +103 -0
  415. loopx/control_plane/goals/active_state_metadata.py +47 -0
  416. loopx/control_plane/goals/active_state_sections.py +58 -0
  417. loopx/control_plane/goals/configure_goal_service.py +354 -0
  418. loopx/control_plane/goals/contract_health.py +132 -0
  419. loopx/control_plane/goals/dreaming.py +152 -0
  420. loopx/control_plane/goals/global_registry_health.py +199 -0
  421. loopx/control_plane/goals/global_registry_shadow.py +33 -0
  422. loopx/control_plane/goals/goal_channel.py +34 -0
  423. loopx/control_plane/goals/goal_channel_projection.py +560 -0
  424. loopx/control_plane/goals/goal_frontier/__init__.py +1917 -0
  425. loopx/control_plane/goals/goal_frontier/ack_policy.py +149 -0
  426. loopx/control_plane/goals/goal_frontier/outcome_continuity.py +437 -0
  427. loopx/control_plane/goals/goal_frontier/replan_rules.py +210 -0
  428. loopx/control_plane/goals/goal_frontier/semantic_history.py +314 -0
  429. loopx/control_plane/goals/goal_frontier/terminal.py +180 -0
  430. loopx/control_plane/goals/goal_vision.py +443 -0
  431. loopx/control_plane/goals/goal_vision_policy.py +36 -0
  432. loopx/control_plane/goals/goal_vision_state.py +62 -0
  433. loopx/control_plane/goals/goal_vision_wait.py +290 -0
  434. loopx/control_plane/goals/path_resolution.py +20 -0
  435. loopx/control_plane/goals/start_contract.py +206 -0
  436. loopx/control_plane/goals/vision_checkpoint.py +92 -0
  437. loopx/control_plane/handoff/__init__.py +1 -0
  438. loopx/control_plane/handoff/cross_runtime_impl_review.py +311 -0
  439. loopx/control_plane/handoff/delivery_contract.py +161 -0
  440. loopx/control_plane/handoff/handoff_runs.py +71 -0
  441. loopx/control_plane/handoff/project_handoff.py +155 -0
  442. loopx/control_plane/handoff/review_batch.py +463 -0
  443. loopx/control_plane/handoff/review_packet_context.py +216 -0
  444. loopx/control_plane/heartbeat/agent.py +173 -0
  445. loopx/control_plane/heartbeat/budget.py +66 -0
  446. loopx/control_plane/heartbeat/builder.py +501 -0
  447. loopx/control_plane/heartbeat/host.py +64 -0
  448. loopx/control_plane/heartbeat/rules.py +68 -0
  449. loopx/control_plane/heartbeat/task_body.py +759 -0
  450. loopx/control_plane/heartbeat/visible_goal.py +86 -0
  451. loopx/control_plane/projects/__init__.py +1 -0
  452. loopx/control_plane/projects/contract.py +25 -0
  453. loopx/control_plane/projects/registry.py +663 -0
  454. loopx/control_plane/quota/__init__.py +1 -0
  455. loopx/control_plane/quota/cli_projection.py +704 -0
  456. loopx/control_plane/quota/decision_summary.py +431 -0
  457. loopx/control_plane/quota/effect_program.py +152 -0
  458. loopx/control_plane/quota/error_codes.py +19 -0
  459. loopx/control_plane/quota/goal_boundary.py +464 -0
  460. loopx/control_plane/quota/heartbeat_receipt.py +277 -0
  461. loopx/control_plane/quota/heartbeat_recommendation.py +718 -0
  462. loopx/control_plane/quota/host_poll_receipts.py +162 -0
  463. loopx/control_plane/quota/live_decision.py +142 -0
  464. loopx/control_plane/quota/monitor_poll.py +786 -0
  465. loopx/control_plane/quota/policy_constants.py +40 -0
  466. loopx/control_plane/quota/projection_repair.py +262 -0
  467. loopx/control_plane/quota/recent_runs.py +210 -0
  468. loopx/control_plane/quota/scheduler_ack.py +490 -0
  469. loopx/control_plane/quota/selected_todo_projection.py +139 -0
  470. loopx/control_plane/quota/settlement.py +437 -0
  471. loopx/control_plane/quota/settlement_cli.py +246 -0
  472. loopx/control_plane/quota/settlement_validation.py +64 -0
  473. loopx/control_plane/quota/settlement_workspace_causality.py +180 -0
  474. loopx/control_plane/quota/should_run.py +249 -0
  475. loopx/control_plane/quota/should_run_packet.py +1165 -0
  476. loopx/control_plane/quota/should_run_prepare.py +675 -0
  477. loopx/control_plane/quota/slot_accounting.py +1123 -0
  478. loopx/control_plane/quota/spend_sources.py +11 -0
  479. loopx/control_plane/quota/stall_repair.py +397 -0
  480. loopx/control_plane/quota/states.py +29 -0
  481. loopx/control_plane/quota/task_orchestration.py +448 -0
  482. loopx/control_plane/quota/task_orchestration_admission.py +497 -0
  483. loopx/control_plane/quota/turn_envelope.py +889 -0
  484. loopx/control_plane/quota/usage_summary.py +140 -0
  485. loopx/control_plane/reward_memory.py +43 -0
  486. loopx/control_plane/runtime/__init__.py +2 -0
  487. loopx/control_plane/runtime/active_user_assisted_pilot.py +275 -0
  488. loopx/control_plane/runtime/agent_scoped_evidence_log.py +435 -0
  489. loopx/control_plane/runtime/decision_freshness.py +203 -0
  490. loopx/control_plane/runtime/event_ledger.py +197 -0
  491. loopx/control_plane/runtime/event_store_migration_bridge.py +196 -0
  492. loopx/control_plane/runtime/goal_project_route.py +70 -0
  493. loopx/control_plane/runtime/local_state_write_correctness.py +242 -0
  494. loopx/control_plane/runtime/promotion_readiness.py +152 -0
  495. loopx/control_plane/runtime/public_safety.py +120 -0
  496. loopx/control_plane/runtime/run_artifacts.py +78 -0
  497. loopx/control_plane/runtime/run_compaction.py +397 -0
  498. loopx/control_plane/runtime/run_context_retention.py +241 -0
  499. loopx/control_plane/runtime/run_history.py +132 -0
  500. loopx/control_plane/runtime/run_index_duplicates.py +205 -0
  501. loopx/control_plane/runtime/run_index_rebuild.py +263 -0
  502. loopx/control_plane/runtime/run_ingest_health.py +336 -0
  503. loopx/control_plane/runtime/runtime_projection_route.py +624 -0
  504. loopx/control_plane/runtime/runtime_projection_writer.py +98 -0
  505. loopx/control_plane/runtime/session_runtime.py +339 -0
  506. loopx/control_plane/runtime/shared_runtime_material_projection.py +332 -0
  507. loopx/control_plane/runtime/shared_runtime_refresh_projection.py +183 -0
  508. loopx/control_plane/runtime/stale_latest_run.py +90 -0
  509. loopx/control_plane/runtime/status_classifications.py +49 -0
  510. loopx/control_plane/runtime/status_projection_cache.py +235 -0
  511. loopx/control_plane/runtime/stride_observation.py +144 -0
  512. loopx/control_plane/runtime/time.py +39 -0
  513. loopx/control_plane/runtime/trajectory_hygiene.py +149 -0
  514. loopx/control_plane/runtime/validation_command.py +69 -0
  515. loopx/control_plane/scheduler/__init__.py +1 -0
  516. loopx/control_plane/scheduler/ack.py +329 -0
  517. loopx/control_plane/scheduler/arbitration.py +188 -0
  518. loopx/control_plane/scheduler/automation_liveness.py +183 -0
  519. loopx/control_plane/scheduler/execution_context.py +555 -0
  520. loopx/control_plane/scheduler/external_evidence_observation.py +428 -0
  521. loopx/control_plane/scheduler/monitor_display.py +143 -0
  522. loopx/control_plane/scheduler/monitor_poll_policy.py +161 -0
  523. loopx/control_plane/scheduler/monitor_poll_writeback.py +351 -0
  524. loopx/control_plane/scheduler/monitor_target.py +64 -0
  525. loopx/control_plane/scheduler/monitor_todo.py +146 -0
  526. loopx/control_plane/scheduler/monitor_wait.py +237 -0
  527. loopx/control_plane/scheduler/scheduler_hint.py +1284 -0
  528. loopx/control_plane/scheduler/state.py +354 -0
  529. loopx/control_plane/scheduler/state_transition_rules.py +179 -0
  530. loopx/control_plane/scheduler/time.py +10 -0
  531. loopx/control_plane/settlement_driver.py +293 -0
  532. loopx/control_plane/status/__init__.py +6 -0
  533. loopx/control_plane/status/active_state_projection.py +105 -0
  534. loopx/control_plane/status/agent_lane_projection.py +375 -0
  535. loopx/control_plane/status/attention_projection.py +74 -0
  536. loopx/control_plane/status/autonomous_replan_projection.py +103 -0
  537. loopx/control_plane/status/collection.py +140 -0
  538. loopx/control_plane/status/contract_projection.py +31 -0
  539. loopx/control_plane/status/dreaming_projection.py +52 -0
  540. loopx/control_plane/status/goal_attention_projection.py +157 -0
  541. loopx/control_plane/status/lifecycle_projection.py +110 -0
  542. loopx/control_plane/status/monitor_display_projection.py +69 -0
  543. loopx/control_plane/status/registry_health_projection.py +75 -0
  544. loopx/control_plane/status/run_projection.py +70 -0
  545. loopx/control_plane/status/runtime_summaries.py +161 -0
  546. loopx/control_plane/testing/__init__.py +1 -0
  547. loopx/control_plane/testing/actual_default_model_behavior_portfolio.py +1371 -0
  548. loopx/control_plane/testing/canary_harness.py +182 -0
  549. loopx/control_plane/testing/capability_monitor_repair_tool_behavior.py +674 -0
  550. loopx/control_plane/testing/cli_output_budget.py +807 -0
  551. loopx/control_plane/testing/cli_output_differential.py +250 -0
  552. loopx/control_plane/testing/cli_output_semantics.py +87 -0
  553. loopx/control_plane/testing/control_plane_composition_scenarios.py +225 -0
  554. loopx/control_plane/testing/decision_replay.py +268 -0
  555. loopx/control_plane/testing/doubao_model_behavior_actor.py +559 -0
  556. loopx/control_plane/testing/model_behavior_corpus.py +344 -0
  557. loopx/control_plane/testing/model_behavior_qualification.py +769 -0
  558. loopx/control_plane/testing/model_behavior_retained_cases.py +235 -0
  559. loopx/control_plane/testing/model_tool_behavior.py +536 -0
  560. loopx/control_plane/testing/onboarding_model_behavior_qualification.py +642 -0
  561. loopx/control_plane/testing/quota_fixtures.py +208 -0
  562. loopx/control_plane/testing/quota_should_run_parity.py +57 -0
  563. loopx/control_plane/testing/release_commit_qualification.py +671 -0
  564. loopx/control_plane/testing/replan_semantic_action_behavior.py +1302 -0
  565. loopx/control_plane/testing/scoped_gate_successor_tool_behavior.py +527 -0
  566. loopx/control_plane/testing/selected_todo_tool_behavior.py +1002 -0
  567. loopx/control_plane/testing/terminal_settlement_tool_behavior.py +656 -0
  568. loopx/control_plane/todos/__init__.py +1 -0
  569. loopx/control_plane/todos/active_state_editing.py +296 -0
  570. loopx/control_plane/todos/active_state_todo_parser.py +138 -0
  571. loopx/control_plane/todos/active_state_todos.py +175 -0
  572. loopx/control_plane/todos/addition.py +103 -0
  573. loopx/control_plane/todos/claim_visibility.py +253 -0
  574. loopx/control_plane/todos/completed_archive.py +139 -0
  575. loopx/control_plane/todos/completion_fence.py +49 -0
  576. loopx/control_plane/todos/completion_policy.py +153 -0
  577. loopx/control_plane/todos/completion_validation.py +248 -0
  578. loopx/control_plane/todos/completion_validation_accountability.py +27 -0
  579. loopx/control_plane/todos/completion_validation_projection.py +57 -0
  580. loopx/control_plane/todos/contract.py +1476 -0
  581. loopx/control_plane/todos/decision_scope.py +554 -0
  582. loopx/control_plane/todos/deferred_resume.py +546 -0
  583. loopx/control_plane/todos/durable_completion.py +201 -0
  584. loopx/control_plane/todos/event_writeback.py +484 -0
  585. loopx/control_plane/todos/frontier_deadline.py +132 -0
  586. loopx/control_plane/todos/handoff_gate.py +283 -0
  587. loopx/control_plane/todos/handoff_mode.py +444 -0
  588. loopx/control_plane/todos/handoff_note.py +202 -0
  589. loopx/control_plane/todos/line_update.py +361 -0
  590. loopx/control_plane/todos/list_projection.py +205 -0
  591. loopx/control_plane/todos/markdown.py +199 -0
  592. loopx/control_plane/todos/monitor_metadata.py +88 -0
  593. loopx/control_plane/todos/mutation_authority.py +299 -0
  594. loopx/control_plane/todos/projection.py +655 -0
  595. loopx/control_plane/todos/quota_summary.py +1138 -0
  596. loopx/control_plane/todos/route_continuation.py +267 -0
  597. loopx/control_plane/todos/succession_warning.py +174 -0
  598. loopx/control_plane/todos/summary_item.py +223 -0
  599. loopx/control_plane/todos/text.py +30 -0
  600. loopx/control_plane/todos/todo_index.py +226 -0
  601. loopx/control_plane/todos/todo_summary.py +1458 -0
  602. loopx/control_plane/todos/unblock_resume.py +326 -0
  603. loopx/control_plane/todos/user_gate.py +263 -0
  604. loopx/control_plane/todos/write_hint.py +63 -0
  605. loopx/control_plane/todos/write_policy.py +135 -0
  606. loopx/control_plane/turn_driver/__init__.py +85 -0
  607. loopx/control_plane/turn_driver/codex_cli.py +502 -0
  608. loopx/control_plane/turn_driver/driver.py +355 -0
  609. loopx/control_plane/turn_driver/executor.py +1468 -0
  610. loopx/control_plane/turn_driver/loop_controller.py +669 -0
  611. loopx/control_plane/turn_driver/settlement.py +318 -0
  612. loopx/control_plane/turn_driver/transaction.py +375 -0
  613. loopx/control_plane/work_items/__init__.py +1 -0
  614. loopx/control_plane/work_items/attention_fields.py +56 -0
  615. loopx/control_plane/work_items/attention_item.py +77 -0
  616. loopx/control_plane/work_items/attention_queue.py +322 -0
  617. loopx/control_plane/work_items/attention_routing.py +213 -0
  618. loopx/control_plane/work_items/autonomous_candidates.py +135 -0
  619. loopx/control_plane/work_items/autonomous_replan_ack.py +276 -0
  620. loopx/control_plane/work_items/autonomous_replan_obligation.py +786 -0
  621. loopx/control_plane/work_items/backlog_hygiene.py +59 -0
  622. loopx/control_plane/work_items/capability_monitor_fallback.py +221 -0
  623. loopx/control_plane/work_items/delivery_batch_scale.py +66 -0
  624. loopx/control_plane/work_items/delivery_outcome.py +152 -0
  625. loopx/control_plane/work_items/delivery_signals.py +113 -0
  626. loopx/control_plane/work_items/execution_obligation.py +235 -0
  627. loopx/control_plane/work_items/goal_route_hint.py +320 -0
  628. loopx/control_plane/work_items/interaction_contract.py +1540 -0
  629. loopx/control_plane/work_items/issue_meta_surface.py +159 -0
  630. loopx/control_plane/work_items/lifecycle.py +139 -0
  631. loopx/control_plane/work_items/operator_inbox.py +266 -0
  632. loopx/control_plane/work_items/outcome_followthrough.py +69 -0
  633. loopx/control_plane/work_items/primary_action.py +326 -0
  634. loopx/control_plane/work_items/progress_observation.py +630 -0
  635. loopx/control_plane/work_items/project_asset.py +675 -0
  636. loopx/control_plane/work_items/repair_delta.py +693 -0
  637. loopx/control_plane/work_items/runtime_capability_reentry.py +168 -0
  638. loopx/control_plane/work_items/semantic_replan_writeback.py +177 -0
  639. loopx/control_plane/work_items/status_contract.py +49 -0
  640. loopx/control_plane/work_items/task_graph.py +1046 -0
  641. loopx/control_plane/work_items/task_lease.py +1254 -0
  642. loopx/control_plane/work_items/task_lease_settlement.py +422 -0
  643. loopx/control_plane/work_items/work_lane.py +510 -0
  644. loopx/control_plane/work_items/work_lane_context.py +161 -0
  645. loopx/demo.py +247 -0
  646. loopx/diagnose.py +633 -0
  647. loopx/doctor.py +1251 -0
  648. loopx/domain_packs/__init__.py +1 -0
  649. loopx/domain_packs/issue_fix.py +571 -0
  650. loopx/domain_packs/ml_experiment.py +854 -0
  651. loopx/domain_state.py +137 -0
  652. loopx/dreaming.py +706 -0
  653. loopx/entrypoint.py +16 -0
  654. loopx/event_sourced_state.py +981 -0
  655. loopx/execution_profile.py +286 -0
  656. loopx/experiments/__init__.py +1 -0
  657. loopx/experiments/planner_worker/__init__.py +1 -0
  658. loopx/experiments/planner_worker/contract.py +523 -0
  659. loopx/experiments/planner_worker/runtime.py +391 -0
  660. loopx/experiments/planner_worker/traex.py +461 -0
  661. loopx/explore_graph.py +11 -0
  662. loopx/extensions/__init__.py +1 -0
  663. loopx/extensions/bundled.py +28 -0
  664. loopx/extensions/execution_envelope.py +126 -0
  665. loopx/extensions/lark/__init__.py +11 -0
  666. loopx/extensions/lark/event_collector.py +478 -0
  667. loopx/extensions/lark/event_collector_runtime.py +506 -0
  668. loopx/extensions/lark/event_inbox.py +454 -0
  669. loopx/extensions/lark/extension.toml +88 -0
  670. loopx/extensions/lark/goal_channel.py +44 -0
  671. loopx/extensions/lark/goal_channel_contracts.py +388 -0
  672. loopx/extensions/lark/goal_channel_lifecycle.py +218 -0
  673. loopx/extensions/lark/goal_channel_runtime.py +792 -0
  674. loopx/extensions/lark/goal_channel_setup.py +805 -0
  675. loopx/extensions/lark/goal_channel_targets.py +215 -0
  676. loopx/extensions/lark/goal_channel_transport.py +281 -0
  677. loopx/extensions/lark/inbox_reactions.py +650 -0
  678. loopx/extensions/lark/inbox_reply.py +430 -0
  679. loopx/extensions/lark/presentation/__init__.py +11 -0
  680. loopx/extensions/lark/presentation/explore_results.py +2276 -0
  681. loopx/extensions/lark/presentation/explore_singleflight.py +127 -0
  682. loopx/extensions/lark/presentation/explore_source_guard.py +121 -0
  683. loopx/extensions/lark/presentation/explore_stage_document.py +703 -0
  684. loopx/extensions/lark/presentation/explore_visual_integrity.py +122 -0
  685. loopx/extensions/lark/presentation/explore_visual_readback.py +452 -0
  686. loopx/extensions/lark/presentation/explore_visual_styles.py +156 -0
  687. loopx/extensions/lark/presentation/issue_fix_surface.py +612 -0
  688. loopx/extensions/lark/presentation/kanban.py +2791 -0
  689. loopx/extensions/lark/presentation/message_card.py +112 -0
  690. loopx/extensions/lark/presentation/periodic_report.py +261 -0
  691. loopx/extensions/lark/presentation/projection_rows.py +600 -0
  692. loopx/extensions/lark/presentation/record_io.py +95 -0
  693. loopx/extensions/lark/presentation/sync_receipt.py +145 -0
  694. loopx/extensions/lark/private_json.py +40 -0
  695. loopx/extensions/lark/provider.py +86 -0
  696. loopx/extensions/lark/reviewer_notification.py +604 -0
  697. loopx/extensions/manifest.py +385 -0
  698. loopx/extensions/openviking_periodic_report/__init__.py +17 -0
  699. loopx/extensions/openviking_periodic_report/activation.py +173 -0
  700. loopx/extensions/openviking_periodic_report/extension.toml +17 -0
  701. loopx/extensions/openviking_periodic_report/provider.py +355 -0
  702. loopx/extensions/openviking_periodic_report/sink.py +117 -0
  703. loopx/extensions/openviking_semantic_preference/__init__.py +5 -0
  704. loopx/extensions/openviking_semantic_preference/extension.toml +16 -0
  705. loopx/extensions/openviking_semantic_preference/history_export.py +484 -0
  706. loopx/extensions/openviking_semantic_preference/project_peer.py +68 -0
  707. loopx/extensions/openviking_semantic_preference/provider.py +312 -0
  708. loopx/extensions/presentation.py +979 -0
  709. loopx/extensions/process_runtime.py +204 -0
  710. loopx/extensions/readiness.py +168 -0
  711. loopx/extensions/runtime.py +931 -0
  712. loopx/extensions/scaffold.py +335 -0
  713. loopx/feedback.py +581 -0
  714. loopx/file_lock.py +382 -0
  715. loopx/global_registry.py +842 -0
  716. loopx/global_risks.py +970 -0
  717. loopx/global_todos.py +568 -0
  718. loopx/handoff_budget.py +28 -0
  719. loopx/heartbeat_prequota.py +80 -0
  720. loopx/heartbeat_prompt.py +159 -0
  721. loopx/help_surface.py +516 -0
  722. loopx/history.py +1507 -0
  723. loopx/host_loop_activation.py +1311 -0
  724. loopx/host_mode_planner.py +991 -0
  725. loopx/install_contract.py +1 -0
  726. loopx/interface_budget.py +196 -0
  727. loopx/long_task_cadence.py +208 -0
  728. loopx/materials.py +185 -0
  729. loopx/ml_experiment.py +3 -0
  730. loopx/onboarding.py +214 -0
  731. loopx/opencode2_goal_mode/README.md +81 -0
  732. loopx/opencode2_goal_mode/__init__.py +9 -0
  733. loopx/opencode2_goal_mode/opencode2-goal-worker.mjs +1018 -0
  734. loopx/opencode_goal_mode/README.md +99 -0
  735. loopx/opencode_goal_mode/__init__.py +13 -0
  736. loopx/opencode_goal_mode/goal-bridge-runtime.mjs +858 -0
  737. loopx/opencode_goal_mode/loopx-goal.js +8 -0
  738. loopx/operator_gate.py +420 -0
  739. loopx/orchestration.py +127 -0
  740. loopx/paths.py +59 -0
  741. loopx/pi_goal_mode/README.md +67 -0
  742. loopx/pi_goal_mode/__init__.py +13 -0
  743. loopx/pi_goal_mode/loopx-goal.ts +254 -0
  744. loopx/pi_goal_mode/pi-goal-loop-runtime.mjs +574 -0
  745. loopx/pr_review.py +1206 -0
  746. loopx/presentation/__init__.py +1 -0
  747. loopx/presentation/explore_views.py +1334 -0
  748. loopx/presentation/markdown.py +61 -0
  749. loopx/presentation/projection_source_reconcile.py +140 -0
  750. loopx/presentation/public_safety.py +42 -0
  751. loopx/presentation/renderers/__init__.py +17 -0
  752. loopx/presentation/renderers/goal_channel_html.py +269 -0
  753. loopx/presentation/renderers/periodic_report_html.py +786 -0
  754. loopx/presentation/renderers/periodic_report_markdown.py +184 -0
  755. loopx/presentation/renderers/quota_event_markdown.py +116 -0
  756. loopx/presentation/renderers/quota_markdown.py +1112 -0
  757. loopx/presentation/renderers/status_markdown.py +1570 -0
  758. loopx/presentation/renderers/trajectory_hygiene_markdown.py +39 -0
  759. loopx/presentation/renderers/turn_envelope_markdown.py +33 -0
  760. loopx/presentation/sinks/__init__.py +5 -0
  761. loopx/presentation/sinks/openviking_periodic_report.py +7 -0
  762. loopx/presentation/static_site.py +691 -0
  763. loopx/presets.py +369 -0
  764. loopx/project_alias.py +217 -0
  765. loopx/project_map.py +589 -0
  766. loopx/project_prompt.py +1153 -0
  767. loopx/project_skill_cli.py +125 -0
  768. loopx/project_skill_delivery.py +470 -0
  769. loopx/project_uninstall.py +462 -0
  770. loopx/promotion_gate.py +197 -0
  771. loopx/quota.py +1197 -0
  772. loopx/ready_score.py +413 -0
  773. loopx/registry.py +621 -0
  774. loopx/registry_writability.py +64 -0
  775. loopx/release_candidate.py +148 -0
  776. loopx/release_manifest.py +316 -0
  777. loopx/repository_identity.py +100 -0
  778. loopx/review_packet.py +1024 -0
  779. loopx/rollout_event_log.py +505 -0
  780. loopx/runtime.py +112 -0
  781. loopx/self_update.py +750 -0
  782. loopx/session_runtime.py +418 -0
  783. loopx/skill_install_readback.py +500 -0
  784. loopx/slash_command_install.py +1393 -0
  785. loopx/slash_commands.py +264 -0
  786. loopx/state_backup.py +573 -0
  787. loopx/state_migration.py +350 -0
  788. loopx/state_projection.py +809 -0
  789. loopx/state_refresh.py +1416 -0
  790. loopx/status.py +1383 -0
  791. loopx/status_server.py +935 -0
  792. loopx/summary_all.py +725 -0
  793. loopx/terminal_bench_agent.py +2056 -0
  794. loopx/thread_agent_binding.py +408 -0
  795. loopx/todo_followups.py +168 -0
  796. loopx/todo_suggestion_prompt.py +204 -0
  797. loopx/todos.py +2229 -0
  798. loopx/turn_identity.py +17 -0
  799. loopx/upgrade.py +1083 -0
  800. loopx/visible_governance.py +667 -0
  801. loopx/visible_multi_agent_launcher.py +1253 -0
  802. loopx/visible_multi_agent_tmux.py +429 -0
  803. loopx/worker_bridge.py +1574 -0
  804. loopx-0.4.8.dist-info/METADATA +708 -0
  805. loopx-0.4.8.dist-info/RECORD +811 -0
  806. loopx-0.4.8.dist-info/WHEEL +5 -0
  807. loopx-0.4.8.dist-info/entry_points.txt +5 -0
  808. loopx-0.4.8.dist-info/licenses/LICENSE +202 -0
  809. loopx-0.4.8.dist-info/licenses/LICENSE-MIT +21 -0
  810. loopx-0.4.8.dist-info/licenses/NOTICE +6 -0
  811. loopx-0.4.8.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1286 @@
1
+ from __future__ import annotations
2
+
3
+ import shlex
4
+ from collections.abc import Mapping, Sequence
5
+ from typing import Any
6
+
7
+ from .acceptance_loop import build_issue_fix_caller_repo_branch_packet
8
+ from .candidate_preflight import build_issue_fix_candidate_preflight_packet
9
+ from .intake_surface import build_content_ops_issue_fix_metadata_preview_packet
10
+ from .repository_context import (
11
+ ISSUE_FIX_REPOSITORY_CONTEXT_INPUT_SCHEMA_VERSION,
12
+ build_issue_fix_repository_context_packet,
13
+ repository_context_input_contract,
14
+ )
15
+
16
+ ISSUE_FIX_WORKFLOW_PLAN_PACKET_SCHEMA_VERSION = "issue_fix_workflow_plan_packet_v0"
17
+ ISSUE_FIX_GOAL_CANDIDATE_DISCOVERY_COMMAND_TEMPLATE = (
18
+ "gh issue list --repo "
19
+ '"$(gh repo view --json nameWithOwner --jq .nameWithOwner)" '
20
+ "--state open --limit 20 --json number,title,url,labels"
21
+ )
22
+ def _command_arg(value: str) -> str:
23
+ if value.startswith("<") and value.endswith(">"):
24
+ return value
25
+ return shlex.quote(value)
26
+
27
+
28
+ def build_issue_fix_pr_lifecycle_command(
29
+ *,
30
+ cli_bin: str,
31
+ goal_id: str,
32
+ agent_id: str,
33
+ project: str | None = None,
34
+ ) -> str:
35
+ """Build the canonical executable PR lifecycle reconciliation command."""
36
+
37
+ parts = [
38
+ shlex.quote(cli_bin),
39
+ "issue-fix",
40
+ "pr-lifecycle",
41
+ "--url",
42
+ "<github-pr-url>",
43
+ ]
44
+ if project:
45
+ parts.extend(["--project", _command_arg(project)])
46
+ parts.extend(
47
+ [
48
+ "--goal-id",
49
+ _command_arg(goal_id),
50
+ "--claimed-by",
51
+ _command_arg(agent_id),
52
+ "--execute-transition",
53
+ "--format",
54
+ "json",
55
+ ]
56
+ )
57
+ return " ".join(parts)
58
+
59
+
60
+ def build_issue_fix_goal_command_templates(
61
+ *, cli_bin: str, goal_id: str, agent_id: str = "<agent-id>"
62
+ ) -> dict[str, str]:
63
+ """Return the capability-owned commands projected into goal-start packets."""
64
+
65
+ cli = shlex.quote(cli_bin)
66
+ goal = (
67
+ goal_id
68
+ if goal_id.startswith("<") and goal_id.endswith(">")
69
+ else shlex.quote(goal_id)
70
+ )
71
+ return {
72
+ "issue_fix_workflow_plan_template": (
73
+ f"{cli} issue-fix workflow-plan "
74
+ "--url <github-issue-or-pr-url> "
75
+ "--repo-path <approved-repo> "
76
+ "--repository-context-json <compact-context.json> "
77
+ "--fetch-candidate-evidence "
78
+ "--validation-label '<validation command>' "
79
+ f"--goal-id {goal} "
80
+ "--format json"
81
+ ),
82
+ "issue_fix_feasibility_template": (
83
+ f"{cli} issue-fix feasibility "
84
+ "--url <github-issue-or-pr-url> "
85
+ "--reproduction-status <confirmed|planned|missing|blocked> "
86
+ "--scope-class <bounded|uncertain|oversized> "
87
+ "--repository-context-json <compact-context.json> "
88
+ f"--goal-id {goal} "
89
+ "--format json"
90
+ ),
91
+ "issue_fix_pr_lifecycle_template": build_issue_fix_pr_lifecycle_command(
92
+ cli_bin=cli_bin,
93
+ goal_id=goal_id,
94
+ agent_id=agent_id,
95
+ ),
96
+ "issue_fix_reviewer_request_template": (
97
+ f"{cli} issue-fix reviewer-request "
98
+ "--url <github-pr-url> "
99
+ "--repo-path <approved-repo> "
100
+ "--base-ref <base-ref> "
101
+ "--execute --format json"
102
+ ),
103
+ }
104
+
105
+
106
+ def _todo_preview(
107
+ *,
108
+ planner_order: int,
109
+ role: str,
110
+ priority: str,
111
+ task_class: str,
112
+ action_kind: str,
113
+ text: str,
114
+ depends_on: Sequence[str],
115
+ blocks: Sequence[str] | None = None,
116
+ target_key: str | None = None,
117
+ next_command_preview: str | None = None,
118
+ ) -> dict[str, Any]:
119
+ preview = {
120
+ "schema_version": "loopx_todo_writeback_preview_v0",
121
+ "planner_order": planner_order,
122
+ "command_preview": "loopx todo add",
123
+ "role": role,
124
+ "priority": priority,
125
+ "status": "preview_only",
126
+ "task_class": task_class,
127
+ "action_kind": action_kind,
128
+ "text": text,
129
+ "depends_on": list(depends_on),
130
+ "blocks": list(blocks or []),
131
+ "would_write": False,
132
+ "requires_execute_flag": True,
133
+ }
134
+ if target_key:
135
+ preview["target_key"] = target_key
136
+ if next_command_preview:
137
+ preview["next_command_preview"] = next_command_preview
138
+ return preview
139
+
140
+
141
+ def _resolution_route_candidates(
142
+ *,
143
+ repo_label: str,
144
+ issue_label: str,
145
+ ) -> list[dict[str, Any]]:
146
+ return [
147
+ {
148
+ "schema_version": "issue_fix_resolution_route_candidate_v0",
149
+ "route": "fix_pr",
150
+ "priority": "P0",
151
+ "when": [
152
+ "public metadata suggests a bounded bug",
153
+ "caller-approved repo context is available",
154
+ "a focused repro or validation label can be named",
155
+ ],
156
+ "next_action_kind": "issue_fix_branch_validation",
157
+ "external_issue_comment_performed": False,
158
+ "external_pr_created": False,
159
+ "requires_user_gate_before_external_write": True,
160
+ "summary": (
161
+ f"Prepare a small fix branch for {repo_label} {issue_label}, "
162
+ "validate it, and emit a PR review packet."
163
+ ),
164
+ },
165
+ {
166
+ "schema_version": "issue_fix_resolution_route_candidate_v0",
167
+ "route": "comment_only",
168
+ "priority": "P1",
169
+ "when": [
170
+ "the issue needs missing repro detail",
171
+ "the safe answer is maintainer-facing clarification",
172
+ "patching would require private material or oversized design work",
173
+ ],
174
+ "next_action_kind": "issue_fix_external_comment_packet",
175
+ "external_issue_comment_performed": False,
176
+ "external_pr_created": False,
177
+ "requires_user_gate_before_external_write": True,
178
+ "summary": (
179
+ "Draft a public-safe maintainer comment packet, but require an "
180
+ "explicit gate before posting it."
181
+ ),
182
+ },
183
+ {
184
+ "schema_version": "issue_fix_resolution_route_candidate_v0",
185
+ "route": "triage_only",
186
+ "priority": "P2",
187
+ "when": [
188
+ "public metadata is too weak for repro or a useful comment",
189
+ "the issue is likely policy, product, or environment specific",
190
+ ],
191
+ "next_action_kind": "issue_fix_no_followup_or_owner_gate",
192
+ "external_issue_comment_performed": False,
193
+ "external_pr_created": False,
194
+ "requires_user_gate_before_external_write": True,
195
+ "summary": (
196
+ "Record a blocker or no-follow-up decision rather than opening "
197
+ "an ungrounded patch loop."
198
+ ),
199
+ },
200
+ ]
201
+
202
+
203
+ def _post_pr_lifecycle_monitor_plan() -> dict[str, Any]:
204
+ return {
205
+ "schema_version": "issue_fix_post_pr_lifecycle_monitor_plan_v1",
206
+ "command_preview": build_issue_fix_pr_lifecycle_command(
207
+ cli_bin="loopx",
208
+ goal_id="<goal-id>",
209
+ agent_id="<agent-id>",
210
+ project="<approved-repo>",
211
+ ),
212
+ "creates_per_pr_continuous_monitor_todo": False,
213
+ "monitor_scope": "lifecycle_state_bucket",
214
+ "monitor_action_kind_template": "issue_fix_pr_state_<state_bucket>_monitor",
215
+ "bucket_projection_source": "pr-lifecycle.grouped_monitor_projection",
216
+ "materializes_nonempty_buckets_only": True,
217
+ "terminal_members_removed": True,
218
+ "per_pr_material_actions_are_one_shot": True,
219
+ "external_notification_granularity": "one_pr_per_message",
220
+ "decisions": [
221
+ "runnable_successor",
222
+ "monitor_continuation",
223
+ "user_gate",
224
+ "no_followup",
225
+ ],
226
+ "terminal_state_precedence": (
227
+ "PR terminal states such as MERGED or CLOSED win over stale review "
228
+ "metadata and must close the monitor with no-follow-up."
229
+ ),
230
+ "external_writes_performed": False,
231
+ "raw_check_logs_captured": False,
232
+ }
233
+
234
+
235
+ def _feasibility_checkpoint_plan() -> dict[str, Any]:
236
+ return {
237
+ "schema_version": "issue_fix_feasibility_checkpoint_plan_v0",
238
+ "command_preview": (
239
+ "loopx issue-fix feasibility --url <github-issue-url> "
240
+ "--reproduction-status <confirmed|planned|missing|blocked> "
241
+ "--scope-class <bounded|uncertain|oversized> "
242
+ "--repository-context-json <compact-context.json> "
243
+ "--goal-id <goal-id> --format json"
244
+ ),
245
+ "input_contract": "compact_public_safe_agent_observation",
246
+ "selects_exactly_one_route": True,
247
+ "required_when_candidate_preflight_route": "proceed",
248
+ "non_proceed_receipt_stream": "candidate-preflight",
249
+ "routes": ["fix_pr", "comment_only", "triage_only"],
250
+ "fix_pr_requires": [
251
+ "bounded_scope",
252
+ "named_reproduction_or_plan",
253
+ "named_validation_surface",
254
+ ],
255
+ "writes_domain_state_by_default_with_goal_id": True,
256
+ "persists_repository_context_with_feasibility": True,
257
+ "writes_loopx_todo": False,
258
+ "raw_issue_or_log_material_captured": False,
259
+ }
260
+
261
+
262
+ def _branch_plan_from_dry_run(
263
+ *,
264
+ repo_path: str | None,
265
+ repo: str,
266
+ issue_ref: str,
267
+ url: str | None,
268
+ base_branch: str,
269
+ issue_branch: str | None,
270
+ validation_label: str,
271
+ generated_at: str | None,
272
+ ) -> dict[str, Any]:
273
+ if not repo_path:
274
+ return {
275
+ "schema_version": "issue_fix_workflow_branch_plan_v0",
276
+ "status": "needs_approved_repo_context",
277
+ "repo_label": repo,
278
+ "base_branch": base_branch,
279
+ "issue_branch": issue_branch,
280
+ "branch_ready": False,
281
+ "repo_path_captured": False,
282
+ "private_repo_state_read": False,
283
+ "execute_required_for_branch_claim": True,
284
+ }
285
+
286
+ dry_run = build_issue_fix_caller_repo_branch_packet(
287
+ repo_path=repo_path,
288
+ repo=repo,
289
+ issue_ref=issue_ref,
290
+ url=url,
291
+ base_branch=base_branch,
292
+ issue_branch=issue_branch,
293
+ validation_label=validation_label,
294
+ execute=False,
295
+ generated_at=generated_at,
296
+ )
297
+ branch = dry_run.get("caller_repo_branch")
298
+ if not isinstance(branch, Mapping):
299
+ raise ValueError("caller repo branch dry-run did not return branch metadata")
300
+ return {
301
+ "schema_version": "issue_fix_workflow_branch_plan_v0",
302
+ "status": "approved_repo_dry_run",
303
+ "repo_label": branch.get("repo_label"),
304
+ "base_branch": branch.get("base_branch"),
305
+ "issue_branch": branch.get("issue_branch"),
306
+ "branch_action": branch.get("branch_action"),
307
+ "branch_ready": False,
308
+ "repo_path_captured": False,
309
+ "private_repo_state_read": False,
310
+ "execute_required_for_branch_claim": True,
311
+ "dry_run_schema_version": dry_run.get("schema_version"),
312
+ }
313
+
314
+
315
+ def build_issue_fix_workflow_plan_packet(
316
+ *,
317
+ repo: str = "public_repo_fixture",
318
+ issue_ref: str = "issue_123_public_metadata_fixture",
319
+ url: str | None = None,
320
+ provider_payload: Mapping[str, Any] | None = None,
321
+ fetch_metadata: bool = False,
322
+ fetch_timeout_seconds: int = 10,
323
+ repo_path: str | None = None,
324
+ base_branch: str = "main",
325
+ issue_branch: str | None = None,
326
+ validation_label: str = "caller-declared validation",
327
+ repository_context_input: Mapping[str, Any] | None = None,
328
+ repository_memory_input: Mapping[str, Any] | None = None,
329
+ candidate_preflight_input: Mapping[str, Any] | None = None,
330
+ generated_at: str | None = "2026-06-23T00:00:00Z",
331
+ ) -> dict[str, Any]:
332
+ """Build a public-safe issue-fix workflow plan without writing state."""
333
+
334
+ metadata_packet = build_content_ops_issue_fix_metadata_preview_packet(
335
+ repo=repo,
336
+ issue_ref=issue_ref,
337
+ url=url,
338
+ provider_payload=provider_payload,
339
+ fetch_metadata=fetch_metadata,
340
+ fetch_timeout_seconds=fetch_timeout_seconds,
341
+ generated_at=generated_at,
342
+ )
343
+ metadata = metadata_packet["github_metadata_preview"]
344
+ intake = metadata_packet["issue_fix_intake"]
345
+ adapter_preview = metadata_packet["adapter_preview"]
346
+ gated_fields = list(adapter_preview.get("gated_provider_fields_present") or [])
347
+ branch_plan = _branch_plan_from_dry_run(
348
+ repo_path=repo_path,
349
+ repo=str(metadata["repo"]),
350
+ issue_ref=str(metadata["issue_ref"]),
351
+ url=url,
352
+ base_branch=base_branch,
353
+ issue_branch=issue_branch,
354
+ validation_label=validation_label,
355
+ generated_at=generated_at,
356
+ )
357
+
358
+ repo_label = str(metadata["repo"])
359
+ issue_label = str(metadata["issue_ref"])
360
+ candidate_preflight = build_issue_fix_candidate_preflight_packet(
361
+ repo=repo_label,
362
+ issue_ref=issue_label,
363
+ input_payload=candidate_preflight_input,
364
+ generated_at=generated_at,
365
+ )
366
+ candidate_source_receipt = (
367
+ candidate_preflight.get("evidence", {}).get("source_receipt")
368
+ if isinstance(candidate_preflight.get("evidence"), Mapping)
369
+ else None
370
+ )
371
+ repository_context = build_issue_fix_repository_context_packet(
372
+ repo=repo_label,
373
+ issue_ref=issue_label,
374
+ context_input=repository_context_input,
375
+ memory_retrieval_input=repository_memory_input,
376
+ generated_at=generated_at,
377
+ )
378
+ unresolved_context = list(
379
+ repository_context.get("unresolved_required_aspects") or []
380
+ )
381
+ resolution_routes = _resolution_route_candidates(
382
+ repo_label=repo_label,
383
+ issue_label=issue_label,
384
+ )
385
+ feasibility_checkpoint = _feasibility_checkpoint_plan()
386
+ post_pr_monitor = _post_pr_lifecycle_monitor_plan()
387
+ default_agent_todos = [
388
+ _todo_preview(
389
+ planner_order=1,
390
+ role="agent",
391
+ priority="P0",
392
+ task_class="advancement_task",
393
+ action_kind="issue_fix_public_metadata_classification",
394
+ text=(
395
+ f"[P0] Classify {repo_label} {issue_label} from body-free public "
396
+ "metadata and compact repository context; ground any missing "
397
+ "change-scope, reproduction, or validation evidence, or preserve it "
398
+ "as unresolved before routing."
399
+ ),
400
+ depends_on=[
401
+ "content_ops_issue_fix_metadata_preview_packet_v0",
402
+ "issue_fix_intake_v0",
403
+ "issue_fix_repository_context_v0",
404
+ ],
405
+ ),
406
+ _todo_preview(
407
+ planner_order=2,
408
+ role="agent",
409
+ priority="P0",
410
+ task_class="advancement_task",
411
+ action_kind="issue_fix_feasibility_decision",
412
+ text=(
413
+ "[P0] Record a compact feasibility observation and select exactly "
414
+ "one fix_pr, comment_only, or triage_only route; write only the "
415
+ "selected successor."
416
+ ),
417
+ depends_on=["issue_fix_public_metadata_classification"],
418
+ ),
419
+ ]
420
+ preflight_decision = candidate_preflight.get("decision") or {}
421
+ preflight_admission = candidate_preflight.get("admission") or {}
422
+ preflight_route = preflight_decision.get("route")
423
+ admission_state = str(preflight_admission.get("state") or "")
424
+ successors = list(preflight_admission.get("successors") or [])
425
+ agent_todos = default_agent_todos
426
+ if admission_state in {"evidence_required", "verification_required"}:
427
+ successor_text = {
428
+ "issue_fix_collect_candidate_evidence": (
429
+ "[P0] Collect complete source-backed closing PR, cross-reference, "
430
+ f"and maintainer-comment metadata for {repo_label} {issue_label}; "
431
+ "rerun candidate admission before implementation."
432
+ ),
433
+ "issue_fix_verify_pr_current_revision": (
434
+ "[P0] Inspect {ref} at revision {revision} and record whether that "
435
+ f"exact revision implements {repo_label} {issue_label}; rerun "
436
+ "candidate admission with the compact resolution receipt."
437
+ ),
438
+ "issue_fix_resolve_closed_candidate": (
439
+ "[P0] Classify why closed candidate {ref} ended and record retry, "
440
+ f"comment-only, or skip for {repo_label} {issue_label}; do not "
441
+ "silently reopen implementation."
442
+ ),
443
+ "issue_fix_read_maintainer_disposition": (
444
+ "[P0] After the provider-content gate, read the referenced maintainer "
445
+ f"comments for {repo_label} {issue_label} at evidence revision "
446
+ "{revision}; retain only a compact non-blocking, comment-only, or "
447
+ "skip outcome, and rerun admission."
448
+ ),
449
+ }
450
+ collect_command = (
451
+ "loopx issue-fix workflow-plan --url <github-issue-url> "
452
+ "--fetch-candidate-evidence --goal-id <goal-id> --format json"
453
+ )
454
+ resolution_command = (
455
+ "loopx issue-fix workflow-plan --url <github-issue-url> "
456
+ "--fetch-candidate-evidence "
457
+ "--candidate-resolution-json <candidate-resolution.json> "
458
+ "--goal-id <goal-id> --format json"
459
+ )
460
+ agent_todos = []
461
+ for order, successor in enumerate(successors, start=1):
462
+ action_kind = str(successor.get("action_kind") or "")
463
+ template = successor_text[action_kind]
464
+ agent_todos.append(
465
+ _todo_preview(
466
+ planner_order=order,
467
+ role="agent",
468
+ priority="P0",
469
+ task_class="advancement_task",
470
+ action_kind=action_kind,
471
+ text=template.format(
472
+ ref=successor.get("ref"),
473
+ revision=successor.get("revision"),
474
+ ),
475
+ depends_on=["issue_fix_candidate_preflight_v0"],
476
+ target_key=str(successor.get("target_key") or ""),
477
+ next_command_preview=(
478
+ collect_command
479
+ if action_kind == "issue_fix_collect_candidate_evidence"
480
+ else resolution_command
481
+ ),
482
+ )
483
+ )
484
+ elif preflight_route != "proceed":
485
+ existing_refs = list(preflight_decision.get("existing_pr_refs") or [])
486
+ route_action = {
487
+ "reuse_existing_pr": "issue_fix_reuse_existing_pr",
488
+ "comment_only": "issue_fix_existing_work_disposition",
489
+ "skip": "issue_fix_candidate_no_followup",
490
+ }[preflight_route]
491
+ route_text = {
492
+ "reuse_existing_pr": (
493
+ f"[P0] Evaluate and reuse existing implementation work "
494
+ f"{', '.join(existing_refs)} for {repo_label} {issue_label}; "
495
+ "do not create a competing patch or reopen agentic recall."
496
+ ),
497
+ "comment_only": (
498
+ f"[P0] Preserve the existing disposition for {repo_label} "
499
+ f"{issue_label}; assess whether a compact maintainer comment is "
500
+ "useful before any new patch planning."
501
+ ),
502
+ "skip": (
503
+ f"[P0] Record the prior-work no-follow-up disposition for "
504
+ f"{repo_label} {issue_label}; do not make the issue runnable again."
505
+ ),
506
+ }[preflight_route]
507
+ agent_todos = [
508
+ _todo_preview(
509
+ planner_order=1,
510
+ role="agent",
511
+ priority="P0",
512
+ task_class="advancement_task",
513
+ action_kind=route_action,
514
+ text=route_text,
515
+ depends_on=["issue_fix_candidate_preflight_v0"],
516
+ )
517
+ ]
518
+ user_gates: list[dict[str, Any]] = []
519
+ comment_read_required = any(
520
+ isinstance(successor, Mapping)
521
+ and successor.get("action_kind") == "issue_fix_read_maintainer_disposition"
522
+ for successor in successors
523
+ )
524
+ if (gated_fields and preflight_route == "proceed") or comment_read_required:
525
+ gate_fields = sorted(
526
+ set(gated_fields) | ({"comments"} if comment_read_required else set())
527
+ )
528
+ user_gates.append(
529
+ _todo_preview(
530
+ planner_order=len(agent_todos) + 1,
531
+ role="user",
532
+ priority="P0",
533
+ task_class="user_gate",
534
+ action_kind="approve_github_issue_body_or_comment_read",
535
+ text=(
536
+ "[P0] Approve a gated read before LoopX uses GitHub issue "
537
+ "body, comment bodies, timeline events, or raw provider payloads."
538
+ ),
539
+ depends_on=["content_ops_issue_fix_metadata_preview_packet_v0"],
540
+ blocks=["private_repro_material_read", "raw_issue_body_read"],
541
+ )
542
+ | {"gated_fields": gate_fields},
543
+ )
544
+ ordered_previews = sorted(
545
+ agent_todos + user_gates,
546
+ key=lambda preview: int(preview.get("planner_order", 0)),
547
+ )
548
+
549
+ validation_plan = [
550
+ {
551
+ "schema_version": "issue_fix_validation_command_v0",
552
+ "command_label": validation_label,
553
+ "command_captured": False,
554
+ "stdout_captured": False,
555
+ "stderr_captured": False,
556
+ "local_path_captured": False,
557
+ "required_for_pr_review": True,
558
+ "executed": False,
559
+ "passed": False,
560
+ }
561
+ ]
562
+ readiness_blockers = [
563
+ "branch_not_executed",
564
+ "validation_not_run",
565
+ "repo_relative_changed_files_missing",
566
+ ]
567
+ if branch_plan["status"] == "needs_approved_repo_context":
568
+ readiness_blockers.insert(0, "approved_repo_context_missing")
569
+ review_packet_preview = {
570
+ "schema_version": "issue_fix_pr_review_packet_v0",
571
+ "ready": False,
572
+ "readiness_blockers": readiness_blockers,
573
+ "files_changed": [],
574
+ "validation_commands": [validation_label],
575
+ "pr_description_contract": {
576
+ "schema_version": "issue_fix_pr_description_contract_v0",
577
+ "source_contract": "pr_review_five_block_template_v0",
578
+ "extension_contract": "issue_fix_reviewer_context_v0",
579
+ "builder_contract": {
580
+ "schema_version": "issue_fix_pr_description_build_v0",
581
+ "surface": "issue_fix.pr_description",
582
+ "default_enabled": False,
583
+ "explicit_dependency_injection": True,
584
+ "provider_call_budget": 1,
585
+ "fail_open_preserves_base_description": True,
586
+ "applied_preferences_require_compact_receipt": True,
587
+ },
588
+ "sections": [
589
+ {
590
+ "label": "动机",
591
+ "purpose": "Explain the reproduced user or maintainer problem and why the fix is necessary.",
592
+ },
593
+ {
594
+ "label": "改动思路",
595
+ "purpose": "Explain the chosen fix route and the main design tradeoff.",
596
+ },
597
+ {
598
+ "label": "关键代码或伪代码",
599
+ "purpose": (
600
+ "Show the smallest code or pseudocode slice that lets a "
601
+ "reviewer verify the behavioral change quickly."
602
+ ),
603
+ "applicability": "code_changes",
604
+ },
605
+ {
606
+ "label": "具体改动",
607
+ "purpose": "Name the reviewer-relevant modules, behavior, and focused regression coverage.",
608
+ },
609
+ {
610
+ "label": "修复后复现",
611
+ "purpose": (
612
+ "Provide a post-fix reproduction path using the repository "
613
+ "CLI or focused code/test surface."
614
+ ),
615
+ "applicability": "reproducible_changes",
616
+ "accepted_surfaces": [
617
+ "repository_cli",
618
+ "focused_code_or_test",
619
+ ],
620
+ },
621
+ {
622
+ "label": "验证",
623
+ "purpose": "List repository-native commands and honest pass, fail, or skipped results.",
624
+ },
625
+ {
626
+ "label": "对主干的风险与未覆盖",
627
+ "purpose": "State compatibility risk, residual gaps, and checks not run.",
628
+ },
629
+ {
630
+ "label": "关联 Issue",
631
+ "purpose": (
632
+ "Use a GitHub closing keyword for each fully resolved issue; "
633
+ "use a non-closing related reference for partial work."
634
+ ),
635
+ "applicability": "issue_backed_changes",
636
+ },
637
+ ],
638
+ "issue_reference_policy": {
639
+ "schema_version": "issue_fix_pr_issue_reference_policy_v0",
640
+ "default_closing_keyword": "Fixes",
641
+ "partial_fix_prefix": "Related to",
642
+ "closing_requires_default_branch": True,
643
+ "full_syntax_required_per_issue": True,
644
+ "applied_after_semantic_preferences": True,
645
+ "verification_surface": "closingIssuesReferences",
646
+ },
647
+ "infographic_policy": {
648
+ "required": False,
649
+ "allowed_when": "complex_change",
650
+ "must_not_replace_textual_evidence": True,
651
+ },
652
+ "review_only_section_excluded": "我的整体评价",
653
+ "requires_current_diff_evidence": True,
654
+ },
655
+ "external_issue_comment_performed": False,
656
+ "external_pr_created": False,
657
+ "merge_performed": False,
658
+ }
659
+ preflight_next_action = {
660
+ "reuse_existing_pr": (
661
+ "reuse or assess the matched implementation PR; keep the candidate out "
662
+ "of new patch planning and preserve the existing recall receipt"
663
+ ),
664
+ "comment_only": (
665
+ "preserve the existing route and produce only a compact disposition or "
666
+ "maintainer-comment plan"
667
+ ),
668
+ "skip": (
669
+ "record no-follow-up from prior terminal or triage evidence; do not "
670
+ "reopen patch planning"
671
+ ),
672
+ }.get(preflight_route)
673
+ if admission_state in {"evidence_required", "verification_required"}:
674
+ preflight_next_action = (
675
+ "complete the projected source-bound candidate successor, then rerun "
676
+ "candidate admission; do not enter feasibility or patch planning"
677
+ )
678
+ first_screen = {
679
+ "waiting_on": "agent",
680
+ "user_action_required": False,
681
+ "agent_can_continue": True,
682
+ "top_agent_todo": agent_todos[0],
683
+ "top_gate": user_gates[0] if user_gates else None,
684
+ "next_safe_action": preflight_next_action or (
685
+ (
686
+ "inspect current repository evidence for "
687
+ f"{', '.join(unresolved_context)}; ground what is available and "
688
+ "preserve the rest as unresolved in feasibility instead of guessing"
689
+ )
690
+ if unresolved_context
691
+ else (
692
+ "use the grounded repository context in the metadata classification "
693
+ "and feasibility checkpoint; then let feasibility project one "
694
+ "route-specific successor or no-follow-up"
695
+ )
696
+ ),
697
+ }
698
+ packet: dict[str, Any] = {
699
+ "ok": True,
700
+ "schema_version": ISSUE_FIX_WORKFLOW_PLAN_PACKET_SCHEMA_VERSION,
701
+ "mode": "issue-fix-workflow-plan",
702
+ "generated_at": generated_at,
703
+ "metadata_preview_schema_version": metadata_packet["schema_version"],
704
+ "issue_fix_intake_schema_version": intake.get("schema_version"),
705
+ "issue_signal": {
706
+ "repo": metadata["repo"],
707
+ "issue_ref": metadata["issue_ref"],
708
+ "kind": metadata["kind"],
709
+ "state": metadata["state"],
710
+ "labels": metadata["labels"],
711
+ "body_captured": False,
712
+ "comment_bodies_captured": False,
713
+ },
714
+ "repository_context_input_contract": repository_context_input_contract(),
715
+ "repository_context": repository_context,
716
+ "candidate_preflight": candidate_preflight,
717
+ "candidate_fix_workflow_allowed": preflight_decision.get(
718
+ "candidate_runnable"
719
+ )
720
+ is True,
721
+ "first_screen": first_screen,
722
+ "branch_plan": branch_plan,
723
+ "resolution_route_candidates": resolution_routes,
724
+ "feasibility_checkpoint_plan": feasibility_checkpoint,
725
+ "post_pr_lifecycle_monitor_plan": post_pr_monitor,
726
+ "ordered_loopx_todo_writeback_preview": ordered_previews,
727
+ "validation_plan": validation_plan,
728
+ "review_packet_preview": review_packet_preview,
729
+ "external_reads_performed": bool(
730
+ metadata_packet["external_reads_performed"]
731
+ or (
732
+ isinstance(candidate_source_receipt, Mapping)
733
+ and candidate_source_receipt.get("external_reads_performed") is True
734
+ )
735
+ ),
736
+ "external_writes_performed": False,
737
+ "issue_body_captured": False,
738
+ "comment_bodies_captured": False,
739
+ "response_payloads_captured": False,
740
+ "local_paths_captured": False,
741
+ "private_repo_state_read": False,
742
+ "todo_write_performed": False,
743
+ "destructive_git_used": False,
744
+ "autopublish_allowed": False,
745
+ "automerge_allowed": False,
746
+ "next_safe_action": first_screen["next_safe_action"],
747
+ }
748
+ validation = validate_issue_fix_workflow_plan_packet(packet)
749
+ packet["ok"] = bool(metadata_packet["ok"] and validation["ok"])
750
+ packet["validation"] = validation
751
+ return packet
752
+
753
+
754
+ def validate_issue_fix_workflow_plan_packet(
755
+ packet: Mapping[str, Any],
756
+ ) -> dict[str, Any]:
757
+ errors: list[str] = []
758
+ if packet.get("schema_version") != ISSUE_FIX_WORKFLOW_PLAN_PACKET_SCHEMA_VERSION:
759
+ errors.append("packet schema_version must be issue_fix_workflow_plan_packet_v0")
760
+ for key in (
761
+ "external_writes_performed",
762
+ "issue_body_captured",
763
+ "comment_bodies_captured",
764
+ "response_payloads_captured",
765
+ "local_paths_captured",
766
+ "private_repo_state_read",
767
+ "todo_write_performed",
768
+ "destructive_git_used",
769
+ "autopublish_allowed",
770
+ "automerge_allowed",
771
+ ):
772
+ if packet.get(key) is not False:
773
+ errors.append(f"packet {key} must be false")
774
+
775
+ issue_signal = packet.get("issue_signal")
776
+ if not isinstance(issue_signal, Mapping):
777
+ errors.append("issue_signal is required")
778
+ issue_signal = {}
779
+ for key in ("repo", "issue_ref", "kind", "state"):
780
+ if not issue_signal.get(key):
781
+ errors.append(f"issue_signal {key} is required")
782
+ if issue_signal.get("body_captured") is not False:
783
+ errors.append("issue_signal body_captured must be false")
784
+ if issue_signal.get("comment_bodies_captured") is not False:
785
+ errors.append("issue_signal comment_bodies_captured must be false")
786
+
787
+ branch_plan = packet.get("branch_plan")
788
+ if not isinstance(branch_plan, Mapping):
789
+ errors.append("branch_plan is required")
790
+ branch_plan = {}
791
+ if branch_plan.get("repo_path_captured") is not False:
792
+ errors.append("branch_plan repo_path_captured must be false")
793
+ if branch_plan.get("private_repo_state_read") is not False:
794
+ errors.append("branch_plan private_repo_state_read must be false")
795
+
796
+ repository_context = packet.get("repository_context")
797
+ if repository_context is not None:
798
+ if not isinstance(repository_context, Mapping):
799
+ errors.append("repository_context must be an object when present")
800
+ repository_context = {}
801
+ if repository_context.get("ok") is not True:
802
+ errors.append("repository_context must be valid")
803
+ if repository_context.get("external_writes_performed") is not False:
804
+ errors.append("repository_context must not perform external writes")
805
+ truth_contract = repository_context.get("truth_contract")
806
+ if (
807
+ not isinstance(truth_contract, Mapping)
808
+ or truth_contract.get("context_cannot_authorize_external_writes")
809
+ is not True
810
+ ):
811
+ errors.append("repository_context must deny external-write authority")
812
+
813
+ repository_context_contract = packet.get("repository_context_input_contract")
814
+ if not isinstance(repository_context_contract, Mapping):
815
+ errors.append("repository_context_input_contract is required")
816
+ elif (
817
+ repository_context_contract.get("schema_version")
818
+ != ISSUE_FIX_REPOSITORY_CONTEXT_INPUT_SCHEMA_VERSION
819
+ ):
820
+ errors.append("repository_context_input_contract has wrong schema")
821
+
822
+ candidate_preflight = packet.get("candidate_preflight")
823
+ if not isinstance(candidate_preflight, Mapping):
824
+ errors.append("candidate_preflight is required")
825
+ candidate_preflight = {}
826
+ if candidate_preflight.get("schema_version") != "issue_fix_candidate_preflight_v0":
827
+ errors.append("candidate_preflight has wrong schema")
828
+ if candidate_preflight.get("external_reads_performed") is not False:
829
+ errors.append("candidate_preflight must not perform external reads")
830
+ if candidate_preflight.get("external_writes_performed") is not False:
831
+ errors.append("candidate_preflight must not perform external writes")
832
+ preflight_projection = candidate_preflight.get("domain_state_projection")
833
+ if not isinstance(preflight_projection, Mapping):
834
+ errors.append("candidate_preflight domain_state_projection is required")
835
+ else:
836
+ if (
837
+ preflight_projection.get("schema_version")
838
+ != "issue_fix_candidate_preflight_domain_state_projection_v0"
839
+ ):
840
+ errors.append("candidate_preflight domain_state_projection has wrong schema")
841
+ if preflight_projection.get("stream") != "candidate-preflight":
842
+ errors.append("candidate_preflight domain_state_projection has wrong stream")
843
+ if preflight_projection.get("write_performed") is not False:
844
+ errors.append(
845
+ "workflow-plan builder must leave candidate preflight write pending"
846
+ )
847
+ preflight_decision = candidate_preflight.get("decision")
848
+ preflight_decision = (
849
+ preflight_decision if isinstance(preflight_decision, Mapping) else {}
850
+ )
851
+ preflight_admission = candidate_preflight.get("admission")
852
+ if not isinstance(preflight_admission, Mapping):
853
+ errors.append("candidate_preflight admission is required")
854
+ preflight_admission = {}
855
+ admission_state = preflight_admission.get("state")
856
+ if admission_state not in {
857
+ "evidence_required",
858
+ "verification_required",
859
+ "admitted",
860
+ "terminal",
861
+ }:
862
+ errors.append("candidate_preflight admission state is invalid")
863
+ admission_successors = preflight_admission.get("successors")
864
+ if not isinstance(admission_successors, Sequence) or isinstance(
865
+ admission_successors, (str, bytes)
866
+ ):
867
+ errors.append("candidate_preflight admission successors must be a list")
868
+ admission_successors = []
869
+ if admission_state in {"evidence_required", "verification_required"}:
870
+ if preflight_decision.get("route") is not None:
871
+ errors.append("pending candidate admission must not expose a final route")
872
+ if not admission_successors:
873
+ errors.append("pending candidate admission requires a successor")
874
+ elif admission_successors:
875
+ errors.append("final candidate admission must not retain successors")
876
+ candidate_runnable = preflight_decision.get("candidate_runnable") is True
877
+ if candidate_runnable and (
878
+ admission_state != "admitted" or preflight_decision.get("route") != "proceed"
879
+ ):
880
+ errors.append("candidate runnable requires admitted proceed")
881
+ if packet.get("candidate_fix_workflow_allowed") is not candidate_runnable:
882
+ errors.append("candidate workflow permission must match preflight decision")
883
+
884
+ routes = packet.get("resolution_route_candidates")
885
+ if not isinstance(routes, Sequence) or isinstance(routes, (str, bytes)):
886
+ errors.append("resolution_route_candidates must be a list")
887
+ routes = []
888
+ route_names = {route.get("route") for route in routes if isinstance(route, Mapping)}
889
+ for route_name in ("fix_pr", "comment_only", "triage_only"):
890
+ if route_name not in route_names:
891
+ errors.append(f"resolution route {route_name} is required")
892
+ for route in routes:
893
+ if not isinstance(route, Mapping):
894
+ errors.append("resolution route entries must be objects")
895
+ continue
896
+ if route.get("external_issue_comment_performed") is not False:
897
+ errors.append("resolution routes must not perform external comments")
898
+ if route.get("external_pr_created") is not False:
899
+ errors.append("resolution routes must not create PRs")
900
+ if route.get("requires_user_gate_before_external_write") is not True:
901
+ errors.append("resolution routes must gate external writes")
902
+
903
+ feasibility = packet.get("feasibility_checkpoint_plan")
904
+ if not isinstance(feasibility, Mapping):
905
+ errors.append("feasibility_checkpoint_plan is required")
906
+ feasibility = {}
907
+ if feasibility.get("selects_exactly_one_route") is not True:
908
+ errors.append("feasibility checkpoint must select exactly one route")
909
+ if feasibility.get("required_when_candidate_preflight_route") != "proceed":
910
+ errors.append("feasibility checkpoint must only follow a proceed preflight")
911
+ if feasibility.get("non_proceed_receipt_stream") != "candidate-preflight":
912
+ errors.append("non-proceed candidates must use candidate-preflight receipts")
913
+ if feasibility.get("writes_domain_state_by_default_with_goal_id") is not True:
914
+ errors.append("feasibility checkpoint must default-write domain state")
915
+ if (
916
+ packet.get("repository_context") is not None
917
+ and feasibility.get("persists_repository_context_with_feasibility") is not True
918
+ ):
919
+ errors.append("feasibility checkpoint must persist repository context")
920
+ if feasibility.get("writes_loopx_todo") is not False:
921
+ errors.append("feasibility checkpoint must not directly write LoopX todos")
922
+ if feasibility.get("raw_issue_or_log_material_captured") is not False:
923
+ errors.append("feasibility checkpoint must not capture raw material")
924
+
925
+ post_pr = packet.get("post_pr_lifecycle_monitor_plan")
926
+ if not isinstance(post_pr, Mapping):
927
+ errors.append("post_pr_lifecycle_monitor_plan is required")
928
+ post_pr = {}
929
+ if post_pr.get("schema_version") != "issue_fix_post_pr_lifecycle_monitor_plan_v1":
930
+ errors.append("post PR lifecycle plan must use grouped monitor plan v1")
931
+ if post_pr.get("creates_per_pr_continuous_monitor_todo") is not False:
932
+ errors.append("post PR lifecycle plan must not create per-PR monitor todos")
933
+ if post_pr.get("monitor_scope") != "lifecycle_state_bucket":
934
+ errors.append("post PR lifecycle plan must group by lifecycle state")
935
+ if post_pr.get("materializes_nonempty_buckets_only") is not True:
936
+ errors.append("post PR lifecycle plan must materialize only nonempty buckets")
937
+ if post_pr.get("terminal_members_removed") is not True:
938
+ errors.append("post PR lifecycle plan must remove terminal members")
939
+ if post_pr.get("per_pr_material_actions_are_one_shot") is not True:
940
+ errors.append("post PR lifecycle plan must use one-shot per-PR actions")
941
+ if post_pr.get("external_notification_granularity") != "one_pr_per_message":
942
+ errors.append("post PR lifecycle plan must preserve one-PR messages")
943
+ if post_pr.get("external_writes_performed") is not False:
944
+ errors.append("post PR lifecycle plan must not perform external writes")
945
+ if post_pr.get("raw_check_logs_captured") is not False:
946
+ errors.append("post PR lifecycle plan must not capture raw check logs")
947
+
948
+ previews = packet.get("ordered_loopx_todo_writeback_preview")
949
+ if not isinstance(previews, Sequence) or isinstance(previews, (str, bytes)):
950
+ errors.append("ordered_loopx_todo_writeback_preview must be a list")
951
+ previews = []
952
+ orders: list[int] = []
953
+ roles = set()
954
+ priorities = set()
955
+ for preview in previews:
956
+ if not isinstance(preview, Mapping):
957
+ errors.append("todo preview entries must be objects")
958
+ continue
959
+ if preview.get("schema_version") != "loopx_todo_writeback_preview_v0":
960
+ errors.append("todo preview has wrong schema")
961
+ if preview.get("would_write") is not False:
962
+ errors.append("todo preview would_write must be false")
963
+ if preview.get("requires_execute_flag") is not True:
964
+ errors.append("todo preview must require execute flag")
965
+ order = preview.get("planner_order")
966
+ if isinstance(order, int):
967
+ orders.append(order)
968
+ else:
969
+ errors.append("todo preview planner_order must be an integer")
970
+ roles.add(preview.get("role"))
971
+ priorities.add(preview.get("priority"))
972
+ if not candidate_runnable:
973
+ forbidden = {
974
+ "issue_fix_public_metadata_classification",
975
+ "issue_fix_feasibility_decision",
976
+ "issue_fix_branch_validation",
977
+ }
978
+ if any(
979
+ isinstance(preview, Mapping)
980
+ and preview.get("action_kind") in forbidden
981
+ for preview in previews
982
+ ):
983
+ errors.append("deduped candidate must not project new patch-planning todos")
984
+ if orders != sorted(orders):
985
+ errors.append("todo previews must be ordered by planner_order")
986
+ if "agent" not in roles:
987
+ errors.append("at least one agent todo preview is required")
988
+ if "P0" not in priorities:
989
+ errors.append("at least one P0 todo preview is required")
990
+
991
+ review = packet.get("review_packet_preview")
992
+ if not isinstance(review, Mapping):
993
+ errors.append("review_packet_preview is required")
994
+ review = {}
995
+ if review.get("schema_version") != "issue_fix_pr_review_packet_v0":
996
+ errors.append("review packet preview has wrong schema")
997
+ if review.get("ready") is not False:
998
+ errors.append("workflow plan preview must not mark PR review ready")
999
+ description = review.get("pr_description_contract")
1000
+ if not isinstance(description, Mapping):
1001
+ errors.append("review preview must include PR description contract")
1002
+ else:
1003
+ if description.get("schema_version") != (
1004
+ "issue_fix_pr_description_contract_v0"
1005
+ ):
1006
+ errors.append("PR description contract has wrong schema")
1007
+ if description.get("builder_contract") != {
1008
+ "schema_version": "issue_fix_pr_description_build_v0",
1009
+ "surface": "issue_fix.pr_description",
1010
+ "default_enabled": False,
1011
+ "explicit_dependency_injection": True,
1012
+ "provider_call_budget": 1,
1013
+ "fail_open_preserves_base_description": True,
1014
+ "applied_preferences_require_compact_receipt": True,
1015
+ }:
1016
+ errors.append("PR description builder contract is incomplete")
1017
+ sections = description.get("sections")
1018
+ labels = (
1019
+ [
1020
+ section.get("label")
1021
+ for section in sections
1022
+ if isinstance(section, Mapping)
1023
+ ]
1024
+ if isinstance(sections, list)
1025
+ else []
1026
+ )
1027
+ if labels != [
1028
+ "动机",
1029
+ "改动思路",
1030
+ "关键代码或伪代码",
1031
+ "具体改动",
1032
+ "修复后复现",
1033
+ "验证",
1034
+ "对主干的风险与未覆盖",
1035
+ "关联 Issue",
1036
+ ]:
1037
+ errors.append("PR description contract sections are incomplete")
1038
+ section_by_label = {
1039
+ str(section.get("label") or ""): section
1040
+ for section in sections or []
1041
+ if isinstance(section, Mapping)
1042
+ }
1043
+ if section_by_label.get("关键代码或伪代码", {}).get("applicability") != (
1044
+ "code_changes"
1045
+ ):
1046
+ errors.append("key code section must apply to code changes")
1047
+ if section_by_label.get("修复后复现", {}).get("accepted_surfaces") != [
1048
+ "repository_cli",
1049
+ "focused_code_or_test",
1050
+ ]:
1051
+ errors.append("post-fix reproduction surfaces are incomplete")
1052
+ if section_by_label.get("关联 Issue", {}).get("applicability") != (
1053
+ "issue_backed_changes"
1054
+ ):
1055
+ errors.append("issue reference section applicability is incomplete")
1056
+ if description.get("issue_reference_policy") != {
1057
+ "schema_version": "issue_fix_pr_issue_reference_policy_v0",
1058
+ "default_closing_keyword": "Fixes",
1059
+ "partial_fix_prefix": "Related to",
1060
+ "closing_requires_default_branch": True,
1061
+ "full_syntax_required_per_issue": True,
1062
+ "applied_after_semantic_preferences": True,
1063
+ "verification_surface": "closingIssuesReferences",
1064
+ }:
1065
+ errors.append("PR description issue reference policy is incomplete")
1066
+ if description.get("infographic_policy") != {
1067
+ "required": False,
1068
+ "allowed_when": "complex_change",
1069
+ "must_not_replace_textual_evidence": True,
1070
+ }:
1071
+ errors.append("PR description infographic policy is incomplete")
1072
+ if description.get("review_only_section_excluded") != "我的整体评价":
1073
+ errors.append("PR description contract must exclude reviewer verdict")
1074
+ if review.get("external_issue_comment_performed") is not False:
1075
+ errors.append("review preview must not perform external issue comments")
1076
+ if review.get("external_pr_created") is not False:
1077
+ errors.append("review preview must not create PRs")
1078
+ if review.get("merge_performed") is not False:
1079
+ errors.append("review preview must not merge")
1080
+
1081
+ return {
1082
+ "ok": not errors,
1083
+ "schema_version": "issue_fix_workflow_plan_validation_v0",
1084
+ "errors": errors,
1085
+ "todo_preview_count": len(previews),
1086
+ "user_gate_preview_count": sum(
1087
+ 1
1088
+ for preview in previews
1089
+ if isinstance(preview, Mapping) and preview.get("role") == "user"
1090
+ ),
1091
+ "readiness_blocker_count": len(review.get("readiness_blockers") or []),
1092
+ }
1093
+
1094
+
1095
+ def render_issue_fix_workflow_plan_markdown(payload: dict[str, Any]) -> str:
1096
+ lines = [
1097
+ "# LoopX Issue Fix Workflow Plan",
1098
+ "",
1099
+ f"- ok: `{payload.get('ok')}`",
1100
+ f"- schema_version: `{payload.get('schema_version')}`",
1101
+ f"- external_reads_performed: `{payload.get('external_reads_performed')}`",
1102
+ f"- external_writes_performed: `{payload.get('external_writes_performed')}`",
1103
+ f"- todo_write_performed: `{payload.get('todo_write_performed')}`",
1104
+ f"- local_paths_captured: `{payload.get('local_paths_captured')}`",
1105
+ f"- private_repo_state_read: `{payload.get('private_repo_state_read')}`",
1106
+ ]
1107
+ first_screen = payload.get("first_screen")
1108
+ if isinstance(first_screen, Mapping):
1109
+ lines.extend(
1110
+ [
1111
+ "",
1112
+ "## First Screen",
1113
+ "",
1114
+ f"- waiting_on: `{first_screen.get('waiting_on')}`",
1115
+ f"- user_action_required: `{first_screen.get('user_action_required')}`",
1116
+ f"- agent_can_continue: `{first_screen.get('agent_can_continue')}`",
1117
+ f"- next_safe_action: {first_screen.get('next_safe_action')}",
1118
+ ]
1119
+ )
1120
+ issue_signal = payload.get("issue_signal")
1121
+ if isinstance(issue_signal, Mapping):
1122
+ lines.extend(
1123
+ [
1124
+ "",
1125
+ "## Issue Signal",
1126
+ "",
1127
+ f"- repo: `{issue_signal.get('repo')}`",
1128
+ f"- issue_ref: `{issue_signal.get('issue_ref')}`",
1129
+ f"- kind: `{issue_signal.get('kind')}`",
1130
+ f"- state: `{issue_signal.get('state')}`",
1131
+ f"- labels: `{issue_signal.get('labels')}`",
1132
+ ]
1133
+ )
1134
+ repository_context = payload.get("repository_context")
1135
+ if isinstance(repository_context, Mapping):
1136
+ lines.extend(
1137
+ [
1138
+ "",
1139
+ "## Repository Context",
1140
+ "",
1141
+ f"- status: `{repository_context.get('context_status')}`",
1142
+ f"- repository_revision: `{repository_context.get('repository_revision')}`",
1143
+ f"- context_fingerprint: `{repository_context.get('context_fingerprint')}`",
1144
+ f"- unresolved_required_aspects: "
1145
+ f"`{repository_context.get('unresolved_required_aspects')}`",
1146
+ f"- expert_next_action: "
1147
+ f"`{(repository_context.get('expert_consultation') or {}).get('next_action')}`",
1148
+ ]
1149
+ )
1150
+ candidate_preflight = payload.get("candidate_preflight")
1151
+ if isinstance(candidate_preflight, Mapping):
1152
+ decision = candidate_preflight.get("decision") or {}
1153
+ admission = candidate_preflight.get("admission") or {}
1154
+ evidence = candidate_preflight.get("evidence") or {}
1155
+ recall = candidate_preflight.get("agentic_recall") or {}
1156
+ lines.extend(
1157
+ [
1158
+ "",
1159
+ "## Candidate Preflight",
1160
+ "",
1161
+ f"- configured: `{candidate_preflight.get('configured')}`",
1162
+ f"- admission: `{admission.get('state')}`",
1163
+ f"- route: `{decision.get('route')}`",
1164
+ f"- candidate_runnable: `{decision.get('candidate_runnable')}`",
1165
+ f"- existing_pr_refs: `{decision.get('existing_pr_refs')}`",
1166
+ f"- successor_action_kinds: "
1167
+ f"`{[row.get('action_kind') for row in admission.get('successors', []) if isinstance(row, Mapping)]}`",
1168
+ f"- domain_state_matched: `{evidence.get('domain_state_matched')}`",
1169
+ f"- agentic_recall_action: `{recall.get('action')}`",
1170
+ f"- provider_calls_performed: `{recall.get('provider_calls_performed')}`",
1171
+ ]
1172
+ )
1173
+ branch = payload.get("branch_plan")
1174
+ if isinstance(branch, Mapping):
1175
+ lines.extend(
1176
+ [
1177
+ "",
1178
+ "## Branch Plan",
1179
+ "",
1180
+ f"- status: `{branch.get('status')}`",
1181
+ f"- base_branch: `{branch.get('base_branch')}`",
1182
+ f"- issue_branch: `{branch.get('issue_branch')}`",
1183
+ f"- repo_path_captured: `{branch.get('repo_path_captured')}`",
1184
+ f"- execute_required_for_branch_claim: "
1185
+ f"`{branch.get('execute_required_for_branch_claim')}`",
1186
+ ]
1187
+ )
1188
+ todos = payload.get("ordered_loopx_todo_writeback_preview")
1189
+ if isinstance(todos, Sequence) and not isinstance(todos, (str, bytes)):
1190
+ lines.extend(["", "## Ordered Todo Writeback Preview", ""])
1191
+ for todo in todos:
1192
+ if isinstance(todo, Mapping):
1193
+ lines.append(
1194
+ f"- `{todo.get('planner_order')}` `{todo.get('role')}` "
1195
+ f"`{todo.get('priority')}` `{todo.get('action_kind')}`: "
1196
+ f"would_write=`{todo.get('would_write')}`"
1197
+ )
1198
+ feasibility = payload.get("feasibility_checkpoint_plan")
1199
+ if isinstance(feasibility, Mapping):
1200
+ lines.extend(
1201
+ [
1202
+ "",
1203
+ "## Feasibility Checkpoint",
1204
+ "",
1205
+ f"- selects_exactly_one_route: "
1206
+ f"`{feasibility.get('selects_exactly_one_route')}`",
1207
+ f"- routes: `{feasibility.get('routes')}`",
1208
+ f"- writes_domain_state_by_default_with_goal_id: "
1209
+ f"`{feasibility.get('writes_domain_state_by_default_with_goal_id')}`",
1210
+ f"- command_preview: `{feasibility.get('command_preview')}`",
1211
+ ]
1212
+ )
1213
+ routes = payload.get("resolution_route_candidates")
1214
+ if isinstance(routes, Sequence) and not isinstance(routes, (str, bytes)):
1215
+ lines.extend(["", "## Resolution Routes", ""])
1216
+ for route in routes:
1217
+ if isinstance(route, Mapping):
1218
+ lines.append(
1219
+ f"- `{route.get('route')}` `{route.get('priority')}`: "
1220
+ f"{route.get('summary')}"
1221
+ )
1222
+ post_pr = payload.get("post_pr_lifecycle_monitor_plan")
1223
+ if isinstance(post_pr, Mapping):
1224
+ lines.extend(
1225
+ [
1226
+ "",
1227
+ "## Post-PR Lifecycle Monitor",
1228
+ "",
1229
+ f"- creates_per_pr_continuous_monitor_todo: "
1230
+ f"`{post_pr.get('creates_per_pr_continuous_monitor_todo')}`",
1231
+ f"- monitor_scope: `{post_pr.get('monitor_scope')}`",
1232
+ f"- monitor_action_kind_template: "
1233
+ f"`{post_pr.get('monitor_action_kind_template')}`",
1234
+ f"- external_notification_granularity: "
1235
+ f"`{post_pr.get('external_notification_granularity')}`",
1236
+ f"- decisions: `{post_pr.get('decisions')}`",
1237
+ ]
1238
+ )
1239
+ review = payload.get("review_packet_preview")
1240
+ if isinstance(review, Mapping):
1241
+ lines.extend(
1242
+ [
1243
+ "",
1244
+ "## PR Review Packet Preview",
1245
+ "",
1246
+ f"- ready: `{review.get('ready')}`",
1247
+ f"- readiness_blockers: `{review.get('readiness_blockers')}`",
1248
+ f"- external_pr_created: `{review.get('external_pr_created')}`",
1249
+ f"- merge_performed: `{review.get('merge_performed')}`",
1250
+ ]
1251
+ )
1252
+ description = review.get("pr_description_contract")
1253
+ if isinstance(description, Mapping):
1254
+ lines.extend(["", "### PR Description Contract", ""])
1255
+ for section in description.get("sections") or []:
1256
+ if isinstance(section, Mapping):
1257
+ lines.append(
1258
+ f"- **{section.get('label')}**: {section.get('purpose')}"
1259
+ )
1260
+ infographic = description.get("infographic_policy")
1261
+ if isinstance(infographic, Mapping):
1262
+ lines.append(
1263
+ "- infographic: optional for complex changes; textual evidence remains required"
1264
+ )
1265
+ validation = payload.get("validation")
1266
+ if isinstance(validation, Mapping):
1267
+ errors = (
1268
+ validation.get("errors")
1269
+ if isinstance(validation.get("errors"), list)
1270
+ else []
1271
+ )
1272
+ lines.extend(
1273
+ [
1274
+ "",
1275
+ "## Validation",
1276
+ "",
1277
+ f"- validation_ok: `{validation.get('ok')}`",
1278
+ f"- todo_preview_count: `{validation.get('todo_preview_count')}`",
1279
+ f"- user_gate_preview_count: `{validation.get('user_gate_preview_count')}`",
1280
+ f"- readiness_blocker_count: `{validation.get('readiness_blocker_count')}`",
1281
+ f"- error_count: `{len(errors)}`",
1282
+ ]
1283
+ )
1284
+ if payload.get("error"):
1285
+ lines.extend(["", "## Error", "", str(payload.get("error"))])
1286
+ return "\n".join(lines) + "\n"