Files
momentum-system/docs/ideation/2026-07-13-next-milestone-ideation.html
T
momentum devandClaude Fable 5 653f13a7d9 milestone 2026-07: plans 001-007 + ideation artifacts + architecture diagrams
Recon (8 clusters) -> ideation (48->14->7, all verified) -> plans, cold-read
verified by 8 fresh-context reviewers, 33 plan defects fixed pre-execution.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 16:28:07 -04:00

294 lines
33 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ideation: Next Enhancement Milestone — Momentum</title>
<style>
:root {
--bg: #fafaf8; --fg: #1a1d21; --muted: #5c6470; --line: #dcdfe4;
--card: #ffffff; --accent: #0f6b54; --accent-soft: #e6f2ee; --accent-text: #0b5442;
--warn: #9a5b00; --warn-soft: #fdf3e3; --info: #274f8f; --info-soft: #e9effa;
--danger: #a33; --danger-soft: #faecec; --chip: #eef0f3; --code: #f2f3f5;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #14171a; --fg: #e6e8ea; --muted: #9aa3ad; --line: #2c3238;
--card: #1b1f23; --accent: #4fbf9f; --accent-soft: #14312a; --accent-text: #7dd6bc;
--warn: #e0a94f; --warn-soft: #33270f; --info: #7ea6e0; --info-soft: #17233a;
--danger: #e08080; --danger-soft: #351b1b; --chip: #262b30; --code: #22272c;
}
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--fg);
font: 15px/1.55 -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
.page { max-width: 920px; margin-inline: auto; padding: 2.2rem 1.4rem 4rem; }
p, li, dd { max-width: 72ch; }
h1 { font-size: 1.7rem; line-height: 1.25; margin: .2rem 0 .4rem; }
h2 { font-size: 1.25rem; margin: 2.4rem 0 .8rem; padding-top: 1rem; border-top: 1px solid var(--line); }
h3 { font-size: 1.05rem; margin: 1.6rem 0 .5rem; }
code { background: var(--code); padding: .1em .35em; border-radius: 4px; font-size: .88em; }
a { color: var(--info); }
.eyebrow { font-size: .72rem; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.meta { display: flex; flex-wrap: wrap; gap: .4rem .6rem; margin: .6rem 0 0; padding: 0; list-style: none; }
.meta li { background: var(--chip); border-radius: 999px; padding: .18rem .7rem; font-size: .8rem; color: var(--muted); }
.meta li b { color: var(--fg); font-weight: 600; }
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: .7rem; margin: 1.6rem 0; }
.stat { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: .7rem .9rem; }
.stat .n { font-size: 1.35rem; font-weight: 700; }
.stat .l { font-size: .78rem; color: var(--muted); }
article.idea { background: var(--card); border: 1px solid var(--line); border-radius: 12px;
padding: 1.1rem 1.3rem; margin: 1.1rem 0; }
article.idea h3 { margin: 0 0 .5rem; }
.chips { display: flex; flex-wrap: wrap; gap: .35rem; margin: 0 0 .8rem; }
.chips span { border-radius: 999px; padding: .14rem .6rem; font-size: .74rem; font-weight: 600; }
.chip-axis { background: var(--info-soft); color: var(--info); }
.chip-conf { background: var(--accent-soft); color: var(--accent-text); }
.chip-cx { background: var(--chip); color: var(--muted); }
.chip-cx.high { background: var(--warn-soft); color: var(--warn); }
dl.fields { margin: 0; }
dl.fields dt { font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-top: .7rem; }
dl.fields dd { margin: .15rem 0 0; }
.jump { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: .8rem 1.1rem; }
.jump ol { margin: .3rem 0 0 1.2rem; padding: 0; }
table { border-collapse: collapse; width: 100%; font-size: .88rem; }
th, td { border: 1px solid var(--line); padding: .45rem .6rem; text-align: left; vertical-align: top; }
th { background: var(--chip); font-size: .78rem; letter-spacing: .05em; text-transform: uppercase; }
.tablewrap { overflow-x: auto; }
figure { margin: 1rem 0 .3rem; }
figcaption { font-size: .78rem; color: var(--muted); margin-top: .3rem; }
footer.composition-signal { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--line);
font-size: .78rem; color: var(--muted); }
svg text { font-family: inherit; }
</style>
</head>
<body>
<div class="page">
<div class="eyebrow">Ideation · repo-grounded</div>
<h1>Next Enhancement Milestone — Momentum</h1>
<ul class="meta">
<li><b>date</b> 2026-07-13</li>
<li><b>topic</b> next-enhancement-milestone</li>
<li><b>mode</b> repo-grounded</li>
<li><b>repo</b> momentum @ d54a2a9</li>
<li><b>focus</b> read everything, brainstorm enhancements, pick the highest-leverage build</li>
</ul>
<div class="stats">
<div class="stat"><div class="n">48</div><div class="l">raw ideas · 5 frames</div></div>
<div class="stat"><div class="n">14</div><div class="l">merged candidates</div></div>
<div class="stat"><div class="n">14/14</div><div class="l">verified sound (fresh-context spot-checks)</div></div>
<div class="stat"><div class="n">7</div><div class="l">survivors · 5/5 axes covered</div></div>
</div>
<h2 id="grounding-context">Grounding Context</h2>
<p><strong>Codebase context.</strong> Event-sourced small-cap momentum day-trading system (gap-and-go / opening-range breakout). Alpaca <em>paper</em> account over the SIP feed; single PostgreSQL datastore (append-only <code>events</code> table + projections, ~19M minute bars); production is a Docker Compose stack on TrueNAS SCALE (postgres 18, trading loop, dashboard :8765, admin :8767, telegram bot, nightly scheduler); 376 pytest tests against throwaway <code>mem_*</code> schemas. Solo owner-operator.</p>
<p>Grounding came from an 8-agent recon sweep (2026-07-13) that read every subsystem — live loop, strategy, storage, research/data, dashboard, ops/deploy, brokers, tests — and produced ~95 evidence-cited findings, plus the in-repo external research pass <code>docs/research/entry_conversion_research.md</code> (academic + backtest literature on breakout entry conversion, with a ranked experiment shortlist). A fresh-context verifier then spot-checked every load-bearing claim against HEAD with ~25 targeted reads; <strong>every checked citation matched</strong>.</p>
<p><strong>Settled constraints honored throughout:</strong> the validated entry population stays ($2–20, static open gap 10–35%, real volume, ≥150%-gap &amp; rvol≥5 squeeze exception); seven selection levers are refuted at year scale and are not re-proposed; scale-out partials and retest/pullback entries are refuted; the :8765 dashboard is the only UI to extend; the system's proven bottleneck is <strong>entry-conversion</strong>, not selection.</p>
<h2 id="topic-axes">Topic Axes</h2>
<ul>
<li><strong>money-path-correctness</strong> — session lifecycle, broker-truth handling, order reconcile, entry-path drift, exit-manager safety</li>
<li><strong>learning-flywheel</strong> — tuning/replay scheduling, look-ahead &amp; population parity, dataset growth, experiment machinery</li>
<li><strong>entry-conversion</strong> — execution experiments on the proven bottleneck (time-stop, probe-add, asymmetric exit), shadow-track infrastructure</li>
<li><strong>operability-delivery</strong> — CI gate, alerting/dead-man, backup, retention, env drift, dead-weight deletion</li>
<li><strong>operator-surface</strong> — :8765 dashboard, :8767 admin, telegram: repairs, visibility, manual controls</li>
</ul>
<h2 id="ranked-ideas">Ranked Ideas</h2>
<div class="jump">
<div class="eyebrow">Jump to</div>
<ol>
<li><a href="#i1">Experiment OS — pre-registered, auto-adjudicated counterfactual experiments over logged fires</a></li>
<li><a href="#i2">Learning-flywheel resurrection — one population function + scheduled tune/replay</a></li>
<li><a href="#i3">Entry-path unification + decision receipts</a></li>
<li><a href="#i4">Money-path hardening — self-restart, positive-evidence contract, EOD cage count</a></li>
<li><a href="#i5">Production safety rails — CI gate, dead-man's switch, automated backup</a></li>
<li><a href="#i6">Operator control plane — dashboard repair, kill switch, effective-config panel</a></li>
<li><a href="#i7">Dead-weight deletion sweep — every table names its reader or dies</a></li>
</ol>
</div>
<article class="idea" id="i1">
<h3>1. Experiment OS — pre-registered, auto-adjudicated counterfactual experiments over logged fires</h3>
<div class="chips"><span class="chip-axis">entry-conversion</span><span class="chip-conf">Confidence 75%</span><span class="chip-cx high">Complexity High</span></div>
<dl class="fields">
<dt>Description</dt>
<dd>One parametric experiment harness replacing the four hand-built shadow-track triples in <code>research/labeler.py</code> (vwap_reclaim / runner / liquid / premarket — ~1,467 lines of structurally near-identical build/report/validate code). An experiment becomes a config row: population, intervention (an entry or exit policy variant), pre-registered pass/fail bars, minimum n, and futility criteria. A replay engine runs every logged live fire counterfactually against its recorded bar path — the Tesla shadow-mode pattern — including a <em>counterfactual exit ledger</em> (every real trade re-run under each exit variant). A verdict engine auto-adjudicates at the pre-registered thresholds (the clinical-trial DSMB pattern, with futility stops) and emits PASS / FAIL / INCONCLUSIVE verdict events that flow to Telegram and a dashboard experiment-ledger panel. First cohort ships with the harness: the three literature-backed entry-conversion experiments (idea card behind them in <code>docs/research/entry_conversion_research.md</code>): time-boxed entries + 10-minute time-stop on unconfirmed positions, probe-then-add 0.5×+0.5× sizing, asymmetric exit (volatility-fractional stop with a spread floor, no target, trail to EOD) — plus the rank-concentration "one-bullet" counterfactual and an immediate adjudication of pm1.</dd>
<dt>Basis</dt>
<dd><code>direct:</code> <code>data/premarket_eval_history.tsv</code> latest row (2026-07-09) shows pm1 at n=2377 with rate_1r=0.443 vs the pre-registered &gt;0.50 bar and median_up_60m=0.0433 vs the ≥0.10 bar — failing 3 of 4 pre-registered criteria while the code's own docstring still frames it as "n=21 is far too small… watch n climb". Seven prior levers each required a human to notice a threshold crossing in a log file. <code>external:</code> the three first-cohort experiments carry academic + replicated-backtest support (Zarattini/Barbon/Aziz SSRN 4729284, Osler NY Fed SR150, Mesfin arXiv 2605.04004) per the in-repo research doc. Verifier confirmed none of the harness/experiment machinery exists yet.</dd>
<dt>Rationale</dt>
<dd>The system's bottleneck is proven to be entry-conversion, and the three highest-priority interventions are already researched, pre-registered, and testable for <em>free</em> against fires the system has already logged — zero live risk. The blocker is machinery, not ideas: every new experiment today costs a hand-built ~300-line triple plus a human reading a TSV. Build the machinery once and every future experiment (premarket module included) drops to a config row with an automatic verdict.</dd>
<dt>Downsides</dt>
<dd>Biggest build in the set; replay fidelity is a real risk (fills, spreads, halts must be modeled honestly — the tight-stop zero-slippage artifact has already fooled two shadow tracks here, so the harness must enforce adverse-fill floors by construction). Requires the population module from idea 2 to avoid baking look-ahead into every experiment.</dd>
</dl>
<figure>
<svg viewBox="0 0 860 190" role="img" aria-label="Experiment OS flow">
<defs><marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#8892a0"/></marker></defs>
<rect x="10" y="55" width="150" height="80" rx="10" fill="var(--info-soft)" stroke="var(--info)"/>
<text x="85" y="88" text-anchor="middle" font-size="13" font-weight="600" fill="var(--fg)">Logged fires</text>
<text x="85" y="106" text-anchor="middle" font-size="11" fill="var(--muted)">+ recorded bar paths</text>
<rect x="230" y="20" width="170" height="60" rx="10" fill="var(--card)" stroke="var(--line)"/>
<text x="315" y="45" text-anchor="middle" font-size="12.5" font-weight="600" fill="var(--fg)">Experiment configs</text>
<text x="315" y="62" text-anchor="middle" font-size="11" fill="var(--muted)">population · policy · bars · n</text>
<rect x="230" y="105" width="170" height="65" rx="10" fill="var(--accent-soft)" stroke="var(--accent)"/>
<text x="315" y="132" text-anchor="middle" font-size="12.5" font-weight="600" fill="var(--fg)">Replay engine</text>
<text x="315" y="149" text-anchor="middle" font-size="11" fill="var(--muted)">counterfactual P&amp;L per fire</text>
<rect x="470" y="70" width="160" height="65" rx="10" fill="var(--warn-soft)" stroke="var(--warn)"/>
<text x="550" y="97" text-anchor="middle" font-size="12.5" font-weight="600" fill="var(--fg)">Verdict engine</text>
<text x="550" y="114" text-anchor="middle" font-size="11" fill="var(--muted)">pre-registered bars · futility</text>
<rect x="700" y="20" width="150" height="55" rx="10" fill="var(--card)" stroke="var(--line)"/>
<text x="775" y="43" text-anchor="middle" font-size="12" font-weight="600" fill="var(--fg)">Telegram ping</text>
<text x="775" y="60" text-anchor="middle" font-size="11" fill="var(--muted)">PASS / FAIL / INCONCLUSIVE</text>
<rect x="700" y="115" width="150" height="55" rx="10" fill="var(--card)" stroke="var(--line)"/>
<text x="775" y="138" text-anchor="middle" font-size="12" font-weight="600" fill="var(--fg)">Ledger panel</text>
<text x="775" y="155" text-anchor="middle" font-size="11" fill="var(--muted)">:8765 dashboard</text>
<line x1="160" y1="95" x2="222" y2="130" stroke="#8892a0" stroke-width="1.6" marker-end="url(#arr)"/>
<line x1="315" y1="80" x2="315" y2="98" stroke="#8892a0" stroke-width="1.6" marker-end="url(#arr)"/>
<line x1="400" y1="130" x2="462" y2="108" stroke="#8892a0" stroke-width="1.6" marker-end="url(#arr)"/>
<line x1="630" y1="88" x2="692" y2="55" stroke="#8892a0" stroke-width="1.6" marker-end="url(#arr)"/>
<line x1="630" y1="115" x2="692" y2="138" stroke="#8892a0" stroke-width="1.6" marker-end="url(#arr)"/>
</svg>
<figcaption>Every logged fire becomes reusable evidence; every experiment becomes a config row with an automatic verdict.</figcaption>
</figure>
</article>
<article class="idea" id="i2">
<h3>2. Learning-flywheel resurrection — one population function + scheduled tune/replay</h3>
<div class="chips"><span class="chip-axis">learning-flywheel</span><span class="chip-conf">Confidence 90%</span><span class="chip-cx">Complexity Medium</span></div>
<dl class="fields">
<dt>Description</dt>
<dd>Extract the live population gate into one shared pure module with an as-of-time contract (open-knowable inputs only: static open gap, price band, premarket-knowable volume, squeeze exception) and make every offline consumer — <code>learn_params.py</code>, the sweeps, <code>eod_replay.py</code>, the labeler — consume it instead of re-implementing it. Then actually schedule the flywheel in production: <code>eod_replay</code> after each close (unbiased whole-market dataset growth), <code>nightly_tune</code> after it (atomic tmp+rename write, staleness alert if <code>learned_params.json</code> ages past 2 days).</dd>
<dt>Basis</dt>
<dd><code>direct:</code> verifier-confirmed at HEAD: the TrueNAS scheduler runs <em>only</em> <code>research.premarket_eval</code>; <code>data/learned_params.json</code> is stamped as_of 2026-06-17 — 26 days stale — while the boot log still claims self-tuning; <code>learn_params.py:61,64</code> admits day-end <code>day_rvol</code> (outcome-time look-ahead); <code>eod_replay.py:44-48</code> screens $1–5 under a "live verified config" comment while production trades $2–20 (<code>truenas-compose.yml:105-106</code>); <code>eod_replay.sh</code> points at a dead venv path; <code>nightly_tune.py:91-92</code> writes non-atomically.</dd>
<dt>Rationale</dt>
<dd>The project memory says "nightly_tune self-tunes params, applied on boot" — that story is currently fiction in production, and the offline population drift means even a re-enabled tuner would fit a universe the bot doesn't trade. This is the data-integrity substrate under idea 1: experiments adjudicated against a look-ahead population are worthless. The owner has already been burned twice by exactly this class (the 2026-07-08 look-ahead correction).</dd>
<dt>Downsides</dt>
<dd>Population-module extraction touches the live gate — needs characterization tests before refactor. A deliberate alternative is to <em>delete</em> the tuner and stop claiming self-tuning; the wrong option is the current silent limbo.</dd>
</dl>
<figure>
<svg viewBox="0 0 860 175" role="img" aria-label="One population module fanning out to five consumers">
<defs><marker id="arr2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0,0 L10,5 L0,10 z" fill="#8892a0"/></marker></defs>
<text x="115" y="20" text-anchor="middle" font-size="11.5" font-weight="700" fill="var(--danger)">TODAY: 5 diverging copies</text>
<rect x="30" y="32" width="170" height="26" rx="6" fill="var(--danger-soft)" stroke="var(--danger)"/><text x="115" y="49" text-anchor="middle" font-size="11" fill="var(--fg)">live gate — $2–20, open gap</text>
<rect x="30" y="64" width="170" height="26" rx="6" fill="var(--danger-soft)" stroke="var(--danger)"/><text x="115" y="81" text-anchor="middle" font-size="11" fill="var(--fg)">tuner — day-end rvol (look-ahead)</text>
<rect x="30" y="96" width="170" height="26" rx="6" fill="var(--danger-soft)" stroke="var(--danger)"/><text x="115" y="113" text-anchor="middle" font-size="11" fill="var(--fg)">eod_replay — $1–5, no squeeze</text>
<rect x="30" y="128" width="170" height="26" rx="6" fill="var(--danger-soft)" stroke="var(--danger)"/><text x="115" y="145" text-anchor="middle" font-size="11" fill="var(--fg)">sweeps · labeler — own filters</text>
<text x="580" y="20" text-anchor="middle" font-size="11.5" font-weight="700" fill="var(--accent-text)">TARGET: one as-of-time module</text>
<rect x="360" y="65" width="190" height="56" rx="10" fill="var(--accent-soft)" stroke="var(--accent)"/>
<text x="455" y="88" text-anchor="middle" font-size="12.5" font-weight="600" fill="var(--fg)">population.py</text>
<text x="455" y="105" text-anchor="middle" font-size="11" fill="var(--muted)">open-knowable inputs only</text>
<rect x="660" y="28" width="170" height="24" rx="6" fill="var(--card)" stroke="var(--line)"/><text x="745" y="44" text-anchor="middle" font-size="11" fill="var(--fg)">live gate</text>
<rect x="660" y="58" width="170" height="24" rx="6" fill="var(--card)" stroke="var(--line)"/><text x="745" y="74" text-anchor="middle" font-size="11" fill="var(--fg)">tuner + sweeps</text>
<rect x="660" y="88" width="170" height="24" rx="6" fill="var(--card)" stroke="var(--line)"/><text x="745" y="104" text-anchor="middle" font-size="11" fill="var(--fg)">eod_replay (scheduled)</text>
<rect x="660" y="118" width="170" height="24" rx="6" fill="var(--card)" stroke="var(--line)"/><text x="745" y="134" text-anchor="middle" font-size="11" fill="var(--fg)">labeler / Experiment OS</text>
<line x1="550" y1="80" x2="652" y2="42" stroke="#8892a0" stroke-width="1.5" marker-end="url(#arr2)"/>
<line x1="550" y1="90" x2="652" y2="70" stroke="#8892a0" stroke-width="1.5" marker-end="url(#arr2)"/>
<line x1="550" y1="100" x2="652" y2="100" stroke="#8892a0" stroke-width="1.5" marker-end="url(#arr2)"/>
<line x1="550" y1="110" x2="652" y2="130" stroke="#8892a0" stroke-width="1.5" marker-end="url(#arr2)"/>
</svg>
<figcaption>Every backtest, tune, and experiment verdict becomes trustworthy by construction when all consumers share the live gate.</figcaption>
</figure>
</article>
<article class="idea" id="i3">
<h3>3. Entry-path unification + decision receipts</h3>
<div class="chips"><span class="chip-axis">money-path-correctness</span><span class="chip-conf">Confidence 85%</span><span class="chip-cx">Complexity Medium</span></div>
<dl class="fields">
<dt>Description</dt>
<dd>Collapse the two drifted entry paths — slow auto-approval (<code>request_approvals_for_ready_signals</code>) and fast trigger (<code>submit_breakout_now</code>) — onto one shared pure gate function. Every gate evaluation emits a compact <em>decision receipt</em> event (gate name, inputs, pass/fail), so "why did/didn't it trade X?" becomes a query instead of a forensic session.</dd>
<dt>Basis</dt>
<dd><code>direct:</code> verifier-confirmed: <code>_population_reject</code>/<code>_outside_session</code>/<code>_anti_chase_skip</code> are already shared by both paths, but the VWAP check exists only in the slow path (~<code>trading_execution.py:938</code>) and <code>rank_risk_factor</code> only in the fast path (<code>:1228</code>); the boot log itself warns "rank-concentration is enforced ONLY on the dead fast-trigger path, NOT the live auto-approval path" (<code>run_live_paper.py:1026-1028</code>). The daily-cap counted 44-vs-5 incident (fixed ac1ac50) was this same drift class.</dd>
<dt>Rationale</dt>
<dd>Half the convergence is already done — this finishes it so every future gate (including any Experiment-OS winner promoted to live) lands on both paths by construction. Receipts double as the raw material Experiment OS replays and the operator reads on the dashboard.</dd>
<dt>Downsides</dt>
<dd>Touches the live money path — needs the CI gate (idea 5) and characterization tests first. Receipt events add volume to the events table (bounded; they replace ad-hoc diagnostic events that retention already prunes).</dd>
</dl>
</article>
<article class="idea" id="i4">
<h3>4. Money-path hardening — self-restart, positive-evidence contract, EOD cage count</h3>
<div class="chips"><span class="chip-axis">money-path-correctness</span><span class="chip-conf">Confidence 95%</span><span class="chip-cx">Complexity Low</span></div>
<dl class="fields">
<dt>Description</dt>
<dd>Three small, high-severity fixes sharing one principle — never act on assumed state. (a) <strong>Daily self-restart</strong>: <code>exit(0)</code> after a successful EOD flatten and let compose's <code>restart: unless-stopped</code> resurrect a fresh process — the process <em>is</em> the trading session. (b) <strong>Positive-evidence contract</strong>: no destructive market action on an ambiguous broker read — the exit manager must distinguish "orders call failed / silently empty" from "position confirmed naked" before market-flattening, and a lost order-POST must reconcile via <code>client_order_id</code> lookup before journaling "cancelled". (c) <strong>EOD cage count</strong>: a nightly reconcile that diffs broker positions/orders/fills against event-store truth and alerts on any discrepancy, plus SIGTERM handled as clean shutdown (<code>docker stop</code> currently skips the shutdown path).</dd>
<dt>Basis</dt>
<dd><code>direct:</code> verifier-confirmed: <code>_eod_done</code>/<code>_catchup_done</code> (<code>run_live_paper.py:1064,1113</code>) and <code>_session_closed</code>/<code>_daily_loss_breach</code> (<code>trading_execution.py:398,612</code>) never reset — an uninterrupted day-2 takes zero entries and has no EOD flatten, masked today only by frequent redeploys; <code>exit_manager.py:71-72</code> returns None on any exception and treats it identically to "naked", flattening after ~24s grace; <code>execution.py:124-129</code> journals lost POSTs as cancelled with no reconcile (no <code>by_client_order_id</code> method exists in the client); the 2026-07-06 duplicate-resting-order incident is corroborated by d54a2a9's own commit message; recovery-on-boot (<code>_rebuild_daily_state</code>) already exists and is tested.</dd>
<dt>Rationale</dt>
<dd>Highest severity-to-effort ratio in the whole set. (a) alone converts an entire recurring bug class (session gate, after-hours submissions, bench state — each patched separately before) into a non-issue by construction, in ~5 lines plus tests.</dd>
<dt>Downsides</dt>
<dd>Self-restart must fire only after a <em>successful</em> flatten (exit-on-failure would orphan positions — though broker-side stop legs keep them protected); the positive-evidence branch adds one more state to exit-manager logic that is already subtle.</dd>
</dl>
</article>
<article class="idea" id="i5">
<h3>5. Production safety rails — CI gate, dead-man's switch, automated backup</h3>
<div class="chips"><span class="chip-axis">operability-delivery</span><span class="chip-conf">Confidence 95%</span><span class="chip-cx">Complexity Low</span></div>
<dl class="fields">
<dt>Description</dt>
<dd>The "vacation test" bundle: (a) CI runs the 376-test suite (plus <code>ruff check --select F</code> for the untested script layer) <em>before</em> the image workflow pushes <code>:latest</code> to GHCR/Docker Hub; (b) the always-up qabot container gets a dead-man's switch — alert when the event-store heartbeat goes stale during market hours, plus a nightly OK-ping (the loop can't report its own death; the qabot is the independent observer); (c) a scheduled <code>pg_dump</code> (or documented ZFS snapshot task) — production currently has <strong>no automated backup</strong>.</dd>
<dt>Basis</dt>
<dd><code>direct:</code> verifier-confirmed: <code>.github/workflows/docker.yml</code> has zero test step and ships on every master push; <code>api/main.py</code> at HEAD references <code>os</code>/<code>hmac</code> without importing them (AST-confirmed) — an untested regression that already shipped; loop-down currently means alerts-down (the notifier lives inside the loop process, <code>run_live_paper.py:1034</code>); <code>pg_dump</code> appears only in the one-time migration script.</dd>
<dt>Rationale</dt>
<dd>This is the lever that makes every other lever safe to ship. Every subsequent idea in this list lands as an image push; today each push is an untested bet against the production money path.</dd>
<dt>Downsides</dt>
<dd>CI needs a Postgres service container for the suite (~3–4 min per push). Dead-man thresholds need market-calendar awareness to avoid weekend false alarms — the holiday-aware calendar already exists in <code>runtime/market_calendar.py</code>.</dd>
</dl>
</article>
<article class="idea" id="i6">
<h3>6. Operator control plane — dashboard repair, kill switch, effective-config panel</h3>
<div class="chips"><span class="chip-axis">operator-surface</span><span class="chip-conf">Confidence 85%</span><span class="chip-cx">Complexity Medium</span></div>
<dl class="fields">
<dt>Description</dt>
<dd>Make the production :8765 surface tell the truth and accept commands. Repairs: fix the POST <code>NameError</code> (unimported <code>os</code>/<code>hmac</code>); wire the research DB into the standalone dashboard so sparklines work in production; gate action buttons on the <code>has_execution</code> flag the API already ships; derive the LIVE badge from broker truth (it currently keys on a <code>schwab_live</code> literal the admin go-live flow never sets — it would read PAPER while trading real money). Capability: manual flatten (all / per-symbol) and pause-entries as guarded <em>operator-command events</em> through the store — the loop polls its own 5s guard cadence and executes with the existing <code>cancel_protective_and_close</code> helper; dashboard and qabot become thin command emitters. Efficiency: replace the per-client per-second fresh-connection + full-DDL + <code>COUNT(*)</code> SSE change detector with one shared cached signal. Visibility: an effective-config panel showing the merged config per service with per-key provenance (baked env → compose env → <code>overrides.env</code> → learned params) and drift-vs-inventory warnings.</dd>
<dt>Basis</dt>
<dd><code>direct:</code> verifier-confirmed: <code>telegram_bot.py:29</code> hard-refuses action words; <code>dashboard_api.py:36</code> builds the production dashboard with <code>execution_service=None</code> — no manual flatten path exists anywhere in the production UI; <code>dashboard.html:1061</code> keys LIVE on <code>schwab_live</code> while <code>admin_api.py:276-295</code> only swaps Alpaca URL/keys; SSE poll confirmed at <code>api/main.py:355</code>; concurrency-gauge default drift (3 vs 6) confirmed at <code>trading_execution.py:75</code> vs <code>projections.py:869</code>.</dd>
<dt>Rationale</dt>
<dd>The operator's two moments of need — "something is wrong, get me flat NOW" and "what is this thing actually running?" — both currently require shelling into a container. Command-as-event reuses the store as the bus (no new API surface into the loop) and leaves an audit trail by construction.</dd>
<dt>Downsides</dt>
<dd>A kill switch is a live-money control: needs HMAC/token guard, idempotency, and a test that a replayed or stale command cannot re-fire. Command latency is bounded by the 5s guard cadence (acceptable; broker stops remain the fast layer).</dd>
</dl>
</article>
<article class="idea" id="i7">
<h3>7. Dead-weight deletion sweep — every table names its reader or dies</h3>
<div class="chips"><span class="chip-axis">operability-delivery</span><span class="chip-conf">Confidence 90%</span><span class="chip-cx">Complexity Low</span></div>
<dl class="fields">
<dt>Description</dt>
<dd>Finish the deletion d54a2a9 claimed: <code>schwab/</code> is still fully tracked (23 files) despite the commit message. Then the rest of the confirmed-dead surface: <code>comprehensive_backtest.py</code> (crashes on import — <code>research/connection.py</code> doesn't exist), <code>strategy/regime.py</code>, <code>universe.py</code>, <code>backtest/outcomes.py</code>, the ignition detector, the <code>grafana/</code> stack (points at the decommissioned pre-migration DB with committed plaintext dev credentials), the <code>telemetry/</code> husk, <code>docker-publish.yml</code> (fires on a nonexistent <code>main</code> branch, pushes a wrong image name), stale <code>uv.lock</code>, the empty <code>test_alpaca_client.py</code>, 12 zero-reference tables and 6 dead projections. Standing rule going forward: every table names its reader or dies — <code>quote_snapshots</code> gets retention or deletion; <code>float_cache</code>/<code>dilution_events</code> get wired into the labeler's features or stop being collected nightly.</dd>
<dt>Basis</dt>
<dd><code>direct:</code> verifier-confirmed each item at HEAD, including <code>git ls-files schwab/</code> (23 tracked files) vs d54a2a9's message, the import crash, the grafana datasource credentials, and grep-confirmed zero readers for the write-only tables.</dd>
<dt>Rationale</dt>
<dd>Every dead artifact taxes every future session ("which one is real?") and the grafana credentials are a small standing security smell. Deletion is the cheapest enhancement in the set and makes every subsequent plan smaller.</dd>
<dt>Downsides</dt>
<dd>The schwab/ decision should be explicit (its only non-delete rationale is the dormant human-vs-bot comparison); deleting tables needs a backup first (idea 5c) and a one-session soak.</dd>
</dl>
</article>
<h2 id="rejection-summary">Rejection Summary</h2>
<p>Nothing was refuted: the fresh-context verifier confirmed all 14 merged candidates sound, and all 48 raw ideas were absorbed into the 7 survivors. The table records the merges and the judgment calls.</p>
<div class="tablewrap">
<table>
<tr><th>#</th><th>Idea</th><th>Disposition</th></tr>
<tr><td>1</td><td>Daily self-restart (raw #1, 9, 18, 25, 33 — five frames converged independently)</td><td>Merged into survivor 4a — strongest single convergence in the run</td></tr>
<tr><td>2</td><td>Broker-ambiguity fixes / MCAS rule / "empty is not naked" (raw #2, 26, 37)</td><td>Merged into survivor 4b as one shared contract</td></tr>
<tr><td>3</td><td>EOD cage-count reconciliation (raw #27)</td><td>Folded into survivor 4c — thinnest-sourced candidate (analogy + one past incident); kept as backstop, not standalone</td></tr>
<tr><td>4</td><td>Verdict watchdog / DSMB / experiment ledger / experiment-as-config / Tesla shadow mode / counterfactual exit ledger (raw #4, 13, 22, 30, 34, 43, 44)</td><td>Merged into survivor 1 (Experiment OS) — the run's flagship synthesis</td></tr>
<tr><td>5</td><td>Entry-conversion shortlist experiments (raw #5, 38) and one-bullet rank counterfactual (raw #48)</td><td>Merged into survivor 1 as the first experiment cohort</td></tr>
<tr><td>6</td><td>Population parity / flywheel scheduling / "replay whole market nightly" (raw #3, 11, 12, 20, 21, 28, 35, 47)</td><td>Merged into survivor 2</td></tr>
<tr><td>7</td><td>Kill switch variants: qabot /flatten, fire handle, command-bus events (raw #8, 15, 32, 36)</td><td>Merged into survivor 6 — command-as-event chosen as the unifying mechanism</td></tr>
<tr><td>8</td><td>LISTEN/NOTIFY dashboard change signal (raw #16)</td><td>Demoted to implementation option inside survivor 6 — shared cached signal may be enough (lazy option first)</td></tr>
<tr><td>9</td><td>Effective-config panel (raw #46)</td><td>Merged into survivor 6</td></tr>
<tr><td>10</td><td>CI gate / vacation test / eye-in-the-sky (raw #6, 7, 17, 31, 41, 42)</td><td>Merged into survivor 5</td></tr>
<tr><td>11</td><td>Deletion sweeps (raw #14, 24, 39)</td><td>Merged into survivor 7</td></tr>
<tr><td>—</td><td>Axis coverage</td><td>All five axes have survivors; no recovery dispatch was needed</td></tr>
</table>
</div>
<footer class="composition-signal">Composed 2026-07-13 by ce-ideate (repo-grounded) from an 8-agent recon sweep + 5-frame ideation fleet + fresh-context basis verification, at momentum commit <code>d54a2a9</code>. Scratch: <code>/tmp/compound-engineering/ce-ideate/a3f9c2e1/</code></footer>
</div>
</body>
</html>