Files
Multi_Swarm_Coevolutive/docs/decisions/2026-05-11-phase1-5-nemotron-run.md
T
Adriano 1a171acfb2 docs: decision memo Phase 1.5 nemotron run (NO-GO)
Run phase1.5-nemotron-001 completato in 2h26min, costo $0.1244.
Max fitness 0.0215 stagnante (15x peggio del baseline qwen 0.3347),
DSR=0 universale, Sharpe -1.08/-1.15. Loop non converge.

Adversarial Phase 1.5 attivo: 98 finding totali, 35 fees_eat_alpha
HIGH + 15 flat_too_long + 8 time_in_market — i 3 nuovi check killano
correttamente, ma popolazione non ha materiale sano da cui evolvere.

Tre direzioni candidate per Phase 2: A) rollback qwen-2.5-72b,
B) prompt re-tuning nemotron, C) promuovere deepseek-v4-flash.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 14:46:35 +02:00

118 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1.5 — Run nemotron tier C — Decision Memo
**Data**: 11 maggio 2026
**Run di riferimento**: `phase1.5-nemotron-001` (id `434c417e2b6f42bb8cf32514e5d0db1d`)
**Tier LLM**: C → `nvidia/nemotron-3-super-120b-a12b:free`
**Durata wallclock**: 2 h 26 min (08:15 → 10:11 UTC, gen 0 → gen 9)
**Spesa totale**: $0.1244 (price-table tier C; il modello effettivo è `:free` su OpenRouter, ma il cost tracker applica la pricing nominale del tier)
**Status**: ✅ Completato, ma esito strategico **NO-GO** sulla configurazione corrente
---
## 1. Premessa
Il run `phase1.5-nemotron-001` è la prima esecuzione end-to-end del loop GA con:
- l'Adversarial layer aggiornato in Phase 1.5 (commits `56a631f` + `d3662f6`), con tre nuovi check HIGH (`flat_too_long`, `fees_eat_alpha`, `time_in_market_too_high`) più i due esistenti rinforzati;
- il tier C ribindato a `nvidia/nemotron-3-super-120b-a12b:free`, modello scelto in benchmark contro sette alternative per stabilità JSON e costo nullo;
- il fix `EmptyCompletionError` su `llm/client.py` (commit `9d0deb3`) introdotto durante la stessa sessione per gestire le risposte vuote che alcuni provider `:free` ritornano sporadicamente.
L'obiettivo dichiarato del run era verificare se il nuovo budget di vincoli adversarial — più stretto del v5 — fosse compatibile con la capacità generativa di nemotron, e se la popolazione riuscisse a esplorare una zona di fitness positiva non degenere.
---
## 2. Hard gate Phase 1 — ripercorrenza
I 5 hard gate originali (definiti nello spec strategico di Phase 1) sono stati rivalutati su questo run come sanity check, non come passaggio formale di gate.
| # | Gate | Soglia | Misura | Esito |
|---|------|--------|--------|-------|
| 1 | Loop converge | mediana cresce ≥3 gen consecutive | Gen 0→8: median oscilla tra 0.0 e 0.0073 senza crescita strutturale | ❌ FAIL |
| 2 | Parse success | ≥80% proposte LLM parse-OK | 81/89 = **91.0%** | ✅ PASS |
| 3 | Top-5 ratio | top-5 fitness ≥10× mediana | top-5 = 0.01620.0215; mediana ≈ 0 → ratio indefinito | ⚠️ N/A |
| 4 | Entropy | ≥0.5 a fine run | 0.845 alla gen 9 | ✅ PASS |
| 5 | Budget | costo ≤ cap | $0.1244 vs cap $700 (0.02%) | ✅ PASS |
Il gate critico è il numero 1. La popolazione non converge: il `max_fitness` resta inchiodato a `0.0215` dalla generazione 0 fino alla 9, segnale che l'elite preservation cattura un singolo genoma poco peggiore degli altri ma altrettanto inadatto, mentre il resto della popolazione non riesce a superarlo. La mediana è zero in 9 generazioni su 10 (singolo picco a 0.0073 in gen 8).
---
## 3. Lettura dei top genomi
I cinque genomi a fitness più alta hanno tutti caratteristiche economicamente disastrose:
| Genome ID | Fitness | DSR | Sharpe | Total return | n_trades |
|-----------|---------|-----|--------|--------------|----------|
| `0e1f9d7af25cfd6a` | 0.0215 | 0.000 | 1.083 | 115.9% | 385 |
| `85a8116ab2cd2735` | 0.0215 | 0.000 | 1.083 | 115.9% | 385 |
| `92aae563277b6f21` | 0.0193 | 0.000 | 1.129 | 131.0% | 597 |
| `01d0ca99bbdd7320` | 0.0180 | 0.000 | 1.112 | 131.7% | 602 |
| `194b096f7edab53c` | 0.0162 | 0.000 | 1.154 | 150.7% | 369 |
Il fatto che **DSR sia zero per tutti i top-5** indica che nessuna strategia passa il deflation test di Bailey & López 2014: il loop non sta generando proposte con edge statistico anche solo apparente. Il valore di fitness positivo che li seleziona deriva interamente dal termine `tanh(sharpe) × penalty(dd)` della fitness v1, che resta debolmente non nullo anche per Sharpe negativi grazie alla penalty di drawdown e a saturazioni numeriche. I primi due genomi hanno fitness identico a 0.0215 e total return identico — verosimilmente lo stesso elite riproposto a generazioni adiacenti.
---
## 4. Adversarial findings — il sistema fa il suo lavoro
Il layer Adversarial Phase 1.5 ha emesso 98 finding sul run:
| Severità | Check | Conteggio |
|----------|-------|-----------|
| HIGH | `fees_eat_alpha` (nuovo P1.5) | 35 |
| MEDIUM | `overtrading` | 19 |
| HIGH | `no_trades` | 16 |
| HIGH | `flat_too_long` (nuovo P1.5) | 15 |
| HIGH | `time_in_market_too_high` (nuovo P1.5) | 8 |
| HIGH | `undertrading` | 4 |
| HIGH | `degenerate` | 1 |
Il dato saliente è che i tre check introdotti in Phase 1.5 — `fees_eat_alpha`, `flat_too_long`, `time_in_market_too_high` — sono effettivamente attivi e killano strategie. In particolare `fees_eat_alpha` è la categoria più popolata: 35 occorrenze HIGH. Esempi tipici dai detail dei finding:
- `Fees $17073.82 = 2032.6% of gross $840.00`;
- `Fees $70646.03 = 12671.9% of gross $557.50`;
- `Signal flat for 98.8% of bars (>95% threshold)`.
Il messaggio è netto: il pool di strategie generato da nemotron, ai prompt e ai gradi di libertà attuali, oscilla tra due estremi degeneri — strategie inattive (flat 98%+) e strategie iperattive (overtrading + fee che divorano l'alpha lordo). Phase 1.5 cattura entrambi gli estremi, ma il loop GA non ha materiale di partenza sano da cui evolvere.
---
## 5. Decisione
**Esito**: NO-GO sulla combinazione `tier C = nemotron` + `Phase 1.5 adversarial` come configurazione di Phase 2.
Le ragioni a supporto della decisione sono tre.
Primo, la convergenza è assente per nove generazioni consecutive, non un plateau di selezione raggiunto dopo una fase di salita. Non si tratta cioè di un loop che ha già trovato il suo ottimo e lo conserva, ma di un loop che non ne ha trovato uno.
Secondo, la distanza dal baseline Phase 1 v5 è di un ordine di grandezza: max fitness `0.0215` qui contro `0.3347` nel run di gate Phase 1, mediana che oscilla sullo zero contro una mediana attorno a `0.005``0.09`. Nemotron, in questa configurazione, sta producendo proposte qualitativamente più povere di qwen-2.5-72b nello stesso schema operativo.
Terzo, i finding adversarial non puntano a un bug del sistema ma a una mancanza di edge nelle proposte. Il loop sta sanzionando correttamente — il problema è a monte, nella generazione.
---
## 6. Tre direzioni per Phase 2
Tre opzioni si configurano per il passo successivo. Vanno valutate prima di una nuova esecuzione, non in parallelo a essa.
**Direzione A — Riportare tier C a `qwen/qwen-2.5-72b-instruct`** (configurazione di gate Phase 1). Il run di riferimento `phase1-real-005` è già un baseline noto: max fitness `0.3347`, top genome problematico (flat 99.8%) ma generato sotto Phase 1 adversarial. Rilanciare lo stesso pool con Phase 1.5 adversarial isolerebbe l'effetto del solo hardening sul medesimo motore generativo, senza confondere variabili. Questo è il percorso più informativo nel breve.
**Direzione B — Mantenere nemotron ma rilassare i prompt di Hypothesis**. L'ipotesi alternativa è che il prompting attuale, calibrato su qwen, sia troppo terso o troppo vincolato per la modalità di ragionamento di nemotron. Iterare due o tre versioni del prompt — più esempi few-shot, vincoli espliciti su `n_trades` minimo e `time_in_market` target — può cambiare radicalmente la qualità dell'output senza cambiare il modello.
**Direzione C — Sostituire il tier C con un modello a pagamento di fascia comparabile**. Tra i benchmark precedenti, `deepseek/deepseek-v4-flash` è già usato come tier A/B nel file `.env`; promuoverlo a tier C significa accettare una spesa marginale (stima $13 per run di 10 gen × 20 pop) in cambio di una qualità generativa nota.
La preferenza dell'operatore per modelli cost-conscious orienta verso A o B. La direzione C resta utile come benchmark di controllo se A e B fallissero a loro volta.
---
## 7. Operazioni di pulizia eseguite contestualmente
- Il run zombie `phase1-real-008` (id `6ebcff9f7f6544c18ced50313cf72ca9`, marcato `running` da 07:11 UTC senza processo associato) è stato chiuso a `status='failed'` direttamente in `runs.db`, per evitare contaminazione delle query di dashboard.
- Il commit `9d0deb3` (`fix(llm): handle empty completions + missing usage`) è già su `main`. Il `client.py` ora tratta `resp.choices == []` e `resp.usage is None` come errori retryable invece che assertion failure: precondizione necessaria per qualsiasi run successivo su provider `:free`.
---
## 8. Note per chi legge
Questo memo è un documento di decisione, non un rapporto tecnico completo. Il rapporto tecnico esteso del run può essere ricostruito da `runs.db` interrogando le tabelle `runs`, `generations`, `evaluations`, `adversarial_findings`, `cost_records` con `run_id='434c417e2b6f42bb8cf32514e5d0db1d'`. Il design Phase 1.5 e le motivazioni delle soglie adversarial restano definiti nel commit `56a631f` e nei suoi file di test.