Swing Deck Deep Guide
The power-user reference. About a 45-minute read top-to-bottom; mostly used as a lookup once you've been around the dashboard a few weeks.
If you haven't read Swing Deck Guide Reference yet, start there. This doc assumes you know what a card looks like, what a trap chip does, and that "the math cleared" is different from "the AI told you to."
Part 1 — How it ticks
1. The five-layer architecture
Swing Deck is a stack. Each layer answers a different question. They run in order; outputs feed downstream.
| Layer | What it answers | Output |
|---|---|---|
| L1 — 11-point technical | Is the tape worth trading? | Composite score 0–100, grade A–F |
| L2 — 13 risk pillars (E1–E13) | Does the math allow this trade? | Pass / refuse, per pillar |
| L3 — 12-point war calibration | When VIX > 25, what changes? | Tighter caps, defensive overlays |
| L4 — 13-point options | If options are open, is this strategy worth it? | Long-call vs spread vs CSP, strike, DTE |
| AI surfaces (10 coaches) | What does this mean? | Triggered narration, structured output |
The framework refuses. The dashboard narrates. AI explains. You decide. That order is the brand.
1.5 The two-sleeve architecture
The stack above governs the swing sleeve. Swing Deck actually runs two books in one account, with opposite risk philosophies:
| Swing sleeve | Investor sleeve (◈ INVEST ROOM) | |
|---|---|---|
| Hold | Days–weeks | Years |
| Entry | Setup + score/R:R gate | Underwritten thesis + valuation band |
| Sizing | 1% risk off stop distance | Valuation band (cheap→none at EXTREME) |
| Stop | Hard stop, always | None — exit only on thesis break |
| Exit trigger | Stop hit / score collapse | INTACT → REVIEW → BROKEN |
| Governor | E1–E13 pillars | Hard-max (35% sleeve / 10% name) |
Capital carve-out — the two sleeves are sized off separate capital so neither distorts the other: swing_capital = NAV − max(INVESTOR_SLEEVE_CAPITAL, barbell_market_value).
Anchors enter the investor sleeve either curated (hand-picked, e.g. EOG/ICE) or via a broad quality/durability screen, then must clear the durability pillars (moat / balance sheet / reinvestment runway / patent-cliff read from the FDA Orange Book + SEC EDGAR feed — discovery-only, never sizes or gates). You underwrite with a written thesis after answering a devil's-advocate skeptic pass.
Protected holds — barbell names scored and tracked but locked out of swing actions (no auto-exit, options, or stop alerts; 🔒 HOLD).
Scoring itself runs through a lens architecture — independent frames (trend, momentum, structure, flow, value-quality) that each render a verdict and can issue a legible veto (a plain-English block with a reason, not a silent score cut). Every decision is logged to a corpus the framework calibrates against — does an 80 actually beat a 65? — so the gates tighten when confidence drifts.
2. The audit cycle, every 5 minutes
The daemon (audit_framework.py --watch) runs the cycle on a 5-min interval. One cycle, ~30–90 s for 7–10 tickers:
- Macro fetch — VIX, oil ($USD), brent ($USD), ^IRX. Determines war mode (VIX > 25), oil shock (Oil > $100), armor yield warn (^IRX < 4%).
- Regime classification —
regime_engineresolves the active regime label (OIL_SHOCK,KINETIC,WAR,NORMAL) plus per-sleeve cap overrides. - Per-ticker pass — for each symbol in
portfolio.txt+candidates.txt: - Skip if cash armor (USFR/SGOV). - Fetchdf_d(daily) +df_w(weekly) from yfinance/Polygon. -compute_daily(df_d)→ indicators (EMA stack, RSI, ADX, MACD, ATR, BB, OBV, sweep_clean). -compute_weekly(df_w)→ weekly trend + EMA alignment. -detect_catalyst(t)→ earnings calendar, headline news, Fed events. -compute_structure(df_d)→ primary_S, primary_R, levels_above, levels_below from 10 S/R sources collapsed via 0.15 × ATR confluence merging. -score_11pt(...)→ composite, grade, bias, sl_val, tp1/tp2/tp3, rr. -score_12pt_war(...)if war mode. -score_13pt_options(...)if options engine enabled. -compute_composite(...)→ final score with regime modifiers. - Pillar gate checks — sleeve caps, sector caps, hard-cash floor, drawdown. - Trap contradiction detection — see below. - Enrichment fetches: insider Form 4, float/short, RS-rank, gamma walls, comparable setups. - System-level rebalance — if portfolio drawdown > 7% (E3) or hard-cash floor breached (E5) or armor yield drops (E12),
portfolio_rebalancerwrites rotation orders. - Atomic JSON write to
audit_output.json. Dashboard polls every 5 s. - Alerts engine detects threshold transitions and emails on state changes (entry-eligible, near-stop, exit-review, etc.).
Heartbeat is written at every step (_write_audit_state) so the dashboard's audit signal can show progress and detect a stalled cycle.
3. Trap contradiction detection — the safety net
After scoring, the framework runs _detect_trap_contradictions(ind_d, ind_w, r11). Trap flags fire when two server-computed signals disagree in ways the methodology calls bagholder traps. Pre-v6.6.9 the framework had ALL the data to surface these but didn't — the user had to mentally reconcile contradictory chips. Trap surfacing is the methodology's "math floor not motivation" job.
| Trap flag | Fires when | Translation |
|---|---|---|
⚠ Trap: chase-the-top |
Strong weekly trend (ADX-W ≥ 30) AND overbought weekly RSI (≥ 75) | Move already happened; you'd pay the top |
⚠ Trap: bull-stack distribution |
Bullish EMA stack but Falling OBV with high vol | Price up, smart money out |
⚠ Trap: weak rally |
HH/HL but vol_ratio < 0.7 | Rally on no volume — usually fails |
Trap chips override the score. If you see one, the framework is refusing the trade even when the gate technically opened. Don't override.
Part 2 — The math
4. Layer 1 — The 11-point technical score
Each cell scores 0–10. Sum = 0–100 (Point 9 is the composite, not a separate scoring cell). Grades: A ≥ 90 · B 80–89 · C 70–79 · D 60–69 · F < 60.
| # | Cell | What it reads |
|---|---|---|
| 1 | Trend Confirmation | HH/HL on daily, EMA stack alignment, weekly bonus |
| 2 | Momentum & Strength | RSI band (40–65 sweet spot), ADX (≥ 30 strong), MACD bullish + hist rising |
| 3 | Volatility Context | BB width, ATR%, EMA21/price proximity, loose-trend bonus |
| 4 | Volume & Flow | vol_ratio (today vs 20-day avg), OBV trend, sweep_clean |
| 5 | Whale Sentiment | MarketAux news + AI confirmation coach output |
| 6 | Manipulation Detection | Sweeps + OBV + vol confirmation; book-aware penalty (v6.7.43) |
| 7 | Trade Execution | Price vs EMA21, structure type, entry quality near support |
| 8 | Position Sizing | Vol-adjusted (0–5) + stop-tightness (0–5); cap-breach floor at conc=2 |
| 10 | Macro Correlation | VIX leg (0–3) + sector trend leg (0–3) + per-ticker RS leg (0–4) |
| 11 | Hidden Tape | Call/put gamma ratio + put sweep + max-pain magnet + squeeze potential |
Modifiers apply after the base sum:
- SL breach: −20 (price below EMA21 stop in LH/LL structure)
- Energy-Tech inversion: −10 (oil > $100 + high-energy ticker)
- Diplomatic decay: −10 (within 48 h of named truce; Sports-Cars only)
Composite = max(0, min(100, base + modifiers)).
The cells are not equally weighted — they're equally scored. The 11-pt model trusts that a clean signal across cells matters more than any one cell's strength. That's why a single dead cell (e.g. macro at 5) doesn't tank the score, but five mediocre cells will.
5. Layer 2 — The 13 risk pillars (E1–E13)
Pillars 1–7 are baseline (always active). Pillars 8–13 are war-time / regime overlays.
Detailed mechanics per pillar:
E1 — Armor Cap (15% per asset)
Refuses: any single position > 15% of portfolio. Cash positions exempt. Structural — overrides "I'm so sure about this one."
E2 — Stop Discipline (Trade-the-Structure, v6.7.47)
Refuses: holding without a real broker stop. The stop sits at max(primary_S × 0.999, entry − 2×ATR) — tighter of structural support or 2×ATR floor. The 2×ATR floor preserves Pillar 7's spirit; structural support snaps closer when the framework can see real geometry. Mental stops negotiate. Broker stops don't.
E3 — Red-Line (7% portfolio drawdown)
Refuses: holding through a 7% drop from cost-basis high-water mark. Daemon writes 50%-cash pivot orders automatically. Multi-window thresholds added v5.6: today vs prior close ≤ −4%, week peak ≤ −7%, 30-day rolling ≤ −10%.
E4 — Score Gate (composite ≥ 80)
Refuses: new entries on tickers below B-grade (composite < 80). Gate is hard. Most setups don't clear it. By design.
E5 — Pre-Market Firewall (S&P futures −1.5%)
Refuses: new long entries when ES futures down > 1.5% at 7:25 AM MST. Exits and stop-raises still allowed.
E6 — Sector Cap (40% per theme)
Refuses: > 40% in any single sleeve (semis, AI infra, defense, pharma). Engine tags tickers at audit time. Stops the NVDA + AVGO + AMD + SMCI + MRVL "pretend diversification."
E7 — Weekly Confirmation
Refuses: new entries when weekly EMAs aren't aligned. Half the structural support is missing. Daily trend without weekly = lower-conviction setup.
E8 — Hard-Cash Floor (10%)
Refuses: going below 10% in USFR/SGOV/cash. The sizer refuses to allocate the last 10%. "If you're 100% invested, you can't add."
E9 — Earnings Proximity (≤ 3 sessions)
Refuses: new entries within 3 trading sessions of earnings. Holds and exits unaffected.
E10 — Defensive Oil Cap (15%, war regime)
Refuses: energy > 15% in war regimes (VIX > 25).
E11 — Hardware War Cap (30%)
Refuses: semis + compute infra > 30% in inversion regimes (natgas/oil/uranium term-structure inverted).
E12 — Velocity Exception (35%)
Refuses: sleeve > 35% even on momentum names. Velocity Track tickers can exceed the 25% Sports-Cars cap up to 35%, only while Velocity flag is active AND Armor Cash > 15%.
E13 — Diplomatic Decay (48h post-truce)
Refuses: full-conviction sizing within 48 h of a named truce/summit (Ukraine, Gaza, Taiwan). Sports-Cars score penalized −10. Geopolitics matters to your portfolio whether you like it or not.
The pillars are gates, not rules. They don't generate trades. They filter out trades your technical scanner wants to take but shouldn't.
6. Layer 3 — War mode (VIX > 25)
Activates automatically. What flips:
- 12-point defensive scoring runs alongside L1 (Combat Readiness, Armor Sizing, Gap-Limit Rule, etc.)
- Position caps tighten: WAR_EXPOSURE = 15% (vs 25% default per-asset)
- Pillars E10 + E11 activate (defensive oil cap, hardware war cap)
- Sports-Cars sleeve gets regime penalty in
regime_engine - Energy-Tech inversion modifier (−10) applies to high-energy tickers when oil > $100
What you do differently:
- Don't add to Sports-Cars (NVDA / AVGO / AMD).
- Anchors stay in scope but at half-size.
- Defensive sleeve (LMT / RTX / NOC / GD) becomes the active hunting ground.
- Cash floor effectively rises (the framework refuses sizing that would breach the lower cap).
Back to baseline triggers when VIX < 25 for 5 consecutive cycles, or when the regime engine clears the WAR label via macro re-classification.
7. Layer 4 — 13-point options (Level 2 only)
Activates when OPTIONS_ENGINE_ENABLED = True in config and the ticker has a Tradier chain available.
The 13 cells (each 0–10):
- Structure & Trend — same logic as L1 Point 1 with options-aware loose-trend bucket
- Volatility regime — VIX-driven; tighter when VIX > 25
- IV Rank — ≥ 30 floor, ≤ 80 cap; deep-ITM filter when in VIX trap
- Theta Budget — portfolio theta ≥ MIN_PORTFOLIO_THETA before short premium
- Delta Target — −0.30 to 0 for short puts; matches strategy
- DTE Preference — 14-day default; 7–60 acceptable
- Liquidity — bid-ask < 10%, OI > threshold
- Strategy Fit — long call vs vertical spread vs CSP, picked by IV regime
- Sentiment Alignment — MarketAux / AI thesis must match strategy direction
- Macro Correlation — same VIX/sector/RS structure as L1
- Hidden Tape — gamma exposure ratio, dealer GEX, max pain
- Manipulation — options-specific sweep + book skew detection
- Energy Penalty — applies when oil shock + high-energy ticker
Strategy picker logic:
- IV ≤ 30 → long calls (vol cheap, directional bet)
- IV ≥ 70 → short premium (CSPs, bull put spreads — sell rich vol)
- IV 30–70 → vertical spreads (defined risk)
When to ignore the recommendation:
- L1 composite < 80 (the 13-pt doesn't override L1's gate)
- Trap flag fires on the underlying
- Stale chain data (cache > 15 min)
- Earnings within 3 sessions
- Liquidity below threshold
The options layer is opt-in. If you trade equities only, you can leave it disabled — the dashboard hides the panel. If you trade options, the layer is your structured second opinion. It doesn't pick the trade. It scores it.
Part 3 — The UI, deep
8. Card anatomy — every signal, threshold, edge case
A ticker card has six zones. Top to bottom:
Header
- Ticker + sector tag (e.g.
NVDA · AI Infra) - Live price + change % (color-coded)
- Sparkline (20-bar close trend)
Score row
- Composite score (0–100) + grade (A/B/C/D/F)
- Bias chip (ACCUMULATE / HOLD / DE-RISK 50% / REDUCE / HARD EXIT)
- Audit-age chip (turns amber > 5 min, red > 15 min)
Whale toolkit (3-col)
- Structure chip (HH/HL · Ranging · LH/LL) with magnitude gate
- 🐋 RSI Exhaustion (≥ 80 amber, ≥ 90 red)
- 🧭 MACD Compass (bullish / bearish / cross-imminent)
Live-data chips (when present)
- 🚨 INSIDER SELL ($XXM) — Form 4 last 90d aggregated dollar volume; AMBER if 10b5-1 dominates (SCHEDULED), RED if EXTREME (discretionary)
- 📊 FLOAT/SHORT — short-interest %, float size band
- 🔄 RS-RANK — relative strength composite (1m/3m/6m/1y vs SPY + sector ETF), leader/laggard tag
- 🧱 GAMMA — call-wall + put-wall + zero-gamma flip level
- 🔁 COMPARABLE — count of prior matching setups (when ≥ 1)
Execution levels
- Entry · SL · TP1 · TP2 · TP3 · R:R
- SL label reads "STOP" — tooltip discloses whether it snapped to structural or sat at 2×ATR
- TP1 label same — caps at primary_R × 0.999 when tighter than 3×ATR
- R:R color: green ≥ 2 · amber 1.5–2 · red < 1.5
Position sizer
- Rec. shares (1% account risk via stop distance)
- % of portfolio at recommended size
- Cap status (within 25% per-asset cap, or "CAPPED" when 1%-risk sizing exceeds the cap)
11-point audit grid (bottom row)
A 10-cell grid showing the sub-scores that roll up into the composite. Labeled 11-POINT AUDIT (10 sub-scores + 1 composite). Cells: Trend, Momo, Vol, VPos, Whale, Manip, Exec, Size, Macro, Tape — each 0–10, color-coded. Scan for amber/red cells to know which axis is the weak link. See §8.1 for the full mapping to internal sub-score fields and what each measures.
Flags
- Color-coded by severity: red for traps, amber for warnings, neutral for informational
- Order matters — first three are most important
⚠ Trap:flags trump everything — they're the framework's veto
8.1 Entry signal badges — types and decision paths
Section 8 covered card zones. This section covers the badges that change state cycle-to-cycle — what each one means, what triggers it, and how it interacts with the rest of the gate stack. New users: read this once; you'll recognize every badge thereafter. Existing users: this is the canonical reference for "what's the difference between ARMED and ready_vetoed."
The single-line read
Every audit row produces five state badges that together answer "is this tradeable right now?" Read them top-to-bottom. Each is independent. A green ARMED at the bottom with a yellow bias at the top is the card saying yes and no at the same time — and yes-and-no resolves to no in this framework.
Five paths to ARMED (and what each means)
The dashboard surfaces five different entry-trigger paths. They are not interchangeable. Each one has its own color-coded path card so you can tell them apart at a glance.
- ✓ Above both EMA21 and EMA50
- ✓ Not extended (dist21 < 2 ATR)
- ✓ MACD bullish
- ✓ RSI in 45–70 sweet spot
- ✓ Volume ≥ 1.0× avg
The default trigger. Used by pullback_to_ma, breakout, trend_continuation, reversal setups. Per-setup criterion lists vary (breakout needs vol ≥ 1.5×; pullback needs dist ≤ 0.6 ATR). When 5/5 passes + score ≥ ENTRY_SCORE_GATE (80) + R:R ≥ 2.0 + weekly aligned + no trap flags → alert chimes. Held-aware tier resolver downgrades to info-tier if you already own shares.
Path 2 — Episodic Pivot entry-trigger (Kullamägi setup, currently shadow-only)
The EP overlay re-classifies a row's setup_type to episodic_pivot_pending when a catalyst day exists in the last 5 sessions: ≥ 4% move, ≥ 2× volume, close in upper half of range, and the catalyst close cleared the prior 20-day resistance.
When EP is detected AND today's bar breaks the consolidation high AND today closes in the upper half AND today's volume ≥ 1.2× the trailing 20-day avg, swing_ops.ep_entry_trigger.ready=True. Distinct chip — ⚡ EP ARMED — distinct alert type (entry_armed_ep).
Currently SHADOW-ONLY. config.EP_ENTRY_ALERTS_ENABLED = False by design. The framework emits the trigger and the shadow corpus records every fire with fired-entry geometry (entry = today's close, stop = catalyst-day low, TP = 3R/6R/10R Kullamägi ladder). Alerts stay silent until ≥ 30 resolved outcomes at ≥ 50% win rate and ≥ 2.5R avg winner (the v7.9.x §A.7 promotion gate). When the corpus clears those thresholds, the flag flips and entry_armed_ep alerts go live.
Read this as: the EP trigger is being calibrated in production right now, against your own basket, in real time. When it graduates it will fire alerts on the next live EP detection.
Path 3 — Bull Flag entry-trigger (similar shadow path)
Same shape as EP, different pattern: a prior trend ≥ 30% over 60d, then a tight flag pullback < 25% over 3-21 sessions. When the flag breaks with confirming volume, swing_ops.bull_flag.entry_ready fires the trigger. 🚩 BF ARMED chip, shadow-only until corpus promotion.
Path 4 — Consolidation Breakout Pending overlay
- ✓ Score ≥ 80 (quality clears gate)
- ✓ Price within 2% below resistance
- ✓ ATR contracting vs 22d avg
- ✓ Volume not collapsing (≥ 0.7×)
- ✗ Awaiting breakout above resistance — the trigger event
Not technically an "ARMED" state — it's a queue state. When a row's base setup would be ranging or consolidation but the score has cleared the gate AND price is within 2% of resistance AND ATR is contracting AND volume isn't collapsing, the setup_type re-classifies to consolidation_breakout_pending. Not an entry alert; a watch chip. Use it to set a stop-buy at the resistance level. When CBP rows actually break, they transition to breakout setup_type next cycle and Path 1 takes over.
Path 5 — No trigger / framework-refuses paths
Several non-ARMED states are still informative and end up in the shadow corpus for calibration:
ready_vetoed— entry_trigger passed but a gate refused (R:R < 2.0, score < gate, weekly unaligned, trap flag, etc.). The shadow tracker captures these to answer "did the framework correctly veto?" — 100% loss rate on this cohort means the veto is high-precision.score_cleared_setup_blocked— score is ≥ ENTRY_SCORE_GATE but the setup classifier returned a non-tradeable setup (ranging / consolidation / downtrend / reversal-without-confirmation). Captures the inverse case: "should we open the gate when the score is high but the structure isn't?"
Both cohorts are watched in tools/shadow_corpus_summary.py. If ready_vetoed ever drifts above 30% win rate, the gates are too aggressive. If score_cleared_setup_blocked ever drifts above 50%, the setup classifier is too restrictive. Both currently sit at 0% win rate — the framework's refusals are calibrated correctly.
How to read the WAIT message
When a trigger is partial — say, 3/5 on a generic breakout — the card shows "WAIT — N/M criteria met" with the failing criterion named in the tooltip. The named criterion is the only thing standing between you and ARMED. Read it specifically:
- "Volume ≥ 1.5× avg" missing → the move lacks institutional participation. Wait for a volume spike or fade the move as retail.
- "Not extended (dist21 < 2 ATR)" missing → price ran past the clean entry zone. The breakout already happened; you'd be chasing.
- "Weekly trend aligned" missing → daily is bullish but weekly is mixed or down. Higher-timeframe disagreement.
- "RSI < 75 (room to run)" missing → overbought. Mean reversion risk elevated.
- "MACD bullish" missing → momentum hasn't confirmed the structural setup yet.
Each is a different reason to wait. The badge names the specific lever you're waiting for.
Bias badges — what the framework wants you to do
The bias chip is what the framework would do with this row if it had your portfolio. Six states:
- ACCUMULATE — high-conviction, regime-aligned, all gates passing. Initiate or add.
- HOLD — meets the gate but not screaming. Already-owned: keep. Not owned: only initiate with high marginal conviction beyond the framework.
- DE-RISK 50% — gate-passing on score but a defensive flag fired (extension / sweep / weekly unconfirmed / trap warning). Already-owned: trim half. Not owned: skip.
- REDUCE — multiple defensive flags fired or score is eroding rapidly. Already-owned: trim more aggressively.
- HARD EXIT — gate-failing OR trap-veto firing OR stop-breach detected. Already-owned: exit immediately.
- CASH ARMOR — Treasury ETF (USFR / SGOV / BIL / SHY / TLT / etc). Not a stock; no entry trigger; cash-equivalent that satisfies the HARD_ASSET_FLOOR pillar.
A bias flip from HOLD to DE-RISK 50% mid-session is a regime-warning state. The framework saw something change between cycles that materially affected the trade quality. Re-read the flags row — something there is new.
Structure badges
Three primary states plus one overlay:
- HH/HL (Higher Highs / Higher Lows) — confirmed uptrend. Both daily and weekly structure agree.
- Ranging — sideways price action, no directional bias. Neither bull nor bear committed.
- LH/LL (Lower Highs / Lower Lows) — confirmed downtrend.
- consolidation_breakout_pending — overlay over Ranging when CBP criteria fire (see Path 4 above).
The chip color codes match the bias: green for HH/HL, neutral/amber for Ranging, red for LH/LL.
Structure must agree with setup type for the trigger to be tradeable. A breakout setup on Ranging structure is contradictory — the breakout overlay needs HH/HL underneath. The framework's hysteresis guards against this misalignment but if you see it, the row is in transition and you're catching it mid-classification.
Setup type badges (eight kinds, ordered by tradeability)
| Setup | Structure prereq | Entry trigger gate | What it is |
|---|---|---|---|
pullback_to_ma | HH/HL | 0 ≤ dist21 ≤ 0.6 ATR + MACD bull + weekly aligned + clean sweep + RSI > 40 + vol ≥ 1.2× | Price pulled back to 21-EMA in confirmed uptrend. |
breakout | HH/HL | dist21 > 1.5 ATR + vol > 1.2× + MACD bull | Price > 1.5 ATR above EMA21 on volume. |
trend_continuation | HH/HL | above EMA21 + EMA50 + dist21 < 2 ATR + MACD bull + RSI 45-70 + vol ≥ 1.0× | Trend intact, not extended, momentum confirmed. |
reversal | LH/LL → reclaim | reclaimed EMA21 + MACD turned bullish + clean tape + RSI > 45 + vol ≥ 1.2× | Lowest-conviction tradeable. |
consolidation_breakout_pending | Ranging + CBP criteria | (queue state, not entry) | Coiled spring — watch for break above resistance. |
consolidation / ranging | Ranging | (not actionable) | Sideways. Wait for break. |
downtrend | LH/LL | (not actionable, veto) | Downtrend confirmed. Avoid longs entirely. |
episodic_pivot / bull_flag | overlay | Path 2/3 (specific) | Special overlays — distinct from generic setups. |
R:R chip — the gate-pass color and what to do when chip and gate disagree
The R:R chip shows the displayed ratio from the current entry / SL / TP1 levels. Color:
- ≥ 2.0 → green ✓ (clears the structural R:R floor)
- 1.5–2.0 → amber (close but doesn't clear)
- < 1.5 → red ✗ (well below floor)
A separate R:R RELEASE chip appears when chip math says one thing but the gate sees another — typically because the canonical R:R reader uses different anchors (e.g., max(structural, breakout) on HH/HL setups). When this chip is present, the framework is being transparent that two valid R:R readings exist and they disagree. Trust the gate read for the entry decision; trust the chip read for sizing math. The chip will name the lever (lower entry / raise TP1 / tighten SL) that would close the divergence.
When the chip reads red but the gate reads green, the setup is technically pass-the-gate but the displayed execution levels don't reflect that pass — you'd need a different entry price OR a different TP target to make the chip and gate agree. Don't tighten the stop to force agreement. That's the gate-bypass anti-pattern; see the DXCM walkthrough in the Reference Guide.
Trap flags — when the framework vetoes against the score
Trap flags are the framework's veto layer. They sit on top of the score and override even a clean 85-score+5/5-ARMED combination. The flag list is open-ended (new traps add over time) but the canonical set as of v7.8.161:
⚠ Trap: chase-the-top— strong weekly trend at overbought RSI. The move has happened; you'd be paying the top.⚠ Trap: bull-stack— multiple bullish signals stacking simultaneously (RSI + MACD + vol + structure all green) on a name that just gapped up. Statistically reverts.⚠ Trap: sweep-detected— recent liquidity sweep (stop-hunt) before the current move. The "breakout" may be engineered.⚠ Trap: parabolic-extension— 6+ up days out of last 10, cumulative > 20%, ATR expanding. Late in the move.⚠ Trap: distribution-pattern— institutional selling overlaid on retail buying (Whale Sentiment + Hidden Tape disagree).⚠ E4 review— score below ENTRY_SCORE_GATE for review.⚠ Weekly unconfirmed— daily setup looks tradeable but weekly timeframe doesn't agree.⚠ Earnings within N sessions— earnings risk window (default 3 sessions).⚠ R:R < 2:1— gate canonical below the 2.0 floor.
Trap flags trump the score. A score-90 row with a ⚠ Trap: chase-the-top flag is a no-go regardless of how good the other badges look. Match this against your own willpower honestly: if you'd be tempted to override the trap, you've already lost the discipline argument.
Whale toolkit (3-col) — the auxiliary state
Three secondary badges in the middle of the card give institutional-flow context:
- 🐋 RSI Exhaustion — daily RSI value. Amber ≥ 80, red ≥ 90. Not gating by itself; flags when momentum is statistically over-extended.
- 🧭 MACD Compass — current MACD state plus cross-imminent forecast. Three states:
bullish,bearish,cross-imminent. - 🎯 Hidden Tape (Pillar 11) — 0-10 sub-score from gamma-walls analytics (Tradier/E*TRADE options chains). Reads "is institutional money accumulating or distributing?" When this disagrees with the entry trigger, second-opinion via Whale Confirmation modal (which pulls polygon/databento trade tape for direct evidence).
The 11-point audit sub-score grid (bottom row of the card)
At the very bottom of each card sits a 10-cell grid labeled 11-POINT AUDIT (10 sub-scores + 1 composite). Each cell is 0–10, color-coded by value. The composite at the top of the card is what these roll up to; the sub-score grid is how it got there. Scan for amber/red cells to know which part of the setup is the weak link.
| Cell | Sub-score (internal field) | What it measures |
|---|---|---|
| Trend | trend_confirmation | Daily structure (HH/HL) + weekly alignment |
| Momo | momentum_strength | RSI/MACD combination — overbought penalty above 75 |
| Vol | vix_context | VIX regime fit — calm/elevated/war modifiers |
| VPos | volume_nodes | Volume confirmation — vol_ratio vs 20d avg |
| Whale | sentiment_sweeps | News + insider + sweep detection — institutional flow read |
| Manip | manipulation_trap | Trap detector — chase, bull-stack, distribution patterns |
| Exec | execution_guard | Spread, liquidity, slippage envelope |
| Size | position_sizing | R:R floor + cap headroom check |
| Macro | macro_correlation | Regime fit (STAGFLATION / OIL_SHOCK / etc) and sector bias |
| Tape | hidden_tape | Gamma walls + dark-pool prints (Pillar 11) |
The composite is computed from these cells with modifier weights (SL breach −20, energy-tech inversion −10, etc.). Grades: A=90+, B=80–89, C=70–79, F<70. Read the cells before reading the composite — the composite hides which axis is failing; the grid surfaces it.
The 13 risk pillars (E1–E13) — backend gate layer, not card chips
The 13 pillars are the framework's backend exposure-and-gate layer. They don't render as a row of chips on every card. They show up as:
- Trap flags when triggered — e.g.
⚠ R:R < 2:1is the surface form of E4 + the R:R floor;⚠ Weekly unconfirmedis the surface form of E7. - Cap-status notes in the position sizer — e.g. "CAPPED at 15%" for E1 Armor Cap, "13.3% weight" for the per-asset cap E1 + sizer max-exposure.
- Bias-state changes — e.g. HARD EXIT for a stop-breach (E2), CASH ARMOR pivot when E3 Red-Line fires.
The canonical pillar set as of v7.8.161:
| Pillar | Name | What it gates |
|---|---|---|
| E1 | Armor Cap | 15% per-asset defensive exposure cap |
| E2 | Stop Discipline | Trade-the-Structure SL anchoring |
| E3 | Red-Line | 7% portfolio drawdown auto-cash pivot |
| E4 | Score Gate | Composite ≥ 80 to initiate |
| E5 | Pre-Market Firewall | S&P futures −1.5% kill switch |
| E6 | Sector Cap | 40% per-theme exposure cap |
| E7 | Weekly Confirmation | Weekly trend must align with daily |
| E8 | Hard-Cash Floor | 10% USD/SGOV minimum |
| E9 | Earnings Proximity | ≤ 3 sessions window block |
| E10 | Defensive Oil Cap | 15% in war regime |
| E11 | Hardware War Cap | 30% during energy inversion |
| E12 | Velocity Exception | 35% max sleeve |
| E13 | Diplomatic Decay | 48h post-truce cooldown |
A pillar violation produces a flag, not a chip. When you see a trap flag on a row, look up which pillar it's the surface form of — the trap is the symptom; the pillar is the rule being enforced.
When two badges disagree — ARMED + AUDIT GATE REFUSES
The most important disagreement pattern to learn. The trigger chip can be GREEN while a RED banner says the audit gate refuses. Below is the canonical example — the actual modal from DXCM on 2026-05-20.
- ✓ Volume ≥ 1.5× avg (breakout thrust)
- ✓ MACD bullish
- ✓ Price > 1.5 ATR above EMA21
- ✓ RSI < 75 (room to run)
- ✗ Weekly trend aligned
What this means: the entry mechanics fired, but the composite gate doesn't approve. Score below 80, R:R below 2.0, weekly unaligned, or a trap flag firing — any one will produce this disagreement. The trigger is necessary, not sufficient. Framework's safest default: no-trade when these disagree.
Other disagreement patterns
Same-field-different-writers is a real bug class the framework has hit 15+ times across v7.x. The architecture now enforces canonical readers (rrForDisplay, rr_canonical_from_row, etc.) so chips and alerts agree by construction. But when you see disagreement on screen:
- Card chip ≠ alert text → trust the card. Post-v7.8.146 the alert engine mirrors the card's canonical reader. Pre-fix it didn't; if you see drift, it's a stale process — restart.
- Modal R:R ≠ card R:R → trust the frame. The card reads at current price; the modal reads at planned fill. If you're using a limit order at the modal's planned-fill price, trust the modal. If you're using a market order at current price, trust the card.
- Coach narrative ≠ score → the coach is an LLM second-opinion verification layer. When it disagrees, read its
recommended_adjustmentfield carefully — it may be flagging a real edge case the score didn't weigh. - Three badges green, one red → trust the red. The badges are AND-gated for entry, not OR-gated. The red one is the constraint.
The AND-gate decision pipeline
A useful mental model: every entry decision passes through a series of gates. The trigger gives the trade idea. The score gate, the R:R gate, the weekly gate, the trap-flag gate, the pillar-cap gate, the sizer cap, and the bias each get a separate veto. Any one of them blocks, the whole trade blocks.
What changed in v7.x for entry badges
If you're returning from a pre-v7.5 build:
- v7.4.9 introduced
rrForDisplay(t, role)so the R:R chip and alerts read from the same canonical math. Pre-fix the chip could be green while the alert chimed at a different R:R. - v7.8.107 added the held-aware tier resolver —
entry_armedon a name you already own downgrades to info-tier (no triple-beep on a buy signal for shares you already have). - v7.8.130 added the EP entry trigger in inert mode (Path 2 above). Shadow capture only — no alerts until corpus clears the promotion gate.
- v7.8.146 wired the alert engine to mirror
_rrCanonicalexactly. Now alerts never fire on R:R-divergent ARMED signals. - v7.8.149 consolidated five different R:R consumers behind
rr_canonical_from_row(t)so adding a new consumer can't drift. - v7.8.150 locked all multi-writer files (universe.txt, positions.json) with fcntl symmetry. Dashboard sync can't clobber daemon writes anymore.
- v7.8.156 restored the legible-veto compute that had been silently broken for 22 hours — the "WAIT — N/M criteria met" tooltip now correctly cites the failing criterion.
9. The modal — every tab
Click any card. Modal opens. Header has:
- Refresh chip (
↻ Refreshed @ HH:MM:SS) — visible receipt that the data was pulled fresh - Audit-age chip — same as the card, but in modal context
- Score breakdown — 11 cells with their values
Tabs:
- Execution — entry/SL/TP1–3, R:R, position sizer, broker order builder
- Trap & Structure — auto-classified state (TRAP / FADE / CHASE / CLEAN / NEUTRAL) + AI override (Trap & Structure Coach)
- Whale Sentiment — news headlines, dark pool flow, AI Whale Confirmation Coach
- Hidden Tape — gamma data, max-pain magnet, squeeze potential, dealer GEX
- Position History — your trades on this ticker, P&L, score-drift over time
- Catalyst — earnings calendar, Fed events, news with AI Catalyst Interpreter
- Comparable Setups — prior tape matches with outcome stats (when ≥ 1)
Critical UX rule (v6.7.17): the modal is sacred during a session. Any code path that mounts a coach panel must respect _isModalOpen() or the LLM-loaded coach content gets destroyed. If you're hacking on the dashboard and a coach disappears mid-session, that's the rule you broke.
10. The 10 AI coaches — when, why, what
| Coach | Trigger | Payload it gets | What it produces |
|---|---|---|---|
| Pillar Coach | Pillar violation/warn | Violated pillar + position state + caps | "You're at X% in Y; pillar Z says reduce to W" |
| Exit Coach | Score < 70 OR SL approached | Position state + new score + signals | Sell vs reduce vs wait, with reasoning |
| Entry Coach | ARMED state | Full entry context, pillars, R:R, weekly | Thesis vs risk in one read |
| Devil's Advocate | Conviction high (≥ 90 + ARMED) | Bull thesis + position context | Bear case, adversarial — that's the point |
| Thesis Drift | 14d-old AI thesis vs today | Both theses + signal diff | Where the read changed and why |
| Position History Audit | Held position with score drop | Trade history + audit timeline | Why this position is no longer scoring |
| Comparable Setups | Today's tape matches prior | Comparables + outcome stats | What happened last time |
| Catalyst Interpreter | News / earnings / Fed detected | Catalyst details + ticker context | What it means for this ticker |
| Whale Confirmation | Flow contradicts price | Whale data + price action | Smart money is in or out |
| Trap & Structure | Trap detector fires | Structure state + contradiction details | Walks the contradiction in detail |
Coach payload contract: each coach receives structured inputs (no free-text). Each produces structured output that the dashboard renders into a fixed panel. No chat box. Ever. The coaches are bound to framework events, summoned by triggers, never by free-form questions.
Threshold-citation guard (v6.6.40+): all coaches inject _THRESHOLD_CITATION_GUARD into their prompts so they cite payload thresholds (entry-score gate, R:R floor, sleeve cap, sector cap, stop %) rather than hardcoding them. This is why a coach saying "the 80/100 entry gate" vs "a 80/100 entry gate" matters: the first is canonical, the second is the AI hallucinating a threshold the framework didn't pass it.
Cache TTL: 5 minutes per coach per ticker. Stale-coach badge fires on the panel when audit data refreshes without a re-classify; user clicks ↻ Regenerate to refresh.
Cost tracking: every coach call logs to ai_thesis_log.jsonl with token counts + model + cost. Cost-meter incident (2026-04-28) caught the bug where the cost calc was missing web_search_requests fees — that's now part of the canonical accounting ($10/1000 web_search calls).
Part 4 — Execution
11. Broker integration — preflight, brackets, ladder
The 8-check preflight chain
Every BUY order runs broker_guard.preflight_new_order() before E*TRADE sees it. Strictly ordered, fail-fast:
| # | Guard | Refuses |
|---|---|---|
| 0 | guard_writes_enabled |
Master kill switch (set BROKER_WRITES_ENABLED=false to disable all writes) |
| 1 | guard_circuit |
Recent failures > threshold; circuit breaker open |
| 2 | guard_rate_limit |
E*TRADE rate-limit (50/min default) |
| 3 | guard_audit_freshness |
Audit > 15 min old (G6 stale_audit) |
| 4 | G1 trade_dollar_cap |
Notional > MAX_TRADE_USD |
| — preview returns here — | ||
| 5 | G2 daily_order_budget |
Rolling 24h order count > MAX_DAILY_ORDERS |
| 6 | G4 symbol_cooldown |
Re-order on same symbol within cooldown |
| 7 | G3 new_order_token |
HMAC token from preceding preview, binds (cid, account, symbol, qty, action, price_type, prices) |
G5 — R:R minimum runs inside G1 (v6.5; v6.6.4 limit-price-aware). Refuses BUY when audit R:R < BROKER_RR_MIN (default 2.0). For LIMIT orders, recomputes R:R from planned fill price. Set BROKER_RR_MIN=0 to disable.
Stages:
- stage="preview" → skips G2 + G3 (no order placed)
- stage="place" → full chain
- stage="cancel" → only 0–2 (kill switch never blocks a cancel)
Bracket order flow
Dashboard sends a preview first to get a preview_id. Then place_bracket_order submits the BRACKETED body with two legs:
- Entry leg — STOP_LIMIT or LIMIT, GOOD_FOR_DAY
- SL leg — STOP or STOP_LIMIT, GOOD_UNTIL_CANCEL (stays after entry fills)
The SL leg auto-opposites the entry action (BUY → SELL, SELL_SHORT → BUY_TO_COVER).
E*TRADE returns order IDs for both legs. Reconciler tracks status.
TP ladder reconciler
broker_tp_ladder.py manages the 40/40/20 scale-out. State file: broker_ladder_state.json. Per ticker:
- Snapshot
original_qtyso 40/40/20 is computed against the starting position even if partials fill. - TP1 placed immediately at the recommended price.
- TP2 + TP3 queued internally (NOT placed at broker yet).
- Reconcile cycle: query broker for current leg status:
-
OPEN→ keep waiting -FILLED→ mark done, advance + place next leg -CANCELLED→ user cancelled at broker; markpaused(don't auto-advance) - Source of truth = broker. Local state file is a CACHE reconciled every cycle. Orphan orders we don't recognize are ignored.
Recovery from broker failures
- Token expired → topbar broker chip turns red; re-authorize via Settings menu.
- Rate-limited → exponential backoff (180/360/720 s).
- Code 100 →
<message>service unavailable</message>. First check is COID length (must be < 20 chars; v6.7.40 lesson). Generators usef'sd{secrets.token_hex(8)}'(18 chars) to stay under the cap by construction. - Connection refused → fresh connection retry with backoff.
- Singleton wedged → auto-reset on circuit-open transition.
12. Calibration & customization — what to touch, what not to
settings.json (canonical)
| Key | Default | When to change |
|---|---|---|
BROKER_RR_MIN |
2.0 | Rare. Set 0 to disable G5. |
BROKER_MODE |
live |
Switch to dryrun for testing without firing real orders. |
BROKER_WRITES_ENABLED |
true |
Set false for read-only analyst mode. |
LICENSE_KEY |
required | Set once, don't touch. |
OPTIONS_ENGINE_ENABLED |
false |
Enable for L4 options scoring. Requires Tradier chain access. |
settings.local.json overrides
Per-user / per-machine tweaks that don't ship to the repo. Same shape as settings.json. Wins over settings.json for any key that's set.
Env vars (for Docker / cloud)
ANTHROPIC_API_KEY,OPENAI_API_KEY— AI coach providersE_TRADE_KEY,E_TRADE_SECRET— brokerTRADIER_TOKEN— options chain dataPOLYGON_API_KEY— equity data fallbackDATABENTO_API_KEY— premium tapeMARKETAUX_API_KEY— sentiment
Things you should NOT touch
- ATR multipliers (
ATR_SL_MULT=2.0,ATR_TP1_MULT=3.0, etc.) — calibrated as v6.6 canon. - Pillar caps (
MAX_EXPOSURE=0.25,SECTOR_CAP=0.40,HARD_ASSET_FLOOR=0.10) — calibrated against years of position-sizing memory. - Score thresholds (80 entry gate, 70 de-risk, 60 exit) — calibrated against 8,741+ historical audits. Don't move them.
The framework has been calibrated. If you find yourself wanting to lower the gate to "let more setups through," that's the urge the framework is built to refuse. Tighten your watchlist instead.
Part 5 — Operating reality
13. Edge cases & recovery
| Symptom | Most likely cause | Fix |
|---|---|---|
| Audit signal red, > 15 min stale | Provider timeout, framework wedged | Check topbar; hit refresh; restart daemon if persistent |
| Topbar broker chip red | E*TRADE token expired | Settings → re-authorize |
| All cards grey | yfinance rate-limited or down | Wait one cycle; check audit_dashboard.log |
| Coach panel says "loading" forever | LLM provider timeout | Click ↻ Regenerate; check API key in env |
| Alerts not firing | alerts_engine daemon stopped |
ps aux | grep alerts; restart |
| Bracket order rejected (code 100) | COID > 20 chars OR genuine service outage | Check client_order_id in log; if < 20, retry after backoff |
| Score moved 5+ points cycle-to-cycle | Live data refresh or sentiment swing | Look at the cell breakdown; if no clear cause, restart for clean state |
| TP ladder paused | User cancelled at broker | Modal → review legs → resume or reset |
| Modal coach disappeared mid-session | Code path didn't respect modal-open guard | Bug; reload the page |
| Version banner says "force upgrade" | App version below MIN_VERSION |
git pull && restart |
The "everything turned grey" moment: usually one of three things — provider degradation, license check failing, or the framework process died. Check audit_dashboard.log first. The log will tell you which one.
14. Case studies library
These are the calibration moments that shaped the framework. Each is ~½ page. Read them once; the patterns recur.
VRT TRAP→NEUTRAL (the inverted swept-low rule)
What fired: Original swept-low rule classified VRT as TRAP whenever today swept the prior-day low and close > primary support. VRT had been chronically misclassified TRAP on routine pullbacks.
Root cause: A swept-low that closes above support is a bullish reversal, not a trap. The rule was inverted from the bullish-swept-high TRAP logic without flipping the inequality.
Fix: Geometry classifier now reads swept-low + close > S as NEUTRAL (bullish potential reversal, not failure).
Lesson: When a rule fires on every routine pullback, re-read the rule. It's probably inverted.
Companion case: VRT also produced a published blog post about a separate moment — score 60/D / NO ENTRY — TRAP on VRT despite "trend continuation" being structurally true. R:R was 1.5 (below 2.0 floor); ADX 22; volume 0.52 × normal; RSI 69 daily / 81 weekly; 5 wick sweeps. Framework's read: "Someone is painting this chart sideways-up while distributing — don't be the bagholder who buys $328 on 0.5 × volume after a 30% run." User didn't pull the trigger. Hindsight: would have been right as an investment, not a trade. Trade-quality and structure are separate questions.
AAPL EXTREME→SCHEDULED (10b5-1 distinction)
What fired: insider_transactions._classify_signal() originally flagged any portfolio with ≥ 5 sells, 0 buys, ≥ $5M as EXTREME_SELLING. AAPL fired EXTREME with $25M of sells.
Root cause: ≥ 80% of that volume was 10b5-1 pre-planned — insiders committed months ago while not in possession of MNPI. Today's volume reflects a calendar, not a decision.
Fix (v6.5.0a-4): SCHEDULED_SELLING short-circuit before discretionary classifiers:
if is_predominantly_10b5_1 and sell_count > buy_count:
return "SCHEDULED_SELLING"
The same false-positive is now an amber/neutral chip when ≥ 80% of dollar volume carries the 10b5-1 flag.
Lesson: Insider data needs context. The number alone is misleading; the type of sale carries the signal.
NVDA TRAP→CHASE (auto-rule override)
What fired: structure_classifier.auto_classify_state() returned TRAP on NVDA from a swept-low pattern.
Root cause: The level wasn't a structural support; price was extended > 1.5 × ATR from S/R; momentum-only setup. That's CHASE, not TRAP.
AI synthesizer override: Flipped the verdict from TRAP to CHASE based on geometry the rules didn't capture.
Lesson: "The auto-rule is the prior, not the verdict — the AI then has a chance to override based on geometry the rules don't capture." Rules give the prior; AI gives the verdict. Both ship to the user's panel with rule reasoning AND AI override note.
PLTR insider sell ($435M Thiel)
What fired: PLTR's insider chip read 🚨 INSIDER SELL ($435M).
Detection: 227 sales vs 0 buys in 6 months. Peter Thiel sold 4M shares in 90 days. Director Moore sold 16k on April 15.
Pattern caught on 3 of 6 calibration tickers: PLTR (Thiel), GOOGL (Pichai 2.53M), NVDA (953,976 shares + 15:0 ratio).
Lesson: Insider-selling detection landed on 3 of 6 calibration tickers — the #1 signal AI consistently catches that the 11-pt framework misses. Drove the v6.5 priority bump making Form 4 ingestion canonical.
MU 2026-05-05 (the trap chip in action)
Setup:
- Score: 80/B · HOLD — Bullish · 80
- R:R: 2.45 (clears 2:1 floor)
- Entry $640.20 · SL $599.75 (struct, ~6% drawdown) · TP1 $739.42 (3×ATR — no structural cap)
- Trap flag: ⚠ Trap: chase-the-top
- Weekly: ADX 41.5 (extreme trend) · RSI 80.3 (extreme overbought)
Temptation: every momentum signal is screaming yes. Score is a clean 80. R:R is fine. Daily HH/HL. Bullish news. Call-dominant gamma.
Framework's read: Trap detector caught what the score gate missed. Strong weekly trend on overbought RSI = bagholder pattern. The move has happened. compute_structure couldn't find a primary_R for MU — so the framework can't see where price would actually pause. TP1 sits at $739 because there's no closer ceiling, but that's a 15.5% straight-line run. With weekly RSI at 80, improbable.
Decision: Wait. Watchlist alert at $610–620 — that's where MU pulls back to a tight-structural setup with a real edge.
Lesson: This is the VRT pattern restated. Clean structure, wrong moment. The first override of a ⚠ Trap: flag is the most expensive trade you'll ever make.
The cost-meter incident (meta-case)
What happened: An hour after the v6.4.0 launch, a 12¢ Anthropic charge didn't reconcile with the dashboard's recorded cost.
Two bugs compounding:
1. Whale retry-burn — the Whale Confirmation Coach panel's Retry button fired a fresh paid Anthropic call instead of using the 5-min cache. Stale-cache fallback was missing on the retry path.
2. Missing web_search tool fee — cost calc counted Anthropic input/output/cache tokens but not the $10/1000 server_tool_use.web_search_requests line. Each call invoked web_search 6–8× → recorded cost was ~50% under reality.
Fix: Cost calc reads usage.server_tool_use.web_search_requests from the API response; falls back to scanning content for server_tool_use blocks; adds web_search_requests × $0.01. Whale Retry now uses the 5-min cache; 90s timeout. Per-coach cost capture across all 7 v5.7 AI coaches.
Lesson: "You found a real bug an hour after launch by being annoyed at a 12¢ charge. That's the kind of pressure-testing that catches things." Cost discrepancies are signals.
15. Bug class catalog (the recurring patterns)
These are the bug classes the framework has hit more than once. Each one was caught and shipped a fix; each one tends to recur in new code unless you grep for the pattern.
| Pattern | Where it shows up | Fix |
|---|---|---|
| Timezone anchoring | time.time() vs getmtime(), daily reset boundaries |
Use ZoneInfo("America/New_York"); never bare datetime |
| Atomic writes | JSON state files | Always temp + os.replace; never write directly |
| Cross-surface fix-leakage | Same scoring logic copy-pasted (11pt vs 13pt) | Run diagnostic recipe against BOTH surfaces |
| Baseline-migration leak | Hardcoded constants downstream of new baseline var | Grep for the hardcoded value before shipping |
| Same field, different formula | closed filter, win definition, profit factor |
Rename or unify |
| Modal-render guard staleness | render() blocks during modal-open, data freezes | Add targeted in-place rebuild path |
| DOM-bound observer survival | innerHTML rewrite destroys observed subtree | Disconnect-and-null at every site that replaces target |
| Brand-contract sad-path leaks | Banners are easy; empty states / toasts / chip tooltips are slow drips | Run brand-contract grep end-to-end, not just on banners |
| DOMContentLoaded race vs render() | Component depends on data not yet loaded | Cache + v5states:ready re-fire pattern |
| Hardcoded sticky offsets | top: 44px breaks when sticky parents wrap |
Use var(--Xheight) driven by ResizeObserver |
| Stacking-context trap | Descendant of finite-z-index sticky parent | Bump parent's z-index above all floating descendants |
| Disambiguation tooltips encoding the bug they prevent | "NOT to be confused with Pillar N" | Scan disambiguation text when fixing labels |
| Undocumented vendor caps | E*TRADE COID 20-char limit | Probe boundaries (1, 5, 10, 15, 20, 21, 25) |
| Symptom-text describing failure category, not cause | Generic error text masks specific cause | Diff request bytes between working and broken paths |
| Gate-vs-element-class divergence | Class predicate gate (.contains('show')) misses elements |
Audit every element supposed to flow through the gate |
The pattern that's hit most often: same field name carrying different formulas across surfaces. Always rename or unify. Don't trust two surfaces to "do the same thing" because they share a name.
Where to file bugs
If something looks off — a chip that shouldn't be there, a coach that won't load, a score that doesn't match the cell breakdown, a broker order that errors out — write it down before you investigate. A 30-second note ("MU showed Hidden Tape 5 in modal but 6 in compact") becomes an hour-saver six weeks later when you're debugging the same thing.
Three places to write it:
audit_dashboard.log— the framework's own log. Most issues leave a fingerprint here.tail -50 audit_dashboard.logis the first move.broker_orders.log— broker-specific issues (preflight refusals, place errors, reconciler diffs).- The bug-class catalog above — if it's a pattern that's recurred, add a row.
Swing Deck is a trading framework. Not financial advice.
See Swing Deck Guide Reference for the everyday user manual. See FRAMEWORK_AND_RISK_PILLARS.md for the internal calibration reference (per-cell scoring rubrics, historical case calibration, implementation notes).