specfuse-loop 0.19.0__tar.gz → 0.20.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 (571) hide show
  1. {specfuse_loop-0.19.0/specfuse_loop.egg-info → specfuse_loop-0.20.0}/PKG-INFO +1 -1
  2. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/pyproject.toml +1 -1
  3. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/closing_requirements.py +20 -3
  4. specfuse_loop-0.20.0/specfuse/loop/data/VERSION +1 -0
  5. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/methodology.md +69 -0
  6. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/close-discipline.md +14 -0
  7. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/never-touch.md +23 -26
  8. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/result-contract.md +49 -41
  9. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/security-boundaries.md +23 -27
  10. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules-local/README.md +20 -0
  11. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/driver-event.schema.json +3 -2
  12. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/verification.yml.example +6 -0
  13. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/gate_eval.py +28 -0
  14. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/judge.py +27 -1
  15. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/lint_closing.py +19 -1
  16. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/loop.py +1189 -21
  17. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0/specfuse_loop.egg-info}/PKG-INFO +1 -1
  18. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/SOURCES.txt +17 -0
  19. specfuse_loop-0.20.0/tests/test_binding_block_allocation.py +64 -0
  20. specfuse_loop-0.20.0/tests/test_binding_block_budget.py +43 -0
  21. specfuse_loop-0.20.0/tests/test_brief_covers_every_unit_escalation.py +228 -0
  22. specfuse_loop-0.20.0/tests/test_conditional_reflection.py +437 -0
  23. specfuse_loop-0.20.0/tests/test_distilled_accept_step.py +193 -0
  24. specfuse_loop-0.20.0/tests/test_judge_terminal_flip_state.py +95 -0
  25. specfuse_loop-0.20.0/tests/test_learnings_weights.py +249 -0
  26. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_closing.py +10 -0
  27. specfuse_loop-0.20.0/tests/test_progress_forward_note.py +107 -0
  28. specfuse_loop-0.20.0/tests/test_progress_lines_end_to_end.py +155 -0
  29. specfuse_loop-0.20.0/tests/test_reflection_required_signals.py +151 -0
  30. specfuse_loop-0.20.0/tests/test_replan_end_to_end.py +216 -0
  31. specfuse_loop-0.20.0/tests/test_replan_event_emission.py +186 -0
  32. specfuse_loop-0.20.0/tests/test_replan_note_collision.py +150 -0
  33. specfuse_loop-0.20.0/tests/test_replan_trigger.py +277 -0
  34. specfuse_loop-0.20.0/tests/test_replan_turn_contract.py +304 -0
  35. specfuse_loop-0.20.0/tests/test_spinout_brief_end_to_end.py +180 -0
  36. specfuse_loop-0.20.0/tests/test_spinout_brief_replan_option.py +297 -0
  37. specfuse_loop-0.19.0/specfuse/loop/data/VERSION +0 -1
  38. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/LICENSE +0 -0
  39. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/NOTICE +0 -0
  40. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/README.md +0 -0
  41. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/setup.cfg +0 -0
  42. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/__init__.py +0 -0
  43. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/budget.py +0 -0
  44. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/diagnose_invoke.py +0 -0
  45. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/drafting_answers.py +0 -0
  46. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/drafting_invoke.py +0 -0
  47. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/drafting_questions.py +0 -0
  48. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/driver_command.py +0 -0
  49. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/driver_invoke.py +0 -0
  50. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/invoke.py +0 -0
  51. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/monitoring_read.py +0 -0
  52. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/__init__.py +0 -0
  53. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/answers.py +0 -0
  54. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/bugs.py +0 -0
  55. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/feature.py +0 -0
  56. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/findings_autofix.py +0 -0
  57. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/findings_diagnose.py +0 -0
  58. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/triage.py +0 -0
  59. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/queue_read.py +0 -0
  60. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/repo_detect.py +0 -0
  61. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/run.py +0 -0
  62. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/state.py +0 -0
  63. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/triage_invoke.py +0 -0
  64. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/worktree.py +0 -0
  65. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/__init__.py +0 -0
  66. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/_filelock.py +0 -0
  67. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/_miniyaml.py +0 -0
  68. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/_wu_sections.py +0 -0
  69. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/adopt_feature.py +0 -0
  70. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/agent_policy.py +0 -0
  71. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/arm_eval.py +0 -0
  72. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/arm_sweep.py +0 -0
  73. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/arm_txn.py +0 -0
  74. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/bug_lane.py +0 -0
  75. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/bug_lane_run.py +0 -0
  76. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/bug_lane_state.py +0 -0
  77. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/build_provenance.py +0 -0
  78. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/changelog.py +0 -0
  79. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/cost.py +0 -0
  80. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/criteria_state.py +0 -0
  81. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
  82. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/LEARNINGS.template.md +0 -0
  83. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
  84. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
  85. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
  86. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
  87. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/getting-started.md +0 -0
  88. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/glossary.md +0 -0
  89. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/skills.md +0 -0
  90. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/gitignore.snippet +0 -0
  91. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
  92. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
  93. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/monitoring.yml.example +0 -0
  94. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/roadmap.template.md +0 -0
  95. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/correlation-ids.md +0 -0
  96. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
  97. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/human-output.md +0 -0
  98. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/operator-escalation.md +0 -0
  99. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/planning-discipline.md +0 -0
  100. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/verification-discipline.md +0 -0
  101. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/event.schema.json +0 -0
  102. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
  103. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
  104. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
  105. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
  106. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
  107. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/GATE.template.md +0 -0
  108. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
  109. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/PLAN.template.md +0 -0
  110. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/WU.template.md +0 -0
  111. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
  112. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/decisions_format.py +0 -0
  113. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/driver_edit.py +0 -0
  114. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/escalation.py +0 -0
  115. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/events_stats.py +0 -0
  116. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/gate_commands.py +0 -0
  117. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/gh_backend.py +0 -0
  118. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/gh_features.py +0 -0
  119. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/heartbeat.py +0 -0
  120. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/labels.py +0 -0
  121. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/learnings_query.py +0 -0
  122. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/lint_monitoring.py +0 -0
  123. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/lint_plan.py +0 -0
  124. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/lint_roadmap.py +0 -0
  125. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/notify.py +0 -0
  126. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/notify_escalation.py +0 -0
  127. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/notify_sla.py +0 -0
  128. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/plan_baseline.py +0 -0
  129. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/policy_proposals.py +0 -0
  130. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/policy_review.py +0 -0
  131. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/prerun.py +0 -0
  132. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/prerun_capture.py +0 -0
  133. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/promotion.py +0 -0
  134. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/rearm_migration.py +0 -0
  135. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/replay_spin.py +0 -0
  136. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/roadmap_archive.py +0 -0
  137. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/scaffold.py +0 -0
  138. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/triage.py +0 -0
  139. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/upgrade_merge_gate.py +0 -0
  140. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/validate_event.py +0 -0
  141. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/__init__.py +0 -0
  142. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/adapters.py +0 -0
  143. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/artifact.py +0 -0
  144. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/autofix.py +0 -0
  145. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/autofix_invoke.py +0 -0
  146. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/autofix_run.py +0 -0
  147. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/autofix_state.py +0 -0
  148. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/cli.py +0 -0
  149. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/diagnose_cli.py +0 -0
  150. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/diagnosis.py +0 -0
  151. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/fingerprint.py +0 -0
  152. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/issues.py +0 -0
  153. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/providers/__init__.py +0 -0
  154. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/providers/_azure_auth.py +0 -0
  155. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/providers/azure_app_insights.py +0 -0
  156. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/providers/azure_service_bus.py +0 -0
  157. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/redaction.py +0 -0
  158. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/schedule.py +0 -0
  159. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/dependency_links.txt +0 -0
  160. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/entry_points.txt +0 -0
  161. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/requires.txt +0 -0
  162. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/top_level.txt +0 -0
  163. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_abandon_feature_skill.py +0 -0
  164. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_abandoned_work_reported.py +0 -0
  165. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_abandoned_wu_strands_gate.py +0 -0
  166. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_adopt_feature.py +0 -0
  167. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_budget.py +0 -0
  168. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_bug_selection_dedup.py +0 -0
  169. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_default_features_root.py +0 -0
  170. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_driver_command.py +0 -0
  171. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_driver_invoke.py +0 -0
  172. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_driver_restart.py +0 -0
  173. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_escalation_on_issue.py +0 -0
  174. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_escalation_run_state.py +0 -0
  175. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_findings_seam.py +0 -0
  176. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_invoke_timeout.py +0 -0
  177. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_invoke_usage.py +0 -0
  178. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_item_worktree.py +0 -0
  179. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_lock.py +0 -0
  180. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_policy_key_ownership.py +0 -0
  181. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_policy_queue.py +0 -0
  182. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_policy_schema.py +0 -0
  183. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_policy_triage_dial.py +0 -0
  184. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_answers.py +0 -0
  185. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_bugs.py +0 -0
  186. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_feature.py +0 -0
  187. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_findings_autofix.py +0 -0
  188. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_findings_diagnose.py +0 -0
  189. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_isolation.py +0 -0
  190. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_triage.py +0 -0
  191. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_queue_read.py +0 -0
  192. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_relays_driver_output.py +0 -0
  193. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_repo_detect.py +0 -0
  194. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_run.py +0 -0
  195. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_run_progress.py +0 -0
  196. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_seam.py +0 -0
  197. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_state.py +0 -0
  198. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_answer_escalation_skill.py +0 -0
  199. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_app_insights_adapters.py +0 -0
  200. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_archive_ref_reconciliation.py +0 -0
  201. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_eval.py +0 -0
  202. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_eval_lint_class.py +0 -0
  203. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_eval_wiring.py +0 -0
  204. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_gate_edits_uncommitted.py +0 -0
  205. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_sweep.py +0 -0
  206. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_sweep_gate.py +0 -0
  207. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_txn.py +0 -0
  208. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_wiring.py +0 -0
  209. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_artifact_redaction.py +0 -0
  210. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attempt_note_untracked_files.py +0 -0
  211. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attempt_outcome_contract.py +0 -0
  212. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attempt_outcome_emission.py +0 -0
  213. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attention_nonwriting_guard.py +0 -0
  214. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attention_silence_section.py +0 -0
  215. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attention_skill_structure.py +0 -0
  216. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autoclose_deferral_visibility.py +0 -0
  217. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autoclose_gate_note.py +0 -0
  218. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autoclose_stub_states_what_passed.py +0 -0
  219. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_invoke.py +0 -0
  220. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_live.py +0 -0
  221. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_predicate.py +0 -0
  222. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_run.py +0 -0
  223. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_state.py +0 -0
  224. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync.py +0 -0
  225. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync_consent.py +0 -0
  226. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync_firstrun.py +0 -0
  227. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync_no_cwd_leak.py +0 -0
  228. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync_plugin.py +0 -0
  229. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_azure_credential_resolution.py +0 -0
  230. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_backend.py +0 -0
  231. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_escalation_message.py +0 -0
  232. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_persistence.py +0 -0
  233. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_probe.py +0 -0
  234. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_provenance.py +0 -0
  235. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_tree_hash_key.py +0 -0
  236. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bash_routing.py +0 -0
  237. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bats_suites_gated.py +0 -0
  238. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_binary_verdict.py +0 -0
  239. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bookkeeping_commit_crash_run.py +0 -0
  240. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
  241. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bookkeeping_no_verify.py +0 -0
  242. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_ci_pending.py +0 -0
  243. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_guardrails.py +0 -0
  244. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_label_nonfatal.py +0 -0
  245. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_labels_registered.py +0 -0
  246. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_policy_contract.py +0 -0
  247. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_pr_number_carried.py +0 -0
  248. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_preflight_and_dial.py +0 -0
  249. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_run.py +0 -0
  250. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_state.py +0 -0
  251. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
  252. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_test_paths.py +0 -0
  253. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_build_provenance.py +0 -0
  254. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changed_file_test_selection.py +0 -0
  255. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changelog_append_only.py +0 -0
  256. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changelog_collection.py +0 -0
  257. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changelog_release_wiring.py +0 -0
  258. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changelog_schema.py +0 -0
  259. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ci_conclusion_wait.py +0 -0
  260. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ci_runs_every_gate.py +0 -0
  261. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_claude_resolution.py +0 -0
  262. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_close_b_pending_learnings.py +0 -0
  263. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_close_records_feature_oracle.py +0 -0
  264. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_close_wu_self_reference.py +0 -0
  265. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_deliverable_guard.py +0 -0
  266. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_guard_contracts.py +0 -0
  267. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_guard_prediction.py +0 -0
  268. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_learnings_destination.py +0 -0
  269. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_requirements.py +0 -0
  270. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_coauthor_trailer_allowlist.py +0 -0
  271. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_console_encoding.py +0 -0
  272. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_convergent_iteration.py +0 -0
  273. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_convergent_wu_lint.py +0 -0
  274. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_correlation_id_override.py +0 -0
  275. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_correlation_id_two_surfaces.py +0 -0
  276. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_cost_lifetime.py +0 -0
  277. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_cost_tracking.py +0 -0
  278. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_criteria_per_gate_lint.py +0 -0
  279. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_criteria_state.py +0 -0
  280. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_criteria_worklist.py +0 -0
  281. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_decision_citation_lint.py +0 -0
  282. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_decision_followups_discharged.py +0 -0
  283. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_decision_override_lint.py +0 -0
  284. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_decisions_format.py +0 -0
  285. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_degraded_oracle.py +0 -0
  286. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_deliverable_missing_note.py +0 -0
  287. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_deliverable_presence_gate.py +0 -0
  288. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_derive_agent_policy_review_mode.py +0 -0
  289. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_derive_agent_policy_skill.py +0 -0
  290. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_derive_monitoring_discovery.py +0 -0
  291. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_derive_monitoring_skill_registration.py +0 -0
  292. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_design_for_diagnosis_rule.py +0 -0
  293. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_deterministic_refusal_repeat.py +0 -0
  294. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_diagnose_headless.py +0 -0
  295. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_diagnose_issue_skill.py +0 -0
  296. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_diagnosis.py +0 -0
  297. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_diagnosis_roundtrip_live.py +0 -0
  298. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_dispatch_skeleton.py +0 -0
  299. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_doctor.py +0 -0
  300. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_done_feature_gates.py +0 -0
  301. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_draft_feature_answers_mode.py +0 -0
  302. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_answer_gate.py +0 -0
  303. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_invoke.py +0 -0
  304. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_question_issue.py +0 -0
  305. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_questions.py +0 -0
  306. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_reply_shape.py +0 -0
  307. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_edit_detection.py +0 -0
  308. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_event_registry_covers_emitters.py +0 -0
  309. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_integration.py +0 -0
  310. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_lock.py +0 -0
  311. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_module_surface.py +0 -0
  312. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_restart_halt_surfaced.py +0 -0
  313. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_restart_halt_wiring.py +0 -0
  314. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_restart_hold.py +0 -0
  315. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_staleness_gate_summary.py +0 -0
  316. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_staleness_warning.py +0 -0
  317. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_dry_run_no_branch_mutation.py +0 -0
  318. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_duration_tracking.py +0 -0
  319. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_empty_files_escalation.py +0 -0
  320. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ensure_feature_branch.py +0 -0
  321. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ensure_feature_branch_base.py +0 -0
  322. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_assignee_policy.py +0 -0
  323. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_contract.py +0 -0
  324. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_crash_containment.py +0 -0
  325. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_dedup_search.py +0 -0
  326. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_emit.py +0 -0
  327. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_event_gate_full_envelope.py +0 -0
  328. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_events_redaction.py +0 -0
  329. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_events_stats.py +0 -0
  330. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_extra_gates.py +0 -0
  331. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_failure_artifact_model.py +0 -0
  332. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_failure_signature_fail_prefix.py +0 -0
  333. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_failure_signature_skips_log_noise.py +0 -0
  334. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_branch_auto_sync.py +0 -0
  335. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_branch_squash_merge.py +0 -0
  336. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_branch_stale_base.py +0 -0
  337. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_id_resolution.py +0 -0
  338. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_oracle_e2e.py +0 -0
  339. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_provider_drafting_dispatch.py +0 -0
  340. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_review_accumulation.py +0 -0
  341. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_filelock_portable.py +0 -0
  342. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_files_changed_auto_repair.py +0 -0
  343. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_find_pr_no_search_index.py +0 -0
  344. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fingerprint.py +0 -0
  345. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fix_bug_diff_self_check.py +0 -0
  346. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fix_bug_headless.py +0 -0
  347. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fix_bug_reads_comments.py +0 -0
  348. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fold_contract_documented.py +0 -0
  349. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_followups_artifact.py +0 -0
  350. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_force_full_close.py +0 -0
  351. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_frontmatter_scalar_quoting.py +0 -0
  352. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_broad_run.py +0 -0
  353. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_budget.py +0 -0
  354. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_budget_post_dispatch.py +0 -0
  355. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_commands_needs.py +0 -0
  356. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval.py +0 -0
  357. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval_calibration.py +0 -0
  358. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval_intermediate_wiring.py +0 -0
  359. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval_repo_flag.py +0 -0
  360. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval_terminal_wiring.py +0 -0
  361. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_report_verdict.py +0 -0
  362. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gh_backend.py +0 -0
  363. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gh_features.py +0 -0
  364. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_git_env_isolation.py +0 -0
  365. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gitleaks_pinning.py +0 -0
  366. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_groom_backlog_skill.py +0 -0
  367. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_guard_refusal_failure_class.py +0 -0
  368. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_guard_refusal_failure_excerpt.py +0 -0
  369. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_guard_repair_e2e.py +0 -0
  370. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_guard_repair_prompt.py +0 -0
  371. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_hashed_denylist.py +0 -0
  372. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_hashed_denylist_ci.py +0 -0
  373. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_heartbeat.py +0 -0
  374. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_heartbeat_adapter.py +0 -0
  375. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_human_output_rule.py +0 -0
  376. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_human_work_unit.py +0 -0
  377. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_hyphenated_gate_name.py +0 -0
  378. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_init_integration.py +0 -0
  379. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_installed_copy_driver_e2e.py +0 -0
  380. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_interpreter_normalization.py +0 -0
  381. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_close_path.py +0 -0
  382. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_cost.py +0 -0
  383. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_cost_fold_committed.py +0 -0
  384. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_module.py +0 -0
  385. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_path_registry.py +0 -0
  386. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_label_provisioning_runner_contract.py +0 -0
  387. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_label_registry.py +0 -0
  388. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_label_registry_covers_consumers.py +0 -0
  389. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_language_aware_narrow_selection.py +0 -0
  390. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lazy_baseline_e2e.py +0 -0
  391. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_leak_findings_redaction.py +0 -0
  392. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_leak_scan.py +0 -0
  393. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_leak_scan_content.py +0 -0
  394. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_learnings_curate_vendored_promote.py +0 -0
  395. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_learnings_query.py +0 -0
  396. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_learnings_staging.py +0 -0
  397. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_learnings_suggest_signature_filter.py +0 -0
  398. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_legacy_4wu_terminal_flips.py +0 -0
  399. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lifecycle_integration.py +0 -0
  400. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lifetime_accounting.py +0 -0
  401. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_ac_observable.py +0 -0
  402. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_bare_produces_path.py +0 -0
  403. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_boundary_consistency.py +0 -0
  404. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_boundary_extraction.py +0 -0
  405. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_close_intermediate.py +0 -0
  406. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_close_verdict_not_predecided.py +0 -0
  407. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_close_wu.py +0 -0
  408. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_closing_criteria.py +0 -0
  409. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_closing_criteria_pristine.py +0 -0
  410. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_correlation_id.py +0 -0
  411. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
  412. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_feature_oracle_declared.py +0 -0
  413. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_gate_proportionality.py +0 -0
  414. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_monitoring.py +0 -0
  415. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_oracle_env.py +0 -0
  416. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_contract_fields.py +0 -0
  417. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_errors.py +0 -0
  418. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_next_draft.py +0 -0
  419. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_relative_import.py +0 -0
  420. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_verdict_exempt.py +0 -0
  421. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_planning_sections.py +0 -0
  422. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_produces_driver_helper.py +0 -0
  423. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_produces_satisfiability.py +0 -0
  424. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_roadmap.py +0 -0
  425. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_sections.py +0 -0
  426. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_task_graph_yaml_selection.py +0 -0
  427. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_verification_reference.py +0 -0
  428. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_live_tests_opt_in.py +0 -0
  429. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_load_bearing_close_lint.py +0 -0
  430. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_attempt_evidence.py +0 -0
  431. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_auto_archive.py +0 -0
  432. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_caveman_preamble.py +0 -0
  433. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_close_intermediate.py +0 -0
  434. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_criteria_skeleton.py +0 -0
  435. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_criteria_survival.py +0 -0
  436. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_defaults_by_type.py +0 -0
  437. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_effort.py +0 -0
  438. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_failure_note_cap.py +0 -0
  439. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_files_changed_guard.py +0 -0
  440. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_gate_budget.py +0 -0
  441. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_gate_needs.py +0 -0
  442. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_model_alias.py +0 -0
  443. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_orchestration.py +0 -0
  444. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_post_pass_invariant.py +0 -0
  445. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_reset_preserving_events.py +0 -0
  446. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_smoke_runner.py +0 -0
  447. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_unsandboxed.py +0 -0
  448. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_worklist_injection.py +0 -0
  449. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_zero_token_guard.py +0 -0
  450. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_make_repo_gpgsign_isolation.py +0 -0
  451. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_maven_failure_excerpt.py +0 -0
  452. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_max_attempts_configurable.py +0 -0
  453. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_migrate_legacy.py +0 -0
  454. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_miniyaml_equivalence.py +0 -0
  455. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_miniyaml_negative.py +0 -0
  456. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitor_cli.py +0 -0
  457. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitor_issue_lifecycle.py +0 -0
  458. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitor_runner_surfaces.py +0 -0
  459. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
  460. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_cron_dialect.py +0 -0
  461. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_example.py +0 -0
  462. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_fenced_blocks.py +0 -0
  463. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_seed.py +0 -0
  464. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_narrow_fallback_warning.py +0 -0
  465. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_no_pytest_subprocess.py +0 -0
  466. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_notify.py +0 -0
  467. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_notify_escalation.py +0 -0
  468. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_notify_sla.py +0 -0
  469. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_operator_escalation_rule.py +0 -0
  470. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_oracle_set_declared.py +0 -0
  471. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_oracle_unrunnable_attribution.py +0 -0
  472. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pick_feature_skill.py +0 -0
  473. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pin_honesty_and_integrity.py +0 -0
  474. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pin_marker_not_inherited.py +0 -0
  475. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pin_marker_spawn_sites.py +0 -0
  476. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_plan_baseline.py +0 -0
  477. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_planned_cost_lint.py +0 -0
  478. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_planning_cost_floor.py +0 -0
  479. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_policy_proposals.py +0 -0
  480. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_policy_review.py +0 -0
  481. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pr_checks_json_field.py +0 -0
  482. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
  483. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prep_halt_operator_surface.py +0 -0
  484. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prepare_feature.py +0 -0
  485. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prepare_scaffold_sync.py +0 -0
  486. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prerun_capture.py +0 -0
  487. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prerun_oracles.py +0 -0
  488. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prerun_wiring.py +0 -0
  489. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produced_document_verdict_guard.py +0 -0
  490. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_bracket_literal.py +0 -0
  491. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_bracket_wildcard.py +0 -0
  492. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_field.py +0 -0
  493. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_in_diff.py +0 -0
  494. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_justification.py +0 -0
  495. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_recursive_glob.py +0 -0
  496. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_semantics_unified.py +0 -0
  497. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_shape.py +0 -0
  498. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_promotion_ledger.py +0 -0
  499. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_provider_escalation_traces.py +0 -0
  500. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_provision_labels.py +0 -0
  501. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_queue_stalled_adapter.py +0 -0
  502. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_rearm_clears_stale_criteria_state.py +0 -0
  503. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_rearm_fold_marker.py +0 -0
  504. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_rearm_migration.py +0 -0
  505. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_red_baseline_never_reused.py +0 -0
  506. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_redaction_windows_home.py +0 -0
  507. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_replay_spin.py +0 -0
  508. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_resolve_base.py +0 -0
  509. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_restart_cap_counts_progress.py +0 -0
  510. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_result_block.py +0 -0
  511. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_result_block_audience.py +0 -0
  512. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_resume_command_build.py +0 -0
  513. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_retain_on_guard_refusal_docs.py +0 -0
  514. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_add_skill.py +0 -0
  515. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_archive_cli.py +0 -0
  516. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_archive_shim.py +0 -0
  517. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_archive_skill.py +0 -0
  518. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_archive_skill_delegates.py +0 -0
  519. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_link_gate.py +0 -0
  520. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_row_parser.py +0 -0
  521. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ruff_verdict_lines.py +0 -0
  522. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_data_in_sync.py +0 -0
  523. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_doc_hygiene.py +0 -0
  524. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_docs.py +0 -0
  525. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_init.py +0 -0
  526. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_label_provisioning.py +0 -0
  527. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_manifest.py +0 -0
  528. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_resources.py +0 -0
  529. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_seed_sanity.py +0 -0
  530. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_skew_halts.py +0 -0
  531. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_upgrade.py +0 -0
  532. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_wiring.py +0 -0
  533. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_schedule_dialect.py +0 -0
  534. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_seed_documents_prerun_keys.py +0 -0
  535. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_service_bus_dlq_adapter.py +0 -0
  536. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_session_env_preflight.py +0 -0
  537. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_shipped_templates_parse.py +0 -0
  538. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_skill_discovery_links.py +0 -0
  539. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_skills_vendored_in_sync.py +0 -0
  540. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_spinning_rearm_gate.py +0 -0
  541. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_squash_commit_hook_crash.py +0 -0
  542. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_stop_rationale_captured.py +0 -0
  543. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_surefire_run_level_signature.py +0 -0
  544. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_surefire_verdict_lines.py +0 -0
  545. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_template_closing_shapes.py +0 -0
  546. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_terminal_flip_ownership.py +0 -0
  547. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_terminal_flips.py +0 -0
  548. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_terminal_gate_message.py +0 -0
  549. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_tiered_verification_e2e.py +0 -0
  550. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_timeout_kill_portable.py +0 -0
  551. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_triage.py +0 -0
  552. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_triage_apply.py +0 -0
  553. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_triage_skill_contract.py +0 -0
  554. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_triage_skips_agent_escalations.py +0 -0
  555. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_tsc_verdict_lines.py +0 -0
  556. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_umbrella_version_resolution.py +0 -0
  557. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_unterminated_frontmatter.py +0 -0
  558. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_untracked_feature_folder.py +0 -0
  559. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_untracked_file_absorption.py +0 -0
  560. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_upgrade_integration.py +0 -0
  561. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_upgrade_merge_gate.py +0 -0
  562. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_validate_event.py +0 -0
  563. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_validate_event_driver_types.py +0 -0
  564. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_verdict_coupling.py +0 -0
  565. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_verify_empty_gate_set.py +0 -0
  566. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_version_consistency.py +0 -0
  567. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_version_skew.py +0 -0
  568. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_windows_gate_exec.py +0 -0
  569. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_worktree_restore.py +0 -0
  570. {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_wu_execution_metadata.py +0 -0
  571. {specfuse_loop-0.19.0 → specfuse_loop-0.20.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.19.0
3
+ Version: 0.20.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.19.0"
7
+ version = "0.20.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"
@@ -281,14 +281,25 @@ CLOSING_REQUIREMENTS: dict[str, list[Requirement]] = {
281
281
  ),
282
282
  Requirement(
283
283
  id="close-e", wu_type="close", phase="pre-squash",
284
- description=f"RETROSPECTIVE.md has a '{COST_ANALYSIS_HEADING}' heading",
284
+ description=(
285
+ f"RETROSPECTIVE.md has a '{COST_ANALYSIS_HEADING}' heading "
286
+ "when verdict==met AND gate_eval.reflection_required says "
287
+ "the gate went off-plan (FEAT-2026-0106/T03) — an on-plan "
288
+ "close skips this reflective section"
289
+ ),
285
290
  file=RETROSPECTIVE_FILENAME, heading=COST_ANALYSIS_HEADING,
286
291
  applies_when="verdict_met",
287
292
  enforced_by="assert_cost_analysis_section_when_met",
288
293
  ),
289
294
  Requirement(
290
295
  id="close-f", wu_type="close", phase="pre-squash",
291
- description=f"RETROSPECTIVE.md has a '{FAILURE_CLASS_HEADING}' heading",
296
+ description=(
297
+ f"RETROSPECTIVE.md has a '{FAILURE_CLASS_HEADING}' heading "
298
+ "when non-passing attempts are present AND "
299
+ "gate_eval.reflection_required says the gate went off-plan "
300
+ "(FEAT-2026-0106/T03) — an on-plan close skips this "
301
+ "reflective section"
302
+ ),
292
303
  file=RETROSPECTIVE_FILENAME, heading=FAILURE_CLASS_HEADING,
293
304
  heading_level=FAILURE_CLASS_HEADING_LEVEL,
294
305
  applies_when="failures_present",
@@ -397,7 +408,13 @@ CLOSING_REQUIREMENTS: dict[str, list[Requirement]] = {
397
408
  ),
398
409
  Requirement(
399
410
  id="close-intermediate-d", wu_type="close-intermediate", phase="pre-squash",
400
- description=f"RETROSPECTIVE.md has a '{FAILURE_CLASS_HEADING}' heading",
411
+ description=(
412
+ f"RETROSPECTIVE.md has a '{FAILURE_CLASS_HEADING}' heading "
413
+ "when non-passing attempts are present AND "
414
+ "gate_eval.reflection_required says the gate went off-plan "
415
+ "(FEAT-2026-0106/T03) — an on-plan close skips this "
416
+ "reflective section"
417
+ ),
401
418
  file=RETROSPECTIVE_FILENAME, heading=FAILURE_CLASS_HEADING,
402
419
  heading_level=FAILURE_CLASS_HEADING_LEVEL,
403
420
  applies_when="failures_present",
@@ -0,0 +1 @@
1
+ 0.20.0
@@ -185,6 +185,16 @@ For the full design rationale see `PLAN.md` for FEAT-2026-0018.
185
185
  FEAT-2026-0016, if present, is also inspected — any prior `blocked_human`
186
186
  cycle disables auto.
187
187
  2. **No replan** — no `replan` event in `events.jsonl` for this gate's WUs.
188
+ A replan fires when a unit's next attempt would be its last permitted one
189
+ (the ceiling `resolve_max_attempts` resolves for that unit, not a bare
190
+ count of two) — the driver runs a fresh re-plan session instead of
191
+ retrying the same failing body verbatim. Units with `iterate_on_failure:
192
+ true` are exempt: they fail on purpose against a convergent validator, and
193
+ a replan there would misread deliberate iteration as spinning. Seeing this
194
+ check disable auto-close means a unit was mis-sized at authoring time (see
195
+ `/authoring-work-units` §6), not that anything is broken. A unit that
196
+ still spins out after this automatic re-plan escalates to a human — see
197
+ the escalation brief below for what that escalation tells the operator.
188
198
  3. **Per-WU cost ≤ 1.5× planned** — every substantive WU's `cost_usd` ≤
189
199
  `planned_cost_usd × 1.5`. If `planned_cost_usd` absent: skip this check for
190
200
  that WU (graceful degrade — emits a warning reason in the decision but doesn't
@@ -202,6 +212,28 @@ For the full design rationale see `PLAN.md` for FEAT-2026-0018.
202
212
  failed (already governed by check 1 if blocked), but the FINAL outcome on
203
213
  each WU must be clean.
204
214
 
215
+ **The escalation brief (FEAT-2026-0104)** — **every** `blocked_human`
216
+ escalation of a work unit, not only the spin-out that follows the automatic
217
+ re-plan above, halts with a six-part operator brief
218
+ (`.specfuse/rules/operator-escalation.md`'s six parts, in order), printed to
219
+ the console and recorded verbatim in the `human_escalation` event's `message`
220
+ field in `events.jsonl`. Gate-level halts — a gate budget exceeded, a
221
+ pre-existing gate failure, a failing broad run — are excluded: those are keyed
222
+ on the feature rather than on one unit, and there is no single unit to brief
223
+ about. The escalation `reason` decides
224
+ whether the brief's first option is re-planning the remaining gate:
225
+ `spinning_detected`, `spinning_signature_repeat`, `convergence_plateau`, and
226
+ `replan_unchanged_body` carry it, because for those a wider re-scope is the
227
+ remedy; `all_attempts_zero_token`, `deterministic_refusal_repeat`,
228
+ `produces_shape_invalid`, `spinning_reproduction_missing`, `prep_halted`, and
229
+ `agent_reported_blocked` do not, because re-planning would fix nothing about
230
+ that reason's actual cause (`REPLAN_OPTION_SCOPE` in `loop.py` is the single
231
+ table both the brief and its tests consult). When it applies, the option is a
232
+ recommendation, not an action the driver performs: the brief names
233
+ `/unblock-wu` for the operator to run, re-arming the unit(s) so the driver's
234
+ own automatic re-plan trigger (check 2 above) becomes reachable again for
235
+ each — it resets `attempts`, it does not itself rewrite a body.
236
+
205
237
  **Auto-close terminal** — when the predicate fires on a terminal gate, the driver
206
238
  writes a stub `RETROSPECTIVE.md`, marks the close WU `status: done` with
207
239
  `auto_close: true` frontmatter, and fires `fire_terminal_flips` directly. The
@@ -563,6 +595,18 @@ reflective session. Ceremony proportionality trades reflection only on
563
595
  features that stay small **and** on-plan. The `gate_eval.py` predicate is
564
596
  the safety net; this rule does not replace it.
565
597
 
598
+ **Reflective prose is conditional too (FEAT-2026-0106).** The roadmap once
599
+ asked for a retrospective "only on `not_met` or on request" — superseded,
600
+ for an ordering reason: the close writes `RETROSPECTIVE.md` before the judge
601
+ produces a verdict, so there is nothing to condition on at write time. The
602
+ close instead keys its reflective sections (`## Cost analysis`,
603
+ `### Failure-class breakdown`) on the same off-plan signal named above
604
+ (blocked WU, replan event, cost overrun) rather than on the verdict. Every
605
+ other closing obligation — measurements above all, since the judge's evidence
606
+ bundle depends on them regardless of how the gate went — stays unconditional;
607
+ see [`close-discipline.md`](../.specfuse/rules/close-discipline.md) §1a for
608
+ which is which.
609
+
566
610
  The canonical threshold is **8** (stated here, in `docs/methodology.md`;
567
611
  referenced, not re-defined, in `.specfuse/skills/draft-feature/SKILL.md`).
568
612
 
@@ -610,6 +654,31 @@ feature's `RETROSPECTIVE.md`; only rules that would change how a *future* WU is
610
654
  written or executed graduate to `LEARNINGS.md`. This is the human-scale analogue
611
655
  of the Ralph loop feeding errors back into the prompt.
612
656
 
657
+ ### The binding-block word budget (FEAT-2026-0111)
658
+
659
+ The `.claude/CLAUDE.md` "Specfuse binding rules" block — every `@`-referenced
660
+ file a dispatched work-unit session is held to — is capped at 2,500 words
661
+ (`BINDING_BLOCK_WORD_CAP` in `specfuse/loop/loop.py`), enforced by
662
+ `check_binding_block_budget`. Every rule added to that block, including a
663
+ project-authored entry under `.specfuse/rules-local/`, is counted against this
664
+ one shared cap; a project adding a local rule spends the same allowance the
665
+ loop's own rules already draw from.
666
+
667
+ `.specfuse/rules-local/learnings-distilled.md` — the LEARNINGS-derived
668
+ distillate wired into the block — carries its own 500-word sub-budget
669
+ (`LEARNINGS_DISTILLED_WORD_CAP`) inside the 2,500-word total. `score_learnings_entries`
670
+ ranks candidate entries and a human accept step (`apply_distilled_decisions`)
671
+ cuts the accepted set to that 500-word sub-budget, not to an entry count.
672
+
673
+ The ranking's `reach` field — the count of other feature files that cite an
674
+ entry — is **a tiebreaker with an age bias, not a ranking signal**: it counts
675
+ citations in planning documents, and planning agents cite what they have
676
+ already read in `LEARNINGS.md`, so visibility inflates its own count, and it
677
+ favors older entries that have had more features' worth of planning sessions
678
+ in which to be cited. Neither `reach` nor `cost_usd` measures whether a rule
679
+ actually improves a session's work — that is a judgment the accept step still
680
+ has to make by reading the entry, not a property either weight computes.
681
+
613
682
  ## 9. Autonomy
614
683
 
615
684
  Three levels — `auto`, `review`, `supervised` — set once as a feature default
@@ -76,6 +76,20 @@ conclude it — the reason the judge is a fresh session in the first place. A
76
76
  close body names what to measure and what evidence counts, never what value to
77
77
  write. Naming the verdict in the body is a drafting defect, not a shortcut.
78
78
 
79
+ ## 1a. Which obligations are conditional (FEAT-2026-0106)
80
+
81
+ Not every obligation above binds on every close. The reflective sections —
82
+ `## Cost analysis` and `### Failure-class breakdown` — are conditional on
83
+ `gate_eval`'s off-plan signal (a blocked WU, a `replan` event, a cost
84
+ overrun): an on-plan close skips them. Measurements are not conditional on
85
+ anything, for the reason stated in §1 — the judge's evidence bundle slices
86
+ `## Measurements` out of `RETROSPECTIVE.md` regardless of how the gate went,
87
+ so a close that skipped writing them would starve the judge of the evidence
88
+ it needs to reach a verdict at all. `docs/methodology.md` §6 "Ceremony
89
+ proportionality" states the same off-plan signal at the gate-dispatch level
90
+ (whether a close runs at all); this section is the narrower case of a close
91
+ that does run still skipping prose the gate didn't earn.
92
+
79
93
  ## 2. The verdict is binary; unfinished work is tracked, not hedged
80
94
 
81
95
  The verdict a close records is `met` or `not_met` — there is no partial
@@ -7,50 +7,47 @@ Licensed under the Apache License, Version 2.0. See LICENSE.
7
7
 
8
8
  Three categories of path are off-limits to every work-unit session, regardless of
9
9
  unit type. If a unit's acceptance criteria or verification commands appear to
10
- require modifying something in this list, that is an escalation condition, not a
10
+ require modifying something in this list, that is an escalation condition, not
11
11
  license to proceed — signal blocked per
12
12
  [`verification-discipline.md`](verification-discipline.md), naming the
13
- boundary. (How "blocked" is signalled is surface-specific — a `status: blocked`
13
+ boundary. (How "blocked" is signalled is surface-specific: a `status: blocked`
14
14
  RESULT on the loop, a `blocked_*` transition on the orchestrator.)
15
15
 
16
16
  ## 1. Generated code directories
17
17
 
18
- Any path under a generated directory — `_generated/`, `gen-src/`, or whatever the
19
- repo declares as its generated tree — is off-limits. Generators own those files
20
- end-to-end; an edit there is silently overwritten on the next regeneration and
21
- leaves no trace of why.
18
+ Any path under a generated directory — `_generated/`, `gen-src/`, or whatever
19
+ the repo declares as its generated tree — is off-limits. Generators own those
20
+ files end-to-end; an edit there is silently overwritten on regeneration,
21
+ leaving no trace of why.
22
22
 
23
- - The canonical names are `_generated/` and `gen-src/`, but the repo's own
24
- declaration (in its README, a `specfuse.yaml`, or equivalent config) is
25
- authoritative. If your repo's generated directory uses a different name, treat
26
- that name with identical prohibition.
27
- - The rule applies to every file under the directory, recursively. Creating a new
28
- file inside a generated directory is still a write to that directory.
29
- - The rule applies regardless of whether the file currently exists.
23
+ - Canonical names are `_generated/` and `gen-src/`, but the repo's own
24
+ declaration (README, `specfuse.yaml`, equivalent config) is authoritative;
25
+ a differently-named generated directory gets identical treatment.
26
+ - Applies to every file under the directory recursively, including a new file
27
+ created there, and regardless of whether the file currently exists.
30
28
 
31
- When a generated file is wrong, the response is to change the spec or the generator
32
- that produced it, not the file itself. If that is outside this unit's boundary,
33
- signal blocked with the spec/generator change named.
29
+ When a generated file is wrong, change the spec or generator that produced
30
+ it, not the file itself. If that is outside this unit's boundary, signal
31
+ blocked with the spec/generator change named.
34
32
 
35
33
  ## 2. Secrets and credentials
36
34
 
37
35
  Secrets include, at minimum: API tokens, deploy keys, SSH private keys, OAuth
38
- client secrets, webhook signing secrets, database passwords, `.env` files, cloud
39
- credentials (AWS, GCP, Azure), and any file conventionally holding a credential
36
+ client secrets, webhook signing secrets, database passwords, `.env` files,
37
+ cloud credentials (AWS, GCP, Azure), and any file conventionally holding one
40
38
  (`*.pem`, `*.key`, `id_rsa*`, `credentials.json`, `.npmrc` tokens, `gh auth`
41
39
  tokens).
42
40
 
43
41
  You must not:
44
42
 
45
- - Read the contents of a secrets file. If a unit requires one, see
43
+ - Read a secrets file's contents. If a unit requires one, see
46
44
  [`security-boundaries.md`](security-boundaries.md) for the escalation path.
47
- - Write any value that looks like a credential into the RESULT block, the event
48
- log, a commit, or any artifact you produce — whether the value came from a real
49
- secret or was invented.
50
- - Echo the contents of environment variables that hold secrets. Reference them by
51
- name (`$GITHUB_TOKEN`) over reading their values.
52
- - Commit secret files to the repo under any circumstance, including as examples
53
- or fixtures.
45
+ - Write anything credential-looking into the RESULT block, event log, a
46
+ commit, or any produced artifact — whether real or invented.
47
+ - Echo secret-holding environment variables. Reference by name
48
+ (`$GITHUB_TOKEN`) over reading their values.
49
+ - Commit secret files under any circumstance, including as examples or
50
+ fixtures.
54
51
 
55
52
  ## 3. `.git/` internals
56
53
 
@@ -13,15 +13,15 @@ driver re-runs verification itself, and that is what decides done.
13
13
  ## Who reads it — emit it only when something does
14
14
 
15
15
  This block is a **machine interface**, not a report. Emit it when a program is
16
- on the other end: a work-unit session the driver dispatched (always), or a skill
17
- invoked **non-interactively** from a calling program that parses the outcome
18
- (`fix-bug` under `autofix_invoke` is the live example).
16
+ on the other end: a work-unit session the driver dispatched (always), or a
17
+ skill invoked **non-interactively** from a calling program that parses the
18
+ outcome (`fix-bug` under `autofix_invoke` is the live example).
19
19
 
20
- Do **not** emit it on an interactive run. A human who typed `/pick-feature` has
21
- no parser; the block lands as a slab to scroll past, which is the verbosity
22
- [`human-output.md`](human-output.md) exists to prevent — report to them per that
23
- rule instead. When in doubt, look at who invoked you: a slash command typed by a
24
- person is interactive; a `claude -p` dispatch is not.
20
+ Do **not** emit it on an interactive run — a human who typed `/pick-feature`
21
+ has no parser, and the block lands as a slab to scroll past, the verbosity
22
+ [`human-output.md`](human-output.md) exists to prevent. Report to them per
23
+ that rule instead. When in doubt: a slash command typed by a person is
24
+ interactive; a `claude -p` dispatch is not.
25
25
 
26
26
  ## The cycle: state intent, act, verify, report
27
27
 
@@ -33,25 +33,25 @@ cycle; this file is normative on how the loop surface reports step 4.
33
33
  the unit is not what you thought it was.
34
34
  2. **Act.** Stay inside that scope. "While I was here I also fixed X" is drift;
35
35
  the work unit's **Do not touch** section is binding.
36
- 3. **Verify.** Re-read what you produced — the Write/Edit tool reports the
37
- action it took, not the property you wanted — and run the work unit's own
38
- verification commands, in declared order, with full output. On the loop
39
- that set is the **per-attempt (narrow) tier**: the unit type's gates minus
40
- any declaring `tier: broad`, with `tests` through its `narrow_command` over
41
- the unit's `produces:` test modules. The full suite, coverage and every
42
- `tier: broad` gate are the driver's, once per gate — running them in-session
43
- buys nothing the driver does not re-run. "I assume the
44
- tests still pass" is not a verification. A behavioural claim needs a run, not
45
- a reading of the source; a rule-or-severity claim needs a **negative
46
- observation**, the rule seen rejecting a purpose-built bad input.
36
+ 3. **Verify.** Re-read what you produced — Write/Edit reports the action taken,
37
+ not the property you wanted — and run the work unit's own verification
38
+ commands, in declared order, with full output. On the loop that set is the
39
+ **per-attempt (narrow) tier**: the unit type's gates minus any declaring
40
+ `tier: broad`, with `tests` through its `narrow_command` over the unit's
41
+ `produces:` test modules. The full suite, coverage and every `tier: broad`
42
+ gate are the driver's, once per gate — running them in-session buys nothing
43
+ the driver does not re-run. "I assume the tests still pass" is not
44
+ verification. A behavioural claim needs a run, not a source reading; a
45
+ rule-or-severity claim needs a **negative observation** — the rule seen
46
+ rejecting a purpose-built bad input.
47
47
  4. **Report.** Report only what verification confirmed.
48
48
 
49
- A failing check leaves you in one of three situations: correctable locally (fix
50
- the cause, re-run the **whole narrow tier** from the top), spinning (three fresh
51
- attempts is the driver's budget — emit `status: blocked` with the evidence
52
- rather than guessing), or fundamentally blocked (a spec ambiguity, generated
53
- code that must change, a missing dependency — emit `status: blocked` naming the
54
- boundary).
49
+ A failing check leaves you in one of three situations: correctable locally
50
+ (fix the cause, re-run the **whole narrow tier** from the top), spinning
51
+ (three fresh attempts is the driver's budget — emit `status: blocked` with
52
+ evidence rather than guessing), or fundamentally blocked (spec ambiguity,
53
+ generated code that must change, a missing dependency — emit `status: blocked`
54
+ naming the boundary).
55
55
 
56
56
  ## Format
57
57
 
@@ -59,6 +59,7 @@ boundary).
59
59
  ```result
60
60
  status: complete | blocked # complete = "I believe acceptance criteria are met"
61
61
  summary: <one sentence on what changed>
62
+ forward_note: <optional — one sentence on what the NEXT unit should know>
62
63
  files_changed:
63
64
  - path/to/file
64
65
  acceptance_criteria:
@@ -72,6 +73,13 @@ produces_unchanged: # optional — closing obligation 1 below
72
73
  ```
73
74
  ````
74
75
 
76
+ `summary` is backward-looking by this contract's own definition — one sentence
77
+ on what changed. `forward_note` is the other half: what surprised you, or what
78
+ the next unit should know, that `summary` does not capture. It is optional and
79
+ never required by any guard. Omit it and nothing changes: the driver's
80
+ `PROGRESS.md` entry is exactly what it would have written without this field
81
+ (FEAT-2026-0106/T02).
82
+
75
83
  ## Rules
76
84
 
77
85
  1. **No git.** You edit files only. The driver stages, squashes, and commits one
@@ -94,29 +102,29 @@ produces_unchanged: # optional — closing obligation 1 below
94
102
  7. **A "pre-existing" failure claim cites the commit it was measured on.**
95
103
  Calling a failure pre-existing is a claim about a *different* commit —
96
104
  typically the merge-base — and nothing observed on your own branch
97
- establishes it. Name the command and the commit, give the numbers from both
98
- sides, and emit `status: blocked` rather than asserting a baseline you could
99
- not measure: a mass of errors sharing one signature (network refused,
100
- unresolvable build dependencies) is a report about where the suite ran, not
101
- about the repository (#2075).
105
+ establishes it. Name the command and commit, give the numbers from both
106
+ sides, and emit `status: blocked` rather than asserting an unmeasured
107
+ baseline: a mass of errors sharing one signature (network refused,
108
+ unresolvable build dependencies) reports where the suite ran, not the
109
+ repository (#2075).
102
110
 
103
111
  ## Closing obligations for implementation WUs (FEAT-2026-0049)
104
112
 
105
113
  1. **Diff against `produces:` first.** Every path in the WU's `produces:` list
106
114
  must show a working-tree change, or the RESULT must justify each unchanged
107
- path under `produces_unchanged:` — the entry spelled as `produces:` spells
108
- it, plus the command and output showing the deliverable already holds. The
109
- driver reads that list: a justified entry passes and is recorded on the
110
- attempt as `produces_justified`; an unjustified one, or a blank
111
- justification, is refused (#198, #3268, outcome `produces_not_in_diff`).
112
- Silence on an unchanged deliverable is not a valid close.
113
- 2. **A plan-level contradiction is `blocked`, not `complete`.** If the plan
114
- cannot be delivered as written, put the finding in `blocked_reason`; never
115
- write it into a gate document and close `complete`.
115
+ path under `produces_unchanged:` — spelled as `produces:` spells it, plus
116
+ the command and output showing the deliverable already holds. The driver
117
+ reads that list: a justified entry passes and is recorded on the attempt as
118
+ `produces_justified`; an unjustified one, or a blank justification, is
119
+ refused (#198, #3268, outcome `produces_not_in_diff`). Silence on an
120
+ unchanged deliverable is not a valid close.
121
+ 2. **A plan-level contradiction is `blocked`, not `complete`.** Put the
122
+ finding in `blocked_reason`; never write it into a gate document and close
123
+ `complete`.
116
124
  3. **Every `evidence:` cites an executed command** and its observed exit
117
- code/output. Reading source, grepping for a string, or citing another WU's
125
+ code/output. Reading source, grepping a string, or citing another WU's
118
126
  RESULT is not verification.
119
- 4. **Analysis without edits is not a silent attempt.** Say so explicitly and end
127
+ 4. **Analysis without edits is not a silent attempt.** Say so and end
120
128
  `blocked` rather than spending the attempt on prose.
121
129
 
122
130
  The driver's whole cycle — re-verify, commit, advance the dependency frontier,
@@ -12,10 +12,8 @@ lists the specific path categories that are off-limits.
12
12
 
13
13
  ## Secrets
14
14
 
15
- Secrets include API tokens, deploy keys, SSH private keys, OAuth client secrets,
16
- webhook signing secrets, database passwords, `.env` files, cloud credentials, and
17
- anything conventionally treated as a credential (see the enumeration in
18
- [`never-touch.md`](never-touch.md) §2). The posture is strict:
15
+ The full enumeration lives in [`never-touch.md`](never-touch.md) §2. The
16
+ posture here is strict:
19
17
 
20
18
  - **Never read.** Do not open a secrets file to inspect its contents, not even
21
19
  "just to see the format." If a unit's verification needs one, stop and
@@ -41,29 +39,27 @@ Treat suspected-secret values with the same care as confirmed-secret values. A
41
39
  ## When a work unit appears to require privileged access
42
40
 
43
41
  A unit whose acceptance criteria or verification commands appear to require
44
- reading a secret, editing generated code directly, or any other privileged action
45
- is almost always a unit-definition problem, not a license to break the rule.
46
-
47
- 1. **Stop.** Do not attempt the privileged action. Do not attempt to work around
48
- the requirement (for example, by running a command that reads the secret
49
- implicitly).
50
- 2. **Re-read the unit.** Verify you have understood the step correctly. Often the
51
- unit describes how the *human* will verify, with the session doing an
52
- upstream-only step.
53
- 3. **If the requirement is genuine, signal blocked.** Name the privilege
54
- required (e.g., "verification command requires reading `config/db-prod.env`")
55
- as the blocked reason. Work halts and the human decides whether to adjust the
56
- unit, run the step out-of-band, or provide a scoped credential. (The signal is
57
- surface-specific — a `status: blocked` RESULT on the loop, a `blocked_*`
58
- transition on the orchestrator.)
59
- 4. **Do not report the unit complete.** A verification that could not be run is
60
- not a verification; a unit whose verification cannot be run is not done (see
61
- [`verification-discipline.md`](verification-discipline.md)).
62
-
63
- The common mistake here is to "helpfully" substitute a weaker check for a
64
- privileged one — "I couldn't run the secret-requiring command, so I inspected the
65
- diff visually and it looks right." That is a verification-bypass, not a
66
- verification, and it produces a RESULT block the driver cannot trust.
42
+ reading a secret, editing generated code directly, or any other privileged
43
+ action is almost always a unit-definition problem, not license to break the
44
+ rule.
45
+
46
+ 1. **Stop.** Do not attempt the privileged action, or work around it (e.g. a
47
+ command that reads the secret implicitly).
48
+ 2. **Re-read the unit.** Often it describes how the *human* verifies, with the
49
+ session doing an upstream-only step.
50
+ 3. **If genuine, signal blocked.** Name the privilege required (e.g.
51
+ "verification command requires reading `config/db-prod.env`") as the
52
+ blocked reason; the human decides whether to adjust the unit, run the step
53
+ out-of-band, or provide a scoped credential. (Surface-specific — a
54
+ `status: blocked` RESULT on the loop, a `blocked_*` transition on the
55
+ orchestrator.)
56
+ 4. **Do not report complete.** A verification that could not be run is not a
57
+ verification (see [`verification-discipline.md`](verification-discipline.md)).
58
+
59
+ The common mistake is substituting a weaker check for a privileged one — "I
60
+ couldn't run the secret-requiring command, so I inspected the diff visually."
61
+ That is a verification-bypass, and it produces a RESULT block the driver
62
+ cannot trust.
67
63
 
68
64
  ## Authenticated tooling
69
65
 
@@ -40,4 +40,24 @@ Follow the shipped rules' format: one failure mode per rule, the check stated
40
40
  imperatively, provenance recorded so the reasoning survives the rule (see
41
41
  `.specfuse/rules/planning-discipline.md` for the model).
42
42
 
43
+ ## The shared word budget
44
+
45
+ The `.claude/CLAUDE.md` binding rules block a work-unit session is dispatched
46
+ against is capped at 2,500 words total, and every rule you add here counts
47
+ against that one shared budget alongside the loop's own rules — this is not a
48
+ free directory. `.specfuse/rules-local/learnings-distilled.md`, the
49
+ LEARNINGS-derived distillate, carries its own 500-word sub-budget inside that
50
+ total; its content is decided by a human accept step
51
+ (`apply_distilled_decisions` in `specfuse/loop/loop.py`) that cuts a ranked
52
+ proposal to the sub-budget, not to an entry count. Before adding an entry to
53
+ that distillate or to a rule here, check whether a guard or lint already
54
+ enforces it — if so, it does not belong in the block: the block is for what a
55
+ session must be *told*, not for what tooling already *checks*.
56
+
57
+ The ranking's `reach` field (count of other feature files citing an entry) is
58
+ a tiebreaker with an age bias, not a ranking: it inflates on its own
59
+ visibility and favors older entries. Neither `reach` nor the entry's recorded
60
+ cost measures whether the rule actually improves a session's work — that
61
+ judgment call is still the accept step's, made by reading the entry.
62
+
43
63
  This README is seeded once and never overwritten — edit it freely.
@@ -3,7 +3,7 @@
3
3
  "$id": "https://specfuse.dev/loop/schemas/driver-event.schema.json",
4
4
  "title": "Driver-local envelope registry",
5
5
  "description": "Additive to the vendored orchestrator envelope (event.schema.json): shapes the loop driver emits with no orchestrator-side counterpart. validate_event.py resolves each shape against the vendored envelope first; only when absent there does it fall through to this registry. `event_types` (FEAT-2026-0060) widens the event_type enum; task_started, task_completed, and human_escalation are already sanctioned in the vendored enum and must not be duplicated here. `correlation_id` (FEAT-2026-0073) widens the correlation_id pattern to admit the closing-sequence and hygiene shapes `.specfuse/rules/correlation-ids.md` documents; `closing_names` and `hygiene_suffix_pattern` here must state the same set of shapes as that rules file's combined pattern (and as specfuse/loop/lint_plan.py's CORRELATION_ID_RE, which independently enforces the same contract on PLAN.md graphs).",
6
- "$comment": "FEAT-2026-0060/T01: event_types derived from the union of every build_event(...) call site in specfuse/loop/loop.py and a corpus sweep of every .specfuse/features/*/events.jsonl, subtracting the vendored envelope enum. attempt_outcome and gate_reached were already-known precedent (loop.py's build_arm_predicate_event docstring); auto_close_decision, arm_predicate_evaluated, re_arm_dispatched, plan_next_draft_lint, and unsandboxed_dispatch are additional driver-local mechanics the orchestrator has no concept of. gate_auto_armed (loop.py build_event call under gate_events.append) and re_arm_rejected (loop.py build_event call under the spinning_reproduction_missing re-arm check) are emitted by real code paths that have never fired in a recorded run, so a corpus-only sweep cannot see them; they are included because call-site derivation does. FEAT-2026-0073/T01: correlation_id added — closing_names and hygiene_suffix_pattern mirror correlation-ids.md's documented shapes and lint_plan.py's CORRELATION_ID_RE verbatim, so the envelope, the rules file, and the PLAN-graph linter state one contract. FEAT-2026-0075/T03: driver_staleness_detected added — emitted at gate completion when a work unit's squash diff touched the driver's own importable surface, naming the editing unit, the driver paths it touched, and the IDs of units this process dispatched afterward (which ran the pre-edit module). FEAT-2026-0100/T02: judged added — emitted once per terminal close after the closing-deliverable guards, carrying the close's own verdict, the judge session's verdict (null when the judge was disabled, timed out, or returned nothing parseable, with the reason beside it), and whether the judge lowered it. FEAT-2026-0109/T01: baseline_attribution added — emitted when the retroactive per-attempt-failure baseline probe (attribute_failure_to_baseline) runs fresh, carrying the gate, the failing-gate set, and the unit whose failed attempt triggered the probe. FEAT-2026-0109/T06: broad_run_result added — emitted whenever the once-per-gate broad verification pass (gate_broad_run_check) actually runs (never on a tree-unchanged dedup skip), carrying the gate, the tree it was measured on, and its pass/fail outcome; a failing broad run additionally raises the existing human_escalation event type with reason: broad_run_gate_failure, which needs no schema addition since human_escalation is already sanctioned in the vendored envelope enum. FEAT-2026-0109/T08: driver_build_pinned added — emitted once per process, before any work unit is dispatched, when this process is itself a materialized pin (`_reexec_pinned`); carries the pin's tree hash and its path so an operator or test can read what build actually ran without inferring it from `ps` output. `driver_staleness_detected` needed no addition here: this unit reuses it with `halted: false` for the pinned, non-halting case (the registry constrains the type list, not the payload), adding `pinned_tree` / `next_pin_tree` fields alongside the existing `halted: true` shape.",
6
+ "$comment": "FEAT-2026-0060/T01: event_types derived from the union of every build_event(...) call site in specfuse/loop/loop.py and a corpus sweep of every .specfuse/features/*/events.jsonl, subtracting the vendored envelope enum. attempt_outcome and gate_reached were already-known precedent (loop.py's build_arm_predicate_event docstring); auto_close_decision, arm_predicate_evaluated, re_arm_dispatched, plan_next_draft_lint, and unsandboxed_dispatch are additional driver-local mechanics the orchestrator has no concept of. gate_auto_armed (loop.py build_event call under gate_events.append) and re_arm_rejected (loop.py build_event call under the spinning_reproduction_missing re-arm check) are emitted by real code paths that have never fired in a recorded run, so a corpus-only sweep cannot see them; they are included because call-site derivation does. FEAT-2026-0073/T01: correlation_id added — closing_names and hygiene_suffix_pattern mirror correlation-ids.md's documented shapes and lint_plan.py's CORRELATION_ID_RE verbatim, so the envelope, the rules file, and the PLAN-graph linter state one contract. FEAT-2026-0075/T03: driver_staleness_detected added — emitted at gate completion when a work unit's squash diff touched the driver's own importable surface, naming the editing unit, the driver paths it touched, and the IDs of units this process dispatched afterward (which ran the pre-edit module). FEAT-2026-0100/T02: judged added — emitted once per terminal close after the closing-deliverable guards, carrying the close's own verdict, the judge session's verdict (null when the judge was disabled, timed out, or returned nothing parseable, with the reason beside it), and whether the judge lowered it. FEAT-2026-0109/T01: baseline_attribution added — emitted when the retroactive per-attempt-failure baseline probe (attribute_failure_to_baseline) runs fresh, carrying the gate, the failing-gate set, and the unit whose failed attempt triggered the probe. FEAT-2026-0109/T06: broad_run_result added — emitted whenever the once-per-gate broad verification pass (gate_broad_run_check) actually runs (never on a tree-unchanged dedup skip), carrying the gate, the tree it was measured on, and its pass/fail outcome; a failing broad run additionally raises the existing human_escalation event type with reason: broad_run_gate_failure, which needs no schema addition since human_escalation is already sanctioned in the vendored envelope enum. FEAT-2026-0109/T08: driver_build_pinned added — emitted once per process, before any work unit is dispatched, when this process is itself a materialized pin (`_reexec_pinned`); carries the pin's tree hash and its path so an operator or test can read what build actually ran without inferring it from `ps` output. `driver_staleness_detected` needed no addition here: this unit reuses it with `halted: false` for the pinned, non-halting case (the registry constrains the type list, not the payload), adding `pinned_tree` / `next_pin_tree` fields alongside the existing `halted: true` shape. FEAT-2026-0104/T04: replan added — emitted once a re-plan turn (T03's run_replan_turn) rewrites a unit's body ahead of its last permitted attempt, so gate_eval.py's evaluate_auto_close (check 2, already reading this event_type since FEAT-2026-0018/T02) can disable auto-close for a gate that needed one.",
7
7
  "event_types": [
8
8
  "attempt_outcome",
9
9
  "gate_reached",
@@ -19,7 +19,8 @@
19
19
  "judged",
20
20
  "baseline_attribution",
21
21
  "broad_run_result",
22
- "driver_build_pinned"
22
+ "driver_build_pinned",
23
+ "replan"
23
24
  ],
24
25
  "correlation_id": {
25
26
  "closing_names": [
@@ -121,6 +121,12 @@
121
121
  # defaults:
122
122
  # max_attempts: 3
123
123
  # retain_on_guard_refusal: true
124
+ #
125
+ # The re-plan-after-two-failures behaviour (FEAT-2026-0104) reads this same
126
+ # `max_attempts` resolution and adds no config key of its own — a unit's
127
+ # next-to-last attempt re-plans instead of retrying verbatim, governed
128
+ # entirely by the ceiling above (or a WU's own `max_attempts`) plus that WU's
129
+ # `iterate_on_failure` flag.
124
130
 
125
131
  code:
126
132
  - name: tests
@@ -302,6 +302,34 @@ def evaluate_auto_close(feature_dir: Path, gate_id: int) -> AutoCloseDecision:
302
302
  predicate_version=PREDICATE_VERSION,
303
303
  )
304
304
 
305
+ return _evaluate_predicate_core(feature_dir, gate_id, plan, feature_id)
306
+
307
+
308
+ def evaluate_off_plan_signal(feature_dir: Path, gate_id: int) -> AutoCloseDecision:
309
+ """Same predicate as `evaluate_auto_close`, but never short-circuited by
310
+ `auto_close_disabled` (FEAT-2026-0106/T03).
311
+
312
+ `auto_close_disabled` is an operator's administrative choice to always
313
+ dispatch a close for ceremony/oracle re-run reasons
314
+ (`close-discipline.md` — a "load-bearing" close always sets it) and says
315
+ nothing about whether the gate itself deviated from plan. A caller asking
316
+ "did this gate go off plan" — as opposed to "is this gate eligible to
317
+ auto-close" — needs the real blocked/replan/cost-overrun evidence even
318
+ when that flag is set, so this skips straight to `_evaluate_predicate_core`.
319
+ """
320
+ plan = _read_plan_metrics(feature_dir)
321
+ fm = plan["frontmatter"]
322
+ feature_id = fm.get("feature_id", feature_dir.name)
323
+ return _evaluate_predicate_core(feature_dir, gate_id, plan, feature_id)
324
+
325
+
326
+ def _evaluate_predicate_core(
327
+ feature_dir: Path, gate_id: int, plan: dict, feature_id: str,
328
+ ) -> AutoCloseDecision:
329
+ """The v1 predicate itself, shared by `evaluate_auto_close` and
330
+ `evaluate_off_plan_signal` — everything after the `auto_close_disabled`
331
+ short-circuit those two apply differently.
332
+ """
305
333
  # Locate target gate in task graph
306
334
  gates = plan["gates"]
307
335
  target_gate = next((g for g in gates if g.get("gate") == gate_id), None)
@@ -167,6 +167,25 @@ def strip_forbidden_sections(text: str) -> str:
167
167
  return result
168
168
 
169
169
 
170
+ # The driver, not the close, owns terminal-flip state: `fire_terminal_flips`
171
+ # writes PLAN.md's status, the roadmap row and the gate's own status AFTER a
172
+ # judge returns, and only when the verdict is `met`. So at judge time all three
173
+ # necessarily read un-flipped, on every close of every feature.
174
+ # `GATE.template.md` nevertheless copies a criterion about them into every
175
+ # gate's definition of done, and a judge that reads it literally lowers the
176
+ # verdict -- which guarantees the state stays as found, so a re-close runs a
177
+ # fresh judge against identical evidence and reaches the identical verdict.
178
+ # FEAT-2026-0104 deadlocked there for one close (#3307). Strip the criterion
179
+ # here; `render_judge_prompt` says why, because stripping alone only stops the
180
+ # reminder -- the judge can still go and read the roadmap itself.
181
+ _DRIVER_OWNED_STATUS_CRITERION = re.compile(
182
+ r"^[ \t]*[-*][ \t]+Documentation and roadmap status[^\n]*\n?", re.M)
183
+
184
+
185
+ def _strip_driver_owned_status_criterion(text: str) -> str:
186
+ return _DRIVER_OWNED_STATUS_CRITERION.sub("", text or "")
187
+
188
+
170
189
  def _clean_evidence(text: str) -> str:
171
190
  return truncate_evidence(strip_forbidden_sections(text or ""))
172
191
 
@@ -224,7 +243,8 @@ def build_judge_bundle(
224
243
 
225
244
  return JudgeBundle(
226
245
  gate_number=gate_number,
227
- definition_of_done=_clean_evidence(definition_of_done),
246
+ definition_of_done=_clean_evidence(
247
+ _strip_driver_owned_status_criterion(definition_of_done)),
228
248
  criteria=criteria,
229
249
  diff_text=_clean_evidence(diff_text),
230
250
  measurements=_clean_evidence(measurements_text),
@@ -272,6 +292,12 @@ did not do this work and have no stake in the answer.
272
292
  one. The measurements it recorded are already below.
273
293
  5. Change nothing. You run no git command, edit no file, and fix nothing you
274
294
  find. You report.
295
+ 6. `PLAN.md`'s status, the roadmap row, and this gate's own status are not
296
+ evidence and are not yours to grade. The driver writes all three after you
297
+ return, and only if you answer `met` — so while you are looking at them they
298
+ necessarily read un-flipped, on every close of every feature. Reading one of
299
+ them as a failure is a verdict that manufactures its own evidence: it keeps
300
+ them un-flipped, and the next judge sees exactly what you saw.
275
301
 
276
302
  ## Definition of done (gate {bundle.gate_number})
277
303