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>
This commit is contained in:
momentum devandClaude Fable 5 committed 2026-07-13 16:28:07 -04:00
1 parent d54a2a930c
commit 653f13a7d9
14 files changed
+1887

No files matched your search

@@ -0,0 +1,293 @@
<!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>
@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="drawio" version="26.0.0">
<diagram name="Current architecture">
<mxGraphModel dx="1420" dy="900" grid="1" gridSize="10" page="1" pageWidth="1460" pageHeight="920">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="title" value="Momentum — current production architecture (TrueNAS compose, 2026-07 @ d54a2a9)" style="text;html=1;fontSize=18;fontStyle=1;align=left;" vertex="1" parent="1">
<mxGeometry x="40" y="0" width="900" height="30" as="geometry" />
</mxCell>
<mxCell id="browser" value="Operator browser" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1">
<mxGeometry x="60" y="60" width="180" height="60" as="geometry" />
</mxCell>
<mxCell id="telegram" value="Telegram" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1">
<mxGeometry x="300" y="60" width="160" height="60" as="geometry" />
</mxCell>
<mxCell id="feeds" value="Data feeds&#xa;Alpaca news &#183; RSS &#183; FMP float &#183; SEC EDGAR" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;" vertex="1" parent="1">
<mxGeometry x="700" y="60" width="240" height="60" as="geometry" />
</mxCell>
<mxCell id="alpaca" value="Alpaca Paper API&#xa;orders &#183; account &#183; SIP bars/quotes" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
<mxGeometry x="1040" y="60" width="240" height="60" as="geometry" />
</mxCell>
<mxCell id="compose" value="TrueNAS SCALE &#8212; Docker Compose stack (image: fez5587/momentum-app)" style="swimlane;startSize=30;html=1;fillColor=none;strokeColor=#666666;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="40" y="180" width="1340" height="580" as="geometry" />
</mxCell>
<mxCell id="dashboard" value="Dashboard :8765&#xa;static JS + SSE&#xa;(read-only projections)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="compose">
<mxGeometry x="30" y="60" width="210" height="80" as="geometry" />
</mxCell>
<mxCell id="admin" value="Admin :8767&#xa;config overrides &#183; profiles&#xa;service control" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="compose">
<mxGeometry x="30" y="170" width="210" height="80" as="geometry" />
</mxCell>
<mxCell id="qabot" value="Telegram qabot&#xa;status Q&amp;A (read-only)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="compose">
<mxGeometry x="30" y="280" width="210" height="80" as="geometry" />
</mxCell>
<mxCell id="pg" value="PostgreSQL 18&#xa;events (append-only)&#xa;minute_bars (~19M) &#183; research tables" style="shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;boundedLbl=1;" vertex="1" parent="compose">
<mxGeometry x="480" y="160" width="240" height="130" as="geometry" />
</mxCell>
<mxCell id="nightly" value="Nightly scheduler&#xa;premarket_eval 20:00 ET&#xa;retention &#183; shadow tracks &#183; caches" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="compose">
<mxGeometry x="480" y="380" width="240" height="80" as="geometry" />
</mxCell>
<mxCell id="loop" value="Trading loop &#8212; run_live_paper.py" style="swimlane;startSize=30;html=1;fillColor=#f8f8f8;strokeColor=#6c8ebf;fontStyle=1;" vertex="1" parent="compose">
<mxGeometry x="810" y="50" width="490" height="350" as="geometry" />
</mxCell>
<mxCell id="schedthread" value="Scheduler thread&#xa;discover &#183; ingest &#183; watch &#183; arm &#183; guard" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="loop">
<mxGeometry x="20" y="40" width="210" height="70" as="geometry" />
</mxCell>
<mxCell id="trigthread" value="Trigger thread (4s)&#xa;live cross &#8594; submit_breakout_now" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="loop">
<mxGeometry x="260" y="40" width="210" height="70" as="geometry" />
</mxCell>
<mxCell id="exitmgr" value="LiveExitManager (12s)&#xa;BE ratchet &#183; trail &#183; EOD flatten" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="loop">
<mxGeometry x="20" y="140" width="210" height="70" as="geometry" />
</mxCell>
<mxCell id="execsvc" value="TradingExecutionService&#xa;gates &#183; sizing &#183; bracket orders" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="loop">
<mxGeometry x="260" y="140" width="210" height="70" as="geometry" />
</mxCell>
<mxCell id="syncsvc" value="AlpacaPaperSync (60s)&#xa;account &#183; positions &#183; orders &#183; journal" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="loop">
<mxGeometry x="140" y="250" width="210" height="70" as="geometry" />
</mxCell>
<mxCell id="e1" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="browser" target="dashboard">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.1;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="browser" target="admin">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="50" y="390" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="telegram" target="qabot">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="380" y="500" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="e4" value="projections (read)" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" source="dashboard" target="pg">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e5" value="reads" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="qabot" target="pg">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e6" value="events &#183; bars" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="loop" target="pg">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e7" value="writes &#183; purges" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="nightly" target="pg">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e8" value="REST: bars &#183; quotes &#183; orders &#183; fills" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="alpaca" target="loop">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e9" value="ingest" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.1;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="feeds" target="loop">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset" x="-10" y="0" />
</mxGeometry>
</mxCell>
<mxCell id="e10" value="overrides.env &#183; restart (docker sock)" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=1;exitY=0.9;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="admin" target="loop">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="460" y="690" />
<mxPoint x="1100" y="690" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="legend" value="Legend" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#666666;verticalAlign=top;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="60" y="790" width="200" height="120" as="geometry" />
</mxCell>
<mxCell id="leg1" value="" style="rounded=0;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="legend">
<mxGeometry x="10" y="26" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="leg1t" value="Service / thread" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="24" width="140" height="18" as="geometry" />
</mxCell>
<mxCell id="leg2" value="" style="rounded=0;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="legend">
<mxGeometry x="10" y="48" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="leg2t" value="Datastore" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="46" width="140" height="18" as="geometry" />
</mxCell>
<mxCell id="leg3" value="" style="rounded=0;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="legend">
<mxGeometry x="10" y="70" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="leg3t" value="Scheduled job" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="68" width="140" height="18" as="geometry" />
</mxCell>
<mxCell id="leg4" value="" style="rounded=0;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="legend">
<mxGeometry x="10" y="92" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="leg4t" value="Broker API (money path)" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="90" width="140" height="18" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="drawio" version="26.0.0">
<diagram name="Milestone feature set">
<mxGraphModel dx="1420" dy="900" grid="1" gridSize="10" page="1" pageWidth="1540" pageHeight="900">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="title" value="Momentum — next-milestone feature set: 7 workstreams and their dependencies" style="text;html=1;fontSize=18;fontStyle=1;align=left;" vertex="1" parent="1">
<mxGeometry x="40" y="0" width="960" height="30" as="geometry" />
</mxCell>
<mxCell id="ph0" value="FOUNDATIONS &#8212; ship first" style="text;html=1;fontSize=12;fontStyle=1;fontColor=#888888;align=center;" vertex="1" parent="1">
<mxGeometry x="60" y="50" width="300" height="20" as="geometry" />
</mxCell>
<mxCell id="ph1" value="SUBSTRATE &#8212; trust the data" style="text;html=1;fontSize=12;fontStyle=1;fontColor=#888888;align=center;" vertex="1" parent="1">
<mxGeometry x="500" y="50" width="300" height="20" as="geometry" />
</mxCell>
<mxCell id="ph2" value="FLAGSHIP" style="text;html=1;fontSize=12;fontStyle=1;fontColor=#888888;align=center;" vertex="1" parent="1">
<mxGeometry x="920" y="50" width="280" height="20" as="geometry" />
</mxCell>
<mxCell id="ph3" value="OPERATOR SURFACE" style="text;html=1;fontSize=12;fontStyle=1;fontColor=#888888;align=center;" vertex="1" parent="1">
<mxGeometry x="1280" y="50" width="220" height="20" as="geometry" />
</mxCell>
<mxCell id="ws5" value="WS5 &#183; Production safety rails [S]&#xa;&#xa;CI pytest gate before :latest&#xa;qabot dead-man's switch&#xa;scheduled pg_dump backup" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=10;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="60" y="90" width="300" height="120" as="geometry" />
</mxCell>
<mxCell id="ws7" value="WS7 &#183; Dead-weight deletion [S]&#xa;&#xa;schwab/ &#183; grafana/ &#183; telemetry/ &#183; dead strategy modules&#xa;12 zero-ref tables &#183; 6 dead projections&#xa;rule: every table names its reader or dies" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;align=left;spacingLeft=10;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="60" y="280" width="300" height="130" as="geometry" />
</mxCell>
<mxCell id="ws4" value="WS4 &#183; Money-path hardening [S]&#xa;&#xa;daily self-restart (exit 0 after EOD flatten)&#xa;positive-evidence contract (empty &#8800; naked;&#xa;lost POST &#8594; by_client_order_id reconcile)&#xa;EOD broker-vs-events cage count &#183; SIGTERM" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;align=left;spacingLeft=10;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="60" y="480" width="300" height="140" as="geometry" />
</mxCell>
<mxCell id="ws2" value="WS2 &#183; Learning-flywheel resurrection [M]&#xa;&#xa;ONE population module (as-of-time, open-knowable)&#xa;consumers: live gate &#183; tuner &#183; sweeps &#183; replay &#183; labeler&#xa;schedule eod_replay + nightly_tune in production&#xa;atomic learned_params write + staleness alert" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=10;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="500" y="120" width="330" height="150" as="geometry" />
</mxCell>
<mxCell id="ws3" value="WS3 &#183; Entry-path unification [M]&#xa;&#xa;one shared gate function, both entry paths&#xa;decision-receipt event per gate pass/fail&#xa;(closes VWAP/quality vs rank drift)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;align=left;spacingLeft=10;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="500" y="420" width="330" height="130" as="geometry" />
</mxCell>
<mxCell id="ws1" value="WS1 &#183; Experiment OS [L]&#xa;&#xa;experiment = config row (population &#183; intervention &#183;&#xa;pre-registered bars &#183; min-n &#183; futility)&#xa;counterfactual replay of every logged fire&#xa;counterfactual exit ledger (all exit variants per trade)&#xa;auto verdicts: PASS / FAIL / INCONCLUSIVE&#xa;&#xa;first cohort: 10-min time-stop &#183; probe-then-add&#xa;asymmetric exit (spread floor) &#183; one-bullet rank &#183; pm1 verdict" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;align=left;spacingLeft=10;verticalAlign=top;spacingTop=6;fontStyle=1" vertex="1" parent="1">
<mxGeometry x="920" y="220" width="320" height="230" as="geometry" />
</mxCell>
<mxCell id="ws6" value="WS6 &#183; Operator control plane [M]&#xa;&#xa;dashboard POST fix &#183; sparklines &#183; LIVE badge truth&#xa;kill switch: operator-command events&#xa;(flatten all / symbol &#183; pause entries)&#xa;experiment ledger panel&#xa;effective-config panel (per-key provenance)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;align=left;spacingLeft=10;verticalAlign=top;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="1340" y="230" width="190" height="210" as="geometry" />
</mxCell>
<mxCell id="d1" value="trusted population" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" source="ws2" target="ws1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d2" value="decision receipts" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="ws3" target="ws1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d3" value="verdict events" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="ws1" target="ws6">
<mxGeometry relative="1" as="geometry">
<mxPoint as="offset" x="0" y="-18" />
</mxGeometry>
</mxCell>
<mxCell id="d4" value="safe ships" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="ws5" target="ws2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d5" value="smaller surface" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="ws7" target="ws3">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="d6" value="promoted winners land on the unified gate" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;labelBackgroundColor=#ffffff;fontSize=11;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="ws1" target="ws3">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1090" y="620" />
<mxPoint x="665" y="620" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="note4" value="WS4 is independent &#8212; ship in week 1 alongside WS5/WS7" style="text;html=1;fontSize=11;fontColor=#888888;align=left;" vertex="1" parent="1">
<mxGeometry x="60" y="630" width="330" height="20" as="geometry" />
</mxCell>
<mxCell id="legend" value="Legend" style="rounded=0;whiteSpace=wrap;html=1;fillColor=none;strokeColor=#666666;verticalAlign=top;fontStyle=1;" vertex="1" parent="1">
<mxGeometry x="500" y="680" width="360" height="140" as="geometry" />
</mxCell>
<mxCell id="lg1" value="" style="rounded=0;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="legend">
<mxGeometry x="10" y="26" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="lg1t" value="Foundation (ops / hygiene)" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="24" width="300" height="18" as="geometry" />
</mxCell>
<mxCell id="lg2" value="" style="rounded=0;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="legend">
<mxGeometry x="10" y="48" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="lg2t" value="Money-path correctness" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="46" width="300" height="18" as="geometry" />
</mxCell>
<mxCell id="lg3" value="" style="rounded=0;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="legend">
<mxGeometry x="10" y="70" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="lg3t" value="Substrate (data / gate integrity)" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="68" width="300" height="18" as="geometry" />
</mxCell>
<mxCell id="lg4" value="" style="rounded=0;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="legend">
<mxGeometry x="10" y="92" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="lg4t" value="Flagship build (Experiment OS)" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="90" width="300" height="18" as="geometry" />
</mxCell>
<mxCell id="lg5" value="" style="rounded=0;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;" vertex="1" parent="legend">
<mxGeometry x="10" y="114" width="30" height="14" as="geometry" />
</mxCell>
<mxCell id="lg5t" value="Operator surface (:8765 / :8767 / qabot)" style="text;html=1;align=left;verticalAlign=middle;fontSize=11;" vertex="1" parent="legend">
<mxGeometry x="50" y="112" width="300" height="18" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB