specfuse-loop 0.24.0__tar.gz → 0.25.0__tar.gz

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 (621) hide show
  1. {specfuse_loop-0.24.0/specfuse_loop.egg-info → specfuse_loop-0.25.0}/PKG-INFO +1 -1
  2. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/pyproject.toml +1 -1
  3. specfuse_loop-0.25.0/specfuse/loop/data/VERSION +1 -0
  4. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/methodology.md +29 -1
  5. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/verification.yml.example +13 -0
  6. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/lint_plan.py +1 -1
  7. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/loop.py +124 -8
  8. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0/specfuse_loop.egg-info}/PKG-INFO +1 -1
  9. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/SOURCES.txt +3 -0
  10. specfuse_loop-0.25.0/tests/test_closing_sessions_on_sonnet.py +28 -0
  11. specfuse_loop-0.25.0/tests/test_dispatch_preamble_rules_pointer.py +32 -0
  12. specfuse_loop-0.25.0/tests/test_dispatch_skills_index.py +105 -0
  13. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_followups_artifact.py +26 -2
  14. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_gate_proportionality.py +19 -4
  15. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_auto_archive.py +29 -0
  16. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_close_intermediate.py +2 -2
  17. specfuse_loop-0.24.0/specfuse/loop/data/VERSION +0 -1
  18. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/LICENSE +0 -0
  19. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/NOTICE +0 -0
  20. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/README.md +0 -0
  21. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/setup.cfg +0 -0
  22. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/__init__.py +0 -0
  23. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/budget.py +0 -0
  24. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/diagnose_invoke.py +0 -0
  25. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/drafting_answers.py +0 -0
  26. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/drafting_invoke.py +0 -0
  27. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/drafting_questions.py +0 -0
  28. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/driver_command.py +0 -0
  29. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/driver_invoke.py +0 -0
  30. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/invoke.py +0 -0
  31. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/monitoring_read.py +0 -0
  32. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/__init__.py +0 -0
  33. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/answers.py +0 -0
  34. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/bugs.py +0 -0
  35. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/feature.py +0 -0
  36. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/findings_autofix.py +0 -0
  37. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/findings_diagnose.py +0 -0
  38. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/triage.py +0 -0
  39. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/queue_read.py +0 -0
  40. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/repo_detect.py +0 -0
  41. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/run.py +0 -0
  42. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/severity_backfill.py +0 -0
  43. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/state.py +0 -0
  44. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/triage_invoke.py +0 -0
  45. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/worktree.py +0 -0
  46. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/__init__.py +0 -0
  47. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/_filelock.py +0 -0
  48. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/_miniyaml.py +0 -0
  49. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/_wu_sections.py +0 -0
  50. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/adopt_feature.py +0 -0
  51. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/agent_policy.py +0 -0
  52. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/arm_eval.py +0 -0
  53. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/arm_sweep.py +0 -0
  54. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/arm_txn.py +0 -0
  55. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/bug_lane.py +0 -0
  56. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/bug_lane_run.py +0 -0
  57. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/bug_lane_state.py +0 -0
  58. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/build_provenance.py +0 -0
  59. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/caller_check.py +0 -0
  60. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/changelog.py +0 -0
  61. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/closing_requirements.py +0 -0
  62. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/cost.py +0 -0
  63. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/criteria_state.py +0 -0
  64. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
  65. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/LEARNINGS.template.md +0 -0
  66. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
  67. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
  68. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
  69. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
  70. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/getting-started.md +0 -0
  71. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/glossary.md +0 -0
  72. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/skills.md +0 -0
  73. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/gitignore.snippet +0 -0
  74. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
  75. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
  76. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/monitoring.yml.example +0 -0
  77. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/roadmap.template.md +0 -0
  78. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/close-discipline.md +0 -0
  79. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/correlation-ids.md +0 -0
  80. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
  81. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/human-output.md +0 -0
  82. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/never-touch.md +0 -0
  83. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/operator-escalation.md +0 -0
  84. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/planning-discipline.md +0 -0
  85. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/result-contract.md +0 -0
  86. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/security-boundaries.md +0 -0
  87. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/verification-discipline.md +0 -0
  88. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules-local/README.md +0 -0
  89. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/driver-event.schema.json +0 -0
  90. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/event.schema.json +0 -0
  91. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
  92. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
  93. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
  94. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
  95. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
  96. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/GATE.template.md +0 -0
  97. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
  98. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/PLAN.template.md +0 -0
  99. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/WU.template.md +0 -0
  100. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
  101. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/decisions_format.py +0 -0
  102. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/driver_edit.py +0 -0
  103. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/escalation.py +0 -0
  104. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/events_stats.py +0 -0
  105. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/gate_commands.py +0 -0
  106. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/gate_eval.py +0 -0
  107. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/gh_backend.py +0 -0
  108. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/gh_features.py +0 -0
  109. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/heartbeat.py +0 -0
  110. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/judge.py +0 -0
  111. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/labels.py +0 -0
  112. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/learnings_distil.py +0 -0
  113. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/learnings_query.py +0 -0
  114. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/lint_closing.py +0 -0
  115. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/lint_monitoring.py +0 -0
  116. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/lint_roadmap.py +0 -0
  117. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/notify.py +0 -0
  118. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/notify_escalation.py +0 -0
  119. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/notify_sla.py +0 -0
  120. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/plan_baseline.py +0 -0
  121. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/policy_proposals.py +0 -0
  122. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/policy_review.py +0 -0
  123. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/prerun.py +0 -0
  124. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/prerun_capture.py +0 -0
  125. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/promotion.py +0 -0
  126. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/rearm_migration.py +0 -0
  127. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/red_on_base.py +0 -0
  128. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/replay_spin.py +0 -0
  129. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/roadmap_archive.py +0 -0
  130. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/scaffold.py +0 -0
  131. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/triage.py +0 -0
  132. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/upgrade_merge_gate.py +0 -0
  133. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/validate_event.py +0 -0
  134. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/__init__.py +0 -0
  135. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/adapters.py +0 -0
  136. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/artifact.py +0 -0
  137. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/autofix.py +0 -0
  138. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/autofix_invoke.py +0 -0
  139. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/autofix_run.py +0 -0
  140. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/autofix_state.py +0 -0
  141. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/cli.py +0 -0
  142. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/diagnose_cli.py +0 -0
  143. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/diagnosis.py +0 -0
  144. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/fingerprint.py +0 -0
  145. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/issues.py +0 -0
  146. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/providers/__init__.py +0 -0
  147. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/providers/_azure_auth.py +0 -0
  148. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/providers/azure_app_insights.py +0 -0
  149. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/providers/azure_service_bus.py +0 -0
  150. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/redaction.py +0 -0
  151. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/schedule.py +0 -0
  152. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/dependency_links.txt +0 -0
  153. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/entry_points.txt +0 -0
  154. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/requires.txt +0 -0
  155. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/top_level.txt +0 -0
  156. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_abandon_feature_skill.py +0 -0
  157. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_abandoned_work_reported.py +0 -0
  158. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_abandoned_wu_strands_gate.py +0 -0
  159. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_adopt_feature.py +0 -0
  160. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_budget.py +0 -0
  161. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_bug_selection_dedup.py +0 -0
  162. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_default_features_root.py +0 -0
  163. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_driver_command.py +0 -0
  164. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_driver_invoke.py +0 -0
  165. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_driver_restart.py +0 -0
  166. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_escalation_on_issue.py +0 -0
  167. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_escalation_run_state.py +0 -0
  168. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_findings_seam.py +0 -0
  169. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_invoke_timeout.py +0 -0
  170. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_invoke_usage.py +0 -0
  171. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_item_worktree.py +0 -0
  172. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_lock.py +0 -0
  173. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_policy_key_ownership.py +0 -0
  174. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_policy_queue.py +0 -0
  175. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_policy_schema.py +0 -0
  176. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_policy_triage_dial.py +0 -0
  177. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_answers.py +0 -0
  178. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_bugs.py +0 -0
  179. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_feature.py +0 -0
  180. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_findings_autofix.py +0 -0
  181. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_findings_diagnose.py +0 -0
  182. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_isolation.py +0 -0
  183. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_triage.py +0 -0
  184. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_queue_read.py +0 -0
  185. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_relays_driver_output.py +0 -0
  186. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_repo_detect.py +0 -0
  187. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_run.py +0 -0
  188. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_run_progress.py +0 -0
  189. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_seam.py +0 -0
  190. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_snapshot_refresh.py +0 -0
  191. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_state.py +0 -0
  192. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_answer_escalation_skill.py +0 -0
  193. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_app_insights_adapters.py +0 -0
  194. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_archive_ref_reconciliation.py +0 -0
  195. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_eval.py +0 -0
  196. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_eval_lint_class.py +0 -0
  197. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_eval_wiring.py +0 -0
  198. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_gate_edits_uncommitted.py +0 -0
  199. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_sweep.py +0 -0
  200. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_sweep_gate.py +0 -0
  201. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_txn.py +0 -0
  202. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_wiring.py +0 -0
  203. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_artifact_redaction.py +0 -0
  204. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attempt_note_untracked_files.py +0 -0
  205. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attempt_outcome_contract.py +0 -0
  206. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attempt_outcome_emission.py +0 -0
  207. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attention_nonwriting_guard.py +0 -0
  208. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attention_silence_section.py +0 -0
  209. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attention_skill_structure.py +0 -0
  210. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attribution_halt_claims.py +0 -0
  211. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autoclose_deferral_visibility.py +0 -0
  212. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autoclose_gate_note.py +0 -0
  213. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autoclose_stub_states_what_passed.py +0 -0
  214. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_invoke.py +0 -0
  215. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_live.py +0 -0
  216. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_predicate.py +0 -0
  217. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_run.py +0 -0
  218. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_state.py +0 -0
  219. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync.py +0 -0
  220. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync_consent.py +0 -0
  221. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync_firstrun.py +0 -0
  222. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync_no_cwd_leak.py +0 -0
  223. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync_plugin.py +0 -0
  224. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_azure_credential_resolution.py +0 -0
  225. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_backend.py +0 -0
  226. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_escalation_message.py +0 -0
  227. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_persistence.py +0 -0
  228. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_probe.py +0 -0
  229. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_provenance.py +0 -0
  230. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_tree_hash_key.py +0 -0
  231. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bash_routing.py +0 -0
  232. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bats_suites_gated.py +0 -0
  233. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_binary_verdict.py +0 -0
  234. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_binding_block_advisory.py +0 -0
  235. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_binding_block_allocation.py +0 -0
  236. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_binding_block_budget.py +0 -0
  237. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_blind_run_is_not_drained.py +0 -0
  238. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bookkeeping_commit_crash_run.py +0 -0
  239. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
  240. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bookkeeping_no_verify.py +0 -0
  241. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_brief_covers_every_unit_escalation.py +0 -0
  242. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_ci_pending.py +0 -0
  243. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_guardrails.py +0 -0
  244. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_label_nonfatal.py +0 -0
  245. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_labels_registered.py +0 -0
  246. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_min_severity.py +0 -0
  247. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_policy_contract.py +0 -0
  248. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_pr_number_carried.py +0 -0
  249. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_preflight_and_dial.py +0 -0
  250. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_run.py +0 -0
  251. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_state.py +0 -0
  252. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
  253. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_test_paths.py +0 -0
  254. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_build_provenance.py +0 -0
  255. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_caller_check_ratchet.py +0 -0
  256. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changed_file_test_selection.py +0 -0
  257. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changelog_append_only.py +0 -0
  258. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changelog_collection.py +0 -0
  259. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changelog_release_wiring.py +0 -0
  260. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changelog_schema.py +0 -0
  261. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ci_conclusion_wait.py +0 -0
  262. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ci_runs_every_gate.py +0 -0
  263. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_claude_resolution.py +0 -0
  264. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_close_b_pending_learnings.py +0 -0
  265. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_close_records_feature_oracle.py +0 -0
  266. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_close_wu_self_reference.py +0 -0
  267. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_deliverable_guard.py +0 -0
  268. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_guard_contracts.py +0 -0
  269. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_guard_prediction.py +0 -0
  270. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_learnings_destination.py +0 -0
  271. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_requirements.py +0 -0
  272. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_coauthor_trailer_allowlist.py +0 -0
  273. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_conditional_reflection.py +0 -0
  274. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_console_encoding.py +0 -0
  275. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_convergent_iteration.py +0 -0
  276. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_convergent_wu_lint.py +0 -0
  277. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_correlation_id_override.py +0 -0
  278. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_correlation_id_two_surfaces.py +0 -0
  279. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_cost_lifetime.py +0 -0
  280. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_cost_tracking.py +0 -0
  281. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_criteria_per_gate_lint.py +0 -0
  282. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_criteria_state.py +0 -0
  283. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_criteria_worklist.py +0 -0
  284. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_decision_citation_lint.py +0 -0
  285. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_decision_followups_discharged.py +0 -0
  286. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_decision_override_lint.py +0 -0
  287. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_decisions_format.py +0 -0
  288. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_default_severity_aliases.py +0 -0
  289. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_degraded_oracle.py +0 -0
  290. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_deliverable_missing_note.py +0 -0
  291. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_deliverable_presence_gate.py +0 -0
  292. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_derive_agent_policy_review_mode.py +0 -0
  293. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_derive_agent_policy_skill.py +0 -0
  294. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_derive_monitoring_discovery.py +0 -0
  295. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_derive_monitoring_skill_registration.py +0 -0
  296. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_design_for_diagnosis_rule.py +0 -0
  297. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_deterministic_refusal_repeat.py +0 -0
  298. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_diagnose_headless.py +0 -0
  299. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_diagnose_issue_skill.py +0 -0
  300. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_diagnosis.py +0 -0
  301. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_diagnosis_roundtrip_live.py +0 -0
  302. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_dispatch_model_from_fix_scope.py +0 -0
  303. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_dispatch_skeleton.py +0 -0
  304. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_distilled_accept_step.py +0 -0
  305. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_doctor.py +0 -0
  306. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_doctor_command_preflight.py +0 -0
  307. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_done_feature_gates.py +0 -0
  308. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_draft_feature_answers_mode.py +0 -0
  309. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_answer_gate.py +0 -0
  310. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_invoke.py +0 -0
  311. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_question_issue.py +0 -0
  312. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_questions.py +0 -0
  313. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_reply_shape.py +0 -0
  314. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_edit_detection.py +0 -0
  315. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_event_registry_covers_emitters.py +0 -0
  316. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_integration.py +0 -0
  317. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_lock.py +0 -0
  318. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_module_surface.py +0 -0
  319. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_restart_halt_surfaced.py +0 -0
  320. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_restart_halt_wiring.py +0 -0
  321. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_restart_hold.py +0 -0
  322. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_staleness_gate_summary.py +0 -0
  323. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_staleness_warning.py +0 -0
  324. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_dry_run_no_branch_mutation.py +0 -0
  325. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_duration_tracking.py +0 -0
  326. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_empty_files_escalation.py +0 -0
  327. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ensure_feature_branch.py +0 -0
  328. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ensure_feature_branch_base.py +0 -0
  329. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_assignee_policy.py +0 -0
  330. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_contract.py +0 -0
  331. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_crash_containment.py +0 -0
  332. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_dedup_search.py +0 -0
  333. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_emit.py +0 -0
  334. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_event_gate_full_envelope.py +0 -0
  335. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_events_redaction.py +0 -0
  336. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_events_stats.py +0 -0
  337. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_extra_gates.py +0 -0
  338. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_failure_artifact_model.py +0 -0
  339. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_failure_signature_fail_prefix.py +0 -0
  340. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_failure_signature_skips_log_noise.py +0 -0
  341. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_branch_auto_sync.py +0 -0
  342. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_branch_squash_merge.py +0 -0
  343. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_branch_stale_base.py +0 -0
  344. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_id_resolution.py +0 -0
  345. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_oracle_e2e.py +0 -0
  346. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_provider_drafting_dispatch.py +0 -0
  347. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_review_accumulation.py +0 -0
  348. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_filelock_portable.py +0 -0
  349. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_files_changed_auto_repair.py +0 -0
  350. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_find_pr_no_search_index.py +0 -0
  351. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fingerprint.py +0 -0
  352. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fix_bug_diff_self_check.py +0 -0
  353. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fix_bug_headless.py +0 -0
  354. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fix_bug_reads_comments.py +0 -0
  355. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fold_contract_documented.py +0 -0
  356. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_force_full_close.py +0 -0
  357. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_frontmatter_scalar_quoting.py +0 -0
  358. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_broad_run.py +0 -0
  359. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_budget.py +0 -0
  360. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_budget_post_dispatch.py +0 -0
  361. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_commands_needs.py +0 -0
  362. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval.py +0 -0
  363. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval_calibration.py +0 -0
  364. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval_intermediate_wiring.py +0 -0
  365. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval_repo_flag.py +0 -0
  366. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval_terminal_wiring.py +0 -0
  367. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_report_verdict.py +0 -0
  368. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gh_backend.py +0 -0
  369. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gh_features.py +0 -0
  370. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_git_env_isolation.py +0 -0
  371. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gitleaks_pinning.py +0 -0
  372. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_groom_backlog_skill.py +0 -0
  373. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_guard_refusal_failure_class.py +0 -0
  374. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_guard_refusal_failure_excerpt.py +0 -0
  375. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_guard_repair_e2e.py +0 -0
  376. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_guard_repair_prompt.py +0 -0
  377. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_hashed_denylist.py +0 -0
  378. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_hashed_denylist_ci.py +0 -0
  379. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_heartbeat.py +0 -0
  380. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_heartbeat_adapter.py +0 -0
  381. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_human_output_rule.py +0 -0
  382. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_human_work_unit.py +0 -0
  383. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_hygiene_boundary_guidance.py +0 -0
  384. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_hyphenated_gate_name.py +0 -0
  385. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ignored_cleanup_before_probe.py +0 -0
  386. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_init_integration.py +0 -0
  387. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_installed_copy_driver_e2e.py +0 -0
  388. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_interpreter_normalization.py +0 -0
  389. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_close_path.py +0 -0
  390. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_cost.py +0 -0
  391. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_cost_fold_committed.py +0 -0
  392. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_module.py +0 -0
  393. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_path_registry.py +0 -0
  394. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_terminal_flip_state.py +0 -0
  395. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judged_event_points_at_findings.py +0 -0
  396. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_label_description_length.py +0 -0
  397. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_label_provisioning_runner_contract.py +0 -0
  398. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_label_registry.py +0 -0
  399. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_label_registry_covers_consumers.py +0 -0
  400. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_language_aware_narrow_selection.py +0 -0
  401. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lazy_baseline_e2e.py +0 -0
  402. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_leak_findings_redaction.py +0 -0
  403. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_leak_scan.py +0 -0
  404. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_leak_scan_content.py +0 -0
  405. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_curate_vendored_promote.py +0 -0
  406. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_distil_cli.py +0 -0
  407. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_query.py +0 -0
  408. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_staging.py +0 -0
  409. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_suggest_signature_filter.py +0 -0
  410. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_weights.py +0 -0
  411. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_legacy_4wu_terminal_flips.py +0 -0
  412. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lifecycle_integration.py +0 -0
  413. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lifetime_accounting.py +0 -0
  414. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_ac_observable.py +0 -0
  415. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_bare_produces_path.py +0 -0
  416. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_boundary_consistency.py +0 -0
  417. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_boundary_extraction.py +0 -0
  418. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_close_intermediate.py +0 -0
  419. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_close_verdict_not_predecided.py +0 -0
  420. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_close_wu.py +0 -0
  421. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_closing.py +0 -0
  422. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_closing_criteria.py +0 -0
  423. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_closing_criteria_pristine.py +0 -0
  424. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_correlation_id.py +0 -0
  425. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
  426. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_covers_load_wu_invariants.py +0 -0
  427. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_feature_oracle_declared.py +0 -0
  428. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_monitoring.py +0 -0
  429. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_oracle_env.py +0 -0
  430. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_contract_fields.py +0 -0
  431. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_errors.py +0 -0
  432. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_next_draft.py +0 -0
  433. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_relative_import.py +0 -0
  434. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_verdict_exempt.py +0 -0
  435. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_planning_sections.py +0 -0
  436. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_produces_driver_helper.py +0 -0
  437. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_produces_satisfiability.py +0 -0
  438. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_roadmap.py +0 -0
  439. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_sections.py +0 -0
  440. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_task_graph_yaml_selection.py +0 -0
  441. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_verification_reference.py +0 -0
  442. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_live_tests_opt_in.py +0 -0
  443. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_load_bearing_close_lint.py +0 -0
  444. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_attempt_evidence.py +0 -0
  445. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_caveman_preamble.py +0 -0
  446. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_criteria_skeleton.py +0 -0
  447. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_criteria_survival.py +0 -0
  448. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_defaults_by_type.py +0 -0
  449. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_effort.py +0 -0
  450. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_failure_note_cap.py +0 -0
  451. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_files_changed_guard.py +0 -0
  452. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_gate_budget.py +0 -0
  453. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_gate_needs.py +0 -0
  454. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_model_alias.py +0 -0
  455. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_orchestration.py +0 -0
  456. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_post_pass_invariant.py +0 -0
  457. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_reset_preserving_events.py +0 -0
  458. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_smoke_runner.py +0 -0
  459. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_unsandboxed.py +0 -0
  460. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_worklist_injection.py +0 -0
  461. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_zero_token_guard.py +0 -0
  462. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_make_repo_gpgsign_isolation.py +0 -0
  463. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_marker_dual_shape.py +0 -0
  464. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_maven_failure_excerpt.py +0 -0
  465. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_max_attempts_configurable.py +0 -0
  466. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_max_open_prs.py +0 -0
  467. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_migrate_legacy.py +0 -0
  468. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_miniyaml_equivalence.py +0 -0
  469. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_miniyaml_negative.py +0 -0
  470. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitor_cli.py +0 -0
  471. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitor_issue_lifecycle.py +0 -0
  472. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitor_runner_surfaces.py +0 -0
  473. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
  474. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_cron_dialect.py +0 -0
  475. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_example.py +0 -0
  476. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_fenced_blocks.py +0 -0
  477. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_seed.py +0 -0
  478. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_narrow_fallback_warning.py +0 -0
  479. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_needs_decision_outcome.py +0 -0
  480. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_no_pytest_subprocess.py +0 -0
  481. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_notify.py +0 -0
  482. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_notify_escalation.py +0 -0
  483. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_notify_sla.py +0 -0
  484. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_operator_escalation_rule.py +0 -0
  485. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_oracle_set_declared.py +0 -0
  486. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_oracle_unrunnable_attribution.py +0 -0
  487. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_per_run_item_cap_disclosure.py +0 -0
  488. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pick_feature_skill.py +0 -0
  489. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pin_honesty_and_integrity.py +0 -0
  490. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pin_marker_not_inherited.py +0 -0
  491. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pin_marker_spawn_sites.py +0 -0
  492. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_plan_baseline.py +0 -0
  493. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_planned_cost_lint.py +0 -0
  494. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_planning_cost_floor.py +0 -0
  495. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_plugin_prose_cross_refs.py +0 -0
  496. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_plugin_qualified_dispatch.py +0 -0
  497. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_policy_budgets_applied.py +0 -0
  498. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_policy_proposals.py +0 -0
  499. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_policy_review.py +0 -0
  500. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pr_checks_json_field.py +0 -0
  501. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pr_reference_in_title.py +0 -0
  502. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
  503. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prep_halt_operator_surface.py +0 -0
  504. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prepare_feature.py +0 -0
  505. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prepare_scaffold_sync.py +0 -0
  506. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prerun_capture.py +0 -0
  507. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prerun_oracles.py +0 -0
  508. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prerun_wiring.py +0 -0
  509. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produced_document_verdict_guard.py +0 -0
  510. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_bracket_literal.py +0 -0
  511. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_bracket_wildcard.py +0 -0
  512. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_field.py +0 -0
  513. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_in_diff.py +0 -0
  514. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_justification.py +0 -0
  515. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_recursive_glob.py +0 -0
  516. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_semantics_unified.py +0 -0
  517. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_shape.py +0 -0
  518. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_progress_forward_note.py +0 -0
  519. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_progress_lines_end_to_end.py +0 -0
  520. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_promotion_ledger.py +0 -0
  521. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_provider_escalation_traces.py +0 -0
  522. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_provision_labels.py +0 -0
  523. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_queue_stalled_adapter.py +0 -0
  524. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_rearm_clears_stale_criteria_state.py +0 -0
  525. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_rearm_fold_marker.py +0 -0
  526. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_rearm_migration.py +0 -0
  527. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_red_baseline_never_reused.py +0 -0
  528. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_red_on_base_guardrail.py +0 -0
  529. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_red_on_base_probe.py +0 -0
  530. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_redaction_windows_home.py +0 -0
  531. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_reflection_required_signals.py +0 -0
  532. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_end_to_end.py +0 -0
  533. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_event_emission.py +0 -0
  534. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_note_collision.py +0 -0
  535. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_trigger.py +0 -0
  536. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_turn_contract.py +0 -0
  537. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replay_spin.py +0 -0
  538. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_required_checks.py +0 -0
  539. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_resolve_base.py +0 -0
  540. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_restart_cap_counts_progress.py +0 -0
  541. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_result_block.py +0 -0
  542. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_result_block_audience.py +0 -0
  543. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_resume_command_build.py +0 -0
  544. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_retain_on_guard_refusal_docs.py +0 -0
  545. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_add_skill.py +0 -0
  546. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_archive_cli.py +0 -0
  547. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_archive_shim.py +0 -0
  548. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_archive_skill.py +0 -0
  549. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_archive_skill_delegates.py +0 -0
  550. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_link_gate.py +0 -0
  551. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_row_parser.py +0 -0
  552. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ruff_verdict_lines.py +0 -0
  553. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_rule_import_convergence.py +0 -0
  554. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_run_level_failure_breaker.py +0 -0
  555. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_data_in_sync.py +0 -0
  556. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_doc_hygiene.py +0 -0
  557. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_docs.py +0 -0
  558. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_init.py +0 -0
  559. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_label_provisioning.py +0 -0
  560. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_manifest.py +0 -0
  561. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_resources.py +0 -0
  562. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_seed_sanity.py +0 -0
  563. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_skew_halts.py +0 -0
  564. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_upgrade.py +0 -0
  565. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_wiring.py +0 -0
  566. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_schedule_dialect.py +0 -0
  567. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_seed_documents_prerun_keys.py +0 -0
  568. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_service_bus_dlq_adapter.py +0 -0
  569. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_session_env_preflight.py +0 -0
  570. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_aliases.py +0 -0
  571. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_apply.py +0 -0
  572. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_end_to_end.py +0 -0
  573. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_limit.py +0 -0
  574. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_marker.py +0 -0
  575. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_run.py +0 -0
  576. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_label_projection.py +0 -0
  577. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_reconciliation.py +0 -0
  578. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_rubric.py +0 -0
  579. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_shipped_templates_parse.py +0 -0
  580. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_skill_discovery_links.py +0 -0
  581. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_skills_vendored_in_sync.py +0 -0
  582. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_spec_work_unit_rules.py +0 -0
  583. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_spinning_rearm_gate.py +0 -0
  584. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_spinout_brief_end_to_end.py +0 -0
  585. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_spinout_brief_replan_option.py +0 -0
  586. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_squash_commit_hook_crash.py +0 -0
  587. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_stop_rationale_captured.py +0 -0
  588. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_stranded_halt_cause.py +0 -0
  589. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_surefire_run_level_signature.py +0 -0
  590. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_surefire_verdict_lines.py +0 -0
  591. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_template_closing_shapes.py +0 -0
  592. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_terminal_flip_ownership.py +0 -0
  593. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_terminal_flips.py +0 -0
  594. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_terminal_gate_message.py +0 -0
  595. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_tiered_verification_e2e.py +0 -0
  596. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_timeout_kill_portable.py +0 -0
  597. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage.py +0 -0
  598. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_apply.py +0 -0
  599. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_projects_severity_label.py +0 -0
  600. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_severity_classify.py +0 -0
  601. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_severity_end_to_end.py +0 -0
  602. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_severity_write.py +0 -0
  603. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_skill_contract.py +0 -0
  604. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_skips_agent_escalations.py +0 -0
  605. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_tsc_verdict_lines.py +0 -0
  606. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_umbrella_version_resolution.py +0 -0
  607. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_unterminated_frontmatter.py +0 -0
  608. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_untracked_feature_folder.py +0 -0
  609. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_untracked_file_absorption.py +0 -0
  610. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_upgrade_integration.py +0 -0
  611. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_upgrade_merge_gate.py +0 -0
  612. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_validate_event.py +0 -0
  613. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_validate_event_driver_types.py +0 -0
  614. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_verdict_coupling.py +0 -0
  615. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_verify_empty_gate_set.py +0 -0
  616. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_version_consistency.py +0 -0
  617. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_version_skew.py +0 -0
  618. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_windows_gate_exec.py +0 -0
  619. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_worktree_restore.py +0 -0
  620. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_wu_execution_metadata.py +0 -0
  621. {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_wu_template_renders_lintable.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfuse-loop
3
- Version: 0.24.0
3
+ Version: 0.25.0
4
4
  Summary: Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology.
5
5
  Author: Specfuse contributors
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specfuse-loop"
7
- version = "0.24.0"
7
+ version = "0.25.0"
8
8
  description = "Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1 @@
1
+ 0.25.0
@@ -454,6 +454,27 @@ separately carry `auto_repaired_files_changed` in `extras`: the list of
454
454
  declared-but-unchanged `files_changed` paths the driver dropped on the
455
455
  WU's behalf rather than failing the attempt over.
456
456
 
457
+ **Dispatch without the skills index (#3423).** A dispatched session runs
458
+ `claude -p --disable-slash-commands` by default: a work unit invokes no
459
+ skill, and the project's skills index (34 skills, 1,534 words of descriptions
460
+ in the loop repository) is fixed context carried in every turn's cache read.
461
+ `defaults.dispatch_skills: true` in `verification.yml` restores the index for
462
+ a project whose units do call `/skill-name` in-session.
463
+
464
+ **The post-merge checklist travels with the archive (#3424).** A `met`
465
+ terminal close no longer files PLAN.md's `## Post-merge checklist` as a
466
+ `specfuse:post-merge` issue (ten filed across two repositories, eight never
467
+ actioned); `auto_archive_feature` appends it under the feature's archived
468
+ detail section in `roadmap-archive.md`. `defaults.post_merge_issue: true` in
469
+ `verification.yml` restores the issue.
470
+
471
+ **Closing sessions run on sonnet (#3425).** `close`, `close-intermediate`
472
+ and `plan-next` default to `sonnet` at effort `high`, the same model as the
473
+ judge that checks them (lower-only, about $0.46 per close). Opus was 56% of
474
+ all spend while implementation ran on sonnet. A unit's own
475
+ `model:` still overrides the default, and every `judged` event carries
476
+ `close_model` so judge agreement can be read per close model.
477
+
457
478
  Retention interacts with spinning detection, not around it:
458
479
  `detect_deterministic_refusal_repeat` (#1415) escalates a WU to
459
480
  `blocked_human` when two consecutive attempts emit an identical refusal
@@ -579,7 +600,7 @@ completion.
579
600
 
580
601
  Closing ceremony cost should scale with feature size. A feature whose
581
602
  **planned substantive** WU count (types `implementation`, `qa_authoring`,
582
- `qa_execution`, `qa_curation`) is **≤ 8** drafts as a **single gate** with
603
+ `qa_execution`, `qa_curation`) is **≤ 12** drafts as a **single gate** with
583
604
  a **single terminal `close` WU** — no `close-intermediate`, no `plan-next`.
584
605
  This is the proportional shape: small features do not pay multi-WU closing
585
606
  overhead sized for large ones.
@@ -597,6 +618,13 @@ reflective session. Ceremony proportionality trades reflection only on
597
618
  features that stay small **and** on-plan. The `gate_eval.py` predicate is
598
619
  the safety net; this rule does not replace it.
599
620
 
621
+ The line moved from 8 to 12 on 2026-09-26 (#3426): post-review features
622
+ average 10.7 substantive units, every extra gate costs a `plan-next` plus a
623
+ `close-intermediate` and an `awaiting_review` wait, and the arm predicate
624
+ would have armed only 18 of 74 gate boundaries it evaluated — the wait was a
625
+ human redraft, not a review. A feature goes multi-gate when a human decision
626
+ sits between its gates, not because it is large.
627
+
600
628
  **Reflective prose is conditional too (FEAT-2026-0106).** The roadmap once
601
629
  asked for a retrospective "only on `not_met` or on request" — superseded,
602
630
  for an ordering reason: the close writes `RETROSPECTIVE.md` before the judge
@@ -118,9 +118,22 @@
118
118
  # # attempt repairs the retained tree in place
119
119
  # # instead of re-authoring from scratch. Set to
120
120
  # # false to restore the pre-0.18 discard behaviour.
121
+ # dispatch_skills: false # whether a dispatched session loads the
122
+ # # project's skills index. Defaults to false:
123
+ # # a work unit invokes no skill, and the index
124
+ # # is fixed context paid on every turn (#3423).
125
+ # # Set true for a project whose units call
126
+ # # `/skill-name` in-session.
127
+ # post_merge_issue: false # whether a `met` terminal close files PLAN.md's
128
+ # # `## Post-merge checklist` as a tracked issue.
129
+ # # Defaults to false (#3424): the checklist is
130
+ # # appended under the feature's archived detail
131
+ # # section in roadmap-archive.md instead.
121
132
  # defaults:
122
133
  # max_attempts: 3
123
134
  # retain_on_guard_refusal: true
135
+ # dispatch_skills: false
136
+ # post_merge_issue: false
124
137
  #
125
138
  # The re-plan-after-two-failures behaviour (FEAT-2026-0104) reads this same
126
139
  # `max_attempts` resolution and adds no config key of its own — a unit's
@@ -1041,7 +1041,7 @@ def check_produces_satisfiability(feature_dir: Path, gates: list) -> None:
1041
1041
 
1042
1042
  # Ceremony-proportionality threshold (docs/methodology.md §6): one fact, one
1043
1043
  # home. Referenced, not redefined, in the draft-feature skill.
1044
- GATE_PROPORTIONALITY_THRESHOLD = 8
1044
+ GATE_PROPORTIONALITY_THRESHOLD = 12 # was 8 until #3426
1045
1045
  GATE_PROPORTIONALITY_SUBSTANTIVE_TYPES = frozenset(
1046
1046
  {"implementation", "qa_authoring", "qa_execution", "qa_curation"}
1047
1047
  )
@@ -42,6 +42,7 @@ from __future__ import annotations
42
42
  import argparse
43
43
  import datetime as dt
44
44
  import fnmatch
45
+ import functools
45
46
  import glob
46
47
  import hashlib
47
48
  import inspect
@@ -125,7 +126,7 @@ SPECFUSE_DIR = Path(".specfuse")
125
126
  REPO_ROOT = SPECFUSE_DIR.parent
126
127
  FEATURES_DIR = SPECFUSE_DIR / "features"
127
128
  VERIFICATION_PATH = SPECFUSE_DIR / "verification.yml"
128
- DRIVER_VERSION = "0.24.0"
129
+ DRIVER_VERSION = "0.25.0"
129
130
  # Oldest scaffold layout this driver can drive. init.sh stamps the scaffold's own
130
131
  # version into `.specfuse/VERSION`; check_scaffold_version() fails loud at startup if
131
132
  # the consumer's scaffold is older than this, pointing at `specfuse upgrade`. Bump
@@ -635,6 +636,66 @@ def resolve_retain_on_guard_refusal(verification_cfg: dict) -> bool:
635
636
  """
636
637
  project = (verification_cfg or {}).get("defaults") or {}
637
638
  return bool(project.get("retain_on_guard_refusal", True))
639
+
640
+
641
+ def resolve_dispatch_skills(verification_cfg: dict) -> bool:
642
+ """Whether a dispatched session gets the project's skills index (#3423).
643
+
644
+ Reads `defaults.dispatch_skills` from verification.yml — the same
645
+ `defaults` block `resolve_max_attempts` reads. Defaults to False: a
646
+ dispatched work unit invokes no skill (the narrow-tier instructions are in
647
+ the preamble and unit bodies name skill files by path, for reading), so
648
+ the index — 34 skills and 1,534 words of descriptions in this repository —
649
+ is fixed context carried in every turn's cache read for nothing. Set true
650
+ for a project whose units do invoke `/skill-name` in-session.
651
+ """
652
+ project = (verification_cfg or {}).get("defaults") or {}
653
+ return bool(project.get("dispatch_skills", False))
654
+
655
+
656
+ @functools.lru_cache(maxsize=None)
657
+ def claude_supports_flag(flag: str) -> bool:
658
+ """Whether the installed Claude Code CLI accepts *flag* (#3432).
659
+
660
+ Probed once per driver run from `claude --help`. A CLI that cannot be run
661
+ reads as not supporting anything: the dispatch then omits the flag and
662
+ fails on its own terms, not on an unknown option.
663
+ """
664
+ try:
665
+ proc = subprocess.run(
666
+ resolve_claude_cmd(["claude", "--help"]), capture_output=True,
667
+ text=True, check=False, timeout=30,
668
+ env=child_env_without_pin_marker(),
669
+ )
670
+ except Exception: # noqa: BLE001 - a missing or broken CLI is "no"
671
+ return False
672
+ out = "".join(s for s in (proc.stdout, proc.stderr) if isinstance(s, str))
673
+ return flag in out
674
+
675
+
676
+ _FLAG_WARNED: set[str] = set()
677
+
678
+
679
+ def _warn_flag_unsupported(flag: str, consequence: str) -> None:
680
+ if flag in _FLAG_WARNED:
681
+ return
682
+ _FLAG_WARNED.add(flag)
683
+ print(f" WARN: this Claude Code CLI does not accept {flag}; {consequence}")
684
+
685
+
686
+ def resolve_post_merge_issue(verification_cfg: dict) -> bool:
687
+ """Whether a `met` terminal close files the post-merge checklist as an issue (#3424).
688
+
689
+ Reads `defaults.post_merge_issue` from verification.yml. Defaults to False:
690
+ across this repository and its heaviest consumer, ten such issues were
691
+ filed and eight were never actioned — the checklist is a measurement note
692
+ for the operator, not a work item. The record survives instead under the
693
+ feature's archived detail section (`auto_archive_feature`).
694
+ """
695
+ project = (verification_cfg or {}).get("defaults") or {}
696
+ return bool(project.get("post_merge_issue", False))
697
+
698
+
638
699
  # Per-gate-command wall-clock ceiling. A gate that exceeds it is killed and the gate
639
700
  # FAILS (not hangs) — so a deadlocked command (e.g. a test blocked on input()) can't
640
701
  # stall the whole driver indefinitely. Generous vs real suites (this repo's is ~20s).
@@ -657,9 +718,16 @@ MODEL_BY_TYPE = {
657
718
  "retrospective": "sonnet",
658
719
  "lessons": "sonnet",
659
720
  "docs": "sonnet",
660
- "plan-next": "opus",
661
- "close": "opus",
662
- "close-intermediate": "opus",
721
+ # #3425: closing sessions on sonnet. Opus was 56% of all spend while
722
+ # implementation ran on sonnet; the judge (JUDGE_MODEL, itself sonnet,
723
+ # lower-only, ~$0.46 per close) is the independent check on a close's
724
+ # measurements and lowered 9 of 54 verdicts correctly, so the close does
725
+ # not need a bigger model than the session that checks it. A unit's own
726
+ # `model:` still overrides; `judged` events carry `close_model` so
727
+ # agreement can be split by model.
728
+ "plan-next": "sonnet",
729
+ "close": "sonnet",
730
+ "close-intermediate": "sonnet",
663
731
  }
664
732
  EFFORT_BY_TYPE = {
665
733
  "implementation": "medium",
@@ -4439,8 +4507,9 @@ def squash_commit(
4439
4507
  # --------------------------------------------------------------------------- #
4440
4508
 
4441
4509
  PROMPT_PREAMBLE = """\
4442
- You are executing a single Specfuse work unit. Read .specfuse/rules/ in full before \
4443
- acting; they are binding. Do NOT run any git command — the driver owns all commits \
4510
+ You are executing a single Specfuse work unit. The binding rules are already in \
4511
+ your context through .claude/CLAUDE.md; read a further file under .specfuse/rules/ \
4512
+ only when your unit body names it. Do NOT run any git command — the driver owns all commits \
4444
4513
  and bookkeeping. Edit files only. Verification is tiered: before you report, run \
4445
4514
  only the per-attempt (narrow) tier yourself — your unit type's gate set in \
4446
4515
  .specfuse/verification.yml minus every gate declaring `tier: broad`, with the \
@@ -4790,7 +4859,8 @@ def format_reverification_worklist(wu: WorkUnit, feature_dir: Path) -> str:
4790
4859
 
4791
4860
 
4792
4861
  def dispatch(wu: WorkUnit, failure_note: str | None,
4793
- cost_tracking: bool = True) -> tuple[str, dict | None]:
4862
+ cost_tracking: bool = True, *,
4863
+ dispatch_skills: bool | None = None) -> tuple[str, dict | None]:
4794
4864
  """Run a fresh agent session for this WU.
4795
4865
 
4796
4866
  When `cost_tracking` is True (default), requests JSON output from
@@ -4810,6 +4880,24 @@ def dispatch(wu: WorkUnit, failure_note: str | None,
4810
4880
  cmd = [p.replace("{model}", wu.model).replace("{effort}", wu.effort)
4811
4881
  for p in CLAUDE_CMD]
4812
4882
  cmd = resolve_claude_cmd(cmd)
4883
+ if dispatch_skills is None:
4884
+ # Resolved here rather than threaded through execute_unit_attempt:
4885
+ # every test fake of dispatch() takes the three positional arguments
4886
+ # and nothing else, and the yaml read is nothing next to a session.
4887
+ try:
4888
+ dispatch_skills = resolve_dispatch_skills(load_verification())
4889
+ except Exception: # noqa: BLE001 - an unreadable config keeps the default
4890
+ dispatch_skills = False
4891
+ if not dispatch_skills:
4892
+ # #3423: a dispatched unit invokes no skill, so the skills index is
4893
+ # fixed context paid on every turn. `defaults.dispatch_skills: true`
4894
+ # in verification.yml restores it (resolve_dispatch_skills).
4895
+ if claude_supports_flag("--disable-slash-commands"):
4896
+ cmd.insert(2, "--disable-slash-commands")
4897
+ else:
4898
+ _warn_flag_unsupported(
4899
+ "--disable-slash-commands",
4900
+ "the skills index stays in the session prompt (#3432)")
4813
4901
  if wu.unsandboxed:
4814
4902
  # Per-WU sandbox-escape. Audited via the unsandboxed_dispatch event
4815
4903
  # emitted in run()'s attempt loop; rationale lives in WU frontmatter.
@@ -7368,6 +7456,19 @@ def _reconcile_moved_section(
7368
7456
  return section_text
7369
7457
 
7370
7458
 
7459
+ def _post_merge_checklist_for_archive(feature_id: str, repo_root: Path) -> str | None:
7460
+ """PLAN.md's `## Post-merge checklist` body for *feature_id*, or None (#3424)."""
7461
+ features = repo_root / ".specfuse" / "features"
7462
+ for plan in sorted(features.glob(f"{feature_id}-*/PLAN.md")):
7463
+ try:
7464
+ _, body = read_frontmatter(plan)
7465
+ except Exception: # noqa: BLE001 - archive must never fail on a bad PLAN
7466
+ return None
7467
+ section = find_post_merge_checklist_section(body)
7468
+ return section.strip("\n") + "\n" if section else None
7469
+ return None
7470
+
7471
+
7371
7472
  def auto_archive_feature(feature_id: str, repo_root: Path) -> str:
7372
7473
  """Re-implement roadmap-archive single-feature algorithm (Steps 1–6) in-driver.
7373
7474
 
@@ -7480,6 +7581,13 @@ def auto_archive_feature(feature_id: str, repo_root: Path) -> str:
7480
7581
  f"](roadmap.md#{feat_id_lower})", f"](#{feat_id_lower})"
7481
7582
  )
7482
7583
 
7584
+ # #3424: the feature's post-merge checklist travels with the archived
7585
+ # detail section instead of becoming an issue nobody actions. Read from
7586
+ # the feature folder's PLAN.md when one exists; a row-only feature has none.
7587
+ checklist = _post_merge_checklist_for_archive(feature_id, repo_root)
7588
+ if checklist and "**Post-merge checklist.**" not in section_text:
7589
+ section_text = section_text.rstrip("\n") + "\n\n**Post-merge checklist.**\n\n" + checklist
7590
+
7483
7591
  marker_end = archive_text.index(marker) + len(marker)
7484
7592
  new_archive = archive_text[:marker_end] + f"\n{anchor}\n{section_text}" + archive_text[marker_end:]
7485
7593
  archive_path.write_text(new_archive)
@@ -8833,6 +8941,7 @@ def record_tracked_issue(
8833
8941
 
8834
8942
  def file_followup_issues(
8835
8943
  feature_dir: Path, repo_root: Path, runner=None, *, commit: bool | None = None,
8944
+ post_merge_issue: bool | None = None,
8836
8945
  ) -> dict:
8837
8946
  """File one tracked GitHub issue per FOLLOW-UPS.md entry, after a close's squash.
8838
8947
 
@@ -8883,7 +8992,13 @@ def file_followup_issues(
8883
8992
  followups_path,
8884
8993
  ))
8885
8994
 
8886
- if plan_fm.get("verdict") == "met" or plan_fm.get("status") == "done":
8995
+ if post_merge_issue is None:
8996
+ post_merge_issue = resolve_post_merge_issue(load_verification())
8997
+ if post_merge_issue and (
8998
+ plan_fm.get("verdict") == "met" or plan_fm.get("status") == "done"
8999
+ ):
9000
+ # #3424: off by default — the checklist lands under the archived
9001
+ # detail section instead (auto_archive_feature).
8887
9002
  section = find_post_merge_checklist_section(plan_body)
8888
9003
  if section:
8889
9004
  entries.append((
@@ -9588,6 +9703,7 @@ def judge_close(
9588
9703
  payload: dict = {
9589
9704
  "gate": gate_number,
9590
9705
  "close_verdict": close_verdict,
9706
+ "close_model": getattr(wu, "model", None),
9591
9707
  "judge_verdict": None,
9592
9708
  "verdict": close_verdict,
9593
9709
  "lowered": False,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfuse-loop
3
- Version: 0.24.0
3
+ Version: 0.25.0
4
4
  Summary: Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology.
5
5
  Author: Specfuse contributors
6
6
  License: Apache-2.0
@@ -259,6 +259,7 @@ tests/test_closing_guard_contracts.py
259
259
  tests/test_closing_guard_prediction.py
260
260
  tests/test_closing_learnings_destination.py
261
261
  tests/test_closing_requirements.py
262
+ tests/test_closing_sessions_on_sonnet.py
262
263
  tests/test_coauthor_trailer_allowlist.py
263
264
  tests/test_conditional_reflection.py
264
265
  tests/test_console_encoding.py
@@ -290,7 +291,9 @@ tests/test_diagnose_issue_skill.py
290
291
  tests/test_diagnosis.py
291
292
  tests/test_diagnosis_roundtrip_live.py
292
293
  tests/test_dispatch_model_from_fix_scope.py
294
+ tests/test_dispatch_preamble_rules_pointer.py
293
295
  tests/test_dispatch_skeleton.py
296
+ tests/test_dispatch_skills_index.py
294
297
  tests/test_distilled_accept_step.py
295
298
  tests/test_doctor.py
296
299
  tests/test_doctor_command_preflight.py
@@ -0,0 +1,28 @@
1
+ # Copyright 2026 Specfuse Contributors
2
+ # Licensed under the Apache License, Version 2.0. See LICENSE.
3
+ """Closing sessions default to sonnet, like the judge that checks them (#3425)."""
4
+ import unittest
5
+
6
+ from tests._loop_loader import load_loop
7
+
8
+ loop = load_loop()
9
+
10
+
11
+ class ClosingTypesDefaultToSonnet(unittest.TestCase):
12
+ def test_the_three_closing_types_default_to_sonnet_high(self):
13
+ for wu_type in ("close", "close-intermediate", "plan-next"):
14
+ self.assertEqual(loop.MODEL_BY_TYPE[wu_type], "sonnet", wu_type)
15
+ self.assertEqual(loop.EFFORT_BY_TYPE[wu_type], "high", wu_type)
16
+
17
+ def test_implementation_default_is_unchanged(self):
18
+ self.assertEqual(loop.MODEL_BY_TYPE["implementation"], "sonnet")
19
+ self.assertEqual(loop.EFFORT_BY_TYPE["implementation"], "medium")
20
+
21
+ def test_the_judge_model_is_its_own_constant(self):
22
+ # The judge already ran on sonnet before this change; the close no
23
+ # longer needs a bigger model than the session that checks it.
24
+ self.assertEqual(loop.JUDGE_MODEL, "sonnet")
25
+
26
+
27
+ if __name__ == "__main__":
28
+ unittest.main()
@@ -0,0 +1,32 @@
1
+ # Copyright 2026 Specfuse Contributors
2
+ # Licensed under the Apache License, Version 2.0. See LICENSE.
3
+ """The dispatch preamble points at the injected binding block instead of
4
+ telling every session to read `.specfuse/rules/` in full (#3422).
5
+
6
+ Measured 2026-09-26: the "read in full" sentence cost every dispatched session
7
+ ten files and 11,573 words of tool reads on top of the 2,461 words CLAUDE.md
8
+ already injects, and those tokens rode along in every later turn's cache read.
9
+ """
10
+ import unittest
11
+
12
+ from tests._loop_loader import load_loop
13
+
14
+ loop = load_loop()
15
+
16
+
17
+ class PreamblePointsAtTheBindingBlock(unittest.TestCase):
18
+ def test_no_session_is_told_to_read_the_rules_in_full(self):
19
+ self.assertNotIn("in full", loop.PROMPT_PREAMBLE)
20
+
21
+ def test_preamble_names_the_injected_binding_block(self):
22
+ self.assertIn(".claude/CLAUDE.md", loop.PROMPT_PREAMBLE)
23
+ self.assertIn("only when your unit body names it", loop.PROMPT_PREAMBLE)
24
+
25
+ def test_the_other_obligations_survive(self):
26
+ for phrase in ("Do NOT run any git command", "narrow", "RESULT block",
27
+ ".specfuse/rules/result-contract.md"):
28
+ self.assertIn(phrase, loop.PROMPT_PREAMBLE)
29
+
30
+
31
+ if __name__ == "__main__":
32
+ unittest.main()
@@ -0,0 +1,105 @@
1
+ # Copyright 2026 Specfuse Contributors
2
+ # Licensed under the Apache License, Version 2.0. See LICENSE.
3
+ """A dispatched session does not load the skills index unless the project asks
4
+ for it (#3423).
5
+
6
+ `dispatch()` passes `--disable-slash-commands` by default; the resolver reads
7
+ `defaults.dispatch_skills` from verification.yml and `execute_unit_attempt`
8
+ threads it through.
9
+ """
10
+ import contextlib
11
+ import io
12
+ import unittest
13
+ from pathlib import Path
14
+ from unittest import mock
15
+
16
+ from tests._loop_loader import load_loop
17
+
18
+ loop = load_loop()
19
+
20
+
21
+ def _wu(**over):
22
+ base = dict(
23
+ wu_id="FEAT-2026-9999/T01", file=Path("WU-T01.md"), depends_on=[],
24
+ type="implementation", model="claude-sonnet-4-6", effort="medium",
25
+ status="pending", attempts=0, title="t", body="body",
26
+ )
27
+ base.update(over)
28
+ return loop.WorkUnit(**base)
29
+
30
+
31
+ class ResolverReadsTheDefaultsBlock(unittest.TestCase):
32
+ def test_absent_means_no_skills(self):
33
+ self.assertFalse(loop.resolve_dispatch_skills({}))
34
+ self.assertFalse(loop.resolve_dispatch_skills({"defaults": {}}))
35
+
36
+ def test_true_restores_the_index(self):
37
+ self.assertTrue(loop.resolve_dispatch_skills({"defaults": {"dispatch_skills": True}}))
38
+
39
+
40
+ class DispatchCmdCarriesTheFlag(unittest.TestCase):
41
+ def _cmd(self, supported: bool = True, **kw):
42
+ fake_proc = mock.MagicMock(stdout="ignored", returncode=0)
43
+ with mock.patch.object(loop, "claude_supports_flag", return_value=supported), \
44
+ mock.patch.object(loop.subprocess, "run", return_value=fake_proc) as run:
45
+ loop.dispatch(_wu(), failure_note=None, cost_tracking=False, **kw)
46
+ return run.call_args[0][0]
47
+
48
+ def test_unsupported_cli_omits_the_flag_and_warns_once(self):
49
+ # #3432: an older CLI must not fail every dispatch on an unknown option.
50
+ loop._FLAG_WARNED.discard("--disable-slash-commands")
51
+ buf = io.StringIO()
52
+ with contextlib.redirect_stdout(buf):
53
+ first = self._cmd(supported=False)
54
+ second = self._cmd(supported=False)
55
+ self.assertNotIn("--disable-slash-commands", first)
56
+ self.assertNotIn("--disable-slash-commands", second)
57
+ self.assertEqual(buf.getvalue().count("does not accept --disable-slash-commands"), 1)
58
+
59
+ def test_default_disables_slash_commands_after_dash_p(self):
60
+ cmd = self._cmd()
61
+ self.assertEqual(cmd[:2], ["claude", "-p"])
62
+ self.assertIn("--disable-slash-commands", cmd)
63
+ self.assertLess(cmd.index("--disable-slash-commands"), cmd.index("--model"))
64
+
65
+ def test_opt_in_keeps_the_index(self):
66
+ self.assertNotIn("--disable-slash-commands", self._cmd(dispatch_skills=True))
67
+
68
+ def test_composes_with_the_sandbox_escape(self):
69
+ fake_proc = mock.MagicMock(stdout="ignored", returncode=0)
70
+ wu = _wu(unsandboxed=True, unsandboxed_rationale="needs gh")
71
+ with mock.patch.object(loop, "claude_supports_flag", return_value=True), \
72
+ mock.patch.object(loop.subprocess, "run", return_value=fake_proc) as run:
73
+ loop.dispatch(wu, failure_note=None, cost_tracking=False)
74
+ cmd = run.call_args[0][0]
75
+ self.assertIn("--dangerously-skip-permissions", cmd)
76
+ self.assertIn("--disable-slash-commands", cmd)
77
+ self.assertEqual(cmd[1], "-p")
78
+
79
+
80
+ if __name__ == "__main__":
81
+ unittest.main()
82
+
83
+
84
+ class ProbeReadsTheHelpText(unittest.TestCase):
85
+ def setUp(self):
86
+ loop.claude_supports_flag.cache_clear()
87
+
88
+ def tearDown(self):
89
+ loop.claude_supports_flag.cache_clear()
90
+
91
+ def test_flag_in_help_output_is_supported_and_cached(self):
92
+ fake = mock.MagicMock(stdout="Usage: claude\n --disable-slash-commands Disable all skills\n", stderr="")
93
+ with mock.patch.object(loop.subprocess, "run", return_value=fake) as run:
94
+ self.assertTrue(loop.claude_supports_flag("--disable-slash-commands"))
95
+ self.assertTrue(loop.claude_supports_flag("--disable-slash-commands"))
96
+ self.assertEqual(run.call_count, 1)
97
+
98
+ def test_flag_absent_or_cli_broken_is_not_supported(self):
99
+ fake = mock.MagicMock(stdout="Usage: claude\n --model <m>\n", stderr="")
100
+ with mock.patch.object(loop.subprocess, "run", return_value=fake):
101
+ self.assertFalse(loop.claude_supports_flag("--disable-slash-commands"))
102
+ loop.claude_supports_flag.cache_clear()
103
+ with mock.patch.object(loop.subprocess, "run", side_effect=OSError("no claude")):
104
+ self.assertFalse(loop.claude_supports_flag("--disable-slash-commands"))
105
+
@@ -404,7 +404,9 @@ class TestTitlesTrackingAndBoundaries(unittest.TestCase):
404
404
  "## Post-merge checklist\n\n- **`gatecheck.py --forbid-no-changes` exits 0 on merged HEAD.**\n"
405
405
  )
406
406
  runner = _FakeGhRunner()
407
- result = loop.file_followup_issues(feature_dir, feature_dir, runner=runner)
407
+ result = loop.file_followup_issues(
408
+ feature_dir, feature_dir, runner=runner, post_merge_issue=True,
409
+ )
408
410
  self.assertEqual(result["filed"], 1)
409
411
  argv = runner.create_calls[0]
410
412
  self.assertEqual(argv[argv.index("--title") + 1], "[FEAT-9999 post-merge] Post-merge checklist")
@@ -412,10 +414,32 @@ class TestTitlesTrackingAndBoundaries(unittest.TestCase):
412
414
  plan = (feature_dir / "PLAN.md").read_text()
413
415
  self.assertIn("## Post-merge checklist\n\n**Tracked as #101.**\n\n- **`gatecheck.py", plan)
414
416
  # And the tracked line makes the next call a no-op.
415
- again = loop.file_followup_issues(feature_dir, feature_dir, runner=runner)
417
+ again = loop.file_followup_issues(
418
+ feature_dir, feature_dir, runner=runner, post_merge_issue=True,
419
+ )
416
420
  self.assertEqual((again["filed"], again["already_tracked"]), (0, 1))
417
421
  self.assertEqual(len(runner.create_calls), 1)
418
422
 
423
+ def test_post_merge_checklist_is_not_an_issue_by_default(self):
424
+ # #3424: ten filed across two repositories, eight never actioned.
425
+ with tempfile.TemporaryDirectory() as tmp:
426
+ feature_dir = Path(tmp)
427
+ (feature_dir / "PLAN.md").write_text(
428
+ "---\nfeature_id: FEAT-9999\nstatus: done\nverdict: met\n---\n\n# Plan\n\n"
429
+ "## Post-merge checklist\n\n- [ ] count the thing over the next ten features\n"
430
+ )
431
+ runner = _FakeGhRunner()
432
+ result = loop.file_followup_issues(
433
+ feature_dir, feature_dir, runner=runner, post_merge_issue=False,
434
+ )
435
+ self.assertEqual((result["filed"], result["unfiled"]), (0, 0))
436
+ self.assertEqual(runner.create_calls, [])
437
+ self.assertNotIn("Tracked as", (feature_dir / "PLAN.md").read_text())
438
+
439
+ def test_post_merge_default_reads_the_verification_defaults(self):
440
+ self.assertFalse(loop.resolve_post_merge_issue({}))
441
+ self.assertTrue(loop.resolve_post_merge_issue({"defaults": {"post_merge_issue": True}}))
442
+
419
443
 
420
444
  class TestTrackedLineIsReadUnderTheHeadingOnly(unittest.TestCase):
421
445
  def test_a_foreign_tracked_line_quoted_in_the_evidence_does_not_skip_the_entry(self):
@@ -100,7 +100,7 @@ class TestLintGateProportionality(unittest.TestCase):
100
100
  ]
101
101
  self.assertEqual(len(warns), 1, f"out={out!r}")
102
102
  self.assertIn("6", warns[0])
103
- self.assertIn("8", warns[0])
103
+ self.assertIn("12", warns[0])
104
104
 
105
105
  def test_small_feature_one_gate_clean(self):
106
106
  with tempfile.TemporaryDirectory() as tmpdir:
@@ -114,13 +114,28 @@ class TestLintGateProportionality(unittest.TestCase):
114
114
  out = self._run(feature)
115
115
  self.assertNotIn("WARN", out)
116
116
 
117
- def test_nine_units_two_gates_clean(self):
117
+ def test_nine_units_two_gates_warns_since_the_line_moved_to_twelve(self):
118
+ # #3426: 9 substantive units sat just over the old line of 8.
119
+ with tempfile.TemporaryDirectory() as tmpdir:
120
+ feature = _make_feature(
121
+ tmpdir,
122
+ [["implementation"] * 5, ["implementation"] * 4],
123
+ )
124
+ out = self._run(feature)
125
+ warns = [
126
+ line for line in out.splitlines()
127
+ if "WARN" in line and "planned substantive WU count" in line
128
+ ]
129
+ self.assertEqual(len(warns), 1, f"out={out!r}")
130
+ self.assertIn("9", warns[0])
131
+
132
+ def test_thirteen_units_two_gates_clean(self):
118
133
  with tempfile.TemporaryDirectory() as tmpdir:
119
134
  feature = _make_feature(
120
135
  tmpdir,
121
136
  [
122
- ["implementation"] * 5,
123
- ["implementation"] * 4,
137
+ ["implementation"] * 7,
138
+ ["implementation"] * 6,
124
139
  ],
125
140
  )
126
141
  out = self._run(feature)
@@ -340,3 +340,32 @@ class TestAutoArchiveLeavesNeighbourAnchor(unittest.TestCase):
340
340
 
341
341
  if __name__ == "__main__":
342
342
  unittest.main()
343
+
344
+
345
+ class TestPostMergeChecklistTravelsWithTheArchive(unittest.TestCase):
346
+ """#3424: the checklist lands under the archived detail, not in an issue."""
347
+
348
+ def test_checklist_appended_under_the_archived_section(self):
349
+ with tempfile.TemporaryDirectory() as tmp:
350
+ repo = _make_repo(tmp)
351
+ fdir = repo / ".specfuse" / "features" / "FEAT-2026-9999-slug"
352
+ fdir.mkdir(parents=True)
353
+ (fdir / "PLAN.md").write_text(
354
+ "---\nfeature_id: FEAT-2026-9999\nstatus: done\n---\n\n# Plan\n\n"
355
+ "## Post-merge checklist\n\n- [ ] count the thing over the next ten features\n\n"
356
+ "## Notes\n\n- none\n"
357
+ )
358
+ self.assertEqual(loop.auto_archive_feature("FEAT-2026-9999", repo), "archived")
359
+ archive_text = (repo / ".specfuse" / "roadmap-archive.md").read_text()
360
+ self.assertIn("**Post-merge checklist.**", archive_text)
361
+ self.assertIn("- [ ] count the thing over the next ten features", archive_text)
362
+ self.assertNotIn("## Notes", archive_text)
363
+
364
+ def test_no_plan_means_no_checklist_and_no_change(self):
365
+ with tempfile.TemporaryDirectory() as tmp:
366
+ repo = _make_repo(tmp)
367
+ self.assertEqual(loop.auto_archive_feature("FEAT-2026-9999", repo), "archived")
368
+ self.assertNotIn(
369
+ "Post-merge checklist", (repo / ".specfuse" / "roadmap-archive.md").read_text(),
370
+ )
371
+
@@ -22,7 +22,7 @@ loop = load_loop()
22
22
  class TestCloseIntermediateInDicts(unittest.TestCase):
23
23
 
24
24
  def test_close_intermediate_in_model_by_type(self):
25
- self.assertEqual(loop.MODEL_BY_TYPE["close-intermediate"], "opus")
25
+ self.assertEqual(loop.MODEL_BY_TYPE["close-intermediate"], "sonnet")
26
26
 
27
27
  def test_close_intermediate_in_effort_by_type(self):
28
28
  self.assertEqual(loop.EFFORT_BY_TYPE["close-intermediate"], "high")
@@ -52,5 +52,5 @@ class TestLoadWuCloseIntermediate(unittest.TestCase):
52
52
  "depends_on": []}
53
53
  wu = loop.load_wu(Path(tmp), ref)
54
54
  self.assertEqual(wu.type, "close-intermediate")
55
- self.assertEqual(wu.model, "opus")
55
+ self.assertEqual(wu.model, "sonnet")
56
56
  self.assertEqual(wu.effort, "high")
@@ -1 +0,0 @@
1
- 0.24.0
File without changes