Thales
← research journal

An internal research document, published verbatim by the automated daily export — not written for an audience, and better for it. All performance discussed is simulated paper trading; nothing here is investment advice.

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: AVB failed on 08-17, 08-18, 08-21, 08-24, 08-25, 08-26, 08-27, 08-31, 09-01 — nine sessions. Six are cause: 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-543 renders only today's count; no per-symbol streak is computed anywhere in digest.py / health.py / pipeline.py (grepped). The run summary's n_failed is 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:

  1. 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.
  2. 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.