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.

DISMISSED — RPL-1 — the marketable-limit market-replace is the one order path outside the safety chokepoint

status: dismissed by TRIAGE 2026-09-14 · OVERFLOW — ranked 14 of 21 at the pre-registered 12-item cap · raised 2026-09-04 · body verbatim below

Resolution — mechanical overflow; still live, but it is the only P0-class row in the tree with no clock of any kind

research/queue/open/ held 21 files after this run's sweep against the pre-registered 12-item cap (ops/QUEUE_TRIAGE.md:86-91), so the nine lowest-ranked are dismissed with reopen conditions. Ranking is P0–P5, then expiring-first: this row is genuinely P0 class but carries no dated horizon at all, and it lost every slot to a P0 that is armed today or to a P1 with a maturity date. Its only time language is :76 — "First unhurried week" — and ~2.5 weeks have now passed without one being taken.

Re-verified live at HEAD 340bc5f, verbatim:

  • daily.py:1288 — the only re-check before the replacement is if manual_halt_engaged(limits, self.config):. No evaluate_safety.
  • daily.py:1383-1384 — broker.submit_market_order(...) called directly.
  • daily.py:1348-1349 — filled_qty = float(o.filled_qty or 0.0) / remaining = max(0.0, float(r["shares"]) - filled_qty), read BEFORE cancel_order at :1354.
  • Reachable on two live sleeves: settings.yaml:267 and meanrev.yaml:153 are marketable_limit (vrp.yaml:123 is market).
  • PR #151 touched the cancel guards at :1294-1310 / :1363-1375, not the gate and not the read.

One thing the body does not engage, recorded here because it changes what the owner is being asked. daily.py:1278-1284 now carries a FLEET-LAW comment arguing the bypass — "re-gating would double-count TCA/idempotency machinery". So the covenant deviation is documented-as-deliberate. The row's own escape hatch anticipates this ("if routing through the gate proves impossible… that is a finding about the chokepoint's shape"), but the ruling being asked for is now "does that rationale stand?", not "why is this ungated?".

Split noted for whoever picks this up: facet 2 (the stale filled_qty read) is a pure bug needing no ruling at all — roughly two hours — and can ride any PR that already touches the replacement path.

Reopen condition. Reopen immediately if any of: a live sleeve's execution.order_type changes; a replacement ever over-sends (the daily.py:1348-1349 stale read producing remaining larger than the true leftover); a safety HALT ever lands between a submit and its replacement; or the daily.py:1278-1284 rationale is removed or contradicted by a later change. Otherwise reopen on or before 2026-12-01, since the December go-live diff (paper→false) makes every ungated order path a real-money path.


Body as filed (verbatim, untouched)

RPL-1 — the marketable-limit market-replace is the one order path outside the safety chokepoint

status: open · raised 2026-08-29 (external design review finding 5 + maintainer verification) · class: execution-safety (standing-covenant violation) · judgement: YES · effort ~0.5–1 pd · horizon: live on momentum + meanrev every rebalance with an unfilled limit; P low (minutes-wide, BUY-only window)


Plain-language summary for an owner reading one paragraph. When a touch-priced limit order doesn't fully fill within the fill window, _resolve_unfilled_limits cancels it and re-submits the remainder as a market order. That replacement re-checks only the manual/fleet halt — not the daily-loss breaker or any per-order reject that materialized during the minutes-long wait — and it submits via broker.submit_market_order directly. That makes it the single order path in the codebase that bypasses pipeline.execute_orders, which the shop's own covenant (memory/execution-safety-layer, 2026-06-06) names THE fail-closed chokepoint: "never add an order path that bypasses it." A second facet shares the site: remaining = shares − filled_qty reads filled_qty BEFORE the cancel; fills landing between the read and the cancel taking effect over-buy the remainder (check-then-act race).

Mechanism — verified at HEAD (external review, re-verified by the maintainer)

  • src/thales/execution/daily.py _resolve_unfilled_limits: top-of-function re-check is manual_halt_engaged only; the replacement goes out via broker.submit_market_order(..., client_order_id=…-mr) with no evaluate_safety pass over the remainder batch.
  • filled_qty is read from get_order_status before cancel_order; the remainder is sized from that pre-cancel read.
  • Reachability: config/settings.yaml (momentum) and config/meanrev.yaml both run order_type: "marketable_limit"; only vrp is market.
  • Credit where due (also verified): the surrounding code is careful — unknown status → leave the resting limit untouched (fail closed, 2026-07-18 fix); failed cancel → no replacement. The gap is exactly the missing full-gate re-check and the stale read.

Why P is low (and why it still matters)

The trigger needs a >10% intraday move or a fresh reject to materialize inside a ≤5-minute fill window, and only bites a BUY remainder — a de-risking SELL remainder should complete. But the site is live on both equity sleeves on every rebalance, and it is a covenant violation independent of P: the gate's guarantee is only as good as the paths that go through it.

Fix shape (PROPOSE-only — this row does not implement it)

  1. Route the replacement through the full gate: run evaluate_safety over the remainder batch (fresh account snapshot) before any market replace; a HALT verdict cancels-without-replacing (the fail-closed arm already exists for the manual-halt case).
  2. Re-read filled_qty AFTER the cancel is confirmed, size the remainder from that.

Test design + kill criterion (pre-registered, negative-controlled)

  1. Stub broker whose account crosses the −10% daily-loss line between the initial submit and the resolve pass, with an unfilled BUY limit: the market replacement must NOT be submitted (deny-asserted — red today).
  2. Race test: the stubbed order reports more filled_qty on the post-cancel read than the pre-cancel read; the replacement must be sized from the post-cancel value (red today).
  3. De-risking SELL remainder with the breaker tripped: replacement still goes out (the exemption must survive the rewiring).

Kill criterion: all three green post-fix; revert the gate re-route and test 1 reds; revert the re-read and test 2 reds. If routing through the gate proves impossible without submitting a second time through execute_orders's idempotency machinery, that is a finding about the chokepoint's shape — record it, don't work around it.

Scheduling note

Deliberately NOT built in the 2026-08-29 review-response PR: rewiring order-path plumbing the weekend before a selection day + owner absence is worse risk management than the defect (minutes-wide, BUY-only exposure). First unhurried week.