# FOS-2 — FOS-1's NEW-vs-STANDING split was built into the per-sleeve digest only; THE daily email still prints the flat furniture line, so AVB's 14-session standing failure reads exactly like a fresh one-off

status: open · raised 2026-09-09 (owner-side interactive session, reviewing #154 in the panel's absence — the change reviewer that would normally catch this was rate-limited dead 09-07…09-09) · class: truth divergence between layers (the AI-native audit's recurring class) · judgement: **YES** · effort ~0.25 pd · horizon: live every day; it silently un-does a guard merged 2026-09-07

---

**Plain-language summary for an owner reading one paragraph.** FOS-1 was
built to stop a repeating order failure from looking like a fresh one — a
name that has failed to sell for fourteen sessions is a structural
condition, a name that failed today is an event, and the flat line
`!! 1 FAILED order(s): AVB` cannot tell them apart. The split was
implemented in `digest.py`, which renders the **single-sleeve** digest
(`thales --sleeve meanrev portfolio digest`). The message that actually
reaches the operator is the **fleet** digest, and that renderer was not
touched. So the guard is real, tested, merged — and invisible in the only
channel anybody reads. The escalation half of FOS-1 (a *fresh* de-risking
failure exits 4 and fires the workflow alert) is intact and is not what
this row is about.

## Mechanism — ground truth measured at HEAD `ee68ebe`

- **Rendered, not inferred.** `thales fleet digest` run 2026-09-10 01:50 ET
  for session 2026-09-09 prints, in the MEANREV section:
  `!! 1 FAILED order(s): AVB` — no streak, no length, no cause. AVB's
  actual state that session: `cause: emergency_exit`, `status: failed`,
  fourteenth failed session since 2026-08-17, broker text
  `APIError: {"code":40010001,"message":"asset AVB is not active"}`.
- `src/thales/execution/fleet_digest.py:781-785` builds that line from
  `d["failed_orders"]` alone. `grep -n "failed_streaks|split_new_and_standing|failed_standing"
  src/thales/execution/fleet_digest.py` returns **nothing** — the module
  never imports FOS-1's machinery.
- `src/thales/execution/digest.py:120-132` gathers the split,
  `:516-528` formats it, `:590-591` renders the standing lines. That is the
  per-sleeve renderer, reached by a command a human must type.
- The escalation half is fine and stays out of scope: `cli.py:1176` raises
  `typer.Exit(4)` for de-risking orders failing *for the first time*. Both
  meanrev runs on 09-09 exited 0 correctly, because AVB is standing, not
  fresh.
- **The same divergence already happened once, and its scar is three lines
  above the defect.** `fleet_digest.py:777-779` carries the comment:
  *"Failed submissions must be visible in THE daily email (2026-07-20: a
  broker-rejected SATS buy was invisible here; only the standalone
  single-sleeve digest rendered it)."* A fix landed in the per-sleeve
  renderer and not the fleet one, was caught, was patched — and the next
  reporting feature took the identical wrong turn. That recurrence is the
  argument for a structural fix over a second patch.

## Why it matters beyond the control sleeve

The renderers are shared across sleeves. On momentum the same silence is a
stuck live position whose exit is standing-unable to execute, reported as
an ordinary count. The December gate reads TCA and safety-HALT history on
the assumption that exits execute; a standing exit failure that never
distinguishes itself is exactly the input that assumption cannot survive.

## Fix shape (propose-only)

**One formatter, two callers** — not a second copy of the logic. Lift the
new/standing formatting into a single function (`digest.py`'s
`_failed_detail` is already almost it) and have `fleet_digest.py` call it
with each sleeve's own order history and run summaries. A third renderer
added later then cannot diverge silently, which is the actual defect class.
The minimal alternative (duplicate the gather in `fleet_digest.py`) fixes
today's symptom and re-arms tomorrow's.

## Test design + negative control

Fixture order log with a ≥3-session streak on one symbol plus a fresh
same-day failure on another → the rendered **fleet** email must name both
distinctly (`1 NEW: XYZ [selection]; 1 standing: AVB x14 [emergency_exit]`).
**Negative control, shown in the PR:** revert the fleet renderer to the flat
line and assert the test fails. A control that passes against the bug is
decoration — the FOS-1 build note says so in its own words, and this row
exists because the thing it verified was not the thing the operator reads.

## Kill criterion (pre-registered)

If a path already exists by which the standing/new split reaches the daily
email — any path, including one this row missed — the item dies on that
evidence and is filed dismissed with the path named. If the shared-formatter
shape cannot be built without touching trading-path code, it drops to the
render-only fix and says so; it does not grow.

## Prior art

`research/queue/built/fos-1-per-symbol-failed-streak.md` (the guard this
row says is half-landed) and `research/queue/built/exq-1-batch-quote-fail-open.md`
(whose BUILT note first recorded the furniture line). The AVB position
itself is **not** relitigated: the daily audit adjudicated it a broker-side
owner chore (Alpaca `40010001 asset not active`), that ruling stands, and
nothing here touches it. This row is about the detector only.
