NiceGUI è la dashboard ufficiale (port 8080, dark/neon palette, 3 pagine:
/, /convergence, /genomes). La porta è ora parametrica via env
SWARM_DASHBOARD_PORT, letta in ui.run() — Docker la usa anche per
healthcheck e label Traefik.
docker-compose.yml: entrypoint del servizio dashboard cambiato da
streamlit a python -m multi_swarm.dashboard.nicegui_app. Default porta
8080 ovunque (.env, .env.example, compose, healthcheck).
Rimossi i file legacy della vecchia GUI Streamlit:
- src/multi_swarm/dashboard/streamlit_app.py
- src/multi_swarm/dashboard/aquarium.py (helper canvas HTML5)
- src/multi_swarm/dashboard/pages/{01_overview,02_ga_convergence,
03_genomes,04_aquarium}.py
- tests/integration/test_streamlit_smoke.py
pyproject.toml: rimossa la dep streamlit; uv.lock rigenerato (10 deps
transitive eliminate: pydeck, watchdog, jsonschema, pillow, ecc.).
README aggiornato (architettura, comando dashboard, sezione Dashboard
ora descrive NiceGUI con riferimento al deploy Docker via Traefik).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Due fondamenta scientifiche per filtrare overfit e lucky-shot:
1) undertrading_threshold parametrico (era hardcoded 10):
- AdversarialAgent.__init__(undertrading_threshold=10)
- CLI flag --undertrading-threshold
- Aggiunto a hard_kill_findings v2 default
{"no_trades", "degenerate", "undertrading"}: ora un genome con 1 trade
fortunato (es. genome 80be6bcc-1trade-fit-0.21 di fitness-v2-combo) viene
killato anche sotto fitness v2 soft-kill.
- Test parametric: undertrading_threshold=25 → 15 trade triggerano HIGH.
2) Walk-Forward Validation (WFA):
- RunConfig.wfa_train_split (None=off, 0<x<1=on) + wfa_top_k=5
- run_phase1: split ohlcv in train/test; GA usa solo train; a fine GA
i top_k genomi (by fitness in-sample, fitness>0) vengono rivalutati
sul test_ohlcv via falsification+adversarial+compute_fitness.
- Schema migration: evaluations + fitness_oos, sharpe_oos, return_oos,
max_dd_oos, n_trades_oos (ALTER TABLE con try/except per DB pre-2.6).
- Repository.update_evaluation_oos helper per popolare colonne OOS.
- CLI flags --wfa-train-split, --wfa-top-k.
- Test integration: train_split=0.7 → fitness_oos popolato per top_k.
Motivazione: la fase 2.5 ha generato 17 run con fitness fino a 0.36 + DSR
positivo, ma OOS test su 7 anni mostra che flat-ablation top crolla -37%
mentre fitness-v2 top regge (+143%). WFA in-run permette ora di vedere
direttamente il degradation train→test senza eseguire backtest separati,
rendendo possibile filtrare overfit early durante l'ottimizzazione.
Tests (+2 → 193 totale):
- test_undertrading_threshold_parametric
- test_e2e_wfa_populates_fitness_oos
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sostituisce la grammatica S-expression con uno schema JSON stretto. La
grammatica S-expression falliva il parsing nel 64% delle generazioni del
modello Qwen3-235B sul run reale; JSON e' nativo per gli LLM moderni e
si parsa con json.loads.
Cambiamenti principali:
- grammar.py: costanti rinominate LOGICAL_OPS / COMPARATOR_OPS /
CROSSOVER_OPS / ACTION_VALUES / KIND_VALUES.
- parser.py: nuovo AST a dataclass tipizzato (OpNode, IndicatorNode,
FeatureNode, LiteralNode, Rule, Strategy); parse_strategy ora consuma
JSON tramite json.loads.
- validator.py: walk dispatchato per tipo (isinstance) invece di
pattern-matching su 'kind'; arity check su operatori e indicator.
- compiler.py: traversal del nuovo AST tipizzato, dispatch per
isinstance; logica indicator/feature/literal invariata.
- hypothesis.py: prompt SYSTEM riscritto con esempi JSON e vincoli
espliciti su no-nesting; estrazione via fence ```json``` + fallback
brace-balanced.
- __init__.py: re-export pubblico delle entita' del protocollo.
- Tutti i test (parser, validator, compiler, hypothesis_agent,
falsification, adversarial, e2e, smoke_run) migrati a JSON.
- Rimossa dipendenza sexpdata da pyproject.toml + uv.lock.
Test: 135 passed (era 122; aggiunti casi parser/validator).
ruff + mypy strict clean. Smoke run end-to-end OK.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rimuove sidebar acquario (slider max-pesci, toggle label): la dimensione
popolazione è già definita dal GA, le label sono ridondanti col pannello
di ispezione. Mostra tutti i pesci della generazione selezionata.
Aggiunge `build_lineage_index` (mappa ogni genome_id della run ai suoi
attributi) e `trace_ancestors` (BFS sui parent_ids fino a max_levels,
guardia su cicli). `build_fish_dataset` accetta ora il lineage_index e
allega il campo `ancestors` ad ogni pesce; conserva la firma legacy per
compat con i fixture di test esistenti.
`build_aquarium_html` perde `show_labels`. Embedda click handler con
hit-test in canvas pixel space (account per CSS scaling) + pannello
info top-right con stile, fitness/DSR/Sharpe/maxDD/trades, prompt e
albero discendenza colorato per cognitive_style.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Nuova pagina Streamlit "Aquarium" che renderizza ogni genoma come pesce
animato su canvas HTML5: dimensione proporzionale alla fitness, colore
per cognitive_style, halo per i top-3. Helper puro-Python testabile per
costruire dataset e HTML self-contained (no CDN).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aggiunge scheletro multipage Streamlit per Phase 1:
- modulo data.py con helper (list_runs_df, get_run_overview,
generations_df, evaluations_df, genomes_df) sopra Repository.
- streamlit_app.py entry point con DB_PATH da env.
- pages/01_overview.py per elenco run + metriche + config JSON.
- smoke test import di multi_swarm.dashboard.data.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Loop GA completo: build_initial_population -> hypothesis.propose ->
falsification + adversarial -> compute_fitness -> persistenza ->
next_generation. Stato run/gen/genomes/evals/cost/findings su SQLite,
elite skip-eval, run marcato failed su eccezione.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>