specfuse-loop 0.24.0__tar.gz → 0.25.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.24.0/specfuse_loop.egg-info → specfuse_loop-0.25.0}/PKG-INFO +1 -1
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/pyproject.toml +1 -1
- specfuse_loop-0.25.0/specfuse/loop/data/VERSION +1 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/methodology.md +29 -1
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/verification.yml.example +13 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/lint_plan.py +1 -1
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/loop.py +124 -8
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0/specfuse_loop.egg-info}/PKG-INFO +1 -1
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/SOURCES.txt +3 -0
- specfuse_loop-0.25.0/tests/test_closing_sessions_on_sonnet.py +28 -0
- specfuse_loop-0.25.0/tests/test_dispatch_preamble_rules_pointer.py +32 -0
- specfuse_loop-0.25.0/tests/test_dispatch_skills_index.py +105 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_followups_artifact.py +26 -2
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_gate_proportionality.py +19 -4
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_auto_archive.py +29 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_close_intermediate.py +2 -2
- specfuse_loop-0.24.0/specfuse/loop/data/VERSION +0 -1
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/LICENSE +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/NOTICE +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/README.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/setup.cfg +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/__init__.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/budget.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/diagnose_invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/drafting_answers.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/drafting_invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/drafting_questions.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/driver_command.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/driver_invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/monitoring_read.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/__init__.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/answers.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/bugs.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/feature.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/findings_autofix.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/findings_diagnose.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/providers/triage.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/queue_read.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/repo_detect.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/severity_backfill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/triage_invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/agent/worktree.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/__init__.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/_filelock.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/_miniyaml.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/_wu_sections.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/adopt_feature.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/agent_policy.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/arm_eval.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/arm_sweep.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/arm_txn.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/bug_lane.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/bug_lane_run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/bug_lane_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/build_provenance.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/caller_check.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/changelog.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/closing_requirements.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/cost.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/criteria_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/LEARNINGS.template.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/getting-started.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/glossary.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/docs/skills.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/gitignore.snippet +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/monitoring.yml.example +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/roadmap.template.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/close-discipline.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/correlation-ids.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/human-output.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/never-touch.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/operator-escalation.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/planning-discipline.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/result-contract.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/security-boundaries.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules/verification-discipline.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/rules-local/README.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/driver-event.schema.json +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/event.schema.json +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/GATE.template.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/PLAN.template.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/templates/WU.template.md +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/decisions_format.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/driver_edit.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/escalation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/events_stats.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/gate_commands.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/gate_eval.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/gh_backend.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/gh_features.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/heartbeat.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/judge.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/labels.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/learnings_distil.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/learnings_query.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/lint_closing.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/lint_monitoring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/lint_roadmap.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/notify.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/notify_escalation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/notify_sla.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/plan_baseline.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/policy_proposals.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/policy_review.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/prerun.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/prerun_capture.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/promotion.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/rearm_migration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/red_on_base.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/replay_spin.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/roadmap_archive.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/scaffold.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/triage.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/loop/validate_event.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/__init__.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/adapters.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/artifact.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/autofix.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/autofix_invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/autofix_run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/autofix_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/cli.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/diagnose_cli.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/diagnosis.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/fingerprint.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/issues.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/providers/__init__.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/providers/_azure_auth.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/providers/azure_app_insights.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/providers/azure_service_bus.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/redaction.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse/monitor/schedule.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/dependency_links.txt +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/entry_points.txt +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/requires.txt +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/specfuse_loop.egg-info/top_level.txt +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_abandon_feature_skill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_abandoned_work_reported.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_abandoned_wu_strands_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_adopt_feature.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_budget.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_bug_selection_dedup.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_default_features_root.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_driver_command.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_driver_invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_driver_restart.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_escalation_on_issue.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_escalation_run_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_findings_seam.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_invoke_timeout.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_invoke_usage.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_item_worktree.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_lock.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_policy_key_ownership.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_policy_queue.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_policy_schema.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_policy_triage_dial.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_answers.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_bugs.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_feature.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_findings_autofix.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_findings_diagnose.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_isolation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_provider_triage.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_queue_read.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_relays_driver_output.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_repo_detect.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_run_progress.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_seam.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_snapshot_refresh.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_agent_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_answer_escalation_skill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_app_insights_adapters.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_archive_ref_reconciliation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_eval.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_eval_lint_class.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_eval_wiring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_gate_edits_uncommitted.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_sweep.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_sweep_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_txn.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_arm_wiring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_artifact_redaction.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attempt_note_untracked_files.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attempt_outcome_contract.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attempt_outcome_emission.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attention_nonwriting_guard.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attention_silence_section.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attention_skill_structure.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_attribution_halt_claims.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autoclose_deferral_visibility.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autoclose_gate_note.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autoclose_stub_states_what_passed.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_live.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_predicate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autofix_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync_consent.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync_firstrun.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync_no_cwd_leak.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_autosync_plugin.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_azure_credential_resolution.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_backend.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_escalation_message.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_persistence.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_probe.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_provenance.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_baseline_tree_hash_key.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bash_routing.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bats_suites_gated.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_binary_verdict.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_binding_block_advisory.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_binding_block_allocation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_binding_block_budget.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_blind_run_is_not_drained.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bookkeeping_commit_crash_run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bookkeeping_no_verify.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_brief_covers_every_unit_escalation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_ci_pending.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_guardrails.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_label_nonfatal.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_labels_registered.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_min_severity.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_policy_contract.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_pr_number_carried.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_preflight_and_dial.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_bug_lane_test_paths.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_build_provenance.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_caller_check_ratchet.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changed_file_test_selection.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changelog_append_only.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changelog_collection.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changelog_release_wiring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_changelog_schema.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ci_conclusion_wait.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ci_runs_every_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_claude_resolution.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_close_b_pending_learnings.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_close_records_feature_oracle.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_close_wu_self_reference.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_deliverable_guard.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_guard_contracts.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_guard_prediction.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_learnings_destination.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_closing_requirements.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_coauthor_trailer_allowlist.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_conditional_reflection.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_console_encoding.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_convergent_iteration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_convergent_wu_lint.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_correlation_id_override.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_correlation_id_two_surfaces.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_cost_lifetime.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_cost_tracking.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_criteria_per_gate_lint.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_criteria_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_criteria_worklist.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_decision_citation_lint.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_decision_followups_discharged.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_decision_override_lint.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_decisions_format.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_default_severity_aliases.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_degraded_oracle.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_deliverable_missing_note.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_deliverable_presence_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_derive_agent_policy_review_mode.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_derive_agent_policy_skill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_derive_monitoring_discovery.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_derive_monitoring_skill_registration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_design_for_diagnosis_rule.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_deterministic_refusal_repeat.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_diagnose_headless.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_diagnose_issue_skill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_diagnosis.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_diagnosis_roundtrip_live.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_dispatch_model_from_fix_scope.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_dispatch_skeleton.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_distilled_accept_step.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_doctor.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_doctor_command_preflight.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_done_feature_gates.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_draft_feature_answers_mode.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_answer_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_invoke.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_question_issue.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_questions.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_drafting_reply_shape.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_edit_detection.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_event_registry_covers_emitters.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_integration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_lock.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_module_surface.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_restart_halt_surfaced.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_restart_halt_wiring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_restart_hold.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_staleness_gate_summary.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_driver_staleness_warning.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_dry_run_no_branch_mutation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_duration_tracking.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_empty_files_escalation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ensure_feature_branch.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ensure_feature_branch_base.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_assignee_policy.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_contract.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_crash_containment.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_dedup_search.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_escalation_emit.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_event_gate_full_envelope.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_events_redaction.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_events_stats.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_extra_gates.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_failure_artifact_model.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_failure_signature_fail_prefix.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_failure_signature_skips_log_noise.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_branch_auto_sync.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_branch_squash_merge.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_branch_stale_base.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_id_resolution.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_oracle_e2e.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_provider_drafting_dispatch.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_feature_review_accumulation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_filelock_portable.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_files_changed_auto_repair.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_find_pr_no_search_index.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fingerprint.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fix_bug_diff_self_check.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fix_bug_headless.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fix_bug_reads_comments.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_fold_contract_documented.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_force_full_close.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_frontmatter_scalar_quoting.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_broad_run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_budget.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_budget_post_dispatch.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_commands_needs.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval_calibration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval_intermediate_wiring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval_repo_flag.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_eval_terminal_wiring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gate_report_verdict.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gh_backend.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gh_features.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_git_env_isolation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_gitleaks_pinning.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_groom_backlog_skill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_guard_refusal_failure_class.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_guard_refusal_failure_excerpt.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_guard_repair_e2e.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_guard_repair_prompt.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_hashed_denylist.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_hashed_denylist_ci.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_heartbeat.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_heartbeat_adapter.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_human_output_rule.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_human_work_unit.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_hygiene_boundary_guidance.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_hyphenated_gate_name.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ignored_cleanup_before_probe.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_init_integration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_installed_copy_driver_e2e.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_interpreter_normalization.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_close_path.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_cost.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_cost_fold_committed.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_module.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_path_registry.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judge_terminal_flip_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_judged_event_points_at_findings.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_label_description_length.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_label_provisioning_runner_contract.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_label_registry.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_label_registry_covers_consumers.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_language_aware_narrow_selection.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lazy_baseline_e2e.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_leak_findings_redaction.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_leak_scan.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_leak_scan_content.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_curate_vendored_promote.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_distil_cli.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_query.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_staging.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_suggest_signature_filter.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_learnings_weights.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_legacy_4wu_terminal_flips.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lifecycle_integration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lifetime_accounting.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_ac_observable.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_bare_produces_path.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_boundary_consistency.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_boundary_extraction.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_close_intermediate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_close_verdict_not_predecided.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_close_wu.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_closing.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_closing_criteria.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_closing_criteria_pristine.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_correlation_id.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_covers_load_wu_invariants.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_feature_oracle_declared.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_monitoring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_oracle_env.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_contract_fields.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_errors.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_next_draft.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_relative_import.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_plan_verdict_exempt.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_planning_sections.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_produces_driver_helper.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_produces_satisfiability.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_roadmap.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_sections.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_task_graph_yaml_selection.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_lint_verification_reference.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_live_tests_opt_in.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_load_bearing_close_lint.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_attempt_evidence.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_caveman_preamble.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_criteria_skeleton.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_criteria_survival.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_defaults_by_type.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_effort.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_failure_note_cap.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_files_changed_guard.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_gate_budget.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_gate_needs.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_model_alias.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_orchestration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_post_pass_invariant.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_reset_preserving_events.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_smoke_runner.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_unsandboxed.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_worklist_injection.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_loop_zero_token_guard.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_make_repo_gpgsign_isolation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_marker_dual_shape.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_maven_failure_excerpt.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_max_attempts_configurable.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_max_open_prs.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_migrate_legacy.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_miniyaml_equivalence.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_miniyaml_negative.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitor_cli.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitor_issue_lifecycle.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitor_runner_surfaces.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_cron_dialect.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_example.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_fenced_blocks.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_monitoring_seed.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_narrow_fallback_warning.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_needs_decision_outcome.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_no_pytest_subprocess.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_notify.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_notify_escalation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_notify_sla.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_operator_escalation_rule.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_oracle_set_declared.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_oracle_unrunnable_attribution.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_per_run_item_cap_disclosure.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pick_feature_skill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pin_honesty_and_integrity.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pin_marker_not_inherited.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pin_marker_spawn_sites.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_plan_baseline.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_planned_cost_lint.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_planning_cost_floor.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_plugin_prose_cross_refs.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_plugin_qualified_dispatch.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_policy_budgets_applied.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_policy_proposals.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_policy_review.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pr_checks_json_field.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pr_reference_in_title.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prep_halt_operator_surface.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prepare_feature.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prepare_scaffold_sync.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prerun_capture.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prerun_oracles.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_prerun_wiring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produced_document_verdict_guard.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_bracket_literal.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_bracket_wildcard.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_field.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_in_diff.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_justification.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_recursive_glob.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_semantics_unified.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_produces_shape.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_progress_forward_note.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_progress_lines_end_to_end.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_promotion_ledger.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_provider_escalation_traces.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_provision_labels.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_queue_stalled_adapter.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_rearm_clears_stale_criteria_state.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_rearm_fold_marker.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_rearm_migration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_red_baseline_never_reused.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_red_on_base_guardrail.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_red_on_base_probe.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_redaction_windows_home.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_reflection_required_signals.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_end_to_end.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_event_emission.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_note_collision.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_trigger.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replan_turn_contract.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_replay_spin.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_required_checks.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_resolve_base.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_restart_cap_counts_progress.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_result_block.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_result_block_audience.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_resume_command_build.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_retain_on_guard_refusal_docs.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_add_skill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_archive_cli.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_archive_shim.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_archive_skill.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_archive_skill_delegates.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_link_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_roadmap_row_parser.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_ruff_verdict_lines.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_rule_import_convergence.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_run_level_failure_breaker.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_data_in_sync.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_doc_hygiene.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_docs.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_init.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_label_provisioning.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_manifest.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_resources.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_seed_sanity.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_skew_halts.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_upgrade.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_scaffold_wiring.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_schedule_dialect.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_seed_documents_prerun_keys.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_service_bus_dlq_adapter.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_session_env_preflight.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_aliases.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_apply.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_end_to_end.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_limit.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_marker.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_backfill_run.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_label_projection.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_reconciliation.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_severity_rubric.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_shipped_templates_parse.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_skill_discovery_links.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_skills_vendored_in_sync.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_spec_work_unit_rules.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_spinning_rearm_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_spinout_brief_end_to_end.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_spinout_brief_replan_option.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_squash_commit_hook_crash.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_stop_rationale_captured.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_stranded_halt_cause.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_surefire_run_level_signature.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_surefire_verdict_lines.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_template_closing_shapes.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_terminal_flip_ownership.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_terminal_flips.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_terminal_gate_message.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_tiered_verification_e2e.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_timeout_kill_portable.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_apply.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_projects_severity_label.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_severity_classify.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_severity_end_to_end.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_severity_write.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_skill_contract.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_triage_skips_agent_escalations.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_tsc_verdict_lines.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_umbrella_version_resolution.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_unterminated_frontmatter.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_untracked_feature_folder.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_untracked_file_absorption.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_upgrade_integration.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_validate_event.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_validate_event_driver_types.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_verdict_coupling.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_verify_empty_gate_set.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_version_consistency.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_version_skew.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_windows_gate_exec.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_worktree_restore.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.0}/tests/test_wu_execution_metadata.py +0 -0
- {specfuse_loop-0.24.0 → specfuse_loop-0.25.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.25.0"
|
|
8
8
|
description = "Local-first executor for the Specfuse Plan + Work Unit gate-cycle methodology."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.25.0
|
|
@@ -454,6 +454,27 @@ separately carry `auto_repaired_files_changed` in `extras`: the list of
|
|
|
454
454
|
declared-but-unchanged `files_changed` paths the driver dropped on the
|
|
455
455
|
WU's behalf rather than failing the attempt over.
|
|
456
456
|
|
|
457
|
+
**Dispatch without the skills index (#3423).** A dispatched session runs
|
|
458
|
+
`claude -p --disable-slash-commands` by default: a work unit invokes no
|
|
459
|
+
skill, and the project's skills index (34 skills, 1,534 words of descriptions
|
|
460
|
+
in the loop repository) is fixed context carried in every turn's cache read.
|
|
461
|
+
`defaults.dispatch_skills: true` in `verification.yml` restores the index for
|
|
462
|
+
a project whose units do call `/skill-name` in-session.
|
|
463
|
+
|
|
464
|
+
**The post-merge checklist travels with the archive (#3424).** A `met`
|
|
465
|
+
terminal close no longer files PLAN.md's `## Post-merge checklist` as a
|
|
466
|
+
`specfuse:post-merge` issue (ten filed across two repositories, eight never
|
|
467
|
+
actioned); `auto_archive_feature` appends it under the feature's archived
|
|
468
|
+
detail section in `roadmap-archive.md`. `defaults.post_merge_issue: true` in
|
|
469
|
+
`verification.yml` restores the issue.
|
|
470
|
+
|
|
471
|
+
**Closing sessions run on sonnet (#3425).** `close`, `close-intermediate`
|
|
472
|
+
and `plan-next` default to `sonnet` at effort `high`, the same model as the
|
|
473
|
+
judge that checks them (lower-only, about $0.46 per close). Opus was 56% of
|
|
474
|
+
all spend while implementation ran on sonnet. A unit's own
|
|
475
|
+
`model:` still overrides the default, and every `judged` event carries
|
|
476
|
+
`close_model` so judge agreement can be read per close model.
|
|
477
|
+
|
|
457
478
|
Retention interacts with spinning detection, not around it:
|
|
458
479
|
`detect_deterministic_refusal_repeat` (#1415) escalates a WU to
|
|
459
480
|
`blocked_human` when two consecutive attempts emit an identical refusal
|
|
@@ -579,7 +600,7 @@ completion.
|
|
|
579
600
|
|
|
580
601
|
Closing ceremony cost should scale with feature size. A feature whose
|
|
581
602
|
**planned substantive** WU count (types `implementation`, `qa_authoring`,
|
|
582
|
-
`qa_execution`, `qa_curation`) is **≤
|
|
603
|
+
`qa_execution`, `qa_curation`) is **≤ 12** drafts as a **single gate** with
|
|
583
604
|
a **single terminal `close` WU** — no `close-intermediate`, no `plan-next`.
|
|
584
605
|
This is the proportional shape: small features do not pay multi-WU closing
|
|
585
606
|
overhead sized for large ones.
|
|
@@ -597,6 +618,13 @@ reflective session. Ceremony proportionality trades reflection only on
|
|
|
597
618
|
features that stay small **and** on-plan. The `gate_eval.py` predicate is
|
|
598
619
|
the safety net; this rule does not replace it.
|
|
599
620
|
|
|
621
|
+
The line moved from 8 to 12 on 2026-09-26 (#3426): post-review features
|
|
622
|
+
average 10.7 substantive units, every extra gate costs a `plan-next` plus a
|
|
623
|
+
`close-intermediate` and an `awaiting_review` wait, and the arm predicate
|
|
624
|
+
would have armed only 18 of 74 gate boundaries it evaluated — the wait was a
|
|
625
|
+
human redraft, not a review. A feature goes multi-gate when a human decision
|
|
626
|
+
sits between its gates, not because it is large.
|
|
627
|
+
|
|
600
628
|
**Reflective prose is conditional too (FEAT-2026-0106).** The roadmap once
|
|
601
629
|
asked for a retrospective "only on `not_met` or on request" — superseded,
|
|
602
630
|
for an ordering reason: the close writes `RETROSPECTIVE.md` before the judge
|
|
@@ -118,9 +118,22 @@
|
|
|
118
118
|
# # attempt repairs the retained tree in place
|
|
119
119
|
# # instead of re-authoring from scratch. Set to
|
|
120
120
|
# # false to restore the pre-0.18 discard behaviour.
|
|
121
|
+
# dispatch_skills: false # whether a dispatched session loads the
|
|
122
|
+
# # project's skills index. Defaults to false:
|
|
123
|
+
# # a work unit invokes no skill, and the index
|
|
124
|
+
# # is fixed context paid on every turn (#3423).
|
|
125
|
+
# # Set true for a project whose units call
|
|
126
|
+
# # `/skill-name` in-session.
|
|
127
|
+
# post_merge_issue: false # whether a `met` terminal close files PLAN.md's
|
|
128
|
+
# # `## Post-merge checklist` as a tracked issue.
|
|
129
|
+
# # Defaults to false (#3424): the checklist is
|
|
130
|
+
# # appended under the feature's archived detail
|
|
131
|
+
# # section in roadmap-archive.md instead.
|
|
121
132
|
# defaults:
|
|
122
133
|
# max_attempts: 3
|
|
123
134
|
# retain_on_guard_refusal: true
|
|
135
|
+
# dispatch_skills: false
|
|
136
|
+
# post_merge_issue: false
|
|
124
137
|
#
|
|
125
138
|
# The re-plan-after-two-failures behaviour (FEAT-2026-0104) reads this same
|
|
126
139
|
# `max_attempts` resolution and adds no config key of its own — a unit's
|
|
@@ -1041,7 +1041,7 @@ def check_produces_satisfiability(feature_dir: Path, gates: list) -> None:
|
|
|
1041
1041
|
|
|
1042
1042
|
# Ceremony-proportionality threshold (docs/methodology.md §6): one fact, one
|
|
1043
1043
|
# home. Referenced, not redefined, in the draft-feature skill.
|
|
1044
|
-
GATE_PROPORTIONALITY_THRESHOLD = 8
|
|
1044
|
+
GATE_PROPORTIONALITY_THRESHOLD = 12 # was 8 until #3426
|
|
1045
1045
|
GATE_PROPORTIONALITY_SUBSTANTIVE_TYPES = frozenset(
|
|
1046
1046
|
{"implementation", "qa_authoring", "qa_execution", "qa_curation"}
|
|
1047
1047
|
)
|
|
@@ -42,6 +42,7 @@ from __future__ import annotations
|
|
|
42
42
|
import argparse
|
|
43
43
|
import datetime as dt
|
|
44
44
|
import fnmatch
|
|
45
|
+
import functools
|
|
45
46
|
import glob
|
|
46
47
|
import hashlib
|
|
47
48
|
import inspect
|
|
@@ -125,7 +126,7 @@ SPECFUSE_DIR = Path(".specfuse")
|
|
|
125
126
|
REPO_ROOT = SPECFUSE_DIR.parent
|
|
126
127
|
FEATURES_DIR = SPECFUSE_DIR / "features"
|
|
127
128
|
VERIFICATION_PATH = SPECFUSE_DIR / "verification.yml"
|
|
128
|
-
DRIVER_VERSION = "0.
|
|
129
|
+
DRIVER_VERSION = "0.25.0"
|
|
129
130
|
# Oldest scaffold layout this driver can drive. init.sh stamps the scaffold's own
|
|
130
131
|
# version into `.specfuse/VERSION`; check_scaffold_version() fails loud at startup if
|
|
131
132
|
# the consumer's scaffold is older than this, pointing at `specfuse upgrade`. Bump
|
|
@@ -635,6 +636,66 @@ def resolve_retain_on_guard_refusal(verification_cfg: dict) -> bool:
|
|
|
635
636
|
"""
|
|
636
637
|
project = (verification_cfg or {}).get("defaults") or {}
|
|
637
638
|
return bool(project.get("retain_on_guard_refusal", True))
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
def resolve_dispatch_skills(verification_cfg: dict) -> bool:
|
|
642
|
+
"""Whether a dispatched session gets the project's skills index (#3423).
|
|
643
|
+
|
|
644
|
+
Reads `defaults.dispatch_skills` from verification.yml — the same
|
|
645
|
+
`defaults` block `resolve_max_attempts` reads. Defaults to False: a
|
|
646
|
+
dispatched work unit invokes no skill (the narrow-tier instructions are in
|
|
647
|
+
the preamble and unit bodies name skill files by path, for reading), so
|
|
648
|
+
the index — 34 skills and 1,534 words of descriptions in this repository —
|
|
649
|
+
is fixed context carried in every turn's cache read for nothing. Set true
|
|
650
|
+
for a project whose units do invoke `/skill-name` in-session.
|
|
651
|
+
"""
|
|
652
|
+
project = (verification_cfg or {}).get("defaults") or {}
|
|
653
|
+
return bool(project.get("dispatch_skills", False))
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
@functools.lru_cache(maxsize=None)
|
|
657
|
+
def claude_supports_flag(flag: str) -> bool:
|
|
658
|
+
"""Whether the installed Claude Code CLI accepts *flag* (#3432).
|
|
659
|
+
|
|
660
|
+
Probed once per driver run from `claude --help`. A CLI that cannot be run
|
|
661
|
+
reads as not supporting anything: the dispatch then omits the flag and
|
|
662
|
+
fails on its own terms, not on an unknown option.
|
|
663
|
+
"""
|
|
664
|
+
try:
|
|
665
|
+
proc = subprocess.run(
|
|
666
|
+
resolve_claude_cmd(["claude", "--help"]), capture_output=True,
|
|
667
|
+
text=True, check=False, timeout=30,
|
|
668
|
+
env=child_env_without_pin_marker(),
|
|
669
|
+
)
|
|
670
|
+
except Exception: # noqa: BLE001 - a missing or broken CLI is "no"
|
|
671
|
+
return False
|
|
672
|
+
out = "".join(s for s in (proc.stdout, proc.stderr) if isinstance(s, str))
|
|
673
|
+
return flag in out
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
_FLAG_WARNED: set[str] = set()
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
def _warn_flag_unsupported(flag: str, consequence: str) -> None:
|
|
680
|
+
if flag in _FLAG_WARNED:
|
|
681
|
+
return
|
|
682
|
+
_FLAG_WARNED.add(flag)
|
|
683
|
+
print(f" WARN: this Claude Code CLI does not accept {flag}; {consequence}")
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
def resolve_post_merge_issue(verification_cfg: dict) -> bool:
|
|
687
|
+
"""Whether a `met` terminal close files the post-merge checklist as an issue (#3424).
|
|
688
|
+
|
|
689
|
+
Reads `defaults.post_merge_issue` from verification.yml. Defaults to False:
|
|
690
|
+
across this repository and its heaviest consumer, ten such issues were
|
|
691
|
+
filed and eight were never actioned — the checklist is a measurement note
|
|
692
|
+
for the operator, not a work item. The record survives instead under the
|
|
693
|
+
feature's archived detail section (`auto_archive_feature`).
|
|
694
|
+
"""
|
|
695
|
+
project = (verification_cfg or {}).get("defaults") or {}
|
|
696
|
+
return bool(project.get("post_merge_issue", False))
|
|
697
|
+
|
|
698
|
+
|
|
638
699
|
# Per-gate-command wall-clock ceiling. A gate that exceeds it is killed and the gate
|
|
639
700
|
# FAILS (not hangs) — so a deadlocked command (e.g. a test blocked on input()) can't
|
|
640
701
|
# stall the whole driver indefinitely. Generous vs real suites (this repo's is ~20s).
|
|
@@ -657,9 +718,16 @@ MODEL_BY_TYPE = {
|
|
|
657
718
|
"retrospective": "sonnet",
|
|
658
719
|
"lessons": "sonnet",
|
|
659
720
|
"docs": "sonnet",
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
721
|
+
# #3425: closing sessions on sonnet. Opus was 56% of all spend while
|
|
722
|
+
# implementation ran on sonnet; the judge (JUDGE_MODEL, itself sonnet,
|
|
723
|
+
# lower-only, ~$0.46 per close) is the independent check on a close's
|
|
724
|
+
# measurements and lowered 9 of 54 verdicts correctly, so the close does
|
|
725
|
+
# not need a bigger model than the session that checks it. A unit's own
|
|
726
|
+
# `model:` still overrides; `judged` events carry `close_model` so
|
|
727
|
+
# agreement can be split by model.
|
|
728
|
+
"plan-next": "sonnet",
|
|
729
|
+
"close": "sonnet",
|
|
730
|
+
"close-intermediate": "sonnet",
|
|
663
731
|
}
|
|
664
732
|
EFFORT_BY_TYPE = {
|
|
665
733
|
"implementation": "medium",
|
|
@@ -4439,8 +4507,9 @@ def squash_commit(
|
|
|
4439
4507
|
# --------------------------------------------------------------------------- #
|
|
4440
4508
|
|
|
4441
4509
|
PROMPT_PREAMBLE = """\
|
|
4442
|
-
You are executing a single Specfuse work unit.
|
|
4443
|
-
|
|
4510
|
+
You are executing a single Specfuse work unit. The binding rules are already in \
|
|
4511
|
+
your context through .claude/CLAUDE.md; read a further file under .specfuse/rules/ \
|
|
4512
|
+
only when your unit body names it. Do NOT run any git command — the driver owns all commits \
|
|
4444
4513
|
and bookkeeping. Edit files only. Verification is tiered: before you report, run \
|
|
4445
4514
|
only the per-attempt (narrow) tier yourself — your unit type's gate set in \
|
|
4446
4515
|
.specfuse/verification.yml minus every gate declaring `tier: broad`, with the \
|
|
@@ -4790,7 +4859,8 @@ def format_reverification_worklist(wu: WorkUnit, feature_dir: Path) -> str:
|
|
|
4790
4859
|
|
|
4791
4860
|
|
|
4792
4861
|
def dispatch(wu: WorkUnit, failure_note: str | None,
|
|
4793
|
-
cost_tracking: bool = True
|
|
4862
|
+
cost_tracking: bool = True, *,
|
|
4863
|
+
dispatch_skills: bool | None = None) -> tuple[str, dict | None]:
|
|
4794
4864
|
"""Run a fresh agent session for this WU.
|
|
4795
4865
|
|
|
4796
4866
|
When `cost_tracking` is True (default), requests JSON output from
|
|
@@ -4810,6 +4880,24 @@ def dispatch(wu: WorkUnit, failure_note: str | None,
|
|
|
4810
4880
|
cmd = [p.replace("{model}", wu.model).replace("{effort}", wu.effort)
|
|
4811
4881
|
for p in CLAUDE_CMD]
|
|
4812
4882
|
cmd = resolve_claude_cmd(cmd)
|
|
4883
|
+
if dispatch_skills is None:
|
|
4884
|
+
# Resolved here rather than threaded through execute_unit_attempt:
|
|
4885
|
+
# every test fake of dispatch() takes the three positional arguments
|
|
4886
|
+
# and nothing else, and the yaml read is nothing next to a session.
|
|
4887
|
+
try:
|
|
4888
|
+
dispatch_skills = resolve_dispatch_skills(load_verification())
|
|
4889
|
+
except Exception: # noqa: BLE001 - an unreadable config keeps the default
|
|
4890
|
+
dispatch_skills = False
|
|
4891
|
+
if not dispatch_skills:
|
|
4892
|
+
# #3423: a dispatched unit invokes no skill, so the skills index is
|
|
4893
|
+
# fixed context paid on every turn. `defaults.dispatch_skills: true`
|
|
4894
|
+
# in verification.yml restores it (resolve_dispatch_skills).
|
|
4895
|
+
if claude_supports_flag("--disable-slash-commands"):
|
|
4896
|
+
cmd.insert(2, "--disable-slash-commands")
|
|
4897
|
+
else:
|
|
4898
|
+
_warn_flag_unsupported(
|
|
4899
|
+
"--disable-slash-commands",
|
|
4900
|
+
"the skills index stays in the session prompt (#3432)")
|
|
4813
4901
|
if wu.unsandboxed:
|
|
4814
4902
|
# Per-WU sandbox-escape. Audited via the unsandboxed_dispatch event
|
|
4815
4903
|
# emitted in run()'s attempt loop; rationale lives in WU frontmatter.
|
|
@@ -7368,6 +7456,19 @@ def _reconcile_moved_section(
|
|
|
7368
7456
|
return section_text
|
|
7369
7457
|
|
|
7370
7458
|
|
|
7459
|
+
def _post_merge_checklist_for_archive(feature_id: str, repo_root: Path) -> str | None:
|
|
7460
|
+
"""PLAN.md's `## Post-merge checklist` body for *feature_id*, or None (#3424)."""
|
|
7461
|
+
features = repo_root / ".specfuse" / "features"
|
|
7462
|
+
for plan in sorted(features.glob(f"{feature_id}-*/PLAN.md")):
|
|
7463
|
+
try:
|
|
7464
|
+
_, body = read_frontmatter(plan)
|
|
7465
|
+
except Exception: # noqa: BLE001 - archive must never fail on a bad PLAN
|
|
7466
|
+
return None
|
|
7467
|
+
section = find_post_merge_checklist_section(body)
|
|
7468
|
+
return section.strip("\n") + "\n" if section else None
|
|
7469
|
+
return None
|
|
7470
|
+
|
|
7471
|
+
|
|
7371
7472
|
def auto_archive_feature(feature_id: str, repo_root: Path) -> str:
|
|
7372
7473
|
"""Re-implement roadmap-archive single-feature algorithm (Steps 1–6) in-driver.
|
|
7373
7474
|
|
|
@@ -7480,6 +7581,13 @@ def auto_archive_feature(feature_id: str, repo_root: Path) -> str:
|
|
|
7480
7581
|
f"](roadmap.md#{feat_id_lower})", f"](#{feat_id_lower})"
|
|
7481
7582
|
)
|
|
7482
7583
|
|
|
7584
|
+
# #3424: the feature's post-merge checklist travels with the archived
|
|
7585
|
+
# detail section instead of becoming an issue nobody actions. Read from
|
|
7586
|
+
# the feature folder's PLAN.md when one exists; a row-only feature has none.
|
|
7587
|
+
checklist = _post_merge_checklist_for_archive(feature_id, repo_root)
|
|
7588
|
+
if checklist and "**Post-merge checklist.**" not in section_text:
|
|
7589
|
+
section_text = section_text.rstrip("\n") + "\n\n**Post-merge checklist.**\n\n" + checklist
|
|
7590
|
+
|
|
7483
7591
|
marker_end = archive_text.index(marker) + len(marker)
|
|
7484
7592
|
new_archive = archive_text[:marker_end] + f"\n{anchor}\n{section_text}" + archive_text[marker_end:]
|
|
7485
7593
|
archive_path.write_text(new_archive)
|
|
@@ -8833,6 +8941,7 @@ def record_tracked_issue(
|
|
|
8833
8941
|
|
|
8834
8942
|
def file_followup_issues(
|
|
8835
8943
|
feature_dir: Path, repo_root: Path, runner=None, *, commit: bool | None = None,
|
|
8944
|
+
post_merge_issue: bool | None = None,
|
|
8836
8945
|
) -> dict:
|
|
8837
8946
|
"""File one tracked GitHub issue per FOLLOW-UPS.md entry, after a close's squash.
|
|
8838
8947
|
|
|
@@ -8883,7 +8992,13 @@ def file_followup_issues(
|
|
|
8883
8992
|
followups_path,
|
|
8884
8993
|
))
|
|
8885
8994
|
|
|
8886
|
-
if
|
|
8995
|
+
if post_merge_issue is None:
|
|
8996
|
+
post_merge_issue = resolve_post_merge_issue(load_verification())
|
|
8997
|
+
if post_merge_issue and (
|
|
8998
|
+
plan_fm.get("verdict") == "met" or plan_fm.get("status") == "done"
|
|
8999
|
+
):
|
|
9000
|
+
# #3424: off by default — the checklist lands under the archived
|
|
9001
|
+
# detail section instead (auto_archive_feature).
|
|
8887
9002
|
section = find_post_merge_checklist_section(plan_body)
|
|
8888
9003
|
if section:
|
|
8889
9004
|
entries.append((
|
|
@@ -9588,6 +9703,7 @@ def judge_close(
|
|
|
9588
9703
|
payload: dict = {
|
|
9589
9704
|
"gate": gate_number,
|
|
9590
9705
|
"close_verdict": close_verdict,
|
|
9706
|
+
"close_model": getattr(wu, "model", None),
|
|
9591
9707
|
"judge_verdict": None,
|
|
9592
9708
|
"verdict": close_verdict,
|
|
9593
9709
|
"lowered": False,
|
|
@@ -259,6 +259,7 @@ tests/test_closing_guard_contracts.py
|
|
|
259
259
|
tests/test_closing_guard_prediction.py
|
|
260
260
|
tests/test_closing_learnings_destination.py
|
|
261
261
|
tests/test_closing_requirements.py
|
|
262
|
+
tests/test_closing_sessions_on_sonnet.py
|
|
262
263
|
tests/test_coauthor_trailer_allowlist.py
|
|
263
264
|
tests/test_conditional_reflection.py
|
|
264
265
|
tests/test_console_encoding.py
|
|
@@ -290,7 +291,9 @@ tests/test_diagnose_issue_skill.py
|
|
|
290
291
|
tests/test_diagnosis.py
|
|
291
292
|
tests/test_diagnosis_roundtrip_live.py
|
|
292
293
|
tests/test_dispatch_model_from_fix_scope.py
|
|
294
|
+
tests/test_dispatch_preamble_rules_pointer.py
|
|
293
295
|
tests/test_dispatch_skeleton.py
|
|
296
|
+
tests/test_dispatch_skills_index.py
|
|
294
297
|
tests/test_distilled_accept_step.py
|
|
295
298
|
tests/test_doctor.py
|
|
296
299
|
tests/test_doctor_command_preflight.py
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Copyright 2026 Specfuse Contributors
|
|
2
|
+
# Licensed under the Apache License, Version 2.0. See LICENSE.
|
|
3
|
+
"""Closing sessions default to sonnet, like the judge that checks them (#3425)."""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from tests._loop_loader import load_loop
|
|
7
|
+
|
|
8
|
+
loop = load_loop()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ClosingTypesDefaultToSonnet(unittest.TestCase):
|
|
12
|
+
def test_the_three_closing_types_default_to_sonnet_high(self):
|
|
13
|
+
for wu_type in ("close", "close-intermediate", "plan-next"):
|
|
14
|
+
self.assertEqual(loop.MODEL_BY_TYPE[wu_type], "sonnet", wu_type)
|
|
15
|
+
self.assertEqual(loop.EFFORT_BY_TYPE[wu_type], "high", wu_type)
|
|
16
|
+
|
|
17
|
+
def test_implementation_default_is_unchanged(self):
|
|
18
|
+
self.assertEqual(loop.MODEL_BY_TYPE["implementation"], "sonnet")
|
|
19
|
+
self.assertEqual(loop.EFFORT_BY_TYPE["implementation"], "medium")
|
|
20
|
+
|
|
21
|
+
def test_the_judge_model_is_its_own_constant(self):
|
|
22
|
+
# The judge already ran on sonnet before this change; the close no
|
|
23
|
+
# longer needs a bigger model than the session that checks it.
|
|
24
|
+
self.assertEqual(loop.JUDGE_MODEL, "sonnet")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
unittest.main()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Copyright 2026 Specfuse Contributors
|
|
2
|
+
# Licensed under the Apache License, Version 2.0. See LICENSE.
|
|
3
|
+
"""The dispatch preamble points at the injected binding block instead of
|
|
4
|
+
telling every session to read `.specfuse/rules/` in full (#3422).
|
|
5
|
+
|
|
6
|
+
Measured 2026-09-26: the "read in full" sentence cost every dispatched session
|
|
7
|
+
ten files and 11,573 words of tool reads on top of the 2,461 words CLAUDE.md
|
|
8
|
+
already injects, and those tokens rode along in every later turn's cache read.
|
|
9
|
+
"""
|
|
10
|
+
import unittest
|
|
11
|
+
|
|
12
|
+
from tests._loop_loader import load_loop
|
|
13
|
+
|
|
14
|
+
loop = load_loop()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PreamblePointsAtTheBindingBlock(unittest.TestCase):
|
|
18
|
+
def test_no_session_is_told_to_read_the_rules_in_full(self):
|
|
19
|
+
self.assertNotIn("in full", loop.PROMPT_PREAMBLE)
|
|
20
|
+
|
|
21
|
+
def test_preamble_names_the_injected_binding_block(self):
|
|
22
|
+
self.assertIn(".claude/CLAUDE.md", loop.PROMPT_PREAMBLE)
|
|
23
|
+
self.assertIn("only when your unit body names it", loop.PROMPT_PREAMBLE)
|
|
24
|
+
|
|
25
|
+
def test_the_other_obligations_survive(self):
|
|
26
|
+
for phrase in ("Do NOT run any git command", "narrow", "RESULT block",
|
|
27
|
+
".specfuse/rules/result-contract.md"):
|
|
28
|
+
self.assertIn(phrase, loop.PROMPT_PREAMBLE)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
unittest.main()
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Copyright 2026 Specfuse Contributors
|
|
2
|
+
# Licensed under the Apache License, Version 2.0. See LICENSE.
|
|
3
|
+
"""A dispatched session does not load the skills index unless the project asks
|
|
4
|
+
for it (#3423).
|
|
5
|
+
|
|
6
|
+
`dispatch()` passes `--disable-slash-commands` by default; the resolver reads
|
|
7
|
+
`defaults.dispatch_skills` from verification.yml and `execute_unit_attempt`
|
|
8
|
+
threads it through.
|
|
9
|
+
"""
|
|
10
|
+
import contextlib
|
|
11
|
+
import io
|
|
12
|
+
import unittest
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from unittest import mock
|
|
15
|
+
|
|
16
|
+
from tests._loop_loader import load_loop
|
|
17
|
+
|
|
18
|
+
loop = load_loop()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _wu(**over):
|
|
22
|
+
base = dict(
|
|
23
|
+
wu_id="FEAT-2026-9999/T01", file=Path("WU-T01.md"), depends_on=[],
|
|
24
|
+
type="implementation", model="claude-sonnet-4-6", effort="medium",
|
|
25
|
+
status="pending", attempts=0, title="t", body="body",
|
|
26
|
+
)
|
|
27
|
+
base.update(over)
|
|
28
|
+
return loop.WorkUnit(**base)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ResolverReadsTheDefaultsBlock(unittest.TestCase):
|
|
32
|
+
def test_absent_means_no_skills(self):
|
|
33
|
+
self.assertFalse(loop.resolve_dispatch_skills({}))
|
|
34
|
+
self.assertFalse(loop.resolve_dispatch_skills({"defaults": {}}))
|
|
35
|
+
|
|
36
|
+
def test_true_restores_the_index(self):
|
|
37
|
+
self.assertTrue(loop.resolve_dispatch_skills({"defaults": {"dispatch_skills": True}}))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class DispatchCmdCarriesTheFlag(unittest.TestCase):
|
|
41
|
+
def _cmd(self, supported: bool = True, **kw):
|
|
42
|
+
fake_proc = mock.MagicMock(stdout="ignored", returncode=0)
|
|
43
|
+
with mock.patch.object(loop, "claude_supports_flag", return_value=supported), \
|
|
44
|
+
mock.patch.object(loop.subprocess, "run", return_value=fake_proc) as run:
|
|
45
|
+
loop.dispatch(_wu(), failure_note=None, cost_tracking=False, **kw)
|
|
46
|
+
return run.call_args[0][0]
|
|
47
|
+
|
|
48
|
+
def test_unsupported_cli_omits_the_flag_and_warns_once(self):
|
|
49
|
+
# #3432: an older CLI must not fail every dispatch on an unknown option.
|
|
50
|
+
loop._FLAG_WARNED.discard("--disable-slash-commands")
|
|
51
|
+
buf = io.StringIO()
|
|
52
|
+
with contextlib.redirect_stdout(buf):
|
|
53
|
+
first = self._cmd(supported=False)
|
|
54
|
+
second = self._cmd(supported=False)
|
|
55
|
+
self.assertNotIn("--disable-slash-commands", first)
|
|
56
|
+
self.assertNotIn("--disable-slash-commands", second)
|
|
57
|
+
self.assertEqual(buf.getvalue().count("does not accept --disable-slash-commands"), 1)
|
|
58
|
+
|
|
59
|
+
def test_default_disables_slash_commands_after_dash_p(self):
|
|
60
|
+
cmd = self._cmd()
|
|
61
|
+
self.assertEqual(cmd[:2], ["claude", "-p"])
|
|
62
|
+
self.assertIn("--disable-slash-commands", cmd)
|
|
63
|
+
self.assertLess(cmd.index("--disable-slash-commands"), cmd.index("--model"))
|
|
64
|
+
|
|
65
|
+
def test_opt_in_keeps_the_index(self):
|
|
66
|
+
self.assertNotIn("--disable-slash-commands", self._cmd(dispatch_skills=True))
|
|
67
|
+
|
|
68
|
+
def test_composes_with_the_sandbox_escape(self):
|
|
69
|
+
fake_proc = mock.MagicMock(stdout="ignored", returncode=0)
|
|
70
|
+
wu = _wu(unsandboxed=True, unsandboxed_rationale="needs gh")
|
|
71
|
+
with mock.patch.object(loop, "claude_supports_flag", return_value=True), \
|
|
72
|
+
mock.patch.object(loop.subprocess, "run", return_value=fake_proc) as run:
|
|
73
|
+
loop.dispatch(wu, failure_note=None, cost_tracking=False)
|
|
74
|
+
cmd = run.call_args[0][0]
|
|
75
|
+
self.assertIn("--dangerously-skip-permissions", cmd)
|
|
76
|
+
self.assertIn("--disable-slash-commands", cmd)
|
|
77
|
+
self.assertEqual(cmd[1], "-p")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
unittest.main()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ProbeReadsTheHelpText(unittest.TestCase):
|
|
85
|
+
def setUp(self):
|
|
86
|
+
loop.claude_supports_flag.cache_clear()
|
|
87
|
+
|
|
88
|
+
def tearDown(self):
|
|
89
|
+
loop.claude_supports_flag.cache_clear()
|
|
90
|
+
|
|
91
|
+
def test_flag_in_help_output_is_supported_and_cached(self):
|
|
92
|
+
fake = mock.MagicMock(stdout="Usage: claude\n --disable-slash-commands Disable all skills\n", stderr="")
|
|
93
|
+
with mock.patch.object(loop.subprocess, "run", return_value=fake) as run:
|
|
94
|
+
self.assertTrue(loop.claude_supports_flag("--disable-slash-commands"))
|
|
95
|
+
self.assertTrue(loop.claude_supports_flag("--disable-slash-commands"))
|
|
96
|
+
self.assertEqual(run.call_count, 1)
|
|
97
|
+
|
|
98
|
+
def test_flag_absent_or_cli_broken_is_not_supported(self):
|
|
99
|
+
fake = mock.MagicMock(stdout="Usage: claude\n --model <m>\n", stderr="")
|
|
100
|
+
with mock.patch.object(loop.subprocess, "run", return_value=fake):
|
|
101
|
+
self.assertFalse(loop.claude_supports_flag("--disable-slash-commands"))
|
|
102
|
+
loop.claude_supports_flag.cache_clear()
|
|
103
|
+
with mock.patch.object(loop.subprocess, "run", side_effect=OSError("no claude")):
|
|
104
|
+
self.assertFalse(loop.claude_supports_flag("--disable-slash-commands"))
|
|
105
|
+
|
|
@@ -404,7 +404,9 @@ class TestTitlesTrackingAndBoundaries(unittest.TestCase):
|
|
|
404
404
|
"## Post-merge checklist\n\n- **`gatecheck.py --forbid-no-changes` exits 0 on merged HEAD.**\n"
|
|
405
405
|
)
|
|
406
406
|
runner = _FakeGhRunner()
|
|
407
|
-
result = loop.file_followup_issues(
|
|
407
|
+
result = loop.file_followup_issues(
|
|
408
|
+
feature_dir, feature_dir, runner=runner, post_merge_issue=True,
|
|
409
|
+
)
|
|
408
410
|
self.assertEqual(result["filed"], 1)
|
|
409
411
|
argv = runner.create_calls[0]
|
|
410
412
|
self.assertEqual(argv[argv.index("--title") + 1], "[FEAT-9999 post-merge] Post-merge checklist")
|
|
@@ -412,10 +414,32 @@ class TestTitlesTrackingAndBoundaries(unittest.TestCase):
|
|
|
412
414
|
plan = (feature_dir / "PLAN.md").read_text()
|
|
413
415
|
self.assertIn("## Post-merge checklist\n\n**Tracked as #101.**\n\n- **`gatecheck.py", plan)
|
|
414
416
|
# And the tracked line makes the next call a no-op.
|
|
415
|
-
again = loop.file_followup_issues(
|
|
417
|
+
again = loop.file_followup_issues(
|
|
418
|
+
feature_dir, feature_dir, runner=runner, post_merge_issue=True,
|
|
419
|
+
)
|
|
416
420
|
self.assertEqual((again["filed"], again["already_tracked"]), (0, 1))
|
|
417
421
|
self.assertEqual(len(runner.create_calls), 1)
|
|
418
422
|
|
|
423
|
+
def test_post_merge_checklist_is_not_an_issue_by_default(self):
|
|
424
|
+
# #3424: ten filed across two repositories, eight never actioned.
|
|
425
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
426
|
+
feature_dir = Path(tmp)
|
|
427
|
+
(feature_dir / "PLAN.md").write_text(
|
|
428
|
+
"---\nfeature_id: FEAT-9999\nstatus: done\nverdict: met\n---\n\n# Plan\n\n"
|
|
429
|
+
"## Post-merge checklist\n\n- [ ] count the thing over the next ten features\n"
|
|
430
|
+
)
|
|
431
|
+
runner = _FakeGhRunner()
|
|
432
|
+
result = loop.file_followup_issues(
|
|
433
|
+
feature_dir, feature_dir, runner=runner, post_merge_issue=False,
|
|
434
|
+
)
|
|
435
|
+
self.assertEqual((result["filed"], result["unfiled"]), (0, 0))
|
|
436
|
+
self.assertEqual(runner.create_calls, [])
|
|
437
|
+
self.assertNotIn("Tracked as", (feature_dir / "PLAN.md").read_text())
|
|
438
|
+
|
|
439
|
+
def test_post_merge_default_reads_the_verification_defaults(self):
|
|
440
|
+
self.assertFalse(loop.resolve_post_merge_issue({}))
|
|
441
|
+
self.assertTrue(loop.resolve_post_merge_issue({"defaults": {"post_merge_issue": True}}))
|
|
442
|
+
|
|
419
443
|
|
|
420
444
|
class TestTrackedLineIsReadUnderTheHeadingOnly(unittest.TestCase):
|
|
421
445
|
def test_a_foreign_tracked_line_quoted_in_the_evidence_does_not_skip_the_entry(self):
|
|
@@ -100,7 +100,7 @@ class TestLintGateProportionality(unittest.TestCase):
|
|
|
100
100
|
]
|
|
101
101
|
self.assertEqual(len(warns), 1, f"out={out!r}")
|
|
102
102
|
self.assertIn("6", warns[0])
|
|
103
|
-
self.assertIn("
|
|
103
|
+
self.assertIn("12", warns[0])
|
|
104
104
|
|
|
105
105
|
def test_small_feature_one_gate_clean(self):
|
|
106
106
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
@@ -114,13 +114,28 @@ class TestLintGateProportionality(unittest.TestCase):
|
|
|
114
114
|
out = self._run(feature)
|
|
115
115
|
self.assertNotIn("WARN", out)
|
|
116
116
|
|
|
117
|
-
def
|
|
117
|
+
def test_nine_units_two_gates_warns_since_the_line_moved_to_twelve(self):
|
|
118
|
+
# #3426: 9 substantive units sat just over the old line of 8.
|
|
119
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
120
|
+
feature = _make_feature(
|
|
121
|
+
tmpdir,
|
|
122
|
+
[["implementation"] * 5, ["implementation"] * 4],
|
|
123
|
+
)
|
|
124
|
+
out = self._run(feature)
|
|
125
|
+
warns = [
|
|
126
|
+
line for line in out.splitlines()
|
|
127
|
+
if "WARN" in line and "planned substantive WU count" in line
|
|
128
|
+
]
|
|
129
|
+
self.assertEqual(len(warns), 1, f"out={out!r}")
|
|
130
|
+
self.assertIn("9", warns[0])
|
|
131
|
+
|
|
132
|
+
def test_thirteen_units_two_gates_clean(self):
|
|
118
133
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
119
134
|
feature = _make_feature(
|
|
120
135
|
tmpdir,
|
|
121
136
|
[
|
|
122
|
-
["implementation"] *
|
|
123
|
-
["implementation"] *
|
|
137
|
+
["implementation"] * 7,
|
|
138
|
+
["implementation"] * 6,
|
|
124
139
|
],
|
|
125
140
|
)
|
|
126
141
|
out = self._run(feature)
|
|
@@ -340,3 +340,32 @@ class TestAutoArchiveLeavesNeighbourAnchor(unittest.TestCase):
|
|
|
340
340
|
|
|
341
341
|
if __name__ == "__main__":
|
|
342
342
|
unittest.main()
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class TestPostMergeChecklistTravelsWithTheArchive(unittest.TestCase):
|
|
346
|
+
"""#3424: the checklist lands under the archived detail, not in an issue."""
|
|
347
|
+
|
|
348
|
+
def test_checklist_appended_under_the_archived_section(self):
|
|
349
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
350
|
+
repo = _make_repo(tmp)
|
|
351
|
+
fdir = repo / ".specfuse" / "features" / "FEAT-2026-9999-slug"
|
|
352
|
+
fdir.mkdir(parents=True)
|
|
353
|
+
(fdir / "PLAN.md").write_text(
|
|
354
|
+
"---\nfeature_id: FEAT-2026-9999\nstatus: done\n---\n\n# Plan\n\n"
|
|
355
|
+
"## Post-merge checklist\n\n- [ ] count the thing over the next ten features\n\n"
|
|
356
|
+
"## Notes\n\n- none\n"
|
|
357
|
+
)
|
|
358
|
+
self.assertEqual(loop.auto_archive_feature("FEAT-2026-9999", repo), "archived")
|
|
359
|
+
archive_text = (repo / ".specfuse" / "roadmap-archive.md").read_text()
|
|
360
|
+
self.assertIn("**Post-merge checklist.**", archive_text)
|
|
361
|
+
self.assertIn("- [ ] count the thing over the next ten features", archive_text)
|
|
362
|
+
self.assertNotIn("## Notes", archive_text)
|
|
363
|
+
|
|
364
|
+
def test_no_plan_means_no_checklist_and_no_change(self):
|
|
365
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
366
|
+
repo = _make_repo(tmp)
|
|
367
|
+
self.assertEqual(loop.auto_archive_feature("FEAT-2026-9999", repo), "archived")
|
|
368
|
+
self.assertNotIn(
|
|
369
|
+
"Post-merge checklist", (repo / ".specfuse" / "roadmap-archive.md").read_text(),
|
|
370
|
+
)
|
|
371
|
+
|
|
@@ -22,7 +22,7 @@ loop = load_loop()
|
|
|
22
22
|
class TestCloseIntermediateInDicts(unittest.TestCase):
|
|
23
23
|
|
|
24
24
|
def test_close_intermediate_in_model_by_type(self):
|
|
25
|
-
self.assertEqual(loop.MODEL_BY_TYPE["close-intermediate"], "
|
|
25
|
+
self.assertEqual(loop.MODEL_BY_TYPE["close-intermediate"], "sonnet")
|
|
26
26
|
|
|
27
27
|
def test_close_intermediate_in_effort_by_type(self):
|
|
28
28
|
self.assertEqual(loop.EFFORT_BY_TYPE["close-intermediate"], "high")
|
|
@@ -52,5 +52,5 @@ class TestLoadWuCloseIntermediate(unittest.TestCase):
|
|
|
52
52
|
"depends_on": []}
|
|
53
53
|
wu = loop.load_wu(Path(tmp), ref)
|
|
54
54
|
self.assertEqual(wu.type, "close-intermediate")
|
|
55
|
-
self.assertEqual(wu.model, "
|
|
55
|
+
self.assertEqual(wu.model, "sonnet")
|
|
56
56
|
self.assertEqual(wu.effort, "high")
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.24.0
|
|
File without changes
|