specfuse-loop 0.28.2__tar.gz → 0.29.1__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 (682) hide show
  1. {specfuse_loop-0.28.2/specfuse_loop.egg-info → specfuse_loop-0.29.1}/PKG-INFO +1 -1
  2. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/pyproject.toml +1 -1
  3. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/diagnose_invoke.py +6 -2
  4. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/invoke.py +14 -3
  5. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/providers/findings_autofix.py +26 -2
  6. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/providers/findings_diagnose.py +80 -15
  7. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/providers/triage.py +13 -6
  8. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/run.py +45 -2
  9. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/triage_invoke.py +25 -0
  10. specfuse_loop-0.29.1/specfuse/loop/data/VERSION +1 -0
  11. specfuse_loop-0.29.1/specfuse/loop/data/docs/concepts/monitoring-runners.md +199 -0
  12. specfuse_loop-0.29.1/specfuse/loop/data/docs/concepts/monitoring-schema.md +211 -0
  13. specfuse_loop-0.29.1/specfuse/loop/data/docs/concepts/monitoring-to-fix.md +249 -0
  14. specfuse_loop-0.29.1/specfuse/loop/data/docs/flows.html +519 -0
  15. specfuse_loop-0.29.1/specfuse/loop/data/docs/lifecycles.md +394 -0
  16. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/gitignore.snippet +2 -0
  17. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/escalation.py +65 -0
  18. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/labels.py +8 -0
  19. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/loop.py +41 -4
  20. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/scaffold.py +13 -3
  21. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/triage.py +34 -13
  22. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/artifact.py +11 -0
  23. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/cli.py +154 -3
  24. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/diagnose_cli.py +6 -0
  25. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/diagnosis.py +31 -1
  26. specfuse_loop-0.29.1/specfuse/monitor/issues.py +572 -0
  27. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/providers/azure_app_insights.py +377 -32
  28. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/providers/azure_service_bus.py +157 -1
  29. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/redaction.py +6 -0
  30. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1/specfuse_loop.egg-info}/PKG-INFO +1 -1
  31. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse_loop.egg-info/SOURCES.txt +22 -0
  32. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_invoke_usage.py +2 -2
  33. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_app_insights_query_schema_check.py +38 -2
  34. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_app_insights_workspace_schema.py +6 -2
  35. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_spend.py +3 -3
  36. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_caller_check_ratchet.py +0 -1
  37. specfuse_loop-0.29.1/tests/test_closed_escalation_labels.py +148 -0
  38. specfuse_loop-0.29.1/tests/test_diagnosis_severity_end_to_end.py +191 -0
  39. specfuse_loop-0.29.1/tests/test_diagnosis_severity_rubric.py +41 -0
  40. specfuse_loop-0.29.1/tests/test_floor_skip_summary.py +94 -0
  41. specfuse_loop-0.29.1/tests/test_flows_page.py +94 -0
  42. specfuse_loop-0.29.1/tests/test_gate_log_size_budget.py +67 -0
  43. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_heartbeat_adapter.py +70 -4
  44. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_init_integration.py +5 -0
  45. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_label_registry.py +4 -2
  46. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitor_check_isolation.py +2 -0
  47. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitor_cli.py +10 -1
  48. specfuse_loop-0.29.1/tests/test_monitor_diagnose_auto_warning.py +120 -0
  49. specfuse_loop-0.29.1/tests/test_monitor_finding_context_end_to_end.py +463 -0
  50. specfuse_loop-0.29.1/tests/test_monitor_finding_lifecycle_end_to_end.py +268 -0
  51. specfuse_loop-0.29.1/tests/test_monitor_finding_meta.py +208 -0
  52. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitor_issue_lifecycle.py +17 -12
  53. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitor_one_issue_per_fingerprint.py +2 -0
  54. specfuse_loop-0.29.1/tests/test_monitor_quiet_annotation.py +189 -0
  55. specfuse_loop-0.29.1/tests/test_rearm_close_broad_run.py +124 -0
  56. specfuse_loop-0.29.1/tests/test_rediagnose_on_reopen.py +151 -0
  57. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_data_in_sync.py +5 -0
  58. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_docs.py +5 -0
  59. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_init.py +5 -0
  60. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_resources.py +5 -0
  61. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_wiring.py +7 -1
  62. specfuse_loop-0.29.1/tests/test_spend_counts_cache_tokens.py +62 -0
  63. specfuse_loop-0.29.1/tests/test_triage_reads_comments.py +111 -0
  64. specfuse_loop-0.29.1/tests/test_triage_severity_label_conflict.py +165 -0
  65. specfuse_loop-0.29.1/tests/test_upgrade_gitignore_lines.py +64 -0
  66. specfuse_loop-0.28.2/specfuse/loop/data/VERSION +0 -1
  67. specfuse_loop-0.28.2/specfuse/monitor/issues.py +0 -303
  68. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/LICENSE +0 -0
  69. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/NOTICE +0 -0
  70. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/README.md +0 -0
  71. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/setup.cfg +0 -0
  72. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/__init__.py +0 -0
  73. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/budget.py +0 -0
  74. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/drafting_answers.py +0 -0
  75. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/drafting_invoke.py +0 -0
  76. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/drafting_questions.py +0 -0
  77. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/driver_command.py +0 -0
  78. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/driver_invoke.py +0 -0
  79. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/monitoring_read.py +0 -0
  80. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/providers/__init__.py +0 -0
  81. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/providers/answers.py +0 -0
  82. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/providers/bugs.py +0 -0
  83. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/providers/feature.py +0 -0
  84. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/queue_read.py +0 -0
  85. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/repo_detect.py +0 -0
  86. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/severity_backfill.py +0 -0
  87. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/state.py +0 -0
  88. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/agent/worktree.py +0 -0
  89. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/__init__.py +0 -0
  90. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/_filelock.py +0 -0
  91. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/_miniyaml.py +0 -0
  92. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/_wu_sections.py +0 -0
  93. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/adopt_feature.py +0 -0
  94. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/agent_policy.py +0 -0
  95. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/arm_eval.py +0 -0
  96. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/arm_sweep.py +0 -0
  97. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/arm_txn.py +0 -0
  98. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/bug_lane.py +0 -0
  99. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/bug_lane_run.py +0 -0
  100. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/bug_lane_state.py +0 -0
  101. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/build_provenance.py +0 -0
  102. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/caller_check.py +0 -0
  103. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/changelog.py +0 -0
  104. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/closing_requirements.py +0 -0
  105. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/cost.py +0 -0
  106. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/criteria_state.py +0 -0
  107. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
  108. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/LEARNINGS.template.md +0 -0
  109. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
  110. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
  111. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
  112. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
  113. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/docs/getting-started.md +0 -0
  114. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/docs/glossary.md +0 -0
  115. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/docs/methodology.md +0 -0
  116. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/docs/skills.md +0 -0
  117. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
  118. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
  119. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/monitoring.yml.example +0 -0
  120. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/roadmap.template.md +0 -0
  121. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/close-discipline.md +0 -0
  122. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/correlation-ids.md +0 -0
  123. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
  124. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/human-output.md +0 -0
  125. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/never-touch.md +0 -0
  126. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/operator-escalation.md +0 -0
  127. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/planning-discipline.md +0 -0
  128. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/result-contract.md +0 -0
  129. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/security-boundaries.md +0 -0
  130. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules/verification-discipline.md +0 -0
  131. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/rules-local/README.md +0 -0
  132. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/schemas/driver-event.schema.json +0 -0
  133. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/schemas/event.schema.json +0 -0
  134. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
  135. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
  136. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
  137. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
  138. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
  139. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/templates/GATE.template.md +0 -0
  140. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
  141. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/templates/PLAN.template.md +0 -0
  142. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/templates/WU.template.md +0 -0
  143. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/verification.yml.example +0 -0
  144. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
  145. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/decisions_format.py +0 -0
  146. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/driver_edit.py +0 -0
  147. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/events_stats.py +0 -0
  148. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/gate_commands.py +0 -0
  149. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/gate_eval.py +0 -0
  150. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/gh_backend.py +0 -0
  151. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/gh_features.py +0 -0
  152. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/heartbeat.py +0 -0
  153. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/judge.py +0 -0
  154. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/learnings_distil.py +0 -0
  155. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/learnings_query.py +0 -0
  156. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/lint_closing.py +0 -0
  157. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/lint_monitoring.py +0 -0
  158. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/lint_plan.py +0 -0
  159. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/lint_roadmap.py +0 -0
  160. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/notify.py +0 -0
  161. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/notify_escalation.py +0 -0
  162. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/notify_sla.py +0 -0
  163. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/plan_baseline.py +0 -0
  164. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/policy_proposals.py +0 -0
  165. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/policy_review.py +0 -0
  166. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/prerun.py +0 -0
  167. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/prerun_capture.py +0 -0
  168. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/promotion.py +0 -0
  169. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/rearm_migration.py +0 -0
  170. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/red_on_base.py +0 -0
  171. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/replay_spin.py +0 -0
  172. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/roadmap_archive.py +0 -0
  173. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/upgrade_merge_gate.py +0 -0
  174. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/loop/validate_event.py +0 -0
  175. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/__init__.py +0 -0
  176. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/adapters.py +0 -0
  177. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/autofix.py +0 -0
  178. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/autofix_invoke.py +0 -0
  179. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/autofix_run.py +0 -0
  180. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/autofix_state.py +0 -0
  181. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/durations.py +0 -0
  182. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/fingerprint.py +0 -0
  183. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/providers/__init__.py +0 -0
  184. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/providers/_azure_auth.py +0 -0
  185. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse/monitor/schedule.py +0 -0
  186. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse_loop.egg-info/dependency_links.txt +0 -0
  187. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse_loop.egg-info/entry_points.txt +0 -0
  188. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse_loop.egg-info/requires.txt +0 -0
  189. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/specfuse_loop.egg-info/top_level.txt +0 -0
  190. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_abandon_feature_skill.py +0 -0
  191. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_abandoned_work_reported.py +0 -0
  192. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_abandoned_wu_strands_gate.py +0 -0
  193. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_adopt_feature.py +0 -0
  194. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_budget.py +0 -0
  195. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_bug_selection_dedup.py +0 -0
  196. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_default_features_root.py +0 -0
  197. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_driver_command.py +0 -0
  198. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_driver_invoke.py +0 -0
  199. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_driver_restart.py +0 -0
  200. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_escalation_on_issue.py +0 -0
  201. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_escalation_run_state.py +0 -0
  202. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_findings_seam.py +0 -0
  203. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_invoke_timeout.py +0 -0
  204. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_item_worktree.py +0 -0
  205. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_lock.py +0 -0
  206. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_policy_key_ownership.py +0 -0
  207. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_policy_queue.py +0 -0
  208. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_policy_schema.py +0 -0
  209. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_policy_triage_dial.py +0 -0
  210. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_provider_answers.py +0 -0
  211. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_provider_bugs.py +0 -0
  212. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_provider_feature.py +0 -0
  213. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_provider_findings_autofix.py +0 -0
  214. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_provider_findings_diagnose.py +0 -0
  215. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_provider_isolation.py +0 -0
  216. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_provider_triage.py +0 -0
  217. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_queue_read.py +0 -0
  218. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_relays_driver_output.py +0 -0
  219. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_repo_detect.py +0 -0
  220. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_run.py +0 -0
  221. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_run_progress.py +0 -0
  222. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_seam.py +0 -0
  223. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_snapshot_refresh.py +0 -0
  224. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_agent_state.py +0 -0
  225. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_answer_escalation_skill.py +0 -0
  226. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_app_insights_adapters.py +0 -0
  227. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_app_insights_harvest_window.py +0 -0
  228. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_archive_ref_reconciliation.py +0 -0
  229. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_arm_eval.py +0 -0
  230. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_arm_eval_lint_class.py +0 -0
  231. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_arm_eval_wiring.py +0 -0
  232. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_arm_gate_edits_uncommitted.py +0 -0
  233. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_arm_sweep.py +0 -0
  234. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_arm_sweep_gate.py +0 -0
  235. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_arm_txn.py +0 -0
  236. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_arm_wiring.py +0 -0
  237. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_artifact_redaction.py +0 -0
  238. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_attempt_note_untracked_files.py +0 -0
  239. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_attempt_outcome_contract.py +0 -0
  240. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_attempt_outcome_emission.py +0 -0
  241. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_attention_nonwriting_guard.py +0 -0
  242. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_attention_silence_section.py +0 -0
  243. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_attention_skill_structure.py +0 -0
  244. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_attribution_halt_claims.py +0 -0
  245. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autoclose_deferral_visibility.py +0 -0
  246. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autoclose_gate_note.py +0 -0
  247. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autoclose_stub_states_what_passed.py +0 -0
  248. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autofix_invoke.py +0 -0
  249. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autofix_live.py +0 -0
  250. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autofix_predicate.py +0 -0
  251. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autofix_run.py +0 -0
  252. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autofix_state.py +0 -0
  253. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autosync.py +0 -0
  254. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autosync_consent.py +0 -0
  255. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autosync_firstrun.py +0 -0
  256. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autosync_no_cwd_leak.py +0 -0
  257. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_autosync_plugin.py +0 -0
  258. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_azure_credential_resolution.py +0 -0
  259. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_backend.py +0 -0
  260. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_baseline_escalation_message.py +0 -0
  261. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_baseline_persistence.py +0 -0
  262. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_baseline_probe.py +0 -0
  263. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_baseline_provenance.py +0 -0
  264. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_baseline_tree_hash_key.py +0 -0
  265. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bash_routing.py +0 -0
  266. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bats_suites_gated.py +0 -0
  267. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_binary_verdict.py +0 -0
  268. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_binding_block_advisory.py +0 -0
  269. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_binding_block_allocation.py +0 -0
  270. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_binding_block_budget.py +0 -0
  271. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_blind_run_is_not_drained.py +0 -0
  272. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bookkeeping_commit_crash_run.py +0 -0
  273. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
  274. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bookkeeping_no_verify.py +0 -0
  275. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_brief_covers_every_unit_escalation.py +0 -0
  276. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_ci_pending.py +0 -0
  277. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_guardrails.py +0 -0
  278. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_label_nonfatal.py +0 -0
  279. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_labels_registered.py +0 -0
  280. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_min_severity.py +0 -0
  281. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_no_checks_pending.py +0 -0
  282. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_policy_contract.py +0 -0
  283. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_pr_number_carried.py +0 -0
  284. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_preflight_and_dial.py +0 -0
  285. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_run.py +0 -0
  286. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_state.py +0 -0
  287. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
  288. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_superseded.py +0 -0
  289. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_bug_lane_test_paths.py +0 -0
  290. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_build_provenance.py +0 -0
  291. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_carried_green_invalidated_by_diff.py +0 -0
  292. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_carry_accounting_close_and_judge.py +0 -0
  293. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_changed_file_test_selection.py +0 -0
  294. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_changelog_append_only.py +0 -0
  295. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_changelog_collection.py +0 -0
  296. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_changelog_release_wiring.py +0 -0
  297. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_changelog_schema.py +0 -0
  298. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_ci_conclusion_wait.py +0 -0
  299. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_ci_runs_every_gate.py +0 -0
  300. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_claude_resolution.py +0 -0
  301. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_close_b_pending_learnings.py +0 -0
  302. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_close_records_feature_oracle.py +0 -0
  303. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_close_wu_self_reference.py +0 -0
  304. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_closing_deliverable_guard.py +0 -0
  305. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_closing_guard_contracts.py +0 -0
  306. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_closing_guard_prediction.py +0 -0
  307. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_closing_learnings_destination.py +0 -0
  308. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_closing_requirements.py +0 -0
  309. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_closing_sessions_on_sonnet.py +0 -0
  310. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_coauthor_trailer_allowlist.py +0 -0
  311. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_conditional_reflection.py +0 -0
  312. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_console_encoding.py +0 -0
  313. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_convergent_iteration.py +0 -0
  314. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_convergent_wu_lint.py +0 -0
  315. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_correlation_id_override.py +0 -0
  316. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_correlation_id_two_surfaces.py +0 -0
  317. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_cost_lifetime.py +0 -0
  318. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_cost_tracking.py +0 -0
  319. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_criteria_per_gate_lint.py +0 -0
  320. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_criteria_state.py +0 -0
  321. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_criteria_worklist.py +0 -0
  322. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_decision_citation_lint.py +0 -0
  323. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_decision_followups_discharged.py +0 -0
  324. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_decision_override_lint.py +0 -0
  325. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_decisions_format.py +0 -0
  326. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_default_severity_aliases.py +0 -0
  327. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_degraded_oracle.py +0 -0
  328. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_deliverable_missing_note.py +0 -0
  329. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_deliverable_presence_gate.py +0 -0
  330. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_derive_agent_policy_review_mode.py +0 -0
  331. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_derive_agent_policy_skill.py +0 -0
  332. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_derive_monitoring_discovery.py +0 -0
  333. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_derive_monitoring_skill_registration.py +0 -0
  334. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_design_for_diagnosis_rule.py +0 -0
  335. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_deterministic_refusal_repeat.py +0 -0
  336. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_diagnose_fenced_analysis.py +0 -0
  337. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_diagnose_headless.py +0 -0
  338. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_diagnose_issue_skill.py +0 -0
  339. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_diagnosis.py +0 -0
  340. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_diagnosis_roundtrip_live.py +0 -0
  341. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_dispatch_model_from_fix_scope.py +0 -0
  342. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_dispatch_preamble_rules_pointer.py +0 -0
  343. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_dispatch_skeleton.py +0 -0
  344. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_dispatch_skills_index.py +0 -0
  345. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_distilled_accept_step.py +0 -0
  346. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_doctor.py +0 -0
  347. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_doctor_command_preflight.py +0 -0
  348. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_done_feature_gates.py +0 -0
  349. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_draft_feature_answers_mode.py +0 -0
  350. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_drafting_answer_gate.py +0 -0
  351. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_drafting_invoke.py +0 -0
  352. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_drafting_question_issue.py +0 -0
  353. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_drafting_questions.py +0 -0
  354. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_drafting_reply_shape.py +0 -0
  355. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_edit_detection.py +0 -0
  356. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_event_registry_covers_emitters.py +0 -0
  357. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_integration.py +0 -0
  358. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_lock.py +0 -0
  359. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_module_surface.py +0 -0
  360. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_restart_halt_surfaced.py +0 -0
  361. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_restart_halt_wiring.py +0 -0
  362. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_restart_hold.py +0 -0
  363. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_staleness_gate_summary.py +0 -0
  364. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_driver_staleness_warning.py +0 -0
  365. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_dry_run_no_branch_mutation.py +0 -0
  366. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_duration_tracking.py +0 -0
  367. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_empty_files_escalation.py +0 -0
  368. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_ensure_feature_branch.py +0 -0
  369. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_ensure_feature_branch_base.py +0 -0
  370. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_escalation_assignee_policy.py +0 -0
  371. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_escalation_contract.py +0 -0
  372. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_escalation_crash_containment.py +0 -0
  373. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_escalation_dedup_search.py +0 -0
  374. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_escalation_emit.py +0 -0
  375. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_event_gate_full_envelope.py +0 -0
  376. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_events_redaction.py +0 -0
  377. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_events_stats.py +0 -0
  378. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_extra_gates.py +0 -0
  379. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_failure_artifact_model.py +0 -0
  380. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_failure_signature_fail_prefix.py +0 -0
  381. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_failure_signature_names_the_test.py +0 -0
  382. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_failure_signature_skips_log_noise.py +0 -0
  383. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_feature_branch_auto_sync.py +0 -0
  384. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_feature_branch_squash_merge.py +0 -0
  385. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_feature_branch_stale_base.py +0 -0
  386. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_feature_id_resolution.py +0 -0
  387. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_feature_oracle_e2e.py +0 -0
  388. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_feature_provider_drafting_dispatch.py +0 -0
  389. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_feature_review_accumulation.py +0 -0
  390. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_filelock_portable.py +0 -0
  391. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_files_changed_auto_repair.py +0 -0
  392. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_find_pr_no_search_index.py +0 -0
  393. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fingerprint.py +0 -0
  394. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fix_bug_cwd_worktree.py +0 -0
  395. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fix_bug_diff_self_check.py +0 -0
  396. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fix_bug_headless.py +0 -0
  397. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fix_bug_reads_comments.py +0 -0
  398. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fix_unit_insertion_bookkeeping.py +0 -0
  399. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fix_unit_insertion_e2e.py +0 -0
  400. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fix_unit_insertion_refused.py +0 -0
  401. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_fold_contract_documented.py +0 -0
  402. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_followups_artifact.py +0 -0
  403. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_force_full_close.py +0 -0
  404. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_frontmatter_scalar_quoting.py +0 -0
  405. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_broad_run.py +0 -0
  406. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_budget.py +0 -0
  407. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_budget_post_dispatch.py +0 -0
  408. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_commands_needs.py +0 -0
  409. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_eval.py +0 -0
  410. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_eval_calibration.py +0 -0
  411. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_eval_intermediate_wiring.py +0 -0
  412. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_eval_repo_flag.py +0 -0
  413. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_eval_terminal_wiring.py +0 -0
  414. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gate_report_verdict.py +0 -0
  415. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gh_backend.py +0 -0
  416. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gh_features.py +0 -0
  417. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_git_env_isolation.py +0 -0
  418. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_gitleaks_pinning.py +0 -0
  419. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_groom_backlog_skill.py +0 -0
  420. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_guard_refusal_failure_class.py +0 -0
  421. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_guard_refusal_failure_excerpt.py +0 -0
  422. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_guard_repair_e2e.py +0 -0
  423. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_guard_repair_prompt.py +0 -0
  424. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_hashed_denylist.py +0 -0
  425. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_hashed_denylist_ci.py +0 -0
  426. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_headless_no_background_tasks.py +0 -0
  427. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_heartbeat.py +0 -0
  428. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_heartbeat_emission_contract.py +0 -0
  429. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_http_status_regression_adapter.py +0 -0
  430. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_http_status_regression_end_to_end.py +0 -0
  431. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_human_output_rule.py +0 -0
  432. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_human_work_unit.py +0 -0
  433. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_hygiene_boundary_guidance.py +0 -0
  434. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_hyphenated_gate_name.py +0 -0
  435. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_ignored_cleanup_before_probe.py +0 -0
  436. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_installed_copy_driver_e2e.py +0 -0
  437. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_interpreter_normalization.py +0 -0
  438. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_judge_close_path.py +0 -0
  439. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_judge_cost.py +0 -0
  440. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_judge_cost_fold_committed.py +0 -0
  441. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_judge_module.py +0 -0
  442. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_judge_path_registry.py +0 -0
  443. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_judge_sees_dropped_produces.py +0 -0
  444. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_judge_terminal_flip_state.py +0 -0
  445. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_judged_event_points_at_findings.py +0 -0
  446. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_label_description_length.py +0 -0
  447. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_label_provisioning_runner_contract.py +0 -0
  448. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_label_registry_covers_consumers.py +0 -0
  449. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_language_aware_narrow_selection.py +0 -0
  450. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lazy_baseline_e2e.py +0 -0
  451. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_leak_findings_redaction.py +0 -0
  452. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_leak_scan.py +0 -0
  453. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_leak_scan_content.py +0 -0
  454. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_learnings_curate_vendored_promote.py +0 -0
  455. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_learnings_distil_cli.py +0 -0
  456. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_learnings_query.py +0 -0
  457. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_learnings_staging.py +0 -0
  458. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_learnings_suggest_signature_filter.py +0 -0
  459. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_learnings_weights.py +0 -0
  460. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_legacy_4wu_terminal_flips.py +0 -0
  461. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lifecycle_integration.py +0 -0
  462. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lifetime_accounting.py +0 -0
  463. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_ac_observable.py +0 -0
  464. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_bare_produces_path.py +0 -0
  465. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_boundary_consistency.py +0 -0
  466. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_boundary_extraction.py +0 -0
  467. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_close_intermediate.py +0 -0
  468. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_close_verdict_not_predecided.py +0 -0
  469. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_close_wu.py +0 -0
  470. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_closing.py +0 -0
  471. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_closing_criteria.py +0 -0
  472. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_closing_criteria_pristine.py +0 -0
  473. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_correlation_id.py +0 -0
  474. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
  475. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_covers_load_wu_invariants.py +0 -0
  476. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_feature_oracle_declared.py +0 -0
  477. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_gate_proportionality.py +0 -0
  478. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_monitoring.py +0 -0
  479. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_oracle_env.py +0 -0
  480. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_plan_contract_fields.py +0 -0
  481. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_plan_errors.py +0 -0
  482. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_plan_next_draft.py +0 -0
  483. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_plan_relative_import.py +0 -0
  484. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_plan_verdict_exempt.py +0 -0
  485. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_planning_sections.py +0 -0
  486. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_produces_driver_helper.py +0 -0
  487. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_produces_satisfiability.py +0 -0
  488. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_roadmap.py +0 -0
  489. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_sections.py +0 -0
  490. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_task_graph_yaml_selection.py +0 -0
  491. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_lint_verification_reference.py +0 -0
  492. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_live_tests_opt_in.py +0 -0
  493. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_load_bearing_close_lint.py +0 -0
  494. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_attempt_evidence.py +0 -0
  495. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_auto_archive.py +0 -0
  496. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_caveman_preamble.py +0 -0
  497. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_close_intermediate.py +0 -0
  498. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_criteria_skeleton.py +0 -0
  499. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_criteria_survival.py +0 -0
  500. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_defaults_by_type.py +0 -0
  501. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_effort.py +0 -0
  502. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_failure_note_cap.py +0 -0
  503. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_files_changed_guard.py +0 -0
  504. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_gate_budget.py +0 -0
  505. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_gate_needs.py +0 -0
  506. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_model_alias.py +0 -0
  507. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_orchestration.py +0 -0
  508. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_post_pass_invariant.py +0 -0
  509. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_reset_preserving_events.py +0 -0
  510. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_smoke_runner.py +0 -0
  511. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_unsandboxed.py +0 -0
  512. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_worklist_injection.py +0 -0
  513. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_loop_zero_token_guard.py +0 -0
  514. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_make_repo_gpgsign_isolation.py +0 -0
  515. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_marker_dual_shape.py +0 -0
  516. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_maven_failure_excerpt.py +0 -0
  517. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_max_attempts_configurable.py +0 -0
  518. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_max_open_prs.py +0 -0
  519. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_migrate_legacy.py +0 -0
  520. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_miniyaml_equivalence.py +0 -0
  521. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_miniyaml_negative.py +0 -0
  522. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitor_durations.py +0 -0
  523. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitor_runner_surfaces.py +0 -0
  524. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
  525. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitoring_cron_dialect.py +0 -0
  526. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitoring_example.py +0 -0
  527. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitoring_fenced_blocks.py +0 -0
  528. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_monitoring_seed.py +0 -0
  529. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_narrow_fallback_warning.py +0 -0
  530. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_needs_decision_outcome.py +0 -0
  531. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_no_pytest_subprocess.py +0 -0
  532. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_notify.py +0 -0
  533. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_notify_escalation.py +0 -0
  534. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_notify_sla.py +0 -0
  535. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_operator_escalation_rule.py +0 -0
  536. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_oracle_set_declared.py +0 -0
  537. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_oracle_unrunnable_attribution.py +0 -0
  538. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_per_run_item_cap_disclosure.py +0 -0
  539. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_pick_feature_skill.py +0 -0
  540. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_pin_honesty_and_integrity.py +0 -0
  541. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_pin_marker_not_inherited.py +0 -0
  542. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_pin_marker_spawn_sites.py +0 -0
  543. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_plan_baseline.py +0 -0
  544. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_planned_cost_lint.py +0 -0
  545. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_planning_cost_floor.py +0 -0
  546. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_plugin_prose_cross_refs.py +0 -0
  547. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_plugin_qualified_dispatch.py +0 -0
  548. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_policy_budgets_applied.py +0 -0
  549. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_policy_proposals.py +0 -0
  550. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_policy_review.py +0 -0
  551. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_pr_checks_json_field.py +0 -0
  552. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_pr_reference_in_title.py +0 -0
  553. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
  554. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_prep_halt_operator_surface.py +0 -0
  555. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_prepare_feature.py +0 -0
  556. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_prepare_scaffold_sync.py +0 -0
  557. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_prerun_capture.py +0 -0
  558. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_prerun_oracles.py +0 -0
  559. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_prerun_wiring.py +0 -0
  560. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produced_document_verdict_guard.py +0 -0
  561. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_amendment_e2e.py +0 -0
  562. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_bracket_literal.py +0 -0
  563. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_bracket_wildcard.py +0 -0
  564. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_field.py +0 -0
  565. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_in_diff.py +0 -0
  566. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_justification.py +0 -0
  567. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_recursive_glob.py +0 -0
  568. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_repair_note.py +0 -0
  569. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_semantics_unified.py +0 -0
  570. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_produces_shape.py +0 -0
  571. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_progress_forward_note.py +0 -0
  572. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_progress_lines_end_to_end.py +0 -0
  573. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_promoted_issue_not_redispatched.py +0 -0
  574. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_promotion_ledger.py +0 -0
  575. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_provider_escalation_traces.py +0 -0
  576. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_provision_labels.py +0 -0
  577. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_queue_stalled_adapter.py +0 -0
  578. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_rearm_clears_stale_criteria_state.py +0 -0
  579. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_rearm_fold_marker.py +0 -0
  580. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_rearm_migration.py +0 -0
  581. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_reclose_carries_narrow_greens_e2e.py +0 -0
  582. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_red_baseline_never_reused.py +0 -0
  583. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_red_on_base_fetch_and_reason.py +0 -0
  584. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_red_on_base_guardrail.py +0 -0
  585. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_red_on_base_overlay.py +0 -0
  586. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_red_on_base_probe.py +0 -0
  587. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_red_on_base_real_runner.py +0 -0
  588. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_redaction_windows_home.py +0 -0
  589. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_reescalation_posts_comment.py +0 -0
  590. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_reflection_required_signals.py +0 -0
  591. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_replan_end_to_end.py +0 -0
  592. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_replan_event_emission.py +0 -0
  593. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_replan_note_collision.py +0 -0
  594. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_replan_trigger.py +0 -0
  595. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_replan_turn_contract.py +0 -0
  596. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_replay_spin.py +0 -0
  597. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_replay_spin_failing_sets.py +0 -0
  598. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_required_checks.py +0 -0
  599. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_resolve_base.py +0 -0
  600. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_restart_cap_counts_progress.py +0 -0
  601. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_result_block.py +0 -0
  602. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_result_block_audience.py +0 -0
  603. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_result_block_near_miss.py +0 -0
  604. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_result_block_scalar.py +0 -0
  605. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_resume_command_build.py +0 -0
  606. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_retain_on_guard_refusal_docs.py +0 -0
  607. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_roadmap_add_skill.py +0 -0
  608. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_roadmap_archive_cli.py +0 -0
  609. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_roadmap_archive_shim.py +0 -0
  610. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_roadmap_archive_skill.py +0 -0
  611. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_roadmap_archive_skill_delegates.py +0 -0
  612. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_roadmap_link_gate.py +0 -0
  613. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_roadmap_row_parser.py +0 -0
  614. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_ruff_verdict_lines.py +0 -0
  615. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_rule_import_convergence.py +0 -0
  616. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_run_level_failure_breaker.py +0 -0
  617. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_doc_hygiene.py +0 -0
  618. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_label_provisioning.py +0 -0
  619. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_manifest.py +0 -0
  620. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_seed_sanity.py +0 -0
  621. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_skew_halts.py +0 -0
  622. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_scaffold_upgrade.py +0 -0
  623. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_schedule_dialect.py +0 -0
  624. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_seed_documents_prerun_keys.py +0 -0
  625. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_service_bus_dlq_adapter.py +0 -0
  626. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_session_env_preflight.py +0 -0
  627. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_aliases.py +0 -0
  628. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_backfill_apply.py +0 -0
  629. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_backfill_bugs_only.py +0 -0
  630. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_backfill_end_to_end.py +0 -0
  631. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_backfill_limit.py +0 -0
  632. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_backfill_marker.py +0 -0
  633. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_backfill_run.py +0 -0
  634. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_label_projection.py +0 -0
  635. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_reconciliation.py +0 -0
  636. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_severity_rubric.py +0 -0
  637. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_shipped_templates_parse.py +0 -0
  638. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_skill_discovery_links.py +0 -0
  639. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_skills_vendored_in_sync.py +0 -0
  640. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_spec_work_unit_rules.py +0 -0
  641. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_spinning_rearm_gate.py +0 -0
  642. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_spinning_repeat_same_failing_set.py +0 -0
  643. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_spinout_brief_end_to_end.py +0 -0
  644. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_spinout_brief_replan_option.py +0 -0
  645. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_squash_commit_hook_crash.py +0 -0
  646. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_stop_rationale_captured.py +0 -0
  647. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_stranded_halt_cause.py +0 -0
  648. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_surefire_run_level_signature.py +0 -0
  649. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_surefire_verdict_lines.py +0 -0
  650. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_template_closing_shapes.py +0 -0
  651. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_terminal_auto_close_changelog.py +0 -0
  652. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_terminal_flip_ownership.py +0 -0
  653. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_terminal_flips.py +0 -0
  654. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_terminal_gate_message.py +0 -0
  655. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_tiered_verification_e2e.py +0 -0
  656. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_timeout_kill_portable.py +0 -0
  657. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_triage.py +0 -0
  658. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_triage_apply.py +0 -0
  659. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_triage_projects_severity_label.py +0 -0
  660. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_triage_severity_classify.py +0 -0
  661. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_triage_severity_end_to_end.py +0 -0
  662. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_triage_severity_write.py +0 -0
  663. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_triage_skill_contract.py +0 -0
  664. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_triage_skips_agent_escalations.py +0 -0
  665. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_tsc_verdict_lines.py +0 -0
  666. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_umbrella_version_resolution.py +0 -0
  667. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_unreadable_pr_listing_holds_pr_work.py +0 -0
  668. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_unterminated_frontmatter.py +0 -0
  669. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_untracked_feature_folder.py +0 -0
  670. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_untracked_file_absorption.py +0 -0
  671. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_upgrade_integration.py +0 -0
  672. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_upgrade_merge_gate.py +0 -0
  673. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_validate_event.py +0 -0
  674. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_validate_event_driver_types.py +0 -0
  675. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_verdict_coupling.py +0 -0
  676. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_verify_empty_gate_set.py +0 -0
  677. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_version_consistency.py +0 -0
  678. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_version_skew.py +0 -0
  679. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_windows_gate_exec.py +0 -0
  680. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_worktree_restore.py +0 -0
  681. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/tests/test_wu_execution_metadata.py +0 -0
  682. {specfuse_loop-0.28.2 → specfuse_loop-0.29.1}/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.28.2
3
+ Version: 0.29.1
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.28.2"
7
+ version = "0.29.1"
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"
@@ -23,7 +23,7 @@ from __future__ import annotations
23
23
 
24
24
  from specfuse.agent.invoke import build_claude_argv
25
25
  from specfuse.monitor.diagnose_cli import AnalysisParseError, render_headless
26
- from specfuse.monitor.diagnosis import FIX_SCOPES
26
+ from specfuse.monitor.diagnosis import FIX_SCOPES, SEVERITY_RUBRIC
27
27
 
28
28
  __all__ = ("AnalysisParseError", "build_invocation", "read_result")
29
29
 
@@ -69,7 +69,11 @@ def build_invocation(
69
69
  "partial evidence gets a low number.\n"
70
70
  f"- fix_scope: exactly one of {', '.join(FIX_SCOPES)} -- do not "
71
71
  "invent or default this value; if none plainly fits, say so in "
72
- "candidate_fix and still pick the closest of the three.\n\n"
72
+ "candidate_fix and still pick the closest of the three.\n"
73
+ "- severity (optional): how serious the finding is, judged from its "
74
+ "evidence against this rubric; omit it if you cannot tell:\n"
75
+ + "".join(f" - {line}\n" for line in SEVERITY_RUBRIC)
76
+ + "\n"
73
77
  "Do not post anything and do not run `gh issue comment` yourself; "
74
78
  "the caller renders and posts the diagnosis this session produces."
75
79
  )
@@ -112,13 +112,24 @@ def _parse_envelope(raw: str) -> tuple:
112
112
  return result_text, (usage if usage else None)
113
113
 
114
114
 
115
+ #: Every token field `budgets.max_tokens_per_run` is compared against (#3522).
116
+ SPEND_TOKEN_FIELDS = (
117
+ "input_tokens",
118
+ "output_tokens",
119
+ "cache_read_input_tokens",
120
+ "cache_creation_input_tokens",
121
+ )
122
+
123
+
115
124
  def usage_spend(usage: Optional[dict]) -> int:
116
- """`spend` for `ActionOutcome`: input + output tokens, cache reads
117
- excluded -- matching the driver's own cost line (`loop.py:7300-7302`).
125
+ """`spend` for `ActionOutcome`: all four usage token fields, cache reads
126
+ and cache creation included (#3522). With prompt caching nearly all of a
127
+ headless session's input is cache traffic, so leaving it out reported a
128
+ small fraction of the real volume and `max_tokens_per_run` never bound.
118
129
  Zero for a `None` usage, never a `KeyError`."""
119
130
  if not usage:
120
131
  return 0
121
- return int(usage.get("input_tokens", 0)) + int(usage.get("output_tokens", 0))
132
+ return sum(int(usage.get(key, 0)) for key in SPEND_TOKEN_FIELDS)
122
133
 
123
134
 
124
135
  def run_claude(
@@ -7,7 +7,8 @@ confidence threshold, `fix_scope` routing, fingerprint rate limit, and daily
7
7
  cap all stay in `specfuse.monitor.autofix`/`autofix_state`, read only
8
8
  through `run_autofix`.
9
9
 
10
- `advertise` returns one `kind="finding-autofix"` item per open snapshot
10
+ `advertise` returns, most severe diagnosis first (stable within a severity),
11
+ one `kind="finding-autofix"` item per open snapshot
11
12
  issue carrying `specfuse.monitor.issues.FINDING_LABEL` that already has a
12
13
  diagnosis comment -- the mirror of T10's filter, read the same way via
13
14
  `gh issue view N --json body,comments` and `specfuse.monitor.diagnosis.parse`.
@@ -63,6 +64,7 @@ from specfuse.monitor.issues import FINDING_LABEL
63
64
 
64
65
  _ITEM_ID_PREFIX = "finding-autofix-"
65
66
  _DEFAULT_MONITORING_CONFIG_PATH = ".specfuse/monitoring.yml"
67
+ _SEVERITY_ORDER = ("critical", "high", "medium", "low")
66
68
  _FAILING_OUTCOMES = ("refused", "could_not_proceed")
67
69
 
68
70
 
@@ -91,6 +93,24 @@ def _has_diagnosis(comments: list) -> bool:
91
93
  return False
92
94
 
93
95
 
96
+ def _latest_diagnosis(comments: list):
97
+ latest = None
98
+ for comment in comments or []:
99
+ body = comment.get("body", "") if isinstance(comment, dict) else ""
100
+ try:
101
+ diagnosis = parse(body)
102
+ except DiagnosisParseError:
103
+ continue
104
+ if diagnosis is not None:
105
+ latest = diagnosis
106
+ return latest
107
+
108
+
109
+ def _severity_rank(diagnosis) -> int:
110
+ severity = diagnosis.severity if diagnosis is not None else None
111
+ return _SEVERITY_ORDER.index(severity) if severity in _SEVERITY_ORDER else len(_SEVERITY_ORDER)
112
+
113
+
94
114
  def _known_components(monitoring_config: Any) -> set:
95
115
  components = monitoring_config.get("components") if isinstance(monitoring_config, dict) else None
96
116
  if not isinstance(components, list):
@@ -171,6 +191,7 @@ class FindingsAutofixProvider:
171
191
  known_components = _known_components(monitoring_config)
172
192
 
173
193
  items = []
194
+ ranks = {}
174
195
  for issue in snapshot.issues:
175
196
  if FINDING_LABEL not in issue.labels:
176
197
  continue
@@ -183,7 +204,8 @@ class FindingsAutofixProvider:
183
204
  if component is None or component not in known_components:
184
205
  continue
185
206
 
186
- if not _has_diagnosis(comments):
207
+ diagnosis = _latest_diagnosis(comments)
208
+ if diagnosis is None:
187
209
  continue
188
210
 
189
211
  item_id = f"{_ITEM_ID_PREFIX}{issue.number}"
@@ -192,6 +214,7 @@ class FindingsAutofixProvider:
192
214
  "component": component,
193
215
  "monitoring_config": monitoring_config,
194
216
  }
217
+ ranks[item_id] = _severity_rank(diagnosis)
195
218
  items.append(
196
219
  ActionItem(
197
220
  item_id=item_id,
@@ -200,6 +223,7 @@ class FindingsAutofixProvider:
200
223
  queue_key=None,
201
224
  )
202
225
  )
226
+ items.sort(key=lambda item: ranks[item.item_id])
203
227
  return items
204
228
 
205
229
  def execute(self, item: ActionItem) -> ActionOutcome:
@@ -7,8 +7,9 @@
7
7
  `AgentSnapshot` cannot answer.
8
8
 
9
9
  `advertise` returns one `kind="finding-diagnose"` item per open snapshot
10
- issue carrying `specfuse.monitor.issues.FINDING_LABEL` that has no diagnosis
11
- comment yet. The snapshot's `IssueSummary` carries no body, so this
10
+ issue carrying `specfuse.monitor.issues.FINDING_LABEL` that needs a diagnosis:
11
+ none yet, a monitor reopen comment newer than its latest diagnosis, or the
12
+ `rediagnose` label (#3487). The snapshot's `IssueSummary` carries no body, so this
12
13
  provider reads each candidate's body and comments itself with
13
14
  `gh issue view N --json body,comments` -- the same read
14
15
  `autofix_run._read_finding_issue` performs and the same softening of "the
@@ -25,8 +26,8 @@ The rendered comment body is `diagnosis.render`'s, unaltered -- this module
25
26
  holds no heading template and no marker string of its own. An unparseable
26
27
  analysis result posts nothing: `execute` escalates with the parse error's
27
28
  own message and never retries, defaults a field, or posts a partial body.
28
- This provider performs no git mutation and no label write of its own; a
29
- diagnosis is a comment.
29
+ This provider performs no git mutation. Its only label write is the
30
+ `severity:<value>` label of a diagnosis that carries a severity.
30
31
  """
31
32
 
32
33
  from __future__ import annotations
@@ -51,14 +52,16 @@ from specfuse.agent.run import (
51
52
  _default_runner,
52
53
  )
53
54
  from specfuse.agent.state import AgentSnapshot
55
+ from specfuse.loop.agent_policy import SEVERITY_LABEL_PREFIX
54
56
  from specfuse.monitor.diagnosis import DiagnosisParseError, parse
55
- from specfuse.monitor.issues import FINDING_LABEL
57
+ from specfuse.monitor.issues import FINDING_LABEL, REDIAGNOSE_LABEL, is_reopen_comment
56
58
 
57
59
  _ITEM_ID_PREFIX = "finding-diagnose-"
58
60
  _DEFAULT_MONITORING_CONFIG_PATH = ".specfuse/monitoring.yml"
59
61
  _DIAGNOSE_DIAL_AUTO = "auto"
60
62
 
61
63
 
64
+
62
65
  def _read_issue(runner: Callable, repo: str, issue_number: int) -> dict:
63
66
  result = runner(
64
67
  ["gh", "issue", "view", str(issue_number), "--repo", repo, "--json", "body,comments"],
@@ -73,15 +76,25 @@ def _read_issue(runner: Callable, repo: str, issue_number: int) -> dict:
73
76
  return parsed if isinstance(parsed, dict) else {}
74
77
 
75
78
 
76
- def _already_diagnosed(comments: list) -> bool:
77
- for comment in comments or []:
79
+ def _is_diagnosis(body: str) -> bool:
80
+ try:
81
+ return parse(body) is not None
82
+ except DiagnosisParseError:
83
+ return False
84
+
85
+
86
+ def _needs_diagnosis(comments: list) -> bool:
87
+ """True when the finding has no diagnosis yet, or the monitor reopened it
88
+ after its latest diagnosis (#3487: a regression after a fix is diagnosed
89
+ again, once per reopen). `gh issue view` lists comments oldest first."""
90
+ last_diagnosis = last_reopen = -1
91
+ for index, comment in enumerate(comments or []):
78
92
  body = comment.get("body", "") if isinstance(comment, dict) else ""
79
- try:
80
- if parse(body) is not None:
81
- return True
82
- except DiagnosisParseError:
83
- continue
84
- return False
93
+ if _is_diagnosis(body):
94
+ last_diagnosis = index
95
+ elif is_reopen_comment(body):
96
+ last_reopen = index
97
+ return last_diagnosis < 0 or last_reopen > last_diagnosis
85
98
 
86
99
 
87
100
  def _unparseable_diagnosis_payload(number: int, error: str) -> EscalationPayload:
@@ -168,11 +181,15 @@ class FindingsDiagnoseProvider:
168
181
  if dial != _DIAGNOSE_DIAL_AUTO:
169
182
  continue
170
183
 
171
- if _already_diagnosed(comments):
184
+ relabelled = REDIAGNOSE_LABEL in issue.labels
185
+ if not relabelled and not _needs_diagnosis(comments):
172
186
  continue
173
187
 
174
188
  item_id = f"{_ITEM_ID_PREFIX}{issue.number}"
175
- self._rows[item_id] = {"number": issue.number, "title": issue.title, "body": body}
189
+ self._rows[item_id] = {
190
+ "number": issue.number, "title": issue.title, "body": body,
191
+ "relabelled": relabelled, "labels": tuple(issue.labels),
192
+ }
176
193
  items.append(
177
194
  ActionItem(
178
195
  item_id=item_id,
@@ -221,11 +238,59 @@ class FindingsDiagnoseProvider:
221
238
  ],
222
239
  check=False,
223
240
  )
241
+ self._label_severity(number, rendered, row.get("labels", ()))
242
+ if row.get("relabelled"):
243
+ # Consume the request so the next run does not diagnose again.
244
+ self._runner(
245
+ ["gh", "issue", "edit", str(number), "--repo", self._repo,
246
+ "--remove-label", REDIAGNOSE_LABEL],
247
+ check=False,
248
+ )
224
249
  return ActionOutcome(
225
250
  status=STATUS_COMPLETED,
226
251
  detail=f"issue #{number} diagnosed",
227
252
  spend=spend,
228
253
  )
229
254
 
255
+ def _read_labels(self, number: int) -> set:
256
+ result = self._runner(
257
+ ["gh", "issue", "view", str(number), "--repo", self._repo, "--json", "labels"],
258
+ check=False,
259
+ )
260
+ if getattr(result, "returncode", 1) != 0 or not getattr(result, "stdout", None):
261
+ return set()
262
+ try:
263
+ parsed = json.loads(result.stdout)
264
+ except ValueError:
265
+ return set()
266
+ entries = parsed.get("labels") if isinstance(parsed, dict) else None
267
+ return {
268
+ e["name"] for e in entries or []
269
+ if isinstance(e, dict) and isinstance(e.get("name"), str)
270
+ }
271
+
272
+ def _label_severity(self, number: int, rendered: str, labels) -> None:
273
+ """Give the finding exactly one `severity:<value>` label, replacing any
274
+ previous one. No severity on the diagnosis, no label write."""
275
+ diagnosis = parse(rendered)
276
+ severity = diagnosis.severity if diagnosis is not None else None
277
+ if severity is None:
278
+ return
279
+ wanted = f"{SEVERITY_LABEL_PREFIX}{severity}"
280
+ self._runner(
281
+ ["gh", "label", "create", wanted, "--force", "--repo", self._repo],
282
+ check=False,
283
+ )
284
+ current = set(labels) | self._read_labels(number)
285
+ stale = [
286
+ label for label in sorted(current)
287
+ if label.startswith(SEVERITY_LABEL_PREFIX) and label != wanted
288
+ ]
289
+ argv = ["gh", "issue", "edit", str(number), "--repo", self._repo]
290
+ for label in stale:
291
+ argv += ["--remove-label", label]
292
+ argv += ["--add-label", wanted]
293
+ self._runner(argv, check=False)
294
+
230
295
  def reconcile(self, item: ActionItem, outcome: ActionOutcome) -> None:
231
296
  return None
@@ -303,7 +303,8 @@ class TriageProvider:
303
303
 
304
304
  rubric = self._rubric_for_run()
305
305
  argv, prompt = build_invocation(
306
- number, title, body, self._repo, self._working_dir, rubric=rubric
306
+ number, title, body, self._repo, self._working_dir, rubric=rubric,
307
+ comments=row.get("comments") or [],
307
308
  )
308
309
  invoked = run_claude(argv, prompt, runner=self._runner)
309
310
  spend = usage_spend(invoked.usage)
@@ -368,6 +369,9 @@ class TriageProvider:
368
369
  "category": category,
369
370
  "confidence": confidence,
370
371
  "severity": severity,
372
+ # #3521: without the issue's labels `apply_triage` cannot see
373
+ # a person's `severity:*` label, and adds a second one beside it.
374
+ "labels": row.get("labels") or [],
371
375
  }
372
376
  ]
373
377
  results = apply_triage(
@@ -391,11 +395,14 @@ class TriageProvider:
391
395
  spend=spend,
392
396
  )
393
397
 
394
- return ActionOutcome(
395
- status=STATUS_COMPLETED,
396
- detail=f"issue #{number} triaged as {row_result.get('category')}",
397
- spend=spend,
398
- )
398
+ detail = f"issue #{number} triaged as {row_result.get('category')}"
399
+ if row_result.get("severity_conflict"):
400
+ detail += (
401
+ f"; severity label left as "
402
+ f"{', '.join(row_result['severity_conflict'])} "
403
+ f"(triage judged {severity})"
404
+ )
405
+ return ActionOutcome(status=STATUS_COMPLETED, detail=detail, spend=spend)
399
406
 
400
407
  def reconcile(self, item: ActionItem, outcome: ActionOutcome) -> None:
401
408
  return None
@@ -62,6 +62,7 @@ from specfuse.loop.build_provenance import warn_if_out_of_tree
62
62
  from specfuse.loop.escalation import (
63
63
  CREATED_NUMBER_UNKNOWN,
64
64
  annotate_escalation,
65
+ clear_closed_escalation_labels,
65
66
  emit_escalation,
66
67
  )
67
68
 
@@ -198,8 +199,8 @@ class ActionOutcome:
198
199
  `spend` is real tokens, not a proxy — a provider that dispatches a
199
200
  headless `claude` session reports it through
200
201
  `specfuse.agent.invoke.usage_spend(invoke_result.usage)`
201
- (FEAT-2026-0108/T01): input plus output tokens, cache reads excluded, so
202
- it lines up with the driver's own cost line. It defaults to zero so a
202
+ (FEAT-2026-0108/T01): all four usage token fields, cache reads and cache
203
+ creation included (#3522). It defaults to zero so a
203
204
  provider that dispatches nothing, or whose session reported no usage
204
205
  envelope, leaves the run's total spend untouched. `escalation`, when set
205
206
  on a `STATUS_ESCALATED` outcome, is recorded — on `target_issue` when the
@@ -299,6 +300,10 @@ class RunSummary:
299
300
  #: re-run, because a triage-only run otherwise looks like a bug lane that
300
301
  #: declined everything.
301
302
  newly_triaged_bugs_undispatched: tuple = ()
303
+ #: `(number, reason)` for bugs this run triaged that the severity floor
304
+ #: holds back (#3521). Kept apart from the re-run list above: a re-run
305
+ #: would not dispatch them either, so the summary names the floor instead.
306
+ newly_triaged_bugs_below_floor: tuple = ()
302
307
 
303
308
 
304
309
  def _bug_marked_numbers(snapshot: AgentSnapshot) -> set:
@@ -306,6 +311,30 @@ def _bug_marked_numbers(snapshot: AgentSnapshot) -> set:
306
311
  return {issue.number for issue in snapshot.issues if issue.triage_category == "bug"}
307
312
 
308
313
 
314
+ def _split_by_severity_floor(numbers, snapshot: AgentSnapshot,
315
+ policy_path: Optional[str]) -> tuple:
316
+ """`(re-runnable, [(number, reason), ...])` for bugs triaged and never
317
+ dispatched (#3521).
318
+
319
+ Reads the floor exactly as `BugsProvider.advertise` does, so a bug this
320
+ returns as held back is one the next run's lane would skip too -- telling
321
+ the operator to re-run for it was a promise the lane would not keep.
322
+ """
323
+ floor = agent_policy.resolve_min_severity(policy_path)
324
+ aliases = agent_policy.resolve_severity_aliases(policy_path)
325
+ labels_by_number = {issue.number: issue.labels for issue in snapshot.issues}
326
+ rerun, held = [], []
327
+ for number in numbers:
328
+ severity, via = agent_policy.read_severity_label(
329
+ labels_by_number.get(number), aliases)
330
+ ok, why = agent_policy.meets_severity_floor(severity, floor, via=via)
331
+ if ok:
332
+ rerun.append(number)
333
+ else:
334
+ held.append((number, why))
335
+ return rerun, held
336
+
337
+
309
338
  def _refresh_snapshot(
310
339
  previous: AgentSnapshot,
311
340
  *,
@@ -838,6 +867,13 @@ def run_agent(
838
867
  policy_path=policy_path,
839
868
  features_root=features_root,
840
869
  )
870
+ # #3523: a closed issue keeps no escalation labels the lane wrote.
871
+ cleared = clear_closed_escalation_labels(runner, repo)
872
+ if cleared:
873
+ report(
874
+ "cleared needs-human from closed escalated issue(s): "
875
+ + ", ".join(f"#{number}" for number in cleared)
876
+ )
841
877
  bugs_preempt = _resolve_bugs_preempt(policy_path)
842
878
  report(
843
879
  f"snapshot: {len(snapshot.issues)} open issues, "
@@ -1179,6 +1215,10 @@ def run_agent(
1179
1215
  for number in _bug_marked_numbers(snapshot) - bugs_marked_at_start
1180
1216
  if f"bug-{number}" not in handled_ids
1181
1217
  )
1218
+ newly_triaged, below_floor = _split_by_severity_floor(
1219
+ newly_triaged, snapshot, policy_path)
1220
+ for number, why in below_floor:
1221
+ report(f"#{number} newly triaged as bug, not dispatched — {why}")
1182
1222
  if newly_triaged:
1183
1223
  report(
1184
1224
  f"{len(newly_triaged)} issue(s) newly triaged as bug and not "
@@ -1200,6 +1240,7 @@ def run_agent(
1200
1240
  escalations=tuple(escalations),
1201
1241
  wip_refs=tuple(wip_refs),
1202
1242
  newly_triaged_bugs_undispatched=tuple(newly_triaged),
1243
+ newly_triaged_bugs_below_floor=tuple(below_floor),
1203
1244
  )
1204
1245
  finally:
1205
1246
  lock_fd.close()
@@ -1229,6 +1270,8 @@ def _format_summary(summary: RunSummary) -> str:
1229
1270
  f" {len(summary.newly_triaged_bugs_undispatched)} newly triaged "
1230
1271
  f"as bug, not dispatched — re-run to fix them: {numbers}"
1231
1272
  )
1273
+ for number, why in summary.newly_triaged_bugs_below_floor:
1274
+ lines.append(f" #{number} newly triaged as bug, not dispatched — {why}")
1232
1275
  return "\n".join(lines)
1233
1276
 
1234
1277
 
@@ -47,6 +47,7 @@ def build_invocation(
47
47
  model: str = "sonnet",
48
48
  effort: str = "medium",
49
49
  rubric: Optional[dict] = None,
50
+ comments: Optional[list] = None,
50
51
  ):
51
52
  """Build argv and prompt text for a headless triage-classification
52
53
  session against one issue. Returns a `(argv, prompt)` tuple; runs
@@ -60,6 +61,12 @@ def build_invocation(
60
61
  session -- and the marker instruction grows a third `severity=` field.
61
62
  The prompt is built from `rubric`'s own mapping alone; it holds no copy
62
63
  of any shipped default definitions.
64
+
65
+ `comments` is the issue's comment list as `gh issue list --json comments`
66
+ returns it (#3520): a maintainer often routes an issue -- folds it into a
67
+ feature, marks it a duplicate -- in a comment, and a classifier reading
68
+ the body alone labels it `bug` anyway. No comments leaves the prompt
69
+ byte-identical to the one built without them.
63
70
  """
64
71
  argv = build_claude_argv(model, effort)
65
72
  if rubric:
@@ -88,6 +95,7 @@ def build_invocation(
88
95
  f"Issue number: {issue_number}\n"
89
96
  f"Issue title: {title}\n\n"
90
97
  f"Issue body:\n{body}\n\n"
98
+ f"{_comments_block(comments)}"
91
99
  "Classify this issue into exactly one of the categories: "
92
100
  f"{', '.join(CATEGORIES)}.\n\n"
93
101
  f"{marker_instruction}"
@@ -95,6 +103,23 @@ def build_invocation(
95
103
  return argv, prompt
96
104
 
97
105
 
106
+ def _comments_block(comments: Optional[list]) -> str:
107
+ if not comments:
108
+ return ""
109
+ rendered = []
110
+ for comment in comments:
111
+ author = (comment.get("author") or {}).get("login") or "unknown"
112
+ association = comment.get("authorAssociation") or "NONE"
113
+ rendered.append(f"--- @{author} ({association}):\n{comment.get('body') or ''}")
114
+ return (
115
+ "Issue comments, oldest first:\n"
116
+ + "\n\n".join(rendered)
117
+ + "\n\nIf a maintainer comment already routes this issue -- folds it "
118
+ "into a feature or another issue, or marks it a duplicate -- classify "
119
+ "it by that decision, not by the body alone.\n\n"
120
+ )
121
+
122
+
98
123
  def classify_result(result_text: str) -> Optional[tuple]:
99
124
  """Return the `(category, confidence)` pair a classification session's
100
125
  output names, or `None` if the output carries no parseable triage
@@ -0,0 +1 @@
1
+ 0.29.1