specfuse-loop 0.22.2__tar.gz → 0.22.3__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.22.2/specfuse_loop.egg-info → specfuse_loop-0.22.3}/PKG-INFO +1 -1
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/pyproject.toml +1 -1
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/severity_backfill.py +58 -5
- specfuse_loop-0.22.3/specfuse/loop/data/VERSION +1 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/loop.py +189 -10
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/triage.py +87 -1
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3/specfuse_loop.egg-info}/PKG-INFO +1 -1
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/SOURCES.txt +3 -0
- specfuse_loop-0.22.3/tests/test_attribution_halt_claims.py +139 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_escalation_message.py +18 -5
- specfuse_loop-0.22.3/tests/test_ignored_cleanup_before_probe.py +292 -0
- specfuse_loop-0.22.3/tests/test_severity_backfill_end_to_end.py +215 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_backfill_run.py +98 -0
- specfuse_loop-0.22.3/tests/test_severity_reconciliation.py +177 -0
- specfuse_loop-0.22.2/specfuse/loop/data/VERSION +0 -1
- specfuse_loop-0.22.2/tests/test_severity_backfill_end_to_end.py +0 -86
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/LICENSE +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/NOTICE +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/README.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/setup.cfg +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/__init__.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/budget.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/diagnose_invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/drafting_answers.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/drafting_invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/drafting_questions.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/driver_command.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/driver_invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/monitoring_read.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/__init__.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/answers.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/bugs.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/feature.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/findings_autofix.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/findings_diagnose.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/providers/triage.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/queue_read.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/repo_detect.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/run.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/triage_invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/agent/worktree.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/__init__.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/_filelock.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/_miniyaml.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/_wu_sections.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/adopt_feature.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/agent_policy.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/arm_eval.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/arm_sweep.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/arm_txn.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/bug_lane.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/bug_lane_run.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/bug_lane_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/build_provenance.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/caller_check.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/changelog.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/closing_requirements.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/cost.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/criteria_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/CHANGELOG.seed.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/LEARNINGS.template.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/concepts/adopting-auto-mode.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/concepts/architecture-addendum-gates-and-iterative-planning.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/concepts/autonomy-stop-classes.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/concepts/ralph-lineage.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/getting-started.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/glossary.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/methodology.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/docs/skills.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/gitignore.snippet +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/monitoring-secrets-checklist.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/monitoring.overrides.yml.example +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/monitoring.yml.example +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/roadmap.template.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/close-discipline.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/correlation-ids.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/design-for-diagnosis.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/human-output.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/never-touch.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/operator-escalation.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/planning-discipline.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/result-contract.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/security-boundaries.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules/verification-discipline.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/rules-local/README.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/driver-event.schema.json +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/event.schema.json +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/events/initiative_created.schema.json +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/events/spec_issue_resolved.schema.json +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/events/spec_issue_routed.schema.json +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/schemas/events/spec_validated.schema.json +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/DECISIONS.template.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/GATE.template.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/LEARNINGS-pending.template.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/PLAN.template.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/templates/WU.template.md +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/verification.yml.example +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/data/workflows/specfuse-monitor.yml +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/decisions_format.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/driver_edit.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/escalation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/events_stats.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/gate_commands.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/gate_eval.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/gh_backend.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/gh_features.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/heartbeat.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/judge.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/labels.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/learnings_distil.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/learnings_query.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/lint_closing.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/lint_monitoring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/lint_plan.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/lint_roadmap.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/notify.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/notify_escalation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/notify_sla.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/plan_baseline.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/policy_proposals.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/policy_review.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/prerun.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/prerun_capture.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/promotion.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/rearm_migration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/replay_spin.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/roadmap_archive.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/scaffold.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/loop/validate_event.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/__init__.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/adapters.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/artifact.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/autofix.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/autofix_invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/autofix_run.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/autofix_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/cli.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/diagnose_cli.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/diagnosis.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/fingerprint.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/issues.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/providers/__init__.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/providers/_azure_auth.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/providers/azure_app_insights.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/providers/azure_service_bus.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/redaction.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse/monitor/schedule.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/dependency_links.txt +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/entry_points.txt +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/requires.txt +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/specfuse_loop.egg-info/top_level.txt +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_abandon_feature_skill.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_abandoned_work_reported.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_abandoned_wu_strands_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_adopt_feature.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_budget.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_bug_selection_dedup.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_default_features_root.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_driver_command.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_driver_invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_driver_restart.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_escalation_on_issue.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_escalation_run_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_findings_seam.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_invoke_timeout.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_invoke_usage.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_item_worktree.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_lock.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_policy_key_ownership.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_policy_queue.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_policy_schema.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_policy_triage_dial.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_answers.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_bugs.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_feature.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_findings_autofix.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_findings_diagnose.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_isolation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_provider_triage.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_queue_read.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_relays_driver_output.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_repo_detect.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_run.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_run_progress.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_seam.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_snapshot_refresh.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_agent_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_answer_escalation_skill.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_app_insights_adapters.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_archive_ref_reconciliation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_eval.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_eval_lint_class.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_eval_wiring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_gate_edits_uncommitted.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_sweep.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_sweep_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_txn.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_arm_wiring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_artifact_redaction.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attempt_note_untracked_files.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attempt_outcome_contract.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attempt_outcome_emission.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attention_nonwriting_guard.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attention_silence_section.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_attention_skill_structure.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autoclose_deferral_visibility.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autoclose_gate_note.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autoclose_stub_states_what_passed.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_live.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_predicate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_run.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autofix_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync_consent.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync_firstrun.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync_no_cwd_leak.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_autosync_plugin.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_azure_credential_resolution.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_backend.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_persistence.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_probe.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_provenance.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_baseline_tree_hash_key.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bash_routing.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bats_suites_gated.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_binary_verdict.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_binding_block_advisory.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_binding_block_allocation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_binding_block_budget.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bookkeeping_commit_crash_run.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bookkeeping_commit_hook_crash.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bookkeeping_no_verify.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_brief_covers_every_unit_escalation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_ci_pending.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_guardrails.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_label_nonfatal.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_labels_registered.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_min_severity.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_policy_contract.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_pr_number_carried.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_preflight_and_dial.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_run.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_stopped_outcome_pr_number.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_bug_lane_test_paths.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_build_provenance.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_caller_check_ratchet.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changed_file_test_selection.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changelog_append_only.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changelog_collection.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changelog_release_wiring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_changelog_schema.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ci_conclusion_wait.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ci_runs_every_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_claude_resolution.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_close_b_pending_learnings.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_close_records_feature_oracle.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_close_wu_self_reference.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_deliverable_guard.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_guard_contracts.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_guard_prediction.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_learnings_destination.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_closing_requirements.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_coauthor_trailer_allowlist.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_conditional_reflection.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_console_encoding.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_convergent_iteration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_convergent_wu_lint.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_correlation_id_override.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_correlation_id_two_surfaces.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_cost_lifetime.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_cost_tracking.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_criteria_per_gate_lint.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_criteria_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_criteria_worklist.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_decision_citation_lint.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_decision_followups_discharged.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_decision_override_lint.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_decisions_format.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_default_severity_aliases.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_degraded_oracle.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_deliverable_missing_note.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_deliverable_presence_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_derive_agent_policy_review_mode.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_derive_agent_policy_skill.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_derive_monitoring_discovery.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_derive_monitoring_skill_registration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_design_for_diagnosis_rule.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_deterministic_refusal_repeat.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_diagnose_headless.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_diagnose_issue_skill.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_diagnosis.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_diagnosis_roundtrip_live.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_dispatch_skeleton.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_distilled_accept_step.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_doctor.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_doctor_command_preflight.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_done_feature_gates.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_draft_feature_answers_mode.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_answer_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_invoke.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_question_issue.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_questions.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_drafting_reply_shape.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_edit_detection.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_event_registry_covers_emitters.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_integration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_lock.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_module_surface.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_restart_halt_surfaced.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_restart_halt_wiring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_restart_hold.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_staleness_gate_summary.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_driver_staleness_warning.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_dry_run_no_branch_mutation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_duration_tracking.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_empty_files_escalation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ensure_feature_branch.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ensure_feature_branch_base.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_assignee_policy.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_contract.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_crash_containment.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_dedup_search.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_escalation_emit.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_event_gate_full_envelope.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_events_redaction.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_events_stats.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_extra_gates.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_failure_artifact_model.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_failure_signature_fail_prefix.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_failure_signature_skips_log_noise.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_branch_auto_sync.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_branch_squash_merge.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_branch_stale_base.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_id_resolution.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_oracle_e2e.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_provider_drafting_dispatch.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_feature_review_accumulation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_filelock_portable.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_files_changed_auto_repair.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_find_pr_no_search_index.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fingerprint.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fix_bug_diff_self_check.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fix_bug_headless.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fix_bug_reads_comments.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_fold_contract_documented.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_followups_artifact.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_force_full_close.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_frontmatter_scalar_quoting.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_broad_run.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_budget.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_budget_post_dispatch.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_commands_needs.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval_calibration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval_intermediate_wiring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval_repo_flag.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_eval_terminal_wiring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gate_report_verdict.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gh_backend.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gh_features.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_git_env_isolation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_gitleaks_pinning.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_groom_backlog_skill.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_guard_refusal_failure_class.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_guard_refusal_failure_excerpt.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_guard_repair_e2e.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_guard_repair_prompt.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_hashed_denylist.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_hashed_denylist_ci.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_heartbeat.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_heartbeat_adapter.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_human_output_rule.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_human_work_unit.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_hygiene_boundary_guidance.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_hyphenated_gate_name.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_init_integration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_installed_copy_driver_e2e.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_interpreter_normalization.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_close_path.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_cost.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_cost_fold_committed.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_module.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_path_registry.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_judge_terminal_flip_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_label_provisioning_runner_contract.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_label_registry.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_label_registry_covers_consumers.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_language_aware_narrow_selection.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lazy_baseline_e2e.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_leak_findings_redaction.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_leak_scan.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_leak_scan_content.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_curate_vendored_promote.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_distil_cli.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_query.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_staging.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_suggest_signature_filter.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_learnings_weights.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_legacy_4wu_terminal_flips.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lifecycle_integration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lifetime_accounting.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_ac_observable.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_bare_produces_path.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_boundary_consistency.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_boundary_extraction.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_close_intermediate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_close_verdict_not_predecided.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_close_wu.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_closing.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_closing_criteria.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_closing_criteria_pristine.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_correlation_id.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_correlation_id_close_intermediate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_covers_load_wu_invariants.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_feature_oracle_declared.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_gate_proportionality.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_monitoring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_oracle_env.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_contract_fields.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_errors.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_next_draft.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_relative_import.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_plan_verdict_exempt.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_planning_sections.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_produces_driver_helper.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_produces_satisfiability.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_roadmap.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_sections.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_task_graph_yaml_selection.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_lint_verification_reference.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_live_tests_opt_in.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_load_bearing_close_lint.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_attempt_evidence.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_auto_archive.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_caveman_preamble.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_close_intermediate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_criteria_skeleton.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_criteria_survival.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_defaults_by_type.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_effort.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_failure_note_cap.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_files_changed_guard.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_gate_budget.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_gate_needs.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_model_alias.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_orchestration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_post_pass_invariant.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_reset_preserving_events.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_smoke_runner.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_unsandboxed.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_worklist_injection.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_loop_zero_token_guard.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_make_repo_gpgsign_isolation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_marker_dual_shape.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_maven_failure_excerpt.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_max_attempts_configurable.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_max_open_prs.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_migrate_legacy.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_miniyaml_equivalence.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_miniyaml_negative.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitor_cli.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitor_issue_lifecycle.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitor_runner_surfaces.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_bootstrap_artifacts.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_cron_dialect.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_example.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_fenced_blocks.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_monitoring_seed.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_narrow_fallback_warning.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_no_pytest_subprocess.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_notify.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_notify_escalation.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_notify_sla.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_operator_escalation_rule.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_oracle_set_declared.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_oracle_unrunnable_attribution.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_per_run_item_cap_disclosure.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pick_feature_skill.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pin_honesty_and_integrity.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pin_marker_not_inherited.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pin_marker_spawn_sites.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_plan_baseline.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_planned_cost_lint.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_planning_cost_floor.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_plugin_prose_cross_refs.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_plugin_qualified_dispatch.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_policy_budgets_applied.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_policy_proposals.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_policy_review.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pr_checks_json_field.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pr_reference_in_title.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_pre_existing_claims_cite_evidence.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prep_halt_operator_surface.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prepare_feature.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prepare_scaffold_sync.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prerun_capture.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prerun_oracles.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_prerun_wiring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produced_document_verdict_guard.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_bracket_literal.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_bracket_wildcard.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_field.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_in_diff.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_justification.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_recursive_glob.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_semantics_unified.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_produces_shape.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_progress_forward_note.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_progress_lines_end_to_end.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_promotion_ledger.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_provider_escalation_traces.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_provision_labels.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_queue_stalled_adapter.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_rearm_clears_stale_criteria_state.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_rearm_fold_marker.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_rearm_migration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_red_baseline_never_reused.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_redaction_windows_home.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_reflection_required_signals.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_end_to_end.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_event_emission.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_note_collision.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_trigger.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replan_turn_contract.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_replay_spin.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_required_checks.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_resolve_base.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_restart_cap_counts_progress.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_result_block.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_result_block_audience.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_resume_command_build.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_retain_on_guard_refusal_docs.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_add_skill.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_archive_cli.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_archive_shim.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_archive_skill.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_archive_skill_delegates.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_link_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_roadmap_row_parser.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_ruff_verdict_lines.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_rule_import_convergence.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_run_level_failure_breaker.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_data_in_sync.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_doc_hygiene.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_docs.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_init.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_label_provisioning.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_manifest.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_resources.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_seed_sanity.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_skew_halts.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_upgrade.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_scaffold_wiring.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_schedule_dialect.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_seed_documents_prerun_keys.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_service_bus_dlq_adapter.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_session_env_preflight.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_aliases.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_backfill_apply.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_backfill_limit.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_backfill_marker.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_label_projection.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_severity_rubric.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_shipped_templates_parse.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_skill_discovery_links.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_skills_vendored_in_sync.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_spinning_rearm_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_spinout_brief_end_to_end.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_spinout_brief_replan_option.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_squash_commit_hook_crash.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_stop_rationale_captured.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_stranded_halt_cause.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_surefire_run_level_signature.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_surefire_verdict_lines.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_template_closing_shapes.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_terminal_flip_ownership.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_terminal_flips.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_terminal_gate_message.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_tiered_verification_e2e.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_timeout_kill_portable.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_apply.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_severity_classify.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_severity_end_to_end.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_severity_write.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_skill_contract.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_triage_skips_agent_escalations.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_tsc_verdict_lines.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_umbrella_version_resolution.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_unterminated_frontmatter.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_untracked_feature_folder.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_untracked_file_absorption.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_upgrade_integration.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_upgrade_merge_gate.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_validate_event.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_validate_event_driver_types.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_verdict_coupling.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_verify_empty_gate_set.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_version_consistency.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_version_skew.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_windows_gate_exec.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_worktree_restore.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/tests/test_wu_execution_metadata.py +0 -0
- {specfuse_loop-0.22.2 → specfuse_loop-0.22.3}/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.22.
|
|
7
|
+
version = "0.22.3"
|
|
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"
|
|
@@ -43,7 +43,7 @@ from specfuse.loop.labels import (
|
|
|
43
43
|
severity_label_projection,
|
|
44
44
|
)
|
|
45
45
|
|
|
46
|
-
from specfuse.loop import triage
|
|
46
|
+
from specfuse.loop import agent_policy, triage
|
|
47
47
|
from specfuse.loop.build_provenance import warn_if_out_of_tree
|
|
48
48
|
|
|
49
49
|
#: Stands in for T10's classification session (gate 3, walking skeleton).
|
|
@@ -105,6 +105,7 @@ def apply_severity_backfill(
|
|
|
105
105
|
"number": number,
|
|
106
106
|
"severity": severity,
|
|
107
107
|
"skipped": False,
|
|
108
|
+
"severity_source": decision.get("severity_source", "classifier"),
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
new_body = triage.amend_marker_severity(body, severity)
|
|
@@ -121,6 +122,16 @@ def apply_severity_backfill(
|
|
|
121
122
|
continue
|
|
122
123
|
row["marker_written"] = True
|
|
123
124
|
|
|
125
|
+
if decision.get("severity_source") == "label":
|
|
126
|
+
# Reconciled (#3360): the label IS the source of this severity, so
|
|
127
|
+
# it is already on the issue. Writing one would at best re-apply
|
|
128
|
+
# what is there and at worst add a second spelling beside the
|
|
129
|
+
# person's, which is the collision this path exists to avoid.
|
|
130
|
+
row["label_written"] = False
|
|
131
|
+
row["label_skipped_reason"] = "severity read from the issue's own label"
|
|
132
|
+
results.append(row)
|
|
133
|
+
continue
|
|
134
|
+
|
|
124
135
|
label = (label_projection or {}).get(
|
|
125
136
|
severity, triage.severity_label_for(severity)
|
|
126
137
|
)
|
|
@@ -206,6 +217,8 @@ def run_backfill(
|
|
|
206
217
|
),
|
|
207
218
|
}
|
|
208
219
|
|
|
220
|
+
aliases = agent_policy.resolve_severity_aliases()
|
|
221
|
+
|
|
209
222
|
rows = []
|
|
210
223
|
decisions = []
|
|
211
224
|
for issue in candidates:
|
|
@@ -213,6 +226,31 @@ def run_backfill(
|
|
|
213
226
|
title = issue.get("title", "")
|
|
214
227
|
body = issue.get("body") or ""
|
|
215
228
|
|
|
229
|
+
# The label is consulted BEFORE any classification session (#3360): an
|
|
230
|
+
# issue a person already labelled must have its marker written from
|
|
231
|
+
# that label, never from a fresh opinion about it. This also means a
|
|
232
|
+
# reconciled issue costs no `claude` invocation at all.
|
|
233
|
+
action, labelled_severity, reason = triage.severity_decision(
|
|
234
|
+
issue.get("labels"), aliases)
|
|
235
|
+
|
|
236
|
+
if action == triage.SEVERITY_SKIP:
|
|
237
|
+
rows.append({
|
|
238
|
+
"number": number, "classified": False, "severity": None,
|
|
239
|
+
"severity_source": "label", "skipped_reason": reason,
|
|
240
|
+
})
|
|
241
|
+
continue
|
|
242
|
+
|
|
243
|
+
if action == triage.SEVERITY_RECONCILE:
|
|
244
|
+
rows.append({
|
|
245
|
+
"number": number, "classified": True,
|
|
246
|
+
"severity": labelled_severity, "severity_source": "label",
|
|
247
|
+
})
|
|
248
|
+
decisions.append({
|
|
249
|
+
"number": number, "body": body,
|
|
250
|
+
"severity": labelled_severity, "severity_source": "label",
|
|
251
|
+
})
|
|
252
|
+
continue
|
|
253
|
+
|
|
216
254
|
argv, prompt = build_invocation(
|
|
217
255
|
number, title, body, repo, working_dir, model=model, effort=effort, rubric=rubric
|
|
218
256
|
)
|
|
@@ -220,11 +258,14 @@ def run_backfill(
|
|
|
220
258
|
severity = classify_severity(invoked.text, rubric)
|
|
221
259
|
|
|
222
260
|
if severity is None:
|
|
223
|
-
rows.append({"number": number, "classified": False, "severity": None
|
|
261
|
+
rows.append({"number": number, "classified": False, "severity": None,
|
|
262
|
+
"severity_source": "classifier"})
|
|
224
263
|
continue
|
|
225
264
|
|
|
226
|
-
rows.append({"number": number, "classified": True, "severity": severity
|
|
227
|
-
|
|
265
|
+
rows.append({"number": number, "classified": True, "severity": severity,
|
|
266
|
+
"severity_source": "classifier"})
|
|
267
|
+
decisions.append({"number": number, "body": body, "severity": severity,
|
|
268
|
+
"severity_source": "classifier"})
|
|
228
269
|
|
|
229
270
|
if apply and decisions:
|
|
230
271
|
# A property of the repository's label set, not of any one issue
|
|
@@ -271,7 +312,19 @@ def _print_run_report(report: dict) -> None:
|
|
|
271
312
|
return
|
|
272
313
|
for row in report["rows"]:
|
|
273
314
|
if not row["classified"]:
|
|
274
|
-
|
|
315
|
+
# A refusal to overwrite a person is not a classification failure,
|
|
316
|
+
# and #3360's re-run condition is read off these lines: it asks for
|
|
317
|
+
# zero rows the run would contradict, which is unanswerable if both
|
|
318
|
+
# print the same sentence.
|
|
319
|
+
reason = row.get("skipped_reason")
|
|
320
|
+
if reason:
|
|
321
|
+
print(f"#{row['number']}: left alone — {reason}")
|
|
322
|
+
else:
|
|
323
|
+
print(f"#{row['number']}: no usable classification, skipped")
|
|
324
|
+
continue
|
|
325
|
+
if row.get("severity_source") == "label":
|
|
326
|
+
print(f"#{row['number']}: severity={row['severity']} "
|
|
327
|
+
f"(reconciled from its own label, not classified)")
|
|
275
328
|
continue
|
|
276
329
|
print(f"#{row['number']}: severity={row['severity']}")
|
|
277
330
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.22.3
|
|
@@ -125,7 +125,7 @@ SPECFUSE_DIR = Path(".specfuse")
|
|
|
125
125
|
REPO_ROOT = SPECFUSE_DIR.parent
|
|
126
126
|
FEATURES_DIR = SPECFUSE_DIR / "features"
|
|
127
127
|
VERIFICATION_PATH = SPECFUSE_DIR / "verification.yml"
|
|
128
|
-
DRIVER_VERSION = "0.22.
|
|
128
|
+
DRIVER_VERSION = "0.22.3"
|
|
129
129
|
# Oldest scaffold layout this driver can drive. init.sh stamps the scaffold's own
|
|
130
130
|
# version into `.specfuse/VERSION`; check_scaffold_version() fails loud at startup if
|
|
131
131
|
# the consumer's scaffold is older than this, pointing at `specfuse upgrade`. Bump
|
|
@@ -2244,6 +2244,34 @@ def untracked_paths() -> set[str]:
|
|
|
2244
2244
|
return {line.strip() for line in out.splitlines() if line.strip()}
|
|
2245
2245
|
|
|
2246
2246
|
|
|
2247
|
+
def ignored_paths() -> set[str]:
|
|
2248
|
+
"""Repo-relative paths git reports as IGNORED, file by file.
|
|
2249
|
+
|
|
2250
|
+
Twin of :func:`untracked_paths`, snapshotted per-WU at dispatch so the
|
|
2251
|
+
attempt-failure path can tell "this ignored file was already here" from
|
|
2252
|
+
"this attempt produced it" (#3330). A `git reset --hard` restores tracked
|
|
2253
|
+
content and leaves ignored files in place, so without this the baseline
|
|
2254
|
+
attribution probe measures the failed attempt's own build output and
|
|
2255
|
+
reports the failure as pre-existing.
|
|
2256
|
+
|
|
2257
|
+
`--ignored` is deliberately paired with `ls-files` rather than read off
|
|
2258
|
+
`git status --porcelain --ignored`: status collapses a wholly-ignored
|
|
2259
|
+
directory to a single entry, so `!! out/` is byte-identical before and
|
|
2260
|
+
after an attempt adds files underneath it. That is precisely the reported
|
|
2261
|
+
case -- `out/` already existed and the attempt wrote 11 new files into it --
|
|
2262
|
+
and a snapshot diff over the status listing would have seen nothing.
|
|
2263
|
+
|
|
2264
|
+
Can be large on a repository carrying vendored dependency trees, so it is
|
|
2265
|
+
called only on the failure path that actually probes, where it is cheap
|
|
2266
|
+
beside the full gate-set run it precedes.
|
|
2267
|
+
"""
|
|
2268
|
+
out = subprocess.run(
|
|
2269
|
+
["git", "ls-files", "--others", "--ignored", "--exclude-standard"],
|
|
2270
|
+
capture_output=True, text=True, check=True,
|
|
2271
|
+
).stdout
|
|
2272
|
+
return {line.strip() for line in out.splitlines() if line.strip()}
|
|
2273
|
+
|
|
2274
|
+
|
|
2247
2275
|
def _tracked_dirty_paths() -> set[str]:
|
|
2248
2276
|
"""Paths with TRACKED, uncommitted changes (staged or unstaged), repo-relative.
|
|
2249
2277
|
|
|
@@ -3787,10 +3815,70 @@ def _clean_attempt_untracked(
|
|
|
3787
3815
|
continue
|
|
3788
3816
|
|
|
3789
3817
|
|
|
3818
|
+
#: Ignored path prefixes the attempt-ignored clean never deletes. `work/` holds
|
|
3819
|
+
#: the per-attempt verify-output notes `persist_attempt_notes` writes (#168) --
|
|
3820
|
+
#: gitignored, and written AFTER the reset, so at the next attempt's reset they
|
|
3821
|
+
#: look exactly like the build output this clean exists to remove. The snapshot
|
|
3822
|
+
#: is taken once per WU rather than per attempt, so without this keep-list
|
|
3823
|
+
#: attempt 2 would delete attempt 1's evidence.
|
|
3824
|
+
IGNORED_CLEAN_KEEP_PREFIXES = ("work/", ".specfuse/")
|
|
3825
|
+
|
|
3826
|
+
|
|
3827
|
+
def _clean_attempt_ignored(
|
|
3828
|
+
ignored_before: "set[str] | frozenset[str]", events_path: Path,
|
|
3829
|
+
) -> None:
|
|
3830
|
+
"""Delete gitignored files that appeared since the *ignored_before* snapshot.
|
|
3831
|
+
|
|
3832
|
+
Defect 1 of #3330. `_clean_attempt_untracked` above deliberately leaves
|
|
3833
|
+
ignored paths alone, and that carve-out is load-bearing -- the driver's own
|
|
3834
|
+
gitignored `work/` notes have to survive the reset. But it also leaves the
|
|
3835
|
+
failed attempt's build output on disk, and the baseline attribution probe
|
|
3836
|
+
then runs against it: in the reported incident a unit's own generated files
|
|
3837
|
+
failed the probe, and the driver concluded the failure predated the feature
|
|
3838
|
+
and halted a green branch.
|
|
3839
|
+
|
|
3840
|
+
Only files that appeared SINCE the snapshot are removed, which is what makes
|
|
3841
|
+
this safe for the expensive case raised on #3371: a build cache present at
|
|
3842
|
+
dispatch is in the snapshot and is never touched. Only what this attempt
|
|
3843
|
+
produced goes.
|
|
3844
|
+
|
|
3845
|
+
Never deletes: paths in *ignored_before*, anything under
|
|
3846
|
+
`IGNORED_CLEAN_KEEP_PREFIXES`, *events_path*, or a per-criterion close-state
|
|
3847
|
+
file -- the same exclusions its untracked twin honours.
|
|
3848
|
+
|
|
3849
|
+
Best-effort: any git or filesystem error is swallowed, reverting to the old
|
|
3850
|
+
leftover behaviour rather than crashing the run.
|
|
3851
|
+
"""
|
|
3852
|
+
try:
|
|
3853
|
+
root = Path(git("rev-parse", "--show-toplevel"))
|
|
3854
|
+
candidates = ignored_paths() - set(ignored_before)
|
|
3855
|
+
except (subprocess.CalledProcessError, OSError):
|
|
3856
|
+
return
|
|
3857
|
+
try:
|
|
3858
|
+
keep = events_path.resolve()
|
|
3859
|
+
except OSError:
|
|
3860
|
+
keep = None
|
|
3861
|
+
for rel in sorted(candidates):
|
|
3862
|
+
if any(rel.startswith(p) or f"/{p}" in rel
|
|
3863
|
+
for p in IGNORED_CLEAN_KEEP_PREFIXES):
|
|
3864
|
+
continue
|
|
3865
|
+
target = root / rel
|
|
3866
|
+
try:
|
|
3867
|
+
if keep is not None and target.resolve() == keep:
|
|
3868
|
+
continue
|
|
3869
|
+
if criteria_state.CRITERIA_FILENAME_RE.match(target.name):
|
|
3870
|
+
continue
|
|
3871
|
+
if target.is_file() or target.is_symlink():
|
|
3872
|
+
target.unlink()
|
|
3873
|
+
except OSError:
|
|
3874
|
+
continue
|
|
3875
|
+
|
|
3876
|
+
|
|
3790
3877
|
def reset_preserving_events(
|
|
3791
3878
|
head_before: str,
|
|
3792
3879
|
events_path: Path,
|
|
3793
3880
|
untracked_before: "set[str] | frozenset[str] | None" = None,
|
|
3881
|
+
ignored_before: "set[str] | frozenset[str] | None" = None,
|
|
3794
3882
|
) -> None:
|
|
3795
3883
|
"""`git reset --hard <head_before>` without losing events.jsonl content.
|
|
3796
3884
|
|
|
@@ -3828,6 +3916,12 @@ def reset_preserving_events(
|
|
|
3828
3916
|
nothing untracked" and delete the entire untracked working tree; `None`
|
|
3829
3917
|
means "no snapshot available, do not clean" and preserves the pre-#162
|
|
3830
3918
|
behavior for callers that cannot supply one.
|
|
3919
|
+
|
|
3920
|
+
`ignored_before` (#3330 defect 1) does the same for GITIGNORED paths, and
|
|
3921
|
+
is supplied by the one call site whose reset is followed by the baseline
|
|
3922
|
+
attribution probe. Same inert-on-`None` contract. It is not passed on every
|
|
3923
|
+
reset: the listing it diffs walks ignored trees, which is cheap beside the
|
|
3924
|
+
gate-set run the probe performs and not worth paying where nothing probes.
|
|
3831
3925
|
"""
|
|
3832
3926
|
saved = events_path.read_text() if events_path.is_file() else None
|
|
3833
3927
|
git("reset", "--hard", head_before)
|
|
@@ -3835,6 +3929,8 @@ def reset_preserving_events(
|
|
|
3835
3929
|
events_path.write_text(saved)
|
|
3836
3930
|
if untracked_before is not None:
|
|
3837
3931
|
_clean_attempt_untracked(untracked_before, events_path)
|
|
3932
|
+
if ignored_before is not None:
|
|
3933
|
+
_clean_attempt_ignored(ignored_before, events_path)
|
|
3838
3934
|
|
|
3839
3935
|
|
|
3840
3936
|
def retain_tree_after_refusal(head_before: str, events_path: Path) -> str:
|
|
@@ -6485,6 +6581,7 @@ def baseline_evidence_diffstat(feat_fm: dict) -> "str | None":
|
|
|
6485
6581
|
def format_preexisting_gate_failure(
|
|
6486
6582
|
gate_number: int, failing_gates: list[dict], feat_fm: dict,
|
|
6487
6583
|
done_unit_ids: "list[str] | None" = None,
|
|
6584
|
+
attributed_to: "str | None" = None,
|
|
6488
6585
|
) -> str:
|
|
6489
6586
|
"""Render the `preexisting_gate_failure` halt as a message a non-expert
|
|
6490
6587
|
operator can act on without reading driver source (FEAT-2026-0051/T03).
|
|
@@ -6497,6 +6594,22 @@ def format_preexisting_gate_failure(
|
|
|
6497
6594
|
defer the feature. There is no "proceed anyway" option in v1: the waiver
|
|
6498
6595
|
is future work tracked as FEAT-2026-0052, never offered here as if it
|
|
6499
6596
|
already existed.
|
|
6597
|
+
|
|
6598
|
+
`attributed_to` names the work unit whose failed attempt triggered the
|
|
6599
|
+
probe (#3330 defect 2). This message was written for a gate-entry probe,
|
|
6600
|
+
where "zero work units were dispatched" was true; FEAT-2026-0109/T01 then
|
|
6601
|
+
removed that probe, leaving attribution as the only path that renders it --
|
|
6602
|
+
and on that path a unit *was* dispatched and its failure is what caused the
|
|
6603
|
+
re-run. Left unsaid, every fresh-gate claim here is false exactly when the
|
|
6604
|
+
message is shown.
|
|
6605
|
+
|
|
6606
|
+
The proof is softened on every path (#3371). A `git diff --stat` compares
|
|
6607
|
+
TRACKED files, so it cannot see a check's gitignored inputs; `git reset
|
|
6608
|
+
--hard` restores tracked files and leaves ignored ones behind, which is how
|
|
6609
|
+
a failed attempt's own build output ends up failing the probe that is
|
|
6610
|
+
supposed to exonerate it. Stating "the failure predates this feature" from
|
|
6611
|
+
that diff reads as conclusive and cost one reported incident a bisect
|
|
6612
|
+
across three commits.
|
|
6500
6613
|
"""
|
|
6501
6614
|
# A RESUMED gate -- one where work units already ran and committed -- has a
|
|
6502
6615
|
# baseline that INCLUDES this feature's own landed work, so the fresh-gate
|
|
@@ -6505,8 +6618,17 @@ def format_preexisting_gate_failure(
|
|
|
6505
6618
|
# that a previous unit of the same gate had added two commits earlier.
|
|
6506
6619
|
done_unit_ids = list(done_unit_ids or [])
|
|
6507
6620
|
resumed = bool(done_unit_ids)
|
|
6621
|
+
attributed = bool(attributed_to) and not resumed
|
|
6508
6622
|
|
|
6509
|
-
if
|
|
6623
|
+
if attributed:
|
|
6624
|
+
lines = [
|
|
6625
|
+
f"Gate {gate_number} is blocked: the automated checks it depends "
|
|
6626
|
+
f"on failed on a probe the driver ran AFTER {attributed_to}'s "
|
|
6627
|
+
f"attempt failed and its changes were reset.",
|
|
6628
|
+
"",
|
|
6629
|
+
"Failing check(s) found by that probe:",
|
|
6630
|
+
]
|
|
6631
|
+
elif resumed:
|
|
6510
6632
|
lines = [
|
|
6511
6633
|
f"Gate {gate_number} is blocked: the automated checks it depends on "
|
|
6512
6634
|
f"are failing, and this gate has ALREADY LANDED WORK.",
|
|
@@ -6526,7 +6648,14 @@ def format_preexisting_gate_failure(
|
|
|
6526
6648
|
f"(signature: {g['failure_signature']})"
|
|
6527
6649
|
)
|
|
6528
6650
|
lines.append("")
|
|
6529
|
-
if
|
|
6651
|
+
if attributed:
|
|
6652
|
+
lines.append(
|
|
6653
|
+
f"{attributed_to} WAS dispatched and its attempt failed. The "
|
|
6654
|
+
f"driver then reset the tree and re-ran the checks to ask whether "
|
|
6655
|
+
f"the failure predated that attempt; the result above is what "
|
|
6656
|
+
f"that probe found."
|
|
6657
|
+
)
|
|
6658
|
+
elif resumed:
|
|
6530
6659
|
lines.append(
|
|
6531
6660
|
f"{len(done_unit_ids)} work unit(s) in this gate are already `done` "
|
|
6532
6661
|
f"and committed, so the baseline these checks measured includes this "
|
|
@@ -6554,12 +6683,16 @@ def format_preexisting_gate_failure(
|
|
|
6554
6683
|
)
|
|
6555
6684
|
else:
|
|
6556
6685
|
lines.append(
|
|
6557
|
-
"
|
|
6558
|
-
"the integration branch (
|
|
6559
|
-
"
|
|
6560
|
-
"files, not code the failing check(s) read):"
|
|
6686
|
+
"The failing check(s)' TRACKED input files are unchanged vs "
|
|
6687
|
+
"the integration branch (the diff below is the feature's own "
|
|
6688
|
+
"plan/scaffold files, not code the failing check(s) read):"
|
|
6561
6689
|
)
|
|
6562
6690
|
lines.append(diffstat)
|
|
6691
|
+
elif attributed:
|
|
6692
|
+
lines.append(
|
|
6693
|
+
"Base-tree comparison unavailable (no integration branch could "
|
|
6694
|
+
"be resolved, or the comparison itself failed)."
|
|
6695
|
+
)
|
|
6563
6696
|
else:
|
|
6564
6697
|
lines.append(
|
|
6565
6698
|
"Base-tree comparison unavailable (no integration branch could "
|
|
@@ -6567,9 +6700,41 @@ def format_preexisting_gate_failure(
|
|
|
6567
6700
|
"check(s) above were still measured before any work unit ran, "
|
|
6568
6701
|
"so the conclusion stands even without this proof."
|
|
6569
6702
|
)
|
|
6703
|
+
if not resumed:
|
|
6704
|
+
# The limit of the proof above, stated wherever it is offered (#3371).
|
|
6705
|
+
# A tracked diff is consistent with BOTH "pre-existing" and "left
|
|
6706
|
+
# behind by this run", so naming what it cannot see is the difference
|
|
6707
|
+
# between a reader checking `out/` first and bisecting the branch.
|
|
6708
|
+
lines.append("")
|
|
6709
|
+
lines.append(
|
|
6710
|
+
"What that comparison does NOT cover: untracked and gitignored "
|
|
6711
|
+
"paths. `git reset --hard` restores tracked files and leaves "
|
|
6712
|
+
"ignored ones in place, so a check that reads a build or output "
|
|
6713
|
+
"directory (`out/`, `target/`, generated-code trees, caches) can "
|
|
6714
|
+
"fail on state this feature's own failed attempt produced. The "
|
|
6715
|
+
"diff above cannot distinguish that from pre-existing breakage."
|
|
6716
|
+
)
|
|
6570
6717
|
lines.append("")
|
|
6571
6718
|
lines.append("What to do next:")
|
|
6572
|
-
if
|
|
6719
|
+
if attributed:
|
|
6720
|
+
lines.append(
|
|
6721
|
+
" 1. Check for leftover untracked/ignored state from the reset "
|
|
6722
|
+
"attempt FIRST — it is the cheapest to rule out and the most "
|
|
6723
|
+
"likely cause. `git status --ignored --short` and `git clean -ndX` "
|
|
6724
|
+
"list what survived; if a listed path feeds a failing check, that "
|
|
6725
|
+
"is your answer."
|
|
6726
|
+
)
|
|
6727
|
+
lines.append(
|
|
6728
|
+
" 2. Only if the tree is clean of those is this pre-existing "
|
|
6729
|
+
"debt — confirm by running the failing check(s) on the "
|
|
6730
|
+
"integration branch in a fresh checkout before assuming it."
|
|
6731
|
+
)
|
|
6732
|
+
lines.append(
|
|
6733
|
+
f" 3. If it was leftover state, remove it and re-run; "
|
|
6734
|
+
f"{attributed_to} is back at its previous attempt count and will "
|
|
6735
|
+
f"be retried."
|
|
6736
|
+
)
|
|
6737
|
+
elif resumed:
|
|
6573
6738
|
lines.append(
|
|
6574
6739
|
" 1. Find which of this gate's landed work units introduced the "
|
|
6575
6740
|
"failing check, and fix it ON THIS BRANCH. `git log -S<signature> "
|
|
@@ -10671,6 +10836,13 @@ def run(
|
|
|
10671
10836
|
# (#150). Captured here, not inside squash_commit, because by
|
|
10672
10837
|
# then the agent's own new files are indistinguishable from it.
|
|
10673
10838
|
untracked_before = untracked_paths()
|
|
10839
|
+
# Ignored counterpart (#3330 defect 1), taken in the same
|
|
10840
|
+
# breath: only the attempt-failure reset that precedes the
|
|
10841
|
+
# baseline attribution probe consumes it, but it has to be
|
|
10842
|
+
# captured HERE, before the agent runs, or the attempt's own
|
|
10843
|
+
# build output is already indistinguishable from what was
|
|
10844
|
+
# on disk when it started.
|
|
10845
|
+
ignored_before = ignored_paths()
|
|
10674
10846
|
_is_rearm = detect_rearm_dispatch(wu)
|
|
10675
10847
|
if _is_rearm:
|
|
10676
10848
|
fold_cumulative_on_rearm(wu, backend)
|
|
@@ -11646,9 +11818,15 @@ def run(
|
|
|
11646
11818
|
untracked_before=untracked_before)
|
|
11647
11819
|
print(" no FINDINGS metric — reset to base")
|
|
11648
11820
|
else:
|
|
11821
|
+
# `ignored_before` is passed HERE and nowhere else: this
|
|
11822
|
+
# is the one reset whose tree is then measured by the
|
|
11823
|
+
# attribution probe below, so it is the one place where
|
|
11824
|
+
# the attempt's own gitignored output would be read as
|
|
11825
|
+
# pre-existing breakage (#3330 defect 1).
|
|
11649
11826
|
reset_preserving_events(
|
|
11650
11827
|
head_before, events_path,
|
|
11651
|
-
untracked_before=untracked_before
|
|
11828
|
+
untracked_before=untracked_before,
|
|
11829
|
+
ignored_before=ignored_before)
|
|
11652
11830
|
# Retroactive baseline attribution (FEAT-2026-0109/T01):
|
|
11653
11831
|
# decide, right after the reset above restores the
|
|
11654
11832
|
# tree the unit was dispatched against, whether this
|
|
@@ -11685,7 +11863,8 @@ def run(
|
|
|
11685
11863
|
gate.number, _attr_failing, feat_fm,
|
|
11686
11864
|
done_unit_ids=[
|
|
11687
11865
|
u.wu_id for u in units
|
|
11688
|
-
if u.status == "done"]
|
|
11866
|
+
if u.status == "done"],
|
|
11867
|
+
attributed_to=wu.wu_id))
|
|
11689
11868
|
wu_events.append(build_event(
|
|
11690
11869
|
"human_escalation", feature_id, {
|
|
11691
11870
|
"reason": "preexisting_gate_failure",
|
|
@@ -25,7 +25,11 @@ import json
|
|
|
25
25
|
import re
|
|
26
26
|
from typing import Callable, Optional
|
|
27
27
|
|
|
28
|
-
from specfuse.loop.agent_policy import
|
|
28
|
+
from specfuse.loop.agent_policy import (
|
|
29
|
+
SEVERITY_LABEL_PREFIX,
|
|
30
|
+
SEVERITY_VALUES,
|
|
31
|
+
read_severity_label,
|
|
32
|
+
)
|
|
29
33
|
from specfuse.loop.escalation import CATEGORY_LABELS, NEEDS_HUMAN_LABEL
|
|
30
34
|
from specfuse.monitor.issues import DEFAULT_LIST_LIMIT, has_finding_marker
|
|
31
35
|
|
|
@@ -359,6 +363,88 @@ def list_untriaged(runner: Callable, repo: str, limit: int = DEFAULT_LIST_LIMIT)
|
|
|
359
363
|
_BACKFILL_PAGE_SIZE = DEFAULT_LIST_LIMIT
|
|
360
364
|
|
|
361
365
|
|
|
366
|
+
#: What a backfill run should do with one candidate's severity (#3360).
|
|
367
|
+
SEVERITY_CLASSIFY = "classify"
|
|
368
|
+
SEVERITY_RECONCILE = "reconcile"
|
|
369
|
+
SEVERITY_SKIP = "skip"
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def _severity_label_names(labels) -> list:
|
|
373
|
+
"""The `severity:*` label names on an issue, however `labels` is shaped.
|
|
374
|
+
|
|
375
|
+
`gh issue list --json ...,labels` yields `{"name": ...}` mappings; callers
|
|
376
|
+
holding bare strings are accepted too so the decision below stays testable
|
|
377
|
+
without a fixture shape.
|
|
378
|
+
"""
|
|
379
|
+
names = []
|
|
380
|
+
for label in labels or ():
|
|
381
|
+
name = label.get("name") if isinstance(label, dict) else label
|
|
382
|
+
text = str(name or "").strip().lower()
|
|
383
|
+
if text.startswith(SEVERITY_LABEL_PREFIX):
|
|
384
|
+
names.append(text)
|
|
385
|
+
return names
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def severity_decision(labels, aliases: Optional[dict] = None) -> tuple:
|
|
389
|
+
"""`(action, severity, reason)` for one backfill candidate (#3360).
|
|
390
|
+
|
|
391
|
+
A candidate is selected on its MARKER -- already triaged, no `severity=`
|
|
392
|
+
field. That predicate never looked at the issue's labels, so an issue a
|
|
393
|
+
person had already labelled `severity:minor` was still a candidate: it got
|
|
394
|
+
a fresh classification, and the write path added a second severity label
|
|
395
|
+
beside the human's. `read_severity_label` then returns whichever it
|
|
396
|
+
recognises first, which is the agent silently overriding a person at the
|
|
397
|
+
`min_severity` floor.
|
|
398
|
+
|
|
399
|
+
So the label is consulted first, and when it states a severity the marker is
|
|
400
|
+
written FROM it:
|
|
401
|
+
|
|
402
|
+
* `SEVERITY_RECONCILE` -- the labels agree on one value. The issue stops
|
|
403
|
+
being stranded *and* the person's judgement is what gets recorded. No
|
|
404
|
+
classification session is spent, and no label is written, because the
|
|
405
|
+
label is already there and is the source.
|
|
406
|
+
* `SEVERITY_CLASSIFY` -- no `severity:*` label at all. The original path.
|
|
407
|
+
* `SEVERITY_SKIP` -- the labels resolve to more than one value (the
|
|
408
|
+
operator's own ambiguity), or a `severity:*` label is present that
|
|
409
|
+
nothing can read. Classifying either would put a second, readable label
|
|
410
|
+
beside one a human chose, which is the collision in a different spelling.
|
|
411
|
+
|
|
412
|
+
This was latent when FEAT-2026-0113 closed: the measured repository's
|
|
413
|
+
`critical`/`major`/`minor` scheme yielded a one-entry rubric, so the
|
|
414
|
+
classifier failed closed on exactly the issues that would have collided.
|
|
415
|
+
Shipping the default alias table (#3355) made that scheme readable, which
|
|
416
|
+
removed the mask rather than the hazard.
|
|
417
|
+
"""
|
|
418
|
+
names = _severity_label_names(labels)
|
|
419
|
+
if not names:
|
|
420
|
+
return (SEVERITY_CLASSIFY, None, None)
|
|
421
|
+
|
|
422
|
+
resolved = set()
|
|
423
|
+
unreadable = []
|
|
424
|
+
for name in names:
|
|
425
|
+
value, _aliased_from = read_severity_label([name], aliases)
|
|
426
|
+
if value in SEVERITY_VALUES:
|
|
427
|
+
resolved.add(value)
|
|
428
|
+
else:
|
|
429
|
+
unreadable.append(name)
|
|
430
|
+
|
|
431
|
+
if len(resolved) > 1:
|
|
432
|
+
return (
|
|
433
|
+
SEVERITY_SKIP,
|
|
434
|
+
None,
|
|
435
|
+
f"labels resolve to more than one severity ({', '.join(sorted(resolved))}) "
|
|
436
|
+
f"— the marker is left alone rather than picking one",
|
|
437
|
+
)
|
|
438
|
+
if not resolved:
|
|
439
|
+
return (
|
|
440
|
+
SEVERITY_SKIP,
|
|
441
|
+
None,
|
|
442
|
+
f"carries {', '.join(sorted(unreadable))}, which no vocabulary value "
|
|
443
|
+
f"or alias reads — a person's judgement this run cannot interpret",
|
|
444
|
+
)
|
|
445
|
+
return (SEVERITY_RECONCILE, resolved.pop(), None)
|
|
446
|
+
|
|
447
|
+
|
|
362
448
|
def _is_backfill_candidate(issue: dict) -> bool:
|
|
363
449
|
body = issue.get("body") or ""
|
|
364
450
|
fields = parse_marker_fields(body)
|
|
@@ -196,6 +196,7 @@ tests/test_attempt_outcome_emission.py
|
|
|
196
196
|
tests/test_attention_nonwriting_guard.py
|
|
197
197
|
tests/test_attention_silence_section.py
|
|
198
198
|
tests/test_attention_skill_structure.py
|
|
199
|
+
tests/test_attribution_halt_claims.py
|
|
199
200
|
tests/test_autoclose_deferral_visibility.py
|
|
200
201
|
tests/test_autoclose_gate_note.py
|
|
201
202
|
tests/test_autoclose_stub_states_what_passed.py
|
|
@@ -369,6 +370,7 @@ tests/test_human_output_rule.py
|
|
|
369
370
|
tests/test_human_work_unit.py
|
|
370
371
|
tests/test_hygiene_boundary_guidance.py
|
|
371
372
|
tests/test_hyphenated_gate_name.py
|
|
373
|
+
tests/test_ignored_cleanup_before_probe.py
|
|
372
374
|
tests/test_init_integration.py
|
|
373
375
|
tests/test_installed_copy_driver_e2e.py
|
|
374
376
|
tests/test_interpreter_normalization.py
|
|
@@ -558,6 +560,7 @@ tests/test_severity_backfill_limit.py
|
|
|
558
560
|
tests/test_severity_backfill_marker.py
|
|
559
561
|
tests/test_severity_backfill_run.py
|
|
560
562
|
tests/test_severity_label_projection.py
|
|
563
|
+
tests/test_severity_reconciliation.py
|
|
561
564
|
tests/test_severity_rubric.py
|
|
562
565
|
tests/test_shipped_templates_parse.py
|
|
563
566
|
tests/test_skill_discovery_links.py
|