# MAINNET-PREFLIGHT-RECON — Architecture Audit **Phase:** MAINNET-PREFLIGHT-RECON (read-only) **Stand:** 2026-05-09 nach Commit `0734371` (B-REPORTER-FIX-2) **Ziel:** Architektur-Audit mit Q-Fragen, „Frozen-Baseline"-Konzept, Phasen-Plan und Testnet-Drill-Plan, damit ein späterer Mainnet-Connect mit pre-existing Spot-Holdings sicher und reversibel verläuft. **Status:** Read-only. **Kein Code, keine Migration, kein Bot-Restart, kein Mainnet, kein Push.** **Vorbedingung:** GO MAINNET-PREFLIGHT-RECON erteilt 2026-05-09. --- ## 1. Executive Summary Aus der Snapshot-Diagnose (read-only `fetch_balance` gegen Live-Testnet) wissen wir: - **446 Assets** liegen in der Testnet-Wallet, **436 davon sind „pre-existing"** — vom Bot nicht in `state['positions']` getrackt. - **5 vom Bot getrackte Positionen** (APE/ZEC/CHIP/XRP/SEI) haben alle `real_qty > state_qty` (DCA-Rückstände + Default-Bonus). - **Top-21 Holdings nach USDT-Wert ≈ 102 244 USDT**, davon allein **BTC = 80 856 USDT**. - Bot's `total_value` zeigt **~10 000 USDT** — das ist **Faktor 10× off** gegenüber realem Wallet-Wert. Die gute Nachricht aus der Modul-Analyse: | Modul | Pre-Existing-Sicherheit | |---|---| | `ExchangeBalanceProvider.get_free_quote_balance("USDT")` | liest nur USDT-`free` → BTC/ETH/etc. nicht doppel-gezählt | | `paper_trader.get_portfolio()` | rechnet nur `state.cash + sum(state.positions[*].quantity * current_price)` | | `position_sizer.calculate(...)` | bekommt `portfolio_value` aus get_portfolio, also **nur Bot-Sicht** | | `multi_strategy_position_sizer.calculate(...)` | analog | | `RiskManager.calculate_position(total_value, ...)` | total_value ist Bot-Sicht, also **konservativ klein** statt zu groß | | `paper_trade.execute_sell` / `live_trade.execute_sell` | sellt nur `state['positions'][symbol]['quantity']` → **niemals pre-existing-Holdings** | | N7.2 Stablecoin/Peg | hard-blockiert 19 Stable-Bases als BUY-Target | | N8.1 Balance-Guard | zentral nur free USDT, ignoriert non-quote-assets | **→ Die Gefährdung ist nicht „Bot verkauft heimlich deine BTC".** Das passiert durably nicht. **Die Gefährdung ist:** 1. **Display-Verwirrung:** Operator sieht 10k im Dashboard, real liegen 100k+ im Wallet → Risk-Calc-Wahrnehmung falsch 2. **Symbol-Konflikt:** Bot kauft 0.05 BTC, Wallet hat schon 1.0 BTC → state-position trackt nur 0.05; SELL würde 0.05 verkaufen (kein Loss), aber DCA/Pyramid/Risk-Logic operiert auf falscher Basis 3. **State-Mismatch-Loops:** Wenn `state.qty > real.qty` (z.B. Operator außerhalb-Bot-Sell): SELL → `insufficient_funds` Spam-Errors (siehe live errors.log: 5× TRUMP/USDT am 2026-05-08) 4. **Universe-Filter ignoriert pre-existing-bases:** Bot scannt 197 Symbole, einige davon sind genau die wo User schon was hält → unbeabsichtigtes Hinein-Buying **Lösung:** „Frozen Baseline"-Pattern (Architektur in §6) — eine optionale `baseline_holdings.json` Datei, die deklariert welche Wallet-Holdings vom Bot bewusst **frozen** (nie traden) oder **managed** (aktiv tracken) oder **tradable_quote** (nur als Cash-Pool) behandelt werden. --- ## 2. Status Quo (was wir heute haben) ### 2.1 Mainnet-Block heute durably aktiv 5-Layer Stack (siehe G10-4.0 Audit + G10-CLEANUP-MINOR commit `3f5528d`): | Layer | Surface | |---|---| | L1 `.env` | `Settings.BINANCE_TESTNET=True` (primärer Mainnet-Gate) | | L2 Writer | `runtime_config_writer.py:_assert_testnet` | | L3 Worker F2 | `command_worker.py:_g10_4_2_assert_testnet` Pre-Check | | L4 Worker | `ALLOWED_ENVIRONMENTS['apply_profile_testnet']={"testnet"}` | | L5 GUI | `payload.environment='testnet'` hardcoded in Filament Apply-Action | Plus durable Prerequisites-Chain (alle ☑ closed): B-FEE-FIX 1+2+3+4-1, B-OUTAGE-RESILIENCE-1, Operator-Drill 502. ### 2.2 Snapshot-Daten (aus Diagnose vom 2026-05-09) **446 Assets in Testnet-Wallet.** Top 21 nach USDT-Wert: | Asset | Qty | USDT-Wert | |---|---:|---:| | BTC | 1.0 | 80 856 | | ETH | 1.0 | 2 331 | | XRP | 514 | 731 | | BNB | 1.0 | 652 | | OP | 3 708 | 613 | | ARB | 4 059 | 580 | | FIL | 468 | 569 | | APT | 490 | 548 | | UNI | 144 | 539 | | NEAR | 342 | 534 | | LINK | 50 | 521 | | AVAX | 52 | 519 | | DOT | 383 | 517 | | ADA | 1 885 | 514 | | ATOM | 254 | 492 | | AAVE | 5 | 481 | | DOGE | 4 447 | 487 | | SOL | 5 | 467 | | LTC | 8 | 465 | | TRX | 561.6 | 197 | | **USDT cash** | 9 631 | 9 631 | **Bot-state['positions'] heute:** 5 Positionen (APE/ZEC/CHIP/XRP/SEI) — alle haben real_qty > state_qty. ### 2.3 Empirisches Verhalten (Bot lebt seit Wochen mit dieser Realität) Auf Testnet hat der Bot **nie** auto-pre-existing-Holdings verkauft. errors.log zeigt nur 5× insufficient_funds-Errors auf TRUMP/USDT (2026-05-08, state>real-Mismatch). Das bestätigt: durable rule „Bot sellt nur state['positions']" funktioniert in der Praxis. --- ## 3. Mainnet-Risiko-Analyse (per Module) | Bot-Komponente | Verhalten heute | Mainnet-Risiko | |---|---|---| | **`fetch_balance` Initial** | liest alle 446 Assets bei Connect | OK — info-only, keine Mutation | | **`state['cash']` Sync** | überschrieben mit `bal['USDT']['free']` (oder bleibt von Testnet?) | ⚠ je nach Implementation; Testen | | **`state['positions']` Persistenz** | `live_portfolio.json` ist persistent | ❌ Mainnet würde alle 5 Testnet-Positionen erben → SELL-Errors | | **`get_portfolio().total_value`** | nur bot-managed Werte | ⚠ Display 10× off; **kein** Risk-Calc-Schaden | | **N8.1 Balance-Guard (USDT-free)** | ✅ ignoriert non-USDT | safe | | **`risk_manager.calculate_position`** | nutzt total_value (= bot-Sicht) | safe (konservativer als nötig) | | **N7.2 Stablecoin-Block** | 19 Bases hard-blocked | safe für AEUR/USDC/etc. | | **`universe.scan_all`** | filtert nach Vol+Spread, kennt baseline nicht | ❌ würde BTC/ETH-Trades zulassen während User dort bereits Holdings hat | | **`paper_trader.execute_buy`** | check `if symbol in state['positions']` für DCA | ⚠ kein-state → Bot kauft, nicht-mismatch-aware | | **`paper_trader.execute_sell`** | sellt `state['positions'][sym].quantity` | ✅ pre-existing safe | | **DCA / Pyramid Logic** | rechnet auf state-qty | ⚠ wenn real > state → falsches DCA-Ratio | | **MonitoringDashboard total_value** | aus bot-Sicht | ⚠ Anzeige-Verwirrung 10× off | | **GUI Mainnet-Banner** (heute hardcoded „TESTNET · Mainnet blocked") | ✅ Testnet | ❌ würde nach Switch fälschlich grün bleiben | | **CommandBus Apply/Clear-Pfad** | testnet-only durably | safe (würde Mainnet-Apply ablehnen) | --- ## 4. Was bricht **wirklich** auf Mainnet ohne RECON-Lösung ### 4.1 Hochrisiko (Mensch-Schaden möglich) | Risiko | Mechanismus | Mitigation heute | |---|---|---| | **State-Mismatch SELL-Errors** | Testnet-resident state['positions'] (APE/ZEC/CHIP/XRP/SEI) auf Mainnet null reale Qty | ⛔ keiner — manuelle Reset des state vorher nötig | | **GUI-Banner zeigt fälschlich „Mainnet blocked"** | hardcoded Display | ⛔ Operator denkt Bot ist sicher, ist es nicht | | **Universe-Buy in pre-existing-Symbol** | Scanner sieht BTC, kauft 0.05 zusätzlich; state.qty=0.05, real=1.05 | ⛔ kein Schutz; nicht-Loss aber Verwirrung | ### 4.2 Mittelrisiko (Operations-Schaden) | Risiko | Mechanismus | |---|---| | Display-Total 10× off | Operator-Wahrnehmung verzerrt; Decision-Making auf falscher Basis | | Risk-Limits operieren auf Bot-Sicht | konservativ-zu-klein; kein Loss-Pfad, aber Sub-Optimal | | Reporter-Telegram-Alerts mit falscher Total-Value | kosmetisch + Operator-Verwirrung | | state.qty > real.qty Loops | wenn Operator extern verkauft → Bot SELL → insufficient_funds → endless retry-Spam (B-OUTAGE-RES-1 fängt teilweise) | ### 4.3 Niedrigrisiko (durably abgedeckt) | Aspekt | Mitigation | |---|---| | Auto-Sell von pre-existing | ✅ durable rule, empirisch über Wochen verifiziert | | Stablecoin-Auto-Buy | ✅ N7.2 | | Mainnet-Apply-Versehen | ✅ 5-Layer-Block | | Available-Balance-Verzerrung | ✅ N8.1 nur USDT-free | --- ## 5. Frozen-Baseline-Konzept (Architektur-Vorschlag) ### 5.1 Kern-Idee **Eine optionale State-Datei `trading/state/baseline_holdings.json`** — analog zu `runtime_config.json` aus G10-4.2. Sie deklariert pro Asset eine **Policy**, die die Bot-Komponenten konsumieren. ```jsonc { "captured_at": "2026-05-09T20:30:00Z", "captured_via": "operator_apply", "environment": "testnet", // testnet | mainnet "_meta": { "command_id": "", "checksum": "", "phase": "RECON-2.1" }, "holdings": { "BTC": { "qty_at_baseline": 1.0, "policy": "frozen", "note": "long-term hold" }, "ETH": { "qty_at_baseline": 1.0, "policy": "frozen" }, "SOL": { "qty_at_baseline": 5.0, "policy": "managed", "note": "released for bot tracking" }, "USDT": { "qty_at_baseline": null, "policy": "tradable_quote" }, "USDC": { "qty_at_baseline": null, "policy": "tradable_quote" } // alle anderen 441 Assets implizit `frozen` (default policy) }, "default_policy_for_unlisted": "frozen" } ``` ### 5.2 Drei Policies | Policy | Bot-Sicht | Auto-Sell | Auto-Buy | Im total_value | |---|---|---|---|---| | **`frozen`** | sichtbar | NEIN | NEIN (universe-filter exkludiert base) | optional anzeigen als „frozen value" | | **`managed`** | als state-Position importieren | JA (wenn Sell-Trigger) | JA | regulär | | **`tradable_quote`** | Cash-Pool | NEIN (ist quote) | NEIN (ist quote) | als cash | ### 5.3 Default-Verhalten (sicher per default) - `default_policy_for_unlisted: "frozen"` → wenn Operator NICHTS deklariert, sind ALLE pre-existing-Holdings frozen - `tradable_quote` muss explizit für USDT/USDC etc. gesetzt werden (oder vom Schema-Default abgeleitet) - `managed` ist immer **opt-in pro Asset** — niemals default ### 5.4 Architektur-Layer-Stack ``` Bot Startup ↓ LiveTrader.fetch_balance() → 446 raw holdings ↓ BaselineHoldingsReader.snapshot() ← liest baseline_holdings.json ↓ PolicyResolver(holdings, baseline) → {asset: policy} map (frozen|managed|tradable_quote|unknown) ↓ balance_provider.get_free_quote_balance() = sum(quote_assets where tradable_quote) - sum(reserve % anteilig) universe.filter(symbols) = symbols where base NOT in frozen-set state.positions auto-import ← managed-holdings als synthetic positions (entry_price = current_price at import) get_portfolio().total_value = state.cash + sum(state.positions value) + sum(frozen value) [optional Display] ↓ Bot-Cycle läuft normal - Auto-Sells nur auf state['positions'] (= managed + Bot-opened) - Auto-Buys nur auf nicht-frozen-bases - Frozen-Holdings sind „read-only-known" ``` ### 5.5 Reader/Writer-Pattern (G10-Analogie) | G10 RuntimeConfig | RECON BaselineHoldings | |---|---| | `runtime_config_writer.py` (atomic write + backup) | `baseline_holdings_writer.py` (analog) | | `runtime_config_reader.py` (pure SELECT) | `baseline_holdings_reader.py` (pure SELECT) | | `RuntimeConfigStatusWidget` (G10-6.1) | `BaselineHoldingsStatusWidget` | | `apply_profile_testnet` Command | `apply_baseline_holdings` Command | | `clear_runtime_config` Command | `clear_baseline_holdings` Command | | Postgres CHECK constraint values | CHECK constraint policies (`frozen`/`managed`/`tradable_quote`) | | 5-Layer Mainnet-Guard | analog für Mainnet-baseline-Apply | | GUI hard-confirm `applyToTestnetAction` | GUI hard-confirm `applyBaselineAction` (Wallet-Hash + Asset-Count tippen) | → **Wir bauen kein neues Mental-Model.** Wir spiegeln G10 exakt. --- ## 6. Datenmodell-Vorschlag ### 6.1 baseline_holdings.json Schema (final) ```jsonc { "captured_at": "2026-05-09T20:30:00Z", // ISO8601 UTC "captured_via": "operator_apply", // operator_apply | bootstrap | recon_drill "environment": "testnet", // testnet | mainnet "wallet_signature": { "exchange": "binance", "account_hash": "sha256:abc…123", // hash über sortierte (asset, qty) "total_assets": 446, "total_value_usdt": 102244.50 // Snapshot at baseline-time }, "default_policy_for_unlisted": "frozen", // frozen | tradable_quote "holdings": { "": { "qty_at_baseline": , // null für tradable_quote "policy": "frozen|managed|tradable_quote", "note": "", "managed_since": "", "synthetic_entry": // for managed: entry-price proxy } }, "_meta": { "command_id": "", "checksum": "", "phase": "RECON-2.1", "applied_at": "", "applied_via": "operator_apply | recon_drill" } } ``` ### 6.2 Allowed Policy Values (durable rule, CHECK-style) ```python BASELINE_POLICY_ALLOWED = {"frozen", "managed", "tradable_quote"} DEFAULT_POLICY_ALLOWED = {"frozen", "tradable_quote"} # never "managed" as default ``` → `managed` muss **explizit** pro Asset gesetzt sein. Niemals impliziter Default. ### 6.3 Wallet-Signature-Lock Pre Mainnet-Connect: Bot vergleicht aktuellen `wallet_signature.account_hash` mit dem in `baseline_holdings.json`. Wenn Mismatch → **STOP-Bot** mit klarer Operator-Meldung "Wallet hat sich geändert seit baseline; reconcile zuerst". Verhindert dass Bot mit veralteter Baseline auf veränderter Wallet läuft. --- ## 7. Phasen-Plan RECON-2.1 bis 2.5 | Phase | Inhalt | DB-Migration | Bot-Restart | Risk | |---|---|---|---|---| | **MAINNET-PREFLIGHT-RECON** (this document) | Audit + Q-Fragen | nein | nein | trivial | | **RECON-2.1** | Schema + BaselineHoldingsReader/Writer + tests (analog G10-4.1) | nein | nein | gering | | **RECON-2.2** | Bot-Side Awareness: balance_provider + position_sizer + universe-filter respektieren baseline | nein | **JA** (separate Sub-Phase) | mittel | | **RECON-2.3** | Filament-UI: Resource „Holdings", Action „Manage Holdings", Audit-Trail (analog G10-6) | nein (Filament reads JSON) | nein | gering | | **RECON-2.4** | **Testnet-Drill** mit echter 446-Assets-Wallet | nein | **JA** (drill-restart) | mittel — aber komplett-reversibel | | **RECON-2.5** | Mainnet-Cutover-Checklist (eigener Preflight, NICHT teil dieser Phase) | tbd | tbd | hoch | ### 7.1 RECON-2.1 — Schema + Reader/Writer **Inhalt:** - `trading/baseline_holdings_writer.py` (atomic write, backup-pattern) - `trading/baseline_holdings_reader.py` (pure-SELECT, COALESCE-friendly) - Tests `trading/tests/test_recon_2_1_baseline_writer.py` (analog T-SPLIT-1 schema-tests) **Out of scope:** - Bot-Code-Awareness (das ist 2.2) - GUI (2.3) - Live-Drill (2.4) **Tests (~12):** - writer.apply atomic (tmp + os.replace, backup before) - writer.clear with backup - reader.snapshot returns None when absent - reader.policy_for(asset) → frozen/managed/tradable_quote/default - wallet_signature mismatch detection - CHECK-like validation: invalid policy rejected at writer - file-shape canonicalization for checksum - testnet-only at this phase (CHECK environment='testnet') - legacy: no baseline-file → all unknown → safe behaviour ### 7.2 RECON-2.2 — Bot-Awareness **Inhalt:** - `balance_provider.ExchangeBalanceProvider`: optional `baseline_reader` injection, subtract frozen quote-amounts from `get_free_quote_balance` if any (für USDT-frozen z.B.) - `paper_trader.get_portfolio()`: optional `baseline_aware=True` flag → adds frozen_value as separate field - `universe.scan_all(...)`: filter excludes symbols where base in baseline.frozen-set - `paper_trader.execute_buy`: refuses BUY if base in baseline.frozen - Auto-import managed-holdings into state['positions'] at startup with synthetic entry/SL/TP **Tests (~16):** - balance subtraction für USDT-frozen - universe-filter mit frozen-set - execute_buy refuses frozen base - managed auto-import to state at startup - backward-compat: no baseline → unchanged behaviour - wallet-signature-mismatch → bot refuses to start (with clear error) **Bot-Restart erforderlich** für Aktivierung — eigener Sub-Step `RECON-2.2-RESTART` mit Backup-Pflicht (analog T-SPLIT-2-RESTART). ### 7.3 RECON-2.3 — Filament-GUI **Inhalt:** - New Resource `BaselineHoldingsResource` (read-only Tabelle mit 446 Holdings) - Filter: by policy - Header-Action „Manage Holdings" — admin-only, hard-confirm-modal mit Wallet-Hash + Asset-Count tippen - Service `ApplyBaselineService` (analog `ApplyProfileService`) - Audit-Events `baseline.requested` / `baseline.applied` / `baseline.cleared` **Tests (~14)** — analog G10-6.2/6.3. ### 7.4 RECON-2.4 — Testnet-Drill (KERN-PHASE) **Drill-Plan:** 1. **Pre-State Capture** - Snapshot aktueller 446 Holdings - Snapshot state['positions'] (5 entries) - Bot-PID, .env mtime, runtime_config-Status - DB-Backup 2. **Baseline-Erzeugung** - Operator triggert via GUI „Generate Baseline from Wallet" (one-shot dry-run-Service) - Output: `baseline_holdings.json` mit allen 446 Assets als `frozen` (default), USDT/USDC als `tradable_quote` - Operator wählt explizit 1-2 Assets als `managed` (z.B. SEI als bereits-getrackt) 3. **Apply via CommandBus** - `apply_baseline_holdings` Command erzeugt - Worker `--once` → schreibt `baseline_holdings.json` - Audit `baseline.applied` 4. **Bot-Restart RECON-2.4-RESTART** - SIGTERM + watchdog - Bot lädt baseline beim Startup - Initial-Wallet-Signature-Check passes - State auto-import: SEI-managed → state['positions'][SEI/USDT] mit synthetic entry 5. **Cycle-Verify (1-2 cycles)** - Decision-Logs zeigen: kein BUY auf BTC/ETH (frozen) - kein BUY auf irgendeinem der 436 implizit-frozen Assets - SEI-managed-position weiterhin tracked - Total-Value-Anzeige: cash + bot-positions + frozen-Wert (separat) - errors.log clean 6. **Operator-Action: Release** - Operator GUI „Release SOL to managed" - CommandBus → apply - Bot picks SOL up im nächsten Cycle als managed-Position - SOL/USDT BUY/SELL erlaubt 7. **Operator-Action: Re-Freeze** - Operator GUI „Freeze SOL again" - Bot stoppt SOL-Trading - State['positions'][SOL] bleibt aber in state (nicht auto-removed; Operator entscheidet) 8. **Cleanup** - Operator GUI „Clear Baseline" - `baseline_holdings.json` gelöscht (Backup) - Bot fällt zurück auf default-no-baseline-Verhalten **Drill-Acceptance-Criteria:** - ✅ Während gesamter Drill: 0 SELL-Errors auf pre-existing - ✅ Auto-Buys nur auf nicht-frozen-Bases - ✅ Total-Value-Display zeigt frozen separat - ✅ Wallet-Signature-Check fängt Mismatch - ✅ Reversible: nach Clear-Baseline kein Drift ### 7.5 RECON-2.5 — Mainnet-Cutover (eigener Preflight, NICHT teil dieser Phase) **Vorbedingungen:** - RECON-2.1 + 2.2 + 2.3 + 2.4 alle ☑ - Mainnet-API-Keys mit IP-Whitelist + No-Withdraw-Permissions - Universe-Whitelist (statt full-scan) konfiguriert - Sizing-Initial-Reduktion auf 1% Risk-pro-Trade (statt 2%) - Max-Open-Positions auf 1-2 - GUI-Banner-Update („Mainnet active"-Klasse statt hardcoded "blocked") - Mode-Display-Relabel `paper`→`MAINNET (live)` umgesetzt **Out of scope für RECON:** Mainnet-Cutover hat eigenen Preflight mit eigenen Q-Fragen. --- ## 8. Testnet-Drill-Plan (detailliert) ### 8.1 Drill-Vorbereitung | Step | Aktion | Verifikation | |---|---|---| | 1 | Pre-Backup pg_dump + state + .env | sha256 manifest | | 2 | Wallet-Snapshot (Asset-Hash) | account_hash gespeichert | | 3 | Bot-PID + Startzeit dokumentieren | health_pre.txt | ### 8.2 Drill-Phase A — Schema + Apply | Step | Aktion | Erwartetes Verhalten | |---|---|---| | 4 | Per CommandBus `apply_baseline_holdings` Command erzeugen | Command status pending | | 5 | Worker `--once` ausführen | exit 0, processed=True | | 6 | `baseline_holdings.json` existiert + sha256 verifizieren | file present | | 7 | Bot-PID unverändert (kein Restart in dieser Etappe) | confirmed | ### 8.3 Drill-Phase B — Restart + Awareness | Step | Aktion | Erwartetes Verhalten | |---|---|---| | 8 | Pre-restart-snapshot | health_b_pre.txt | | 9 | docker cp aktualisierter Bot-Files (RECON-2.2 code) | sha256-match | | 10 | SIGTERM + watchdog-restart | new PID | | 11 | Bot reads baseline at startup | log-line "baseline_holdings: 446 assets, 444 frozen, 2 managed" | | 12 | Wallet-Signature-Check passes | log-line "wallet_signature OK" | ### 8.4 Drill-Phase C — Cycle-Verify (1-2 cycles) | Step | Verifikation | Erfolg-Kriterium | |---|---|---| | 13 | Decision-Logs filter `action=buy` | KEIN BTC/ETH/etc. unter den frozen-Bases | | 14 | Decision-Logs filter `reject_reason=baseline_frozen` | rejects sichtbar für frozen-Assets | | 15 | Total-Value-Display | zeigt cash + bot + frozen separat | | 16 | errors.log seit Restart | clean (keine insufficient_funds) | | 17 | state['positions'] | enthält die 2 managed-Holdings | ### 8.5 Drill-Phase D — Release + Re-Freeze | Step | Aktion | Erwartung | |---|---|---| | 18 | GUI: Release SOL → CommandBus → Worker --once | baseline.json updated, audit | | 19 | Bot-Cycle danach: SOL ist tradable | decision_logs: SOL/USDT evaluating/buy | | 20 | GUI: Re-Freeze SOL | baseline.json updated | | 21 | state['positions'][SOL] bleibt | Operator-Entscheidung manueller close oder behalten | ### 8.6 Drill-Phase E — Clear-Baseline | Step | Aktion | Erwartung | |---|---|---| | 22 | GUI: „Clear Baseline" via CommandBus | baseline.json gelöscht, Backup | | 23 | Bot-Cycle danach | default-no-baseline-Verhalten zurück | | 24 | Bot-Restart NICHT nötig (analog G10-Clear) | Bot picks up via per-cycle-snapshot | ### 8.7 Drill-Stop-Regeln Sofort STOP + Bericht wenn: - Auto-Sell auf einem frozen-Asset (sollte unmöglich sein) - Bot-PID wechselt unerwartet (Crash) - Wallet-Signature-Mismatch nach Drill (sollte deterministisch passen) - DB-Migration/Mutation außerhalb apply_baseline (verboten) - Mainnet-Pfad sichtbar (verboten) - universe.filter zeigt frozen-Bases trotz Filter - errors.log: insufficient_funds Loop --- ## 9. Open Questions Q-1..Q-12 | ID | Frage | Default-Vorschlag | |---|---|---| | **Q-1** | Default policy für unlisted assets — `frozen` oder `tradable_quote`? | `frozen` (sicherster default) | | **Q-2** | Soll `tradable_quote` set hardcoded (USDT/USDC/BUSD/...) oder operator-konfiguriert? | hardcoded mit Override-Option | | **Q-3** | Soll Bot bei Wallet-Signature-Mismatch komplett refuse-to-start oder warning + continue? | **refuse-to-start** (sicherer) | | **Q-4** | Soll `managed`-Auto-Import bei Bot-Restart synthetic SL/TP setzen oder pending lassen? | pending lassen (Operator setzt manuell), sonst künstlich-ungenaue SL/TP | | **Q-5** | Soll baseline.environment per CHECK auf testnet beschränkt sein bis RECON-2.5? | ja (analog G10-Mainnet-Lock) | | **Q-6** | Soll Total-Value-Display frozen-value separat anzeigen oder verstecken? | separat anzeigen mit klarer Klassifikation | | **Q-7** | Soll universe-filter pre-existing-bases auch bei `managed` exkludieren? | nein — managed darf Bot traden | | **Q-8** | Wallet-Signature-Hash über alle 446 oder nur top-N nach Wert? | alle 446 (sicher) | | **Q-9** | Soll Drill-Plan optional vor RECON-2.2 ein „dry-run-baseline" liefern (read-only-Generator) ohne write? | ja — RECON-2.1 sollte einen Dry-Run-Modus haben | | **Q-10** | Soll `clear_baseline_holdings` ein full-clear oder per-asset-clear sein? | full-clear (analog G10-clear); per-asset-mutation via apply mit neuem JSON | | **Q-11** | Soll der Bot bei Connect die wallet_signature **immer** loggen (auch ohne baseline)? | ja — als forensische Baseline für späteren Recon | | **Q-12** | RECON-2.5 Mainnet-Cutover als eigener Preflight oder als Sub-Phase von RECON? | **eigener Preflight** (analog G10/T-SPLIT/CAP-1 Pattern) | --- ## 10. Stop-Regeln (durable, alle RECON-Phasen) Sofort STOP + Bericht wenn: - Bot verkauft Asset das in `baseline_holdings.json` als `frozen` markiert ist - Bot kauft Asset dessen Base in `baseline.frozen-set` ist - universe-filter zeigt frozen-base ohne `baseline_frozen` reject_reason - Wallet-Signature-Mismatch beim Bot-Connect (jede Phase) - baseline_holdings.json mutiert ohne CommandBus (außerhalb-Apply) - live_portfolio.json wird durch Auto-Import zu groß / falsch - Mainnet-Pfad sichtbar (durably blocked, jede Phase) - runtime_config.json mutiert (orthogonal zu RECON; sollte unangetastet bleiben) - DB-Migration ohne explizite RECON-2.1-/2.3-Phase --- ## 11. Future-Phase-Anchors | Phase | Was RECON dafür liefert | |---|---| | **CAP-1 Profit-Reinvestment** | `tradable_quote`-Set definiert was als „investable_capital" zählt | | **T-SPLIT-5 T2 Operator-View** | T2-eigene baseline-policies möglich (z.B. Solana-Holdings frozen pro T2) | | **T-SPLIT-6 T3 Copy Trading** | T3-source-Wallets könnten als `managed` mit speziellem T3-Tag importiert werden | | **Naming-Cleanup paper→TESTNET/MAINNET** | baseline_holdings.environment wird zentraler Anker | | **Mainnet-Cutover (RECON-2.5)** | basiert direkt auf RECON-2.4 Drill-Erfahrung | --- ## 12. Boundaries des PREFLIGHT-Audits selbst | Bedingung | Status | |---|---| | Bot **PID 15373 alive** (post B-REPORTER-FIX-2-RESTART) | ✅ | | `runtime_config.json` **absent** | ✅ | | `.env` mtime **1777991334 unverändert** | ✅ | | Kein Code geändert | ✅ | | Keine Migration | ✅ | | Keine Datenmutation | ✅ | | Kein Bot-Restart | ✅ | | Kein Mainnet | ✅ | | Kein Worker-Daemon | ✅ | | Kein Push (außer User-getrieben) | ✅ | | Diagnostic Snapshot-Script aus Container entfernt | ✅ | | Konzept basiert auf G10-Pattern (durable proven) | ✅ | --- ## 13. Empfohlener nächster aktiver Schritt Per User-Direktive *"nicht direkt RECON-2.1 bauen, erst den Preflight sauber abschließen"*: **Aktuell:** Preflight-Lieferbericht (dieses Dokument) zur User-Review. **Nach User-Approve + Q-1..Q-12 Entscheidungen:** GO RECON-2.1 (Schema + Reader/Writer + Tests, analog G10-4.1 / T-SPLIT-1). **Wichtig:** RECON-2.1 ist **rein additiv** (neue Files, keine Modul-Awareness im Bot, keine Migration, kein Bot-Restart). Risk gering. RECON-2.2 ist die erste Phase mit Bot-Restart. --- ## 14. Lieferbericht-Zusammenfassung | Aspekt | Wert | |---|---| | Audit-Phase | MAINNET-PREFLIGHT-RECON, read-only | | Bot-Stand | PID 15373, T-SPLIT-2 + B-REPORTER-FIX-2 active | | Snapshot-Daten | 446 assets / 5 state-positions / 102k+ USDT real wallet value | | Architektur-Vorschlag | Frozen-Baseline Pattern (analog G10 RuntimeConfig) | | Datenmodell | `baseline_holdings.json` mit 3 Policies: frozen/managed/tradable_quote | | Phasen | RECON-2.1 (Schema) → 2.2 (Bot-Awareness, Restart) → 2.3 (GUI) → 2.4 (Testnet-Drill) → 2.5 (eigener Mainnet-Cutover-Preflight) | | Q-Fragen offen | 12 (Q-1..Q-12) | | Tests-Surface geschätzt | 12 + 16 + 14 + 8 = ~50 | | Bot-Restarts geplant | 2 (RECON-2.2-RESTART + RECON-2.4-DRILL-RESTART) | | Mainnet-Risiko | bleibt durable blockiert bis explizit RECON-2.5 startet | **STOP.** Warte auf User-Antwort zu Q-1..Q-12 + GO für RECON-2.1. --- *Generated 2026-05-09 — read-only Audit für MAINNET-PREFLIGHT-RECON Phase. Konsumierbar als Markdown (committed) + PDF (publiziert auf /srv/shares). Konzept basiert auf G10 RuntimeConfig + T-SPLIT-1 Schema-Pattern.*