Wires the GUI's first write path through the manual_actions queue:
* runtime/manual_actions_consumer.py — drains the queue and
dispatches arm_kill / disarm_kill via KillSwitch (preserving the
audit chain). Unsupported kinds (force_close, approve/reject_proposal)
are marked result="not_supported" so they don't sit forever.
* runtime/orchestrator.py — adds a `manual_actions` job at */1 cron
to the canonical scheduler manifest.
* gui/data_layer.py — write helpers enqueue_arm_kill /
enqueue_disarm_kill (the only write path the GUI uses) plus
load_pending_manual_actions for the pending strip.
* gui/pages/1_📊_Status.py — kill-switch arm/disarm panel with typed
confirmation ("yes I am sure") + reason field; pending-actions table
rendered when the queue is non-empty.
End-to-end smoke against the testnet state.sqlite:
GUI enqueue → consumer dispatch → KillSwitch transition → audit
chain hash linkage holds, "source":"manual_gui" recorded.
7 new unit tests for the consumer (arm, disarm, drain, unsupported,
default-reason, KillSwitchError handling, empty queue); 360/360 pass.
ruff clean; mypy strict src clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each bot now manages its own notification + portfolio aggregation:
* TelegramClient calls the public Bot API directly via httpx, reading
CERBERO_BITE_TELEGRAM_BOT_TOKEN / CERBERO_BITE_TELEGRAM_CHAT_ID from
env. No credentials → silent disabled mode.
* PortfolioClient composes DeribitClient + HyperliquidClient + the new
MacroClient.get_asset_price/eur_usd_rate to expose equity (EUR) and
per-asset exposure as the bot's own slice (no cross-bot view).
* mcp-telegram and mcp-portfolio removed from MCP_SERVICES / McpEndpoints
and the cerbero-bite ping CLI; health_check no longer probes portfolio.
Docs (02/04/06/07) and docker-compose updated to reflect the new
architecture.
353/353 tests pass; ruff clean; mypy src clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Integra due nuovi filtri dal pacchetto quant indicators rilasciato in
Cerbero_mcp (commit a13e3fe). 335 test pass, mypy strict pulito,
ruff clean.
Filtri (§2.8 — nuovo):
- dealer-gamma: blocca entry quando total_net_dealer_gamma <
dealer_gamma_min (default 0). Long-gamma regime favorisce credit
spread (vol-suppressing dealer flow); short-gamma flow lo amplifica
ed è da evitare.
- liquidation-heatmap: blocca entry quando il segnale euristico di
cerbero-sentiment riporta long o short squeeze risk = "high"
(cluster di liquidations imminenti entro 24h).
Entrambi sono best-effort: se il tool MCP fallisce o restituisce
dati anomali l'entry_cycle popola EntryContext con None e
validate_entry salta il gate per non bloccare entry su problemi
infrastrutturali.
Wrapper:
- DeribitClient.dealer_gamma_profile_eth → DealerGammaSnapshot.
- SentimentClient.liquidation_heatmap → LiquidationHeatmap con
property has_high_squeeze_risk.
Schema:
- EntryConfig.dealer_gamma_min, dealer_gamma_filter_enabled,
liquidation_filter_enabled.
- EntryContext.dealer_net_gamma, liquidation_squeeze_risk_high
opzionali.
- strategy.yaml: nuovi campi documentati con commento + hash
ricalcolato (4c2be4c5...).
Documentazione:
- docs/04-mcp-integration.md riscritto al modello attuale (HTTP
REST, no mcp SDK, no memory/brain-bridge, place_combo_order
documentato, environment_info al boot).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sei interventi MEDIA priorità sul sistema. 323 test pass, mypy strict
pulito, ruff clean.
1. Docker HEALTHCHECK + cerbero-bite healthcheck:
- nuovo subcommand che esce 0 se kill_switch=0 e last_health_check
entro --max-staleness-s (default 600s);
- HEALTHCHECK direttiva nel Dockerfile (60s interval, 5s timeout,
start_period 120s, retries 3);
- healthcheck definition nel docker-compose.yml.
2. Audit hash chain anti-truncation:
- migration 0002: nuova colonna system_state.last_audit_hash;
- AuditLog accetta callback on_append, dependencies.py la wire al
repository.set_last_audit_hash;
- Orchestrator.boot verifica che il tail file matcha l'anchor
persistito; mismatch → kill switch CRITICAL.
3. return_4h bootstrap da deribit get_historical:
- quando dvol_history è vuoto _fetch_return_4h cade su
deribit.historical_close (1h candle 4h fa);
- alert LOW se anche il fallback fallisce.
4. execution.environment + execution.eur_to_usd in strategy.yaml:
- ExecutionConfig promosso a typed schema con i due campi
consumati al boot;
- CLI start preferisce i valori da config; CLI flag overridano
solo quando differenti dai default.
5. Cycle correlation ID:
- structlog.contextvars.bind_contextvars in run_entry/run_monitor/
run_health propaga cycle_id e cycle nei log strutturati.
6. SIGTERM/SIGINT clean shutdown:
- run_forever installa loop.add_signal_handler per SIGTERM e
SIGINT; il segnale set()ta un asyncio.Event che termina il
blocco principale, scheduler.shutdown e ctx.aclose finalizzano.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sei interventi mirati sui rischi operativi rilevati nell'audit
post-Fase 4. 317 test pass, mypy strict pulito, ruff clean.
1. status CLI: legge SQLite reale e mostra kill_switch, posizioni
aperte, environment, config_version, last_health_check, started_at.
Sostituisce il placeholder "phase 0 skeleton".
2. Lock file single-instance: runtime/lockfile.py acquisisce
data/.lockfile via fcntl.flock al boot di run_forever; un secondo
container fallisce subito con LockError.
3. Backup orario nello scheduler: nuovo job APScheduler 0 * * * *
chiama scripts.backup.backup_database + prune_backups.
4. config_hash enforce su start: il CLI start verifica l'integrità
del file (enforce_hash=True). Mismatch → exit 1 prima di toccare
stato. dry-run resta enforce_hash=False per debug.
5. Connection pooling MCP: RuntimeContext espone un httpx.AsyncClient
long-lived condiviso da tutti i wrapper (limits 20/10
connections/keepalive). aclose() chiamato in run_forever finale.
6. Bias direzionale reale: deribit.historical_close +
deribit.adx_14 popolano TrendContext con spot a 30 giorni e
ADX(14) effettivi. Sblocca bull_put e bear_call. Quando i dati
storici mancano l'engine emette alert MEDIUM e cade su no_entry
in modo deterministico.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>