[Senate] Waste detector — auto-archive tasks abandoned 3+ times

← All Specs

Goal

The 2026-04-24 recurring-block incident
(project_orchestra_recurring_block_incident) showed 165 tasks burning
slots with zero output. aa8c3204_2746's "Wasted Resources" section
flags individual high-cost-low-impact tasks but doesn't act. Build a
detector that, when a task has been picked up by 3+ slots without a
landed commit (no task_runs.commit_sha row), automatically archives
it with a waste_archived status, refunds the bidder's wallet, and
emits a Senate proposal asking a human to spec-rewrite or kill it.

Acceptance Criteria

scidex/senate/waste_detector.py::scan() -> list[WasteCandidate] with fields (task_id, attempt_count, total_tokens_burned, last_failure_reason).
☐ A task counts as "abandoned" when count(task_runs WHERE task_id = T AND finished_at IS NOT NULL AND commit_sha IS NULL) >= 3 AND no successful run in last 14 days.
☐ When auto-archived: status → waste_archived, write a row to waste_archive_log with full attempt history, refund wallet via token_ledger.refund_task_cost(task_id).
☐ Senate proposal waste_review enumerates the candidates and links to the spec file for human-readable triage.
☐ Cron daily at 04:00 UTC; dry-run flag in env (WASTE_DETECTOR_DRY_RUN=1) defaults to 0 only after a 7-day shadow period (logged decisions but no archive).
/senate adds "Waste Archive" tab listing last 90 days of auto-archives with un-archive button.
☐ Test: insert 3 failed task_runs for a task; scan returns it; archive sets status and refund; un-archive restores open.

Approach

  • Read existing archive lifecycle code paths in orchestra/services.py to ensure we don't break audit trails.
  • Use task_runs.commit_sha IS NULL AND finished_at IS NOT NULL as the abandonment signal — avoids racing with in-flight runs.
  • Refund logic: sum cost_ledger.cost_usd for the task's runs and credit the spawning quest's wallet.
  • Senate proposal references waste_archive_log.id so the human can see the full history without 3 SQL hops.
  • Dependencies

    • 2147d16ef177 (wallets) for refund.
    • task_runs table from Orchestra (existing).

    Work Log

    2026-04-27 — Implementation

    Files created/modified:

    • scidex/senate/waste_detector.py — core module with scan(), archive_waste(),
    unarchive_task(), run_once(), get_archive_log(); WasteCandidate dataclass;
    ensure_tables() for waste_archive_log.
    • tests/test_waste_detector.py — 10 tests covering scan, archive, dry-run, unarchive,
    and full pipeline; all pass.
    • api_routes/senate.py — added POST /api/senate/waste-detector/run,
    GET /api/senate/waste-archive, POST /api/senate/waste-archive/{task_id}/unarchive.
    • scidex/senate/scheduled_tasks.py — registered senate.waste_detector as a daily
    (1440 min) scheduled task.
    • api.py — added GET /senate/waste-archive page route with un-archive buttons;
    added link in About The Senate section.

    Implementation notes:

    • Orchestra valid task statuses don't include waste_archived; used archived instead
    and tracked waste-specific metadata in waste_archive_log (SciDEX PostgreSQL).
    • Abandonment signal: task_runs.ended_at IS NOT NULL AND task_runs.last_commit_sha
    IN ('', NULL) AND status IN (abandoned, failed, aborted, rate_limited),
    count >= 3, no successful run in 14 days.
    • Senate proposal uses quality_gate proposal type (only valid type that fits).
    • WASTE_DETECTOR_DRY_RUN defaults to "1" (shadow period); set to "0" to activate.
    • Best-effort token refund via token_ledger; no-op when billing is disabled.

    Tasks using this spec (1)
    [Senate] Waste detector - auto-archive tasks abandoned 3+ ti
    File: q-ri-waste-detector_spec.md
    Modified: 2026-05-01 20:13
    Size: 3.7 KB