specfuse-loop 0.22.2__tar.gz → 0.22.3__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 (609) hide show
  1. {specfuse_loop-0.22.2/specfuse_loop.egg-info → specfuse_loop-0.22.3}/PKG-INFO +1 -1
  2. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/pyproject.toml +1 -1
  3. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/severity_backfill.py +58 -5
  4. specfuse_loop-0.22.3/specfuse/loop/data/VERSION +1 -0
  5. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/loop.py +189 -10
  6. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/triage.py +87 -1
  7. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3/specfuse_loop.egg-info}/PKG-INFO +1 -1
  8. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/SOURCES.txt +3 -0
  9. specfuse_loop-0.22.3/tests/test_attribution_halt_claims.py +139 -0
  10. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_escalation_message.py +18 -5
  11. specfuse_loop-0.22.3/tests/test_ignored_cleanup_before_probe.py +292 -0
  12. specfuse_loop-0.22.3/tests/test_severity_backfill_end_to_end.py +215 -0
  13. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_backfill_run.py +98 -0
  14. specfuse_loop-0.22.3/tests/test_severity_reconciliation.py +177 -0
  15. specfuse_loop-0.22.2/specfuse/loop/data/VERSION +0 -1
  16. specfuse_loop-0.22.2/tests/test_severity_backfill_end_to_end.py +0 -86
  17. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/LICENSE +0 -0
  18. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/NOTICE +0 -0
  19. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/README.md +0 -0
  20. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/setup.cfg +0 -0
  21. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/__init__.py +0 -0
  22. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/budget.py +0 -0
  23. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/diagnose_invoke.py +0 -0
  24. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/drafting_answers.py +0 -0
  25. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/drafting_invoke.py +0 -0
  26. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/drafting_questions.py +0 -0
  27. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/driver_command.py +0 -0
  28. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/driver_invoke.py +0 -0
  29. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/invoke.py +0 -0
  30. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/monitoring_read.py +0 -0
  31. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/__init__.py +0 -0
  32. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/answers.py +0 -0
  33. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/bugs.py +0 -0
  34. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/feature.py +0 -0
  35. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/findings_autofix.py +0 -0
  36. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/findings_diagnose.py +0 -0
  37. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/triage.py +0 -0
  38. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/queue_read.py +0 -0
  39. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/repo_detect.py +0 -0
  40. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/run.py +0 -0
  41. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/state.py +0 -0
  42. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/triage_invoke.py +0 -0
  43. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/worktree.py +0 -0
  44. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/__init__.py +0 -0
  45. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/_filelock.py +0 -0
  46. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/_miniyaml.py +0 -0
  47. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/_wu_sections.py +0 -0
  48. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/adopt_feature.py +0 -0
  49. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/agent_policy.py +0 -0
  50. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/arm_eval.py +0 -0
  51. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/arm_sweep.py +0 -0
  52. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/arm_txn.py +0 -0
  53. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/bug_lane.py +0 -0
  54. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/bug_lane_run.py +0 -0
  55. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/bug_lane_state.py +0 -0
  56. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/build_provenance.py +0 -0
  57. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/caller_check.py +0 -0
  58. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/changelog.py +0 -0
  59. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/closing_requirements.py +0 -0
  60. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/cost.py +0 -0
  61. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/criteria_state.py +0 -0
  62. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
  63. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/LEARNINGS.template.md +0 -0
  64. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
  65. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
  66. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
  67. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
  68. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/getting-started.md +0 -0
  69. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/glossary.md +0 -0
  70. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/methodology.md +0 -0
  71. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/skills.md +0 -0
  72. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/gitignore.snippet +0 -0
  73. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
  74. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
  75. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/monitoring.yml.example +0 -0
  76. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/roadmap.template.md +0 -0
  77. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/close-discipline.md +0 -0
  78. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/correlation-ids.md +0 -0
  79. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
  80. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/human-output.md +0 -0
  81. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/never-touch.md +0 -0
  82. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/operator-escalation.md +0 -0
  83. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/planning-discipline.md +0 -0
  84. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/result-contract.md +0 -0
  85. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/security-boundaries.md +0 -0
  86. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/verification-discipline.md +0 -0
  87. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules-local/README.md +0 -0
  88. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/driver-event.schema.json +0 -0
  89. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/event.schema.json +0 -0
  90. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
  91. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
  92. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
  93. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
  94. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
  95. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/GATE.template.md +0 -0
  96. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
  97. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/PLAN.template.md +0 -0
  98. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/WU.template.md +0 -0
  99. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/verification.yml.example +0 -0
  100. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
  101. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/decisions_format.py +0 -0
  102. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/driver_edit.py +0 -0
  103. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/escalation.py +0 -0
  104. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/events_stats.py +0 -0
  105. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/gate_commands.py +0 -0
  106. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/gate_eval.py +0 -0
  107. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/gh_backend.py +0 -0
  108. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/gh_features.py +0 -0
  109. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/heartbeat.py +0 -0
  110. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/judge.py +0 -0
  111. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/labels.py +0 -0
  112. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/learnings_distil.py +0 -0
  113. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/learnings_query.py +0 -0
  114. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/lint_closing.py +0 -0
  115. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/lint_monitoring.py +0 -0
  116. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/lint_plan.py +0 -0
  117. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/lint_roadmap.py +0 -0
  118. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/notify.py +0 -0
  119. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/notify_escalation.py +0 -0
  120. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/notify_sla.py +0 -0
  121. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/plan_baseline.py +0 -0
  122. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/policy_proposals.py +0 -0
  123. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/policy_review.py +0 -0
  124. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/prerun.py +0 -0
  125. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/prerun_capture.py +0 -0
  126. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/promotion.py +0 -0
  127. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/rearm_migration.py +0 -0
  128. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/replay_spin.py +0 -0
  129. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/roadmap_archive.py +0 -0
  130. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/scaffold.py +0 -0
  131. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/upgrade_merge_gate.py +0 -0
  132. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/validate_event.py +0 -0
  133. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/__init__.py +0 -0
  134. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/adapters.py +0 -0
  135. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/artifact.py +0 -0
  136. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/autofix.py +0 -0
  137. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/autofix_invoke.py +0 -0
  138. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/autofix_run.py +0 -0
  139. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/autofix_state.py +0 -0
  140. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/cli.py +0 -0
  141. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/diagnose_cli.py +0 -0
  142. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/diagnosis.py +0 -0
  143. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/fingerprint.py +0 -0
  144. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/issues.py +0 -0
  145. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/providers/__init__.py +0 -0
  146. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/providers/_azure_auth.py +0 -0
  147. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/providers/azure_app_insights.py +0 -0
  148. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/providers/azure_service_bus.py +0 -0
  149. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/redaction.py +0 -0
  150. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/schedule.py +0 -0
  151. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/dependency_links.txt +0 -0
  152. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/entry_points.txt +0 -0
  153. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/requires.txt +0 -0
  154. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/top_level.txt +0 -0
  155. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_abandon_feature_skill.py +0 -0
  156. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_abandoned_work_reported.py +0 -0
  157. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_abandoned_wu_strands_gate.py +0 -0
  158. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_adopt_feature.py +0 -0
  159. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_budget.py +0 -0
  160. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_bug_selection_dedup.py +0 -0
  161. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_default_features_root.py +0 -0
  162. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_driver_command.py +0 -0
  163. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_driver_invoke.py +0 -0
  164. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_driver_restart.py +0 -0
  165. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_escalation_on_issue.py +0 -0
  166. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_escalation_run_state.py +0 -0
  167. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_findings_seam.py +0 -0
  168. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_invoke_timeout.py +0 -0
  169. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_invoke_usage.py +0 -0
  170. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_item_worktree.py +0 -0
  171. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_lock.py +0 -0
  172. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_policy_key_ownership.py +0 -0
  173. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_policy_queue.py +0 -0
  174. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_policy_schema.py +0 -0
  175. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_policy_triage_dial.py +0 -0
  176. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_answers.py +0 -0
  177. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_bugs.py +0 -0
  178. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_feature.py +0 -0
  179. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_findings_autofix.py +0 -0
  180. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_findings_diagnose.py +0 -0
  181. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_isolation.py +0 -0
  182. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_triage.py +0 -0
  183. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_queue_read.py +0 -0
  184. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_relays_driver_output.py +0 -0
  185. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_repo_detect.py +0 -0
  186. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_run.py +0 -0
  187. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_run_progress.py +0 -0
  188. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_seam.py +0 -0
  189. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_snapshot_refresh.py +0 -0
  190. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_state.py +0 -0
  191. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_answer_escalation_skill.py +0 -0
  192. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_app_insights_adapters.py +0 -0
  193. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_archive_ref_reconciliation.py +0 -0
  194. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_eval.py +0 -0
  195. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_eval_lint_class.py +0 -0
  196. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_eval_wiring.py +0 -0
  197. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_gate_edits_uncommitted.py +0 -0
  198. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_sweep.py +0 -0
  199. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_sweep_gate.py +0 -0
  200. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_txn.py +0 -0
  201. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_wiring.py +0 -0
  202. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_artifact_redaction.py +0 -0
  203. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attempt_note_untracked_files.py +0 -0
  204. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attempt_outcome_contract.py +0 -0
  205. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attempt_outcome_emission.py +0 -0
  206. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attention_nonwriting_guard.py +0 -0
  207. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attention_silence_section.py +0 -0
  208. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attention_skill_structure.py +0 -0
  209. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autoclose_deferral_visibility.py +0 -0
  210. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autoclose_gate_note.py +0 -0
  211. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autoclose_stub_states_what_passed.py +0 -0
  212. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_invoke.py +0 -0
  213. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_live.py +0 -0
  214. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_predicate.py +0 -0
  215. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_run.py +0 -0
  216. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_state.py +0 -0
  217. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync.py +0 -0
  218. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync_consent.py +0 -0
  219. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync_firstrun.py +0 -0
  220. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync_no_cwd_leak.py +0 -0
  221. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync_plugin.py +0 -0
  222. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_azure_credential_resolution.py +0 -0
  223. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_backend.py +0 -0
  224. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_persistence.py +0 -0
  225. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_probe.py +0 -0
  226. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_provenance.py +0 -0
  227. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_tree_hash_key.py +0 -0
  228. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bash_routing.py +0 -0
  229. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bats_suites_gated.py +0 -0
  230. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_binary_verdict.py +0 -0
  231. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_binding_block_advisory.py +0 -0
  232. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_binding_block_allocation.py +0 -0
  233. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_binding_block_budget.py +0 -0
  234. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bookkeeping_commit_crash_run.py +0 -0
  235. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
  236. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bookkeeping_no_verify.py +0 -0
  237. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_brief_covers_every_unit_escalation.py +0 -0
  238. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_ci_pending.py +0 -0
  239. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_guardrails.py +0 -0
  240. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_label_nonfatal.py +0 -0
  241. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_labels_registered.py +0 -0
  242. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_min_severity.py +0 -0
  243. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_policy_contract.py +0 -0
  244. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_pr_number_carried.py +0 -0
  245. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_preflight_and_dial.py +0 -0
  246. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_run.py +0 -0
  247. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_state.py +0 -0
  248. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
  249. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_test_paths.py +0 -0
  250. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_build_provenance.py +0 -0
  251. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_caller_check_ratchet.py +0 -0
  252. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changed_file_test_selection.py +0 -0
  253. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changelog_append_only.py +0 -0
  254. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changelog_collection.py +0 -0
  255. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changelog_release_wiring.py +0 -0
  256. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changelog_schema.py +0 -0
  257. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ci_conclusion_wait.py +0 -0
  258. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ci_runs_every_gate.py +0 -0
  259. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_claude_resolution.py +0 -0
  260. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_close_b_pending_learnings.py +0 -0
  261. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_close_records_feature_oracle.py +0 -0
  262. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_close_wu_self_reference.py +0 -0
  263. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_deliverable_guard.py +0 -0
  264. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_guard_contracts.py +0 -0
  265. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_guard_prediction.py +0 -0
  266. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_learnings_destination.py +0 -0
  267. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_requirements.py +0 -0
  268. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_coauthor_trailer_allowlist.py +0 -0
  269. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_conditional_reflection.py +0 -0
  270. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_console_encoding.py +0 -0
  271. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_convergent_iteration.py +0 -0
  272. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_convergent_wu_lint.py +0 -0
  273. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_correlation_id_override.py +0 -0
  274. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_correlation_id_two_surfaces.py +0 -0
  275. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_cost_lifetime.py +0 -0
  276. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_cost_tracking.py +0 -0
  277. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_criteria_per_gate_lint.py +0 -0
  278. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_criteria_state.py +0 -0
  279. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_criteria_worklist.py +0 -0
  280. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_decision_citation_lint.py +0 -0
  281. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_decision_followups_discharged.py +0 -0
  282. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_decision_override_lint.py +0 -0
  283. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_decisions_format.py +0 -0
  284. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_default_severity_aliases.py +0 -0
  285. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_degraded_oracle.py +0 -0
  286. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_deliverable_missing_note.py +0 -0
  287. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_deliverable_presence_gate.py +0 -0
  288. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_derive_agent_policy_review_mode.py +0 -0
  289. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_derive_agent_policy_skill.py +0 -0
  290. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_derive_monitoring_discovery.py +0 -0
  291. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_derive_monitoring_skill_registration.py +0 -0
  292. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_design_for_diagnosis_rule.py +0 -0
  293. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_deterministic_refusal_repeat.py +0 -0
  294. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_diagnose_headless.py +0 -0
  295. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_diagnose_issue_skill.py +0 -0
  296. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_diagnosis.py +0 -0
  297. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_diagnosis_roundtrip_live.py +0 -0
  298. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_dispatch_skeleton.py +0 -0
  299. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_distilled_accept_step.py +0 -0
  300. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_doctor.py +0 -0
  301. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_doctor_command_preflight.py +0 -0
  302. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_done_feature_gates.py +0 -0
  303. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_draft_feature_answers_mode.py +0 -0
  304. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_answer_gate.py +0 -0
  305. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_invoke.py +0 -0
  306. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_question_issue.py +0 -0
  307. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_questions.py +0 -0
  308. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_reply_shape.py +0 -0
  309. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_edit_detection.py +0 -0
  310. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_event_registry_covers_emitters.py +0 -0
  311. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_integration.py +0 -0
  312. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_lock.py +0 -0
  313. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_module_surface.py +0 -0
  314. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_restart_halt_surfaced.py +0 -0
  315. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_restart_halt_wiring.py +0 -0
  316. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_restart_hold.py +0 -0
  317. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_staleness_gate_summary.py +0 -0
  318. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_staleness_warning.py +0 -0
  319. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_dry_run_no_branch_mutation.py +0 -0
  320. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_duration_tracking.py +0 -0
  321. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_empty_files_escalation.py +0 -0
  322. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ensure_feature_branch.py +0 -0
  323. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ensure_feature_branch_base.py +0 -0
  324. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_assignee_policy.py +0 -0
  325. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_contract.py +0 -0
  326. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_crash_containment.py +0 -0
  327. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_dedup_search.py +0 -0
  328. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_emit.py +0 -0
  329. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_event_gate_full_envelope.py +0 -0
  330. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_events_redaction.py +0 -0
  331. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_events_stats.py +0 -0
  332. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_extra_gates.py +0 -0
  333. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_failure_artifact_model.py +0 -0
  334. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_failure_signature_fail_prefix.py +0 -0
  335. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_failure_signature_skips_log_noise.py +0 -0
  336. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_branch_auto_sync.py +0 -0
  337. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_branch_squash_merge.py +0 -0
  338. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_branch_stale_base.py +0 -0
  339. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_id_resolution.py +0 -0
  340. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_oracle_e2e.py +0 -0
  341. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_provider_drafting_dispatch.py +0 -0
  342. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_review_accumulation.py +0 -0
  343. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_filelock_portable.py +0 -0
  344. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_files_changed_auto_repair.py +0 -0
  345. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_find_pr_no_search_index.py +0 -0
  346. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fingerprint.py +0 -0
  347. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fix_bug_diff_self_check.py +0 -0
  348. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fix_bug_headless.py +0 -0
  349. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fix_bug_reads_comments.py +0 -0
  350. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fold_contract_documented.py +0 -0
  351. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_followups_artifact.py +0 -0
  352. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_force_full_close.py +0 -0
  353. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_frontmatter_scalar_quoting.py +0 -0
  354. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_broad_run.py +0 -0
  355. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_budget.py +0 -0
  356. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_budget_post_dispatch.py +0 -0
  357. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_commands_needs.py +0 -0
  358. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval.py +0 -0
  359. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval_calibration.py +0 -0
  360. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval_intermediate_wiring.py +0 -0
  361. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval_repo_flag.py +0 -0
  362. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval_terminal_wiring.py +0 -0
  363. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_report_verdict.py +0 -0
  364. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gh_backend.py +0 -0
  365. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gh_features.py +0 -0
  366. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_git_env_isolation.py +0 -0
  367. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gitleaks_pinning.py +0 -0
  368. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_groom_backlog_skill.py +0 -0
  369. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_guard_refusal_failure_class.py +0 -0
  370. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_guard_refusal_failure_excerpt.py +0 -0
  371. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_guard_repair_e2e.py +0 -0
  372. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_guard_repair_prompt.py +0 -0
  373. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_hashed_denylist.py +0 -0
  374. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_hashed_denylist_ci.py +0 -0
  375. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_heartbeat.py +0 -0
  376. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_heartbeat_adapter.py +0 -0
  377. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_human_output_rule.py +0 -0
  378. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_human_work_unit.py +0 -0
  379. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_hygiene_boundary_guidance.py +0 -0
  380. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_hyphenated_gate_name.py +0 -0
  381. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_init_integration.py +0 -0
  382. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_installed_copy_driver_e2e.py +0 -0
  383. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_interpreter_normalization.py +0 -0
  384. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_close_path.py +0 -0
  385. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_cost.py +0 -0
  386. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_cost_fold_committed.py +0 -0
  387. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_module.py +0 -0
  388. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_path_registry.py +0 -0
  389. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_terminal_flip_state.py +0 -0
  390. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_label_provisioning_runner_contract.py +0 -0
  391. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_label_registry.py +0 -0
  392. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_label_registry_covers_consumers.py +0 -0
  393. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_language_aware_narrow_selection.py +0 -0
  394. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lazy_baseline_e2e.py +0 -0
  395. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_leak_findings_redaction.py +0 -0
  396. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_leak_scan.py +0 -0
  397. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_leak_scan_content.py +0 -0
  398. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_curate_vendored_promote.py +0 -0
  399. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_distil_cli.py +0 -0
  400. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_query.py +0 -0
  401. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_staging.py +0 -0
  402. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_suggest_signature_filter.py +0 -0
  403. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_weights.py +0 -0
  404. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_legacy_4wu_terminal_flips.py +0 -0
  405. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lifecycle_integration.py +0 -0
  406. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lifetime_accounting.py +0 -0
  407. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_ac_observable.py +0 -0
  408. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_bare_produces_path.py +0 -0
  409. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_boundary_consistency.py +0 -0
  410. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_boundary_extraction.py +0 -0
  411. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_close_intermediate.py +0 -0
  412. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_close_verdict_not_predecided.py +0 -0
  413. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_close_wu.py +0 -0
  414. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_closing.py +0 -0
  415. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_closing_criteria.py +0 -0
  416. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_closing_criteria_pristine.py +0 -0
  417. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_correlation_id.py +0 -0
  418. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
  419. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_covers_load_wu_invariants.py +0 -0
  420. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_feature_oracle_declared.py +0 -0
  421. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_gate_proportionality.py +0 -0
  422. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_monitoring.py +0 -0
  423. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_oracle_env.py +0 -0
  424. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_contract_fields.py +0 -0
  425. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_errors.py +0 -0
  426. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_next_draft.py +0 -0
  427. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_relative_import.py +0 -0
  428. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_verdict_exempt.py +0 -0
  429. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_planning_sections.py +0 -0
  430. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_produces_driver_helper.py +0 -0
  431. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_produces_satisfiability.py +0 -0
  432. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_roadmap.py +0 -0
  433. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_sections.py +0 -0
  434. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_task_graph_yaml_selection.py +0 -0
  435. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_verification_reference.py +0 -0
  436. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_live_tests_opt_in.py +0 -0
  437. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_load_bearing_close_lint.py +0 -0
  438. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_attempt_evidence.py +0 -0
  439. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_auto_archive.py +0 -0
  440. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_caveman_preamble.py +0 -0
  441. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_close_intermediate.py +0 -0
  442. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_criteria_skeleton.py +0 -0
  443. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_criteria_survival.py +0 -0
  444. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_defaults_by_type.py +0 -0
  445. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_effort.py +0 -0
  446. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_failure_note_cap.py +0 -0
  447. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_files_changed_guard.py +0 -0
  448. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_gate_budget.py +0 -0
  449. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_gate_needs.py +0 -0
  450. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_model_alias.py +0 -0
  451. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_orchestration.py +0 -0
  452. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_post_pass_invariant.py +0 -0
  453. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_reset_preserving_events.py +0 -0
  454. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_smoke_runner.py +0 -0
  455. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_unsandboxed.py +0 -0
  456. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_worklist_injection.py +0 -0
  457. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_zero_token_guard.py +0 -0
  458. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_make_repo_gpgsign_isolation.py +0 -0
  459. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_marker_dual_shape.py +0 -0
  460. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_maven_failure_excerpt.py +0 -0
  461. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_max_attempts_configurable.py +0 -0
  462. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_max_open_prs.py +0 -0
  463. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_migrate_legacy.py +0 -0
  464. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_miniyaml_equivalence.py +0 -0
  465. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_miniyaml_negative.py +0 -0
  466. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitor_cli.py +0 -0
  467. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitor_issue_lifecycle.py +0 -0
  468. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitor_runner_surfaces.py +0 -0
  469. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
  470. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_cron_dialect.py +0 -0
  471. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_example.py +0 -0
  472. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_fenced_blocks.py +0 -0
  473. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_seed.py +0 -0
  474. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_narrow_fallback_warning.py +0 -0
  475. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_no_pytest_subprocess.py +0 -0
  476. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_notify.py +0 -0
  477. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_notify_escalation.py +0 -0
  478. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_notify_sla.py +0 -0
  479. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_operator_escalation_rule.py +0 -0
  480. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_oracle_set_declared.py +0 -0
  481. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_oracle_unrunnable_attribution.py +0 -0
  482. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_per_run_item_cap_disclosure.py +0 -0
  483. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pick_feature_skill.py +0 -0
  484. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pin_honesty_and_integrity.py +0 -0
  485. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pin_marker_not_inherited.py +0 -0
  486. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pin_marker_spawn_sites.py +0 -0
  487. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_plan_baseline.py +0 -0
  488. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_planned_cost_lint.py +0 -0
  489. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_planning_cost_floor.py +0 -0
  490. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_plugin_prose_cross_refs.py +0 -0
  491. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_plugin_qualified_dispatch.py +0 -0
  492. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_policy_budgets_applied.py +0 -0
  493. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_policy_proposals.py +0 -0
  494. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_policy_review.py +0 -0
  495. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pr_checks_json_field.py +0 -0
  496. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pr_reference_in_title.py +0 -0
  497. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
  498. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prep_halt_operator_surface.py +0 -0
  499. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prepare_feature.py +0 -0
  500. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prepare_scaffold_sync.py +0 -0
  501. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prerun_capture.py +0 -0
  502. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prerun_oracles.py +0 -0
  503. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prerun_wiring.py +0 -0
  504. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produced_document_verdict_guard.py +0 -0
  505. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_bracket_literal.py +0 -0
  506. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_bracket_wildcard.py +0 -0
  507. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_field.py +0 -0
  508. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_in_diff.py +0 -0
  509. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_justification.py +0 -0
  510. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_recursive_glob.py +0 -0
  511. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_semantics_unified.py +0 -0
  512. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_shape.py +0 -0
  513. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_progress_forward_note.py +0 -0
  514. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_progress_lines_end_to_end.py +0 -0
  515. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_promotion_ledger.py +0 -0
  516. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_provider_escalation_traces.py +0 -0
  517. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_provision_labels.py +0 -0
  518. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_queue_stalled_adapter.py +0 -0
  519. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_rearm_clears_stale_criteria_state.py +0 -0
  520. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_rearm_fold_marker.py +0 -0
  521. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_rearm_migration.py +0 -0
  522. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_red_baseline_never_reused.py +0 -0
  523. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_redaction_windows_home.py +0 -0
  524. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_reflection_required_signals.py +0 -0
  525. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_end_to_end.py +0 -0
  526. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_event_emission.py +0 -0
  527. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_note_collision.py +0 -0
  528. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_trigger.py +0 -0
  529. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_turn_contract.py +0 -0
  530. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replay_spin.py +0 -0
  531. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_required_checks.py +0 -0
  532. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_resolve_base.py +0 -0
  533. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_restart_cap_counts_progress.py +0 -0
  534. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_result_block.py +0 -0
  535. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_result_block_audience.py +0 -0
  536. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_resume_command_build.py +0 -0
  537. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_retain_on_guard_refusal_docs.py +0 -0
  538. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_add_skill.py +0 -0
  539. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_archive_cli.py +0 -0
  540. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_archive_shim.py +0 -0
  541. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_archive_skill.py +0 -0
  542. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_archive_skill_delegates.py +0 -0
  543. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_link_gate.py +0 -0
  544. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_row_parser.py +0 -0
  545. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ruff_verdict_lines.py +0 -0
  546. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_rule_import_convergence.py +0 -0
  547. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_run_level_failure_breaker.py +0 -0
  548. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_data_in_sync.py +0 -0
  549. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_doc_hygiene.py +0 -0
  550. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_docs.py +0 -0
  551. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_init.py +0 -0
  552. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_label_provisioning.py +0 -0
  553. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_manifest.py +0 -0
  554. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_resources.py +0 -0
  555. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_seed_sanity.py +0 -0
  556. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_skew_halts.py +0 -0
  557. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_upgrade.py +0 -0
  558. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_wiring.py +0 -0
  559. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_schedule_dialect.py +0 -0
  560. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_seed_documents_prerun_keys.py +0 -0
  561. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_service_bus_dlq_adapter.py +0 -0
  562. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_session_env_preflight.py +0 -0
  563. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_aliases.py +0 -0
  564. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_backfill_apply.py +0 -0
  565. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_backfill_limit.py +0 -0
  566. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_backfill_marker.py +0 -0
  567. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_label_projection.py +0 -0
  568. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_rubric.py +0 -0
  569. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_shipped_templates_parse.py +0 -0
  570. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_skill_discovery_links.py +0 -0
  571. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_skills_vendored_in_sync.py +0 -0
  572. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_spinning_rearm_gate.py +0 -0
  573. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_spinout_brief_end_to_end.py +0 -0
  574. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_spinout_brief_replan_option.py +0 -0
  575. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_squash_commit_hook_crash.py +0 -0
  576. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_stop_rationale_captured.py +0 -0
  577. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_stranded_halt_cause.py +0 -0
  578. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_surefire_run_level_signature.py +0 -0
  579. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_surefire_verdict_lines.py +0 -0
  580. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_template_closing_shapes.py +0 -0
  581. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_terminal_flip_ownership.py +0 -0
  582. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_terminal_flips.py +0 -0
  583. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_terminal_gate_message.py +0 -0
  584. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_tiered_verification_e2e.py +0 -0
  585. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_timeout_kill_portable.py +0 -0
  586. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage.py +0 -0
  587. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_apply.py +0 -0
  588. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_severity_classify.py +0 -0
  589. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_severity_end_to_end.py +0 -0
  590. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_severity_write.py +0 -0
  591. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_skill_contract.py +0 -0
  592. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_skips_agent_escalations.py +0 -0
  593. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_tsc_verdict_lines.py +0 -0
  594. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_umbrella_version_resolution.py +0 -0
  595. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_unterminated_frontmatter.py +0 -0
  596. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_untracked_feature_folder.py +0 -0
  597. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_untracked_file_absorption.py +0 -0
  598. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_upgrade_integration.py +0 -0
  599. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_upgrade_merge_gate.py +0 -0
  600. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_validate_event.py +0 -0
  601. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_validate_event_driver_types.py +0 -0
  602. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_verdict_coupling.py +0 -0
  603. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_verify_empty_gate_set.py +0 -0
  604. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_version_consistency.py +0 -0
  605. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_version_skew.py +0 -0
  606. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_windows_gate_exec.py +0 -0
  607. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_worktree_restore.py +0 -0
  608. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_wu_execution_metadata.py +0 -0
  609. {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/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.22.2
3
+ Version: 0.22.3
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.22.2"
7
+ version = "0.22.3"
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"
@@ -43,7 +43,7 @@ from specfuse.loop.labels import (
43
43
  severity_label_projection,
44
44
  )
45
45
 
46
- from specfuse.loop import triage
46
+ from specfuse.loop import agent_policy, triage
47
47
  from specfuse.loop.build_provenance import warn_if_out_of_tree
48
48
 
49
49
  #: Stands in for T10's classification session (gate 3, walking skeleton).
@@ -105,6 +105,7 @@ def apply_severity_backfill(
105
105
  "number": number,
106
106
  "severity": severity,
107
107
  "skipped": False,
108
+ "severity_source": decision.get("severity_source", "classifier"),
108
109
  }
109
110
 
110
111
  new_body = triage.amend_marker_severity(body, severity)
@@ -121,6 +122,16 @@ def apply_severity_backfill(
121
122
  continue
122
123
  row["marker_written"] = True
123
124
 
125
+ if decision.get("severity_source") == "label":
126
+ # Reconciled (#3360): the label IS the source of this severity, so
127
+ # it is already on the issue. Writing one would at best re-apply
128
+ # what is there and at worst add a second spelling beside the
129
+ # person's, which is the collision this path exists to avoid.
130
+ row["label_written"] = False
131
+ row["label_skipped_reason"] = "severity read from the issue's own label"
132
+ results.append(row)
133
+ continue
134
+
124
135
  label = (label_projection or {}).get(
125
136
  severity, triage.severity_label_for(severity)
126
137
  )
@@ -206,6 +217,8 @@ def run_backfill(
206
217
  ),
207
218
  }
208
219
 
220
+ aliases = agent_policy.resolve_severity_aliases()
221
+
209
222
  rows = []
210
223
  decisions = []
211
224
  for issue in candidates:
@@ -213,6 +226,31 @@ def run_backfill(
213
226
  title = issue.get("title", "")
214
227
  body = issue.get("body") or ""
215
228
 
229
+ # The label is consulted BEFORE any classification session (#3360): an
230
+ # issue a person already labelled must have its marker written from
231
+ # that label, never from a fresh opinion about it. This also means a
232
+ # reconciled issue costs no `claude` invocation at all.
233
+ action, labelled_severity, reason = triage.severity_decision(
234
+ issue.get("labels"), aliases)
235
+
236
+ if action == triage.SEVERITY_SKIP:
237
+ rows.append({
238
+ "number": number, "classified": False, "severity": None,
239
+ "severity_source": "label", "skipped_reason": reason,
240
+ })
241
+ continue
242
+
243
+ if action == triage.SEVERITY_RECONCILE:
244
+ rows.append({
245
+ "number": number, "classified": True,
246
+ "severity": labelled_severity, "severity_source": "label",
247
+ })
248
+ decisions.append({
249
+ "number": number, "body": body,
250
+ "severity": labelled_severity, "severity_source": "label",
251
+ })
252
+ continue
253
+
216
254
  argv, prompt = build_invocation(
217
255
  number, title, body, repo, working_dir, model=model, effort=effort, rubric=rubric
218
256
  )
@@ -220,11 +258,14 @@ def run_backfill(
220
258
  severity = classify_severity(invoked.text, rubric)
221
259
 
222
260
  if severity is None:
223
- rows.append({"number": number, "classified": False, "severity": None})
261
+ rows.append({"number": number, "classified": False, "severity": None,
262
+ "severity_source": "classifier"})
224
263
  continue
225
264
 
226
- rows.append({"number": number, "classified": True, "severity": severity})
227
- decisions.append({"number": number, "body": body, "severity": severity})
265
+ rows.append({"number": number, "classified": True, "severity": severity,
266
+ "severity_source": "classifier"})
267
+ decisions.append({"number": number, "body": body, "severity": severity,
268
+ "severity_source": "classifier"})
228
269
 
229
270
  if apply and decisions:
230
271
  # A property of the repository's label set, not of any one issue
@@ -271,7 +312,19 @@ def _print_run_report(report: dict) -> None:
271
312
  return
272
313
  for row in report["rows"]:
273
314
  if not row["classified"]:
274
- print(f"#{row['number']}: no usable classification, skipped")
315
+ # A refusal to overwrite a person is not a classification failure,
316
+ # and #3360's re-run condition is read off these lines: it asks for
317
+ # zero rows the run would contradict, which is unanswerable if both
318
+ # print the same sentence.
319
+ reason = row.get("skipped_reason")
320
+ if reason:
321
+ print(f"#{row['number']}: left alone — {reason}")
322
+ else:
323
+ print(f"#{row['number']}: no usable classification, skipped")
324
+ continue
325
+ if row.get("severity_source") == "label":
326
+ print(f"#{row['number']}: severity={row['severity']} "
327
+ f"(reconciled from its own label, not classified)")
275
328
  continue
276
329
  print(f"#{row['number']}: severity={row['severity']}")
277
330
 
@@ -0,0 +1 @@
1
+ 0.22.3
@@ -125,7 +125,7 @@ SPECFUSE_DIR = Path(".specfuse")
125
125
  REPO_ROOT = SPECFUSE_DIR.parent
126
126
  FEATURES_DIR = SPECFUSE_DIR / "features"
127
127
  VERIFICATION_PATH = SPECFUSE_DIR / "verification.yml"
128
- DRIVER_VERSION = "0.22.2"
128
+ DRIVER_VERSION = "0.22.3"
129
129
  # Oldest scaffold layout this driver can drive. init.sh stamps the scaffold's own
130
130
  # version into `.specfuse/VERSION`; check_scaffold_version() fails loud at startup if
131
131
  # the consumer's scaffold is older than this, pointing at `specfuse upgrade`. Bump
@@ -2244,6 +2244,34 @@ def untracked_paths() -> set[str]:
2244
2244
  return {line.strip() for line in out.splitlines() if line.strip()}
2245
2245
 
2246
2246
 
2247
+ def ignored_paths() -> set[str]:
2248
+ """Repo-relative paths git reports as IGNORED, file by file.
2249
+
2250
+ Twin of :func:`untracked_paths`, snapshotted per-WU at dispatch so the
2251
+ attempt-failure path can tell "this ignored file was already here" from
2252
+ "this attempt produced it" (#3330). A `git reset --hard` restores tracked
2253
+ content and leaves ignored files in place, so without this the baseline
2254
+ attribution probe measures the failed attempt's own build output and
2255
+ reports the failure as pre-existing.
2256
+
2257
+ `--ignored` is deliberately paired with `ls-files` rather than read off
2258
+ `git status --porcelain --ignored`: status collapses a wholly-ignored
2259
+ directory to a single entry, so `!! out/` is byte-identical before and
2260
+ after an attempt adds files underneath it. That is precisely the reported
2261
+ case -- `out/` already existed and the attempt wrote 11 new files into it --
2262
+ and a snapshot diff over the status listing would have seen nothing.
2263
+
2264
+ Can be large on a repository carrying vendored dependency trees, so it is
2265
+ called only on the failure path that actually probes, where it is cheap
2266
+ beside the full gate-set run it precedes.
2267
+ """
2268
+ out = subprocess.run(
2269
+ ["git", "ls-files", "--others", "--ignored", "--exclude-standard"],
2270
+ capture_output=True, text=True, check=True,
2271
+ ).stdout
2272
+ return {line.strip() for line in out.splitlines() if line.strip()}
2273
+
2274
+
2247
2275
  def _tracked_dirty_paths() -> set[str]:
2248
2276
  """Paths with TRACKED, uncommitted changes (staged or unstaged), repo-relative.
2249
2277
 
@@ -3787,10 +3815,70 @@ def _clean_attempt_untracked(
3787
3815
  continue
3788
3816
 
3789
3817
 
3818
+ #: Ignored path prefixes the attempt-ignored clean never deletes. `work/` holds
3819
+ #: the per-attempt verify-output notes `persist_attempt_notes` writes (#168) --
3820
+ #: gitignored, and written AFTER the reset, so at the next attempt's reset they
3821
+ #: look exactly like the build output this clean exists to remove. The snapshot
3822
+ #: is taken once per WU rather than per attempt, so without this keep-list
3823
+ #: attempt 2 would delete attempt 1's evidence.
3824
+ IGNORED_CLEAN_KEEP_PREFIXES = ("work/", ".specfuse/")
3825
+
3826
+
3827
+ def _clean_attempt_ignored(
3828
+ ignored_before: "set[str] | frozenset[str]", events_path: Path,
3829
+ ) -> None:
3830
+ """Delete gitignored files that appeared since the *ignored_before* snapshot.
3831
+
3832
+ Defect 1 of #3330. `_clean_attempt_untracked` above deliberately leaves
3833
+ ignored paths alone, and that carve-out is load-bearing -- the driver's own
3834
+ gitignored `work/` notes have to survive the reset. But it also leaves the
3835
+ failed attempt's build output on disk, and the baseline attribution probe
3836
+ then runs against it: in the reported incident a unit's own generated files
3837
+ failed the probe, and the driver concluded the failure predated the feature
3838
+ and halted a green branch.
3839
+
3840
+ Only files that appeared SINCE the snapshot are removed, which is what makes
3841
+ this safe for the expensive case raised on #3371: a build cache present at
3842
+ dispatch is in the snapshot and is never touched. Only what this attempt
3843
+ produced goes.
3844
+
3845
+ Never deletes: paths in *ignored_before*, anything under
3846
+ `IGNORED_CLEAN_KEEP_PREFIXES`, *events_path*, or a per-criterion close-state
3847
+ file -- the same exclusions its untracked twin honours.
3848
+
3849
+ Best-effort: any git or filesystem error is swallowed, reverting to the old
3850
+ leftover behaviour rather than crashing the run.
3851
+ """
3852
+ try:
3853
+ root = Path(git("rev-parse", "--show-toplevel"))
3854
+ candidates = ignored_paths() - set(ignored_before)
3855
+ except (subprocess.CalledProcessError, OSError):
3856
+ return
3857
+ try:
3858
+ keep = events_path.resolve()
3859
+ except OSError:
3860
+ keep = None
3861
+ for rel in sorted(candidates):
3862
+ if any(rel.startswith(p) or f"/{p}" in rel
3863
+ for p in IGNORED_CLEAN_KEEP_PREFIXES):
3864
+ continue
3865
+ target = root / rel
3866
+ try:
3867
+ if keep is not None and target.resolve() == keep:
3868
+ continue
3869
+ if criteria_state.CRITERIA_FILENAME_RE.match(target.name):
3870
+ continue
3871
+ if target.is_file() or target.is_symlink():
3872
+ target.unlink()
3873
+ except OSError:
3874
+ continue
3875
+
3876
+
3790
3877
  def reset_preserving_events(
3791
3878
  head_before: str,
3792
3879
  events_path: Path,
3793
3880
  untracked_before: "set[str] | frozenset[str] | None" = None,
3881
+ ignored_before: "set[str] | frozenset[str] | None" = None,
3794
3882
  ) -> None:
3795
3883
  """`git reset --hard <head_before>` without losing events.jsonl content.
3796
3884
 
@@ -3828,6 +3916,12 @@ def reset_preserving_events(
3828
3916
  nothing untracked" and delete the entire untracked working tree; `None`
3829
3917
  means "no snapshot available, do not clean" and preserves the pre-#162
3830
3918
  behavior for callers that cannot supply one.
3919
+
3920
+ `ignored_before` (#3330 defect 1) does the same for GITIGNORED paths, and
3921
+ is supplied by the one call site whose reset is followed by the baseline
3922
+ attribution probe. Same inert-on-`None` contract. It is not passed on every
3923
+ reset: the listing it diffs walks ignored trees, which is cheap beside the
3924
+ gate-set run the probe performs and not worth paying where nothing probes.
3831
3925
  """
3832
3926
  saved = events_path.read_text() if events_path.is_file() else None
3833
3927
  git("reset", "--hard", head_before)
@@ -3835,6 +3929,8 @@ def reset_preserving_events(
3835
3929
  events_path.write_text(saved)
3836
3930
  if untracked_before is not None:
3837
3931
  _clean_attempt_untracked(untracked_before, events_path)
3932
+ if ignored_before is not None:
3933
+ _clean_attempt_ignored(ignored_before, events_path)
3838
3934
 
3839
3935
 
3840
3936
  def retain_tree_after_refusal(head_before: str, events_path: Path) -> str:
@@ -6485,6 +6581,7 @@ def baseline_evidence_diffstat(feat_fm: dict) -> "str | None":
6485
6581
  def format_preexisting_gate_failure(
6486
6582
  gate_number: int, failing_gates: list[dict], feat_fm: dict,
6487
6583
  done_unit_ids: "list[str] | None" = None,
6584
+ attributed_to: "str | None" = None,
6488
6585
  ) -> str:
6489
6586
  """Render the `preexisting_gate_failure` halt as a message a non-expert
6490
6587
  operator can act on without reading driver source (FEAT-2026-0051/T03).
@@ -6497,6 +6594,22 @@ def format_preexisting_gate_failure(
6497
6594
  defer the feature. There is no "proceed anyway" option in v1: the waiver
6498
6595
  is future work tracked as FEAT-2026-0052, never offered here as if it
6499
6596
  already existed.
6597
+
6598
+ `attributed_to` names the work unit whose failed attempt triggered the
6599
+ probe (#3330 defect 2). This message was written for a gate-entry probe,
6600
+ where "zero work units were dispatched" was true; FEAT-2026-0109/T01 then
6601
+ removed that probe, leaving attribution as the only path that renders it --
6602
+ and on that path a unit *was* dispatched and its failure is what caused the
6603
+ re-run. Left unsaid, every fresh-gate claim here is false exactly when the
6604
+ message is shown.
6605
+
6606
+ The proof is softened on every path (#3371). A `git diff --stat` compares
6607
+ TRACKED files, so it cannot see a check's gitignored inputs; `git reset
6608
+ --hard` restores tracked files and leaves ignored ones behind, which is how
6609
+ a failed attempt's own build output ends up failing the probe that is
6610
+ supposed to exonerate it. Stating "the failure predates this feature" from
6611
+ that diff reads as conclusive and cost one reported incident a bisect
6612
+ across three commits.
6500
6613
  """
6501
6614
  # A RESUMED gate -- one where work units already ran and committed -- has a
6502
6615
  # baseline that INCLUDES this feature's own landed work, so the fresh-gate
@@ -6505,8 +6618,17 @@ def format_preexisting_gate_failure(
6505
6618
  # that a previous unit of the same gate had added two commits earlier.
6506
6619
  done_unit_ids = list(done_unit_ids or [])
6507
6620
  resumed = bool(done_unit_ids)
6621
+ attributed = bool(attributed_to) and not resumed
6508
6622
 
6509
- if resumed:
6623
+ if attributed:
6624
+ lines = [
6625
+ f"Gate {gate_number} is blocked: the automated checks it depends "
6626
+ f"on failed on a probe the driver ran AFTER {attributed_to}'s "
6627
+ f"attempt failed and its changes were reset.",
6628
+ "",
6629
+ "Failing check(s) found by that probe:",
6630
+ ]
6631
+ elif resumed:
6510
6632
  lines = [
6511
6633
  f"Gate {gate_number} is blocked: the automated checks it depends on "
6512
6634
  f"are failing, and this gate has ALREADY LANDED WORK.",
@@ -6526,7 +6648,14 @@ def format_preexisting_gate_failure(
6526
6648
  f"(signature: {g['failure_signature']})"
6527
6649
  )
6528
6650
  lines.append("")
6529
- if resumed:
6651
+ if attributed:
6652
+ lines.append(
6653
+ f"{attributed_to} WAS dispatched and its attempt failed. The "
6654
+ f"driver then reset the tree and re-ran the checks to ask whether "
6655
+ f"the failure predated that attempt; the result above is what "
6656
+ f"that probe found."
6657
+ )
6658
+ elif resumed:
6530
6659
  lines.append(
6531
6660
  f"{len(done_unit_ids)} work unit(s) in this gate are already `done` "
6532
6661
  f"and committed, so the baseline these checks measured includes this "
@@ -6554,12 +6683,16 @@ def format_preexisting_gate_failure(
6554
6683
  )
6555
6684
  else:
6556
6685
  lines.append(
6557
- "Proof the failing check(s)' input files are unchanged vs "
6558
- "the integration branch (so the failure predates this "
6559
- "feature; the diff below is the feature's own plan/scaffold "
6560
- "files, not code the failing check(s) read):"
6686
+ "The failing check(s)' TRACKED input files are unchanged vs "
6687
+ "the integration branch (the diff below is the feature's own "
6688
+ "plan/scaffold files, not code the failing check(s) read):"
6561
6689
  )
6562
6690
  lines.append(diffstat)
6691
+ elif attributed:
6692
+ lines.append(
6693
+ "Base-tree comparison unavailable (no integration branch could "
6694
+ "be resolved, or the comparison itself failed)."
6695
+ )
6563
6696
  else:
6564
6697
  lines.append(
6565
6698
  "Base-tree comparison unavailable (no integration branch could "
@@ -6567,9 +6700,41 @@ def format_preexisting_gate_failure(
6567
6700
  "check(s) above were still measured before any work unit ran, "
6568
6701
  "so the conclusion stands even without this proof."
6569
6702
  )
6703
+ if not resumed:
6704
+ # The limit of the proof above, stated wherever it is offered (#3371).
6705
+ # A tracked diff is consistent with BOTH "pre-existing" and "left
6706
+ # behind by this run", so naming what it cannot see is the difference
6707
+ # between a reader checking `out/` first and bisecting the branch.
6708
+ lines.append("")
6709
+ lines.append(
6710
+ "What that comparison does NOT cover: untracked and gitignored "
6711
+ "paths. `git reset --hard` restores tracked files and leaves "
6712
+ "ignored ones in place, so a check that reads a build or output "
6713
+ "directory (`out/`, `target/`, generated-code trees, caches) can "
6714
+ "fail on state this feature's own failed attempt produced. The "
6715
+ "diff above cannot distinguish that from pre-existing breakage."
6716
+ )
6570
6717
  lines.append("")
6571
6718
  lines.append("What to do next:")
6572
- if resumed:
6719
+ if attributed:
6720
+ lines.append(
6721
+ " 1. Check for leftover untracked/ignored state from the reset "
6722
+ "attempt FIRST — it is the cheapest to rule out and the most "
6723
+ "likely cause. `git status --ignored --short` and `git clean -ndX` "
6724
+ "list what survived; if a listed path feeds a failing check, that "
6725
+ "is your answer."
6726
+ )
6727
+ lines.append(
6728
+ " 2. Only if the tree is clean of those is this pre-existing "
6729
+ "debt — confirm by running the failing check(s) on the "
6730
+ "integration branch in a fresh checkout before assuming it."
6731
+ )
6732
+ lines.append(
6733
+ f" 3. If it was leftover state, remove it and re-run; "
6734
+ f"{attributed_to} is back at its previous attempt count and will "
6735
+ f"be retried."
6736
+ )
6737
+ elif resumed:
6573
6738
  lines.append(
6574
6739
  " 1. Find which of this gate's landed work units introduced the "
6575
6740
  "failing check, and fix it ON THIS BRANCH. `git log -S<signature> "
@@ -10671,6 +10836,13 @@ def run(
10671
10836
  # (#150). Captured here, not inside squash_commit, because by
10672
10837
  # then the agent's own new files are indistinguishable from it.
10673
10838
  untracked_before = untracked_paths()
10839
+ # Ignored counterpart (#3330 defect 1), taken in the same
10840
+ # breath: only the attempt-failure reset that precedes the
10841
+ # baseline attribution probe consumes it, but it has to be
10842
+ # captured HERE, before the agent runs, or the attempt's own
10843
+ # build output is already indistinguishable from what was
10844
+ # on disk when it started.
10845
+ ignored_before = ignored_paths()
10674
10846
  _is_rearm = detect_rearm_dispatch(wu)
10675
10847
  if _is_rearm:
10676
10848
  fold_cumulative_on_rearm(wu, backend)
@@ -11646,9 +11818,15 @@ def run(
11646
11818
  untracked_before=untracked_before)
11647
11819
  print(" no FINDINGS metric — reset to base")
11648
11820
  else:
11821
+ # `ignored_before` is passed HERE and nowhere else: this
11822
+ # is the one reset whose tree is then measured by the
11823
+ # attribution probe below, so it is the one place where
11824
+ # the attempt's own gitignored output would be read as
11825
+ # pre-existing breakage (#3330 defect 1).
11649
11826
  reset_preserving_events(
11650
11827
  head_before, events_path,
11651
- untracked_before=untracked_before)
11828
+ untracked_before=untracked_before,
11829
+ ignored_before=ignored_before)
11652
11830
  # Retroactive baseline attribution (FEAT-2026-0109/T01):
11653
11831
  # decide, right after the reset above restores the
11654
11832
  # tree the unit was dispatched against, whether this
@@ -11685,7 +11863,8 @@ def run(
11685
11863
  gate.number, _attr_failing, feat_fm,
11686
11864
  done_unit_ids=[
11687
11865
  u.wu_id for u in units
11688
- if u.status == "done"]))
11866
+ if u.status == "done"],
11867
+ attributed_to=wu.wu_id))
11689
11868
  wu_events.append(build_event(
11690
11869
  "human_escalation", feature_id, {
11691
11870
  "reason": "preexisting_gate_failure",
@@ -25,7 +25,11 @@ import json
25
25
  import re
26
26
  from typing import Callable, Optional
27
27
 
28
- from specfuse.loop.agent_policy import SEVERITY_LABEL_PREFIX
28
+ from specfuse.loop.agent_policy import (
29
+ SEVERITY_LABEL_PREFIX,
30
+ SEVERITY_VALUES,
31
+ read_severity_label,
32
+ )
29
33
  from specfuse.loop.escalation import CATEGORY_LABELS, NEEDS_HUMAN_LABEL
30
34
  from specfuse.monitor.issues import DEFAULT_LIST_LIMIT, has_finding_marker
31
35
 
@@ -359,6 +363,88 @@ def list_untriaged(runner: Callable, repo: str, limit: int = DEFAULT_LIST_LIMIT)
359
363
  _BACKFILL_PAGE_SIZE = DEFAULT_LIST_LIMIT
360
364
 
361
365
 
366
+ #: What a backfill run should do with one candidate's severity (#3360).
367
+ SEVERITY_CLASSIFY = "classify"
368
+ SEVERITY_RECONCILE = "reconcile"
369
+ SEVERITY_SKIP = "skip"
370
+
371
+
372
+ def _severity_label_names(labels) -> list:
373
+ """The `severity:*` label names on an issue, however `labels` is shaped.
374
+
375
+ `gh issue list --json ...,labels` yields `{"name": ...}` mappings; callers
376
+ holding bare strings are accepted too so the decision below stays testable
377
+ without a fixture shape.
378
+ """
379
+ names = []
380
+ for label in labels or ():
381
+ name = label.get("name") if isinstance(label, dict) else label
382
+ text = str(name or "").strip().lower()
383
+ if text.startswith(SEVERITY_LABEL_PREFIX):
384
+ names.append(text)
385
+ return names
386
+
387
+
388
+ def severity_decision(labels, aliases: Optional[dict] = None) -> tuple:
389
+ """`(action, severity, reason)` for one backfill candidate (#3360).
390
+
391
+ A candidate is selected on its MARKER -- already triaged, no `severity=`
392
+ field. That predicate never looked at the issue's labels, so an issue a
393
+ person had already labelled `severity:minor` was still a candidate: it got
394
+ a fresh classification, and the write path added a second severity label
395
+ beside the human's. `read_severity_label` then returns whichever it
396
+ recognises first, which is the agent silently overriding a person at the
397
+ `min_severity` floor.
398
+
399
+ So the label is consulted first, and when it states a severity the marker is
400
+ written FROM it:
401
+
402
+ * `SEVERITY_RECONCILE` -- the labels agree on one value. The issue stops
403
+ being stranded *and* the person's judgement is what gets recorded. No
404
+ classification session is spent, and no label is written, because the
405
+ label is already there and is the source.
406
+ * `SEVERITY_CLASSIFY` -- no `severity:*` label at all. The original path.
407
+ * `SEVERITY_SKIP` -- the labels resolve to more than one value (the
408
+ operator's own ambiguity), or a `severity:*` label is present that
409
+ nothing can read. Classifying either would put a second, readable label
410
+ beside one a human chose, which is the collision in a different spelling.
411
+
412
+ This was latent when FEAT-2026-0113 closed: the measured repository's
413
+ `critical`/`major`/`minor` scheme yielded a one-entry rubric, so the
414
+ classifier failed closed on exactly the issues that would have collided.
415
+ Shipping the default alias table (#3355) made that scheme readable, which
416
+ removed the mask rather than the hazard.
417
+ """
418
+ names = _severity_label_names(labels)
419
+ if not names:
420
+ return (SEVERITY_CLASSIFY, None, None)
421
+
422
+ resolved = set()
423
+ unreadable = []
424
+ for name in names:
425
+ value, _aliased_from = read_severity_label([name], aliases)
426
+ if value in SEVERITY_VALUES:
427
+ resolved.add(value)
428
+ else:
429
+ unreadable.append(name)
430
+
431
+ if len(resolved) > 1:
432
+ return (
433
+ SEVERITY_SKIP,
434
+ None,
435
+ f"labels resolve to more than one severity ({', '.join(sorted(resolved))}) "
436
+ f"— the marker is left alone rather than picking one",
437
+ )
438
+ if not resolved:
439
+ return (
440
+ SEVERITY_SKIP,
441
+ None,
442
+ f"carries {', '.join(sorted(unreadable))}, which no vocabulary value "
443
+ f"or alias reads — a person's judgement this run cannot interpret",
444
+ )
445
+ return (SEVERITY_RECONCILE, resolved.pop(), None)
446
+
447
+
362
448
  def _is_backfill_candidate(issue: dict) -> bool:
363
449
  body = issue.get("body") or ""
364
450
  fields = parse_marker_fields(body)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfuse-loop
3
- Version: 0.22.2
3
+ Version: 0.22.3
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
@@ -196,6 +196,7 @@ tests/test_attempt_outcome_emission.py
196
196
  tests/test_attention_nonwriting_guard.py
197
197
  tests/test_attention_silence_section.py
198
198
  tests/test_attention_skill_structure.py
199
+ tests/test_attribution_halt_claims.py
199
200
  tests/test_autoclose_deferral_visibility.py
200
201
  tests/test_autoclose_gate_note.py
201
202
  tests/test_autoclose_stub_states_what_passed.py
@@ -369,6 +370,7 @@ tests/test_human_output_rule.py
369
370
  tests/test_human_work_unit.py
370
371
  tests/test_hygiene_boundary_guidance.py
371
372
  tests/test_hyphenated_gate_name.py
373
+ tests/test_ignored_cleanup_before_probe.py
372
374
  tests/test_init_integration.py
373
375
  tests/test_installed_copy_driver_e2e.py
374
376
  tests/test_interpreter_normalization.py
@@ -558,6 +560,7 @@ tests/test_severity_backfill_limit.py
558
560
  tests/test_severity_backfill_marker.py
559
561
  tests/test_severity_backfill_run.py
560
562
  tests/test_severity_label_projection.py
563
+ tests/test_severity_reconciliation.py
561
564
  tests/test_severity_rubric.py
562
565
  tests/test_shipped_templates_parse.py
563
566
  tests/test_skill_discovery_links.py