specfuse-loop 0.9.2__tar.gz → 0.10.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 (348) hide show
  1. {specfuse_loop-0.9.2/specfuse_loop.egg-info → specfuse_loop-0.10.0}/PKG-INFO +20 -10
  2. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/README.md +19 -9
  3. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/pyproject.toml +1 -1
  4. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/closing_requirements.py +27 -2
  5. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/cost.py +21 -16
  6. specfuse_loop-0.10.0/specfuse/loop/criteria_state.py +195 -0
  7. specfuse_loop-0.10.0/specfuse/loop/data/VERSION +1 -0
  8. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +1 -1
  9. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/getting-started.md +17 -13
  10. specfuse_loop-0.10.0/specfuse/loop/data/docs/glossary.md +108 -0
  11. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/methodology.md +4 -2
  12. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/skills.md +3 -3
  13. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/monitoring-secrets-checklist.md +2 -2
  14. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/monitoring.overrides.yml.example +1 -1
  15. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/close-discipline.md +20 -3
  16. specfuse_loop-0.10.0/specfuse/loop/data/rules/human-output.md +85 -0
  17. specfuse_loop-0.10.0/specfuse/loop/data/rules/operator-escalation.md +160 -0
  18. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/result-contract.md +20 -0
  19. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/driver-event.schema.json +3 -2
  20. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/templates/GATE.template.md +1 -0
  21. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/templates/WU.template.md +26 -3
  22. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/verification.yml.example +11 -3
  23. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/workflows/specfuse-monitor.yml +3 -3
  24. specfuse_loop-0.10.0/specfuse/loop/driver_edit.py +67 -0
  25. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/labels.py +1 -1
  26. specfuse_loop-0.10.0/specfuse/loop/learnings_query.py +210 -0
  27. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/lint_closing.py +68 -1
  28. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/lint_plan.py +123 -3
  29. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/loop.py +734 -51
  30. specfuse_loop-0.10.0/specfuse/loop/prerun.py +136 -0
  31. specfuse_loop-0.10.0/specfuse/loop/prerun_capture.py +133 -0
  32. specfuse_loop-0.10.0/specfuse/loop/rearm_migration.py +267 -0
  33. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/scaffold.py +48 -2
  34. specfuse_loop-0.10.0/specfuse/loop/upgrade_merge_gate.py +156 -0
  35. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/autofix_run.py +1 -1
  36. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/cli.py +3 -3
  37. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0/specfuse_loop.egg-info}/PKG-INFO +20 -10
  38. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/SOURCES.txt +38 -0
  39. specfuse_loop-0.10.0/tests/test_autoclose_gate_note.py +140 -0
  40. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_closing_guard_contracts.py +3 -3
  41. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_closing_requirements.py +10 -2
  42. specfuse_loop-0.10.0/tests/test_criteria_state.py +91 -0
  43. specfuse_loop-0.10.0/tests/test_criteria_worklist.py +121 -0
  44. specfuse_loop-0.10.0/tests/test_deterministic_refusal_repeat.py +166 -0
  45. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_done_feature_gates.py +20 -0
  46. specfuse_loop-0.10.0/tests/test_driver_edit_detection.py +151 -0
  47. specfuse_loop-0.10.0/tests/test_driver_module_surface.py +97 -0
  48. specfuse_loop-0.10.0/tests/test_driver_restart_halt_wiring.py +278 -0
  49. specfuse_loop-0.10.0/tests/test_driver_restart_hold.py +199 -0
  50. specfuse_loop-0.10.0/tests/test_driver_staleness_gate_summary.py +218 -0
  51. specfuse_loop-0.10.0/tests/test_driver_staleness_warning.py +169 -0
  52. specfuse_loop-0.10.0/tests/test_fold_contract_documented.py +127 -0
  53. specfuse_loop-0.10.0/tests/test_guard_refusal_failure_class.py +193 -0
  54. specfuse_loop-0.10.0/tests/test_human_output_rule.py +189 -0
  55. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_init_integration.py +4 -2
  56. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_learnings_query.py +60 -19
  57. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lifecycle_integration.py +12 -0
  58. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_closing.py +1 -1
  59. specfuse_loop-0.10.0/tests/test_lint_closing_criteria.py +299 -0
  60. specfuse_loop-0.10.0/tests/test_lint_closing_criteria_pristine.py +154 -0
  61. specfuse_loop-0.10.0/tests/test_load_bearing_close_lint.py +193 -0
  62. specfuse_loop-0.10.0/tests/test_loop_criteria_skeleton.py +230 -0
  63. specfuse_loop-0.10.0/tests/test_loop_criteria_survival.py +123 -0
  64. specfuse_loop-0.10.0/tests/test_loop_worklist_injection.py +215 -0
  65. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitor_cli.py +1 -1
  66. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitor_runner_surfaces.py +15 -3
  67. specfuse_loop-0.10.0/tests/test_oracle_set_declared.py +66 -0
  68. specfuse_loop-0.10.0/tests/test_prep_halt_operator_surface.py +252 -0
  69. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_prepare_feature.py +2 -2
  70. specfuse_loop-0.10.0/tests/test_prerun_capture.py +159 -0
  71. specfuse_loop-0.10.0/tests/test_prerun_oracles.py +152 -0
  72. specfuse_loop-0.10.0/tests/test_prerun_wiring.py +198 -0
  73. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_produces_shape.py +1 -1
  74. specfuse_loop-0.10.0/tests/test_rearm_fold_marker.py +143 -0
  75. specfuse_loop-0.10.0/tests/test_rearm_migration.py +306 -0
  76. specfuse_loop-0.10.0/tests/test_result_block_audience.py +157 -0
  77. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_roadmap_add_skill.py +215 -29
  78. specfuse_loop-0.10.0/tests/test_ruff_verdict_lines.py +98 -0
  79. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_data_in_sync.py +2 -0
  80. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_docs.py +1 -0
  81. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_init.py +3 -0
  82. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_resources.py +2 -0
  83. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_seed_sanity.py +51 -3
  84. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_wiring.py +64 -12
  85. specfuse_loop-0.10.0/tests/test_seed_documents_prerun_keys.py +30 -0
  86. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_upgrade_integration.py +1 -2
  87. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_upgrade_merge_gate.py +9 -23
  88. specfuse_loop-0.9.2/specfuse/loop/data/VERSION +0 -1
  89. specfuse_loop-0.9.2/specfuse/loop/data/rules/operator-escalation.md +0 -70
  90. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/LICENSE +0 -0
  91. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/NOTICE +0 -0
  92. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/setup.cfg +0 -0
  93. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/__init__.py +0 -0
  94. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/_filelock.py +0 -0
  95. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/_miniyaml.py +0 -0
  96. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/_wu_sections.py +0 -0
  97. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/adopt_feature.py +0 -0
  98. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/arm_eval.py +0 -0
  99. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/arm_sweep.py +0 -0
  100. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/arm_txn.py +0 -0
  101. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/changelog.py +0 -0
  102. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
  103. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/LEARNINGS.template.md +0 -0
  104. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
  105. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
  106. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
  107. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/gitignore.snippet +0 -0
  108. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/monitoring.yml.example +0 -0
  109. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/roadmap.template.md +0 -0
  110. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/correlation-ids.md +0 -0
  111. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
  112. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/never-touch.md +0 -0
  113. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/planning-discipline.md +0 -0
  114. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/security-boundaries.md +0 -0
  115. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/verification-discipline.md +0 -0
  116. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules-local/README.md +0 -0
  117. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/event.schema.json +0 -0
  118. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
  119. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
  120. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
  121. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
  122. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
  123. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/templates/PLAN.template.md +0 -0
  124. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/escalation.py +0 -0
  125. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/events_stats.py +0 -0
  126. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/gate_commands.py +0 -0
  127. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/gate_eval.py +0 -0
  128. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/gh_backend.py +0 -0
  129. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/gh_features.py +0 -0
  130. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/lint_monitoring.py +0 -0
  131. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/lint_roadmap.py +0 -0
  132. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/plan_baseline.py +0 -0
  133. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/validate_event.py +0 -0
  134. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/__init__.py +0 -0
  135. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/adapters.py +0 -0
  136. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/artifact.py +0 -0
  137. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/autofix.py +0 -0
  138. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/autofix_invoke.py +0 -0
  139. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/autofix_state.py +0 -0
  140. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/diagnose_cli.py +0 -0
  141. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/diagnosis.py +0 -0
  142. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/fingerprint.py +0 -0
  143. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/issues.py +0 -0
  144. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/providers/__init__.py +0 -0
  145. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/providers/_azure_auth.py +0 -0
  146. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/providers/azure_app_insights.py +0 -0
  147. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/providers/azure_service_bus.py +0 -0
  148. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/redaction.py +0 -0
  149. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/schedule.py +0 -0
  150. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/dependency_links.txt +0 -0
  151. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/entry_points.txt +0 -0
  152. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/requires.txt +0 -0
  153. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/top_level.txt +0 -0
  154. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_accept_hedged_close_headline.py +0 -0
  155. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_accept_hedged_close_skill.py +0 -0
  156. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_adopt_feature.py +0 -0
  157. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_app_insights_adapters.py +0 -0
  158. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_eval.py +0 -0
  159. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_eval_lint_class.py +0 -0
  160. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_eval_wiring.py +0 -0
  161. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_gate_edits_uncommitted.py +0 -0
  162. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_sweep.py +0 -0
  163. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_sweep_gate.py +0 -0
  164. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_txn.py +0 -0
  165. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_wiring.py +0 -0
  166. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_artifact_redaction.py +0 -0
  167. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_attempt_outcome_contract.py +0 -0
  168. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_attempt_outcome_emission.py +0 -0
  169. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_attention_nonwriting_guard.py +0 -0
  170. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_attention_skill_structure.py +0 -0
  171. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autoclose_deferral_visibility.py +0 -0
  172. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_invoke.py +0 -0
  173. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_live.py +0 -0
  174. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_predicate.py +0 -0
  175. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_run.py +0 -0
  176. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_state.py +0 -0
  177. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync.py +0 -0
  178. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync_consent.py +0 -0
  179. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync_firstrun.py +0 -0
  180. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync_no_cwd_leak.py +0 -0
  181. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync_plugin.py +0 -0
  182. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_azure_credential_resolution.py +0 -0
  183. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_backend.py +0 -0
  184. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_baseline_escalation_message.py +0 -0
  185. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_baseline_persistence.py +0 -0
  186. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_baseline_probe.py +0 -0
  187. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bash_routing.py +0 -0
  188. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bats_suites_gated.py +0 -0
  189. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bookkeeping_commit_crash_run.py +0 -0
  190. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
  191. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bookkeeping_no_verify.py +0 -0
  192. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_changelog_collection.py +0 -0
  193. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_changelog_release_wiring.py +0 -0
  194. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_changelog_schema.py +0 -0
  195. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_ci_runs_every_gate.py +0 -0
  196. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_claude_resolution.py +0 -0
  197. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_close_wu_self_reference.py +0 -0
  198. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_closing_deliverable_guard.py +0 -0
  199. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_closing_guard_prediction.py +0 -0
  200. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_console_encoding.py +0 -0
  201. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_correlation_id_override.py +0 -0
  202. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_correlation_id_two_surfaces.py +0 -0
  203. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_cost_lifetime.py +0 -0
  204. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_cost_tracking.py +0 -0
  205. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_degraded_oracle.py +0 -0
  206. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_deliverable_presence_gate.py +0 -0
  207. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_derive_monitoring_discovery.py +0 -0
  208. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_derive_monitoring_skill_registration.py +0 -0
  209. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_design_for_diagnosis_rule.py +0 -0
  210. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_diagnose_headless.py +0 -0
  211. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_diagnose_issue_skill.py +0 -0
  212. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_diagnosis.py +0 -0
  213. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_diagnosis_roundtrip_live.py +0 -0
  214. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_dispatch_skeleton.py +0 -0
  215. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_doctor.py +0 -0
  216. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_driver_event_registry_covers_emitters.py +0 -0
  217. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_driver_integration.py +0 -0
  218. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_driver_lock.py +0 -0
  219. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_duration_tracking.py +0 -0
  220. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_empty_files_escalation.py +0 -0
  221. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_ensure_feature_branch.py +0 -0
  222. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_ensure_feature_branch_base.py +0 -0
  223. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_escalation_contract.py +0 -0
  224. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_escalation_emit.py +0 -0
  225. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_event_gate_full_envelope.py +0 -0
  226. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_events_redaction.py +0 -0
  227. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_events_stats.py +0 -0
  228. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_extra_gates.py +0 -0
  229. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_failure_artifact_model.py +0 -0
  230. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_feature_id_resolution.py +0 -0
  231. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_feature_review_accumulation.py +0 -0
  232. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_filelock_portable.py +0 -0
  233. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_fingerprint.py +0 -0
  234. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_fix_bug_headless.py +0 -0
  235. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_force_full_close.py +0 -0
  236. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_budget.py +0 -0
  237. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_budget_post_dispatch.py +0 -0
  238. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_eval.py +0 -0
  239. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_eval_calibration.py +0 -0
  240. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_eval_intermediate_wiring.py +0 -0
  241. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_eval_terminal_wiring.py +0 -0
  242. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_report_verdict.py +0 -0
  243. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gh_backend.py +0 -0
  244. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gh_features.py +0 -0
  245. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_git_env_isolation.py +0 -0
  246. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gitleaks_pinning.py +0 -0
  247. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_hashed_denylist.py +0 -0
  248. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_hashed_denylist_ci.py +0 -0
  249. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_heartbeat_adapter.py +0 -0
  250. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_hedged_kind_contract.py +0 -0
  251. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_interpreter_normalization.py +0 -0
  252. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_label_registry.py +0 -0
  253. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_label_registry_covers_consumers.py +0 -0
  254. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_leak_findings_redaction.py +0 -0
  255. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_leak_scan.py +0 -0
  256. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_leak_scan_content.py +0 -0
  257. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_learnings_staging.py +0 -0
  258. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_legacy_4wu_terminal_flips.py +0 -0
  259. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lifetime_accounting.py +0 -0
  260. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_bare_produces_path.py +0 -0
  261. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_boundary_consistency.py +0 -0
  262. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_boundary_extraction.py +0 -0
  263. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_close_intermediate.py +0 -0
  264. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_close_wu.py +0 -0
  265. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_correlation_id.py +0 -0
  266. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
  267. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_monitoring.py +0 -0
  268. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_oracle_env.py +0 -0
  269. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_contract_fields.py +0 -0
  270. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_errors.py +0 -0
  271. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_next_draft.py +0 -0
  272. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_relative_import.py +0 -0
  273. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_verdict_exempt.py +0 -0
  274. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_planning_sections.py +0 -0
  275. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_produces_driver_helper.py +0 -0
  276. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_produces_satisfiability.py +0 -0
  277. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_roadmap.py +0 -0
  278. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_sections.py +0 -0
  279. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_task_graph_yaml_selection.py +0 -0
  280. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_verification_reference.py +0 -0
  281. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_attempt_evidence.py +0 -0
  282. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_auto_archive.py +0 -0
  283. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_caveman_preamble.py +0 -0
  284. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_close_intermediate.py +0 -0
  285. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_defaults_by_type.py +0 -0
  286. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_effort.py +0 -0
  287. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_failure_note_cap.py +0 -0
  288. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_files_changed_guard.py +0 -0
  289. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_gate_budget.py +0 -0
  290. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_model_alias.py +0 -0
  291. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_orchestration.py +0 -0
  292. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_post_pass_invariant.py +0 -0
  293. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_reset_preserving_events.py +0 -0
  294. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_smoke_runner.py +0 -0
  295. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_unsandboxed.py +0 -0
  296. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_zero_token_guard.py +0 -0
  297. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_migrate_legacy.py +0 -0
  298. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_miniyaml_equivalence.py +0 -0
  299. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_miniyaml_negative.py +0 -0
  300. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitor_issue_lifecycle.py +0 -0
  301. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
  302. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_cron_dialect.py +0 -0
  303. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_example.py +0 -0
  304. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_fenced_blocks.py +0 -0
  305. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_seed.py +0 -0
  306. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_no_pytest_subprocess.py +0 -0
  307. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_operator_escalation_rule.py +0 -0
  308. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_plan_baseline.py +0 -0
  309. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_planned_cost_lint.py +0 -0
  310. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_planning_cost_floor.py +0 -0
  311. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_prepare_scaffold_sync.py +0 -0
  312. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_produces_field.py +0 -0
  313. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_produces_in_diff.py +0 -0
  314. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_produces_semantics_unified.py +0 -0
  315. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_provision_labels.py +0 -0
  316. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_queue_stalled_adapter.py +0 -0
  317. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_redaction_windows_home.py +0 -0
  318. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_resolve_base.py +0 -0
  319. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_result_block.py +0 -0
  320. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_roadmap_archive_skill.py +0 -0
  321. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_roadmap_link_gate.py +0 -0
  322. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_roadmap_row_parser.py +0 -0
  323. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_routed_finding_tracking.py +0 -0
  324. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_doc_hygiene.py +0 -0
  325. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_label_provisioning.py +0 -0
  326. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_manifest.py +0 -0
  327. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_upgrade.py +0 -0
  328. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_schedule_dialect.py +0 -0
  329. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_service_bus_dlq_adapter.py +0 -0
  330. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_skill_discovery_links.py +0 -0
  331. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_skills_vendored_in_sync.py +0 -0
  332. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_spinning_rearm_gate.py +0 -0
  333. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_squash_commit_hook_crash.py +0 -0
  334. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_template_closing_shapes.py +0 -0
  335. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_terminal_flip_ownership.py +0 -0
  336. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_terminal_flips.py +0 -0
  337. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_timeout_kill_portable.py +0 -0
  338. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_unterminated_frontmatter.py +0 -0
  339. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_untracked_feature_folder.py +0 -0
  340. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_untracked_file_absorption.py +0 -0
  341. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_validate_event.py +0 -0
  342. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_validate_event_driver_types.py +0 -0
  343. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_verdict_coupling.py +0 -0
  344. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_verify_empty_gate_set.py +0 -0
  345. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_version_consistency.py +0 -0
  346. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_version_skew.py +0 -0
  347. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_windows_gate_exec.py +0 -0
  348. {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_wu_execution_metadata.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfuse-loop
3
- Version: 0.9.2
3
+ Version: 0.10.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
@@ -81,7 +81,7 @@ the planning rigor Ralph's bare task list lacks.
81
81
  `.specfuse/scripts/adopt_feature.py <repo> <issue-number>` (or the
82
82
  interactive `/adopt-feature` skill) to scaffold a dispatchable feature
83
83
  folder from a picked issue.
84
- - The **driver** (`specfuse-loop`, from the pip package) walks the current gate's
84
+ - The **driver** (`specfuse run`, from the `specfuse-loop` pip package) walks the current gate's
85
85
  ready work units, dispatches each as a fresh `claude -p` session, runs the unit's
86
86
  verification itself as the exit oracle, and commits one squashed,
87
87
  trailer-carrying commit per unit. A failed gate is retried with a fresh
@@ -108,8 +108,9 @@ checks CI runs — before each `git push`). Bypass with `git push --no-verify`.
108
108
  The driver installs from PyPI and the skills ship as a Claude Code plugin:
109
109
 
110
110
  ```bash
111
- pipx install specfuse # umbrella CLI; pulls specfuse-loop>=0.3.0
112
- # gives you: specfuse, specfuse-loop, specfuse-lint (or: python3 -m pip install specfuse, in a venv)
111
+ pipx install specfuse # or: uv tool install specfuse
112
+ # one command for the whole suite: specfuse run / lint / monitor / stats / …
113
+ # (or: python3 -m pip install specfuse, in a venv)
113
114
 
114
115
  # in Claude Code, enable the skills plugin (one-time):
115
116
  # /plugin marketplace add specfuse/specfuse
@@ -120,19 +121,28 @@ specfuse init /path/to/your-project # scaffold .specfuse/ + wire .cl
120
121
  cd /path/to/your-project
121
122
  $EDITOR .specfuse/verification.yml # match the `code` gates to your stack
122
123
  # author your first feature (in Claude Code: /draft-feature)
123
- specfuse-loop --dry-run # show the gate walk, no dispatch
124
- specfuse-loop # the real run
124
+ specfuse run --dry-run # show the gate walk, no dispatch
125
+ specfuse run # the real run
125
126
  ```
126
127
 
127
- > **Distribution.** Code ships via pip — `specfuse` (umbrella CLI: `init` /
128
- > `upgrade`) pulls `specfuse-loop` (the driver); Claude assets ship via the
128
+ > **Distribution.** Code ships via pip — the `specfuse` umbrella hard-depends on
129
+ > `specfuse-loop` (the driver) and every other component, so `pipx upgrade
130
+ > specfuse` / `uv tool upgrade specfuse` re-resolves the whole suite. Claude
131
+ > assets ship via the
129
132
  > [`specfuse/specfuse`](https://github.com/specfuse/specfuse) plugin marketplace.
130
133
  > `specfuse init` lays down `.specfuse/` and wires `.claude/`; `specfuse upgrade`
131
- > overlays a newer scaffold and pip-upgrades both packages. Every `specfuse-loop`
132
- > run self-provisions (version-syncs `.specfuse/` from the installed package), so
134
+ > is the same idempotent operation over an existing scaffold. Every `specfuse
135
+ > run` self-provisions (version-syncs `.specfuse/` from the installed package), so
133
136
  > an upgrade reaches existing projects on their next run. (`./init.sh` is a
134
137
  > deprecated v1.0 shim that delegates to `specfuse init`/`upgrade`; slated for
135
138
  > removal.)
139
+ >
140
+ > **Flat commands are deprecated.** `specfuse-loop`, `specfuse-lint`,
141
+ > `specfuse-monitor`, `specfuse-monitor-lint` and `specfuse-stats` still work as
142
+ > aliases until 1.0.0, with identical arguments and behaviour. Use the
143
+ > subcommands. `specfuse doctor` reports which flat names are still on your PATH;
144
+ > `SPECFUSE_NO_DEPRECATION_WARNING=1` silences the notice in noisy hooks or CI.
145
+ > `pip install specfuse-loop` on its own remains supported for library use.
136
146
 
137
147
  > **One driver per working tree.** The driver holds an exclusive advisory lock on
138
148
  > `.specfuse/.loop.lock` for the duration of a run; a second driver targeting the
@@ -48,7 +48,7 @@ the planning rigor Ralph's bare task list lacks.
48
48
  `.specfuse/scripts/adopt_feature.py <repo> <issue-number>` (or the
49
49
  interactive `/adopt-feature` skill) to scaffold a dispatchable feature
50
50
  folder from a picked issue.
51
- - The **driver** (`specfuse-loop`, from the pip package) walks the current gate's
51
+ - The **driver** (`specfuse run`, from the `specfuse-loop` pip package) walks the current gate's
52
52
  ready work units, dispatches each as a fresh `claude -p` session, runs the unit's
53
53
  verification itself as the exit oracle, and commits one squashed,
54
54
  trailer-carrying commit per unit. A failed gate is retried with a fresh
@@ -75,8 +75,9 @@ checks CI runs — before each `git push`). Bypass with `git push --no-verify`.
75
75
  The driver installs from PyPI and the skills ship as a Claude Code plugin:
76
76
 
77
77
  ```bash
78
- pipx install specfuse # umbrella CLI; pulls specfuse-loop>=0.3.0
79
- # gives you: specfuse, specfuse-loop, specfuse-lint (or: python3 -m pip install specfuse, in a venv)
78
+ pipx install specfuse # or: uv tool install specfuse
79
+ # one command for the whole suite: specfuse run / lint / monitor / stats / …
80
+ # (or: python3 -m pip install specfuse, in a venv)
80
81
 
81
82
  # in Claude Code, enable the skills plugin (one-time):
82
83
  # /plugin marketplace add specfuse/specfuse
@@ -87,19 +88,28 @@ specfuse init /path/to/your-project # scaffold .specfuse/ + wire .cl
87
88
  cd /path/to/your-project
88
89
  $EDITOR .specfuse/verification.yml # match the `code` gates to your stack
89
90
  # author your first feature (in Claude Code: /draft-feature)
90
- specfuse-loop --dry-run # show the gate walk, no dispatch
91
- specfuse-loop # the real run
91
+ specfuse run --dry-run # show the gate walk, no dispatch
92
+ specfuse run # the real run
92
93
  ```
93
94
 
94
- > **Distribution.** Code ships via pip — `specfuse` (umbrella CLI: `init` /
95
- > `upgrade`) pulls `specfuse-loop` (the driver); Claude assets ship via the
95
+ > **Distribution.** Code ships via pip — the `specfuse` umbrella hard-depends on
96
+ > `specfuse-loop` (the driver) and every other component, so `pipx upgrade
97
+ > specfuse` / `uv tool upgrade specfuse` re-resolves the whole suite. Claude
98
+ > assets ship via the
96
99
  > [`specfuse/specfuse`](https://github.com/specfuse/specfuse) plugin marketplace.
97
100
  > `specfuse init` lays down `.specfuse/` and wires `.claude/`; `specfuse upgrade`
98
- > overlays a newer scaffold and pip-upgrades both packages. Every `specfuse-loop`
99
- > run self-provisions (version-syncs `.specfuse/` from the installed package), so
101
+ > is the same idempotent operation over an existing scaffold. Every `specfuse
102
+ > run` self-provisions (version-syncs `.specfuse/` from the installed package), so
100
103
  > an upgrade reaches existing projects on their next run. (`./init.sh` is a
101
104
  > deprecated v1.0 shim that delegates to `specfuse init`/`upgrade`; slated for
102
105
  > removal.)
106
+ >
107
+ > **Flat commands are deprecated.** `specfuse-loop`, `specfuse-lint`,
108
+ > `specfuse-monitor`, `specfuse-monitor-lint` and `specfuse-stats` still work as
109
+ > aliases until 1.0.0, with identical arguments and behaviour. Use the
110
+ > subcommands. `specfuse doctor` reports which flat names are still on your PATH;
111
+ > `SPECFUSE_NO_DEPRECATION_WARNING=1` silences the notice in noisy hooks or CI.
112
+ > `pip install specfuse-loop` on its own remains supported for library use.
103
113
 
104
114
  > **One driver per working tree.** The driver holds an exclusive advisory lock on
105
115
  > `.specfuse/.loop.lock` for the duration of a run; a second driver targeting the
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "specfuse-loop"
7
- version = "0.9.2"
7
+ version = "0.10.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"
@@ -179,8 +179,9 @@ class Requirement:
179
179
  """One closing-artifact requirement, as data.
180
180
 
181
181
  ``applies_when`` names the condition under which the requirement fires:
182
- ``always``, ``verdict_met``, ``verdict_hedged``, ``failures_present``, or
183
- ``autoclose_debt_marker``. ``phase`` is ``pre-squash`` (checked by
182
+ ``always``, ``verdict_met``, ``verdict_hedged``, ``failures_present``,
183
+ ``autoclose_debt_marker``, or ``criteria_artifact_present`` (the gate's
184
+ ``GATE-NN-CRITERIA.md`` exists). ``phase`` is ``pre-squash`` (checked by
184
185
  ``assert_closing_deliverables`` right after the WU's own squash) or
185
186
  ``post-pass`` (checked by ``verify_post_pass_invariants`` after the
186
187
  gate-boundary state flips run).
@@ -299,6 +300,18 @@ CLOSING_REQUIREMENTS: dict[str, list[Requirement]] = {
299
300
  file=RETROSPECTIVE_FILENAME,
300
301
  enforced_by="assert_changelog_entry_for_contract_changes",
301
302
  ),
303
+ Requirement(
304
+ id="close-l", wu_type="close", phase="pre-squash",
305
+ description=(
306
+ "Every entry in GATE-NN-CRITERIA.md carries a kind: in "
307
+ "criteria_state.ORACLE_KINDS and a state: in "
308
+ "criteria_state.CRITERION_STATES, and every entry whose kind "
309
+ "has no knowable scope and whose state reads pass carries an "
310
+ "attempt: equal to the current attempt"
311
+ ),
312
+ applies_when="criteria_artifact_present",
313
+ enforced_by="check_criteria_state_well_formed",
314
+ ),
302
315
  ],
303
316
  "close-intermediate": [
304
317
  Requirement(
@@ -343,6 +356,18 @@ CLOSING_REQUIREMENTS: dict[str, list[Requirement]] = {
343
356
  file=LEARNINGS_PATH,
344
357
  enforced_by="assert_learnings_staged_under_auto",
345
358
  ),
359
+ Requirement(
360
+ id="close-intermediate-f", wu_type="close-intermediate", phase="pre-squash",
361
+ description=(
362
+ "Every entry in GATE-NN-CRITERIA.md carries a kind: in "
363
+ "criteria_state.ORACLE_KINDS and a state: in "
364
+ "criteria_state.CRITERION_STATES, and every entry whose kind "
365
+ "has no knowable scope and whose state reads pass carries an "
366
+ "attempt: equal to the current attempt"
367
+ ),
368
+ applies_when="criteria_artifact_present",
369
+ enforced_by="check_criteria_state_well_formed",
370
+ ),
346
371
  ],
347
372
  "plan-next": [
348
373
  Requirement(
@@ -5,22 +5,27 @@
5
5
  """One lifetime-cost reader shared by both cost-gated consumers.
6
6
 
7
7
  `wu_lifetime_cost_usd` answers "what has this work unit cost over its whole
8
- life," correctly on both re-arm shapes recorded in FEAT-2026-0062/PLAN.md:
9
-
10
- * fold-ran — a re-arm folded the prior cycle's spend into
11
- `cumulative_cost_usd`, and `re_arm_history[].prior_cost_usd`
12
- names the same money.
13
- * fold-never-ran — the prior cycle's spend survives only in
14
- `re_arm_history[].prior_cost_usd`; `cumulative_cost_usd` is
15
- absent.
16
-
17
- Summing frontmatter fields cannot distinguish these shapes without replaying
18
- fold history, and naive summation double-counts the fold-ran shape. Instead
19
- this module sums `payload.cost_usd` across every `attempt_outcome` event for
20
- the work unit in `events.jsonl` — a source that already carries every
21
- dispatch cycle's cost exactly once, independent of fold shape. Frontmatter is
22
- used only as a fallback for the units this repo's corpus shows have no usable
23
- event history (see FEAT-2026-0062 criterion 9's measurement).
8
+ life." FEAT-2026-0067 converged the fold onto one path: every re-arm now
9
+ unconditionally folds the prior cycle's spend into `cumulative_cost_usd`
10
+ (driven by an explicit `folded_through_re_arm` marker, not by inferring state
11
+ from a value), so `cumulative_cost_usd` is the lifetime accumulator and
12
+ `re_arm_history[].prior_cost_usd` is a pure audit record of what each cycle
13
+ cost — not a second place the fold might or might not have run.
14
+
15
+ Before that migration, some already-re-armed WUs had a prior cycle's spend
16
+ survive only in `re_arm_history[].prior_cost_usd` with `cumulative_cost_usd`
17
+ absent — a pre-migration legacy shape that this module's frontmatter fallback
18
+ still tolerates for projects that have not run the FEAT-2026-0067 migration,
19
+ not an ongoing design a reader needs to branch on.
20
+
21
+ Summing frontmatter fields cannot distinguish "already folded" from "never
22
+ folded" without replaying fold history, and naive summation double-counts a
23
+ folded record. Instead this module sums `payload.cost_usd` across every
24
+ `attempt_outcome` event for the work unit in `events.jsonl` — a source that
25
+ already carries every dispatch cycle's cost exactly once, independent of fold
26
+ shape. Frontmatter is used only as a fallback for the units this repo's
27
+ corpus shows have no usable event history (see FEAT-2026-0062 criterion 9's
28
+ measurement).
24
29
 
25
30
  Deliberately dependency-light: this module must not import `loop.py` or
26
31
  `arm_eval.py` (see `arm_eval.py`'s module docstring on the `loop -> arm_eval`
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ # Copyright 2026 Specfuse contributors
4
+ # Licensed under the Apache License, Version 2.0. See LICENSE.
5
+ #
6
+ """Per-criterion close state — schema, parser, renderer (FEAT-2026-0056/T01).
7
+
8
+ Defines the entry shape for `GATE-NN-CRITERIA.md`, the per-gate artifact that
9
+ lets a close remember, per acceptance criterion, which oracle proved it, that
10
+ oracle's exit code, and the tree state it ran against. Follows the shape of
11
+ `closing_requirements.py`'s hedged-verdict follow-up record: a per-entry
12
+ classified record living inside a markdown artifact, regex-parsed, with the
13
+ classification written by the close that ran the oracle and never inferred by
14
+ a reader.
15
+
16
+ Data and parsing only — no file I/O, no driver wiring, no skip policy. See
17
+ FEAT-2026-0056/PLAN.md and GATE-01.md for the design this module encodes.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import re
23
+ from dataclasses import dataclass
24
+ from typing import Optional
25
+
26
+ #: An oracle's scope classification. `narrow` oracles (a scoped test nodeid,
27
+ #: a symbol-existence import, a structural assert, a countable grep) survive
28
+ #: a re-close; `broad` oracles (the full suite, a full regen, a scenario
29
+ #: matrix) re-run unconditionally on every close attempt.
30
+ ORACLE_KINDS: frozenset = frozenset({"narrow", "broad"})
31
+
32
+ #: A criterion's recorded verification outcome for a given close attempt.
33
+ CRITERION_STATES: frozenset = frozenset({"pass", "fail", "unverified"})
34
+
35
+ _ENTRY_HEADING_RE = re.compile(r"^### (\S+)\s*$", re.MULTILINE)
36
+
37
+ _FIELD_PATTERNS = {
38
+ "criterion": re.compile(r"^- \*\*criterion:\*\*\s*(.+)$", re.MULTILINE),
39
+ "oracle": re.compile(r"^- \*\*oracle:\*\*\s*(.+)$", re.MULTILINE),
40
+ "kind": re.compile(r"^- \*\*kind:\*\*\s*`([^`]+)`", re.MULTILINE),
41
+ "state": re.compile(r"^- \*\*state:\*\*\s*`([^`]+)`", re.MULTILINE),
42
+ "proved_at_sha": re.compile(r"^- \*\*proved_at_sha:\*\*\s*`([^`]+)`", re.MULTILINE),
43
+ "attempt": re.compile(r"^- \*\*attempt:\*\*\s*`?([^`\n]+)`?", re.MULTILINE),
44
+ }
45
+
46
+
47
+ @dataclass(frozen=True)
48
+ class CriterionStateEntry:
49
+ """One `### <criterion_id>` block in a `GATE-NN-CRITERIA.md` artifact."""
50
+
51
+ criterion_id: str
52
+ criterion: Optional[str]
53
+ oracle: Optional[str]
54
+ kind: Optional[str]
55
+ state: Optional[str]
56
+ proved_at_sha: Optional[str]
57
+ attempt: Optional[str]
58
+
59
+
60
+ #: Matches `GATE-NN-CRITERIA.md` basenames (any `NN`), and nothing else —
61
+ #: not `GATE-NN.md`, not `GATE-NN-REVIEW.md`, not `RETROSPECTIVE.md`.
62
+ CRITERIA_FILENAME_RE = re.compile(r"^GATE-\d+-CRITERIA\.md$")
63
+
64
+
65
+ def criteria_filename(gate_n: int) -> str:
66
+ """The single source of truth for a gate's criteria-artifact basename."""
67
+ return f"GATE-{gate_n:02d}-CRITERIA.md"
68
+
69
+
70
+ def criterion_id_for(wu_sub_id: str, ordinal: int) -> str:
71
+ """Stable criterion identity: producing WU's sub-ID + 1-based ordinal.
72
+
73
+ Ordinal, not a hash of the criterion text — a criterion whose wording is
74
+ edited between attempts is still the same criterion, and a hash would
75
+ silently orphan its recorded state.
76
+ """
77
+ return f"{wu_sub_id}#{ordinal}"
78
+
79
+
80
+ def _extract_field(block: str, name: str) -> Optional[str]:
81
+ m = _FIELD_PATTERNS[name].search(block)
82
+ if not m:
83
+ return None
84
+ return m.group(1).strip()
85
+
86
+
87
+ def parse_criteria_state(text: str) -> list[CriterionStateEntry]:
88
+ """Parse a `GATE-NN-CRITERIA.md` artifact into entries, in document order.
89
+
90
+ A block missing a field yields that field as `None` rather than raising —
91
+ the artifact is written incrementally across attempts, so a partially
92
+ populated block is a normal, not exceptional, state.
93
+ """
94
+ headings = list(_ENTRY_HEADING_RE.finditer(text))
95
+ entries: list[CriterionStateEntry] = []
96
+ for i, m in enumerate(headings):
97
+ criterion_id = m.group(1)
98
+ start = m.end()
99
+ end = headings[i + 1].start() if i + 1 < len(headings) else len(text)
100
+ block = text[start:end]
101
+ entries.append(
102
+ CriterionStateEntry(
103
+ criterion_id=criterion_id,
104
+ criterion=_extract_field(block, "criterion"),
105
+ oracle=_extract_field(block, "oracle"),
106
+ kind=_extract_field(block, "kind"),
107
+ state=_extract_field(block, "state"),
108
+ proved_at_sha=_extract_field(block, "proved_at_sha"),
109
+ attempt=_extract_field(block, "attempt"),
110
+ )
111
+ )
112
+ return entries
113
+
114
+
115
+ @dataclass(frozen=True)
116
+ class ReverificationWorklist:
117
+ """Partition of a gate's recorded entries for a re-dispatched close attempt.
118
+
119
+ `carry_forward` entries are provably safe to skip re-verifying this
120
+ attempt; `reverify` entries must re-run their oracle. `oracle_groups`
121
+ collapses byte-identical oracle commands among `reverify` entries so each
122
+ runs once per attempt rather than once per criterion.
123
+ """
124
+
125
+ carry_forward: list[CriterionStateEntry]
126
+ reverify: list[CriterionStateEntry]
127
+ oracle_groups: list[tuple[str, list[str]]]
128
+
129
+
130
+ def build_reverification_worklist(
131
+ entries: list[CriterionStateEntry], current_attempt: str
132
+ ) -> ReverificationWorklist:
133
+ """Partition recorded entries into what a re-close may carry vs. re-verify.
134
+
135
+ An entry carries forward only when it is provably safe: `kind ==
136
+ "narrow"`, `state == "pass"`, a non-empty `oracle`, and a non-empty
137
+ `attempt`. Everything else — a missing or unrecognized `kind`, `state:
138
+ fail` or `state: unverified`, and every `broad` entry regardless of
139
+ state — goes to `reverify`. Fail-safe default: unclassifiable entries
140
+ land in `reverify`, never in `carry_forward`.
141
+ """
142
+ carry_forward: list[CriterionStateEntry] = []
143
+ reverify: list[CriterionStateEntry] = []
144
+ for entry in entries:
145
+ if (
146
+ entry.kind == "narrow"
147
+ and entry.state == "pass"
148
+ and entry.oracle
149
+ and entry.attempt
150
+ ):
151
+ carry_forward.append(entry)
152
+ else:
153
+ reverify.append(entry)
154
+
155
+ groups: dict[str, list[str]] = {}
156
+ order: list[str] = []
157
+ for entry in reverify:
158
+ if not entry.oracle:
159
+ continue
160
+ if entry.oracle not in groups:
161
+ groups[entry.oracle] = []
162
+ order.append(entry.oracle)
163
+ groups[entry.oracle].append(entry.criterion_id)
164
+ oracle_groups = [(oracle, groups[oracle]) for oracle in order]
165
+
166
+ return ReverificationWorklist(
167
+ carry_forward=carry_forward,
168
+ reverify=reverify,
169
+ oracle_groups=oracle_groups,
170
+ )
171
+
172
+
173
+ def render_criteria_state(entries: list[CriterionStateEntry]) -> str:
174
+ """Render entries back into `GATE-NN-CRITERIA.md` markdown.
175
+
176
+ Round-trips through `parse_criteria_state` — a missing field is simply
177
+ omitted from its block rather than rendered as a literal `None`.
178
+ """
179
+ blocks = []
180
+ for entry in entries:
181
+ lines = [f"### {entry.criterion_id}", ""]
182
+ if entry.criterion is not None:
183
+ lines.append(f"- **criterion:** {entry.criterion}")
184
+ if entry.oracle is not None:
185
+ lines.append(f"- **oracle:** {entry.oracle}")
186
+ if entry.kind is not None:
187
+ lines.append(f"- **kind:** `{entry.kind}`")
188
+ if entry.state is not None:
189
+ lines.append(f"- **state:** `{entry.state}`")
190
+ if entry.proved_at_sha is not None:
191
+ lines.append(f"- **proved_at_sha:** `{entry.proved_at_sha}`")
192
+ if entry.attempt is not None:
193
+ lines.append(f"- **attempt:** `{entry.attempt}`")
194
+ blocks.append("\n".join(lines) + "\n")
195
+ return "\n".join(blocks)
@@ -0,0 +1 @@
1
+ 0.10.0
@@ -44,7 +44,7 @@ Additive, present whether or not any feature in the project uses `auto`:
44
44
  (`close-e` / `close-intermediate-e`, `closing_requirements.py`), fired when
45
45
  a closing WU under `autonomy_default: auto` touches `.specfuse/LEARNINGS.md`
46
46
  directly instead of staging to `LEARNINGS-pending.md`. Changes
47
- `specfuse-lint --closing` output accordingly. Inert outside `auto`, but the
47
+ `specfuse lint --closing` output accordingly. Inert outside `auto`, but the
48
48
  requirement registry is a published surface every project's lint now
49
49
  carries.
50
50
 
@@ -14,22 +14,26 @@ each project you want to drive with one command.
14
14
 
15
15
  ## 1. Install the tooling and scaffold your project
16
16
 
17
- Install the umbrella package — it pulls the driver (`specfuse-loop>=0.3.0`) as a
18
- dependency and puts the `specfuse`, `specfuse-loop`, and `specfuse-lint` commands
19
- on your PATH. It's a command-line app, so **pipx** is the recommended installer
20
- (isolated environment, no `--break-system-packages` on PEP 668 / externally-
21
- managed Pythons):
17
+ Install the umbrella package — it hard-depends on every component, so one
18
+ install puts the whole suite behind a single `specfuse` command. It's a
19
+ command-line app, so **pipx** (or **uv**) is the recommended installer (isolated
20
+ environment, no `--break-system-packages` on PEP 668 / externally-managed
21
+ Pythons):
22
22
 
23
23
  ```bash
24
24
  pipx install specfuse # recommended
25
+ uv tool install specfuse # equivalent
25
26
  # or, inside a virtualenv you control:
26
27
  python3 -m pip install specfuse
27
28
  ```
28
29
 
30
+ Upgrade the whole suite the same way — `pipx upgrade specfuse` /
31
+ `uv tool upgrade specfuse` re-resolves every component. No extras, no flags, no
32
+ bracket quoting.
33
+
29
34
  > On Debian/Ubuntu/macOS-Homebrew Pythons a bare `pip install` into the system
30
35
  > interpreter is blocked (`externally-managed-environment`). Use `pipx` (or a
31
- > venv) — that's what puts `specfuse-loop` / `specfuse-lint` on PATH for the gate
32
- > commands to find.
36
+ > venv) — that's what puts `specfuse` on PATH for the gate commands to find.
33
37
 
34
38
  > **Windows: Git-Bash is required.** The driver runs natively on Windows (no WSL),
35
39
  > but it routes gate commands through **Git-Bash** so a target repo's
@@ -65,7 +69,7 @@ files copied into your repo.)
65
69
  > **Don't gitignore `.specfuse/`.** The loop's durable state lives there and must
66
70
  > be committed for the loop to work.
67
71
 
68
- > **Self-provisioning.** Every `specfuse-loop` run first version-syncs `.specfuse/`
72
+ > **Self-provisioning.** Every `specfuse run` first version-syncs `.specfuse/`
69
73
  > from the installed package (missing → scaffold, older → overlay, equal → no-op,
70
74
  > never downgrades). So `pip install -U specfuse` followed by a run keeps the
71
75
  > scaffold current — `specfuse upgrade` is the explicit equivalent. Disable with
@@ -124,7 +128,7 @@ the loop will refuse to start until the folder is on its branch and committed.
124
128
  Let the driver do both for you:
125
129
 
126
130
  ```bash
127
- specfuse-loop --prepare # create the PLAN.md `branch:`, commit the folder, then run
131
+ specfuse run --prepare # create the PLAN.md `branch:`, commit the folder, then run
128
132
  ```
129
133
 
130
134
  (Or by hand: `git checkout -b <branch>` from `PLAN.md`'s frontmatter, then
@@ -133,7 +137,7 @@ specfuse-loop --prepare # create the PLAN.md `branch:`, commit the folder,
133
137
  ## 4. Validate before running
134
138
 
135
139
  ```bash
136
- specfuse-lint .specfuse/features/FEAT-YYYY-NNNN-your-feature
140
+ specfuse lint .specfuse/features/FEAT-YYYY-NNNN-your-feature
137
141
  ```
138
142
 
139
143
  The linter checks structure: every WU has the five mandatory sections, the closing
@@ -144,8 +148,8 @@ dispatch.
144
148
  ## 5. Dry-run, then run
145
149
 
146
150
  ```bash
147
- specfuse-loop --dry-run # show the gate walked, in dep order, no dispatch
148
- specfuse-loop # the real thing
151
+ specfuse run --dry-run # show the gate walked, in dep order, no dispatch
152
+ specfuse run # the real thing
149
153
  ```
150
154
 
151
155
  With no `--feature` flag the driver picks the single `active` feature. For each
@@ -188,7 +192,7 @@ the ones you accept to `pending`, marks the finished gate `passed`, and prints t
188
192
  resume command. Read the `GATE-NN-REVIEW.md` the planner wrote first: it's
189
193
  weighted toward where the planner was *least* certain.
190
194
 
191
- Then re-run `specfuse-loop`. Repeat until the terminal gate is `done`.
195
+ Then re-run `specfuse run`. Repeat until the terminal gate is `done`.
192
196
 
193
197
  ## 7. Wrap up
194
198
 
@@ -0,0 +1,108 @@
1
+ # Glossary
2
+
3
+ The words Specfuse uses, in the order you meet them. Each entry says what the
4
+ thing *is* and, where one exists, the command or skill that acts on it.
5
+
6
+ For the full contract behind any of these, see
7
+ [`methodology.md`](methodology.md); this page is the first read, not the
8
+ reference.
9
+
10
+ ## The shape of the work
11
+
12
+ **Roadmap** — `.specfuse/roadmap.md`, the ordered list of features a project
13
+ intends to build, one row each. Add to it with `/roadmap-add`; pick what to
14
+ build next with `/pick-feature`.
15
+
16
+ **Feature** — one substantial piece of work, `FEAT-YYYY-NNNN`, with a folder
17
+ under `.specfuse/features/`. Its `PLAN.md` holds the goal, the gates, and the
18
+ budget. Roughly: a thing you would describe in a sentence to someone who does
19
+ not work on the project.
20
+
21
+ **Gate** — a stage of a feature, numbered from 1. A gate holds a set of work
22
+ units, a budget, and acceptance criteria. **The gate is where the loop stops
23
+ and you decide** — everything inside one runs unattended; the boundary between
24
+ two is yours.
25
+
26
+ **Work unit (WU)** — the smallest dispatchable piece: one file, one job, one
27
+ fresh session. `FEAT-YYYY-NNNN/T01`. Everything the session needs is in that
28
+ file, because it starts with no memory of anything before it.
29
+
30
+ **Verification** — the commands in `.specfuse/verification.yml` that decide
31
+ whether a work unit actually passed. The loop runs them itself and does not
32
+ take the session's word for it.
33
+
34
+ **LEARNINGS** — `.specfuse/LEARNINGS.md`, what earlier work taught, carried
35
+ into later planning so the same mistake is not made twice.
36
+
37
+ ## What happens to it
38
+
39
+ **Draft** — write a feature and its first gate's work units, usually with
40
+ `/draft-feature`. Drafted units are proposals; nothing runs yet.
41
+
42
+ **Arm** — review the drafted units and accept, revise, or reject each, then
43
+ release the gate to run. This is the human checkpoint. `/arm-gate`.
44
+
45
+ **Dispatch** — hand one work unit to a fresh session and let it work.
46
+ `specfuse run` walks the current gate and dispatches whatever is ready.
47
+
48
+ **Attempt** — one dispatch of one work unit. A unit gets three before the loop
49
+ gives up and asks you.
50
+
51
+ **Close** — the ceremony that ends a gate: what was learned, what it cost,
52
+ whether the goal was met, and drafting the next gate. The loop runs it as a
53
+ work unit like any other.
54
+
55
+ **Wrap** — finish the feature: push the branch, open the pull request.
56
+ `/wrap-feature`.
57
+
58
+ **Self-provisioning** — every `specfuse run` first checks whether
59
+ `.specfuse/` matches the installed version and updates it if not, so an upgrade
60
+ reaches a project on its next run.
61
+
62
+ ## States you will see
63
+
64
+ **A feature** is `planned`, `active`, `blocked`, `done`, or `abandoned`.
65
+ `blocked` means a named dependency is unmet — clear it with `/block-feature
66
+ --unblock`.
67
+
68
+ **A gate** is `open` (running), `awaiting_review` (finished, waiting for you to
69
+ arm the next one), or `passed`.
70
+
71
+ **A work unit** is `draft`, `pending` (armed, waiting its turn), `in_progress`,
72
+ `done`, `abandoned`, or `blocked_human`.
73
+
74
+ **`blocked_human`** — a unit tried, failed three times, and stopped. Nothing is
75
+ broken and nothing is lost; it needs a decision. `/gate-status` explains what
76
+ happened, `/unblock-wu` re-arms it once you have fixed the cause.
77
+
78
+ **A close verdict** is `met` (the goal was achieved and shown), `met_locally`
79
+ (achieved here, but not proven beyond this repository), `partially_met`, or
80
+ `not_met`. The middle two are **hedged**: the feature is held short of finished
81
+ on purpose until you accept the gap, with `/accept-hedged-close`.
82
+
83
+ ## Terms that look like jargon because they are
84
+
85
+ **Oracle** — the check that decides pass or fail. A *narrow* oracle tests one
86
+ specific thing, so a pass can be trusted later; a *broad* one (a whole test
87
+ suite) covers too much for its green to be carried forward.
88
+
89
+ **`produces:`** — the files a work unit promises to deliver. The loop compares
90
+ them against what actually changed, so a unit cannot report success having
91
+ written nothing.
92
+
93
+ **Hollow pass** — a work unit reporting success without changing anything. The
94
+ `produces:` check exists to catch it.
95
+
96
+ **Spinning** — repeated attempts making no progress. The loop detects it and
97
+ stops rather than spending the remaining budget.
98
+
99
+ **Re-arm** — putting a stopped work unit back in the queue after fixing the
100
+ cause. Requires a one-line reason from you, which is the record of why it was
101
+ worth retrying.
102
+
103
+ **Escalation** — the loop stopping to ask you something, with what it tried,
104
+ why it stopped, the options, and a recommendation.
105
+
106
+ **Auto mode** — letting safe gates arm themselves. The dangerous boundaries
107
+ still stop for you. See
108
+ [`concepts/adopting-auto-mode.md`](concepts/adopting-auto-mode.md).