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,1822 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from collections.abc import Callable
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from ...agent_registry import load_goal_from_registry
9
+ from ...boundary_authority import checkpointed_boundary_authority_summary
10
+ from ...control_plane.runtime.time import now_utc_iso
11
+ from ...domain_packs.issue_fix import (
12
+ default_issue_fix_candidate_preflight_ledger_path,
13
+ default_issue_fix_domain_state_ledger_path,
14
+ default_issue_fix_feasibility_ledger_path,
15
+ default_issue_fix_repository_snapshot_ledger_path,
16
+ retain_issue_fix_repository_snapshot_jsonl,
17
+ upsert_issue_fix_candidate_preflight_ledger_jsonl,
18
+ upsert_issue_fix_feasibility_ledger_jsonl,
19
+ upsert_issue_fix_pr_lifecycle_ledger_jsonl,
20
+ )
21
+ from ...todos import add_goal_todo
22
+ from .acceptance_loop import (
23
+ build_issue_fix_acceptance_fixture_packet,
24
+ build_issue_fix_caller_repo_branch_packet,
25
+ build_issue_fix_repo_branch_fixture_packet,
26
+ render_issue_fix_acceptance_loop_markdown,
27
+ )
28
+ from .candidate_evidence import collect_public_github_candidate_preflight_input
29
+ from .feasibility import (
30
+ build_issue_fix_feasibility_packet,
31
+ render_issue_fix_feasibility_markdown,
32
+ )
33
+ from .discovered_issue_promotion import (
34
+ build_discovered_issue_promotion_from_cli_args,
35
+ register_discovered_issue_promotion_command,
36
+ render_issue_fix_discovered_issue_promotion_markdown,
37
+ )
38
+ from .cli_input import (
39
+ _MAX_INLINE_JSON_CHARS as _MAX_INLINE_JSON_CHARS,
40
+ load_json_object as _load_json_object,
41
+ load_jsonl_row as _load_jsonl_row,
42
+ load_jsonl_rows as _load_jsonl_rows,
43
+ )
44
+ from .outcome_projection import (
45
+ build_issue_fix_outcome_projection,
46
+ compact_issue_fix_delivery_evidence,
47
+ render_issue_fix_outcome_projection_markdown,
48
+ )
49
+ from .metrics_projection import (
50
+ build_issue_fix_metrics_projection,
51
+ render_issue_fix_metrics_projection_markdown,
52
+ )
53
+ from .metrics_supplement import (
54
+ render_issue_fix_metrics_supplement_markdown,
55
+ )
56
+ from .metrics_supplement_cli import (
57
+ build_issue_fix_metrics_supplement_from_args,
58
+ register_issue_fix_metrics_supplement_command,
59
+ )
60
+ from .metadata_preview import normalise_github_issue_reference
61
+ from .pr_lifecycle import (
62
+ build_issue_fix_pr_lifecycle_monitor_packet,
63
+ render_issue_fix_pr_lifecycle_monitor_markdown,
64
+ validate_issue_fix_pr_lifecycle_monitor_packet,
65
+ )
66
+ from .pr_lifecycle_rollout import append_pr_merge_rollout_event
67
+ from .pr_monitor_materialization import (
68
+ DEFAULT_ISSUE_FIX_MONITOR_CADENCE,
69
+ materialize_issue_fix_grouped_monitors,
70
+ )
71
+ from .provider_hooks import IssueFixReviewerProviderHooksFactory
72
+ from . import pr_gate_reconcile_cli
73
+ from .reviewer_cli import (
74
+ REVIEWER_COMMANDS,
75
+ _materialize_goal_reviewer_notification_lifecycle as _materialize_goal_reviewer_notification_lifecycle,
76
+ handle_issue_fix_reviewer_command,
77
+ register_issue_fix_reviewer_commands,
78
+ reviewer_renderer,
79
+ )
80
+ from .repository_memory import SUPPORT_ASPECTS
81
+ from .repository_memory_provider import (
82
+ default_repository_memory_provider_config_path,
83
+ render_issue_fix_repository_memory_sync_markdown,
84
+ retrieve_issue_fix_repository_memory,
85
+ sync_issue_fix_repository_memory,
86
+ write_issue_fix_validated_outcome_memory,
87
+ )
88
+ from .repository_commit_evidence import verify_issue_fix_repository_commit_evidence
89
+ from .repository_snapshot import (
90
+ collect_public_github_repository_snapshot,
91
+ render_repository_snapshot_markdown,
92
+ repository_snapshot_record,
93
+ )
94
+ from .workflow_plan import (
95
+ build_issue_fix_workflow_plan_packet,
96
+ render_issue_fix_workflow_plan_markdown,
97
+ )
98
+
99
+
100
+ PrintPayload = Callable[
101
+ [dict[str, object], str, Callable[[dict[str, object]], str]],
102
+ None,
103
+ ]
104
+ FormatSelector = Callable[..., str]
105
+ AddFormat = Callable[[argparse.ArgumentParser], None]
106
+
107
+
108
+ def _comparable_delivery_evidence(
109
+ value: dict[str, Any] | None,
110
+ ) -> dict[str, Any] | None:
111
+ if value is None:
112
+ return None
113
+ comparable = {key: item for key, item in value.items() if key != "recorded_at"}
114
+ repository_evidence = comparable.get("repository_commit_evidence")
115
+ if isinstance(repository_evidence, dict):
116
+ comparable["repository_commit_evidence"] = {
117
+ key: item
118
+ for key, item in repository_evidence.items()
119
+ if key != "verified_at"
120
+ }
121
+ return comparable
122
+
123
+
124
+ def _configured_repository_memory_input(
125
+ *,
126
+ provider_path: str | None,
127
+ raw_memory_path: str | None,
128
+ repo_path: str | None,
129
+ repository_context_input: dict[str, Any] | None,
130
+ repo: str,
131
+ issue_ref: str,
132
+ query: str | None,
133
+ supports: list[str],
134
+ validation_label: str | None,
135
+ observed_at: str,
136
+ ) -> dict[str, Any] | None:
137
+ if raw_memory_path and provider_path:
138
+ raise ValueError(
139
+ "--repository-memory-json cannot be combined with a configured provider"
140
+ )
141
+ if raw_memory_path:
142
+ return _load_json_object(raw_memory_path)
143
+ if not provider_path:
144
+ return None
145
+ if not repo_path or not repository_context_input:
146
+ return None
147
+ revision = str(repository_context_input.get("repository_revision") or "").strip()
148
+ if not revision:
149
+ return None
150
+ retrieval_query = query or " ".join(
151
+ value
152
+ for value in (
153
+ repo,
154
+ issue_ref,
155
+ validation_label or "repository architecture reproduction validation",
156
+ )
157
+ if value
158
+ )
159
+ query_summary = (
160
+ query
161
+ or f"Public repository context for {repo} {issue_ref} before patch planning."
162
+ )
163
+ result = retrieve_issue_fix_repository_memory(
164
+ config=_load_json_object(provider_path),
165
+ repo_path=repo_path,
166
+ repository_revision=revision,
167
+ query=retrieval_query,
168
+ query_summary=query_summary,
169
+ supports=(
170
+ supports or ["architecture", "change_scope", "reproduction", "validation"]
171
+ ),
172
+ observed_at=observed_at,
173
+ )
174
+ return result["memory_input"]
175
+
176
+
177
+ def _add_repository_memory_provider_args(parser: argparse.ArgumentParser) -> None:
178
+ parser.add_argument(
179
+ "--repository-memory-provider-json",
180
+ default=None,
181
+ help=(
182
+ "Optional local-private issue_fix_repository_memory_provider_config_v0. "
183
+ "Defaults to LOOPX_ISSUE_FIX_REPOSITORY_MEMORY_PROVIDER_CONFIG. "
184
+ "The path, provider command, credentials, and raw payloads are never kept."
185
+ ),
186
+ )
187
+ parser.add_argument(
188
+ "--repository-memory-query",
189
+ default=None,
190
+ help=(
191
+ "Optional compact public query for configured provider search/read. "
192
+ "A bounded issue/ref/validation query is derived when omitted."
193
+ ),
194
+ )
195
+ parser.add_argument(
196
+ "--repository-memory-support",
197
+ action="append",
198
+ default=[],
199
+ choices=sorted(SUPPORT_ASPECTS),
200
+ help="Repository aspect supported by retrieved context. Repeat as needed.",
201
+ )
202
+
203
+
204
+ def _add_generated_at_arg(
205
+ parser: argparse.ArgumentParser,
206
+ *,
207
+ artifact: str,
208
+ ) -> None:
209
+ parser.add_argument(
210
+ "--generated-at",
211
+ default=None,
212
+ help=(
213
+ f"Public-safe generated_at timestamp for {artifact}; "
214
+ "defaults to current UTC invocation time."
215
+ ),
216
+ )
217
+
218
+
219
+ def _goal_boundary_authority_projection(
220
+ *,
221
+ registry_path: Path | None,
222
+ goal_id: str | None,
223
+ ) -> tuple[list[str], bool]:
224
+ if registry_path is None or not goal_id:
225
+ return [], False
226
+ goal = load_goal_from_registry(registry_path, goal_id)
227
+ if not isinstance(goal, dict):
228
+ return [], False
229
+ coordination = (
230
+ goal.get("coordination") if isinstance(goal.get("coordination"), dict) else {}
231
+ )
232
+ summary = checkpointed_boundary_authority_summary(coordination)
233
+ scopes = (
234
+ list(summary.get("active_write_scope") or [])
235
+ if isinstance(summary, dict)
236
+ else []
237
+ )
238
+ return [str(scope) for scope in scopes], True
239
+
240
+
241
+ def register_issue_fix_commands(
242
+ subparsers: argparse._SubParsersAction,
243
+ add_subcommand_format: AddFormat,
244
+ ) -> None:
245
+ issue_fix_parser = subparsers.add_parser(
246
+ "issue-fix",
247
+ help="Run public-safe issue fix acceptance loops.",
248
+ )
249
+ issue_fix_sub = issue_fix_parser.add_subparsers(
250
+ dest="issue_fix_command",
251
+ required=True,
252
+ )
253
+ memory_sync_parser = issue_fix_sub.add_parser(
254
+ "repository-memory-sync",
255
+ help=(
256
+ "Plan or explicitly execute a bounded public resource sync through "
257
+ "the reusable context-provider module."
258
+ ),
259
+ )
260
+ add_subcommand_format(memory_sync_parser)
261
+ memory_sync_parser.add_argument("--repo-path", required=True)
262
+ memory_sync_parser.add_argument("--repository-context-json", required=True)
263
+ memory_sync_parser.add_argument(
264
+ "--repository-memory-provider-json",
265
+ default=None,
266
+ help=(
267
+ "Local-private provider config; defaults to "
268
+ "LOOPX_ISSUE_FIX_REPOSITORY_MEMORY_PROVIDER_CONFIG."
269
+ ),
270
+ )
271
+ memory_sync_parser.add_argument(
272
+ "--resource-reference",
273
+ action="append",
274
+ default=[],
275
+ required=True,
276
+ help="Repo-relative public file to index. Repeat up to the bounded cap.",
277
+ )
278
+ memory_sync_parser.add_argument(
279
+ "--execute",
280
+ action="store_true",
281
+ help="Perform the provider resource write. Without this flag, return a plan.",
282
+ )
283
+ _add_generated_at_arg(memory_sync_parser, artifact="the resource sync")
284
+ register_discovered_issue_promotion_command(
285
+ issue_fix_sub,
286
+ add_subcommand_format=add_subcommand_format,
287
+ add_generated_at_arg=_add_generated_at_arg,
288
+ )
289
+ workflow_parser = issue_fix_sub.add_parser(
290
+ "workflow-plan",
291
+ help=(
292
+ "Plan the full issue-fix workflow from public metadata to ordered "
293
+ "LoopX todos, validation, and PR review packet readiness without writes."
294
+ ),
295
+ )
296
+ add_subcommand_format(workflow_parser)
297
+ workflow_parser.add_argument(
298
+ "--repo",
299
+ default="public_repo_fixture",
300
+ help="Public-safe repository label for the issue metadata.",
301
+ )
302
+ workflow_parser.add_argument(
303
+ "--issue-ref",
304
+ default="issue_123_public_metadata_fixture",
305
+ help="Public-safe issue or PR reference label.",
306
+ )
307
+ workflow_parser.add_argument(
308
+ "--url",
309
+ default=None,
310
+ help="Optional https://github.com/owner/repo/issues/123 or /pull/123 URL.",
311
+ )
312
+ workflow_parser.add_argument(
313
+ "--metadata-json",
314
+ default=None,
315
+ help=(
316
+ "Path to mocked provider JSON metadata, or '-' for stdin. "
317
+ "Body/comment fields stay gated and are not copied."
318
+ ),
319
+ )
320
+ workflow_parser.add_argument(
321
+ "--fetch-metadata",
322
+ action="store_true",
323
+ help=(
324
+ "Explicitly fetch public GitHub issue/PR metadata with gh api --jq. "
325
+ "Only body-free metadata fields are captured."
326
+ ),
327
+ )
328
+ workflow_parser.add_argument(
329
+ "--fetch-timeout-seconds",
330
+ type=int,
331
+ default=10,
332
+ help="Timeout for --fetch-metadata.",
333
+ )
334
+ workflow_parser.add_argument(
335
+ "--repo-path",
336
+ default=None,
337
+ help=(
338
+ "Optional caller-approved local git repository path. Planning keeps "
339
+ "this as a dry-run and never records the path."
340
+ ),
341
+ )
342
+ workflow_parser.add_argument(
343
+ "--base-branch",
344
+ default="main",
345
+ help="Approved local base branch for the eventual issue branch.",
346
+ )
347
+ workflow_parser.add_argument(
348
+ "--issue-branch",
349
+ default=None,
350
+ help="Optional issue branch for the eventual caller-repo execution.",
351
+ )
352
+ workflow_parser.add_argument(
353
+ "--validation-label",
354
+ default="caller-declared validation",
355
+ help="Public-safe validation label stored in the workflow plan.",
356
+ )
357
+ workflow_parser.add_argument(
358
+ "--repository-context-json",
359
+ default=None,
360
+ help=(
361
+ "Optional issue_fix_repository_context_input_v0 JSON path, or '-' for "
362
+ "stdin. Only compact source refs, trust, freshness, and coverage are kept."
363
+ ),
364
+ )
365
+ workflow_parser.add_argument(
366
+ "--candidate-preflight-json",
367
+ default=None,
368
+ help=(
369
+ "Optional issue_fix_candidate_preflight_input_v0 with compact prior "
370
+ "domain state, all-state numeric PR references, verified semantic "
371
+ "implementation candidates, and an existing recall receipt. The "
372
+ "workflow performs no provider or memory calls."
373
+ ),
374
+ )
375
+ workflow_parser.add_argument(
376
+ "--fetch-candidate-evidence",
377
+ action="store_true",
378
+ help=(
379
+ "Collect complete issue-specific GitHub closing-PR, cross-reference, "
380
+ "and maintainer-disposition receipts before planning."
381
+ ),
382
+ )
383
+ workflow_parser.add_argument(
384
+ "--candidate-evidence-timeout-seconds",
385
+ type=int,
386
+ default=30,
387
+ help="Timeout for --fetch-candidate-evidence.",
388
+ )
389
+ workflow_parser.add_argument(
390
+ "--candidate-resolution-json",
391
+ default=None,
392
+ help=(
393
+ "Optional issue_fix_candidate_resolution_v0 that resolves source-backed "
394
+ "PR revisions, closed PRs, or maintainer comments. Requires "
395
+ "--fetch-candidate-evidence so stale source bindings fail closed."
396
+ ),
397
+ )
398
+ workflow_parser.add_argument(
399
+ "--goal-id",
400
+ default=None,
401
+ help=(
402
+ "Goal id used to persist the source-qualified candidate admission "
403
+ "receipt before any feasibility or implementation decision."
404
+ ),
405
+ )
406
+ workflow_parser.add_argument(
407
+ "--project",
408
+ default=".",
409
+ help="Project root for the default issue_fix candidate preflight ledger.",
410
+ )
411
+ workflow_parser.add_argument(
412
+ "--candidate-preflight-ledger-path",
413
+ default=None,
414
+ help="Optional candidate preflight JSONL path. Overrides the default path.",
415
+ )
416
+ workflow_parser.add_argument(
417
+ "--no-write-domain-state",
418
+ action="store_true",
419
+ help=(
420
+ "Keep candidate preflight preview-only even when --goal-id or an "
421
+ "explicit ledger path is present."
422
+ ),
423
+ )
424
+ workflow_parser.add_argument(
425
+ "--repository-memory-json",
426
+ default=None,
427
+ help=(
428
+ "Optional issue_fix_repository_memory_read_result_v0 JSON path, or '-' "
429
+ "for stdin. The host must perform explicit public-namespace search/read; "
430
+ "LoopX keeps only compact advisory refs and checkout verification."
431
+ ),
432
+ )
433
+ _add_repository_memory_provider_args(workflow_parser)
434
+ _add_generated_at_arg(workflow_parser, artifact="the workflow plan")
435
+ feasibility_parser = issue_fix_sub.add_parser(
436
+ "feasibility",
437
+ help=(
438
+ "Select exactly one fix_pr, comment_only, or triage_only route "
439
+ "from compact public-safe agent observations."
440
+ ),
441
+ )
442
+ add_subcommand_format(feasibility_parser)
443
+ feasibility_parser.add_argument(
444
+ "--repo",
445
+ default="public_repo_fixture",
446
+ help="Public-safe repository label for the issue.",
447
+ )
448
+ feasibility_parser.add_argument(
449
+ "--issue-ref",
450
+ default="issue_123_public_metadata_fixture",
451
+ help="Public-safe issue reference label.",
452
+ )
453
+ feasibility_parser.add_argument(
454
+ "--url",
455
+ default=None,
456
+ help="Optional https://github.com/owner/repo/issues/123 URL.",
457
+ )
458
+ feasibility_parser.add_argument(
459
+ "--reproduction-status",
460
+ required=True,
461
+ choices=("confirmed", "planned", "missing", "blocked"),
462
+ help="Compact agent observation of reproduction readiness.",
463
+ )
464
+ feasibility_parser.add_argument(
465
+ "--scope-class",
466
+ required=True,
467
+ choices=("bounded", "uncertain", "oversized"),
468
+ help="Compact agent observation of expected change scope.",
469
+ )
470
+ feasibility_parser.add_argument(
471
+ "--reproduction-label",
472
+ default=None,
473
+ help="Compact public-safe repro or repro-plan label; never raw logs.",
474
+ )
475
+ feasibility_parser.add_argument(
476
+ "--validation-label",
477
+ default=None,
478
+ help="Compact public-safe validation surface label.",
479
+ )
480
+ feasibility_parser.add_argument(
481
+ "--comment-value",
482
+ default="none",
483
+ choices=("none", "clarification", "diagnosis"),
484
+ help="Whether a maintainer-facing comment would add public value.",
485
+ )
486
+ feasibility_parser.add_argument(
487
+ "--repository-context-json",
488
+ default=None,
489
+ help=(
490
+ "Optional issue_fix_repository_context_input_v0 JSON path, or '-' for "
491
+ "stdin. The compact projection is persisted with feasibility domain state."
492
+ ),
493
+ )
494
+ feasibility_parser.add_argument(
495
+ "--repository-memory-json",
496
+ default=None,
497
+ help=(
498
+ "Optional issue_fix_repository_memory_read_result_v0 JSON path, or '-' "
499
+ "for stdin. Provider failures stay fail-open and no writeback is allowed."
500
+ ),
501
+ )
502
+ feasibility_parser.add_argument(
503
+ "--repo-path",
504
+ default=None,
505
+ help=(
506
+ "Optional caller-approved current checkout used only to verify provider "
507
+ "content. The path is never retained."
508
+ ),
509
+ )
510
+ _add_repository_memory_provider_args(feasibility_parser)
511
+ _add_generated_at_arg(feasibility_parser, artifact="the feasibility decision")
512
+ feasibility_parser.add_argument(
513
+ "--goal-id",
514
+ default=None,
515
+ help="Goal id used for the default issue_fix feasibility ledger path.",
516
+ )
517
+ feasibility_parser.add_argument(
518
+ "--project",
519
+ default=".",
520
+ help="Project root for the default issue_fix feasibility ledger path.",
521
+ )
522
+ feasibility_parser.add_argument(
523
+ "--ledger-path",
524
+ default=None,
525
+ help="Optional local JSONL ledger path. Overrides the default path.",
526
+ )
527
+ feasibility_parser.add_argument(
528
+ "--no-write-domain-state",
529
+ action="store_true",
530
+ help=(
531
+ "Keep feasibility preview-only even when --goal-id or --ledger-path "
532
+ "is present."
533
+ ),
534
+ )
535
+ pr_lifecycle_parser = issue_fix_sub.add_parser(
536
+ "pr-lifecycle",
537
+ help=(
538
+ "Project a public PR lifecycle observation into a successor, "
539
+ "monitor-continuation, user-gate, or no-follow-up transition."
540
+ ),
541
+ )
542
+ add_subcommand_format(pr_lifecycle_parser)
543
+ pr_lifecycle_parser.add_argument(
544
+ "--repo",
545
+ default="public_repo_fixture",
546
+ help="Public-safe repository label for the PR metadata.",
547
+ )
548
+ pr_lifecycle_parser.add_argument(
549
+ "--pr-ref",
550
+ default="pull_123_public_metadata_fixture",
551
+ help="Public-safe PR reference label.",
552
+ )
553
+ pr_lifecycle_parser.add_argument(
554
+ "--issue-ref",
555
+ default=None,
556
+ help=(
557
+ "Optional public-safe issue reference linked to this PR. Persisting "
558
+ "the explicit link lets default Kanban sync compose the issue outcome "
559
+ "without guessing from titles or branch names. Numeric aliases such "
560
+ "as #123 and issue_123 are stored as issues_123."
561
+ ),
562
+ )
563
+ pr_lifecycle_parser.add_argument(
564
+ "--url",
565
+ default=None,
566
+ help="Optional https://github.com/owner/repo/pull/123 URL.",
567
+ )
568
+ pr_lifecycle_parser.add_argument(
569
+ "--metadata-json",
570
+ default=None,
571
+ help=(
572
+ "Path to mocked gh pr view JSON metadata, or '-' for stdin. "
573
+ "Bodies, comments, raw logs, and provider responses stay out."
574
+ ),
575
+ )
576
+ pr_lifecycle_parser.add_argument(
577
+ "--maintainer-correction-json",
578
+ default=None,
579
+ help=(
580
+ "Optional issue_fix_maintainer_correction_input_v0 JSON object. "
581
+ "It contains only a compact public correction, source reference, "
582
+ "verification plan/update path, ambiguity question, or missing scopes."
583
+ ),
584
+ )
585
+ pr_lifecycle_parser.add_argument(
586
+ "--fetch-metadata",
587
+ action="store_true",
588
+ help=(
589
+ "Explicitly fetch public GitHub PR state with gh pr view. "
590
+ "Only compact lifecycle fields are captured."
591
+ ),
592
+ )
593
+ pr_lifecycle_parser.add_argument(
594
+ "--fetch-timeout-seconds",
595
+ type=int,
596
+ default=10,
597
+ help="Timeout for --fetch-metadata.",
598
+ )
599
+ _add_generated_at_arg(pr_lifecycle_parser, artifact="the lifecycle projection")
600
+ pr_lifecycle_parser.add_argument(
601
+ "--goal-id",
602
+ default=None,
603
+ help="Goal id used for the default issue_fix domain-state ledger path.",
604
+ )
605
+ pr_lifecycle_parser.add_argument(
606
+ "--project",
607
+ default=".",
608
+ help="Project root for the default issue_fix domain-state ledger path.",
609
+ )
610
+ pr_lifecycle_parser.add_argument(
611
+ "--ledger-path",
612
+ default=None,
613
+ help="Optional local JSONL ledger path. Overrides the default domain-state path.",
614
+ )
615
+ pr_lifecycle_parser.add_argument(
616
+ "--no-write-domain-state",
617
+ action="store_true",
618
+ help=(
619
+ "Keep the PR lifecycle command preview-only even when --goal-id or "
620
+ "--ledger-path is present."
621
+ ),
622
+ )
623
+ pr_lifecycle_parser.add_argument(
624
+ "--execute-transition",
625
+ action="store_true",
626
+ help=(
627
+ "Write the lifecycle transition and reconcile grouped monitors in "
628
+ "the existing LoopX todo state. Requires --goal-id, --claimed-by, "
629
+ "and a registry."
630
+ ),
631
+ )
632
+ pr_lifecycle_parser.add_argument(
633
+ "--claimed-by",
634
+ default=None,
635
+ help=(
636
+ "Registered agent that claims an actionable patch successor or is blocked "
637
+ "by the generated concrete user gate."
638
+ ),
639
+ )
640
+ pr_lifecycle_parser.add_argument(
641
+ "--monitor-cadence",
642
+ default=DEFAULT_ISSUE_FIX_MONITOR_CADENCE,
643
+ help=(
644
+ "Cadence for grouped PR lifecycle continuous monitors materialized "
645
+ "by --execute-transition (default: 30m)."
646
+ ),
647
+ )
648
+ pr_gate_reconcile_cli.register_pr_gate_reconciliation_command(issue_fix_sub)
649
+ outcome_parser = issue_fix_sub.add_parser(
650
+ "outcome",
651
+ help=(
652
+ "Compose one public-safe issue-fix status/output projection from "
653
+ "existing feasibility and optional PR lifecycle state."
654
+ ),
655
+ )
656
+ add_subcommand_format(outcome_parser)
657
+ outcome_parser.add_argument("--goal-id", required=True)
658
+ outcome_parser.add_argument("--project", default=".")
659
+ outcome_parser.add_argument("--repo", required=True)
660
+ outcome_parser.add_argument("--issue-ref", required=True)
661
+ outcome_parser.add_argument(
662
+ "--pr-ref",
663
+ help="Optional PR ref linked to this issue, such as pull_456.",
664
+ )
665
+ outcome_parser.add_argument(
666
+ "--feasibility-json",
667
+ help="Optional issue_fix_feasibility_v0 JSON object; defaults to domain state.",
668
+ )
669
+ outcome_parser.add_argument(
670
+ "--pr-lifecycle-json",
671
+ help=(
672
+ "Optional issue_fix_pr_lifecycle_monitor_v0 JSON object; defaults "
673
+ "to domain state when --pr-ref is present."
674
+ ),
675
+ )
676
+ outcome_parser.add_argument(
677
+ "--delivery-evidence-json",
678
+ help=(
679
+ "Optional issue_fix_delivery_evidence_input_v0 JSON with explicit "
680
+ "validation status, repo-relative changed files, commit ref, outputs, and risks."
681
+ ),
682
+ )
683
+ outcome_parser.add_argument(
684
+ "--write-delivery-evidence",
685
+ action="store_true",
686
+ help=(
687
+ "Validate and write compact delivery evidence into the selected "
688
+ "existing feasibility row so default outcome and Kanban sync retain it."
689
+ ),
690
+ )
691
+ outcome_parser.add_argument(
692
+ "--repository-memory-provider-json",
693
+ default=None,
694
+ help=(
695
+ "Local-private issue_fix_repository_memory_provider_config_v0 used "
696
+ "only when --write-repository-memory is explicit. Defaults to "
697
+ "LOOPX_ISSUE_FIX_REPOSITORY_MEMORY_PROVIDER_CONFIG."
698
+ ),
699
+ )
700
+ outcome_parser.add_argument(
701
+ "--write-repository-memory",
702
+ action="store_true",
703
+ help=(
704
+ "After passed validation and completed delivery, write one distilled "
705
+ "public outcome through an owner-enabled, revision-scoped provider. "
706
+ "No transcript or tool-result capture is performed."
707
+ ),
708
+ )
709
+ outcome_parser.add_argument(
710
+ "--repo-path",
711
+ default=None,
712
+ help=(
713
+ "Caller-approved git checkout used to prove delivery commit identity "
714
+ "before evidence writeback or repository-memory publication. "
715
+ "The path and raw git output are never recorded."
716
+ ),
717
+ )
718
+ outcome_parser.add_argument(
719
+ "--repository-ref",
720
+ default=None,
721
+ help=(
722
+ "Full recoverable git ref (refs/heads, refs/remotes, or refs/tags) that "
723
+ "must resolve exactly to the pinned repository revision when recording "
724
+ "passed or completed commit evidence."
725
+ ),
726
+ )
727
+ outcome_parser.add_argument(
728
+ "--agent-id",
729
+ help="Optional registered agent id projected as the case owner.",
730
+ )
731
+ _add_generated_at_arg(outcome_parser, artifact="the read model")
732
+ metrics_parser = issue_fix_sub.add_parser(
733
+ "metrics",
734
+ help=(
735
+ "Compose a read-only baseline, attributable output inventory, repository "
736
+ "delta, and missing-data projection from existing issue-fix domain state."
737
+ ),
738
+ )
739
+ add_subcommand_format(metrics_parser)
740
+ metrics_parser.add_argument("--goal-id", required=True)
741
+ metrics_parser.add_argument("--project", default=".")
742
+ metrics_parser.add_argument("--repo", required=True)
743
+ metrics_parser.add_argument(
744
+ "--repository-baseline-json",
745
+ required=True,
746
+ help="Public-safe issue_fix_repository_reporting_snapshot_v0 at period start.",
747
+ )
748
+ metrics_parser.add_argument(
749
+ "--repository-current-json",
750
+ required=True,
751
+ help=(
752
+ "Public-safe issue_fix_repository_reporting_snapshot_v0 at current time, "
753
+ "including flow_since_baseline."
754
+ ),
755
+ )
756
+ metrics_parser.add_argument(
757
+ "--supplement-json",
758
+ default=None,
759
+ help=(
760
+ "Optional public-safe issue_fix_metrics_supplement_v0 for autonomy, "
761
+ "first-push CI, memory, and capability-delta counts."
762
+ ),
763
+ )
764
+ metrics_parser.add_argument(
765
+ "--feasibility-ledger",
766
+ default=None,
767
+ help="Optional feasibility JSONL override; defaults to goal domain state.",
768
+ )
769
+ metrics_parser.add_argument(
770
+ "--pr-lifecycle-ledger",
771
+ default=None,
772
+ help="Optional PR lifecycle JSONL override; defaults to goal domain state.",
773
+ )
774
+ _add_generated_at_arg(metrics_parser, artifact="the metrics projection")
775
+ register_issue_fix_metrics_supplement_command(
776
+ issue_fix_sub,
777
+ add_subcommand_format=add_subcommand_format,
778
+ add_generated_at_arg=_add_generated_at_arg,
779
+ )
780
+ snapshot_parser = issue_fix_sub.add_parser(
781
+ "repository-snapshot",
782
+ help=(
783
+ "Collect a compact public GitHub repository snapshot for issue-fix "
784
+ "metrics and optionally retain one material snapshot per day."
785
+ ),
786
+ )
787
+ add_subcommand_format(snapshot_parser)
788
+ snapshot_parser.add_argument("--goal-id", required=True)
789
+ snapshot_parser.add_argument("--project", default=".")
790
+ snapshot_parser.add_argument("--repo", required=True)
791
+ snapshot_parser.add_argument("--repository-baseline-json", required=True)
792
+ snapshot_parser.add_argument(
793
+ "--supplement-json",
794
+ default=None,
795
+ help=(
796
+ "Optional public-safe issue_fix_metrics_supplement_v0 whose "
797
+ "issue-close activity refs must be included in current-state collection."
798
+ ),
799
+ )
800
+ snapshot_parser.add_argument(
801
+ "--fetch-public-github",
802
+ action="store_true",
803
+ help="Explicitly read bounded public repository metadata through gh.",
804
+ )
805
+ snapshot_parser.add_argument(
806
+ "--retain-material-snapshot",
807
+ action="store_true",
808
+ help=(
809
+ "Write only a material daily change into the existing issue_fix "
810
+ "domain-state stream."
811
+ ),
812
+ )
813
+ snapshot_parser.add_argument("--fetch-timeout-seconds", type=int, default=30)
814
+ _add_generated_at_arg(snapshot_parser, artifact="the repository snapshot")
815
+ register_issue_fix_reviewer_commands(
816
+ issue_fix_sub,
817
+ add_subcommand_format=add_subcommand_format,
818
+ add_generated_at_arg=_add_generated_at_arg,
819
+ )
820
+ acceptance_parser = issue_fix_sub.add_parser(
821
+ "acceptance-fixture",
822
+ help=(
823
+ "Run a deterministic fix loop: failing repro, minimal patch, "
824
+ "focused validation, and PR-review-ready artifact."
825
+ ),
826
+ )
827
+ add_subcommand_format(acceptance_parser)
828
+ acceptance_parser.add_argument(
829
+ "--repo",
830
+ default="public_repo_fixture",
831
+ help="Public-safe repository label for the issue metadata fixture.",
832
+ )
833
+ acceptance_parser.add_argument(
834
+ "--issue-ref",
835
+ default="issue_123_public_metadata_fixture",
836
+ help="Public-safe issue or PR reference label for the fixture.",
837
+ )
838
+ acceptance_parser.add_argument(
839
+ "--url",
840
+ default=None,
841
+ help="Optional public GitHub issue or PR URL for metadata parsing.",
842
+ )
843
+ _add_generated_at_arg(acceptance_parser, artifact="the fixture artifact")
844
+ branch_parser = issue_fix_sub.add_parser(
845
+ "repo-branch-fixture",
846
+ help=(
847
+ "Run the fix loop through a temporary git repo issue branch: "
848
+ "branch, repro, patch, validation, and PR evidence."
849
+ ),
850
+ )
851
+ add_subcommand_format(branch_parser)
852
+ branch_parser.add_argument(
853
+ "--repo",
854
+ default="public_repo_fixture",
855
+ help="Public-safe repository label for the issue metadata fixture.",
856
+ )
857
+ branch_parser.add_argument(
858
+ "--issue-ref",
859
+ default="issue_123_public_metadata_fixture",
860
+ help="Public-safe issue or PR reference label for the fixture.",
861
+ )
862
+ branch_parser.add_argument(
863
+ "--url",
864
+ default=None,
865
+ help="Optional public GitHub issue or PR URL for metadata parsing.",
866
+ )
867
+ _add_generated_at_arg(branch_parser, artifact="the fixture artifact")
868
+ caller_branch_parser = issue_fix_sub.add_parser(
869
+ "caller-repo-branch",
870
+ help=(
871
+ "Prepare or execute an explicitly approved local repo issue branch "
872
+ "workflow without external comments, PR creation, or merge."
873
+ ),
874
+ )
875
+ add_subcommand_format(caller_branch_parser)
876
+ caller_branch_parser.add_argument(
877
+ "--repo-path",
878
+ required=True,
879
+ help=(
880
+ "Caller-approved local git repository path. The public artifact records "
881
+ "only a repo label, never this path."
882
+ ),
883
+ )
884
+ caller_branch_parser.add_argument(
885
+ "--repo",
886
+ default="approved_local_repo",
887
+ help="Public-safe repository label when no URL-derived repo is provided.",
888
+ )
889
+ caller_branch_parser.add_argument(
890
+ "--issue-ref",
891
+ default="issue_123_public_metadata",
892
+ help="Public-safe issue or PR reference label.",
893
+ )
894
+ caller_branch_parser.add_argument(
895
+ "--url",
896
+ default=None,
897
+ help="Optional public GitHub issue or PR URL used only for compact metadata.",
898
+ )
899
+ caller_branch_parser.add_argument(
900
+ "--base-branch",
901
+ default="main",
902
+ help="Approved local base branch used when creating a new issue branch.",
903
+ )
904
+ caller_branch_parser.add_argument(
905
+ "--issue-branch",
906
+ default=None,
907
+ help="Optional issue branch to create or claim. Defaults to codex/<issue>-fix.",
908
+ )
909
+ caller_branch_parser.add_argument(
910
+ "--validation-command",
911
+ default=None,
912
+ help="Caller-declared validation command. Required with --execute.",
913
+ )
914
+ caller_branch_parser.add_argument(
915
+ "--validation-label",
916
+ default="caller-declared validation",
917
+ help="Public-safe validation label stored in the artifact instead of raw command text.",
918
+ )
919
+ caller_branch_parser.add_argument(
920
+ "--timeout-seconds",
921
+ type=int,
922
+ default=60,
923
+ help="Validation timeout in seconds.",
924
+ )
925
+ caller_branch_parser.add_argument(
926
+ "--execute",
927
+ action="store_true",
928
+ help=(
929
+ "Actually inspect the approved repo, create or claim the issue branch, "
930
+ "and run the caller-declared validation."
931
+ ),
932
+ )
933
+ _add_generated_at_arg(caller_branch_parser, artifact="the artifact")
934
+
935
+
936
+ def handle_issue_fix_command(
937
+ args: argparse.Namespace,
938
+ *,
939
+ registry_path: Path | None = None,
940
+ runtime_root_arg: str | None = None,
941
+ reviewer_provider_hooks_factory: (
942
+ IssueFixReviewerProviderHooksFactory | None
943
+ ) = None,
944
+ output_format: FormatSelector,
945
+ print_payload: PrintPayload,
946
+ ) -> int:
947
+ try:
948
+ invocation_at = now_utc_iso()
949
+ generated_at = str(args.generated_at or invocation_at).strip()
950
+ reviewer_result = handle_issue_fix_reviewer_command(
951
+ args,
952
+ registry_path=registry_path,
953
+ generated_at=generated_at,
954
+ delivery_observed_at=invocation_at,
955
+ reviewer_provider_hooks_factory=reviewer_provider_hooks_factory,
956
+ )
957
+ if reviewer_result is not None:
958
+ payload, renderer = reviewer_result
959
+ elif args.issue_fix_command == "repository-memory-sync":
960
+ provider_path = (
961
+ args.repository_memory_provider_json
962
+ or default_repository_memory_provider_config_path()
963
+ )
964
+ if not provider_path:
965
+ raise ValueError("repository memory provider config is required")
966
+ if provider_path == "-" and args.repository_context_json == "-":
967
+ raise ValueError("only one JSON input may read from stdin")
968
+ repository_context_input = _load_json_object(args.repository_context_json)
969
+ revision = str(
970
+ repository_context_input.get("repository_revision") or ""
971
+ ).strip()
972
+ if not revision:
973
+ raise ValueError("repository context must pin repository_revision")
974
+ payload = sync_issue_fix_repository_memory(
975
+ config=_load_json_object(provider_path),
976
+ repo_path=args.repo_path,
977
+ repository_revision=revision,
978
+ references=args.resource_reference,
979
+ observed_at=generated_at,
980
+ execute=args.execute,
981
+ )
982
+ renderer = render_issue_fix_repository_memory_sync_markdown
983
+ elif args.issue_fix_command == "promote-discovered-issue":
984
+ boundary_authority_scopes, boundary_authority_resolved = (
985
+ _goal_boundary_authority_projection(
986
+ registry_path=registry_path,
987
+ goal_id=args.goal_id,
988
+ )
989
+ )
990
+ payload = build_discovered_issue_promotion_from_cli_args(
991
+ args,
992
+ load_json_object=_load_json_object,
993
+ boundary_authority_scopes=boundary_authority_scopes,
994
+ boundary_authority_resolved=boundary_authority_resolved,
995
+ generated_at=generated_at,
996
+ )
997
+ renderer = render_issue_fix_discovered_issue_promotion_markdown
998
+ elif args.issue_fix_command == "workflow-plan":
999
+ if args.fetch_metadata and args.metadata_json:
1000
+ raise ValueError(
1001
+ "--fetch-metadata cannot be combined with --metadata-json"
1002
+ )
1003
+ if args.fetch_candidate_evidence and args.candidate_preflight_json:
1004
+ raise ValueError(
1005
+ "--fetch-candidate-evidence cannot be combined with "
1006
+ "--candidate-preflight-json"
1007
+ )
1008
+ if args.candidate_resolution_json and not args.fetch_candidate_evidence:
1009
+ raise ValueError(
1010
+ "--candidate-resolution-json requires --fetch-candidate-evidence"
1011
+ )
1012
+ provider_path = args.repository_memory_provider_json or (
1013
+ None
1014
+ if args.repository_memory_json
1015
+ else default_repository_memory_provider_config_path()
1016
+ )
1017
+ stdin_inputs = [
1018
+ value
1019
+ for value in (
1020
+ args.metadata_json,
1021
+ args.repository_context_json,
1022
+ args.repository_memory_json,
1023
+ args.candidate_preflight_json,
1024
+ args.candidate_resolution_json,
1025
+ provider_path,
1026
+ )
1027
+ if value == "-"
1028
+ ]
1029
+ if len(stdin_inputs) > 1:
1030
+ raise ValueError("only one JSON input may read from stdin")
1031
+ repository_context_input = (
1032
+ _load_json_object(args.repository_context_json)
1033
+ if args.repository_context_json
1034
+ else None
1035
+ )
1036
+ if args.fetch_candidate_evidence:
1037
+ reference = normalise_github_issue_reference(
1038
+ repo=args.repo,
1039
+ issue_ref=args.issue_ref,
1040
+ url=args.url,
1041
+ )
1042
+ if reference["kind"] != "issue":
1043
+ raise ValueError(
1044
+ "--fetch-candidate-evidence requires a GitHub issue"
1045
+ )
1046
+ candidate_preflight_input = (
1047
+ collect_public_github_candidate_preflight_input(
1048
+ repo=str(reference["repo"]),
1049
+ issue_ref=str(reference["issue_ref"]),
1050
+ generated_at=generated_at,
1051
+ timeout_seconds=args.candidate_evidence_timeout_seconds,
1052
+ )
1053
+ )
1054
+ if args.candidate_resolution_json:
1055
+ candidate_preflight_input["candidate_resolution"] = (
1056
+ _load_json_object(args.candidate_resolution_json)
1057
+ )
1058
+ else:
1059
+ candidate_preflight_input = (
1060
+ _load_json_object(args.candidate_preflight_json)
1061
+ if args.candidate_preflight_json
1062
+ else None
1063
+ )
1064
+ repository_memory_input = _configured_repository_memory_input(
1065
+ provider_path=provider_path,
1066
+ raw_memory_path=args.repository_memory_json,
1067
+ repo_path=args.repo_path,
1068
+ repository_context_input=repository_context_input,
1069
+ repo=args.repo,
1070
+ issue_ref=args.issue_ref,
1071
+ query=args.repository_memory_query,
1072
+ supports=args.repository_memory_support,
1073
+ validation_label=args.validation_label,
1074
+ observed_at=generated_at,
1075
+ )
1076
+ payload = build_issue_fix_workflow_plan_packet(
1077
+ repo=args.repo,
1078
+ issue_ref=args.issue_ref,
1079
+ url=args.url,
1080
+ provider_payload=_load_json_object(args.metadata_json)
1081
+ if args.metadata_json
1082
+ else None,
1083
+ fetch_metadata=args.fetch_metadata,
1084
+ fetch_timeout_seconds=args.fetch_timeout_seconds,
1085
+ repo_path=args.repo_path,
1086
+ base_branch=args.base_branch,
1087
+ issue_branch=args.issue_branch,
1088
+ validation_label=args.validation_label,
1089
+ repository_context_input=repository_context_input,
1090
+ repository_memory_input=repository_memory_input,
1091
+ candidate_preflight_input=candidate_preflight_input,
1092
+ generated_at=generated_at,
1093
+ )
1094
+ candidate_preflight = payload.get("candidate_preflight")
1095
+ should_write_candidate_preflight = bool(
1096
+ not args.no_write_domain_state
1097
+ and (args.goal_id or args.candidate_preflight_ledger_path)
1098
+ )
1099
+ if should_write_candidate_preflight:
1100
+ if not isinstance(candidate_preflight, dict):
1101
+ raise ValueError(
1102
+ "workflow plan omitted the candidate preflight receipt"
1103
+ )
1104
+ candidate_preflight_ledger_path = (
1105
+ Path(args.candidate_preflight_ledger_path).expanduser()
1106
+ if args.candidate_preflight_ledger_path
1107
+ else default_issue_fix_candidate_preflight_ledger_path(
1108
+ project=args.project,
1109
+ goal_id=args.goal_id,
1110
+ )
1111
+ )
1112
+ upsert_issue_fix_candidate_preflight_ledger_jsonl(
1113
+ candidate_preflight_ledger_path,
1114
+ candidate_preflight,
1115
+ )
1116
+ elif isinstance(candidate_preflight, dict):
1117
+ domain_state = candidate_preflight.get("domain_state_projection")
1118
+ if isinstance(domain_state, dict):
1119
+ domain_state["write_skipped_reason"] = (
1120
+ "explicitly_disabled"
1121
+ if args.no_write_domain_state
1122
+ else "goal_id_or_ledger_path_missing"
1123
+ )
1124
+ renderer = render_issue_fix_workflow_plan_markdown
1125
+ elif args.issue_fix_command == "feasibility":
1126
+ provider_path = args.repository_memory_provider_json or (
1127
+ None
1128
+ if args.repository_memory_json
1129
+ else default_repository_memory_provider_config_path()
1130
+ )
1131
+ if (
1132
+ args.repository_context_json == "-"
1133
+ and args.repository_memory_json == "-"
1134
+ ):
1135
+ raise ValueError("only one JSON input may read from stdin")
1136
+ if provider_path == "-" and (
1137
+ args.repository_context_json == "-"
1138
+ or args.repository_memory_json == "-"
1139
+ ):
1140
+ raise ValueError("only one JSON input may read from stdin")
1141
+ repository_context_input = (
1142
+ _load_json_object(args.repository_context_json)
1143
+ if args.repository_context_json
1144
+ else None
1145
+ )
1146
+ repository_memory_input = _configured_repository_memory_input(
1147
+ provider_path=provider_path,
1148
+ raw_memory_path=args.repository_memory_json,
1149
+ repo_path=args.repo_path,
1150
+ repository_context_input=repository_context_input,
1151
+ repo=args.repo,
1152
+ issue_ref=args.issue_ref,
1153
+ query=args.repository_memory_query,
1154
+ supports=args.repository_memory_support,
1155
+ validation_label=args.validation_label,
1156
+ observed_at=generated_at,
1157
+ )
1158
+ boundary_authority_scopes, boundary_authority_resolved = (
1159
+ _goal_boundary_authority_projection(
1160
+ registry_path=registry_path,
1161
+ goal_id=args.goal_id,
1162
+ )
1163
+ )
1164
+ payload = build_issue_fix_feasibility_packet(
1165
+ repo=args.repo,
1166
+ issue_ref=args.issue_ref,
1167
+ url=args.url,
1168
+ reproduction_status=args.reproduction_status,
1169
+ scope_class=args.scope_class,
1170
+ reproduction_label=args.reproduction_label,
1171
+ validation_label=args.validation_label,
1172
+ comment_value=args.comment_value,
1173
+ repository_context_input=repository_context_input,
1174
+ repository_memory_input=repository_memory_input,
1175
+ boundary_authority_scopes=boundary_authority_scopes,
1176
+ boundary_authority_resolved=boundary_authority_resolved,
1177
+ generated_at=generated_at,
1178
+ )
1179
+ should_write_domain_state = bool(
1180
+ not args.no_write_domain_state and (args.goal_id or args.ledger_path)
1181
+ )
1182
+ if should_write_domain_state:
1183
+ ledger_path = (
1184
+ Path(args.ledger_path).expanduser()
1185
+ if args.ledger_path
1186
+ else default_issue_fix_feasibility_ledger_path(
1187
+ project=args.project,
1188
+ goal_id=args.goal_id,
1189
+ )
1190
+ )
1191
+ upsert_issue_fix_feasibility_ledger_jsonl(
1192
+ ledger_path,
1193
+ payload,
1194
+ )
1195
+ else:
1196
+ domain_state = payload.get("domain_state_projection")
1197
+ if isinstance(domain_state, dict) and not args.no_write_domain_state:
1198
+ domain_state["write_skipped_reason"] = (
1199
+ "goal_id_or_ledger_path_missing"
1200
+ )
1201
+ renderer = render_issue_fix_feasibility_markdown
1202
+ elif args.issue_fix_command in {
1203
+ "pr-gate-reconcile",
1204
+ "pr-review-ack",
1205
+ "pr-review-reconcile",
1206
+ "pr-review-reconcile-acked",
1207
+ }:
1208
+ if args.issue_fix_command == "pr-gate-reconcile":
1209
+ payload = (
1210
+ pr_gate_reconcile_cli.build_pr_gate_reconciliation_from_args(
1211
+ args, registry_path, runtime_root_arg, generated_at
1212
+ )
1213
+ )
1214
+ renderer = (
1215
+ pr_gate_reconcile_cli.render_issue_fix_pr_gate_reconciliation_markdown
1216
+ )
1217
+ elif args.issue_fix_command == "pr-review-ack":
1218
+ payload = pr_gate_reconcile_cli.build_pr_review_ack_from_args(
1219
+ args, registry_path, runtime_root_arg, generated_at
1220
+ )
1221
+ renderer = (
1222
+ pr_gate_reconcile_cli.render_issue_fix_pr_review_ack_markdown
1223
+ )
1224
+ elif args.issue_fix_command == "pr-review-reconcile-acked":
1225
+ payload = (
1226
+ pr_gate_reconcile_cli.build_acked_pr_review_reconciliation_from_args(
1227
+ args, registry_path, runtime_root_arg, generated_at
1228
+ )
1229
+ )
1230
+ renderer = (
1231
+ pr_gate_reconcile_cli.render_issue_fix_acked_pr_review_reconciliation_markdown
1232
+ )
1233
+ else:
1234
+ payload = (
1235
+ pr_gate_reconcile_cli.build_pr_review_reconciliation_from_args(
1236
+ args, registry_path, runtime_root_arg, generated_at
1237
+ )
1238
+ )
1239
+ renderer = (
1240
+ pr_gate_reconcile_cli.render_issue_fix_pr_review_reconciliation_markdown
1241
+ )
1242
+ elif args.issue_fix_command == "pr-lifecycle":
1243
+ if args.fetch_metadata and args.metadata_json:
1244
+ raise ValueError(
1245
+ "--fetch-metadata cannot be combined with --metadata-json"
1246
+ )
1247
+ fetch_metadata = bool(
1248
+ args.fetch_metadata
1249
+ or (args.execute_transition and args.url and not args.metadata_json)
1250
+ )
1251
+ if args.execute_transition and args.no_write_domain_state:
1252
+ raise ValueError(
1253
+ "--execute-transition cannot be combined with --no-write-domain-state"
1254
+ )
1255
+ if args.execute_transition and registry_path is None:
1256
+ raise ValueError("--execute-transition requires a LoopX registry")
1257
+ if args.execute_transition and not args.goal_id:
1258
+ raise ValueError("--execute-transition requires --goal-id")
1259
+ if args.execute_transition and not args.claimed_by:
1260
+ raise ValueError("--execute-transition requires --claimed-by")
1261
+ payload = build_issue_fix_pr_lifecycle_monitor_packet(
1262
+ repo=args.repo,
1263
+ pr_ref=args.pr_ref,
1264
+ issue_ref=args.issue_ref,
1265
+ url=args.url,
1266
+ provider_payload=_load_json_object(args.metadata_json)
1267
+ if args.metadata_json
1268
+ else None,
1269
+ fetch_metadata=fetch_metadata,
1270
+ fetch_timeout_seconds=args.fetch_timeout_seconds,
1271
+ maintainer_correction_input=(
1272
+ _load_json_object(args.maintainer_correction_json)
1273
+ if args.maintainer_correction_json
1274
+ else None
1275
+ ),
1276
+ generated_at=generated_at,
1277
+ )
1278
+ should_write_domain_state = bool(
1279
+ not args.no_write_domain_state and (args.goal_id or args.ledger_path)
1280
+ )
1281
+ if should_write_domain_state:
1282
+ ledger_path = (
1283
+ Path(args.ledger_path).expanduser()
1284
+ if args.ledger_path
1285
+ else default_issue_fix_domain_state_ledger_path(
1286
+ project=args.project,
1287
+ goal_id=args.goal_id,
1288
+ )
1289
+ )
1290
+ upsert_issue_fix_pr_lifecycle_ledger_jsonl(
1291
+ ledger_path,
1292
+ payload,
1293
+ )
1294
+ observation = payload.get("observation")
1295
+ if (
1296
+ args.goal_id
1297
+ and isinstance(observation, dict)
1298
+ and str(observation.get("state") or "").upper() == "MERGED"
1299
+ ):
1300
+ payload["rollout_event"] = append_pr_merge_rollout_event(
1301
+ payload=payload,
1302
+ goal_id=args.goal_id,
1303
+ registry_path=registry_path,
1304
+ runtime_root_arg=runtime_root_arg,
1305
+ )
1306
+ else:
1307
+ domain_state = payload.get("domain_state_projection")
1308
+ if isinstance(domain_state, dict) and not args.no_write_domain_state:
1309
+ domain_state["write_skipped_reason"] = (
1310
+ "goal_id_or_ledger_path_missing"
1311
+ )
1312
+ transition = payload.get("transition")
1313
+ if args.execute_transition:
1314
+ if not isinstance(transition, dict):
1315
+ raise ValueError("PR lifecycle transition is missing")
1316
+ grouped_monitor_writeback = materialize_issue_fix_grouped_monitors(
1317
+ registry_path=registry_path,
1318
+ goal_id=args.goal_id,
1319
+ project=Path(args.project).expanduser(),
1320
+ ledger_path=ledger_path,
1321
+ claimed_by=args.claimed_by,
1322
+ cadence=args.monitor_cadence,
1323
+ generated_at=str(payload.get("generated_at") or generated_at),
1324
+ )
1325
+ payload["grouped_monitor_writeback"] = grouped_monitor_writeback
1326
+ grouped_monitor_projection = payload.get("grouped_monitor_projection")
1327
+ if isinstance(grouped_monitor_projection, dict):
1328
+ grouped_monitor_projection["todo_write_performed"] = bool(
1329
+ grouped_monitor_writeback.get("write_performed")
1330
+ )
1331
+ decision = str(transition.get("decision") or "")
1332
+ if decision in {"runnable_successor", "user_gate"}:
1333
+ role = str(transition.get("role") or "agent")
1334
+ todo_write = add_goal_todo(
1335
+ registry_path=registry_path,
1336
+ goal_id=args.goal_id,
1337
+ role=role,
1338
+ text=str(transition.get("text") or ""),
1339
+ task_class=str(
1340
+ transition.get("task_class") or "advancement_task"
1341
+ ),
1342
+ action_kind=str(transition.get("action_kind") or ""),
1343
+ required_write_scopes=(
1344
+ list(transition.get("required_write_scopes") or [])
1345
+ if role == "agent"
1346
+ else None
1347
+ ),
1348
+ claimed_by=args.claimed_by if role == "agent" else None,
1349
+ agent_id=args.claimed_by if role == "user" else None,
1350
+ project=Path(args.project).expanduser(),
1351
+ )
1352
+ todo_changed = bool(
1353
+ todo_write.get("added")
1354
+ or todo_write.get("metadata_updated")
1355
+ or todo_write.get("status_changed")
1356
+ )
1357
+ payload["todo_write"] = {
1358
+ "schema_version": "issue_fix_maintainer_correction_todo_write_v0",
1359
+ "write_performed": todo_changed,
1360
+ "already_exists": bool(todo_write.get("already_exists")),
1361
+ "todo_id": todo_write.get("todo_id"),
1362
+ "role": todo_write.get("role"),
1363
+ "claimed_by": todo_write.get("claimed_by"),
1364
+ "blocks_agent": todo_write.get("blocks_agent"),
1365
+ "path_recorded": False,
1366
+ }
1367
+ payload["todo_write_performed"] = todo_changed
1368
+ writeback_contract = payload.get("writeback_contract")
1369
+ if isinstance(writeback_contract, dict):
1370
+ writeback_contract["todo_write_performed"] = bool(todo_changed)
1371
+ else:
1372
+ payload["todo_write"] = {
1373
+ "schema_version": "issue_fix_maintainer_correction_todo_write_v0",
1374
+ "write_performed": False,
1375
+ "already_exists": False,
1376
+ "skip_reason": (
1377
+ "unchanged_monitor_quiet"
1378
+ if decision == "monitor_continuation"
1379
+ else "terminal_or_no_followup"
1380
+ ),
1381
+ "path_recorded": False,
1382
+ }
1383
+ grouped_write_performed = bool(
1384
+ grouped_monitor_writeback.get("write_performed")
1385
+ )
1386
+ transition_write_performed = bool(payload.get("todo_write_performed"))
1387
+ payload["todo_write_performed"] = bool(
1388
+ grouped_write_performed or transition_write_performed
1389
+ )
1390
+ if grouped_write_performed and not transition_write_performed:
1391
+ payload["todo_write"] = {
1392
+ "schema_version": "issue_fix_pr_lifecycle_todo_write_v1",
1393
+ "write_performed": True,
1394
+ "grouped_monitor_write_performed": True,
1395
+ "transition_write_performed": False,
1396
+ "path_recorded": False,
1397
+ }
1398
+ writeback_contract = payload.get("writeback_contract")
1399
+ if isinstance(writeback_contract, dict):
1400
+ writeback_contract["todo_write_performed"] = bool(
1401
+ payload["todo_write_performed"]
1402
+ )
1403
+ validation = validate_issue_fix_pr_lifecycle_monitor_packet(payload)
1404
+ payload["validation"] = validation
1405
+ payload["ok"] = bool(validation["ok"])
1406
+ renderer = render_issue_fix_pr_lifecycle_monitor_markdown
1407
+ elif args.issue_fix_command == "outcome":
1408
+ if args.write_delivery_evidence and not args.delivery_evidence_json:
1409
+ raise ValueError(
1410
+ "--write-delivery-evidence requires --delivery-evidence-json"
1411
+ )
1412
+ if args.write_delivery_evidence and args.feasibility_json:
1413
+ raise ValueError(
1414
+ "--write-delivery-evidence uses the default feasibility domain-state row; "
1415
+ "do not combine it with --feasibility-json"
1416
+ )
1417
+ provider_path = args.repository_memory_provider_json or (
1418
+ default_repository_memory_provider_config_path()
1419
+ if args.write_repository_memory
1420
+ else None
1421
+ )
1422
+ if args.write_repository_memory and not provider_path:
1423
+ raise ValueError(
1424
+ "--write-repository-memory requires an explicit provider config "
1425
+ "or LOOPX_ISSUE_FIX_REPOSITORY_MEMORY_PROVIDER_CONFIG"
1426
+ )
1427
+ stdin_input_count = sum(
1428
+ value == "-"
1429
+ for value in (
1430
+ args.feasibility_json,
1431
+ args.pr_lifecycle_json,
1432
+ args.delivery_evidence_json,
1433
+ )
1434
+ )
1435
+ if stdin_input_count > 1:
1436
+ raise ValueError("only one outcome JSON input may read from stdin")
1437
+ project = Path(args.project).expanduser()
1438
+ feasibility_packet = (
1439
+ _load_json_object(args.feasibility_json)
1440
+ if args.feasibility_json
1441
+ else _load_jsonl_row(
1442
+ default_issue_fix_feasibility_ledger_path(
1443
+ project=project,
1444
+ goal_id=args.goal_id,
1445
+ ),
1446
+ repo=args.repo,
1447
+ ref_field="issue_ref",
1448
+ ref_value=args.issue_ref,
1449
+ )
1450
+ )
1451
+ feasibility_observation = feasibility_packet.get("observation")
1452
+ if not isinstance(feasibility_observation, dict) or (
1453
+ str(feasibility_observation.get("repo") or "").strip() != args.repo
1454
+ or str(feasibility_observation.get("issue_ref") or "").strip()
1455
+ != args.issue_ref
1456
+ ):
1457
+ raise ValueError(
1458
+ "--repo/--issue-ref must match the selected feasibility packet"
1459
+ )
1460
+ pr_lifecycle_packet = None
1461
+ if args.pr_lifecycle_json:
1462
+ pr_lifecycle_packet = _load_json_object(args.pr_lifecycle_json)
1463
+ elif args.pr_ref:
1464
+ pr_lifecycle_packet = _load_jsonl_row(
1465
+ default_issue_fix_domain_state_ledger_path(
1466
+ project=project,
1467
+ goal_id=args.goal_id,
1468
+ ),
1469
+ repo=args.repo,
1470
+ ref_field="pr_ref",
1471
+ ref_value=args.pr_ref,
1472
+ )
1473
+ if pr_lifecycle_packet is not None and args.pr_ref:
1474
+ lifecycle_observation = pr_lifecycle_packet.get("observation")
1475
+ if (
1476
+ not isinstance(lifecycle_observation, dict)
1477
+ or str(lifecycle_observation.get("pr_ref") or "").strip()
1478
+ != args.pr_ref
1479
+ ):
1480
+ raise ValueError(
1481
+ "--pr-ref must match the selected PR lifecycle packet"
1482
+ )
1483
+ explicit_delivery_evidence = (
1484
+ _load_json_object(args.delivery_evidence_json)
1485
+ if args.delivery_evidence_json
1486
+ else None
1487
+ )
1488
+ delivery_evidence = (
1489
+ compact_issue_fix_delivery_evidence(
1490
+ explicit_delivery_evidence,
1491
+ )
1492
+ if explicit_delivery_evidence is not None
1493
+ else (
1494
+ feasibility_packet.get("delivery_evidence")
1495
+ if isinstance(feasibility_packet.get("delivery_evidence"), dict)
1496
+ else None
1497
+ )
1498
+ )
1499
+ if explicit_delivery_evidence is not None:
1500
+ requires_commit_verification = bool(
1501
+ delivery_evidence.get("commit_ref")
1502
+ and (
1503
+ delivery_evidence.get("validation_status") == "passed"
1504
+ or delivery_evidence.get("outcome_status") == "completed"
1505
+ )
1506
+ )
1507
+ if requires_commit_verification and (
1508
+ args.repo_path
1509
+ or args.repository_ref
1510
+ or args.write_delivery_evidence
1511
+ ):
1512
+ if not args.repo_path or not args.repository_ref:
1513
+ raise ValueError(
1514
+ "passed or completed commit evidence writeback requires "
1515
+ "--repo-path and --repository-ref"
1516
+ )
1517
+ repository_context = feasibility_observation.get(
1518
+ "repository_context"
1519
+ )
1520
+ revision = (
1521
+ str(repository_context.get("repository_revision") or "").strip()
1522
+ if isinstance(repository_context, dict)
1523
+ else ""
1524
+ )
1525
+ if not revision:
1526
+ raise ValueError(
1527
+ "passed or completed commit evidence requires a pinned "
1528
+ "repository_revision in feasibility context"
1529
+ )
1530
+ repository_commit_evidence = (
1531
+ verify_issue_fix_repository_commit_evidence(
1532
+ repo_path=args.repo_path,
1533
+ repo=args.repo,
1534
+ repository_revision=revision,
1535
+ commit_ref=str(delivery_evidence["commit_ref"]),
1536
+ recovery_ref=args.repository_ref,
1537
+ verified_at=generated_at,
1538
+ )
1539
+ )
1540
+ delivery_evidence = compact_issue_fix_delivery_evidence(
1541
+ {
1542
+ **delivery_evidence,
1543
+ "repository_commit_evidence": repository_commit_evidence,
1544
+ }
1545
+ )
1546
+ domain_state_write: dict[str, Any] | None = None
1547
+ if args.write_delivery_evidence:
1548
+ existing_delivery = feasibility_packet.get("delivery_evidence")
1549
+ existing_compact = (
1550
+ compact_issue_fix_delivery_evidence(existing_delivery)
1551
+ if isinstance(existing_delivery, dict)
1552
+ else None
1553
+ )
1554
+ comparable_existing = _comparable_delivery_evidence(existing_compact)
1555
+ comparable_delivery = _comparable_delivery_evidence(delivery_evidence)
1556
+ if comparable_existing == comparable_delivery:
1557
+ delivery_evidence = existing_delivery
1558
+ write_result = {
1559
+ "write_performed": False,
1560
+ "status": "unchanged",
1561
+ "row_count": None,
1562
+ }
1563
+ else:
1564
+ delivery_evidence = {
1565
+ **delivery_evidence,
1566
+ "recorded_at": generated_at,
1567
+ }
1568
+ feasibility_packet["delivery_evidence"] = delivery_evidence
1569
+ write_result = upsert_issue_fix_feasibility_ledger_jsonl(
1570
+ default_issue_fix_feasibility_ledger_path(
1571
+ project=project,
1572
+ goal_id=args.goal_id,
1573
+ ),
1574
+ feasibility_packet,
1575
+ )
1576
+ domain_state_write = {
1577
+ "schema_version": "issue_fix_delivery_evidence_writeback_v0",
1578
+ "domain_pack": "issue_fix",
1579
+ "stream": "feasibility",
1580
+ "key": {"repo": args.repo, "issue_ref": args.issue_ref},
1581
+ "write_performed": write_result.get("write_performed") is True,
1582
+ "status": write_result.get("status"),
1583
+ "row_count": write_result.get("row_count"),
1584
+ "path_recorded": False,
1585
+ }
1586
+ payload = build_issue_fix_outcome_projection(
1587
+ goal_id=args.goal_id,
1588
+ feasibility_packet=feasibility_packet,
1589
+ pr_lifecycle_packet=pr_lifecycle_packet,
1590
+ delivery_evidence_input=delivery_evidence,
1591
+ agent_id=args.agent_id,
1592
+ generated_at=generated_at,
1593
+ )
1594
+ if args.write_repository_memory:
1595
+ if not args.repo_path:
1596
+ raise ValueError(
1597
+ "--write-repository-memory requires --repo-path for commit ancestry verification"
1598
+ )
1599
+ outcome_case = (payload.get("issue_fix_outcomes") or [{}])[0]
1600
+ repository_context = (
1601
+ outcome_case.get("repository_context")
1602
+ if isinstance(outcome_case, dict)
1603
+ else None
1604
+ )
1605
+ revision = (
1606
+ str(repository_context.get("revision") or "").strip()
1607
+ if isinstance(repository_context, dict)
1608
+ else ""
1609
+ )
1610
+ if not revision:
1611
+ raise ValueError(
1612
+ "--write-repository-memory requires a revision-pinned outcome"
1613
+ )
1614
+ writeback = write_issue_fix_validated_outcome_memory(
1615
+ config=_load_json_object(str(provider_path)),
1616
+ outcome_packet=payload,
1617
+ repository_revision=revision,
1618
+ repo_path=args.repo_path,
1619
+ observed_at=generated_at,
1620
+ execute=True,
1621
+ )
1622
+ payload["repository_memory_writeback"] = writeback
1623
+ payload["external_writes_performed"] = bool(
1624
+ writeback.get("external_writes_performed")
1625
+ )
1626
+ payload["ok"] = writeback.get("ok") is True
1627
+ payload["source_contract"]["repository_memory_writeback"] = (
1628
+ "issue_fix_validated_outcome_memory_writeback_v0"
1629
+ )
1630
+ payload["source_contract"]["writes_external_provider"] = bool(
1631
+ writeback.get("external_writes_performed")
1632
+ )
1633
+ if payload["ok"] is not True:
1634
+ payload["error"] = (
1635
+ "repository memory writeback "
1636
+ f"{writeback.get('status')}: "
1637
+ f"{writeback.get('reason_code') or 'provider write failed'}"
1638
+ )
1639
+ if domain_state_write is not None:
1640
+ payload["domain_state_write"] = domain_state_write
1641
+ payload["source_contract"]["writes_source_state"] = True
1642
+ renderer = render_issue_fix_outcome_projection_markdown
1643
+ elif args.issue_fix_command == "metrics":
1644
+ stdin_input_count = sum(
1645
+ value == "-"
1646
+ for value in (
1647
+ args.repository_baseline_json,
1648
+ args.repository_current_json,
1649
+ args.supplement_json,
1650
+ )
1651
+ )
1652
+ if stdin_input_count > 1:
1653
+ raise ValueError("only one metrics JSON input may read from stdin")
1654
+ project = Path(args.project).expanduser()
1655
+ feasibility_path = (
1656
+ Path(args.feasibility_ledger).expanduser()
1657
+ if args.feasibility_ledger
1658
+ else default_issue_fix_feasibility_ledger_path(
1659
+ project=project,
1660
+ goal_id=args.goal_id,
1661
+ )
1662
+ )
1663
+ lifecycle_path = (
1664
+ Path(args.pr_lifecycle_ledger).expanduser()
1665
+ if args.pr_lifecycle_ledger
1666
+ else default_issue_fix_domain_state_ledger_path(
1667
+ project=project,
1668
+ goal_id=args.goal_id,
1669
+ )
1670
+ )
1671
+ payload = build_issue_fix_metrics_projection(
1672
+ goal_id=args.goal_id,
1673
+ repo=args.repo,
1674
+ baseline_snapshot=_load_json_object(args.repository_baseline_json),
1675
+ current_snapshot=_load_json_object(args.repository_current_json),
1676
+ feasibility_rows=_load_jsonl_rows(feasibility_path),
1677
+ pr_lifecycle_rows=_load_jsonl_rows(lifecycle_path),
1678
+ supplement_input=(
1679
+ _load_json_object(args.supplement_json)
1680
+ if args.supplement_json
1681
+ else None
1682
+ ),
1683
+ generated_at=generated_at,
1684
+ )
1685
+ renderer = render_issue_fix_metrics_projection_markdown
1686
+ elif args.issue_fix_command == "metrics-supplement":
1687
+ payload = build_issue_fix_metrics_supplement_from_args(
1688
+ args,
1689
+ registry_path=registry_path,
1690
+ runtime_root_arg=runtime_root_arg,
1691
+ generated_at=generated_at,
1692
+ load_json_object=_load_json_object,
1693
+ load_jsonl_rows=_load_jsonl_rows,
1694
+ )
1695
+ renderer = render_issue_fix_metrics_supplement_markdown
1696
+ elif args.issue_fix_command == "repository-snapshot":
1697
+ if not args.fetch_public_github:
1698
+ raise ValueError("repository-snapshot requires --fetch-public-github")
1699
+ if sum(
1700
+ value == "-"
1701
+ for value in (
1702
+ args.repository_baseline_json,
1703
+ args.supplement_json,
1704
+ )
1705
+ if value is not None
1706
+ ) > 1:
1707
+ raise ValueError(
1708
+ "only one repository-snapshot JSON input may read from stdin"
1709
+ )
1710
+ project = Path(args.project).expanduser()
1711
+ payload = collect_public_github_repository_snapshot(
1712
+ repo=args.repo,
1713
+ baseline_snapshot=_load_json_object(args.repository_baseline_json),
1714
+ feasibility_rows=_load_jsonl_rows(
1715
+ default_issue_fix_feasibility_ledger_path(
1716
+ project=project, goal_id=args.goal_id
1717
+ )
1718
+ ),
1719
+ pr_lifecycle_rows=_load_jsonl_rows(
1720
+ default_issue_fix_domain_state_ledger_path(
1721
+ project=project, goal_id=args.goal_id
1722
+ )
1723
+ ),
1724
+ metrics_supplement=(
1725
+ _load_json_object(args.supplement_json)
1726
+ if args.supplement_json
1727
+ else None
1728
+ ),
1729
+ generated_at=generated_at,
1730
+ timeout_seconds=args.fetch_timeout_seconds,
1731
+ )
1732
+ if args.retain_material_snapshot:
1733
+ write_result = retain_issue_fix_repository_snapshot_jsonl(
1734
+ default_issue_fix_repository_snapshot_ledger_path(
1735
+ project=project, goal_id=args.goal_id
1736
+ ),
1737
+ repository_snapshot_record(payload["snapshot"]),
1738
+ )
1739
+ payload["retention"] = {
1740
+ "schema_version": "issue_fix_repository_snapshot_retention_v0",
1741
+ "domain_pack": "issue_fix",
1742
+ "stream": "repository_snapshots",
1743
+ "write_performed": write_result.get("write_performed") is True,
1744
+ "status": write_result.get("status"),
1745
+ "row_count": write_result.get("row_count"),
1746
+ "path_recorded": False,
1747
+ }
1748
+ payload["source_contract"]["writes_source_state"] = True
1749
+ renderer = render_repository_snapshot_markdown
1750
+ elif args.issue_fix_command == "acceptance-fixture":
1751
+ payload = build_issue_fix_acceptance_fixture_packet(
1752
+ repo=args.repo,
1753
+ issue_ref=args.issue_ref,
1754
+ url=args.url,
1755
+ generated_at=generated_at,
1756
+ )
1757
+ renderer = render_issue_fix_acceptance_loop_markdown
1758
+ elif args.issue_fix_command == "repo-branch-fixture":
1759
+ payload = build_issue_fix_repo_branch_fixture_packet(
1760
+ repo=args.repo,
1761
+ issue_ref=args.issue_ref,
1762
+ url=args.url,
1763
+ generated_at=generated_at,
1764
+ )
1765
+ renderer = render_issue_fix_acceptance_loop_markdown
1766
+ elif args.issue_fix_command == "caller-repo-branch":
1767
+ payload = build_issue_fix_caller_repo_branch_packet(
1768
+ repo_path=args.repo_path,
1769
+ repo=args.repo,
1770
+ issue_ref=args.issue_ref,
1771
+ url=args.url,
1772
+ base_branch=args.base_branch,
1773
+ issue_branch=args.issue_branch,
1774
+ validation_command=args.validation_command,
1775
+ validation_label=args.validation_label,
1776
+ execute=args.execute,
1777
+ timeout_seconds=args.timeout_seconds,
1778
+ generated_at=generated_at,
1779
+ )
1780
+ renderer = render_issue_fix_acceptance_loop_markdown
1781
+ else:
1782
+ raise ValueError(
1783
+ "issue-fix requires `repository-memory-sync`, `promote-discovered-issue`, "
1784
+ "`workflow-plan`, `feasibility`, "
1785
+ "`acceptance-fixture`, `pr-lifecycle`, `pr-gate-reconcile`, `outcome`, `metrics`, "
1786
+ "`metrics-supplement`, "
1787
+ "`repository-snapshot`, `reviewer-plan`, "
1788
+ "`reviewer-request`, `reviewer-notification-drain`, "
1789
+ "`repo-branch-fixture`, or `caller-repo-branch`"
1790
+ )
1791
+ except Exception as exc:
1792
+ payload = {
1793
+ "ok": False,
1794
+ "mode": "issue-fix",
1795
+ "error": str(exc),
1796
+ }
1797
+ renderer = (
1798
+ render_issue_fix_repository_memory_sync_markdown
1799
+ if getattr(args, "issue_fix_command", None) == "repository-memory-sync"
1800
+ else render_issue_fix_discovered_issue_promotion_markdown
1801
+ if getattr(args, "issue_fix_command", None) == "promote-discovered-issue"
1802
+ else render_issue_fix_workflow_plan_markdown
1803
+ if getattr(args, "issue_fix_command", None) == "workflow-plan"
1804
+ else render_issue_fix_feasibility_markdown
1805
+ if getattr(args, "issue_fix_command", None) == "feasibility"
1806
+ else render_issue_fix_pr_lifecycle_monitor_markdown
1807
+ if getattr(args, "issue_fix_command", None)
1808
+ in {"pr-lifecycle", "pr-gate-reconcile"}
1809
+ else render_issue_fix_outcome_projection_markdown
1810
+ if getattr(args, "issue_fix_command", None) == "outcome"
1811
+ else render_issue_fix_metrics_projection_markdown
1812
+ if getattr(args, "issue_fix_command", None) == "metrics"
1813
+ else render_issue_fix_metrics_supplement_markdown
1814
+ if getattr(args, "issue_fix_command", None) == "metrics-supplement"
1815
+ else render_repository_snapshot_markdown
1816
+ if getattr(args, "issue_fix_command", None) == "repository-snapshot"
1817
+ else reviewer_renderer(getattr(args, "issue_fix_command", None))
1818
+ if getattr(args, "issue_fix_command", None) in REVIEWER_COMMANDS
1819
+ else render_issue_fix_acceptance_loop_markdown
1820
+ )
1821
+ print_payload(payload, output_format(args), renderer)
1822
+ return 0 if payload.get("ok") else 1