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.
- {specfuse_loop-0.9.2/specfuse_loop.egg-info → specfuse_loop-0.10.0}/PKG-INFO +20 -10
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/README.md +19 -9
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/pyproject.toml +1 -1
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/closing_requirements.py +27 -2
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/cost.py +21 -16
- specfuse_loop-0.10.0/specfuse/loop/criteria_state.py +195 -0
- specfuse_loop-0.10.0/specfuse/loop/data/VERSION +1 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +1 -1
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/getting-started.md +17 -13
- specfuse_loop-0.10.0/specfuse/loop/data/docs/glossary.md +108 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/methodology.md +4 -2
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/skills.md +3 -3
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/monitoring-secrets-checklist.md +2 -2
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/monitoring.overrides.yml.example +1 -1
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/close-discipline.md +20 -3
- specfuse_loop-0.10.0/specfuse/loop/data/rules/human-output.md +85 -0
- specfuse_loop-0.10.0/specfuse/loop/data/rules/operator-escalation.md +160 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/result-contract.md +20 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/driver-event.schema.json +3 -2
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/templates/GATE.template.md +1 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/templates/WU.template.md +26 -3
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/verification.yml.example +11 -3
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/workflows/specfuse-monitor.yml +3 -3
- specfuse_loop-0.10.0/specfuse/loop/driver_edit.py +67 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/labels.py +1 -1
- specfuse_loop-0.10.0/specfuse/loop/learnings_query.py +210 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/lint_closing.py +68 -1
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/lint_plan.py +123 -3
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/loop.py +734 -51
- specfuse_loop-0.10.0/specfuse/loop/prerun.py +136 -0
- specfuse_loop-0.10.0/specfuse/loop/prerun_capture.py +133 -0
- specfuse_loop-0.10.0/specfuse/loop/rearm_migration.py +267 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/scaffold.py +48 -2
- specfuse_loop-0.10.0/specfuse/loop/upgrade_merge_gate.py +156 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/autofix_run.py +1 -1
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/cli.py +3 -3
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0/specfuse_loop.egg-info}/PKG-INFO +20 -10
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/SOURCES.txt +38 -0
- specfuse_loop-0.10.0/tests/test_autoclose_gate_note.py +140 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_closing_guard_contracts.py +3 -3
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_closing_requirements.py +10 -2
- specfuse_loop-0.10.0/tests/test_criteria_state.py +91 -0
- specfuse_loop-0.10.0/tests/test_criteria_worklist.py +121 -0
- specfuse_loop-0.10.0/tests/test_deterministic_refusal_repeat.py +166 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_done_feature_gates.py +20 -0
- specfuse_loop-0.10.0/tests/test_driver_edit_detection.py +151 -0
- specfuse_loop-0.10.0/tests/test_driver_module_surface.py +97 -0
- specfuse_loop-0.10.0/tests/test_driver_restart_halt_wiring.py +278 -0
- specfuse_loop-0.10.0/tests/test_driver_restart_hold.py +199 -0
- specfuse_loop-0.10.0/tests/test_driver_staleness_gate_summary.py +218 -0
- specfuse_loop-0.10.0/tests/test_driver_staleness_warning.py +169 -0
- specfuse_loop-0.10.0/tests/test_fold_contract_documented.py +127 -0
- specfuse_loop-0.10.0/tests/test_guard_refusal_failure_class.py +193 -0
- specfuse_loop-0.10.0/tests/test_human_output_rule.py +189 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_init_integration.py +4 -2
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_learnings_query.py +60 -19
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lifecycle_integration.py +12 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_closing.py +1 -1
- specfuse_loop-0.10.0/tests/test_lint_closing_criteria.py +299 -0
- specfuse_loop-0.10.0/tests/test_lint_closing_criteria_pristine.py +154 -0
- specfuse_loop-0.10.0/tests/test_load_bearing_close_lint.py +193 -0
- specfuse_loop-0.10.0/tests/test_loop_criteria_skeleton.py +230 -0
- specfuse_loop-0.10.0/tests/test_loop_criteria_survival.py +123 -0
- specfuse_loop-0.10.0/tests/test_loop_worklist_injection.py +215 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitor_cli.py +1 -1
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitor_runner_surfaces.py +15 -3
- specfuse_loop-0.10.0/tests/test_oracle_set_declared.py +66 -0
- specfuse_loop-0.10.0/tests/test_prep_halt_operator_surface.py +252 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_prepare_feature.py +2 -2
- specfuse_loop-0.10.0/tests/test_prerun_capture.py +159 -0
- specfuse_loop-0.10.0/tests/test_prerun_oracles.py +152 -0
- specfuse_loop-0.10.0/tests/test_prerun_wiring.py +198 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_produces_shape.py +1 -1
- specfuse_loop-0.10.0/tests/test_rearm_fold_marker.py +143 -0
- specfuse_loop-0.10.0/tests/test_rearm_migration.py +306 -0
- specfuse_loop-0.10.0/tests/test_result_block_audience.py +157 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_roadmap_add_skill.py +215 -29
- specfuse_loop-0.10.0/tests/test_ruff_verdict_lines.py +98 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_data_in_sync.py +2 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_docs.py +1 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_init.py +3 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_resources.py +2 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_seed_sanity.py +51 -3
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_wiring.py +64 -12
- specfuse_loop-0.10.0/tests/test_seed_documents_prerun_keys.py +30 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_upgrade_integration.py +1 -2
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_upgrade_merge_gate.py +9 -23
- specfuse_loop-0.9.2/specfuse/loop/data/VERSION +0 -1
- specfuse_loop-0.9.2/specfuse/loop/data/rules/operator-escalation.md +0 -70
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/LICENSE +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/NOTICE +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/setup.cfg +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/__init__.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/_filelock.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/_miniyaml.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/_wu_sections.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/adopt_feature.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/arm_eval.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/arm_sweep.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/arm_txn.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/changelog.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/LEARNINGS.template.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/gitignore.snippet +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/monitoring.yml.example +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/roadmap.template.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/correlation-ids.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/never-touch.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/planning-discipline.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/security-boundaries.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules/verification-discipline.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/rules-local/README.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/event.schema.json +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/templates/PLAN.template.md +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/escalation.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/events_stats.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/gate_commands.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/gate_eval.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/gh_backend.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/gh_features.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/lint_monitoring.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/lint_roadmap.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/plan_baseline.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/validate_event.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/__init__.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/adapters.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/artifact.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/autofix.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/autofix_invoke.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/autofix_state.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/diagnose_cli.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/diagnosis.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/fingerprint.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/issues.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/providers/__init__.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/providers/_azure_auth.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/providers/azure_app_insights.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/providers/azure_service_bus.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/redaction.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/monitor/schedule.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/dependency_links.txt +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/entry_points.txt +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/requires.txt +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse_loop.egg-info/top_level.txt +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_accept_hedged_close_headline.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_accept_hedged_close_skill.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_adopt_feature.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_app_insights_adapters.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_eval.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_eval_lint_class.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_eval_wiring.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_gate_edits_uncommitted.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_sweep.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_sweep_gate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_txn.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_arm_wiring.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_artifact_redaction.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_attempt_outcome_contract.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_attempt_outcome_emission.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_attention_nonwriting_guard.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_attention_skill_structure.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autoclose_deferral_visibility.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_invoke.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_live.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_predicate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_run.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autofix_state.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync_consent.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync_firstrun.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync_no_cwd_leak.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_autosync_plugin.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_azure_credential_resolution.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_backend.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_baseline_escalation_message.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_baseline_persistence.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_baseline_probe.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bash_routing.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bats_suites_gated.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bookkeeping_commit_crash_run.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_bookkeeping_no_verify.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_changelog_collection.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_changelog_release_wiring.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_changelog_schema.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_ci_runs_every_gate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_claude_resolution.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_close_wu_self_reference.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_closing_deliverable_guard.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_closing_guard_prediction.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_console_encoding.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_correlation_id_override.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_correlation_id_two_surfaces.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_cost_lifetime.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_cost_tracking.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_degraded_oracle.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_deliverable_presence_gate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_derive_monitoring_discovery.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_derive_monitoring_skill_registration.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_design_for_diagnosis_rule.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_diagnose_headless.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_diagnose_issue_skill.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_diagnosis.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_diagnosis_roundtrip_live.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_dispatch_skeleton.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_doctor.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_driver_event_registry_covers_emitters.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_driver_integration.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_driver_lock.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_duration_tracking.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_empty_files_escalation.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_ensure_feature_branch.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_ensure_feature_branch_base.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_escalation_contract.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_escalation_emit.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_event_gate_full_envelope.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_events_redaction.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_events_stats.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_extra_gates.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_failure_artifact_model.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_feature_id_resolution.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_feature_review_accumulation.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_filelock_portable.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_fingerprint.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_fix_bug_headless.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_force_full_close.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_budget.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_budget_post_dispatch.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_eval.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_eval_calibration.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_eval_intermediate_wiring.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_eval_terminal_wiring.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gate_report_verdict.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gh_backend.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gh_features.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_git_env_isolation.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_gitleaks_pinning.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_hashed_denylist.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_hashed_denylist_ci.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_heartbeat_adapter.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_hedged_kind_contract.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_interpreter_normalization.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_label_registry.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_label_registry_covers_consumers.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_leak_findings_redaction.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_leak_scan.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_leak_scan_content.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_learnings_staging.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_legacy_4wu_terminal_flips.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lifetime_accounting.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_bare_produces_path.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_boundary_consistency.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_boundary_extraction.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_close_intermediate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_close_wu.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_correlation_id.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_monitoring.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_oracle_env.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_contract_fields.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_errors.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_next_draft.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_relative_import.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_plan_verdict_exempt.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_planning_sections.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_produces_driver_helper.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_produces_satisfiability.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_roadmap.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_sections.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_task_graph_yaml_selection.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_lint_verification_reference.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_attempt_evidence.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_auto_archive.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_caveman_preamble.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_close_intermediate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_defaults_by_type.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_effort.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_failure_note_cap.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_files_changed_guard.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_gate_budget.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_model_alias.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_orchestration.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_post_pass_invariant.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_reset_preserving_events.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_smoke_runner.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_unsandboxed.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_loop_zero_token_guard.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_migrate_legacy.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_miniyaml_equivalence.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_miniyaml_negative.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitor_issue_lifecycle.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_cron_dialect.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_example.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_fenced_blocks.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_monitoring_seed.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_no_pytest_subprocess.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_operator_escalation_rule.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_plan_baseline.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_planned_cost_lint.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_planning_cost_floor.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_prepare_scaffold_sync.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_produces_field.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_produces_in_diff.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_produces_semantics_unified.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_provision_labels.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_queue_stalled_adapter.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_redaction_windows_home.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_resolve_base.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_result_block.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_roadmap_archive_skill.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_roadmap_link_gate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_roadmap_row_parser.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_routed_finding_tracking.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_doc_hygiene.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_label_provisioning.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_manifest.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_scaffold_upgrade.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_schedule_dialect.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_service_bus_dlq_adapter.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_skill_discovery_links.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_skills_vendored_in_sync.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_spinning_rearm_gate.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_squash_commit_hook_crash.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_template_closing_shapes.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_terminal_flip_ownership.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_terminal_flips.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_timeout_kill_portable.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_unterminated_frontmatter.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_untracked_feature_folder.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_untracked_file_absorption.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_validate_event.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_validate_event_driver_types.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_verdict_coupling.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_verify_empty_gate_set.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_version_consistency.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_version_skew.py +0 -0
- {specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/tests/test_windows_gate_exec.py +0 -0
- {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.
|
|
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
|
|
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 #
|
|
112
|
-
#
|
|
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
|
|
124
|
-
specfuse
|
|
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`
|
|
128
|
-
> `
|
|
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
|
-
>
|
|
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
|
|
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 #
|
|
79
|
-
#
|
|
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
|
|
91
|
-
specfuse
|
|
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`
|
|
95
|
-
> `
|
|
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
|
-
>
|
|
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.
|
|
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``,
|
|
183
|
-
``autoclose_debt_marker
|
|
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
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
{specfuse_loop-0.9.2 → specfuse_loop-0.10.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md
RENAMED
|
@@ -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
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
148
|
-
specfuse
|
|
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
|
|
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).
|