Follow-up from #374 (T2 of the burst-capacity-safety plan), which made deadline auto-holds
visible at the three sites that go through _maybe_apply_timeout.
ExternalBacktestSession.submit_decisions() has a fourth, independent deadline check that
bypasses _maybe_apply_timeout entirely, so the hold it creates prints nothing:
# dashboard/backend/domain/backtesting/external_run_service.py:~514
if _utcnow() > self._deadline_at():
self._advance_step(executable=[], decision_source="timeout_hold")
Traced all three production callers of session.submit_decisions(...):
| caller |
preceded by an instrumented call? |
domain/runs/service.py:909 — /api/v1/runs/* (shipping SDK) |
yes — get_status() pre-empts this branch under the same lock |
api/routers/external_backtest.py:212 — legacy /api/v1/backtest/* (Discord bot, built-in agents) |
no — silent |
api/v2/runs.py:303 → execution/backtest_backend.py:226 — canonical v2 contract |
no — silent |
Both silent paths are ordinary GET-then-POST flows where the deadline elapses in the gap, which
is exactly the case the feature exists to surface. The periodic reaper does not cover it either:
submit_decisions has already advanced the step, so drain_expired finds nothing expired.
Suggested fix: call the same emit helper #374 added, from this branch too — a couple of lines,
no wire-contract change. Left out of #374 deliberately because the plan scoped that task to
exactly three sites.
Follow-up from #374 (T2 of the burst-capacity-safety plan), which made deadline auto-holds
visible at the three sites that go through
_maybe_apply_timeout.ExternalBacktestSession.submit_decisions()has a fourth, independent deadline check thatbypasses
_maybe_apply_timeoutentirely, so the hold it creates prints nothing:Traced all three production callers of
session.submit_decisions(...):domain/runs/service.py:909—/api/v1/runs/*(shipping SDK)get_status()pre-empts this branch under the same lockapi/routers/external_backtest.py:212— legacy/api/v1/backtest/*(Discord bot, built-in agents)api/v2/runs.py:303→execution/backtest_backend.py:226— canonical v2 contractBoth silent paths are ordinary GET-then-POST flows where the deadline elapses in the gap, which
is exactly the case the feature exists to surface. The periodic reaper does not cover it either:
submit_decisionshas already advanced the step, sodrain_expiredfinds nothing expired.Suggested fix: call the same emit helper #374 added, from this branch too — a couple of lines,
no wire-contract change. Left out of #374 deliberately because the plan scoped that task to
exactly three sites.