FOS-1 — a per-symbol failed-order streak is indistinguishable from a one-off failure: AVB has failed 9 consecutive sessions, six of them the EMERGENCY-EXIT path, and no channel escalates
status: open · raised panel run 17 (2026-09-02) · class: loudness & safety (G2, observability layer — change-review catch, does NOT count toward the frontier cadence) · judgement: YES · effort ~0.25–0.5 pd · horizon: live now; concentrates before December (the gate's TCA/exit reading assumes exits execute)
Plain-language summary for an owner reading one paragraph. The daily
digest reports order failures as a bare count: !! N FAILED orders. A
failure that repeats for the same name every session is a different
condition than N one-off failures — it means the book structurally cannot
express an exit — and the digest cannot tell the two apart. The live case:
meanrev has failed to sell AVB for nine consecutive sessions, and since
08-21 the failing order is the emergency-exit path — the machinery that
exists for getting out of a name is itself standing-unable to act, and
nothing anywhere says so distinctly. EXQ-1's BUILT note already recorded
the consequence in so many words: the failed-order line "has become
permanent furniture — a real new failure would now hide behind it." That
observation was recorded twice (EXQ-1 BUILT 08-26, RESEARCH.md banner) but
never queued; this row is its decision point.
Mechanism — ground truth re-verified this run at HEAD ebce244
data/state/meanrev/order_log.jsonl: AVBfailedon 08-17, 08-18, 08-21, 08-24, 08-25, 08-26, 08-27, 08-31, 09-01 — nine sessions. Six arecause: emergency_exit(identical qty 119.836203 since 08-21). One, 08-27, is a failed BUY (cause: selection) — the selection path re-buying a broker-not-active name, the same wedge from the other side.src/thales/execution/digest.py:542-543renders only today's count; no per-symbol streak is computed anywhere indigest.py/health.py/pipeline.py(grepped). The run summary'sn_failedis likewise a daily scalar.- Prior handling, cited so this row cannot be read as relitigation: panel
run 9 routed the day-2 recurrence to the daily audit ("a third identical
day would mean the negative control is standing-unable to express two of
its names — the audit's to adjudicate"); the audit adjudicated AVB as a
broker-side chore (Alpaca
40010001 asset not active; EXQ-1 ops note: "Broker-side action, owner" — that ruling STANDS and this row does not touch it). What was never adjudicated is the detector: BRK-B's leg was fixed by EXQ-1's symbology, the AVB position waits on the owner, and meanwhile the alerting layer has demonstrated exactly the failure mode the shop's doctrine names — a red that became furniture. - Why it matters beyond the control sleeve: the code path is shared. On momentum the same silence is a stuck live position that never pages; the December gate reads TCA and safety-HALT history on the assumption that exits execute.
Fix shape (propose-only)
Per-symbol consecutive-failure streak computed from the order log at digest
time (no new state file): the digest line distinguishes standing streaks
from fresh failures — e.g. !! 1 FAILED order (1 standing ≥3 sessions: AVB x9)
vs a NEW symbol entering failed state, which fires the normal attention
channel instead of folding into the furniture line. An emergency_exit
failure renders as its own line: the emergency machinery failing is a
louder condition than a selection order failing.
Test design + negative control
Fixture order log with a 3-session streak plus a fresh same-day failure → the rendered digest must name both distinctly; revert the streak computation → red. A log where the streak symbol fills on day 4 → streak resets to zero (the detector can fail — CQA-1 doctrine). No trading path, no config value, no pinned rule.
Kill criterion — pre-registered
Two exits, either closes the row:
- Decoration kill: if six months after building, the streak line has neither changed an owner action nor distinguished any real event the flat count would have hidden, remove it and record that the flat count was sufficient all along.
- Ruling kill: if the owner rules the flat digest line + daily-audit adjudication IS the intended channel, dismiss with that ruling recorded. Reopen condition: the first time a NEW failure is discovered late because it hid behind a standing streak.
Zero registry rows, zero DSR debt.
Built — recorded 2026-09-06 (with IGD-1 leg 3, under the owner's ruling)
Shipped (code PR #154). execution/failed_streaks.py computes per-symbol
consecutive-failure streaks at digest time from the order log — no new state
file — over the sessions the sleeve actually RAN (run-summary dates), so a
missed day neither breaks nor extends a streak; a fill resets it; a
market-replace re-log is ignored. The digest line now reads
!! 2 FAILED orders — 1 NEW: XYZ [selection]; 1 standing: AVB x9 [emergency_exit], an emergency-exit streak gets its own line ("the exit
machinery itself cannot act on this name"), the HTML twin carries the same
summary, and a NEW de-risking failure turns the subject 🔴 (a standing streak
stays ⚠️). Rider from OSR-1: every failed order record now carries the
broker's rejection text (error), so the streak is diagnosable from the
ledger — none of the 19 failed records before this carried a reason.
The escalation rule the owner chose (IGD-1 leg 3): thales run exits 4
when a de-risking order (sell, or an order-intent close) fails for a symbol
that was NOT already failing in the previous session; standing streaks exit 0
and live on this digest line. The workflows run set -o pipefail and persist
state if: always(), so the red reaches CI without losing the day's state.
Test design — met (tests/test_execution/test_digest.py,
test_failed_streaks.py): a 3-session AVB streak plus a fresh XYZ failure
render distinctly; a name that fills on day 4 resets to no streak; a standing
streak alone is amber, not red; the rule escalates a fresh sell and a VRP
close but not a fresh buy or a standing sell.
Kill criterion — armed, not tripped: the decoration kill (six months, no owner action changed) is dated 2027-03-06.
Route — recorded honestly: built on the owner's direct instruction in the
2026-09-06 interactive session, NOT via queue/approved/; the guard denies
the open→built rename, so a human merges.