# 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.
