specfuse-loop 0.25.0__tar.gz → 0.26.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.25.0/specfuse_loop.egg-info → specfuse_loop-0.26.0}/PKG-INFO +1 -1
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/pyproject.toml +1 -1
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/closing_requirements.py +32 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/criteria_state.py +154 -1
- specfuse_loop-0.26.0/specfuse/loop/data/VERSION +1 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/docs/methodology.md +39 -2
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/close-discipline.md +11 -0
- specfuse_loop-0.26.0/specfuse/loop/data/rules/result-contract.md +143 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/schemas/driver-event.schema.json +3 -2
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/verification.yml.example +24 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/gate_eval.py +17 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/judge.py +113 -2
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/lint_closing.py +35 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/loop.py +1116 -30
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/replay_spin.py +102 -1
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0/specfuse_loop.egg-info}/PKG-INFO +1 -1
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse_loop.egg-info/SOURCES.txt +12 -0
- specfuse_loop-0.26.0/tests/test_carried_green_invalidated_by_diff.py +367 -0
- specfuse_loop-0.26.0/tests/test_carry_accounting_close_and_judge.py +223 -0
- specfuse_loop-0.26.0/tests/test_failure_signature_names_the_test.py +242 -0
- specfuse_loop-0.26.0/tests/test_fix_unit_insertion_bookkeeping.py +193 -0
- specfuse_loop-0.26.0/tests/test_fix_unit_insertion_e2e.py +283 -0
- specfuse_loop-0.26.0/tests/test_fix_unit_insertion_refused.py +320 -0
- specfuse_loop-0.26.0/tests/test_judge_sees_dropped_produces.py +145 -0
- specfuse_loop-0.26.0/tests/test_produces_amendment_e2e.py +247 -0
- specfuse_loop-0.26.0/tests/test_produces_repair_note.py +205 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_rearm_clears_stale_criteria_state.py +36 -7
- specfuse_loop-0.26.0/tests/test_reclose_carries_narrow_greens_e2e.py +293 -0
- specfuse_loop-0.26.0/tests/test_replay_spin_failing_sets.py +110 -0
- specfuse_loop-0.26.0/tests/test_spinning_repeat_same_failing_set.py +230 -0
- specfuse_loop-0.25.0/specfuse/loop/data/VERSION +0 -1
- specfuse_loop-0.25.0/specfuse/loop/data/rules/result-contract.md +0 -132
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/LICENSE +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/NOTICE +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/README.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/setup.cfg +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/__init__.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/budget.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/diagnose_invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/drafting_answers.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/drafting_invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/drafting_questions.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/driver_command.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/driver_invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/monitoring_read.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/providers/__init__.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/providers/answers.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/providers/bugs.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/providers/feature.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/providers/findings_autofix.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/providers/findings_diagnose.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/providers/triage.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/queue_read.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/repo_detect.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/severity_backfill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/triage_invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/agent/worktree.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/__init__.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/_filelock.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/_miniyaml.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/_wu_sections.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/adopt_feature.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/agent_policy.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/arm_eval.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/arm_sweep.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/arm_txn.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/bug_lane.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/bug_lane_run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/bug_lane_state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/build_provenance.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/caller_check.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/changelog.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/cost.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/LEARNINGS.template.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/docs/getting-started.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/docs/glossary.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/docs/skills.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/gitignore.snippet +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/monitoring.yml.example +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/roadmap.template.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/correlation-ids.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/human-output.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/never-touch.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/operator-escalation.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/planning-discipline.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/security-boundaries.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules/verification-discipline.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/rules-local/README.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/schemas/event.schema.json +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/templates/GATE.template.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/templates/PLAN.template.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/templates/WU.template.md +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/decisions_format.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/driver_edit.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/escalation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/events_stats.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/gate_commands.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/gh_backend.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/gh_features.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/heartbeat.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/labels.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/learnings_distil.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/learnings_query.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/lint_monitoring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/lint_plan.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/lint_roadmap.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/notify.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/notify_escalation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/notify_sla.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/plan_baseline.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/policy_proposals.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/policy_review.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/prerun.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/prerun_capture.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/promotion.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/rearm_migration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/red_on_base.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/roadmap_archive.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/scaffold.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/triage.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/loop/validate_event.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/__init__.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/adapters.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/artifact.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/autofix.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/autofix_invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/autofix_run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/autofix_state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/cli.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/diagnose_cli.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/diagnosis.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/fingerprint.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/issues.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/providers/__init__.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/providers/_azure_auth.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/providers/azure_app_insights.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/providers/azure_service_bus.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/redaction.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse/monitor/schedule.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse_loop.egg-info/dependency_links.txt +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse_loop.egg-info/entry_points.txt +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse_loop.egg-info/requires.txt +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/specfuse_loop.egg-info/top_level.txt +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_abandon_feature_skill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_abandoned_work_reported.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_abandoned_wu_strands_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_adopt_feature.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_budget.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_bug_selection_dedup.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_default_features_root.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_driver_command.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_driver_invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_driver_restart.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_escalation_on_issue.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_escalation_run_state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_findings_seam.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_invoke_timeout.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_invoke_usage.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_item_worktree.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_lock.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_policy_key_ownership.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_policy_queue.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_policy_schema.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_policy_triage_dial.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_provider_answers.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_provider_bugs.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_provider_feature.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_provider_findings_autofix.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_provider_findings_diagnose.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_provider_isolation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_provider_triage.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_queue_read.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_relays_driver_output.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_repo_detect.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_run_progress.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_seam.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_snapshot_refresh.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_agent_state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_answer_escalation_skill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_app_insights_adapters.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_archive_ref_reconciliation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_arm_eval.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_arm_eval_lint_class.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_arm_eval_wiring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_arm_gate_edits_uncommitted.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_arm_sweep.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_arm_sweep_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_arm_txn.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_arm_wiring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_artifact_redaction.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_attempt_note_untracked_files.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_attempt_outcome_contract.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_attempt_outcome_emission.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_attention_nonwriting_guard.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_attention_silence_section.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_attention_skill_structure.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_attribution_halt_claims.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autoclose_deferral_visibility.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autoclose_gate_note.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autoclose_stub_states_what_passed.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autofix_invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autofix_live.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autofix_predicate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autofix_run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autofix_state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autosync.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autosync_consent.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autosync_firstrun.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autosync_no_cwd_leak.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_autosync_plugin.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_azure_credential_resolution.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_backend.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_baseline_escalation_message.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_baseline_persistence.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_baseline_probe.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_baseline_provenance.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_baseline_tree_hash_key.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bash_routing.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bats_suites_gated.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_binary_verdict.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_binding_block_advisory.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_binding_block_allocation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_binding_block_budget.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_blind_run_is_not_drained.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bookkeeping_commit_crash_run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bookkeeping_no_verify.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_brief_covers_every_unit_escalation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_ci_pending.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_guardrails.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_label_nonfatal.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_labels_registered.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_min_severity.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_policy_contract.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_pr_number_carried.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_preflight_and_dial.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_bug_lane_test_paths.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_build_provenance.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_caller_check_ratchet.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_changed_file_test_selection.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_changelog_append_only.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_changelog_collection.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_changelog_release_wiring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_changelog_schema.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_ci_conclusion_wait.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_ci_runs_every_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_claude_resolution.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_close_b_pending_learnings.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_close_records_feature_oracle.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_close_wu_self_reference.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_closing_deliverable_guard.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_closing_guard_contracts.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_closing_guard_prediction.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_closing_learnings_destination.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_closing_requirements.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_closing_sessions_on_sonnet.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_coauthor_trailer_allowlist.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_conditional_reflection.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_console_encoding.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_convergent_iteration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_convergent_wu_lint.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_correlation_id_override.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_correlation_id_two_surfaces.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_cost_lifetime.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_cost_tracking.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_criteria_per_gate_lint.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_criteria_state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_criteria_worklist.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_decision_citation_lint.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_decision_followups_discharged.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_decision_override_lint.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_decisions_format.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_default_severity_aliases.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_degraded_oracle.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_deliverable_missing_note.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_deliverable_presence_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_derive_agent_policy_review_mode.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_derive_agent_policy_skill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_derive_monitoring_discovery.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_derive_monitoring_skill_registration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_design_for_diagnosis_rule.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_deterministic_refusal_repeat.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_diagnose_headless.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_diagnose_issue_skill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_diagnosis.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_diagnosis_roundtrip_live.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_dispatch_model_from_fix_scope.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_dispatch_preamble_rules_pointer.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_dispatch_skeleton.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_dispatch_skills_index.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_distilled_accept_step.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_doctor.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_doctor_command_preflight.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_done_feature_gates.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_draft_feature_answers_mode.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_drafting_answer_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_drafting_invoke.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_drafting_question_issue.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_drafting_questions.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_drafting_reply_shape.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_edit_detection.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_event_registry_covers_emitters.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_integration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_lock.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_module_surface.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_restart_halt_surfaced.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_restart_halt_wiring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_restart_hold.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_staleness_gate_summary.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_driver_staleness_warning.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_dry_run_no_branch_mutation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_duration_tracking.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_empty_files_escalation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_ensure_feature_branch.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_ensure_feature_branch_base.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_escalation_assignee_policy.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_escalation_contract.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_escalation_crash_containment.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_escalation_dedup_search.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_escalation_emit.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_event_gate_full_envelope.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_events_redaction.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_events_stats.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_extra_gates.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_failure_artifact_model.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_failure_signature_fail_prefix.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_failure_signature_skips_log_noise.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_feature_branch_auto_sync.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_feature_branch_squash_merge.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_feature_branch_stale_base.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_feature_id_resolution.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_feature_oracle_e2e.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_feature_provider_drafting_dispatch.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_feature_review_accumulation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_filelock_portable.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_files_changed_auto_repair.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_find_pr_no_search_index.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_fingerprint.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_fix_bug_diff_self_check.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_fix_bug_headless.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_fix_bug_reads_comments.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_fold_contract_documented.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_followups_artifact.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_force_full_close.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_frontmatter_scalar_quoting.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_broad_run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_budget.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_budget_post_dispatch.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_commands_needs.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_eval.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_eval_calibration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_eval_intermediate_wiring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_eval_repo_flag.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_eval_terminal_wiring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gate_report_verdict.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gh_backend.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gh_features.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_git_env_isolation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_gitleaks_pinning.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_groom_backlog_skill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_guard_refusal_failure_class.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_guard_refusal_failure_excerpt.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_guard_repair_e2e.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_guard_repair_prompt.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_hashed_denylist.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_hashed_denylist_ci.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_heartbeat.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_heartbeat_adapter.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_human_output_rule.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_human_work_unit.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_hygiene_boundary_guidance.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_hyphenated_gate_name.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_ignored_cleanup_before_probe.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_init_integration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_installed_copy_driver_e2e.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_interpreter_normalization.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_judge_close_path.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_judge_cost.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_judge_cost_fold_committed.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_judge_module.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_judge_path_registry.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_judge_terminal_flip_state.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_judged_event_points_at_findings.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_label_description_length.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_label_provisioning_runner_contract.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_label_registry.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_label_registry_covers_consumers.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_language_aware_narrow_selection.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lazy_baseline_e2e.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_leak_findings_redaction.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_leak_scan.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_leak_scan_content.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_learnings_curate_vendored_promote.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_learnings_distil_cli.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_learnings_query.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_learnings_staging.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_learnings_suggest_signature_filter.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_learnings_weights.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_legacy_4wu_terminal_flips.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lifecycle_integration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lifetime_accounting.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_ac_observable.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_bare_produces_path.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_boundary_consistency.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_boundary_extraction.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_close_intermediate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_close_verdict_not_predecided.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_close_wu.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_closing.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_closing_criteria.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_closing_criteria_pristine.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_correlation_id.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_covers_load_wu_invariants.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_feature_oracle_declared.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_gate_proportionality.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_monitoring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_oracle_env.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_plan_contract_fields.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_plan_errors.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_plan_next_draft.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_plan_relative_import.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_plan_verdict_exempt.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_planning_sections.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_produces_driver_helper.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_produces_satisfiability.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_roadmap.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_sections.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_task_graph_yaml_selection.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_lint_verification_reference.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_live_tests_opt_in.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_load_bearing_close_lint.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_attempt_evidence.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_auto_archive.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_caveman_preamble.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_close_intermediate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_criteria_skeleton.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_criteria_survival.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_defaults_by_type.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_effort.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_failure_note_cap.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_files_changed_guard.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_gate_budget.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_gate_needs.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_model_alias.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_orchestration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_post_pass_invariant.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_reset_preserving_events.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_smoke_runner.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_unsandboxed.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_worklist_injection.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_loop_zero_token_guard.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_make_repo_gpgsign_isolation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_marker_dual_shape.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_maven_failure_excerpt.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_max_attempts_configurable.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_max_open_prs.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_migrate_legacy.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_miniyaml_equivalence.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_miniyaml_negative.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_monitor_cli.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_monitor_issue_lifecycle.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_monitor_runner_surfaces.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_monitoring_cron_dialect.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_monitoring_example.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_monitoring_fenced_blocks.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_monitoring_seed.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_narrow_fallback_warning.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_needs_decision_outcome.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_no_pytest_subprocess.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_notify.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_notify_escalation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_notify_sla.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_operator_escalation_rule.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_oracle_set_declared.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_oracle_unrunnable_attribution.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_per_run_item_cap_disclosure.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_pick_feature_skill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_pin_honesty_and_integrity.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_pin_marker_not_inherited.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_pin_marker_spawn_sites.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_plan_baseline.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_planned_cost_lint.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_planning_cost_floor.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_plugin_prose_cross_refs.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_plugin_qualified_dispatch.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_policy_budgets_applied.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_policy_proposals.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_policy_review.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_pr_checks_json_field.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_pr_reference_in_title.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_prep_halt_operator_surface.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_prepare_feature.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_prepare_scaffold_sync.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_prerun_capture.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_prerun_oracles.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_prerun_wiring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produced_document_verdict_guard.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produces_bracket_literal.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produces_bracket_wildcard.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produces_field.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produces_in_diff.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produces_justification.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produces_recursive_glob.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produces_semantics_unified.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_produces_shape.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_progress_forward_note.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_progress_lines_end_to_end.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_promotion_ledger.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_provider_escalation_traces.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_provision_labels.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_queue_stalled_adapter.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_rearm_fold_marker.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_rearm_migration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_red_baseline_never_reused.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_red_on_base_guardrail.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_red_on_base_probe.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_redaction_windows_home.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_reflection_required_signals.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_replan_end_to_end.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_replan_event_emission.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_replan_note_collision.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_replan_trigger.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_replan_turn_contract.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_replay_spin.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_required_checks.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_resolve_base.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_restart_cap_counts_progress.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_result_block.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_result_block_audience.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_resume_command_build.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_retain_on_guard_refusal_docs.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_roadmap_add_skill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_roadmap_archive_cli.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_roadmap_archive_shim.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_roadmap_archive_skill.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_roadmap_archive_skill_delegates.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_roadmap_link_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_roadmap_row_parser.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_ruff_verdict_lines.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_rule_import_convergence.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_run_level_failure_breaker.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_data_in_sync.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_doc_hygiene.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_docs.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_init.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_label_provisioning.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_manifest.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_resources.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_seed_sanity.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_skew_halts.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_upgrade.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_scaffold_wiring.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_schedule_dialect.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_seed_documents_prerun_keys.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_service_bus_dlq_adapter.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_session_env_preflight.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_aliases.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_backfill_apply.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_backfill_end_to_end.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_backfill_limit.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_backfill_marker.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_backfill_run.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_label_projection.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_reconciliation.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_severity_rubric.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_shipped_templates_parse.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_skill_discovery_links.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_skills_vendored_in_sync.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_spec_work_unit_rules.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_spinning_rearm_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_spinout_brief_end_to_end.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_spinout_brief_replan_option.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_squash_commit_hook_crash.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_stop_rationale_captured.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_stranded_halt_cause.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_surefire_run_level_signature.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_surefire_verdict_lines.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_template_closing_shapes.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_terminal_flip_ownership.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_terminal_flips.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_terminal_gate_message.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_tiered_verification_e2e.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_timeout_kill_portable.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_triage.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_triage_apply.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_triage_projects_severity_label.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_triage_severity_classify.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_triage_severity_end_to_end.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_triage_severity_write.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_triage_skill_contract.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_triage_skips_agent_escalations.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_tsc_verdict_lines.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_umbrella_version_resolution.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_unterminated_frontmatter.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_untracked_feature_folder.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_untracked_file_absorption.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_upgrade_integration.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_validate_event.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_validate_event_driver_types.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_verdict_coupling.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_verify_empty_gate_set.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_version_consistency.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_version_skew.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_windows_gate_exec.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_worktree_restore.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.0}/tests/test_wu_execution_metadata.py +0 -0
- {specfuse_loop-0.25.0 → specfuse_loop-0.26.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.26.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"
|
|
@@ -155,6 +155,25 @@ FEATURE_ORACLE_VERDICT_RE = re.compile(
|
|
|
155
155
|
rf"^###\s+{re.escape(FEATURE_ORACLE_KEY)}:\s*(PASS|FAIL)\s*$", re.MULTILINE,
|
|
156
156
|
)
|
|
157
157
|
|
|
158
|
+
#: A re-close's `## Measurements` carry-accounting line (FEAT-2026-0117/T03),
|
|
159
|
+
#: required only when `GATE-NN-CRITERIA.md` has at least one
|
|
160
|
+
#: `carried_from_attempt` entry — a first close has no new obligation.
|
|
161
|
+
#: `entries` is duck-typed (`criteria_state.CriterionStateEntry`, or anything
|
|
162
|
+
#: with a `carried_from_attempt` attribute): this registry stays a pure-data
|
|
163
|
+
#: module with no import of the artifact schema it describes.
|
|
164
|
+
def carry_summary_is_required(entries) -> bool:
|
|
165
|
+
"""True when at least one entry carries a green forward from a prior
|
|
166
|
+
attempt — the trigger for the `## Measurements` carry-accounting line."""
|
|
167
|
+
return any(entry.carried_from_attempt is not None for entry in entries)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def render_carry_summary(entries) -> str:
|
|
171
|
+
"""The exact `## Measurements` line a close pastes when `entries` carries
|
|
172
|
+
any criterion forward: `carried forward: N criteria, re-measured: M`."""
|
|
173
|
+
carried = sum(1 for entry in entries if entry.carried_from_attempt is not None)
|
|
174
|
+
return f"carried forward: {carried} criteria, re-measured: {len(entries) - carried}"
|
|
175
|
+
|
|
176
|
+
|
|
158
177
|
GATE_REVIEW_FILENAME_TEMPLATE = "GATE-{next_gate:02d}-REVIEW.md"
|
|
159
178
|
|
|
160
179
|
|
|
@@ -378,6 +397,19 @@ CLOSING_REQUIREMENTS: dict[str, list[Requirement]] = {
|
|
|
378
397
|
file=RETROSPECTIVE_FILENAME,
|
|
379
398
|
enforced_by="check_feature_oracle_verdict_recorded",
|
|
380
399
|
),
|
|
400
|
+
Requirement(
|
|
401
|
+
id="close-o", wu_type="close", phase="pre-squash",
|
|
402
|
+
description=(
|
|
403
|
+
"When GATE-NN-CRITERIA.md carries at least one entry forward "
|
|
404
|
+
"from a prior attempt, RETROSPECTIVE.md's Measurements "
|
|
405
|
+
"section records the render_carry_summary(entries) line — "
|
|
406
|
+
"'carried forward: N criteria, re-measured: M' — so the "
|
|
407
|
+
"close states what it inherited (FEAT-2026-0117/T03)"
|
|
408
|
+
),
|
|
409
|
+
file=RETROSPECTIVE_FILENAME,
|
|
410
|
+
applies_when="criteria_artifact_present",
|
|
411
|
+
enforced_by="check_carry_summary_recorded",
|
|
412
|
+
),
|
|
381
413
|
],
|
|
382
414
|
"close-intermediate": [
|
|
383
415
|
Requirement(
|
|
@@ -20,7 +20,8 @@ FEAT-2026-0056/PLAN.md and GATE-01.md for the design this module encodes.
|
|
|
20
20
|
from __future__ import annotations
|
|
21
21
|
|
|
22
22
|
import re
|
|
23
|
-
from dataclasses import dataclass
|
|
23
|
+
from dataclasses import dataclass, field
|
|
24
|
+
from pathlib import Path
|
|
24
25
|
from typing import Optional
|
|
25
26
|
|
|
26
27
|
#: An oracle's scope classification. `narrow` oracles (a scoped test nodeid,
|
|
@@ -41,6 +42,11 @@ _FIELD_PATTERNS = {
|
|
|
41
42
|
"state": re.compile(r"^- \*\*state:\*\*\s*`([^`]+)`", re.MULTILINE),
|
|
42
43
|
"proved_at_sha": re.compile(r"^- \*\*proved_at_sha:\*\*\s*`([^`]+)`", re.MULTILINE),
|
|
43
44
|
"attempt": re.compile(r"^- \*\*attempt:\*\*\s*`?([^`\n]+)`?", re.MULTILINE),
|
|
45
|
+
"carried_from_attempt": re.compile(
|
|
46
|
+
r"^- \*\*carried_from_attempt:\*\*\s*`?([^`\n]+)`?", re.MULTILINE
|
|
47
|
+
),
|
|
48
|
+
"covers": re.compile(r"^- \*\*covers:\*\*\s*(.+)$", re.MULTILINE),
|
|
49
|
+
"invalidated_by": re.compile(r"^- \*\*invalidated_by:\*\*\s*(.+)$", re.MULTILINE),
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
|
|
@@ -55,6 +61,20 @@ class CriterionStateEntry:
|
|
|
55
61
|
state: Optional[str]
|
|
56
62
|
proved_at_sha: Optional[str]
|
|
57
63
|
attempt: Optional[str]
|
|
64
|
+
#: Set by `reset_stale_criteria_entries` when a re-arm carries this
|
|
65
|
+
#: entry's narrow green past the attempt cycle that proved it — the
|
|
66
|
+
#: attempt number it was carried FROM, not the current attempt.
|
|
67
|
+
carried_from_attempt: Optional[str] = None
|
|
68
|
+
#: Paths this criterion's proof depends on — its producing WU's
|
|
69
|
+
#: `produces:` plus its oracle's test file, when derivable
|
|
70
|
+
#: (`derive_criterion_covers`, FEAT-2026-0117/T02). Empty when never
|
|
71
|
+
#: seeded with a `- **covers:**` line: an entry the skeleton step hasn't
|
|
72
|
+
#: backfilled yet, or one predating this field.
|
|
73
|
+
covers: list = field(default_factory=list)
|
|
74
|
+
#: Set by `invalidate_carried_entries` when a re-close's gate diff
|
|
75
|
+
#: touches a path this (formerly carried) entry `covers` — names that
|
|
76
|
+
#: path, not the whole diff.
|
|
77
|
+
invalidated_by: Optional[str] = None
|
|
58
78
|
|
|
59
79
|
|
|
60
80
|
#: Matches `GATE-NN-CRITERIA.md` basenames (any `NN`), and nothing else —
|
|
@@ -98,6 +118,8 @@ def parse_criteria_state(text: str) -> list[CriterionStateEntry]:
|
|
|
98
118
|
start = m.end()
|
|
99
119
|
end = headings[i + 1].start() if i + 1 < len(headings) else len(text)
|
|
100
120
|
block = text[start:end]
|
|
121
|
+
covers_raw = _extract_field(block, "covers")
|
|
122
|
+
covers = [c.strip() for c in covers_raw.split(",") if c.strip()] if covers_raw else []
|
|
101
123
|
entries.append(
|
|
102
124
|
CriterionStateEntry(
|
|
103
125
|
criterion_id=criterion_id,
|
|
@@ -107,11 +129,77 @@ def parse_criteria_state(text: str) -> list[CriterionStateEntry]:
|
|
|
107
129
|
state=_extract_field(block, "state"),
|
|
108
130
|
proved_at_sha=_extract_field(block, "proved_at_sha"),
|
|
109
131
|
attempt=_extract_field(block, "attempt"),
|
|
132
|
+
carried_from_attempt=_extract_field(block, "carried_from_attempt"),
|
|
133
|
+
covers=covers,
|
|
134
|
+
invalidated_by=_extract_field(block, "invalidated_by"),
|
|
110
135
|
)
|
|
111
136
|
)
|
|
112
137
|
return entries
|
|
113
138
|
|
|
114
139
|
|
|
140
|
+
def resolve_carry_forward_narrow_greens(cfg: "dict | None") -> bool:
|
|
141
|
+
"""Whether a re-armed close carries a `narrow`/`pass` entry's green
|
|
142
|
+
forward past the attempt cycle that proved it (FEAT-2026-0117/T01).
|
|
143
|
+
|
|
144
|
+
Reads `verification.yml` `defaults.carry_forward_narrow_greens` — default
|
|
145
|
+
True, same project-default precedence tier as `loop.py`'s other
|
|
146
|
+
`resolve_*` readers. *cfg* is the already-loaded `verification.yml` dict;
|
|
147
|
+
this module does no file I/O of its own.
|
|
148
|
+
"""
|
|
149
|
+
if not cfg:
|
|
150
|
+
return True
|
|
151
|
+
return (cfg.get("defaults") or {}).get("carry_forward_narrow_greens", True) is not False
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def reset_stale_criteria_entries(
|
|
155
|
+
entries: list[CriterionStateEntry], current_attempt: int, carry_narrow: bool,
|
|
156
|
+
) -> list[CriterionStateEntry]:
|
|
157
|
+
"""Reset entries left behind by a superseded attempt cycle (#3279).
|
|
158
|
+
|
|
159
|
+
An entry whose recorded `attempt` exceeds *current_attempt* was measured
|
|
160
|
+
in a cycle a re-arm has since superseded. With *carry_narrow* true, an
|
|
161
|
+
entry that is also `kind: narrow` and `state: pass` is provably safe to
|
|
162
|
+
keep — its oracle's scope was knowable, so a re-arm does not invalidate
|
|
163
|
+
what it proved — and keeps every field, gaining `carried_from_attempt`
|
|
164
|
+
set to the attempt it was proved on. Every other stale entry resets to
|
|
165
|
+
`unverified` with its per-attempt fields cleared, exactly as if it had
|
|
166
|
+
never been verified. Entries at or below the current attempt, and
|
|
167
|
+
entries with no recorded attempt, are returned unchanged.
|
|
168
|
+
"""
|
|
169
|
+
refreshed: list[CriterionStateEntry] = []
|
|
170
|
+
for entry in entries:
|
|
171
|
+
recorded = entry.attempt
|
|
172
|
+
try:
|
|
173
|
+
is_stale = recorded is not None and int(str(recorded).strip()) > current_attempt
|
|
174
|
+
except (TypeError, ValueError):
|
|
175
|
+
is_stale = False # unparseable attempt: leave it for the close
|
|
176
|
+
if is_stale:
|
|
177
|
+
if carry_narrow and entry.kind == "narrow" and entry.state == "pass":
|
|
178
|
+
entry = CriterionStateEntry(
|
|
179
|
+
criterion_id=entry.criterion_id,
|
|
180
|
+
criterion=entry.criterion,
|
|
181
|
+
oracle=entry.oracle,
|
|
182
|
+
kind=entry.kind,
|
|
183
|
+
state=entry.state,
|
|
184
|
+
proved_at_sha=entry.proved_at_sha,
|
|
185
|
+
attempt=entry.attempt,
|
|
186
|
+
carried_from_attempt=str(recorded).strip(),
|
|
187
|
+
)
|
|
188
|
+
else:
|
|
189
|
+
entry = CriterionStateEntry(
|
|
190
|
+
criterion_id=entry.criterion_id,
|
|
191
|
+
criterion=entry.criterion,
|
|
192
|
+
oracle=None,
|
|
193
|
+
kind=None,
|
|
194
|
+
state="unverified",
|
|
195
|
+
proved_at_sha=None,
|
|
196
|
+
attempt=None,
|
|
197
|
+
carried_from_attempt=None,
|
|
198
|
+
)
|
|
199
|
+
refreshed.append(entry)
|
|
200
|
+
return refreshed
|
|
201
|
+
|
|
202
|
+
|
|
115
203
|
@dataclass(frozen=True)
|
|
116
204
|
class ReverificationWorklist:
|
|
117
205
|
"""Partition of a gate's recorded entries for a re-dispatched close attempt.
|
|
@@ -138,6 +226,11 @@ def build_reverification_worklist(
|
|
|
138
226
|
fail` or `state: unverified`, and every `broad` entry regardless of
|
|
139
227
|
state — goes to `reverify`. Fail-safe default: unclassifiable entries
|
|
140
228
|
land in `reverify`, never in `carry_forward`.
|
|
229
|
+
|
|
230
|
+
`covers` plays no part in this partition — a `carried_from_attempt`
|
|
231
|
+
entry with an empty `covers` is kept out of `carry_forward` by
|
|
232
|
+
`loop.invalidate_carried_entries` resetting it to `unverified` before
|
|
233
|
+
this runs (FEAT-2026-0117/T02), not by a check here.
|
|
141
234
|
"""
|
|
142
235
|
carry_forward: list[CriterionStateEntry] = []
|
|
143
236
|
reverify: list[CriterionStateEntry] = []
|
|
@@ -191,5 +284,65 @@ def render_criteria_state(entries: list[CriterionStateEntry]) -> str:
|
|
|
191
284
|
lines.append(f"- **proved_at_sha:** `{entry.proved_at_sha}`")
|
|
192
285
|
if entry.attempt is not None:
|
|
193
286
|
lines.append(f"- **attempt:** `{entry.attempt}`")
|
|
287
|
+
if entry.carried_from_attempt is not None:
|
|
288
|
+
lines.append(f"- **carried_from_attempt:** `{entry.carried_from_attempt}`")
|
|
289
|
+
if entry.covers:
|
|
290
|
+
lines.append(f"- **covers:** {', '.join(entry.covers)}")
|
|
291
|
+
if entry.invalidated_by is not None:
|
|
292
|
+
lines.append(f"- **invalidated_by:** {entry.invalidated_by}")
|
|
194
293
|
blocks.append("\n".join(lines) + "\n")
|
|
195
294
|
return "\n".join(blocks)
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
_UNITTEST_ORACLE_RE = re.compile(r"-m\s+unittest\s+([\w.]+)")
|
|
298
|
+
_MAVEN_DTEST_RE = re.compile(r"-Dtest=([A-Za-z_][A-Za-z0-9_]*)")
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _unittest_module_path(oracle_command: str) -> "Optional[str]":
|
|
302
|
+
"""`tests.foo_bar[.TestX.test_y]` -> `tests/foo_bar.py`, the file the
|
|
303
|
+
unittest oracle actually runs regardless of which class/method suffix it
|
|
304
|
+
names. Tries the longest dotted prefix that exists on disk first, so a
|
|
305
|
+
package (`tests/foo_bar/__init__` style) is not required; falls back to
|
|
306
|
+
the full dotted-to-slash mapping when nothing on disk matches yet."""
|
|
307
|
+
m = _UNITTEST_ORACLE_RE.search(oracle_command)
|
|
308
|
+
if not m:
|
|
309
|
+
return None
|
|
310
|
+
parts = m.group(1).split(".")
|
|
311
|
+
for i in range(len(parts), 0, -1):
|
|
312
|
+
candidate = "/".join(parts[:i]) + ".py"
|
|
313
|
+
if Path(candidate).is_file():
|
|
314
|
+
return candidate
|
|
315
|
+
return "/".join(parts) + ".py"
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def _maven_test_class_path(oracle_command: str) -> "Optional[str]":
|
|
319
|
+
"""`-Dtest=FooBarTest` -> its `src/test/**/FooBarTest.java`, only when
|
|
320
|
+
one actually exists — unlike the unittest case, a Maven class name gives
|
|
321
|
+
no reliable package-to-path mapping without a filesystem lookup."""
|
|
322
|
+
m = _MAVEN_DTEST_RE.search(oracle_command)
|
|
323
|
+
if not m:
|
|
324
|
+
return None
|
|
325
|
+
root = Path("src/test")
|
|
326
|
+
if not root.is_dir():
|
|
327
|
+
return None
|
|
328
|
+
matches = sorted(root.rglob(f"{m.group(1)}.java"))
|
|
329
|
+
return str(matches[0]) if matches else None
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def derive_criterion_covers(wu, oracle_command: "Optional[str]") -> list:
|
|
333
|
+
"""Paths a criterion's proof depends on (FEAT-2026-0117/T02): its
|
|
334
|
+
producing WU's `produces:` plus the test file its oracle command names,
|
|
335
|
+
when derivable. Feeds a seeded entry's `- **covers:**` line so a re-close
|
|
336
|
+
can tell whether a later diff touched what a carried green actually
|
|
337
|
+
measured — see `invalidate_carried_entries` in `loop.py`.
|
|
338
|
+
|
|
339
|
+
*wu* is anything with a `.produces` list (a `WorkUnit`, or a duck-typed
|
|
340
|
+
stand-in built from a WU read off disk); *oracle_command* is the entry's
|
|
341
|
+
recorded `oracle`, or `None` before a close has run it.
|
|
342
|
+
"""
|
|
343
|
+
covers = list(getattr(wu, "produces", None) or [])
|
|
344
|
+
if oracle_command:
|
|
345
|
+
test_path = _unittest_module_path(oracle_command) or _maven_test_class_path(oracle_command)
|
|
346
|
+
if test_path and test_path not in covers:
|
|
347
|
+
covers.append(test_path)
|
|
348
|
+
return covers
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.26.0
|
|
@@ -127,6 +127,22 @@ it mostly does not need. Author-set unless marked driver-owned.
|
|
|
127
127
|
`attempts`, `cost_usd`, `input_tokens`, `output_tokens`, `duration_seconds`,
|
|
128
128
|
`cumulative_*`, `re_arm_count`, `re_arm_history`, `folded_through_re_arm`,
|
|
129
129
|
`model`/`effort` as resolved, `gate_set`, `driver_version`, `started_at`.
|
|
130
|
+
- `produces_dropped` — driver-owned. Written when a RESULT's `produces_amended:`
|
|
131
|
+
entries are accepted (`defaults.produces_amendable: true`): the paths dropped
|
|
132
|
+
from this unit's recorded `produces:` (`.specfuse/rules/result-contract.md`).
|
|
133
|
+
- `covers` — driver-seeded, on a `GATE-NN-CRITERIA.md` entry, not WU frontmatter.
|
|
134
|
+
The path(s) that criterion's oracle actually exercises; absent when no path is
|
|
135
|
+
derivable, in which case the criterion is never carried forward.
|
|
136
|
+
- `carried_from_attempt` — driver-owned, on a carried `GATE-NN-CRITERIA.md`
|
|
137
|
+
entry. The attempt number whose run proved the green being carried.
|
|
138
|
+
- `invalidated_by` — driver-owned, on a `GATE-NN-CRITERIA.md` entry whose
|
|
139
|
+
carried green was invalidated. Names the path in `covers:` the gate diff
|
|
140
|
+
touched since `proved_at_sha`.
|
|
141
|
+
|
|
142
|
+
`defaults.carry_forward_narrow_greens` (`verification.yml`, default `true`) —
|
|
143
|
+
whether a re-close may carry forward a prior attempt's `narrow` green at all;
|
|
144
|
+
see `.specfuse/verification.yml.example` and
|
|
145
|
+
`.specfuse/rules/close-discipline.md` §5.
|
|
130
146
|
|
|
131
147
|
## 3. Work unit types
|
|
132
148
|
|
|
@@ -388,12 +404,19 @@ after v2+ revisions ship.
|
|
|
388
404
|
Every dispatched attempt emits exactly one `attempt_outcome` event to
|
|
389
405
|
`events.jsonl`. The payload carries a standardized set of fields:
|
|
390
406
|
`outcome`, `failure_class`, `failure_signature`, `failure_excerpt`,
|
|
391
|
-
`cost_usd`, `duration_seconds`, `attempt`, and
|
|
392
|
-
the field-by-field schema see
|
|
407
|
+
`failing_tests`, `cost_usd`, `duration_seconds`, `attempt`, and
|
|
408
|
+
`re_arm_count`. For the field-by-field schema see
|
|
393
409
|
`.specfuse/features/FEAT-2026-0016-attempt-outcome-rearm-contract/PLAN.md`
|
|
394
410
|
§ "Event payload shape — `attempt_outcome` v1". The full payload is
|
|
395
411
|
not restated here (one fact, one home).
|
|
396
412
|
|
|
413
|
+
`failing_tests` is the sorted, de-duplicated list of failing test ids
|
|
414
|
+
`extract_failing_tests` recognised in the gate report (empty when no
|
|
415
|
+
runner-recognised per-test id was found); for `failure_class: tests`,
|
|
416
|
+
`detect_spinning_signature_repeat` treats two non-empty `failing_tests`
|
|
417
|
+
sets as the same failure iff they are equal as sets, ahead of the
|
|
418
|
+
`(failure_class, failure_signature)` comparison (FEAT-2026-0116).
|
|
419
|
+
|
|
397
420
|
`outcome` taxonomy, as `loop.py` actually emits it — thirteen values,
|
|
398
421
|
bound to the emitter by `tests/test_attempt_outcome_contract.py`:
|
|
399
422
|
|
|
@@ -468,6 +491,20 @@ actioned); `auto_archive_feature` appends it under the feature's archived
|
|
|
468
491
|
detail section in `roadmap-archive.md`. `defaults.post_merge_issue: true` in
|
|
469
492
|
`verification.yml` restores the issue.
|
|
470
493
|
|
|
494
|
+
**A RESULT may amend the plan, never add to it (FEAT-2026-0114).** A session's
|
|
495
|
+
`produces_amended:` entry claims a planned `produces:` path the solution did
|
|
496
|
+
not need; `defaults.produces_amendable: true` in `verification.yml` lets the
|
|
497
|
+
driver accept it, dropping the path into `produces_dropped` on the unit.
|
|
498
|
+
Default `false` — an unrecognized amendment is judged as an unjustified
|
|
499
|
+
unchanged deliverable (`.specfuse/rules/result-contract.md`).
|
|
500
|
+
|
|
501
|
+
**A block may name its own fix (FEAT-2026-0115).** A `blocked` RESULT's
|
|
502
|
+
`blocked_next:` names a drafted fix unit; once the arm checks clear, the
|
|
503
|
+
driver inserts it ahead of the blocked unit and emits `fix_unit_inserted` to
|
|
504
|
+
`events.jsonl` on re-arm. `defaults.fix_unit_insertion: true` in
|
|
505
|
+
`verification.yml` gates the feature accepting one at all;
|
|
506
|
+
`defaults.max_fix_units_per_unit: 2` caps insertions per blocked unit.
|
|
507
|
+
|
|
471
508
|
**Closing sessions run on sonnet (#3425).** `close`, `close-intermediate`
|
|
472
509
|
and `plan-next` default to `sonnet` at effort `high`, the same model as the
|
|
473
510
|
judge that checks them (lower-only, about $0.46 per close). Opus was 56% of
|
|
@@ -222,6 +222,17 @@ green would be an unsound coverage claim; it re-runs on every close attempt.
|
|
|
222
222
|
inferred by a reader, the same posture §2 already takes on the hedged-record
|
|
223
223
|
`kind:`. `specfuse lint --closing` is the check.
|
|
224
224
|
|
|
225
|
+
**A carried `narrow` green is invalidated when the criterion's covered paths
|
|
226
|
+
changed since it was proved.** Each entry may carry a driver-seeded `covers:`
|
|
227
|
+
— the path(s) its oracle actually exercises. On a re-close, a carried entry's
|
|
228
|
+
`narrow` green is invalidated (re-measured, not trusted) when the gate diff
|
|
229
|
+
since that entry's `proved_at_sha` touches a path in its `covers:`. A
|
|
230
|
+
criterion with no derivable `covers:` is never carried — it re-measures on
|
|
231
|
+
every close attempt, the same as a `broad` entry. A carried entry also
|
|
232
|
+
carries `carried_from_attempt`, the attempt number whose run proved it. A
|
|
233
|
+
re-close's `## Measurements` states how much of the gate's state was inherited
|
|
234
|
+
versus fresh: `carried forward: N criteria, re-measured: M`.
|
|
235
|
+
|
|
225
236
|
## Split with project-local rules
|
|
226
237
|
|
|
227
238
|
These are the generic obligations. The concrete grounding — which command is
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Copyright 2026 Specfuse Contributors
|
|
3
|
+
Licensed under the Apache License, Version 2.0. See LICENSE.
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Rule: the RESULT block contract
|
|
7
|
+
|
|
8
|
+
A dispatched work-unit session ends with one fenced `result` block as the last
|
|
9
|
+
thing in its output; the driver reads it, and a session emitting none is a
|
|
10
|
+
failed attempt. The RESULT is **advisory** — the driver re-runs verification
|
|
11
|
+
itself, and that decides done.
|
|
12
|
+
|
|
13
|
+
## Who reads it — emit it only when something does
|
|
14
|
+
|
|
15
|
+
This block is a **machine interface**, not a report. Emit it only when a
|
|
16
|
+
program is on the other end: a dispatched work-unit session (always), or a
|
|
17
|
+
skill invoked **non-interactively** from a calling program parsing the
|
|
18
|
+
outcome (`fix-bug` under `autofix_invoke`).
|
|
19
|
+
|
|
20
|
+
Do **not** emit it on an interactive run — a human typing `/pick-feature` has
|
|
21
|
+
no parser, and the block becomes a slab to scroll past, the verbosity
|
|
22
|
+
[`human-output.md`](human-output.md) prevents. Report per that rule instead.
|
|
23
|
+
Rule of thumb: a person-typed slash command is interactive; a `claude -p`
|
|
24
|
+
dispatch is not.
|
|
25
|
+
|
|
26
|
+
## The cycle: state intent, act, verify, report
|
|
27
|
+
|
|
28
|
+
[`verification-discipline.md`](verification-discipline.md) is normative on the
|
|
29
|
+
cycle; this file is normative on how the loop surface reports step 4.
|
|
30
|
+
|
|
31
|
+
1. **State intent.** One sentence on what you are about to do and why it is the
|
|
32
|
+
next right step. If it disagrees with the work unit's acceptance criteria,
|
|
33
|
+
the unit is not what you thought it was.
|
|
34
|
+
2. **Act.** Stay inside that scope. "While I was here I also fixed X" is drift;
|
|
35
|
+
the work unit's **Do not touch** section is binding.
|
|
36
|
+
3. **Verify.** Re-read what you produced — Write/Edit reports the action taken,
|
|
37
|
+
not the property you wanted — and run the unit's own verification commands,
|
|
38
|
+
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
|
|
43
|
+
nothing. "I assume the tests still pass" is not verification. A
|
|
44
|
+
behavioural claim needs a run, not a source reading; a rule-or-severity
|
|
45
|
+
claim needs a **negative observation** — the rule seen rejecting a
|
|
46
|
+
purpose-built bad input.
|
|
47
|
+
4. **Report.** Report only what verification confirmed.
|
|
48
|
+
|
|
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
|
+
|
|
56
|
+
## Format
|
|
57
|
+
|
|
58
|
+
````markdown
|
|
59
|
+
```result
|
|
60
|
+
status: complete | blocked # complete = "I believe acceptance criteria are met"
|
|
61
|
+
summary: <one sentence on what changed>
|
|
62
|
+
forward_note: <optional — one sentence on what the NEXT unit should know>
|
|
63
|
+
files_changed:
|
|
64
|
+
- path/to/file
|
|
65
|
+
acceptance_criteria:
|
|
66
|
+
- text: <criterion, copied from the work unit>
|
|
67
|
+
met: true | false
|
|
68
|
+
evidence: <how you know — a test name, a behavior, a line reference>
|
|
69
|
+
blocked_reason: <present only when status is blocked>
|
|
70
|
+
blocked_next: # optional — a drafted fix unit
|
|
71
|
+
kind: fix_unit
|
|
72
|
+
file: <path to the drafted WU>
|
|
73
|
+
id: <the drafted WU's id>
|
|
74
|
+
produces_unchanged: # optional — obligation 1 below
|
|
75
|
+
- path: <a produces: entry, verbatim>
|
|
76
|
+
justification: <the command you ran and its output showing the deliverable already holds>
|
|
77
|
+
produces_amended: # optional — obligation 1 below
|
|
78
|
+
- path: <a produces: entry, verbatim>
|
|
79
|
+
justification: <why the plan named it but the solution didn't need it>
|
|
80
|
+
```
|
|
81
|
+
````
|
|
82
|
+
|
|
83
|
+
`summary` is backward-looking by this contract's own definition — one sentence
|
|
84
|
+
on what changed. `forward_note` is the other half: what surprised you, or what
|
|
85
|
+
the next unit should know, that `summary` misses. Optional, never required by
|
|
86
|
+
any guard — omit it and the driver's `PROGRESS.md` entry is unchanged
|
|
87
|
+
(FEAT-2026-0106/T02).
|
|
88
|
+
|
|
89
|
+
## Rules
|
|
90
|
+
|
|
91
|
+
1. **No git.** Edit files only. The driver stages, squashes, and commits one
|
|
92
|
+
trailer-carrying commit per unit.
|
|
93
|
+
2. **Verify before reporting.** Do not report success you have not checked.
|
|
94
|
+
3. **Blocked is a valid, respectable outcome.** A precise `blocked_reason`
|
|
95
|
+
after one honest attempt beats three attempts chasing a `complete`
|
|
96
|
+
verification keeps rejecting.
|
|
97
|
+
4. **Stop at a boundary rather than working around it.** Generated
|
|
98
|
+
directories, secrets, and `.git/` internals are off-limits
|
|
99
|
+
([`never-touch.md`](never-touch.md),
|
|
100
|
+
[`security-boundaries.md`](security-boundaries.md)); weakening a failing
|
|
101
|
+
gate to pass is the same failure class. Silence at a boundary is not
|
|
102
|
+
permission.
|
|
103
|
+
5. **No secret-looking values in evidence.** The driver reads and may archive
|
|
104
|
+
this block.
|
|
105
|
+
6. **Never mint or rewrite a correlation ID to make it fit.** A well-formed
|
|
106
|
+
ID disagreeing across surfaces is `blocked`, not a rename
|
|
107
|
+
([`correlation-ids.md`](correlation-ids.md)).
|
|
108
|
+
7. **A "pre-existing" failure claim cites the commit it was measured on.**
|
|
109
|
+
Calling a failure pre-existing is a claim about a *different* commit,
|
|
110
|
+
typically the merge-base, that nothing on your own branch establishes.
|
|
111
|
+
Name the command and commit, give the numbers from both sides, and emit
|
|
112
|
+
`status: blocked` rather than asserting an unmeasured baseline: a mass of
|
|
113
|
+
errors sharing one signature (network refused, unresolvable build
|
|
114
|
+
dependencies) reports where the suite ran, not the repository (#2075).
|
|
115
|
+
8. **A block may name its own fix.** `blocked_next:` points at a drafted work
|
|
116
|
+
unit — `provenance: agent`, `status: draft`, the five WU sections filled —
|
|
117
|
+
the driver inserts ahead of this one and re-arms it, when the feature runs
|
|
118
|
+
`auto` and the draft passes the arm checks; no `blocked_next` escalates
|
|
119
|
+
unchanged.
|
|
120
|
+
|
|
121
|
+
## Closing obligations for implementation WUs (FEAT-2026-0049)
|
|
122
|
+
|
|
123
|
+
1. **Diff against `produces:` first.** Every path in the WU's `produces:` list
|
|
124
|
+
must show a working-tree change, or the RESULT must justify each unchanged
|
|
125
|
+
path under `produces_unchanged:` (deliverable already held) or
|
|
126
|
+
`produces_amended:` (the plan named a path the solution didn't need — drop
|
|
127
|
+
only, never add) — spelled as `produces:` spells it, plus the proving
|
|
128
|
+
command and output. The driver reads that list: a justified entry passes
|
|
129
|
+
and is recorded as `produces_justified`; an unjustified one, or a blank
|
|
130
|
+
justification, is refused (#198, #3268, outcome `produces_not_in_diff`).
|
|
131
|
+
Silence on an unchanged deliverable is not valid.
|
|
132
|
+
2. **A plan-level contradiction is `blocked`, not `complete`.** Put the
|
|
133
|
+
finding in `blocked_reason`; never bury it in a gate document and close
|
|
134
|
+
`complete`.
|
|
135
|
+
3. **Every `evidence:` cites an executed command** and its observed exit
|
|
136
|
+
code/output. Reading source or citing another WU's RESULT is not
|
|
137
|
+
verification.
|
|
138
|
+
4. **Analysis without edits is not a silent attempt.** Say so; end `blocked`
|
|
139
|
+
rather than spend the attempt on prose.
|
|
140
|
+
|
|
141
|
+
The driver's whole cycle — re-verify, commit, advance the dependency
|
|
142
|
+
frontier, dispatch next — runs on this block being an honest claim. State
|
|
143
|
+
intent. Act. Verify. Report. Every time.
|
{specfuse_loop-0.25.0 → specfuse_loop-0.26.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. 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.",
|
|
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. FEAT-2026-0115/T01: fix_unit_inserted added — emitted once a blocked RESULT's `blocked_next:` names a drafted fix unit that `insert_fix_unit` validated and inserted ahead of the blocked unit, carrying the fix unit's id, its file, the gate, and the insertion count; the blocked unit's own re-arm (an existing `re_arm_dispatched`, reason `fix_unit_inserted`) rides alongside it, so this is the only genuinely new event_type the mechanic needs.",
|
|
7
7
|
"event_types": [
|
|
8
8
|
"attempt_outcome",
|
|
9
9
|
"gate_reached",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"baseline_attribution",
|
|
21
21
|
"broad_run_result",
|
|
22
22
|
"driver_build_pinned",
|
|
23
|
-
"replan"
|
|
23
|
+
"replan",
|
|
24
|
+
"fix_unit_inserted"
|
|
24
25
|
],
|
|
25
26
|
"correlation_id": {
|
|
26
27
|
"closing_names": [
|
|
@@ -129,11 +129,35 @@
|
|
|
129
129
|
# # Defaults to false (#3424): the checklist is
|
|
130
130
|
# # appended under the feature's archived detail
|
|
131
131
|
# # section in roadmap-archive.md instead.
|
|
132
|
+
# produces_amendable: false # whether the driver accepts a RESULT's
|
|
133
|
+
# # `produces_amended:` entries, dropping those
|
|
134
|
+
# # paths from the unit's recorded `produces:`.
|
|
135
|
+
# # Defaults to false: an amendment claim is
|
|
136
|
+
# # ignored and the path is judged as an
|
|
137
|
+
# # unjustified unchanged deliverable instead
|
|
138
|
+
# # (FEAT-2026-0114).
|
|
139
|
+
# fix_unit_insertion: true # whether a blocked RESULT's `blocked_next:`
|
|
140
|
+
# # may insert its drafted fix unit instead of
|
|
141
|
+
# # escalating. Defaults to true (FEAT-2026-0115).
|
|
142
|
+
# max_fix_units_per_unit: 2 # cap on `fix_unit_inserted` insertions per
|
|
143
|
+
# # blocked unit before it escalates instead
|
|
144
|
+
# # (FEAT-2026-0115). Defaults to 2.
|
|
145
|
+
# carry_forward_narrow_greens: true # whether a re-close may carry forward a
|
|
146
|
+
# # prior attempt's `narrow` GATE-NN-CRITERIA.md
|
|
147
|
+
# # green instead of re-measuring it. Defaults to
|
|
148
|
+
# # true. A carried green still invalidates when
|
|
149
|
+
# # the gate diff since its `proved_at_sha`
|
|
150
|
+
# # touches a path in its `covers:` — see
|
|
151
|
+
# # `.specfuse/rules/close-discipline.md` §5.
|
|
132
152
|
# defaults:
|
|
133
153
|
# max_attempts: 3
|
|
134
154
|
# retain_on_guard_refusal: true
|
|
135
155
|
# dispatch_skills: false
|
|
136
156
|
# post_merge_issue: false
|
|
157
|
+
# produces_amendable: false
|
|
158
|
+
# fix_unit_insertion: true
|
|
159
|
+
# max_fix_units_per_unit: 2
|
|
160
|
+
# carry_forward_narrow_greens: true
|
|
137
161
|
#
|
|
138
162
|
# The re-plan-after-two-failures behaviour (FEAT-2026-0104) reads this same
|
|
139
163
|
# `max_attempts` resolution and adds no config key of its own — a unit's
|
|
@@ -203,6 +203,19 @@ def _apply_predicate(
|
|
|
203
203
|
sub_id = wu_id.split("/")[-1] if "/" in wu_id else wu_id
|
|
204
204
|
reasons.append(f"replan_event: {sub_id}")
|
|
205
205
|
|
|
206
|
+
# --- Check 2b: No fix_unit_inserted events (FEAT-2026-0115/T03) ---
|
|
207
|
+
seen_fix_unit_inserted: set[str] = set()
|
|
208
|
+
fix_unit_inserted_events: list[str] = []
|
|
209
|
+
for ev in events:
|
|
210
|
+
if ev.get("event_type") == "fix_unit_inserted":
|
|
211
|
+
wu_id = ev.get("correlation_id", "unknown")
|
|
212
|
+
if wu_id in seen_fix_unit_inserted:
|
|
213
|
+
continue
|
|
214
|
+
seen_fix_unit_inserted.add(wu_id)
|
|
215
|
+
fix_unit_inserted_events.append(wu_id)
|
|
216
|
+
sub_id = wu_id.split("/")[-1] if "/" in wu_id else wu_id
|
|
217
|
+
reasons.append(f"fix_unit_inserted: {sub_id}")
|
|
218
|
+
|
|
206
219
|
# --- Checks 3 & 4: Per-WU cost ratios (skip close/close-intermediate and plan-next) ---
|
|
207
220
|
for wm in wu_metrics_list:
|
|
208
221
|
wu_type = wm["type"]
|
|
@@ -279,6 +292,8 @@ def _apply_predicate(
|
|
|
279
292
|
"plan_next_planned": plan_next_planned,
|
|
280
293
|
"blocked_human_events": blocked_human_events,
|
|
281
294
|
"replan_events": replan_events,
|
|
295
|
+
"fix_unit_inserted_events": fix_unit_inserted_events,
|
|
296
|
+
"fix_unit_inserted_count": len(fix_unit_inserted_events),
|
|
282
297
|
"final_outcomes": final_outcomes,
|
|
283
298
|
"warnings": warnings,
|
|
284
299
|
}
|
|
@@ -388,6 +403,8 @@ def _evaluate_predicate_core(
|
|
|
388
403
|
"plan_next_planned": None,
|
|
389
404
|
"blocked_human_events": [],
|
|
390
405
|
"replan_events": [],
|
|
406
|
+
"fix_unit_inserted_events": [],
|
|
407
|
+
"fix_unit_inserted_count": 0,
|
|
391
408
|
"final_outcomes": {},
|
|
392
409
|
"warnings": pre_warnings,
|
|
393
410
|
},
|