# RWG-1 — the runaway-order guard: phantom turnover-blend base on a HALT, and a blocked drawdown liquidation

status: open · raised panel run 11 (2026-08-20) · migrated 2026-08-24 (body verbatim below) · class: loudness & safety (live path) · judgement: **YES** · effort ~0.5–1 pd · **leg 1 was resolved by the owner 2026-08-20 — see the dated triage note at the foot**

---

**15. RWG-1 — the runaway-order guard has halted the meanrev control sleeve
two consecutive days (zero orders; the sell-count floor rose 44→149), the
halt path advances its own turnover-blend base while nothing executes
(unruled semantics), and a drawdown kill-switch liquidation of the current
196-name book would be blocked by the same guard — armed today, not
latent.** · judgement: **YES** · effort ~0.5–1 pd · horizon: live now (the
control is not trading; the phantom blend base compounds each halted day)

*Ground truth* (`data/state/meanrev/order_log.jsonl`): 08-19
`safety_halted: true`, "205 orders exceeds max 150 (runaway guard)",
`n_targets 209`, `n_submitted 0`; 08-20 same at **158 > 150**, `n_targets
161`, `n_submitted 0`; `selection_completed: false` both days; equity marks
continue on a frozen book (196 names, `portfolio_snapshots` 08-17→08-20:
173→185→196→196).

*Leg 1 — calibration is a policy call, and it is the owner's.* The guard
counts the **entire batch** with no de-risking exemption
(`safety.py:245-250`); the only de-risking exemption in the file
(`all_de_risking`, `safety.py:225`) gates the daily-loss breaker alone — so
CLAUDE.md's "de-risking is never blocked" is true only there and for
per-order REJECTs. `config/meanrev.yaml:128` pins `max_orders_per_run: 150`
as a bare copied value; the calibration comment behind 150 ("a full rebuild
is ~50-100 orders") lives in **momentum's** config (`settings.yaml:238`) —
a 50-name-sleeve number applied unmodified to a daily-churn sleeve holding
196 names against a 50-name selection (PC-1's unbounded growth, peak 2.92x).
Options, none pre-decided: **(a)** exempt all-sell batches from the count
guard (the guard's Knight-Capital rationale is amplification, mostly
buy-side — but a runaway-sell loop is a real class; this trades that
protection for guaranteed de-risking); **(b)** scale meanrev's
`max_orders_per_run` to its book (config VALUE — owner-only, the panel
proposes nothing here); **(c)** accept the wedge for the never-promotable
control and record that it trades only on sub-150-order days. Every code
path here is the fail-closed safety layer: the panel does not touch it.

*Leg 2 — the blend base advanced while nothing executed; rule the semantics
before the burst arrives.* `daily.py:1623-1634` persists `last_targets`
(the next day's turnover-blend base) **before** `execute_orders`
(`:1692`), guarded only by `dry_run` — no halt guard. Verified consequence:
`kelly_ledger.json` `last_targets` is dated 2026-08-20 with 161 weights
despite zero submissions, and `weighted_turnover` read **exactly 0.5000 =
the cap on both halted days — measured against the phantom base**, so the
intended book has walked two full cap-steps away from the real one; the
clearing day's realized weighted churn against the REAL book can approach
~1.0, far past the daily cap. (The 205→158 order-count decline is
phantom-target decay, not book convergence — sells rose 44→149 while
resizes shrank.) This is a **semantics divergence to rule, not a plain
bug**: the engine's own nearest analog retains the intended book in-cash
and re-enters uncapped (`engine.py:868-873`, `:657-666`), and the live
comment shows deliberate mimicry — but a safety HALT was unmodeled. Either
gate the persist on execution success, or record intended-book semantics
(and the post-halt burst) as deliberate; pin whichever ruling the owner
records with a test.

*Leg 3 — the same guard blocks the emergency exit, and on meanrev it is
armed now.* The drawdown kill-switch flat-to-cash path
(`daily.py:1089-1105`) routes through `pipeline.execute_orders` →
`_safety_gate` → the count guard, which exempts nothing: a liquidation of
any >150-name book HALTs. For meanrev's current 196-name book this is not
latent — its own kill switch firing today would be blocked (momentum at 63
names is clear). This contradicts the safety layer's own stated intent
("blocking a de-risking trade during a crash would leave the book exposed,
the opposite of fail-closed", `safety.py:216-219`) precisely in the
emergency it exists for. Compounding, same persist-before-execute class:
the kill-switch path **wipes the Kelly holding-return snapshot at
`daily.py:1101-1103` before `execute_orders`** — a halted liquidation
clears the snapshot while the book remains fully held. Legs 2+3 resolve in
the same fix-sitting as leg 1's policy call.

*Test design.* Leg 1 (if (a)): a 196-sell batch passes the count guard, a
196-mixed batch still halts; revert → red; regression: a simulated
kill-switch liquidation of a >150-name book reaches the broker. Leg 2: pin
the recorded ruling (halt → `last_targets` unmoved, **or** intended-book
semantics asserted with the burst documented); revert → red. Leg 3's
snapshot wipe: on a halted liquidation, the Kelly snapshot survives.

*Kill criterion — pre-registered.* **If by 2026-09-04 (10 td) meanrev has
resumed submitting with NO config or code change, the wedge-persistence
claim for this instance is falsified — record that, and the row narrows to
legs 2+3, which stand independently of whether this halt self-clears.** If
the owner rules (c) and the leg-2 ruling is pinned, the row closes with the
wedge accepted-as-recorded. Zero registry rows, zero DSR debt, no pinned
value touched.

*Coupling flags (for triage, not edits):* PC-1's 08-31 dismissal default
rests on pre-halt evidence (expiry watch above). The AVB/BRK-B failed-pair
day-3 tripwire is **masked, not resolved** — with `n_submitted 0` the two
per-symbol failures cannot occur; it re-arms the day the halt clears.

## Triage note — 2026-08-24 (annotation only; the body above is untouched)

**Leg 1 is DECIDED and the row narrows to legs 2+3.** The owner took option
(b) on 2026-08-20 in `955db93`: meanrev's `safety.max_orders_per_run` 150→300
(config + keystone, the deliberate two-touch); momentum and vrp stay at 150.
Re-verified from `data/state/meanrev/order_log.jsonl`: 08-19 `n_submitted 0`
of 209 targets, 08-20 `0` of 161, then **08-21 `133` of 149 and 08-24 `96` of
73** — the sleeve is submitting again.

**The item's own 09-04 falsifier is therefore already answered, and in the
direction that CONFIRMS the row, not the one that narrows it.** The pinned
wording was "if by 2026-09-04 meanrev has resumed submitting with NO config or
code change, the wedge-persistence claim is falsified". A config change was
required to clear the wedge, so wedge-persistence stands as claimed. Legs 2
and 3 stand independently either way, as the item said.

**Leg 2 has since been measured, not just predicted.** The daily audit of
2026-08-21 recorded the clearing-day churn against the phantom base —
realized cap-accounted churn 67.2% two-sided vs the 0.5/day cap (97.4% gross
incl. cap-exempt emergency exits), with `last_targets` dated 2026-08-20
carrying 161 weights against `n_submitted 0`. Durable record:
`research/2026-08-21_meanrev_clearing_day_churn.md` (PR #113, merged 9b2e268).
Attribution — legal frequency-scaled catch-up vs phantom-base artifact — was
deliberately left to this row and is still open.

**Leg 3 is temporarily de-armed on meanrev and re-arms on its own.** With the
cap at 300 a liquidation of today's book passes the count guard; the book is
**219 names as of 2026-08-24** and rising (173→185→196→196→196→219 since
08-17), so the guard re-arms against the kill-switch path as the book
approaches 300. The structural point the item makes — the count guard exempts
nothing, including an all-sell de-risking batch — is unchanged by the
recalibration.

---

## Triage note — 2026-09-07 (annotation only; the body above is untouched)

**Read this first: PR #154's "leg 3" is IGD-1's leg 3, not this row's.** #154
(`ee68ebe`, 2026-09-06) is titled *"IGD-1 leg 3 (owner ruling) + FOS-1"* and
rules the failed-order escalation shape (exit 4 on a NEW de-risking failure).
It does not touch the runaway-order count guard. Recorded because the titles
collide and a reader scanning git log would reasonably conclude otherwise.

**Leg 2 — STILL LIVE, verbatim.** `daily.py:1795-1803` persists
`ledger["last_targets"]` guarded only by `if not self.pipeline.dry_run:`
(`:1796`); `execute_orders` runs at `:1862`. No halt guard, no recorded
semantics ruling, no pinning test.

**Leg 3 — the core is STILL LIVE; only its compounding facet closed.** KSP-1
(#151, `47ea024`) fixed the side-effects this row named: `_liquidate_to_cash`
now reads the halt state (`daily.py:1222-1223`) and on a halt advances
nothing, the kill-switch `active: True` publish is deferred through
`_kill_switch_pending` (`:1103-1106` → `:1227-1230`), and the Kelly snapshot
is cleared only in the non-halt branch (`:1231-1234`). **The blockage itself
is untouched:** `safety.py:261-267` still counts `len(orders)` with no
exemption, and the only `all_de_risking` exemption remains scoped to the
daily-loss breaker (`safety.py:225-232`). The code's own comment at
`daily.py:1213` names *"RWG-1 leg 3: the count guard blocks any >150-name
book"* as a still-live premise — so the fix that landed knows it did not
close this.

**Arming status re-measured, and it moved the wrong way.** The 08-24 note
predicted leg 3 would re-arm as the book approached the 300 cap; the 08-31
note recorded the book falling. It then climbed:
`203 (08-28) → 233 → 250 (09-01) → 248 → 243 → 239 (09-04)`. On 2026-09-01
meanrev **submitted 241 orders against its 300-order cap** — the closest it
has come since the 08-19/20 halt that needed an owner config change to clear
— and a kill-switch liquidation of that day's 250-name book would have been
250 sells, 50 short of a HALT. Momentum is clear (67 names against 150).

**Consequence for sequencing.** The row's own text says legs 2 and 3 resolve
in one sitting with a ruling; SAC-1's cap note asks to be sequenced first so
the ruling is made once. Triage carries both into this week's decide-list as
one item on that basis, and makes no ruling itself — every path here is the
fail-closed safety layer.
