specfuse-loop 0.32.0__tar.gz → 0.33.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (719) hide show
  1. {specfuse_loop-0.32.0/specfuse_loop.egg-info → specfuse_loop-0.33.0}/PKG-INFO +1 -1
  2. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/pyproject.toml +1 -1
  3. specfuse_loop-0.33.0/specfuse/loop/data/VERSION +1 -0
  4. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/concepts/monitoring-runners.md +5 -1
  5. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/concepts/monitoring-schema.md +42 -1
  6. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/concepts/monitoring-to-fix.md +2 -1
  7. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/flows.html +1 -1
  8. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/monitoring.yml.example +27 -0
  9. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/design-for-diagnosis.md +81 -1
  10. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/lint_monitoring.py +90 -9
  11. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/loop.py +1 -1
  12. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/artifact.py +2 -1
  13. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/autofix_state.py +3 -3
  14. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/cli.py +21 -6
  15. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/issues.py +10 -4
  16. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/providers/azure_app_insights.py +458 -28
  17. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0/specfuse_loop.egg-info}/PKG-INFO +1 -1
  18. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse_loop.egg-info/SOURCES.txt +7 -0
  19. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_app_insights_harvest_window.py +7 -4
  20. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_app_insights_query_schema_check.py +7 -0
  21. specfuse_loop-0.33.0/tests/test_backlog_snapshot_emission_contract.py +93 -0
  22. specfuse_loop-0.33.0/tests/test_backlog_stalled_adapter.py +174 -0
  23. specfuse_loop-0.33.0/tests/test_backlog_stalled_end_to_end.py +109 -0
  24. specfuse_loop-0.33.0/tests/test_datastore_scope_rule.py +112 -0
  25. specfuse_loop-0.33.0/tests/test_dependency_regression_adapter.py +245 -0
  26. specfuse_loop-0.33.0/tests/test_dependency_regression_end_to_end.py +141 -0
  27. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_derive_monitoring_discovery.py +249 -2
  28. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_monitoring.py +124 -0
  29. specfuse_loop-0.33.0/tests/test_monitor_finding_listing_limit.py +154 -0
  30. specfuse_loop-0.32.0/specfuse/loop/data/VERSION +0 -1
  31. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/LICENSE +0 -0
  32. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/NOTICE +0 -0
  33. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/README.md +0 -0
  34. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/setup.cfg +0 -0
  35. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/__init__.py +0 -0
  36. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/budget.py +0 -0
  37. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/diagnose_invoke.py +0 -0
  38. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/drafting_answers.py +0 -0
  39. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/drafting_invoke.py +0 -0
  40. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/drafting_questions.py +0 -0
  41. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/driver_command.py +0 -0
  42. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/driver_invoke.py +0 -0
  43. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/invoke.py +0 -0
  44. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/monitoring_read.py +0 -0
  45. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/providers/__init__.py +0 -0
  46. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/providers/answers.py +0 -0
  47. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/providers/bugs.py +0 -0
  48. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/providers/feature.py +0 -0
  49. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/providers/findings_autofix.py +0 -0
  50. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/providers/findings_diagnose.py +0 -0
  51. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/providers/triage.py +0 -0
  52. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/queue_read.py +0 -0
  53. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/repo_detect.py +0 -0
  54. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/run.py +0 -0
  55. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/severity_backfill.py +0 -0
  56. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/state.py +0 -0
  57. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/triage_invoke.py +0 -0
  58. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/agent/worktree.py +0 -0
  59. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/__init__.py +0 -0
  60. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/_filelock.py +0 -0
  61. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/_miniyaml.py +0 -0
  62. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/_wu_sections.py +0 -0
  63. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/adopt_feature.py +0 -0
  64. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/agent_policy.py +0 -0
  65. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/arm_eval.py +0 -0
  66. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/arm_sweep.py +0 -0
  67. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/arm_txn.py +0 -0
  68. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/bug_lane.py +0 -0
  69. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/bug_lane_run.py +0 -0
  70. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/bug_lane_state.py +0 -0
  71. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/build_provenance.py +0 -0
  72. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/caller_check.py +0 -0
  73. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/changelog.py +0 -0
  74. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/changelog_fragments.py +0 -0
  75. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/closing_requirements.py +0 -0
  76. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/cost.py +0 -0
  77. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/criteria_state.py +0 -0
  78. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
  79. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/LEARNINGS.template.md +0 -0
  80. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
  81. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
  82. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
  83. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
  84. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/getting-started.md +0 -0
  85. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/glossary.md +0 -0
  86. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/lifecycles.md +0 -0
  87. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/methodology.md +0 -0
  88. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/docs/skills.md +0 -0
  89. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/gitignore.snippet +0 -0
  90. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
  91. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
  92. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/roadmap.template.md +0 -0
  93. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/close-discipline.md +0 -0
  94. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/correlation-ids.md +0 -0
  95. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/human-output.md +0 -0
  96. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/never-touch.md +0 -0
  97. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/operator-escalation.md +0 -0
  98. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/planning-discipline.md +0 -0
  99. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/result-contract.md +0 -0
  100. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/security-boundaries.md +0 -0
  101. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules/verification-discipline.md +0 -0
  102. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/rules-local/README.md +0 -0
  103. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/schemas/driver-event.schema.json +0 -0
  104. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/schemas/event.schema.json +0 -0
  105. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
  106. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
  107. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
  108. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
  109. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
  110. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/templates/GATE.template.md +0 -0
  111. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
  112. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/templates/PLAN.template.md +0 -0
  113. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/templates/WU.template.md +0 -0
  114. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/verification.yml.example +0 -0
  115. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
  116. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/decisions_format.py +0 -0
  117. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/driver_edit.py +0 -0
  118. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/escalation.py +0 -0
  119. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/events_stats.py +0 -0
  120. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/gate_commands.py +0 -0
  121. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/gate_eval.py +0 -0
  122. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/gen_contract.py +0 -0
  123. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/gh_backend.py +0 -0
  124. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/gh_features.py +0 -0
  125. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/heartbeat.py +0 -0
  126. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/ids.py +0 -0
  127. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/judge.py +0 -0
  128. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/labels.py +0 -0
  129. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/layout.py +0 -0
  130. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/learnings_distil.py +0 -0
  131. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/learnings_query.py +0 -0
  132. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/lint_closing.py +0 -0
  133. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/lint_plan.py +0 -0
  134. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/lint_roadmap.py +0 -0
  135. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/notify.py +0 -0
  136. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/notify_escalation.py +0 -0
  137. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/notify_sla.py +0 -0
  138. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/plan_baseline.py +0 -0
  139. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/policy_proposals.py +0 -0
  140. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/policy_review.py +0 -0
  141. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/prerun.py +0 -0
  142. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/prerun_capture.py +0 -0
  143. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/promotion.py +0 -0
  144. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/rearm_migration.py +0 -0
  145. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/red_on_base.py +0 -0
  146. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/replay_spin.py +0 -0
  147. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/roadmap_archive.py +0 -0
  148. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/scaffold.py +0 -0
  149. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/triage.py +0 -0
  150. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/upgrade_merge_gate.py +0 -0
  151. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/loop/validate_event.py +0 -0
  152. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/__init__.py +0 -0
  153. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/adapters.py +0 -0
  154. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/autofix.py +0 -0
  155. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/autofix_invoke.py +0 -0
  156. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/autofix_run.py +0 -0
  157. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/diagnose_cli.py +0 -0
  158. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/diagnosis.py +0 -0
  159. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/durations.py +0 -0
  160. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/fingerprint.py +0 -0
  161. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/providers/__init__.py +0 -0
  162. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/providers/_azure_auth.py +0 -0
  163. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/providers/azure_service_bus.py +0 -0
  164. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/redaction.py +0 -0
  165. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse/monitor/schedule.py +0 -0
  166. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse_loop.egg-info/dependency_links.txt +0 -0
  167. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse_loop.egg-info/entry_points.txt +0 -0
  168. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse_loop.egg-info/requires.txt +0 -0
  169. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/specfuse_loop.egg-info/top_level.txt +0 -0
  170. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_abandon_feature_skill.py +0 -0
  171. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_abandoned_work_reported.py +0 -0
  172. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_abandoned_wu_strands_gate.py +0 -0
  173. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_adopt_feature.py +0 -0
  174. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_budget.py +0 -0
  175. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_bug_selection_dedup.py +0 -0
  176. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_default_features_root.py +0 -0
  177. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_driver_command.py +0 -0
  178. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_driver_invoke.py +0 -0
  179. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_driver_restart.py +0 -0
  180. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_escalation_on_issue.py +0 -0
  181. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_escalation_run_state.py +0 -0
  182. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_findings_seam.py +0 -0
  183. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_invoke_timeout.py +0 -0
  184. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_invoke_usage.py +0 -0
  185. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_item_worktree.py +0 -0
  186. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_lock.py +0 -0
  187. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_policy_key_ownership.py +0 -0
  188. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_policy_queue.py +0 -0
  189. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_policy_schema.py +0 -0
  190. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_policy_triage_dial.py +0 -0
  191. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_provider_answers.py +0 -0
  192. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_provider_bugs.py +0 -0
  193. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_provider_feature.py +0 -0
  194. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_provider_findings_autofix.py +0 -0
  195. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_provider_findings_diagnose.py +0 -0
  196. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_provider_isolation.py +0 -0
  197. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_provider_triage.py +0 -0
  198. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_queue_read.py +0 -0
  199. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_relays_driver_output.py +0 -0
  200. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_repo_detect.py +0 -0
  201. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_run.py +0 -0
  202. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_run_progress.py +0 -0
  203. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_seam.py +0 -0
  204. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_snapshot_refresh.py +0 -0
  205. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_agent_state.py +0 -0
  206. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_answer_escalation_skill.py +0 -0
  207. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_app_insights_adapters.py +0 -0
  208. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_app_insights_workspace_schema.py +0 -0
  209. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_archive_ref_reconciliation.py +0 -0
  210. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_eval.py +0 -0
  211. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_eval_lint_class.py +0 -0
  212. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_eval_terminal.py +0 -0
  213. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_eval_wiring.py +0 -0
  214. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_gate_edits_uncommitted.py +0 -0
  215. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_sweep.py +0 -0
  216. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_sweep_gate.py +0 -0
  217. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_txn.py +0 -0
  218. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_arm_wiring.py +0 -0
  219. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_artifact_redaction.py +0 -0
  220. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_attempt_note_untracked_files.py +0 -0
  221. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_attempt_outcome_contract.py +0 -0
  222. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_attempt_outcome_emission.py +0 -0
  223. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_attention_nonwriting_guard.py +0 -0
  224. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_attention_silence_section.py +0 -0
  225. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_attention_skill_structure.py +0 -0
  226. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_attribution_halt_claims.py +0 -0
  227. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autoclose_deferral_visibility.py +0 -0
  228. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autoclose_gate_note.py +0 -0
  229. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autoclose_stub_states_what_passed.py +0 -0
  230. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autofix_invoke.py +0 -0
  231. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autofix_live.py +0 -0
  232. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autofix_predicate.py +0 -0
  233. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autofix_run.py +0 -0
  234. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autofix_state.py +0 -0
  235. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autosync.py +0 -0
  236. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autosync_consent.py +0 -0
  237. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autosync_firstrun.py +0 -0
  238. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autosync_no_cwd_leak.py +0 -0
  239. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_autosync_plugin.py +0 -0
  240. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_azure_credential_resolution.py +0 -0
  241. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_backend.py +0 -0
  242. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_baseline_escalation_message.py +0 -0
  243. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_baseline_persistence.py +0 -0
  244. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_baseline_probe.py +0 -0
  245. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_baseline_provenance.py +0 -0
  246. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_baseline_tree_hash_key.py +0 -0
  247. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bash_routing.py +0 -0
  248. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bats_suites_gated.py +0 -0
  249. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_binary_verdict.py +0 -0
  250. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_binding_block_advisory.py +0 -0
  251. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_binding_block_allocation.py +0 -0
  252. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_binding_block_budget.py +0 -0
  253. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_blind_run_is_not_drained.py +0 -0
  254. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_block_feature_layout.py +0 -0
  255. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_blocked_by_entry_anchor.py +0 -0
  256. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bookkeeping_commit_crash_run.py +0 -0
  257. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
  258. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bookkeeping_no_verify.py +0 -0
  259. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_brief_covers_every_unit_escalation.py +0 -0
  260. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_ci_pending.py +0 -0
  261. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_guardrails.py +0 -0
  262. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_label_nonfatal.py +0 -0
  263. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_labels_registered.py +0 -0
  264. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_min_severity.py +0 -0
  265. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_no_checks_pending.py +0 -0
  266. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_policy_contract.py +0 -0
  267. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_pr_number_carried.py +0 -0
  268. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_preflight_and_dial.py +0 -0
  269. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_run.py +0 -0
  270. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_spend.py +0 -0
  271. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_state.py +0 -0
  272. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
  273. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_superseded.py +0 -0
  274. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_bug_lane_test_paths.py +0 -0
  275. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_build_provenance.py +0 -0
  276. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_caller_check_ratchet.py +0 -0
  277. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_carried_green_invalidated_by_diff.py +0 -0
  278. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_carry_accounting_close_and_judge.py +0 -0
  279. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_changed_file_test_selection.py +0 -0
  280. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_changelog_append_only.py +0 -0
  281. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_changelog_collection.py +0 -0
  282. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_changelog_fragments.py +0 -0
  283. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_changelog_release_wiring.py +0 -0
  284. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_changelog_schema.py +0 -0
  285. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ci_conclusion_wait.py +0 -0
  286. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ci_runs_every_gate.py +0 -0
  287. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_claude_resolution.py +0 -0
  288. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_close_b_pending_learnings.py +0 -0
  289. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_close_records_feature_oracle.py +0 -0
  290. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_close_wu_self_reference.py +0 -0
  291. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_closed_escalation_labels.py +0 -0
  292. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_closing_deliverable_guard.py +0 -0
  293. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_closing_guard_contracts.py +0 -0
  294. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_closing_guard_prediction.py +0 -0
  295. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_closing_learnings_destination.py +0 -0
  296. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_closing_requirements.py +0 -0
  297. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_closing_sessions_on_sonnet.py +0 -0
  298. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_coauthor_trailer_allowlist.py +0 -0
  299. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_conditional_reflection.py +0 -0
  300. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_console_encoding.py +0 -0
  301. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_convergent_iteration.py +0 -0
  302. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_convergent_wu_lint.py +0 -0
  303. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_correlation_id_override.py +0 -0
  304. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_correlation_id_two_surfaces.py +0 -0
  305. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_cost_lifetime.py +0 -0
  306. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_cost_tracking.py +0 -0
  307. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_criteria_per_gate_lint.py +0 -0
  308. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_criteria_state.py +0 -0
  309. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_criteria_worklist.py +0 -0
  310. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_decision_citation_lint.py +0 -0
  311. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_decision_followups_discharged.py +0 -0
  312. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_decision_override_lint.py +0 -0
  313. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_decisions_format.py +0 -0
  314. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_default_severity_aliases.py +0 -0
  315. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_degraded_oracle.py +0 -0
  316. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_deliverable_missing_note.py +0 -0
  317. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_deliverable_presence_gate.py +0 -0
  318. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_derive_agent_policy_review_mode.py +0 -0
  319. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_derive_agent_policy_skill.py +0 -0
  320. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_derive_monitoring_skill_registration.py +0 -0
  321. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_design_for_diagnosis_rule.py +0 -0
  322. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_deterministic_refusal_repeat.py +0 -0
  323. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_diagnose_fenced_analysis.py +0 -0
  324. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_diagnose_headless.py +0 -0
  325. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_diagnose_issue_skill.py +0 -0
  326. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_diagnosis.py +0 -0
  327. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_diagnosis_roundtrip_live.py +0 -0
  328. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_diagnosis_severity_end_to_end.py +0 -0
  329. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_diagnosis_severity_rubric.py +0 -0
  330. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_dispatch_model_from_fix_scope.py +0 -0
  331. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_dispatch_preamble_rules_pointer.py +0 -0
  332. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_dispatch_skeleton.py +0 -0
  333. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_dispatch_skills_index.py +0 -0
  334. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_distilled_accept_step.py +0 -0
  335. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_doctor.py +0 -0
  336. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_doctor_command_preflight.py +0 -0
  337. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_done_feature_gates.py +0 -0
  338. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_draft_feature_answers_mode.py +0 -0
  339. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_drafting_answer_gate.py +0 -0
  340. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_drafting_invoke.py +0 -0
  341. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_drafting_question_issue.py +0 -0
  342. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_drafting_questions.py +0 -0
  343. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_drafting_reply_shape.py +0 -0
  344. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_edit_detection.py +0 -0
  345. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_event_registry_covers_emitters.py +0 -0
  346. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_integration.py +0 -0
  347. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_lock.py +0 -0
  348. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_module_surface.py +0 -0
  349. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_restart_halt_surfaced.py +0 -0
  350. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_restart_halt_wiring.py +0 -0
  351. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_restart_hold.py +0 -0
  352. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_staleness_gate_summary.py +0 -0
  353. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_driver_staleness_warning.py +0 -0
  354. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_dry_run_no_branch_mutation.py +0 -0
  355. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_duration_tracking.py +0 -0
  356. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_empty_files_escalation.py +0 -0
  357. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ensure_feature_branch.py +0 -0
  358. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ensure_feature_branch_base.py +0 -0
  359. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_escalation_assignee_policy.py +0 -0
  360. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_escalation_contract.py +0 -0
  361. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_escalation_crash_containment.py +0 -0
  362. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_escalation_dedup_search.py +0 -0
  363. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_escalation_emit.py +0 -0
  364. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_event_gate_full_envelope.py +0 -0
  365. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_events_redaction.py +0 -0
  366. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_events_stats.py +0 -0
  367. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_extra_gates.py +0 -0
  368. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_failure_artifact_model.py +0 -0
  369. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_failure_signature_fail_prefix.py +0 -0
  370. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_failure_signature_names_the_test.py +0 -0
  371. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_failure_signature_skips_log_noise.py +0 -0
  372. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_feature_branch_auto_sync.py +0 -0
  373. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_feature_branch_squash_merge.py +0 -0
  374. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_feature_branch_stale_base.py +0 -0
  375. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_feature_id_resolution.py +0 -0
  376. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_feature_oracle_e2e.py +0 -0
  377. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_feature_provider_drafting_dispatch.py +0 -0
  378. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_feature_review_accumulation.py +0 -0
  379. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_filelock_portable.py +0 -0
  380. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_files_changed_auto_repair.py +0 -0
  381. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_find_pr_no_search_index.py +0 -0
  382. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fingerprint.py +0 -0
  383. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fix_bug_cwd_worktree.py +0 -0
  384. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fix_bug_diff_self_check.py +0 -0
  385. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fix_bug_headless.py +0 -0
  386. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fix_bug_reads_comments.py +0 -0
  387. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fix_unit_insertion_bookkeeping.py +0 -0
  388. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fix_unit_insertion_e2e.py +0 -0
  389. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fix_unit_insertion_refused.py +0 -0
  390. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_floor_skip_summary.py +0 -0
  391. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_flows_page.py +0 -0
  392. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_fold_contract_documented.py +0 -0
  393. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_followups_artifact.py +0 -0
  394. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_force_full_close.py +0 -0
  395. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_frontmatter_scalar_quoting.py +0 -0
  396. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_broad_run.py +0 -0
  397. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_budget.py +0 -0
  398. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_budget_post_dispatch.py +0 -0
  399. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_commands_needs.py +0 -0
  400. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_eval.py +0 -0
  401. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_eval_calibration.py +0 -0
  402. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_eval_intermediate_wiring.py +0 -0
  403. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_eval_repo_flag.py +0 -0
  404. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_eval_terminal_wiring.py +0 -0
  405. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_log_size_budget.py +0 -0
  406. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gate_report_verdict.py +0 -0
  407. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gen_contract.py +0 -0
  408. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gh_backend.py +0 -0
  409. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gh_features.py +0 -0
  410. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_git_env_isolation.py +0 -0
  411. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_gitleaks_pinning.py +0 -0
  412. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_groom_backlog_skill.py +0 -0
  413. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_guard_refusal_failure_class.py +0 -0
  414. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_guard_refusal_failure_excerpt.py +0 -0
  415. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_guard_repair_e2e.py +0 -0
  416. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_guard_repair_prompt.py +0 -0
  417. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_hashed_denylist.py +0 -0
  418. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_hashed_denylist_ci.py +0 -0
  419. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_headless_no_background_tasks.py +0 -0
  420. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_heartbeat.py +0 -0
  421. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_heartbeat_adapter.py +0 -0
  422. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_heartbeat_emission_contract.py +0 -0
  423. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_http_status_regression_adapter.py +0 -0
  424. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_http_status_regression_end_to_end.py +0 -0
  425. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_human_output_rule.py +0 -0
  426. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_human_work_unit.py +0 -0
  427. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_hygiene_boundary_guidance.py +0 -0
  428. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_hyphenated_gate_name.py +0 -0
  429. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ids.py +0 -0
  430. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ids_aliases.py +0 -0
  431. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ids_call_sites.py +0 -0
  432. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ids_migrate.py +0 -0
  433. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ids_migrate_all.py +0 -0
  434. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ignored_cleanup_before_probe.py +0 -0
  435. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_init_integration.py +0 -0
  436. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_installed_copy_driver_e2e.py +0 -0
  437. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_interpreter_normalization.py +0 -0
  438. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judge_close_path.py +0 -0
  439. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judge_cost.py +0 -0
  440. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judge_cost_fold_committed.py +0 -0
  441. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judge_editing_terminal_docs.py +0 -0
  442. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judge_module.py +0 -0
  443. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judge_path_registry.py +0 -0
  444. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judge_sees_dropped_produces.py +0 -0
  445. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judge_terminal_flip_state.py +0 -0
  446. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_judged_event_points_at_findings.py +0 -0
  447. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_keyed_feature_ids_docs.py +0 -0
  448. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_keyed_feature_ids_end_to_end.py +0 -0
  449. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_label_description_length.py +0 -0
  450. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_label_provisioning_runner_contract.py +0 -0
  451. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_label_registry.py +0 -0
  452. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_label_registry_covers_consumers.py +0 -0
  453. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_language_aware_narrow_selection.py +0 -0
  454. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_layout.py +0 -0
  455. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_layout_end_to_end.py +0 -0
  456. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_layout_link.py +0 -0
  457. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_layout_no_layout_goldens.py +0 -0
  458. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_layout_validation.py +0 -0
  459. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lazy_baseline_e2e.py +0 -0
  460. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_leak_findings_redaction.py +0 -0
  461. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_leak_scan.py +0 -0
  462. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_leak_scan_content.py +0 -0
  463. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_learnings_curate_vendored_promote.py +0 -0
  464. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_learnings_distil_cli.py +0 -0
  465. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_learnings_query.py +0 -0
  466. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_learnings_staging.py +0 -0
  467. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_learnings_suggest_signature_filter.py +0 -0
  468. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_learnings_weights.py +0 -0
  469. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_legacy_4wu_terminal_flips.py +0 -0
  470. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lifecycle_integration.py +0 -0
  471. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lifetime_accounting.py +0 -0
  472. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_ac_observable.py +0 -0
  473. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_bare_produces_path.py +0 -0
  474. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_boundary_consistency.py +0 -0
  475. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_boundary_extraction.py +0 -0
  476. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_close_intermediate.py +0 -0
  477. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_close_verdict_not_predecided.py +0 -0
  478. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_close_wu.py +0 -0
  479. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_closing.py +0 -0
  480. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_closing_criteria.py +0 -0
  481. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_closing_criteria_pristine.py +0 -0
  482. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_correlation_id.py +0 -0
  483. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
  484. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_covers_load_wu_invariants.py +0 -0
  485. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_feature_oracle_declared.py +0 -0
  486. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_gate_proportionality.py +0 -0
  487. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_judge_edit_acknowledged.py +0 -0
  488. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_oracle_env.py +0 -0
  489. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_plan_contract_fields.py +0 -0
  490. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_plan_errors.py +0 -0
  491. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_plan_next_draft.py +0 -0
  492. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_plan_relative_import.py +0 -0
  493. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_plan_verdict_exempt.py +0 -0
  494. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_planning_sections.py +0 -0
  495. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_produces_driver_helper.py +0 -0
  496. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_produces_satisfiability.py +0 -0
  497. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_roadmap.py +0 -0
  498. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_roadmap_unkeyed_rows.py +0 -0
  499. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_sections.py +0 -0
  500. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_task_graph_yaml_selection.py +0 -0
  501. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_lint_verification_reference.py +0 -0
  502. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_live_tests_opt_in.py +0 -0
  503. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_load_bearing_close_lint.py +0 -0
  504. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_attempt_evidence.py +0 -0
  505. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_auto_archive.py +0 -0
  506. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_caveman_preamble.py +0 -0
  507. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_close_intermediate.py +0 -0
  508. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_criteria_skeleton.py +0 -0
  509. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_criteria_survival.py +0 -0
  510. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_defaults_by_type.py +0 -0
  511. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_effort.py +0 -0
  512. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_failure_note_cap.py +0 -0
  513. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_files_changed_guard.py +0 -0
  514. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_gate_budget.py +0 -0
  515. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_gate_needs.py +0 -0
  516. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_model_alias.py +0 -0
  517. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_orchestration.py +0 -0
  518. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_post_pass_invariant.py +0 -0
  519. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_reset_preserving_events.py +0 -0
  520. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_smoke_runner.py +0 -0
  521. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_unsandboxed.py +0 -0
  522. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_worklist_injection.py +0 -0
  523. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_loop_zero_token_guard.py +0 -0
  524. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_make_repo_gpgsign_isolation.py +0 -0
  525. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_marker_dual_shape.py +0 -0
  526. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_maven_failure_excerpt.py +0 -0
  527. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_max_attempts_configurable.py +0 -0
  528. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_max_open_prs.py +0 -0
  529. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_migrate_all_repo_stays_valid.py +0 -0
  530. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_migrate_all_scales.py +0 -0
  531. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_migrate_legacy.py +0 -0
  532. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_miniyaml_equivalence.py +0 -0
  533. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_miniyaml_negative.py +0 -0
  534. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_check_isolation.py +0 -0
  535. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_cli.py +0 -0
  536. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_diagnose_auto_warning.py +0 -0
  537. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_durations.py +0 -0
  538. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_finding_context_end_to_end.py +0 -0
  539. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_finding_lifecycle_end_to_end.py +0 -0
  540. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_finding_meta.py +0 -0
  541. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_issue_lifecycle.py +0 -0
  542. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_one_issue_per_fingerprint.py +0 -0
  543. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_quiet_annotation.py +0 -0
  544. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitor_runner_surfaces.py +0 -0
  545. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
  546. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitoring_cron_dialect.py +0 -0
  547. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitoring_example.py +0 -0
  548. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitoring_fenced_blocks.py +0 -0
  549. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_monitoring_seed.py +0 -0
  550. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_narrow_fallback_warning.py +0 -0
  551. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_narrow_non_py_produces.py +0 -0
  552. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_needs_decision_outcome.py +0 -0
  553. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_no_pytest_subprocess.py +0 -0
  554. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_notify.py +0 -0
  555. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_notify_escalation.py +0 -0
  556. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_notify_sla.py +0 -0
  557. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_operator_escalation_rule.py +0 -0
  558. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_oracle_set_declared.py +0 -0
  559. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_oracle_unrunnable_attribution.py +0 -0
  560. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_per_run_item_cap_disclosure.py +0 -0
  561. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_pick_feature_skill.py +0 -0
  562. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_pin_honesty_and_integrity.py +0 -0
  563. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_pin_marker_not_inherited.py +0 -0
  564. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_pin_marker_spawn_sites.py +0 -0
  565. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_plan_baseline.py +0 -0
  566. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_planned_cost_lint.py +0 -0
  567. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_planning_cost_floor.py +0 -0
  568. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_plugin_prose_cross_refs.py +0 -0
  569. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_plugin_qualified_dispatch.py +0 -0
  570. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_policy_budgets_applied.py +0 -0
  571. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_policy_proposals.py +0 -0
  572. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_policy_review.py +0 -0
  573. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_pr_checks_json_field.py +0 -0
  574. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_pr_reference_in_title.py +0 -0
  575. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
  576. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_prep_halt_operator_surface.py +0 -0
  577. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_prepare_feature.py +0 -0
  578. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_prepare_scaffold_sync.py +0 -0
  579. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_prerun_capture.py +0 -0
  580. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_prerun_oracles.py +0 -0
  581. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_prerun_wiring.py +0 -0
  582. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produced_document_verdict_guard.py +0 -0
  583. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_amendment_e2e.py +0 -0
  584. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_bracket_literal.py +0 -0
  585. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_bracket_wildcard.py +0 -0
  586. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_field.py +0 -0
  587. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_in_diff.py +0 -0
  588. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_justification.py +0 -0
  589. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_recursive_glob.py +0 -0
  590. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_repair_note.py +0 -0
  591. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_semantics_unified.py +0 -0
  592. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_produces_shape.py +0 -0
  593. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_progress_forward_note.py +0 -0
  594. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_progress_lines_end_to_end.py +0 -0
  595. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_promoted_issue_not_redispatched.py +0 -0
  596. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_promotion_ledger.py +0 -0
  597. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_provider_escalation_traces.py +0 -0
  598. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_provision_labels.py +0 -0
  599. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_queue_stalled_adapter.py +0 -0
  600. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_rearm_clears_stale_criteria_state.py +0 -0
  601. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_rearm_close_broad_run.py +0 -0
  602. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_rearm_fold_marker.py +0 -0
  603. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_rearm_migration.py +0 -0
  604. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_rearm_retained_new_files.py +0 -0
  605. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_reclose_carries_narrow_greens_e2e.py +0 -0
  606. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_red_baseline_never_reused.py +0 -0
  607. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_red_on_base_fetch_and_reason.py +0 -0
  608. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_red_on_base_guardrail.py +0 -0
  609. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_red_on_base_overlay.py +0 -0
  610. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_red_on_base_probe.py +0 -0
  611. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_red_on_base_real_runner.py +0 -0
  612. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_redaction_windows_home.py +0 -0
  613. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_rediagnose_on_reopen.py +0 -0
  614. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_reescalation_posts_comment.py +0 -0
  615. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_reflection_required_signals.py +0 -0
  616. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_replan_end_to_end.py +0 -0
  617. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_replan_event_emission.py +0 -0
  618. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_replan_note_collision.py +0 -0
  619. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_replan_trigger.py +0 -0
  620. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_replan_turn_contract.py +0 -0
  621. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_replay_spin.py +0 -0
  622. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_replay_spin_failing_sets.py +0 -0
  623. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_repo_changelog_opt_in.py +0 -0
  624. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_required_checks.py +0 -0
  625. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_resolve_base.py +0 -0
  626. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_restart_cap_counts_progress.py +0 -0
  627. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_result_block.py +0 -0
  628. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_result_block_audience.py +0 -0
  629. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_result_block_near_miss.py +0 -0
  630. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_result_block_scalar.py +0 -0
  631. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_resume_command_build.py +0 -0
  632. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_retain_on_guard_refusal_docs.py +0 -0
  633. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_roadmap_add_skill.py +0 -0
  634. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_roadmap_archive_cli.py +0 -0
  635. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_roadmap_archive_shim.py +0 -0
  636. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_roadmap_archive_skill.py +0 -0
  637. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_roadmap_archive_skill_delegates.py +0 -0
  638. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_roadmap_link_gate.py +0 -0
  639. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_roadmap_row_parser.py +0 -0
  640. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_ruff_verdict_lines.py +0 -0
  641. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_rule_import_convergence.py +0 -0
  642. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_run_level_failure_breaker.py +0 -0
  643. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_data_in_sync.py +0 -0
  644. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_doc_hygiene.py +0 -0
  645. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_docs.py +0 -0
  646. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_init.py +0 -0
  647. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_label_provisioning.py +0 -0
  648. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_manifest.py +0 -0
  649. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_resources.py +0 -0
  650. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_seed_sanity.py +0 -0
  651. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_skew_halts.py +0 -0
  652. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_upgrade.py +0 -0
  653. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_scaffold_wiring.py +0 -0
  654. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_schedule_dialect.py +0 -0
  655. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_seed_documents_prerun_keys.py +0 -0
  656. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_service_bus_dlq_adapter.py +0 -0
  657. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_session_env_preflight.py +0 -0
  658. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_aliases.py +0 -0
  659. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_backfill_apply.py +0 -0
  660. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_backfill_bugs_only.py +0 -0
  661. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_backfill_end_to_end.py +0 -0
  662. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_backfill_limit.py +0 -0
  663. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_backfill_marker.py +0 -0
  664. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_backfill_run.py +0 -0
  665. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_label_projection.py +0 -0
  666. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_reconciliation.py +0 -0
  667. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_severity_rubric.py +0 -0
  668. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_shipped_templates_parse.py +0 -0
  669. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_skill_discovery_links.py +0 -0
  670. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_skills_vendored_in_sync.py +0 -0
  671. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_spec_work_unit_rules.py +0 -0
  672. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_spend_counts_cache_tokens.py +0 -0
  673. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_spinning_rearm_gate.py +0 -0
  674. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_spinning_repeat_same_failing_set.py +0 -0
  675. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_spinout_brief_end_to_end.py +0 -0
  676. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_spinout_brief_replan_option.py +0 -0
  677. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_squash_commit_hook_crash.py +0 -0
  678. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_stop_rationale_captured.py +0 -0
  679. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_stranded_halt_cause.py +0 -0
  680. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_surefire_run_level_signature.py +0 -0
  681. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_surefire_verdict_lines.py +0 -0
  682. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_template_closing_shapes.py +0 -0
  683. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_terminal_auto_close_changelog.py +0 -0
  684. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_terminal_flip_ownership.py +0 -0
  685. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_terminal_flips.py +0 -0
  686. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_terminal_gate_message.py +0 -0
  687. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_terminal_judge_editing_end_to_end.py +0 -0
  688. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_tiered_verification_e2e.py +0 -0
  689. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_timeout_kill_portable.py +0 -0
  690. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage.py +0 -0
  691. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_apply.py +0 -0
  692. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_projects_severity_label.py +0 -0
  693. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_reads_comments.py +0 -0
  694. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_severity_classify.py +0 -0
  695. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_severity_end_to_end.py +0 -0
  696. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_severity_label_conflict.py +0 -0
  697. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_severity_write.py +0 -0
  698. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_skill_contract.py +0 -0
  699. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_triage_skips_agent_escalations.py +0 -0
  700. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_tsc_verdict_lines.py +0 -0
  701. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_umbrella_version_resolution.py +0 -0
  702. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_unreadable_pr_listing_holds_pr_work.py +0 -0
  703. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_unterminated_frontmatter.py +0 -0
  704. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_untracked_feature_folder.py +0 -0
  705. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_untracked_file_absorption.py +0 -0
  706. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_upgrade_gitignore_lines.py +0 -0
  707. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_upgrade_integration.py +0 -0
  708. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_upgrade_merge_gate.py +0 -0
  709. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_validate_event.py +0 -0
  710. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_validate_event_driver_types.py +0 -0
  711. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_validate_feature_dirs_only.py +0 -0
  712. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_verdict_coupling.py +0 -0
  713. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_verify_empty_gate_set.py +0 -0
  714. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_version_consistency.py +0 -0
  715. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_version_skew.py +0 -0
  716. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_windows_gate_exec.py +0 -0
  717. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_worktree_restore.py +0 -0
  718. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_wu_execution_metadata.py +0 -0
  719. {specfuse_loop-0.32.0 → specfuse_loop-0.33.0}/tests/test_wu_template_renders_lintable.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfuse-loop
3
- Version: 0.32.0
3
+ Version: 0.33.0
4
4
  Summary: Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology.
5
5
  Author: Specfuse contributors
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specfuse-loop"
7
- version = "0.32.0"
7
+ version = "0.33.0"
8
8
  description = "Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1 @@
1
+ 0.33.0
@@ -86,11 +86,14 @@ operator) it starts 24 hours back instead, and the run summary says so.
86
86
  The window applies to the checks that read event history: `error-logs` and
87
87
  `http-5xx` filter on `ingestion_time()`, so a row stamped just before the
88
88
  previous run but ingested after it is read by the next run rather than lost
89
- between the two. Three check types are deliberately not bounded by it:
89
+ between the two. These check types are deliberately not bounded by it:
90
90
 
91
91
  - `heartbeat` needs the most recent heartbeat however old it is;
92
+ - `backlog-stalled` reads each backlog's latest snapshot within a fixed
93
+ 7-day lookback, since a stall is a state, not an event;
92
94
  - `http-status-regression` compares the windows around each deployment and
93
95
  carries its own fixed lookback;
96
+ - `dependency-regression` does the same for the component's dependency calls;
94
97
  - `invariant` runs the operator's query as written. A query that reads event
95
98
  history should bound itself (for example `| where TimeGenerated > ago(1h)`);
96
99
  otherwise every matching row in retention is a finding, deduplicated only by
@@ -184,6 +187,7 @@ the issue was last updated (UTC), what was seen in this run (count, first, last,
184
187
  | `dlq` | Message (id, sequence number, subject, enqueued time, delivery count), Dead-letter reason, or the Exception message and top stack frames when the reason is blank, Body shape (the top-level keys, never the values), Peek it |
185
188
  | `heartbeat` | Schedule (cron, dialect, timezone, expected firing), Last run (the function's last execution and result), Host last seen, a Host silent line when the component sent no request telemetry across the expected firing, and Earliest heartbeat (the component's first heartbeat, which the grace rule measures from) |
186
189
  | `queue-stalled` | Queue (oldest active message age, depth, `stall_after`), Where |
190
+ | `backlog-stalled` | Thresholds (`stall_after`, `silent_after`), Latest snapshot (time, oldest pending age, pending count), Investigate |
187
191
 
188
192
  A section with nothing to say is left out rather than printed empty. A
189
193
  `queue-stalled` finding cannot show when the subscription last completed a
@@ -85,16 +85,18 @@ confidence in the checks grows.
85
85
 
86
86
  ## Check types
87
87
 
88
- Every check has a required `type`, one of seven neutral values. This set is
88
+ Every check has a required `type`, one of the neutral values in the table below. This set is
89
89
  provider-agnostic by construction: a check type names a concept
90
90
  (a dead-letter queue, a heartbeat), never a vendor.
91
91
 
92
92
  | Type | Extra required fields | Meaning |
93
93
  |---|---|---|
94
+ | `backlog-stalled` | `targets` | Alerts when a work queue the component keeps in its **own data store** (a transactional outbox, a job table drained by a poller) stops draining. Its rows never reach a broker, so `dlq` and `queue-stalled` cannot see it, and `heartbeat` only proves the poller fired. The component reports each backlog itself as a `BacklogSnapshot` event (the emission contract is in `.specfuse/rules/design-for-diagnosis.md`); the monitor never reads the data store. One finding per (component, backlog `name`) while the latest snapshot's oldest pending item is older than `stall_after`, failure class `stalled-backlog`; with `silent_after` set, a separate `silent-backlog` finding when no snapshot for that backlog arrived within it (the reporter died). The backlog name is the signature, so a stall that lasts many runs stays one issue. `pendingCount` appears in the finding but is never compared against a threshold: this is not volume alerting. A component that has emitted no snapshot at all in the last 7 days yields nothing, since a never-deployed reporter and a dead one look the same. |
94
95
  | `dlq` | `harvest_mode` (`peek` or `quarantine`), `targets` | Alerts on messages landing in this component's dead-letter queue. `peek` reads without removing; `quarantine` removes after reading. `targets` is **required**: a dead-lettered message is attributed to a subscription, and a target-less `dlq` check on a multi-subscription host cannot say which one. |
95
96
  | `error-logs` | none | Scans structured application logs for error-level entries. |
96
97
  | `http-5xx` | none | Alerts when the rolling 5xx rate crosses a threshold. For HTTP-serving components. |
97
98
  | `http-status-regression` | `deploy_signal`, `window_after_deploy` | Alerts when a deployment raises the rate of server-fault 4xx responses compared with the window before it. For HTTP-serving components that stamp a version on every deployment. `deploy_signal` is a mapping with a required `kind`; the only accepted `kind` is `app-version`. `window_after_deploy` is a duration (`<integer><unit>`, e.g. `30m`). `codes` is optional: a non-empty list of unique integers in 400–499, defaulting to `[403, 405, 415]`. Other codes are opt-in: `401` because a 401 wave is as often expired client tokens as a broken deployment, and `410`, `412`, `428` because few services return them. A code fires when its **share of the component's requests** in the window after the deployment is at least 3× its share in the equal window before, and it occurs at least 10 times after; both thresholds are fixed constants, not fields, and comparing shares keeps a traffic ramp from reading as a regression. Each finding states both shares and counts, the deployment's first-seen time, the code's top five operations by after-window count, up to three sample operation ids, and a Log Analytics query covering both windows. |
99
+ | `dependency-regression` | `deploy_signal`, `window_after_deploy` | Alerts when a deployment makes the component's calls to one of its dependencies — its own database first — start failing. For components that stamp a version on every deployment and call a data store or another dependency the telemetry records. `deploy_signal` and `window_after_deploy` are the same block `http-status-regression` takes, validated by the same rules. `dependency_types` is optional: a non-empty list of unique dependency type names as the telemetry records them (e.g. `[SQL]`, matched case-insensitively), defaulting to every type the component records. `min_failures` is optional: an integer of at least 1, defaulting to `5`, so one transient failure is not a regression. A (dependency type, target) pair fires when, in the window after the deployment, it has at least `min_failures` failed calls **and** its failure rate (failed calls ÷ all calls to that pair) is at least 3× its rate in the equal window before — the same fixed factor as `http-status-regression`. A pair with no calls or no failures before the deployment has a before-rate of 0, so a new query that fails, or a target that never failed before, fires on the floor alone; comparing rates keeps a traffic ramp from reading as a regression. One finding per (deployment, type, target); its signature is the version, type, target and the top failing result code. Each finding states both rates and counts, the deployment's first-seen time, the failing result codes, up to three sample operation ids, and a Log Analytics query covering both windows. **Failures only, by decision (#3577):** a failed call is discrete, while latency is a distribution comparison closer to metrics; a latency regression surfaces here once it becomes a timeout, which is a failed call. An opt-in `latency_ratio` remains a possible later decision, to be made explicitly rather than by precedent. |
98
100
  | `heartbeat` | none | Alerts when the component stops reporting in at all. |
99
101
  | `invariant` | `query`, `fingerprint_by` | Runs an operator-supplied query (opaque to this schema — not parsed or executed here) and alerts on unexpected rows. `fingerprint_by` names the field used to dedupe repeat findings into one issue. |
100
102
  | `queue-stalled` | `targets` | Alerts when a consumer stops consuming from a subscription — no message failed (so `dlq` sees nothing), the host is still alive (so `heartbeat` sees nothing), and the symptom is a broker coordinate (queue depth / age of oldest message), not a telemetry query, so `invariant` cannot express it either. `targets` is required from birth: a wedged consumer on a multi-subscription host raises the identical "which one" question `dlq`/`heartbeat` targets already answer. |
@@ -108,6 +110,43 @@ schema (`AppRequests`, `AppExceptions`, `AppEvents`, with `AppRoleName`,
108
110
  (`requests`, `exceptions`, `customEvents`, `cloud_RoleName`, `timestamp`,
109
111
  `customDimensions`), which a workspace does not resolve.
110
112
 
113
+ ## Scope: a component's data store is monitored through the component, never directly
114
+
115
+ The monitor watches component misbehaviour, not metrics or infrastructure.
116
+ A component's data store sits on that boundary; this is where the line falls
117
+ (#3578, also stated in `.specfuse/rules/design-for-diagnosis.md`).
118
+
119
+ **The monitor never connects to a component's data store.** There is no SQL,
120
+ document-store or cache provider, and none will be added: the harvester holds
121
+ telemetry and broker read access only. A data-store connection would mean
122
+ holding credentials to production (often personal) data, coupling a check to a
123
+ schema that a migration can silently break, and adding one provider per engine.
124
+
125
+ **Data-store signals the component owns are in scope, and the component emits
126
+ them as telemetry:**
127
+
128
+ | Signal | Read by |
129
+ |---|---|
130
+ | Backlogs in data-store tables (rows waiting past their expected processing time) | the planned `backlog-stalled` check type (#3576) |
131
+ | Dependency failures that start after a deployment, including data-store calls | the planned `dependency-regression` check type (#3577) |
132
+ | Business-state invariants over persisted data: orphaned rows, records stuck in a state past their deadline, migration drift (the release expects migration N, the store reports M) | the existing `invariant` check |
133
+
134
+ The component computes each invariant itself and emits the result; `invariant`
135
+ queries that telemetry, never the store. This is `invariant`'s sanctioned
136
+ business-state use, not the rate-shaped use FEAT-2026-0069 ruled out.
137
+
138
+ **Data-store platform health is out of scope:** CPU and throughput-unit
139
+ consumption, storage, connections, deadlock rate, replication lag, failover. The
140
+ fix for these lives in infrastructure, not the component's repository, so a
141
+ finding has nowhere to route and autofix cannot act on it. They belong to the
142
+ platform's own infrastructure alerting, owned by whoever owns the
143
+ infrastructure.
144
+
145
+ **The test for any future request:** would the fix be a pull request on the
146
+ component? If yes, it is in scope and the component emits the signal. If the
147
+ fix is a capacity or infrastructure change, it is out of scope. `monitor-lint`
148
+ needs no rule for this: a data-store provider does not exist to be configured.
149
+
111
150
  ## Check targets
112
151
 
113
152
  `component` and check `targets` are two different axes, and the schema keeps
@@ -146,11 +185,13 @@ triggers as `targets[]` is what keeps that property satisfiable.
146
185
  |---|---|---|---|
147
186
  | `dlq` | **required** | `subscription` (required), `function` (required) | `subscription` is what the harvester queries; `function` is what a human diagnoses by — a subscription name alone rarely tells an on-call engineer which handler failed. |
148
187
  | `queue-stalled` | **required** | `subscription` (required), `function` (required), `stall_after` (optional, `<integer><unit>` with unit `s`/`m`/`h`/`d`, e.g. `15m`) | Same `subscription`/`function` coordinates as `dlq` — same subscription, same on-call-facing handler name. `stall_after` (how long is too long since the last message) must match `<integer><unit>` with unit `s`, `m`, `h` or `d` (e.g. `15m`, `90s`, `2h`, `1d`); the linter rejects any other value — the harvester would refuse it on its first poll. A target with no `stall_after` is skipped and recorded at runtime. Only the grammar is checked, not a range. |
188
+ | `backlog-stalled` | **required** | `name` (required), `stall_after` (required), `silent_after` (optional) | `name` is the `backlogName` the component emits. Both durations use the `<integer><unit>` grammar (unit `s`/`m`/`h`/`d`, e.g. `15m`); the linter rejects any other value. Only the grammar is checked, not a range. |
149
189
  | `heartbeat` | optional | `name` (required), `cron` (optional), `dialect` (required when `cron` present), `timezone` (optional) | One target per schedule, so a single silent timer among several stays individually visible. A single-schedule component may omit the list. |
150
190
  | `invariant` | **forbidden** | — | `fingerprint_by` is already this check type's enumeration key; permitting `targets` too would give it two competing enumeration keys. |
151
191
  | `error-logs` | **forbidden** | — | Role-name keyed and genuinely component-scoped; the validator rejects `targets` here. |
152
192
  | `http-5xx` | **forbidden** | — | Same reason as `error-logs`. |
153
193
  | `http-status-regression` | **forbidden** | — | Per-component, like `http-5xx`: the deployment it compares across is a component-wide event. |
194
+ | `dependency-regression` | **forbidden** | — | Same reason as `http-status-regression`; the (dependency type, target) pair a finding names comes from the telemetry, not from configuration. |
154
195
 
155
196
  Where `targets` is present it must be a non-empty list of mappings, and every
156
197
  entry must carry that check type's required coordinates. An empty list is a
@@ -38,7 +38,8 @@ the shipped GitHub Actions template — see
38
38
  itself.
39
39
 
40
40
  **What it reads.** `.specfuse/monitoring.yml`: each component's checks
41
- (`error-logs`, `http-5xx`, `http-status-regression`, `dlq`, `queue-stalled`,
41
+ (`error-logs`, `http-5xx`, `http-status-regression`, `dependency-regression`, `dlq`, `queue-stalled`,
42
+ `backlog-stalled`,
42
43
  `heartbeat`, `invariant`), each environment's telemetry and broker bindings.
43
44
  Event-history checks read only what arrived since the previous run (the
44
45
  watermark in `.specfuse/monitor-watermarks/<env>.json`, or the last 24 hours on
@@ -289,7 +289,7 @@ const FLOWS = [
289
289
  entry: "a failure in a deployed component", who: "specfuse monitor run, then specfuse-agent or you", ceremony: "one issue per fingerprint",
290
290
  summary: "Work that starts in production. The monitor files one issue per distinct failure; two per-component dials in monitoring.yml decide how far it goes without you. Findings skip triage and the bug lane on purpose: their route to a fix is diagnose, then autofix.",
291
291
  stages: [
292
- { k: "auto", t: "Detect", c: "specfuse monitor run", d: "Runs each component's checks against its telemetry and broker: error-logs, http-5xx, http-status-regression, dlq, queue-stalled, heartbeat, invariant. Reads only what arrived since the last run (the watermark), or the last 24 hours on a first run. One failing check is reported and the rest still run.", rows: { Reads: ".specfuse/monitoring.yml, App Insights, Service Bus", Scheduled: "by you: cron, CI, or later the in-cluster runner" } },
292
+ { k: "auto", t: "Detect", c: "specfuse monitor run", d: "Runs each component's checks against its telemetry and broker: error-logs, http-5xx, http-status-regression, dependency-regression, dlq, queue-stalled, backlog-stalled, heartbeat, invariant. Reads only what arrived since the last run (the watermark), or the last 24 hours on a first run. One failing check is reported and the rest still run.", rows: { Reads: ".specfuse/monitoring.yml, App Insights, Service Bus", Scheduled: "by you: cron, CI, or later the in-cluster runner" } },
293
293
  { k: "auto", t: "File", c: "one issue per fingerprint", d: "The fingerprint is component + check + normalised failure. New fingerprint: a new monitoring-finding issue. Same fingerprint, open issue: the occurrence count goes up (at most every 6 hours). The monitor reopens a closed finding but never closes one; a finding unseen for 7 days gets a one-time close-candidate comment. A schedule is not called silent before its component's first heartbeat.", rows: { "Closed issue": "reopened with a comment when it closed within 90 days", "dlq issue": "closing it acknowledges the message; only a new message id reopens it" } },
294
294
  { k: "human", t: "Diagnose", c: "diagnose: manual | auto", d: "manual: you run /diagnose-issue N. auto: specfuse-agent diagnoses each open, undiagnosed finding in a headless session. Either way one comment is posted: root cause, evidence, candidate fix, confidence (0 to 1), fix_scope (small, large, external) and severity (critical, high, medium, low, judged from the evidence); the finding gets one severity label. One diagnosis per issue, except a fresh one after the monitor reopens it following a fix, or when someone adds the rediagnose label.", stops: ["diagnose: manual — every finding waits for you", "diagnose: auto only acts when specfuse-agent is scheduled too"] },
295
295
  { k: "auto", t: "Decide", c: "autofix: \"off\" | \"on\"", d: "Fixed rules, not configuration: autofix off → decline. fix_scope large or external → route to you. confidence below 0.8 → route to you. Already attempted for this fingerprint → decline. Daily cap reached → decline. Otherwise → fire. Severity changes none of these rules: it only orders the queue, most severe first.", stops: ["Routed to a human: an escalation comment says which rule fired"] },
@@ -90,6 +90,19 @@ components:
90
90
  # codes defaults to [403, 405, 415]; this one also opts in to 401.
91
91
  codes: [401, 403, 405, 415]
92
92
 
93
+ # dependency-regression: alerts when a deployment makes calls to one of
94
+ # the component's dependencies (its database first) start failing — a
95
+ # migration that did not run, a renamed column, a broken connection
96
+ # string. Same deploy_signal block as http-status-regression. Failures
97
+ # only: a slow query is seen once it times out. A (type, target) pair
98
+ # fires at min_failures failed calls and 3x its pre-deploy failure rate.
99
+ - type: dependency-regression
100
+ deploy_signal:
101
+ kind: app-version
102
+ window_after_deploy: 1h
103
+ dependency_types: [SQL] # default: every type the component records
104
+ min_failures: 5 # default 5
105
+
93
106
  # heartbeat: alerts when the component stops reporting in at all —
94
107
  # the check that catches "it didn't error, it just went silent."
95
108
  - type: heartbeat
@@ -123,6 +136,20 @@ components:
123
136
  query: "select count(*) from orders where fulfilled_at is null and created_at < now() - interval '1 day'"
124
137
  fingerprint_by: order_id
125
138
 
139
+ # backlog-stalled: catches a work queue this component keeps in its OWN
140
+ # data store (a transactional outbox, a job table) that has stopped
141
+ # draining. The rows never reach the broker, so `dlq`/`queue-stalled`
142
+ # see nothing. The component reports each backlog itself as a
143
+ # `BacklogSnapshot` event (see .specfuse/rules/design-for-diagnosis.md);
144
+ # `name` is that event's `backlogName`. `stall_after`: the oldest pending
145
+ # item older than this is a finding. `silent_after` (optional): no
146
+ # snapshot at all for this long is a finding — the reporter died.
147
+ - type: backlog-stalled
148
+ targets:
149
+ - name: acme-event-outbox
150
+ stall_after: 15m
151
+ silent_after: 30m
152
+
126
153
  - type: heartbeat
127
154
 
128
155
  # acme-functions-host: the motivating shape this feature exists for. One
@@ -7,7 +7,7 @@ Licensed under the Apache License, Version 2.0. See LICENSE.
7
7
 
8
8
  This rule governs the *target application's* code — not this loop's own
9
9
  execution. It states what a deployed component must do so the check types a
10
- `monitoring.yml` admits (`dlq`, `error-logs`, `http-5xx`,
10
+ `monitoring.yml` admits (`backlog-stalled`, `dependency-regression`, `dlq`, `error-logs`, `http-5xx`,
11
11
  `http-status-regression`, `heartbeat`, `invariant`, `queue-stalled`) produce a diagnosable finding instead of a bare alert. A check that
12
12
  fires without one of these properties tells an operator only that something is
13
13
  wrong, not what or where.
@@ -20,6 +20,43 @@ implementations. How a project achieves a property (which library, which
20
20
  platform's native tracing, which log shipper) belongs in that project's
21
21
  `.specfuse/rules-local/`, never here.
22
22
 
23
+ ## A component's data store is monitored through the component, never directly
24
+
25
+ The monitor watches component misbehaviour, not metrics or infrastructure.
26
+ A component's data store sits on that boundary, so the line is drawn here once
27
+ rather than differently in each project.
28
+
29
+ **The monitor never connects to a component's data store.** There is no
30
+ data-store provider for any engine; the harvester holds telemetry and broker
31
+ read access only. Three reasons: credentials (a data store holds production
32
+ data, often personal data), schema coupling (a migration silently breaks a check
33
+ that reads tables directly), and provider sprawl (one adapter per engine).
34
+
35
+ **Data-store signals the component owns are in scope, and the component emits
36
+ them** as telemetry, the same way it emits everything else this rule covers:
37
+
38
+ - backlogs in data-store tables — rows waiting past their expected processing
39
+ time — for the planned `backlog-stalled` check type (#3576);
40
+ - dependency failures that start after a deployment, including calls to the
41
+ data store, for the planned `dependency-regression` check type (#3577);
42
+ - business-state invariants over persisted data — orphaned rows, records stuck
43
+ in a state past their deadline, or migration drift (the running release
44
+ expects migration N while the store reports M). The component computes these
45
+ itself and emits the result; the existing `invariant` check reads that
46
+ telemetry. This is `invariant`'s sanctioned business-state use; a
47
+ rate-shaped signal is not an invariant and belongs to its own check type.
48
+
49
+ **Data-store platform health is out of scope:** CPU and throughput-unit
50
+ consumption, storage, connections, deadlock rate, replication lag, failover.
51
+ The fix for these lives in infrastructure, not in the component's repository,
52
+ so a finding has nowhere to route and an automated fix cannot act on it. They
53
+ belong to the platform's own infrastructure alerting, owned by whoever owns the
54
+ infrastructure.
55
+
56
+ **The test for any future request:** would the fix be a pull request on the
57
+ component? If yes, the signal is in scope and the component emits it. If the fix
58
+ is a capacity or infrastructure change, it is out of scope.
59
+
23
60
  ## Correlation IDs propagate across component boundaries
24
61
 
25
62
  A single request or message carries one correlation ID from the moment it enters
@@ -94,6 +131,37 @@ indistinguishable from one whose schedule has stopped — the check reports ever
94
131
  target as silent from its first run, and the real silence, when it comes, is
95
132
  lost in that noise.
96
133
 
134
+ ## Data-store work queues report a backlog snapshot
135
+
136
+ A component that keeps a work queue in its own data store — a transactional
137
+ outbox table, a job table, a pending-work table drained by a poller loop —
138
+ periodically reports the state of each such backlog, in exactly this shape: one
139
+ custom event named `BacklogSnapshot` per backlog it owns, emitted under the
140
+ component's role name, carrying:
141
+
142
+ - `backlogName` — a stable identifier for the backlog (for example
143
+ `event-outbox`), the same string as the `name` of the matching
144
+ `backlog-stalled` target in `monitoring.yml`;
145
+ - `oldestPendingAgeSeconds` — the age in seconds of the oldest unprocessed
146
+ item, `0` when the backlog is empty;
147
+ - `pendingCount` — optional, the number of unprocessed items.
148
+
149
+ Emit on a fixed interval from the component's own process, independently of
150
+ whether the drainer succeeds, so the snapshot keeps arriving while the drainer
151
+ is wedged.
152
+
153
+ A broker-level check cannot see this queue: rows still in an outbox never reach
154
+ the broker, so the broker looks quiet and healthy, and a schedule that fires on
155
+ time proves nothing about whether the rows it should drain are moving. A
156
+ `backlog-stalled` check reads the latest snapshot per backlog and reports when
157
+ its oldest pending item is older than the target's `stall_after`, and, when the
158
+ target sets `silent_after`, when no snapshot for that backlog arrived within it
159
+ — the reporter itself has stopped. `pendingCount` only enriches the finding; it
160
+ is never compared against a threshold, because this is a "work is waiting and
161
+ not moving" signal, not volume alerting. The component reports its own backlog
162
+ so the monitor never needs credentials to, or knowledge of the schema of, the
163
+ data store itself.
164
+
97
165
  ## DLQ entries carry failure context, not just the payload
98
166
 
99
167
  A message that lands in a dead-letter queue carries, alongside its original
@@ -122,3 +190,15 @@ that stamps no version has no deployment signal at all; one that stamps the same
122
190
  value every release shows no new version to detect, so the check never opens its
123
191
  post-deployment window and a regression ships unseen. Either way the check
124
192
  cannot be evaluated, and discovery reports the gap rather than proposing it.
193
+
194
+ A `dependency-regression` check reads the same version stamp from the
195
+ component's outbound dependency calls — its database first — so the property
196
+ applies to any component that calls a data store, HTTP-serving or not. Each
197
+ call must be recorded with its dependency type, its target and a success flag
198
+ (and the result code where the client has one); a component that catches a
199
+ failed query and degrades still records that call as failed, which is exactly
200
+ what the check looks for. The check is failures only, by decision (#3577): a
201
+ failed call is discrete, while latency is a distribution comparison closer to
202
+ metrics. A query that slows down after a deployment surfaces once it times out,
203
+ because a timeout is a failed call. An opt-in latency ratio stays a possible
204
+ later decision, to be made explicitly rather than by precedent.
@@ -46,6 +46,8 @@ DIAGNOSE_VALUES = frozenset({"manual", "auto"})
46
46
  AUTOFIX_VALUES = frozenset({"off", "on"})
47
47
  CHECK_TYPES = frozenset(
48
48
  {
49
+ "backlog-stalled",
50
+ "dependency-regression",
49
51
  "dlq",
50
52
  "error-logs",
51
53
  "http-5xx",
@@ -262,6 +264,15 @@ def _check_checks(checks: object, component_label: str) -> list[str]:
262
264
  )
263
265
  elif check_type == "http-status-regression":
264
266
  findings.extend(_check_http_status_regression(check, component_label, index))
267
+ elif check_type == "backlog-stalled":
268
+ if check.get("targets") is None:
269
+ findings.append(
270
+ f"component '{component_label}': checks[{index}]: "
271
+ f"'backlog-stalled' check requires 'targets' — each target "
272
+ f"needs 'name' and 'stall_after'"
273
+ )
274
+ elif check_type == "dependency-regression":
275
+ findings.extend(_check_dependency_regression(check, component_label, index))
265
276
  elif check_type == "invariant":
266
277
  for field in ("query", "fingerprint_by"):
267
278
  if not check.get(field):
@@ -282,6 +293,7 @@ def _check_checks(checks: object, component_label: str) -> list[str]:
282
293
  # they are role-name keyed and therefore genuinely component-scoped; see
283
294
  # `_TARGETLESS_CHECK_TYPES` below.
284
295
  _TARGET_REQUIRED_FIELDS = {
296
+ "backlog-stalled": ("name", "stall_after"),
285
297
  "dlq": ("subscription", "function"),
286
298
  "heartbeat": ("name",),
287
299
  "queue-stalled": ("subscription", "function"),
@@ -289,13 +301,10 @@ _TARGET_REQUIRED_FIELDS = {
289
301
  DEPLOY_SIGNAL_KINDS = frozenset({"app-version"})
290
302
 
291
303
 
292
- def _check_http_status_regression(
293
- check: dict, component_label: str, check_index: int
294
- ) -> list[str]:
295
- """Field rules for one `http-status-regression` check (`targets` is
296
- rejected by `_check_targets`)."""
297
- where = f"component '{component_label}': checks[{check_index}]"
298
- prefix = f"{where}: 'http-status-regression' check"
304
+ def _check_deploy_window(check: dict, prefix: str) -> list[str]:
305
+ """The deploy-correlated block every deployment-windowed check type shares
306
+ (`http-status-regression`, `dependency-regression`): a `deploy_signal`
307
+ mapping with a known `kind`, and a `window_after_deploy` duration."""
299
308
  findings: list[str] = []
300
309
 
301
310
  signal = check.get("deploy_signal")
@@ -320,6 +329,17 @@ def _check_http_status_regression(
320
329
  f"{prefix} 'window_after_deploy' value {window!r} is not a "
321
330
  f"valid duration — expected {DURATION_GRAMMAR}"
322
331
  )
332
+ return findings
333
+
334
+
335
+ def _check_http_status_regression(
336
+ check: dict, component_label: str, check_index: int
337
+ ) -> list[str]:
338
+ """Field rules for one `http-status-regression` check (`targets` is
339
+ rejected by `_check_targets`)."""
340
+ where = f"component '{component_label}': checks[{check_index}]"
341
+ prefix = f"{where}: 'http-status-regression' check"
342
+ findings = _check_deploy_window(check, prefix)
323
343
 
324
344
  codes = check.get("codes")
325
345
  if codes is not None:
@@ -339,9 +359,47 @@ def _check_http_status_regression(
339
359
  return findings
340
360
 
341
361
 
362
+ def _check_dependency_regression(
363
+ check: dict, component_label: str, check_index: int
364
+ ) -> list[str]:
365
+ """Field rules for one `dependency-regression` check (#3577): the shared
366
+ deploy block, an optional `dependency_types` list (default: every type
367
+ the component records) and an optional `min_failures` floor (default 5).
368
+ `targets` is rejected by `_check_targets`."""
369
+ where = f"component '{component_label}': checks[{check_index}]"
370
+ prefix = f"{where}: 'dependency-regression' check"
371
+ findings = _check_deploy_window(check, prefix)
372
+
373
+ types = check.get("dependency_types")
374
+ if types is not None:
375
+ if (
376
+ not isinstance(types, list)
377
+ or not types
378
+ or not all(isinstance(t, str) and t.strip() for t in types)
379
+ ):
380
+ findings.append(
381
+ f"{prefix} 'dependency_types' must be a non-empty list of "
382
+ f"dependency type names (e.g. [SQL]) — omit it for every type"
383
+ )
384
+ elif len({t.lower() for t in types}) != len(types):
385
+ findings.append(f"{prefix} 'dependency_types' must not contain duplicates")
386
+
387
+ min_failures = check.get("min_failures")
388
+ if min_failures is not None and (
389
+ not isinstance(min_failures, int)
390
+ or isinstance(min_failures, bool)
391
+ or min_failures < 1
392
+ ):
393
+ findings.append(
394
+ f"{prefix} 'min_failures' must be an integer of at least 1, "
395
+ f"got {min_failures!r}"
396
+ )
397
+ return findings
398
+
399
+
342
400
  # Check types that must never carry `targets` at all.
343
401
  _TARGETLESS_CHECK_TYPES = frozenset(
344
- {"error-logs", "http-5xx", "http-status-regression", "invariant"}
402
+ {"dependency-regression", "error-logs", "http-5xx", "http-status-regression", "invariant"}
345
403
  )
346
404
 
347
405
 
@@ -360,7 +418,8 @@ def _check_targets(
360
418
  check type is required to interpret. `cron`'s field *values* stay
361
419
  opaque; only the field *count* is checked. `timezone` and
362
420
  `invariant.query` are untouched by this and remain fully opaque.
363
- `targets` itself is required for `dlq` and `queue-stalled` (enforced in
421
+ `targets` itself is required for `dlq`, `queue-stalled` and
422
+ `backlog-stalled` (enforced in
364
423
  `_check_checks`, since a missing key and an empty/malformed one are
365
424
  different findings). `error-logs`, `http-5xx`, and `invariant` must not
366
425
  carry `targets` at all; every other check type treats `targets` as
@@ -405,6 +464,28 @@ def _check_targets(
405
464
  f"'stall_after' value {target['stall_after']!r} is not a "
406
465
  f"valid duration — expected {DURATION_GRAMMAR}"
407
466
  )
467
+ if check_type == "backlog-stalled":
468
+ findings.extend(_check_backlog_durations(target, where, t_index))
469
+ return findings
470
+
471
+
472
+ def _check_backlog_durations(target: dict, where: str, t_index: int) -> list[str]:
473
+ """`stall_after` and the optional `silent_after` of one `backlog-stalled`
474
+ target must parse with the shared duration grammar (#3576). A missing
475
+ `stall_after` is already reported by the required-fields pass."""
476
+ findings: list[str] = []
477
+ for field in ("stall_after", "silent_after"):
478
+ value = target.get(field)
479
+ if value is None or (field == "stall_after" and not value):
480
+ continue
481
+ try:
482
+ parse_duration_seconds(str(value), field)
483
+ except ValueError:
484
+ findings.append(
485
+ f"{where}: targets[{t_index}]: 'backlog-stalled' target "
486
+ f"'{field}' value {value!r} is not a valid duration — "
487
+ f"expected {DURATION_GRAMMAR}"
488
+ )
408
489
  return findings
409
490
 
410
491
 
@@ -135,7 +135,7 @@ SPECFUSE_DIR = Path(".specfuse")
135
135
  REPO_ROOT = SPECFUSE_DIR.parent
136
136
  FEATURES_DIR = SPECFUSE_DIR / "features"
137
137
  VERIFICATION_PATH = SPECFUSE_DIR / "verification.yml"
138
- DRIVER_VERSION = "0.32.0"
138
+ DRIVER_VERSION = "0.33.0"
139
139
  # Oldest scaffold layout this driver can drive. init.sh stamps the scaffold's own
140
140
  # version into `.specfuse/VERSION`; check_scaffold_version() fails loud at startup if
141
141
  # the consumer's scaffold is older than this, pointing at `specfuse upgrade`. Bump
@@ -24,6 +24,7 @@ from typing import Mapping, Optional
24
24
  # requirements without importing from lint_monitoring.py — that module is
25
25
  # gate 2's, and this WU only reads its shape (see the WU's "do not touch").
26
26
  _TARGET_COORDINATE_FIELDS: Mapping[str, tuple[str, ...]] = {
27
+ "backlog-stalled": ("name",),
27
28
  "dlq": ("subscription", "function"),
28
29
  "heartbeat": ("name",),
29
30
  "queue-stalled": ("subscription", "function"),
@@ -32,7 +33,7 @@ _TARGET_COORDINATE_FIELDS: Mapping[str, tuple[str, ...]] = {
32
33
  # Check types that must never carry target coordinates — 0069 rejected
33
34
  # `targets` on these, so `fingerprint_by` stays their single enumeration key.
34
35
  _TARGETLESS_CHECK_TYPES = frozenset(
35
- {"error-logs", "http-5xx", "http-status-regression", "invariant"}
36
+ {"dependency-regression", "error-logs", "http-5xx", "http-status-regression", "invariant"}
36
37
  )
37
38
 
38
39
 
@@ -57,7 +57,7 @@ import time
57
57
  from dataclasses import dataclass
58
58
  from typing import Callable, Optional
59
59
 
60
- from specfuse.monitor.issues import DEFAULT_LIST_LIMIT, FINDING_LABEL, find_finding_issue
60
+ from specfuse.monitor.issues import DEFAULT_LIST_LIMIT, FINDING_LABEL, FINDING_LIST_LIMIT, find_finding_issue
61
61
 
62
62
  # Reserved for FEAT-2026-0042 gate 2: applied to a finding issue once a fired
63
63
  # autofix attempt is known to have failed. See module docstring.
@@ -94,7 +94,7 @@ def has_prior_attempt(runner: Callable, repo: str, fingerprint: str) -> bool:
94
94
  (the runner raises, the listing is truncated) fails closed: True.
95
95
  """
96
96
  try:
97
- issue = find_finding_issue(runner, repo, fingerprint, limit=DEFAULT_LIST_LIMIT)
97
+ issue = find_finding_issue(runner, repo, fingerprint, limit=FINDING_LIST_LIMIT)
98
98
  except Exception: # noqa: BLE001 - fail closed on any read failure
99
99
  return True
100
100
  if issue is None:
@@ -119,7 +119,7 @@ def record_attempt(
119
119
  under a different convention.
120
120
  """
121
121
  now = time.time() if now is None else now
122
- issue = find_finding_issue(runner, repo, fingerprint, limit=DEFAULT_LIST_LIMIT)
122
+ issue = find_finding_issue(runner, repo, fingerprint, limit=FINDING_LIST_LIMIT)
123
123
  if issue is None:
124
124
  raise LookupError(f"no finding issue carries fingerprint {fingerprint!r}")
125
125
 
@@ -265,6 +265,8 @@ def _build_adapter(
265
265
  deploy_signal=check.get("deploy_signal"),
266
266
  window_after_deploy=check.get("window_after_deploy"),
267
267
  codes=check.get("codes"),
268
+ dependency_types=check.get("dependency_types"),
269
+ min_failures=check.get("min_failures"),
268
270
  # The harvest window (#3480): adapters that read event history
269
271
  # accept it; those that need older history by design do not.
270
272
  since=since,
@@ -678,11 +680,24 @@ def run_cycle(
678
680
  continue
679
681
  filed_fingerprints.add(fingerprint)
680
682
  recorder = _CallRecorder(gh_runner)
681
- record_finding(
682
- fingerprint, artifact, repo, runner=recorder, now=now.timestamp(),
683
- message_ids=tuple(message_ids.get(fingerprint, ())),
684
- seen=seen_by_fingerprint.get(fingerprint), ensure_label=ensure_label,
685
- )
683
+ # #3579: a filing error (a truncated listing, a gh failure)
684
+ # is isolated like a check error (#3478): reported, the
685
+ # watermark held so the window is retried, other
686
+ # components still filed.
687
+ try:
688
+ record_finding(
689
+ fingerprint, artifact, repo, runner=recorder, now=now.timestamp(),
690
+ message_ids=tuple(message_ids.get(fingerprint, ())),
691
+ seen=seen_by_fingerprint.get(fingerprint), ensure_label=ensure_label,
692
+ )
693
+ except Exception as exc: # noqa: BLE001 — isolation is the point
694
+ env_errored = True
695
+ errored_components.add(component_name)
696
+ summary.append(
697
+ f"{env_name}/{component_name}: filing errored — "
698
+ f"{type(exc).__name__}: {exc}"
699
+ )
700
+ continue
686
701
  outcome = _classify(recorder)
687
702
  if outcome == "created":
688
703
  created += 1
@@ -719,7 +734,7 @@ def run_cycle(
719
734
  if env_errored:
720
735
  any_errored = True
721
736
  summary.append(
722
- f"environment {env_name}: watermark not advanced — a check errored; "
737
+ f"environment {env_name}: watermark not advanced — a check or filing errored; "
723
738
  "its window is retried next cycle"
724
739
  )
725
740
  elif not dry_run:
@@ -70,6 +70,12 @@ REOPENED_MARKER = "<!-- specfuse:finding-reopened -->"
70
70
  REDIAGNOSE_LABEL = "rediagnose"
71
71
 
72
72
  DEFAULT_LIST_LIMIT = 100
73
+ # The finding lookups' own limit, apart from DEFAULT_LIST_LIMIT (which triage
74
+ # borrows as a page size). `gh issue list` pages internally and stops when the
75
+ # repo runs out, so a high limit costs nothing on a small repo. 100 was low
76
+ # enough that a busy project crossed it and every new fingerprint raised
77
+ # TruncatedListingError (#3579); a full page at this limit still raises.
78
+ FINDING_LIST_LIMIT = 2000
73
79
  DEFAULT_THROTTLE_SECONDS = 6 * 60 * 60
74
80
  # A finding with no sighting for this long is annotated as a close candidate
75
81
  # (#3502). Elapsed time, not a run count: the meta records when a fingerprint
@@ -330,7 +336,7 @@ def find_finding_issue(
330
336
  repo: str,
331
337
  fingerprint: str,
332
338
  *,
333
- limit: int = DEFAULT_LIST_LIMIT,
339
+ limit: int = FINDING_LIST_LIMIT,
334
340
  now: Optional[float] = None,
335
341
  ) -> Optional[dict]:
336
342
  """Return the listing row carrying `fingerprint`'s marker, or None.
@@ -376,7 +382,7 @@ def record_finding(
376
382
  *,
377
383
  runner: Optional[Callable] = None,
378
384
  now: Optional[float] = None,
379
- limit: int = DEFAULT_LIST_LIMIT,
385
+ limit: int = FINDING_LIST_LIMIT,
380
386
  throttle_seconds: float = DEFAULT_THROTTLE_SECONDS,
381
387
  message_ids: Sequence[str] = (),
382
388
  seen: Optional[SeenThisRun] = None,
@@ -501,7 +507,7 @@ def finding_component(body: str) -> Optional[str]:
501
507
  return match.group(1) if match else None
502
508
 
503
509
 
504
- def list_finding_issues(runner: Callable, repo: str, *, now: float, limit: int = DEFAULT_LIST_LIMIT) -> list:
510
+ def list_finding_issues(runner: Callable, repo: str, *, now: float, limit: int = FINDING_LIST_LIMIT) -> list:
505
511
  """Open finding issues plus those closed inside the lookup window, each
506
512
  carrying its `state` — the same single listing `find_finding_issue` reads."""
507
513
  return _list_findings(runner, repo, limit=limit, now=now)
@@ -523,7 +529,7 @@ def annotate_if_quiet(
523
529
  now: float,
524
530
  quiet_after_seconds: float = DEFAULT_QUIET_AFTER_SECONDS,
525
531
  runner: Optional[Callable] = None,
526
- limit: int = DEFAULT_LIST_LIMIT,
532
+ limit: int = FINDING_LIST_LIMIT,
527
533
  existing: Optional[dict] = None,
528
534
  ) -> Optional[str]:
529
535
  """Annotate an open finding issue as a close candidate once its fingerprint