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.
Triage note — 2026-09-14 (annotation only; the body above is untouched)
SAC-1 IS FOLDED INTO THIS ROW as of today, at SAC-1's own request
(its cap note asked to be sequenced here so the owner rules once). SAC-1 was
dismissed at the 12-item cap this run; its body is preserved verbatim at
research/queue/dismissed/sac-1-state-advance-census.md. The ruling made on
this row should dispose of SAC-1's three live members, two of which this row
does not contain:
last_targets—daily.py:1795-1803. This is leg 2 here, already covered.last_construction/vol_scalar—daily.py:840→:843-849, consumed atdaily.py:667-668. A halted momentum selection leaves the vol-target estimator de-scaling against a book never held, for up to a month. Not in this row._record_safety_eventarming same-day idempotency —pipeline.py:274→state.py:180-187→daily.py:1523→cli.py:1107, wherecritical_skipsomits "Already ran today", so the run exits 0. Not in this row.
Arming re-measured at committed state through 2026-09-11, one week fresher
than the 09-07 note. The meanrev book ran 239 (09-04) → 238 → 232 → 232 → 242 (09-11). A drawdown-kill-switch liquidation of the 09-11 book is 242
sells against the 300-order cap — 58 short of a HALT. Peak submission remains
09-01's 241. Momentum is clear at 67 against 150.
Legs re-verified at HEAD 340bc5f: leg 2 persists ledger["last_targets"]
at daily.py:1795-1803, guarded only by if not self.pipeline.dry_run:
(:1796) while execute_orders runs at :1862 — no halt guard, no test. Leg 3
core is safety.py:261-265, n = len(orders) with no exemption;
all_de_risking is computed at :225 and consumed only at :228 and :236,
the daily-loss breaker alone. KSP-1 (PR #151) closed only the compounding
facets; daily.py:1213's own comment still names this row's blockage as live.
Nothing in #154, #158, #162, #163 or #165 touched safety.py.
Expiry, resolved: the body's 2026-09-04 falsification clock (:82-84)
passed in the confirming direction — clearing the 08-19/20 halt required the
owner's config change 955db93 (max_orders_per_run 150→300), so the
wedge-persistence claim was not falsified. No live deadline remains on this row.
TRIAGE ANNOTATION 2026-09-21 — fourth consecutive week on the decide list; the margin is closing, not holding
Arming re-measured at committed state through 2026-09-18, one week fresher
than the 09-11 note. data/state/meanrev/portfolio_snapshots.jsonl:
245 (09-16) → 263 (09-17) → 263 (09-18). A drawdown-kill-switch liquidation
of the 09-18 book is 263 sells against the 300-order cap — 37 short of a
HALT, against 58 short a week ago and 61 short a fortnight ago. Three
readings, monotone in the wrong direction. Momentum unchanged and clear at 67
against 150.
Legs re-verified at HEAD a325c3c. safety.py:261-265 is byte-identical:
n = len(orders), if n > limits.max_orders_per_run: res.halted = True, no
de-risking exemption; all_de_risking still computed at :225 and consumed
only at :228/:236. Leg 2 unchanged at daily.py:1795-1803. No merged
commit since 2026-09-14 touched safety.py.
Nothing new is asked of the owner — the two rulings are unchanged since 2026-08-31. Recorded only so the arming number in the file is not stale when somebody finally reads it.
Triage annotation — 2026-09-28 (annotation only; the body above is untouched)
Both live legs byte-identical at HEAD 864da4e. Leg 2:
src/thales/execution/daily.py:1795-1803 — if not self.pipeline.dry_run: →
ledger["last_targets"] = {...} → write_kelly_ledger, with execute_orders
not reached until :1862; no halt guard, no pinning test. Leg 3:
src/thales/execution/safety.py:261-265 — the count guard still HALTs on
n > limits.max_orders_per_run with no de-risking exemption;
all_de_risking is computed at :225 and consumed only at :228 and :236
by the daily-loss breaker. The kill-switch liquidation still routes through
execute_orders (daily.py:1207), and the code's own comment at daily.py:1213
still names "RWG-1 leg 3" as a live premise.
THE ARMING NUMBER IS UNCHANGED AT 263/300, AND THE REASON MATTERS: the trend
is FROZEN, not reversed. data/state/meanrev/portfolio_snapshots.jsonl final
record is 2026-09-18, n_positions: 263, equity $10,848.84 — the same
reading as 09-21, because nothing has traded since 2026-09-18 (GitHub
refused every Actions job from 09-21; last meanrev run_summary 09-18,
n_targets 103, n_submitted 37). Prior readings re-confirmed from the same
JSONL: 09-11 → 242, 09-16 → 245, 09-17 → 263.
So the four-week sequence of margins to a blocked kill-switch liquidation reads 61 → 58 → 37 → 37 short, where the fourth reading is a repeat of the third for want of a trading day, not evidence the book stopped growing. Meanrev selects daily and churned 242 → 263 in five sessions before the outage; the number should be expected to resume climbing on the first restored run, not to have settled. Re-read it on the first post-outage snapshot before treating the plateau as real.
Momentum for contrast, same date: 67 positions against its 150 cap
(config/settings.yaml:238) — clear. Caps re-read: config/meanrev.yaml:136
= 300, config/settings.yaml:238 = 150, config/vrp.yaml:99 = 150.
Blocked on: two owner rulings, now at five weeks (since 2026-08-31). Every
path is execution/safety.py, the fail-closed layer no routine may touch.
(i) leg 2's halt semantics — gate the last_targets persist on execution, or
record intended-book semantics plus the post-halt burst as deliberate;
(ii) leg 3's de-risking exemption for the count guard. SAC-1 is folded in
(research/queue/dismissed/sac-1-state-advance-census.md) and adds two members
this body does not contain: last_construction/vol_scalar (daily.py:840 →
:843-849, consumed :667-668) and _record_safety_event same-day
idempotency (pipeline.py:274 → state.py:180-187 → cli.py:1107). Honest
effort with the fold in scope is ~1 pd, not the body's 0.5.
Eviction note, recorded because the trade was made explicitly. Panel run 29
nominated this row for eviction at the 12-cap when it opened LAB-1, on the
grounds that leg 1 is discharged and the remainder is "a guard corner case with
no date and no active bleed". Triage declined the nomination. A row whose
measured margin to a blocked emergency de-risk has closed 61 → 37 over three
live readings is not an inactive corner case; it is the queue's oldest item
because it is blocked on a ruling nobody has made, and evicting it would
convert an unanswered safety question into a closed one. FIN-4 was evicted
instead — see research/queue/dismissed/fin-4-factor-benchmark-not-just-spy.md.
Triage annotation — 2026-10-05 (annotation only; the body above is untouched)
Still live at HEAD 502690b, both legs, byte-identical. Leg 3:
src/thales/execution/safety.py:261 n = len(orders), halt at :262-266
with no de-risking exemption; all_de_risking is computed at :225 and
consumed only by the daily-loss breaker (:228, :236). Leg 2:
src/thales/execution/daily.py:1795 if not self.pipeline.dry_run: →
:1798-1802 persists ledger["last_targets"] while execute_orders runs at
:1862, unguarded by the halt. grep last_targets tests/ hits three files,
none pairing it with a halt — still unpinned. Line cites have drifted: persist
is :1795-1804 (was :1795-1803), guard safety.py:261-266 (was :261-265).
daily.py:1210 still names "RWG-1 leg 3" as live in its own comment.
TWO NUMBERS FROM LAST WEEK'S ANNOTATION ARE FALSE, and both cut against this row's urgency — recorded here rather than quietly dropped.
- "Peak submission remains 09-01's 241" is wrong. The
order_log.jsonlrun_summary for 2026-08-31 readsn_targets 255, n_submitted 251. The peak is 251, which is 49 short of the 300 cap, not 59. - "Three readings, monotone in the wrong direction" no longer holds. The
meanrev position series from
data/state/meanrev/portfolio_snapshots.jsonlis263 (09-17) → 263 (09-18) → [8-session Actions outage] → 263 (10-01) → 260 (10-02) → **259 (10-05)**. Flat, then retreating. Margin againstconfig/meanrev.yaml:136 max_orders_per_run: 300is 41 orders, not 37, and the direction has reversed.
What that does and does not change. The row stays armed: a drawdown
kill-switch liquidation of today's book is 259 sells in one run
(daily.py:1196-1198 tags one order per position), which the count guard
would HALT. Arming is a structural fact about the cap, not a trend. But the
"closing fast" framing in the 09-14/09-21 notes was an artifact of three
readings taken during a growth phase, and this run cannot reproduce it. The
meanrev book is 2.93% off its 11,340.32 high-water mark against a 20%
kill-switch (config/meanrev.yaml:75) — armed, and far from triggering.
Momentum is 70 positions against its own 150 cap (settings.yaml:238):
clear.
Rank this week: 2 of 12 (P0 safety, live path). Held against the panel's eviction nomination for the second consecutive week, on the same ground: this is the only row where the failure mode is a safety system blocking its own de-risking, and evicting it converts an unanswered question into a closed one. BLOCKED on: two owner rulings (leg 2's halt-path semantics; whether leg 3 exempts an all-de-risking batch). Both are policy calls on the fail-closed layer, which is why nine weeks of an unused gate costs this row specifically.
Triage annotation — 2026-10-19 (annotation only; the body above is untouched)
The 2026-10-05 correction on this row was itself wrong, and in the row's
favour. That note said the arming direction had "reversed" (263/263/260/259,
"flat-to-retreating", margin 41) and held the row against the panel's eviction
nomination on that basis. Re-measured this run from
data/state/meanrev/portfolio_snapshots.jsonl (59 rows):
09-16 245 · 09-17 263 · 09-18 263 · 10-01 263 · 10-02 260 · 10-05 259
10-06 257 · 10-07 251 · 10-08 269 · 10-09 269 · 10-12 287 · 10-13 269
10-14 285 · 10-15 265 · 10-16 265 · 10-19 266
2026-10-12 at 287 positions is the all-time maximum of this book, and the
margin to config/meanrev.yaml:136's max_orders_per_run: 300 is 13 orders —
the tightest reading in this row's entire history (prior annotations recorded
61 → 58 → 37 → 37 → 41). 10-14 was 15 short. Today's book is 266, so a
drawdown kill-switch liquidation (daily.py:1196-1198, one order per position)
would submit 266 sells, 34 short of a HALT. The row's leg-3 claim is therefore
armed but never yet crossed: the guard blocks the de-risking exit on the
first run where the book exceeds 300, and the book has twice come inside 15.
The context behind that exit also moved toward it, not away. meanrev equity
is 10,743.08 against a high-water mark of 11,340.32 — a 5.27% drawdown
against config/meanrev.yaml:75's 20% kill switch (the 10-05 note said 2.93%).
Still far from firing, and still the never-promotable negative control, but the
path leg 3 says is blocked is nearer than it was.
Leg 2 unchanged (daily.py:1795-1804: the Kelly ledger's last_targets
advances before execute_orders at :1862, with no halt guard and no pinning
test). safety_halted is true on only 2026-08-19 and 2026-08-20 across the
whole 60-row run_summary history, so the phantom-blend wedge has not re-fired.
Momentum is clear: 69 positions against config/settings.yaml:238's 150.
Live state: oldest row in the tree (raised 2026-08-20, 60 days) · blocked on two owner rulings (leg 2's halt semantics; whether the count guard gets the de-risking exemption the daily-loss breaker already has) · ~7 weeks pending · urgency UP, and the 10-05 reversal claim is withdrawn.