Vai al contenuto
cd /blog

Miglioramento ricorsivo del supporto ai linguaggi: affinare l'intelligenza del codice su ~280 linguaggi

[Architettura] [Linguaggi] [Agenti]

> Supportiamo l'intelligenza del codice per ~280 linguaggi. Nessun essere umano può controllarli a mano uno per uno. Così abbiamo costruito un loop di miglioramento ricorsivo del supporto ai linguaggi — campionamento, LLM come giudice, correggi una cosa, rivalida — e lo facciamo girare con una flotta di agenti isolati finché l'estrazione non è davvero corretta, non solo verde.

I numeri in questo articolo riflettono il sistema al momento della pubblicazione (maggio 2026). Consulta la nostra pagina del team per le cifre attuali.

Maguyva estrae simboli, riferimenti e un grafo delle dipendenze dal codice sorgente in circa 280 linguaggi. Ogni linguaggio è un handler tree-sitter su misura — query, euristiche, casi limite — e ogni handler può essere sottilmente sbagliato a modo suo. Una chiamata a metodo emessa come una lettura. Una funzione attribuita allo scope contenitore sbagliato. Una relazione che semplicemente non esiste.

Questo non lo puoi controllare a mano. Nessun team può leggere l’output di estrazione su 280 grammatiche e individuare gli edge sbagliati. Quindi la domanda interessante non è “la nostra estrazione è corretta” — è “come scopri che è sbagliata, a questa ampiezza, senza un essere umano in ogni loop.” La nostra risposta è il miglioramento ricorsivo del supporto ai linguaggi: un loop di qualità guidato da agenti specializzati nei linguaggi, un LLM che agisce da giudice, e una regola che continuiamo a reimparare: verde non è lo stesso di corretto.

Verde non è corretto

Ogni linguaggio ha una suite di fixture, e un gate di rilascio lo valuta su cinque dimensioni — accuratezza, integrità strutturale, completezza, qualità e performance. Un linguaggio diventa VERDE solo quando, sulle sue fixture, precisione ≥ 0,95, recall ≥ 0,99, e F1 ≥ 0,97, con almeno 20 edge attesi per confidenza statistica. Sotto quella soglia è GIALLO o ROSSO, e non viene rilasciato.

Quel gate è necessario ma non sufficiente. Le fixture validano contro fixture che abbiamo scritto noi. Codificano i casi a cui abbiamo già pensato. Un handler può essere impeccabile sulle sue fixture e comunque devastare un pattern che compare solo nel codice reale — un idioma da macro, un metodo con vincoli sui tipi generici, una feature del linguaggio per cui nessuno ha scritto una fixture. VERDE significa che le fixture passano. Non significa che un repository reale venga estratto in modo pulito. Quindi il loop deve lasciarsi alle spalle le fixture ed esaminare il codice reale.

Il loop interno: campiona, giudica, correggi, dimostra

Il loop centrale gira un linguaggio alla volta:

        ┌──────────────────────────────────────────────────────────┐
        │                                                          │
        ▼                                                          │
  1. corpus run ── clone real-world repos, extract relationships   │
        │                                                          │
        ▼                                                          │
  2. spot-check 100 edges (seed 42, then seed 123 to cross-check)  │
        │                                                          │
        ▼                                                          │
  3. LLM judge classifies every sampled edge:                      │
        CORRECT · FALSE_POSITIVE · TYPE_ERROR ·                    │
        SCOPE_ERROR · METADATA_ERROR                               │
        │                                                          │
        ▼                                                          │
  4. fix ONE thing — handler .py, .scm query, or config           │
        │                                                          │
        ▼                                                          │
  5. re-validate — F1 + re-classify + manifest diff (no regressions)│
        │                                                          │
   better? ──no──► revert, try a different fix ────────────────────┤
        │ yes                                                       │
        ▼                                                           │
  6. promote the fix into fixtures (a permanent regression guard) ──┘

Alcune cose fanno funzionare tutto questo invece di farlo arrancare a vuoto.

Il giudice è l’agente, non una chiamata API. Quando diciamo “LLM come giudice”, intendiamo che l’agente specializzato nel linguaggio confronta ogni edge campionato con il codice sorgente reale e lo classifica con una griglia di valutazione fissa a cinque categorie: questo edge è corretto, un falso positivo, la relazione giusta con il tipo sbagliato, attaccato allo scope sbagliato, o porta metadati sbagliati? Quella griglia di valutazione è fondamentale — “23% di tasso di errore” non significa nulla finché non sai se sono difetti reali o il giudice che conta male.

Correggi una cosa, poi dimostralo. Ogni iterazione modifica esattamente un asset modificabile, poi riesegue i test con un harness fisso e mantiene la modifica solo se F1 migliora e la riclassificazione sembra migliore. Se non è così, va in rollback. Nessun lotto di modifiche speculative, nessun “dovrebbe essere meglio”. Una modifica si guadagna il suo posto o sparisce. E quando una correzione regge, viene promossa nella suite di fixture — così il bug che ha corretto non può mai tornare silenziosamente. Quel passaggio di promozione è ciò che rende il loop ricorsivo invece di semplicemente ripetitivo: ogni passata rafforza l’oracolo contro cui la passata successiva valida.

La lezione che continuiamo a reimparare: le metriche sovrastimano

Ecco la trappola, e ci siamo caduti dritti. Le metriche secondarie del corpus — con che frequenza un target estratto non ha un simbolo risolvibile, quanti simboli sembrano “orfani”, e così via — sovrastimano enormemente i problemi. Sono per lo più artefatti del paradigma, non bug.

L’esempio più pulito: llvm una volta mostrava un tasso del 73% di “sorgente senza simbolo” e fu bollato come catastrofico. Abbiamo scavato. L’accuratezza reale era del 98,5%. I “simboli mancanti” erano quasi tutti riferimenti esterni legittimi — chiamate nella libreria standard, in framework, in codice che vive fuori dal repository. La metrica stava misurando una proprietà del linguaggio, non un difetto dell’handler. Linguaggi come Zig, COBOL e Odin mostrano tassi di “orfani” del 65-70% e sono completamente corretti; COBOL aveva zero errori reali.

Se avessimo lasciato che quei numeri guidassero il lavoro, avremmo passato settimane a “correggere” handler già corretti e a ignorare i linguaggi con bug reali e silenziosi. La conclusione è netta: le metriche aggregate sono al massimo un rozzo segnale di triage. Il vero segnale di qualità è il controllo a campione con classificazione degli edge — guardare gli edge reali in repository reali e giudicarli uno per uno. Dati sopra l’intuizione, ma solo una volta che sai quali dati dicono la verità.

Il loop esterno: una flotta, non una maratona

Procedere un linguaggio alla volta richiederebbe un’eternità per coprirne 280, quindi il loop interno è avvolto in uno esterno che ne fa girare molti in parallelo.

   pick a wave of near-GREEN / high-error languages
        │
        ▼
   fan out 10–15 agents, each ISOLATED in its own git worktree,
   each grinding ONE language, committing to its own branch
        │
        ▼
   orchestrator integrates serially: file-scoped apply, then
   `manifest diff` — any cross-language regression blocks the batch
        │
        ▼
   gated push (reviewed and confirmed) ──► rotate to the next wave

Ogni agente lavora in un worktree usa-e-getta così da non pestarsi i piedi a vicenda. L’orchestratore integra le loro correzioni una alla volta, ciascuna dietro un controllo di regressione a manifest completo: una modifica che aiuta il suo linguaggio ma silenziosamente ne rompe altri tre non viene integrata. L’integrazione è vincolata e confermata prima che qualcosa venga pushato — il gate di regressione decide cosa è sicuro, un essere umano decide ancora cosa viene rilasciato. Poi il pool ruota verso il prossimo gruppo di linguaggi e tutto il processo si ripete.

Cosa resta imperfetto

Il giudice può sbagliare, e l’errore ha una direzione: un agente che gira con troppo poco contesto sovrastima. In un lotto, otto linguaggi sono stati segnalati con un errore del 5-20%; all’ispezione solo uno di quei linguaggi presentava un bug reale — il resto erano errori del giudice dovuti a non aver colto la semantica propria del linguaggio (una riga sorgente che legittimamente emette più edge, binding di parametri modellati come assegnazioni, linguaggi con riferimento-per-identificatore). Ecco perché campioniamo con due seed e facciamo cross-check, e perché un disaccordo tra il giudice e le fixture è trattato come il segnale più interessante, non un verdetto definitivo — a volte è la fixture a essere sbagliata.

Siamo anche onesti sull’obiettivo. Il traguardo è zero errori reali, punto e basta — ma “zero” è un obiettivo verso cui lavoriamo con costanza, linguaggio per linguaggio, non una casella da spuntare. C’è sempre un altro repository con un altro idioma.

Dimostrato con il lavoro, non solo dichiarato

Tutto ciò che Maguyva fa per un agente — trovare un simbolo, tracciare una dipendenza, rispondere a una domanda con codice citato — poggia sul fatto che l’estrazione sottostante sia corretta. Su 280 linguaggi, la correttezza non può essere soltanto dichiarata; deve essere continuamente dimostrata sul codice reale. Il loop è il modo in cui ce la guadagniamo: un ciclo autonomo di campionamento-e-correzione che tratta le proprie metriche con sospetto, dimostra ogni modifica, e trasforma ogni correzione in una guardia contro la prossima regressione. Non è affascinante. È il lavoro che ci permette di dire “supportiamo il tuo linguaggio” e intenderlo davvero. Verde è facile. La correttezza si conquista con il lavoro.

Letture correlate

Altro dal diario di sviluppo di Maguyva