Baseline {BLE001: 351, S110: 79} (was 455/117): 103 handlers in
memory_store.py, warm_router.py, curator.py, tool_executor.py now log
tracebacks via logger.debug(.., exc_info=True) or carry reasoned
# noqa: BLE001 (warm_router P0-06 record_failure paths). Ledger table
regenerated from the live tree; Completion Record appended to the plan.
2.8 KiB
Silent-handler debt ledger (#126)
Tracked, not silent — the repo's doctrine for known debt (same pattern as
module-coverage-debt.md and the pyright baseline). The lint ratchet
(scripts/lint_ratchet.py, wired into the CI lint job) counts S110
(try-except-pass) and BLE001 (blind except Exception) over src/,
shared/, scripts/ and fails when any count exceeds lint-baseline.json.
Rule: this ledger only shrinks. A handler leaves the ledger by becoming
compliant: re-raise, or log the traceback (.exception() / exc_info=True —
BLE001's built-in exemptions ARE the compliant-handler spec), or carry
# noqa: BLE001 — <reason> where silence is genuinely intentional (e.g.
best-effort cleanup, or the failure already routes through a designed
observable channel such as subsystem_health.record_failure). New silent
handlers fail CI; the baseline may never be raised to admit new debt.
T201 (print) was measured during the #126 sweep (1625 hits) but is out of the handler-visibility scope and is NOT enforced.
Mechanism
lint-baseline.json is the machine ledger ({BLE001, S110} counts);
tests/test_ci_lint_contract.py::test_lint_baseline_matches_current_tree_counts
pins it to reality, so every fix must lower the baseline in the same commit.
Remaining debt (as of 2026-09-07, post-#126 — BLE001 351 / S110 79 = 430)
Paid this PR (#126): memory_store.py, warm_router.py, curator.py,
tool_executor.py (142 handler sites — the four core non-TUI files; 3 of
warm_router's P0-06 record_failure handlers carry reasoned
# noqa: BLE001 instead).
Still ledgered (top first, per-file S110+BLE001 counts):
| File | Count |
|---|---|
| src/rune/rune_tui.py | 125 |
| src/rune/rune_operator.py | 23 |
| src/rune/sleep_time.py | 19 |
| src/rune/memory_consolidation.py | 15 |
| src/rune/work_manager.py | 12 |
| src/rune/canary_tui_drift.py | 10 |
| src/rune/auto_context.py | 8 |
| src/rune/provider_registry.py | 7 |
| src/rune/night_mode.py | 7 |
| src/rune/growth_delta.py | 7 |
| src/rune/contracts.py | 7 |
| src/rune/system_registry.py | 6 |
| src/rune/skills/llm-craft/update.py | 6 |
| src/rune/local_tool_runtime.py | 6 |
| src/rune/complexity_scorer.py | 6 |
| src/rune/capability_broker.py | 6 |
| src/rune/voicebox.py | 5 |
| src/rune/self_improve.py | 5 |
| src/rune/provider_budget.py | 5 |
| src/rune/persona_gate.py | 5 |
| src/rune/model_profiles.py | 5 |
| src/rune/drift_ledger.py | 5 |
| src/rune/canary_unbounded.py | 5 |
| src/rune/canary_query_memory.py | 5 |
| 39 further src/rune files | 81 |
| shared/ + scripts/ | 40 |
rune_tui.py is the largest block and is deliberately deferred from #126:
#139 just landed there and TUI handlers need UX-level judgement, not a
codemod. Every PR that pays handlers down must lower lint-baseline.json and
remove rows from this table in the same commit.