specfuse-loop 0.19.0__tar.gz → 0.20.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.19.0/specfuse_loop.egg-info → specfuse_loop-0.20.0}/PKG-INFO +1 -1
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/pyproject.toml +1 -1
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/closing_requirements.py +20 -3
- specfuse_loop-0.20.0/specfuse/loop/data/VERSION +1 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/methodology.md +69 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/close-discipline.md +14 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/never-touch.md +23 -26
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/result-contract.md +49 -41
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/security-boundaries.md +23 -27
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules-local/README.md +20 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/driver-event.schema.json +3 -2
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/verification.yml.example +6 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/gate_eval.py +28 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/judge.py +27 -1
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/lint_closing.py +19 -1
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/loop.py +1189 -21
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0/specfuse_loop.egg-info}/PKG-INFO +1 -1
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/SOURCES.txt +17 -0
- specfuse_loop-0.20.0/tests/test_binding_block_allocation.py +64 -0
- specfuse_loop-0.20.0/tests/test_binding_block_budget.py +43 -0
- specfuse_loop-0.20.0/tests/test_brief_covers_every_unit_escalation.py +228 -0
- specfuse_loop-0.20.0/tests/test_conditional_reflection.py +437 -0
- specfuse_loop-0.20.0/tests/test_distilled_accept_step.py +193 -0
- specfuse_loop-0.20.0/tests/test_judge_terminal_flip_state.py +95 -0
- specfuse_loop-0.20.0/tests/test_learnings_weights.py +249 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_closing.py +10 -0
- specfuse_loop-0.20.0/tests/test_progress_forward_note.py +107 -0
- specfuse_loop-0.20.0/tests/test_progress_lines_end_to_end.py +155 -0
- specfuse_loop-0.20.0/tests/test_reflection_required_signals.py +151 -0
- specfuse_loop-0.20.0/tests/test_replan_end_to_end.py +216 -0
- specfuse_loop-0.20.0/tests/test_replan_event_emission.py +186 -0
- specfuse_loop-0.20.0/tests/test_replan_note_collision.py +150 -0
- specfuse_loop-0.20.0/tests/test_replan_trigger.py +277 -0
- specfuse_loop-0.20.0/tests/test_replan_turn_contract.py +304 -0
- specfuse_loop-0.20.0/tests/test_spinout_brief_end_to_end.py +180 -0
- specfuse_loop-0.20.0/tests/test_spinout_brief_replan_option.py +297 -0
- specfuse_loop-0.19.0/specfuse/loop/data/VERSION +0 -1
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/LICENSE +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/NOTICE +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/README.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/setup.cfg +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/__init__.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/budget.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/diagnose_invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/drafting_answers.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/drafting_invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/drafting_questions.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/driver_command.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/driver_invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/monitoring_read.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/__init__.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/answers.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/bugs.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/feature.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/findings_autofix.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/findings_diagnose.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/providers/triage.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/queue_read.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/repo_detect.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/run.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/triage_invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/agent/worktree.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/__init__.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/_filelock.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/_miniyaml.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/_wu_sections.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/adopt_feature.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/agent_policy.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/arm_eval.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/arm_sweep.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/arm_txn.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/bug_lane.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/bug_lane_run.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/bug_lane_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/build_provenance.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/changelog.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/cost.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/criteria_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/LEARNINGS.template.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/getting-started.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/glossary.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/docs/skills.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/gitignore.snippet +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/monitoring.yml.example +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/roadmap.template.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/correlation-ids.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/human-output.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/operator-escalation.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/planning-discipline.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/verification-discipline.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/event.schema.json +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/GATE.template.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/PLAN.template.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/templates/WU.template.md +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/decisions_format.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/driver_edit.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/escalation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/events_stats.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/gate_commands.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/gh_backend.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/gh_features.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/heartbeat.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/labels.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/learnings_query.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/lint_monitoring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/lint_plan.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/lint_roadmap.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/notify.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/notify_escalation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/notify_sla.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/plan_baseline.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/policy_proposals.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/policy_review.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/prerun.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/prerun_capture.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/promotion.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/rearm_migration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/replay_spin.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/roadmap_archive.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/scaffold.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/triage.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/validate_event.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/__init__.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/adapters.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/artifact.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/autofix.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/autofix_invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/autofix_run.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/autofix_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/cli.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/diagnose_cli.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/diagnosis.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/fingerprint.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/issues.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/providers/__init__.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/providers/_azure_auth.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/providers/azure_app_insights.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/providers/azure_service_bus.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/redaction.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/monitor/schedule.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/dependency_links.txt +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/entry_points.txt +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/requires.txt +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse_loop.egg-info/top_level.txt +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_abandon_feature_skill.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_abandoned_work_reported.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_abandoned_wu_strands_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_adopt_feature.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_budget.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_bug_selection_dedup.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_default_features_root.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_driver_command.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_driver_invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_driver_restart.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_escalation_on_issue.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_escalation_run_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_findings_seam.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_invoke_timeout.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_invoke_usage.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_item_worktree.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_lock.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_policy_key_ownership.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_policy_queue.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_policy_schema.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_policy_triage_dial.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_answers.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_bugs.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_feature.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_findings_autofix.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_findings_diagnose.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_isolation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_provider_triage.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_queue_read.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_relays_driver_output.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_repo_detect.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_run.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_run_progress.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_seam.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_agent_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_answer_escalation_skill.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_app_insights_adapters.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_archive_ref_reconciliation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_eval.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_eval_lint_class.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_eval_wiring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_gate_edits_uncommitted.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_sweep.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_sweep_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_txn.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_arm_wiring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_artifact_redaction.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attempt_note_untracked_files.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attempt_outcome_contract.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attempt_outcome_emission.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attention_nonwriting_guard.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attention_silence_section.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_attention_skill_structure.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autoclose_deferral_visibility.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autoclose_gate_note.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autoclose_stub_states_what_passed.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_live.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_predicate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_run.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autofix_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync_consent.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync_firstrun.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync_no_cwd_leak.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_autosync_plugin.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_azure_credential_resolution.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_backend.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_escalation_message.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_persistence.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_probe.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_provenance.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_baseline_tree_hash_key.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bash_routing.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bats_suites_gated.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_binary_verdict.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bookkeeping_commit_crash_run.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bookkeeping_no_verify.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_ci_pending.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_guardrails.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_label_nonfatal.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_labels_registered.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_policy_contract.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_pr_number_carried.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_preflight_and_dial.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_run.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_bug_lane_test_paths.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_build_provenance.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changed_file_test_selection.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changelog_append_only.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changelog_collection.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changelog_release_wiring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_changelog_schema.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ci_conclusion_wait.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ci_runs_every_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_claude_resolution.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_close_b_pending_learnings.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_close_records_feature_oracle.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_close_wu_self_reference.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_deliverable_guard.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_guard_contracts.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_guard_prediction.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_learnings_destination.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_closing_requirements.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_coauthor_trailer_allowlist.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_console_encoding.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_convergent_iteration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_convergent_wu_lint.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_correlation_id_override.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_correlation_id_two_surfaces.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_cost_lifetime.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_cost_tracking.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_criteria_per_gate_lint.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_criteria_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_criteria_worklist.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_decision_citation_lint.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_decision_followups_discharged.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_decision_override_lint.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_decisions_format.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_degraded_oracle.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_deliverable_missing_note.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_deliverable_presence_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_derive_agent_policy_review_mode.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_derive_agent_policy_skill.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_derive_monitoring_discovery.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_derive_monitoring_skill_registration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_design_for_diagnosis_rule.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_deterministic_refusal_repeat.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_diagnose_headless.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_diagnose_issue_skill.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_diagnosis.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_diagnosis_roundtrip_live.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_dispatch_skeleton.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_doctor.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_done_feature_gates.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_draft_feature_answers_mode.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_answer_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_invoke.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_question_issue.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_questions.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_drafting_reply_shape.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_edit_detection.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_event_registry_covers_emitters.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_integration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_lock.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_module_surface.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_restart_halt_surfaced.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_restart_halt_wiring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_restart_hold.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_staleness_gate_summary.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_driver_staleness_warning.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_dry_run_no_branch_mutation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_duration_tracking.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_empty_files_escalation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ensure_feature_branch.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ensure_feature_branch_base.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_assignee_policy.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_contract.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_crash_containment.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_dedup_search.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_escalation_emit.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_event_gate_full_envelope.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_events_redaction.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_events_stats.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_extra_gates.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_failure_artifact_model.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_failure_signature_fail_prefix.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_failure_signature_skips_log_noise.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_branch_auto_sync.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_branch_squash_merge.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_branch_stale_base.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_id_resolution.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_oracle_e2e.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_provider_drafting_dispatch.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_feature_review_accumulation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_filelock_portable.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_files_changed_auto_repair.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_find_pr_no_search_index.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fingerprint.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fix_bug_diff_self_check.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fix_bug_headless.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fix_bug_reads_comments.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_fold_contract_documented.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_followups_artifact.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_force_full_close.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_frontmatter_scalar_quoting.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_broad_run.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_budget.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_budget_post_dispatch.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_commands_needs.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval_calibration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval_intermediate_wiring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval_repo_flag.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_eval_terminal_wiring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gate_report_verdict.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gh_backend.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gh_features.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_git_env_isolation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_gitleaks_pinning.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_groom_backlog_skill.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_guard_refusal_failure_class.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_guard_refusal_failure_excerpt.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_guard_repair_e2e.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_guard_repair_prompt.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_hashed_denylist.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_hashed_denylist_ci.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_heartbeat.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_heartbeat_adapter.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_human_output_rule.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_human_work_unit.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_hyphenated_gate_name.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_init_integration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_installed_copy_driver_e2e.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_interpreter_normalization.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_close_path.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_cost.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_cost_fold_committed.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_module.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_judge_path_registry.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_label_provisioning_runner_contract.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_label_registry.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_label_registry_covers_consumers.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_language_aware_narrow_selection.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lazy_baseline_e2e.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_leak_findings_redaction.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_leak_scan.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_leak_scan_content.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_learnings_curate_vendored_promote.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_learnings_query.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_learnings_staging.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_learnings_suggest_signature_filter.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_legacy_4wu_terminal_flips.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lifecycle_integration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lifetime_accounting.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_ac_observable.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_bare_produces_path.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_boundary_consistency.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_boundary_extraction.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_close_intermediate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_close_verdict_not_predecided.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_close_wu.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_closing_criteria.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_closing_criteria_pristine.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_correlation_id.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_feature_oracle_declared.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_gate_proportionality.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_monitoring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_oracle_env.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_contract_fields.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_errors.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_next_draft.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_relative_import.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_plan_verdict_exempt.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_planning_sections.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_produces_driver_helper.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_produces_satisfiability.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_roadmap.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_sections.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_task_graph_yaml_selection.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_lint_verification_reference.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_live_tests_opt_in.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_load_bearing_close_lint.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_attempt_evidence.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_auto_archive.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_caveman_preamble.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_close_intermediate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_criteria_skeleton.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_criteria_survival.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_defaults_by_type.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_effort.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_failure_note_cap.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_files_changed_guard.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_gate_budget.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_gate_needs.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_model_alias.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_orchestration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_post_pass_invariant.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_reset_preserving_events.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_smoke_runner.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_unsandboxed.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_worklist_injection.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_loop_zero_token_guard.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_make_repo_gpgsign_isolation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_maven_failure_excerpt.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_max_attempts_configurable.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_migrate_legacy.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_miniyaml_equivalence.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_miniyaml_negative.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitor_cli.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitor_issue_lifecycle.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitor_runner_surfaces.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_cron_dialect.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_example.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_fenced_blocks.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_monitoring_seed.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_narrow_fallback_warning.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_no_pytest_subprocess.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_notify.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_notify_escalation.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_notify_sla.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_operator_escalation_rule.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_oracle_set_declared.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_oracle_unrunnable_attribution.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pick_feature_skill.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pin_honesty_and_integrity.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pin_marker_not_inherited.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pin_marker_spawn_sites.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_plan_baseline.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_planned_cost_lint.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_planning_cost_floor.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_policy_proposals.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_policy_review.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pr_checks_json_field.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prep_halt_operator_surface.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prepare_feature.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prepare_scaffold_sync.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prerun_capture.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prerun_oracles.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_prerun_wiring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produced_document_verdict_guard.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_bracket_literal.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_bracket_wildcard.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_field.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_in_diff.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_justification.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_recursive_glob.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_semantics_unified.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_produces_shape.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_promotion_ledger.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_provider_escalation_traces.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_provision_labels.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_queue_stalled_adapter.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_rearm_clears_stale_criteria_state.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_rearm_fold_marker.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_rearm_migration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_red_baseline_never_reused.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_redaction_windows_home.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_replay_spin.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_resolve_base.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_restart_cap_counts_progress.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_result_block.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_result_block_audience.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_resume_command_build.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_retain_on_guard_refusal_docs.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_add_skill.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_archive_cli.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_archive_shim.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_archive_skill.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_archive_skill_delegates.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_link_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_roadmap_row_parser.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_ruff_verdict_lines.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_data_in_sync.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_doc_hygiene.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_docs.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_init.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_label_provisioning.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_manifest.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_resources.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_seed_sanity.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_skew_halts.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_upgrade.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_scaffold_wiring.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_schedule_dialect.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_seed_documents_prerun_keys.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_service_bus_dlq_adapter.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_session_env_preflight.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_shipped_templates_parse.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_skill_discovery_links.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_skills_vendored_in_sync.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_spinning_rearm_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_squash_commit_hook_crash.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_stop_rationale_captured.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_surefire_run_level_signature.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_surefire_verdict_lines.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_template_closing_shapes.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_terminal_flip_ownership.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_terminal_flips.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_terminal_gate_message.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_tiered_verification_e2e.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_timeout_kill_portable.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_triage.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_triage_apply.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_triage_skill_contract.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_triage_skips_agent_escalations.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_tsc_verdict_lines.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_umbrella_version_resolution.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_unterminated_frontmatter.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_untracked_feature_folder.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_untracked_file_absorption.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_upgrade_integration.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_validate_event.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_validate_event_driver_types.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_verdict_coupling.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_verify_empty_gate_set.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_version_consistency.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_version_skew.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_windows_gate_exec.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_worktree_restore.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_wu_execution_metadata.py +0 -0
- {specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/tests/test_wu_template_renders_lintable.py +0 -0
|
@@ -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.20.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"
|
|
@@ -281,14 +281,25 @@ CLOSING_REQUIREMENTS: dict[str, list[Requirement]] = {
|
|
|
281
281
|
),
|
|
282
282
|
Requirement(
|
|
283
283
|
id="close-e", wu_type="close", phase="pre-squash",
|
|
284
|
-
description=
|
|
284
|
+
description=(
|
|
285
|
+
f"RETROSPECTIVE.md has a '{COST_ANALYSIS_HEADING}' heading "
|
|
286
|
+
"when verdict==met AND gate_eval.reflection_required says "
|
|
287
|
+
"the gate went off-plan (FEAT-2026-0106/T03) — an on-plan "
|
|
288
|
+
"close skips this reflective section"
|
|
289
|
+
),
|
|
285
290
|
file=RETROSPECTIVE_FILENAME, heading=COST_ANALYSIS_HEADING,
|
|
286
291
|
applies_when="verdict_met",
|
|
287
292
|
enforced_by="assert_cost_analysis_section_when_met",
|
|
288
293
|
),
|
|
289
294
|
Requirement(
|
|
290
295
|
id="close-f", wu_type="close", phase="pre-squash",
|
|
291
|
-
description=
|
|
296
|
+
description=(
|
|
297
|
+
f"RETROSPECTIVE.md has a '{FAILURE_CLASS_HEADING}' heading "
|
|
298
|
+
"when non-passing attempts are present AND "
|
|
299
|
+
"gate_eval.reflection_required says the gate went off-plan "
|
|
300
|
+
"(FEAT-2026-0106/T03) — an on-plan close skips this "
|
|
301
|
+
"reflective section"
|
|
302
|
+
),
|
|
292
303
|
file=RETROSPECTIVE_FILENAME, heading=FAILURE_CLASS_HEADING,
|
|
293
304
|
heading_level=FAILURE_CLASS_HEADING_LEVEL,
|
|
294
305
|
applies_when="failures_present",
|
|
@@ -397,7 +408,13 @@ CLOSING_REQUIREMENTS: dict[str, list[Requirement]] = {
|
|
|
397
408
|
),
|
|
398
409
|
Requirement(
|
|
399
410
|
id="close-intermediate-d", wu_type="close-intermediate", phase="pre-squash",
|
|
400
|
-
description=
|
|
411
|
+
description=(
|
|
412
|
+
f"RETROSPECTIVE.md has a '{FAILURE_CLASS_HEADING}' heading "
|
|
413
|
+
"when non-passing attempts are present AND "
|
|
414
|
+
"gate_eval.reflection_required says the gate went off-plan "
|
|
415
|
+
"(FEAT-2026-0106/T03) — an on-plan close skips this "
|
|
416
|
+
"reflective section"
|
|
417
|
+
),
|
|
401
418
|
file=RETROSPECTIVE_FILENAME, heading=FAILURE_CLASS_HEADING,
|
|
402
419
|
heading_level=FAILURE_CLASS_HEADING_LEVEL,
|
|
403
420
|
applies_when="failures_present",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.20.0
|
|
@@ -185,6 +185,16 @@ For the full design rationale see `PLAN.md` for FEAT-2026-0018.
|
|
|
185
185
|
FEAT-2026-0016, if present, is also inspected — any prior `blocked_human`
|
|
186
186
|
cycle disables auto.
|
|
187
187
|
2. **No replan** — no `replan` event in `events.jsonl` for this gate's WUs.
|
|
188
|
+
A replan fires when a unit's next attempt would be its last permitted one
|
|
189
|
+
(the ceiling `resolve_max_attempts` resolves for that unit, not a bare
|
|
190
|
+
count of two) — the driver runs a fresh re-plan session instead of
|
|
191
|
+
retrying the same failing body verbatim. Units with `iterate_on_failure:
|
|
192
|
+
true` are exempt: they fail on purpose against a convergent validator, and
|
|
193
|
+
a replan there would misread deliberate iteration as spinning. Seeing this
|
|
194
|
+
check disable auto-close means a unit was mis-sized at authoring time (see
|
|
195
|
+
`/authoring-work-units` §6), not that anything is broken. A unit that
|
|
196
|
+
still spins out after this automatic re-plan escalates to a human — see
|
|
197
|
+
the escalation brief below for what that escalation tells the operator.
|
|
188
198
|
3. **Per-WU cost ≤ 1.5× planned** — every substantive WU's `cost_usd` ≤
|
|
189
199
|
`planned_cost_usd × 1.5`. If `planned_cost_usd` absent: skip this check for
|
|
190
200
|
that WU (graceful degrade — emits a warning reason in the decision but doesn't
|
|
@@ -202,6 +212,28 @@ For the full design rationale see `PLAN.md` for FEAT-2026-0018.
|
|
|
202
212
|
failed (already governed by check 1 if blocked), but the FINAL outcome on
|
|
203
213
|
each WU must be clean.
|
|
204
214
|
|
|
215
|
+
**The escalation brief (FEAT-2026-0104)** — **every** `blocked_human`
|
|
216
|
+
escalation of a work unit, not only the spin-out that follows the automatic
|
|
217
|
+
re-plan above, halts with a six-part operator brief
|
|
218
|
+
(`.specfuse/rules/operator-escalation.md`'s six parts, in order), printed to
|
|
219
|
+
the console and recorded verbatim in the `human_escalation` event's `message`
|
|
220
|
+
field in `events.jsonl`. Gate-level halts — a gate budget exceeded, a
|
|
221
|
+
pre-existing gate failure, a failing broad run — are excluded: those are keyed
|
|
222
|
+
on the feature rather than on one unit, and there is no single unit to brief
|
|
223
|
+
about. The escalation `reason` decides
|
|
224
|
+
whether the brief's first option is re-planning the remaining gate:
|
|
225
|
+
`spinning_detected`, `spinning_signature_repeat`, `convergence_plateau`, and
|
|
226
|
+
`replan_unchanged_body` carry it, because for those a wider re-scope is the
|
|
227
|
+
remedy; `all_attempts_zero_token`, `deterministic_refusal_repeat`,
|
|
228
|
+
`produces_shape_invalid`, `spinning_reproduction_missing`, `prep_halted`, and
|
|
229
|
+
`agent_reported_blocked` do not, because re-planning would fix nothing about
|
|
230
|
+
that reason's actual cause (`REPLAN_OPTION_SCOPE` in `loop.py` is the single
|
|
231
|
+
table both the brief and its tests consult). When it applies, the option is a
|
|
232
|
+
recommendation, not an action the driver performs: the brief names
|
|
233
|
+
`/unblock-wu` for the operator to run, re-arming the unit(s) so the driver's
|
|
234
|
+
own automatic re-plan trigger (check 2 above) becomes reachable again for
|
|
235
|
+
each — it resets `attempts`, it does not itself rewrite a body.
|
|
236
|
+
|
|
205
237
|
**Auto-close terminal** — when the predicate fires on a terminal gate, the driver
|
|
206
238
|
writes a stub `RETROSPECTIVE.md`, marks the close WU `status: done` with
|
|
207
239
|
`auto_close: true` frontmatter, and fires `fire_terminal_flips` directly. The
|
|
@@ -563,6 +595,18 @@ reflective session. Ceremony proportionality trades reflection only on
|
|
|
563
595
|
features that stay small **and** on-plan. The `gate_eval.py` predicate is
|
|
564
596
|
the safety net; this rule does not replace it.
|
|
565
597
|
|
|
598
|
+
**Reflective prose is conditional too (FEAT-2026-0106).** The roadmap once
|
|
599
|
+
asked for a retrospective "only on `not_met` or on request" — superseded,
|
|
600
|
+
for an ordering reason: the close writes `RETROSPECTIVE.md` before the judge
|
|
601
|
+
produces a verdict, so there is nothing to condition on at write time. The
|
|
602
|
+
close instead keys its reflective sections (`## Cost analysis`,
|
|
603
|
+
`### Failure-class breakdown`) on the same off-plan signal named above
|
|
604
|
+
(blocked WU, replan event, cost overrun) rather than on the verdict. Every
|
|
605
|
+
other closing obligation — measurements above all, since the judge's evidence
|
|
606
|
+
bundle depends on them regardless of how the gate went — stays unconditional;
|
|
607
|
+
see [`close-discipline.md`](../.specfuse/rules/close-discipline.md) §1a for
|
|
608
|
+
which is which.
|
|
609
|
+
|
|
566
610
|
The canonical threshold is **8** (stated here, in `docs/methodology.md`;
|
|
567
611
|
referenced, not re-defined, in `.specfuse/skills/draft-feature/SKILL.md`).
|
|
568
612
|
|
|
@@ -610,6 +654,31 @@ feature's `RETROSPECTIVE.md`; only rules that would change how a *future* WU is
|
|
|
610
654
|
written or executed graduate to `LEARNINGS.md`. This is the human-scale analogue
|
|
611
655
|
of the Ralph loop feeding errors back into the prompt.
|
|
612
656
|
|
|
657
|
+
### The binding-block word budget (FEAT-2026-0111)
|
|
658
|
+
|
|
659
|
+
The `.claude/CLAUDE.md` "Specfuse binding rules" block — every `@`-referenced
|
|
660
|
+
file a dispatched work-unit session is held to — is capped at 2,500 words
|
|
661
|
+
(`BINDING_BLOCK_WORD_CAP` in `specfuse/loop/loop.py`), enforced by
|
|
662
|
+
`check_binding_block_budget`. Every rule added to that block, including a
|
|
663
|
+
project-authored entry under `.specfuse/rules-local/`, is counted against this
|
|
664
|
+
one shared cap; a project adding a local rule spends the same allowance the
|
|
665
|
+
loop's own rules already draw from.
|
|
666
|
+
|
|
667
|
+
`.specfuse/rules-local/learnings-distilled.md` — the LEARNINGS-derived
|
|
668
|
+
distillate wired into the block — carries its own 500-word sub-budget
|
|
669
|
+
(`LEARNINGS_DISTILLED_WORD_CAP`) inside the 2,500-word total. `score_learnings_entries`
|
|
670
|
+
ranks candidate entries and a human accept step (`apply_distilled_decisions`)
|
|
671
|
+
cuts the accepted set to that 500-word sub-budget, not to an entry count.
|
|
672
|
+
|
|
673
|
+
The ranking's `reach` field — the count of other feature files that cite an
|
|
674
|
+
entry — is **a tiebreaker with an age bias, not a ranking signal**: it counts
|
|
675
|
+
citations in planning documents, and planning agents cite what they have
|
|
676
|
+
already read in `LEARNINGS.md`, so visibility inflates its own count, and it
|
|
677
|
+
favors older entries that have had more features' worth of planning sessions
|
|
678
|
+
in which to be cited. Neither `reach` nor `cost_usd` measures whether a rule
|
|
679
|
+
actually improves a session's work — that is a judgment the accept step still
|
|
680
|
+
has to make by reading the entry, not a property either weight computes.
|
|
681
|
+
|
|
613
682
|
## 9. Autonomy
|
|
614
683
|
|
|
615
684
|
Three levels — `auto`, `review`, `supervised` — set once as a feature default
|
|
@@ -76,6 +76,20 @@ conclude it — the reason the judge is a fresh session in the first place. A
|
|
|
76
76
|
close body names what to measure and what evidence counts, never what value to
|
|
77
77
|
write. Naming the verdict in the body is a drafting defect, not a shortcut.
|
|
78
78
|
|
|
79
|
+
## 1a. Which obligations are conditional (FEAT-2026-0106)
|
|
80
|
+
|
|
81
|
+
Not every obligation above binds on every close. The reflective sections —
|
|
82
|
+
`## Cost analysis` and `### Failure-class breakdown` — are conditional on
|
|
83
|
+
`gate_eval`'s off-plan signal (a blocked WU, a `replan` event, a cost
|
|
84
|
+
overrun): an on-plan close skips them. Measurements are not conditional on
|
|
85
|
+
anything, for the reason stated in §1 — the judge's evidence bundle slices
|
|
86
|
+
`## Measurements` out of `RETROSPECTIVE.md` regardless of how the gate went,
|
|
87
|
+
so a close that skipped writing them would starve the judge of the evidence
|
|
88
|
+
it needs to reach a verdict at all. `docs/methodology.md` §6 "Ceremony
|
|
89
|
+
proportionality" states the same off-plan signal at the gate-dispatch level
|
|
90
|
+
(whether a close runs at all); this section is the narrower case of a close
|
|
91
|
+
that does run still skipping prose the gate didn't earn.
|
|
92
|
+
|
|
79
93
|
## 2. The verdict is binary; unfinished work is tracked, not hedged
|
|
80
94
|
|
|
81
95
|
The verdict a close records is `met` or `not_met` — there is no partial
|
|
@@ -7,50 +7,47 @@ Licensed under the Apache License, Version 2.0. See LICENSE.
|
|
|
7
7
|
|
|
8
8
|
Three categories of path are off-limits to every work-unit session, regardless of
|
|
9
9
|
unit type. If a unit's acceptance criteria or verification commands appear to
|
|
10
|
-
require modifying something in this list, that is an escalation condition, not
|
|
10
|
+
require modifying something in this list, that is an escalation condition, not
|
|
11
11
|
license to proceed — signal blocked per
|
|
12
12
|
[`verification-discipline.md`](verification-discipline.md), naming the
|
|
13
|
-
boundary. (How "blocked" is signalled is surface-specific
|
|
13
|
+
boundary. (How "blocked" is signalled is surface-specific: a `status: blocked`
|
|
14
14
|
RESULT on the loop, a `blocked_*` transition on the orchestrator.)
|
|
15
15
|
|
|
16
16
|
## 1. Generated code directories
|
|
17
17
|
|
|
18
|
-
Any path under a generated directory — `_generated/`, `gen-src/`, or whatever
|
|
19
|
-
repo declares as its generated tree — is off-limits. Generators own those
|
|
20
|
-
end-to-end; an edit there is silently overwritten on
|
|
21
|
-
|
|
18
|
+
Any path under a generated directory — `_generated/`, `gen-src/`, or whatever
|
|
19
|
+
the repo declares as its generated tree — is off-limits. Generators own those
|
|
20
|
+
files end-to-end; an edit there is silently overwritten on regeneration,
|
|
21
|
+
leaving no trace of why.
|
|
22
22
|
|
|
23
|
-
-
|
|
24
|
-
declaration (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
file inside a generated directory is still a write to that directory.
|
|
29
|
-
- The rule applies regardless of whether the file currently exists.
|
|
23
|
+
- Canonical names are `_generated/` and `gen-src/`, but the repo's own
|
|
24
|
+
declaration (README, `specfuse.yaml`, equivalent config) is authoritative;
|
|
25
|
+
a differently-named generated directory gets identical treatment.
|
|
26
|
+
- Applies to every file under the directory recursively, including a new file
|
|
27
|
+
created there, and regardless of whether the file currently exists.
|
|
30
28
|
|
|
31
|
-
When a generated file is wrong,
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
When a generated file is wrong, change the spec or generator that produced
|
|
30
|
+
it, not the file itself. If that is outside this unit's boundary, signal
|
|
31
|
+
blocked with the spec/generator change named.
|
|
34
32
|
|
|
35
33
|
## 2. Secrets and credentials
|
|
36
34
|
|
|
37
35
|
Secrets include, at minimum: API tokens, deploy keys, SSH private keys, OAuth
|
|
38
|
-
client secrets, webhook signing secrets, database passwords, `.env` files,
|
|
39
|
-
credentials (AWS, GCP, Azure), and any file conventionally holding
|
|
36
|
+
client secrets, webhook signing secrets, database passwords, `.env` files,
|
|
37
|
+
cloud credentials (AWS, GCP, Azure), and any file conventionally holding one
|
|
40
38
|
(`*.pem`, `*.key`, `id_rsa*`, `credentials.json`, `.npmrc` tokens, `gh auth`
|
|
41
39
|
tokens).
|
|
42
40
|
|
|
43
41
|
You must not:
|
|
44
42
|
|
|
45
|
-
- Read
|
|
43
|
+
- Read a secrets file's contents. If a unit requires one, see
|
|
46
44
|
[`security-boundaries.md`](security-boundaries.md) for the escalation path.
|
|
47
|
-
- Write
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
or fixtures.
|
|
45
|
+
- Write anything credential-looking into the RESULT block, event log, a
|
|
46
|
+
commit, or any produced artifact — whether real or invented.
|
|
47
|
+
- Echo secret-holding environment variables. Reference by name
|
|
48
|
+
(`$GITHUB_TOKEN`) over reading their values.
|
|
49
|
+
- Commit secret files under any circumstance, including as examples or
|
|
50
|
+
fixtures.
|
|
54
51
|
|
|
55
52
|
## 3. `.git/` internals
|
|
56
53
|
|
|
@@ -13,15 +13,15 @@ driver re-runs verification itself, and that is what decides done.
|
|
|
13
13
|
## Who reads it — emit it only when something does
|
|
14
14
|
|
|
15
15
|
This block is a **machine interface**, not a report. Emit it when a program is
|
|
16
|
-
on the other end: a work-unit session the driver dispatched (always), or a
|
|
17
|
-
invoked **non-interactively** from a calling program that parses the
|
|
18
|
-
(`fix-bug` under `autofix_invoke` is the live example).
|
|
16
|
+
on the other end: a work-unit session the driver dispatched (always), or a
|
|
17
|
+
skill invoked **non-interactively** from a calling program that parses the
|
|
18
|
+
outcome (`fix-bug` under `autofix_invoke` is the live example).
|
|
19
19
|
|
|
20
|
-
Do **not** emit it on an interactive run
|
|
21
|
-
no parser
|
|
22
|
-
[`human-output.md`](human-output.md) exists to prevent
|
|
23
|
-
rule instead. When in doubt
|
|
24
|
-
|
|
20
|
+
Do **not** emit it on an interactive run — a human who typed `/pick-feature`
|
|
21
|
+
has no parser, and the block lands as a slab to scroll past, the verbosity
|
|
22
|
+
[`human-output.md`](human-output.md) exists to prevent. Report to them per
|
|
23
|
+
that rule instead. When in doubt: a slash command typed by a person is
|
|
24
|
+
interactive; a `claude -p` dispatch is not.
|
|
25
25
|
|
|
26
26
|
## The cycle: state intent, act, verify, report
|
|
27
27
|
|
|
@@ -33,25 +33,25 @@ cycle; this file is normative on how the loop surface reports step 4.
|
|
|
33
33
|
the unit is not what you thought it was.
|
|
34
34
|
2. **Act.** Stay inside that scope. "While I was here I also fixed X" is drift;
|
|
35
35
|
the work unit's **Do not touch** section is binding.
|
|
36
|
-
3. **Verify.** Re-read what you produced —
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
36
|
+
3. **Verify.** Re-read what you produced — Write/Edit reports the action taken,
|
|
37
|
+
not the property you wanted — and run the work unit's own verification
|
|
38
|
+
commands, in declared order, with full output. On the loop that set is the
|
|
39
|
+
**per-attempt (narrow) tier**: the unit type's gates minus any declaring
|
|
40
|
+
`tier: broad`, with `tests` through its `narrow_command` over the unit's
|
|
41
|
+
`produces:` test modules. The full suite, coverage and every `tier: broad`
|
|
42
|
+
gate are the driver's, once per gate — running them in-session buys nothing
|
|
43
|
+
the driver does not re-run. "I assume the tests still pass" is not
|
|
44
|
+
verification. A behavioural claim needs a run, not a source reading; a
|
|
45
|
+
rule-or-severity claim needs a **negative observation** — the rule seen
|
|
46
|
+
rejecting a purpose-built bad input.
|
|
47
47
|
4. **Report.** Report only what verification confirmed.
|
|
48
48
|
|
|
49
|
-
A failing check leaves you in one of three situations: correctable locally
|
|
50
|
-
the cause, re-run the **whole narrow tier** from the top), spinning
|
|
51
|
-
attempts is the driver's budget — emit `status: blocked` with
|
|
52
|
-
rather than guessing), or fundamentally blocked (
|
|
53
|
-
code that must change, a missing dependency — emit `status: blocked`
|
|
54
|
-
boundary).
|
|
49
|
+
A failing check leaves you in one of three situations: correctable locally
|
|
50
|
+
(fix the cause, re-run the **whole narrow tier** from the top), spinning
|
|
51
|
+
(three fresh attempts is the driver's budget — emit `status: blocked` with
|
|
52
|
+
evidence rather than guessing), or fundamentally blocked (spec ambiguity,
|
|
53
|
+
generated code that must change, a missing dependency — emit `status: blocked`
|
|
54
|
+
naming the boundary).
|
|
55
55
|
|
|
56
56
|
## Format
|
|
57
57
|
|
|
@@ -59,6 +59,7 @@ boundary).
|
|
|
59
59
|
```result
|
|
60
60
|
status: complete | blocked # complete = "I believe acceptance criteria are met"
|
|
61
61
|
summary: <one sentence on what changed>
|
|
62
|
+
forward_note: <optional — one sentence on what the NEXT unit should know>
|
|
62
63
|
files_changed:
|
|
63
64
|
- path/to/file
|
|
64
65
|
acceptance_criteria:
|
|
@@ -72,6 +73,13 @@ produces_unchanged: # optional — closing obligation 1 below
|
|
|
72
73
|
```
|
|
73
74
|
````
|
|
74
75
|
|
|
76
|
+
`summary` is backward-looking by this contract's own definition — one sentence
|
|
77
|
+
on what changed. `forward_note` is the other half: what surprised you, or what
|
|
78
|
+
the next unit should know, that `summary` does not capture. It is optional and
|
|
79
|
+
never required by any guard. Omit it and nothing changes: the driver's
|
|
80
|
+
`PROGRESS.md` entry is exactly what it would have written without this field
|
|
81
|
+
(FEAT-2026-0106/T02).
|
|
82
|
+
|
|
75
83
|
## Rules
|
|
76
84
|
|
|
77
85
|
1. **No git.** You edit files only. The driver stages, squashes, and commits one
|
|
@@ -94,29 +102,29 @@ produces_unchanged: # optional — closing obligation 1 below
|
|
|
94
102
|
7. **A "pre-existing" failure claim cites the commit it was measured on.**
|
|
95
103
|
Calling a failure pre-existing is a claim about a *different* commit —
|
|
96
104
|
typically the merge-base — and nothing observed on your own branch
|
|
97
|
-
establishes it. Name the command and
|
|
98
|
-
sides, and emit `status: blocked` rather than asserting
|
|
99
|
-
|
|
100
|
-
unresolvable build dependencies)
|
|
101
|
-
|
|
105
|
+
establishes it. Name the command and commit, give the numbers from both
|
|
106
|
+
sides, and emit `status: blocked` rather than asserting an unmeasured
|
|
107
|
+
baseline: a mass of errors sharing one signature (network refused,
|
|
108
|
+
unresolvable build dependencies) reports where the suite ran, not the
|
|
109
|
+
repository (#2075).
|
|
102
110
|
|
|
103
111
|
## Closing obligations for implementation WUs (FEAT-2026-0049)
|
|
104
112
|
|
|
105
113
|
1. **Diff against `produces:` first.** Every path in the WU's `produces:` list
|
|
106
114
|
must show a working-tree change, or the RESULT must justify each unchanged
|
|
107
|
-
path under `produces_unchanged:` —
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
2. **A plan-level contradiction is `blocked`, not `complete`.**
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
path under `produces_unchanged:` — spelled as `produces:` spells it, plus
|
|
116
|
+
the command and output showing the deliverable already holds. The driver
|
|
117
|
+
reads that list: a justified entry passes and is recorded on the attempt as
|
|
118
|
+
`produces_justified`; an unjustified one, or a blank justification, is
|
|
119
|
+
refused (#198, #3268, outcome `produces_not_in_diff`). Silence on an
|
|
120
|
+
unchanged deliverable is not a valid close.
|
|
121
|
+
2. **A plan-level contradiction is `blocked`, not `complete`.** Put the
|
|
122
|
+
finding in `blocked_reason`; never write it into a gate document and close
|
|
123
|
+
`complete`.
|
|
116
124
|
3. **Every `evidence:` cites an executed command** and its observed exit
|
|
117
|
-
code/output. Reading source, grepping
|
|
125
|
+
code/output. Reading source, grepping a string, or citing another WU's
|
|
118
126
|
RESULT is not verification.
|
|
119
|
-
4. **Analysis without edits is not a silent attempt.** Say so
|
|
127
|
+
4. **Analysis without edits is not a silent attempt.** Say so and end
|
|
120
128
|
`blocked` rather than spending the attempt on prose.
|
|
121
129
|
|
|
122
130
|
The driver's whole cycle — re-verify, commit, advance the dependency frontier,
|
{specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/rules/security-boundaries.md
RENAMED
|
@@ -12,10 +12,8 @@ lists the specific path categories that are off-limits.
|
|
|
12
12
|
|
|
13
13
|
## Secrets
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
anything conventionally treated as a credential (see the enumeration in
|
|
18
|
-
[`never-touch.md`](never-touch.md) §2). The posture is strict:
|
|
15
|
+
The full enumeration lives in [`never-touch.md`](never-touch.md) §2. The
|
|
16
|
+
posture here is strict:
|
|
19
17
|
|
|
20
18
|
- **Never read.** Do not open a secrets file to inspect its contents, not even
|
|
21
19
|
"just to see the format." If a unit's verification needs one, stop and
|
|
@@ -41,29 +39,27 @@ Treat suspected-secret values with the same care as confirmed-secret values. A
|
|
|
41
39
|
## When a work unit appears to require privileged access
|
|
42
40
|
|
|
43
41
|
A unit whose acceptance criteria or verification commands appear to require
|
|
44
|
-
reading a secret, editing generated code directly, or any other privileged
|
|
45
|
-
is almost always a unit-definition problem, not
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
implicitly).
|
|
50
|
-
2. **Re-read the unit.**
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
diff visually and it looks right." That is a verification-bypass, not a
|
|
66
|
-
verification, and it produces a RESULT block the driver cannot trust.
|
|
42
|
+
reading a secret, editing generated code directly, or any other privileged
|
|
43
|
+
action is almost always a unit-definition problem, not license to break the
|
|
44
|
+
rule.
|
|
45
|
+
|
|
46
|
+
1. **Stop.** Do not attempt the privileged action, or work around it (e.g. a
|
|
47
|
+
command that reads the secret implicitly).
|
|
48
|
+
2. **Re-read the unit.** Often it describes how the *human* verifies, with the
|
|
49
|
+
session doing an upstream-only step.
|
|
50
|
+
3. **If genuine, signal blocked.** Name the privilege required (e.g.
|
|
51
|
+
"verification command requires reading `config/db-prod.env`") as the
|
|
52
|
+
blocked reason; the human decides whether to adjust the unit, run the step
|
|
53
|
+
out-of-band, or provide a scoped credential. (Surface-specific — a
|
|
54
|
+
`status: blocked` RESULT on the loop, a `blocked_*` transition on the
|
|
55
|
+
orchestrator.)
|
|
56
|
+
4. **Do not report complete.** A verification that could not be run is not a
|
|
57
|
+
verification (see [`verification-discipline.md`](verification-discipline.md)).
|
|
58
|
+
|
|
59
|
+
The common mistake is substituting a weaker check for a privileged one — "I
|
|
60
|
+
couldn't run the secret-requiring command, so I inspected the diff visually."
|
|
61
|
+
That is a verification-bypass, and it produces a RESULT block the driver
|
|
62
|
+
cannot trust.
|
|
67
63
|
|
|
68
64
|
## Authenticated tooling
|
|
69
65
|
|
|
@@ -40,4 +40,24 @@ Follow the shipped rules' format: one failure mode per rule, the check stated
|
|
|
40
40
|
imperatively, provenance recorded so the reasoning survives the rule (see
|
|
41
41
|
`.specfuse/rules/planning-discipline.md` for the model).
|
|
42
42
|
|
|
43
|
+
## The shared word budget
|
|
44
|
+
|
|
45
|
+
The `.claude/CLAUDE.md` binding rules block a work-unit session is dispatched
|
|
46
|
+
against is capped at 2,500 words total, and every rule you add here counts
|
|
47
|
+
against that one shared budget alongside the loop's own rules — this is not a
|
|
48
|
+
free directory. `.specfuse/rules-local/learnings-distilled.md`, the
|
|
49
|
+
LEARNINGS-derived distillate, carries its own 500-word sub-budget inside that
|
|
50
|
+
total; its content is decided by a human accept step
|
|
51
|
+
(`apply_distilled_decisions` in `specfuse/loop/loop.py`) that cuts a ranked
|
|
52
|
+
proposal to the sub-budget, not to an entry count. Before adding an entry to
|
|
53
|
+
that distillate or to a rule here, check whether a guard or lint already
|
|
54
|
+
enforces it — if so, it does not belong in the block: the block is for what a
|
|
55
|
+
session must be *told*, not for what tooling already *checks*.
|
|
56
|
+
|
|
57
|
+
The ranking's `reach` field (count of other feature files citing an entry) is
|
|
58
|
+
a tiebreaker with an age bias, not a ranking: it inflates on its own
|
|
59
|
+
visibility and favors older entries. Neither `reach` nor the entry's recorded
|
|
60
|
+
cost measures whether the rule actually improves a session's work — that
|
|
61
|
+
judgment call is still the accept step's, made by reading the entry.
|
|
62
|
+
|
|
43
63
|
This README is seeded once and never overwritten — edit it freely.
|
{specfuse_loop-0.19.0 → specfuse_loop-0.20.0}/specfuse/loop/data/schemas/driver-event.schema.json
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"$id": "https://specfuse.dev/loop/schemas/driver-event.schema.json",
|
|
4
4
|
"title": "Driver-local envelope registry",
|
|
5
5
|
"description": "Additive to the vendored orchestrator envelope (event.schema.json): shapes the loop driver emits with no orchestrator-side counterpart. validate_event.py resolves each shape against the vendored envelope first; only when absent there does it fall through to this registry. `event_types` (FEAT-2026-0060) widens the event_type enum; task_started, task_completed, and human_escalation are already sanctioned in the vendored enum and must not be duplicated here. `correlation_id` (FEAT-2026-0073) widens the correlation_id pattern to admit the closing-sequence and hygiene shapes `.specfuse/rules/correlation-ids.md` documents; `closing_names` and `hygiene_suffix_pattern` here must state the same set of shapes as that rules file's combined pattern (and as specfuse/loop/lint_plan.py's CORRELATION_ID_RE, which independently enforces the same contract on PLAN.md graphs).",
|
|
6
|
-
"$comment": "FEAT-2026-0060/T01: event_types derived from the union of every build_event(...) call site in specfuse/loop/loop.py and a corpus sweep of every .specfuse/features/*/events.jsonl, subtracting the vendored envelope enum. attempt_outcome and gate_reached were already-known precedent (loop.py's build_arm_predicate_event docstring); auto_close_decision, arm_predicate_evaluated, re_arm_dispatched, plan_next_draft_lint, and unsandboxed_dispatch are additional driver-local mechanics the orchestrator has no concept of. gate_auto_armed (loop.py build_event call under gate_events.append) and re_arm_rejected (loop.py build_event call under the spinning_reproduction_missing re-arm check) are emitted by real code paths that have never fired in a recorded run, so a corpus-only sweep cannot see them; they are included because call-site derivation does. FEAT-2026-0073/T01: correlation_id added — closing_names and hygiene_suffix_pattern mirror correlation-ids.md's documented shapes and lint_plan.py's CORRELATION_ID_RE verbatim, so the envelope, the rules file, and the PLAN-graph linter state one contract. FEAT-2026-0075/T03: driver_staleness_detected added — emitted at gate completion when a work unit's squash diff touched the driver's own importable surface, naming the editing unit, the driver paths it touched, and the IDs of units this process dispatched afterward (which ran the pre-edit module). FEAT-2026-0100/T02: judged added — emitted once per terminal close after the closing-deliverable guards, carrying the close's own verdict, the judge session's verdict (null when the judge was disabled, timed out, or returned nothing parseable, with the reason beside it), and whether the judge lowered it. FEAT-2026-0109/T01: baseline_attribution added — emitted when the retroactive per-attempt-failure baseline probe (attribute_failure_to_baseline) runs fresh, carrying the gate, the failing-gate set, and the unit whose failed attempt triggered the probe. FEAT-2026-0109/T06: broad_run_result added — emitted whenever the once-per-gate broad verification pass (gate_broad_run_check) actually runs (never on a tree-unchanged dedup skip), carrying the gate, the tree it was measured on, and its pass/fail outcome; a failing broad run additionally raises the existing human_escalation event type with reason: broad_run_gate_failure, which needs no schema addition since human_escalation is already sanctioned in the vendored envelope enum. FEAT-2026-0109/T08: driver_build_pinned added — emitted once per process, before any work unit is dispatched, when this process is itself a materialized pin (`_reexec_pinned`); carries the pin's tree hash and its path so an operator or test can read what build actually ran without inferring it from `ps` output. `driver_staleness_detected` needed no addition here: this unit reuses it with `halted: false` for the pinned, non-halting case (the registry constrains the type list, not the payload), adding `pinned_tree` / `next_pin_tree` fields alongside the existing `halted: true` shape.",
|
|
6
|
+
"$comment": "FEAT-2026-0060/T01: event_types derived from the union of every build_event(...) call site in specfuse/loop/loop.py and a corpus sweep of every .specfuse/features/*/events.jsonl, subtracting the vendored envelope enum. attempt_outcome and gate_reached were already-known precedent (loop.py's build_arm_predicate_event docstring); auto_close_decision, arm_predicate_evaluated, re_arm_dispatched, plan_next_draft_lint, and unsandboxed_dispatch are additional driver-local mechanics the orchestrator has no concept of. gate_auto_armed (loop.py build_event call under gate_events.append) and re_arm_rejected (loop.py build_event call under the spinning_reproduction_missing re-arm check) are emitted by real code paths that have never fired in a recorded run, so a corpus-only sweep cannot see them; they are included because call-site derivation does. FEAT-2026-0073/T01: correlation_id added — closing_names and hygiene_suffix_pattern mirror correlation-ids.md's documented shapes and lint_plan.py's CORRELATION_ID_RE verbatim, so the envelope, the rules file, and the PLAN-graph linter state one contract. FEAT-2026-0075/T03: driver_staleness_detected added — emitted at gate completion when a work unit's squash diff touched the driver's own importable surface, naming the editing unit, the driver paths it touched, and the IDs of units this process dispatched afterward (which ran the pre-edit module). FEAT-2026-0100/T02: judged added — emitted once per terminal close after the closing-deliverable guards, carrying the close's own verdict, the judge session's verdict (null when the judge was disabled, timed out, or returned nothing parseable, with the reason beside it), and whether the judge lowered it. FEAT-2026-0109/T01: baseline_attribution added — emitted when the retroactive per-attempt-failure baseline probe (attribute_failure_to_baseline) runs fresh, carrying the gate, the failing-gate set, and the unit whose failed attempt triggered the probe. FEAT-2026-0109/T06: broad_run_result added — emitted whenever the once-per-gate broad verification pass (gate_broad_run_check) actually runs (never on a tree-unchanged dedup skip), carrying the gate, the tree it was measured on, and its pass/fail outcome; a failing broad run additionally raises the existing human_escalation event type with reason: broad_run_gate_failure, which needs no schema addition since human_escalation is already sanctioned in the vendored envelope enum. FEAT-2026-0109/T08: driver_build_pinned added — emitted once per process, before any work unit is dispatched, when this process is itself a materialized pin (`_reexec_pinned`); carries the pin's tree hash and its path so an operator or test can read what build actually ran without inferring it from `ps` output. `driver_staleness_detected` needed no addition here: this unit reuses it with `halted: false` for the pinned, non-halting case (the registry constrains the type list, not the payload), adding `pinned_tree` / `next_pin_tree` fields alongside the existing `halted: true` shape. FEAT-2026-0104/T04: replan added — emitted once a re-plan turn (T03's run_replan_turn) rewrites a unit's body ahead of its last permitted attempt, so gate_eval.py's evaluate_auto_close (check 2, already reading this event_type since FEAT-2026-0018/T02) can disable auto-close for a gate that needed one.",
|
|
7
7
|
"event_types": [
|
|
8
8
|
"attempt_outcome",
|
|
9
9
|
"gate_reached",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"judged",
|
|
20
20
|
"baseline_attribution",
|
|
21
21
|
"broad_run_result",
|
|
22
|
-
"driver_build_pinned"
|
|
22
|
+
"driver_build_pinned",
|
|
23
|
+
"replan"
|
|
23
24
|
],
|
|
24
25
|
"correlation_id": {
|
|
25
26
|
"closing_names": [
|
|
@@ -121,6 +121,12 @@
|
|
|
121
121
|
# defaults:
|
|
122
122
|
# max_attempts: 3
|
|
123
123
|
# retain_on_guard_refusal: true
|
|
124
|
+
#
|
|
125
|
+
# The re-plan-after-two-failures behaviour (FEAT-2026-0104) reads this same
|
|
126
|
+
# `max_attempts` resolution and adds no config key of its own — a unit's
|
|
127
|
+
# next-to-last attempt re-plans instead of retrying verbatim, governed
|
|
128
|
+
# entirely by the ceiling above (or a WU's own `max_attempts`) plus that WU's
|
|
129
|
+
# `iterate_on_failure` flag.
|
|
124
130
|
|
|
125
131
|
code:
|
|
126
132
|
- name: tests
|
|
@@ -302,6 +302,34 @@ def evaluate_auto_close(feature_dir: Path, gate_id: int) -> AutoCloseDecision:
|
|
|
302
302
|
predicate_version=PREDICATE_VERSION,
|
|
303
303
|
)
|
|
304
304
|
|
|
305
|
+
return _evaluate_predicate_core(feature_dir, gate_id, plan, feature_id)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def evaluate_off_plan_signal(feature_dir: Path, gate_id: int) -> AutoCloseDecision:
|
|
309
|
+
"""Same predicate as `evaluate_auto_close`, but never short-circuited by
|
|
310
|
+
`auto_close_disabled` (FEAT-2026-0106/T03).
|
|
311
|
+
|
|
312
|
+
`auto_close_disabled` is an operator's administrative choice to always
|
|
313
|
+
dispatch a close for ceremony/oracle re-run reasons
|
|
314
|
+
(`close-discipline.md` — a "load-bearing" close always sets it) and says
|
|
315
|
+
nothing about whether the gate itself deviated from plan. A caller asking
|
|
316
|
+
"did this gate go off plan" — as opposed to "is this gate eligible to
|
|
317
|
+
auto-close" — needs the real blocked/replan/cost-overrun evidence even
|
|
318
|
+
when that flag is set, so this skips straight to `_evaluate_predicate_core`.
|
|
319
|
+
"""
|
|
320
|
+
plan = _read_plan_metrics(feature_dir)
|
|
321
|
+
fm = plan["frontmatter"]
|
|
322
|
+
feature_id = fm.get("feature_id", feature_dir.name)
|
|
323
|
+
return _evaluate_predicate_core(feature_dir, gate_id, plan, feature_id)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _evaluate_predicate_core(
|
|
327
|
+
feature_dir: Path, gate_id: int, plan: dict, feature_id: str,
|
|
328
|
+
) -> AutoCloseDecision:
|
|
329
|
+
"""The v1 predicate itself, shared by `evaluate_auto_close` and
|
|
330
|
+
`evaluate_off_plan_signal` — everything after the `auto_close_disabled`
|
|
331
|
+
short-circuit those two apply differently.
|
|
332
|
+
"""
|
|
305
333
|
# Locate target gate in task graph
|
|
306
334
|
gates = plan["gates"]
|
|
307
335
|
target_gate = next((g for g in gates if g.get("gate") == gate_id), None)
|
|
@@ -167,6 +167,25 @@ def strip_forbidden_sections(text: str) -> str:
|
|
|
167
167
|
return result
|
|
168
168
|
|
|
169
169
|
|
|
170
|
+
# The driver, not the close, owns terminal-flip state: `fire_terminal_flips`
|
|
171
|
+
# writes PLAN.md's status, the roadmap row and the gate's own status AFTER a
|
|
172
|
+
# judge returns, and only when the verdict is `met`. So at judge time all three
|
|
173
|
+
# necessarily read un-flipped, on every close of every feature.
|
|
174
|
+
# `GATE.template.md` nevertheless copies a criterion about them into every
|
|
175
|
+
# gate's definition of done, and a judge that reads it literally lowers the
|
|
176
|
+
# verdict -- which guarantees the state stays as found, so a re-close runs a
|
|
177
|
+
# fresh judge against identical evidence and reaches the identical verdict.
|
|
178
|
+
# FEAT-2026-0104 deadlocked there for one close (#3307). Strip the criterion
|
|
179
|
+
# here; `render_judge_prompt` says why, because stripping alone only stops the
|
|
180
|
+
# reminder -- the judge can still go and read the roadmap itself.
|
|
181
|
+
_DRIVER_OWNED_STATUS_CRITERION = re.compile(
|
|
182
|
+
r"^[ \t]*[-*][ \t]+Documentation and roadmap status[^\n]*\n?", re.M)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _strip_driver_owned_status_criterion(text: str) -> str:
|
|
186
|
+
return _DRIVER_OWNED_STATUS_CRITERION.sub("", text or "")
|
|
187
|
+
|
|
188
|
+
|
|
170
189
|
def _clean_evidence(text: str) -> str:
|
|
171
190
|
return truncate_evidence(strip_forbidden_sections(text or ""))
|
|
172
191
|
|
|
@@ -224,7 +243,8 @@ def build_judge_bundle(
|
|
|
224
243
|
|
|
225
244
|
return JudgeBundle(
|
|
226
245
|
gate_number=gate_number,
|
|
227
|
-
definition_of_done=_clean_evidence(
|
|
246
|
+
definition_of_done=_clean_evidence(
|
|
247
|
+
_strip_driver_owned_status_criterion(definition_of_done)),
|
|
228
248
|
criteria=criteria,
|
|
229
249
|
diff_text=_clean_evidence(diff_text),
|
|
230
250
|
measurements=_clean_evidence(measurements_text),
|
|
@@ -272,6 +292,12 @@ did not do this work and have no stake in the answer.
|
|
|
272
292
|
one. The measurements it recorded are already below.
|
|
273
293
|
5. Change nothing. You run no git command, edit no file, and fix nothing you
|
|
274
294
|
find. You report.
|
|
295
|
+
6. `PLAN.md`'s status, the roadmap row, and this gate's own status are not
|
|
296
|
+
evidence and are not yours to grade. The driver writes all three after you
|
|
297
|
+
return, and only if you answer `met` — so while you are looking at them they
|
|
298
|
+
necessarily read un-flipped, on every close of every feature. Reading one of
|
|
299
|
+
them as a failure is a verdict that manufactures its own evidence: it keeps
|
|
300
|
+
them un-flipped, and the next judge sees exactly what you saw.
|
|
275
301
|
|
|
276
302
|
## Definition of done (gate {bundle.gate_number})
|
|
277
303
|
|