2026-08-29 — External design review: maintainer-side verification
Provenance. An external design review of this repo at 24cfe0b arrived
2026-08-29 and is committed verbatim as
research/2026-08-29_external_design_review.md. This memo is the
maintainer-side verification: every load-bearing claim re-checked against the
code and — where the reviewer explicitly could not look — against committed
state. Verdict up front: all five findings are real; the headline one had
already fired in production, which the reviewer could not see and
correctly routed to the maintainer.
The live confirmation the reviewer couldn't reach (finding 1)
The review reproduced the Kelly double-book in a harness and flagged
p_manifests ≈ 0.4. The gitignored-state caveat cut the other way: meanrev
selects daily, safety-HALTed on 2026-08-19 and 08-20 (the RWG-1 runaway
guard), and its ledger is committed. Per-commit history of
data/state/meanrev/kelly_ledger.json:
| run | returns count | Δ booked | snapshot date after |
|---|---|---|---|
| 08-18 (ok) | 2,865 | +186 | advances → 08-18 (195 names) |
| 08-19 (HALT) | 3,060 | +195 — P(08-18→19) | frozen at 08-18 |
| 08-20 (HALT) | 3,255 | +195 again — P(08-18→20), overlapping | frozen at 08-18 |
| 08-21 (ok) | 3,450 | +195 a third time — P(08-18→21), overlapping both | advances → 08-21 |
One period start, booked three times: 390 excess overlapping samples ≈ 10.6% of meanrev's 3,668-sample pool, skewed toward the adverse stretch — exactly the bias direction the review predicted, because halts cluster there.
Two mitigations, both verified:
- meanrev has
sizing: "none"(config/meanrev.yaml:88) — the control sleeve's ledger is advisory; the contamination sized nothing. - momentum's ledger is clean — exactly one booking commit per selection day (2026-06-11, 07-01, 08-03), no retried selection day has ever occurred on the flagship.
Which is also why the review's priority-1 call stands: momentum does size from this pool, its next selection day is Tue 2026-09-01, and the week of 08-25 demonstrated the exact triggers (a ~9-hour GHA cron slide, a run crossing UTC midnight, a SIGKILL-class capture failure).
Contamination disposition: recorded, not rewritten. The 390 excess
samples stay in meanrev's ledger — it sizes nothing (sizing: "none"), and
hand-editing committed state to make history prettier is what this shop does
not do. Caveat for any future reader: the pool caps at 5,000, so
contamination also evicts real samples; if meanrev's ledger ever came to
matter it needs a rebuild from order history, not a trim.
Per-finding verification
| # | review's claim | verification | disposition |
|---|---|---|---|
| 1 | Kelly booking double-books on failed-selection retry (daily.py:912 guard keyed on today; snapshot advance gated if not halted) | Confirmed by reading every cited line, then confirmed live (table above). log_run writes selection_completed: not halted, so a halted selection re-enters — exactly as claimed | Fixed this PR — returns_booked_for marker, same atomic write |
| 2 | No request timeout on any Alpaca client; a stall hangs to the GHA job kill; the idempotency path never fires because a hang never raises | Confirmed: TradingClient.__init__/RESTClient.__init__ signatures (installed 0.43.2) accept no timeout; zero timeout occurrences in alpaca/common/rest.py; Tiingo path has timeout=30.0, money path had none | Fixed this PR — with a corrected shape (below) |
| 3 | Daily-loss breaker silently skipped when last_equity is 0/None/NaN — fail-open in a fail-closed layer | Confirmed by reading safety.py:226-231 | Fixed this PR — degenerate equity now HALTs risk-increasing batches; de-risking exemption preserved |
| 4 | requirements-ci.lock has no hashes; non-CI installs float | Confirmed: grep -c -- '--hash' requirements-ci.lock → 0 | Queued (queue/open/lck-1) — deliberately after the trip; see the row for why |
| 5 | The marketable-limit market-replace re-checks only the manual/fleet halt; filled_qty read pre-cancel (over-buy race); live on two sleeves | Confirmed by reading daily.py (_resolve_unfilled_limits); both sleeve configs are marketable_limit | Queued (queue/open/rpl-1) — sharper framing below |
| — | Near-miss: VRP close self-rejects on a legacy position file missing strikes (defaults 1.0/1.0 → equal-strike shape reject); routed to maintainer | Checked: the live data/state/vrp/vrp_position.json carries real strikes (748/747) | Latent-only on current state; noted, no action |
Corrections to the review (it holds up; these sharpen it)
- Finding 2's remedy line is factually wrong in its easiest claim —
"pass a request timeout to the SDK clients (the SDK accepts one)". It does
not: alpaca-py 0.43.2 exposes no timeout parameter anywhere. The finding
is untouched; the fix is a deadline injected at each client's
requests.Session(_apply_default_timeout, this PR) — still small, but it needed a fake-session test, not a kwarg. - Finding 5 is stronger than its principle framing. The replace path
calling
broker.submit_market_orderdirectly is not merely an enforce-invariants miss — it violates the repo's own standing covenant (2026-06-06,memory/execution-safety-layer):pipeline.execute_ordersis THE fail-closed chokepoint and "never add an order path that bypasses it." The queue row carries the covenant citation. - Finding 3's reachability is broader than "unfunded accounts" —
float(getattr(account, "last_equity", 0) or 0)also swallows an SDK field rename or a partial response. Still low-P; same fix. - Finding 4's "the box that trades real money" overstates — trading runs on GHA, which installs from the lock. The true residual is hash-verification plus local-parity. Correctly ranked last.
- "A finding the audits never caught" needs precision — and the precise
version is more instructive. An earlier execution audit hit this site
twice ("Kelly phantom returns"; an "idempotency gap" — the origin of the
:912guard). The guard fixed the same-day-re-run case and missed the retry case. Guards written for the narrow reproduction of an incident, rather than for the invariant, miss the sibling path.
The family observation (for the panel)
Three findings in two weeks are one class: state advanced, or keyed, without regard to whether the run completed.
- RWG-1 leg 2 — the turnover-blend base advances on a HALT;
- STAMP-1 (fired live 2026-08-27/28) — the runner's UTC date is both the trading-day stamp and the idempotency key, so a cron slide across midnight burned a capture day;
- the Kelly booking (this review) — returns persist immediately, the period marker only on successful completion.
The class predicts its next member: any write that pairs "effect now" with "marker later," or keys either on wall-clock rather than the unit of work. Worth a deliberate sweep with that lens rather than waiting for instance four to fire.
What shipped vs. queued (all owner-directed, recorded as such)
- Shipped this PR (each negative-controlled — the guard reverted, only
its own tests red): finding 1 (booking marker, both guards kept — the
:912today-guard still owns the same-day-after-success case), finding 2 (session deadline on all three Alpaca clients: trading, stock data, VRP option data), finding 3 (fail-closed breaker). - Queued: RPL-1 (finding 5 — order-path rewiring deserves an unhurried pass; exposure is a minutes-wide, BUY-only window), LCK-1 (finding 4 — after the trip, because regenerating the lock re-resolves versions and perturbing CI's install inputs before a selection day is its own risk).
- Routing note: built on the owner's direct instruction in an
interactive session, not via
queue/approved/— same route and same honesty note as EXQ-1 (2026-08-26).