Cordis: togliere un pezzo a un programma acceso senza riavviarlo, secondo DeepSeek e Pechino

Un paper di Pechino e DeepSeek-AI porta effetti e coeffetti, due strumenti della teoria dei linguaggi, dentro il runtime: ogni modifica di un componente porta con sé il suo inverso, ogni dipendenza è dichiarata e seguita in tempo reale. Ne esce Cordis, una libreria TypeScript già alla base di un ecosistema di oltre 4000 plugin. Che cosa è dimostrato, che cosa è solo osservato e perché gli autori pensano agli agenti che si modificano da soli.

Chi ha allestito una mostra temporanea in un museo conosce la regola non scritta del disallestimento. Si possono piantare chiodi, tirare cavi, spostare una vetrina, ma a fine mostra le pareti devono tornare come erano, e le cose si smontano in ordine inverso a quello in cui sono state montate: prima il quadro, poi il chiodo, poi lo stucco sul buco. E c’è una seconda regola, più silenziosa: la sala video apre solo se il proiettore è arrivato. Se il proiettore va in riparazione, la sala chiude da sola, e le altre sale restano aperte.

Il software che si compone mentre è acceso ha esattamente questi due problemi, e quasi sempre li risolve nel modo più brutale: spegnendo tutto e riaccendendo. È il punto di partenza di A Programming Paradigm for Spatiotemporal Composability, depositato su arXiv il 26 agosto 2026 (2608.25512) da Yifan Shi, Wei Zhang e Tianyi Cui, dell’Università di Pechino e di DeepSeek-AI. Sono 92 pagine, in buona parte di teoremi, e non contengono un solo benchmark di machine learning. Ma riguarda da vicino chi lavora sugli agenti, per una ragione precisa: una delle due motivazioni dichiarate sono gli harness degli agenti che, prima o poi, riscriveranno i propri componenti senza fermarsi.

Il problema: il riavvio come unico strumento

Gli autori separano la questione in due dimensioni. La prima è temporale: quando un componente viene rimosso, tutto quello che ha modificato nell’ambiente condiviso deve essere annullato, completamente e in ordine. La seconda è spaziale: i componenti devono poter dichiarare da chi dipendono, e il sistema deve reagire quando una dipendenza compare, sparisce o cambia identità.

L’esempio concreto è Visual Studio Code. Le estensioni girano tutte in un processo condiviso, e una volta eseguita la loro funzione di attivazione non c’è modo di scaricarne una sola: per disinstallarla bisogna riavviare l’intero processo, con tutte le altre dentro. Fra le cento estensioni più installate, contano gli autori, 87 contengono codice eseguibile e quindi richiedono quel riavvio. Sul versante spaziale, solo 7 su 100 dichiarano una dipendenza da un’altra estensione non di sistema, e quando un’estensione ne usa un’altra riceve un oggetto senza tipo, senza alcun contratto verificato. I dati sono presi dal marketplace il 9 giugno 2026.

Il ripiego di tutti è delegare al sistema operativo e agli orchestratori di container. Funziona, ma alla granularità sbagliata. Un riavvio butta via cache, connessioni e calcoli a metà, e ricostruirli richiede da secondi a minuti; due componenti che vivono nello stesso processo non possono dichiarare una dipendenza reciproca a quel livello, e ciò che potrebbe essere una chiamata di funzione diventa traffico di rete.

Per un plugin di un editor è una scomodità. Per un harness di agenti che modifica i propri componenti di continuo e con poca supervisione umana, osservano gli autori, diventa un problema serio: ogni automodifica costa un riavvio che interrompe i compiti in corso, e una modifica sbagliata può mettere fuori uso proprio il processo che servirebbe a rimediare.

Che cos’è l’harness di un agente, cioè lo strato di codice che gli dà strumenti, memoria, permessi e sottoagenti, e perché è diventato la parte che si progetta davvero: se ne parla nel capitolo sulle architetture degli agenti.

Leggi «Architetture e valutazione» nel libro →

Effetti che si possono disfare

L’idea è prendere in prestito due strumenti della teoria dei linguaggi di programmazione. Gli effetti descrivono come un calcolo modifica il mondo; i coeffetti, il loro duale, descrivono che cosa un calcolo richiede al mondo. Nella tradizione (Moggi con le monadi, Plotkin e Power con gli effetti algebrici, Petricek e colleghi per i coeffetti) sono strumenti statici: servono al compilatore per ragionare su porzioni di codice con confini fissati. La proposta è spostarli a runtime.

Il primo passo sono gli effetti reversibili. Ogni modifica al contesto condiviso $\Gamma$ viene modellata come una funzione che restituisce il contesto modificato e, insieme, la funzione che lo riporta indietro:

$$e : \Gamma \to \Gamma \times (\Gamma \to \Gamma).$$

Il runtime conserva un accumulatore $\varphi$, la composizione di tutti gli inversi raccolti fin lì. Registrare un effetto $(f, g)$ significa applicare $f$ allo stato e aggiungere $g$ all’accumulatore, $(\gamma, \varphi) \mapsto (f(\gamma),\, \varphi \circ g)$. La composizione di due coppie è «ritorta»:

$$(f_1, g_1) \circ (f_2, g_2) = (f_1 \circ f_2,\; g_2 \circ g_1),$$

cioè gli inversi si accumulano in ordine opposto a quello delle azioni: l’ultima cosa montata è la prima smontata, come nel museo. Rimuovere un componente vuol dire applicare il suo accumulatore. La novità non sta nella pila di funzioni di pulizia, che molti framework hanno, ma nel fatto che l’unico modo di toccare il contesto passa di lì: in Cordis ogni mutazione, compresa la fornitura di un servizio o la creazione di un sottocomponente, si riduce a una chiamata di ctx.effect, quindi nulla di ciò che passa dal contesto sfugge al tracciamento.

Due dimensioni della composizione a runtime Temporale: effetti reversibili azione inverso conservato registra listener rimuovi listener apri connessione chiudi connessione fornisci servizio ritira servizio caricamento rimozione alla rimozione gli inversi girano dall’ultimo al primo: il contesto torna com’era Spaziale: coeffetti reattivi fornitore pubblica «database» componente chiede «database» ogni cambio del contesto viene classificato inattivo attivo il fornitore arriva il fornitore se ne va senza la dipendenza si aspetta, non si fallisce; si riattivano solo i componenti toccati Il «contesto» unico media entrambe: ogni modifica e ogni dipendenza passano di lì

Dipendenze che si accendono e si spengono

Il secondo passo sono i coeffetti reattivi. Un componente dichiara quali chiavi del contesto gli servono (un database, un adattatore di messaggistica, un filesystem) e il runtime classifica ogni cambiamento dello stato rispetto a quella specifica: attivante se prima la specifica non era soddisfatta e ora sì, disattivante nel caso opposto, neutro altrimenti. Un cambio attivante fa partire gli effetti del componente, uno disattivante applica il suo accumulatore. Un plugin la cui dipendenza manca non va in errore: resta inattivo finché la dipendenza non arriva.

Le due metà si saldano in quello che gli autori chiamano paradigma del contesto: effetti e coeffetti vivono in un unico tipo di contesto, e tutto passa da lì. Questa mediazione induce un’equivalenza osservazionale, e a meno di quella gli effetti di componenti diversi si possono intercalare senza disturbarsi. Sopra c’è un calcolo formale della composizione dinamica, con i suoi teoremi: preservazione (un sistema ben formato resta tale a ogni passo), recupero terminale (quando un componente se ne va, il suo contributo allo stato si azzera), progresso (niente stalli, e ogni sequenza di passi termina in uno stato quiescente, purché le dipendenze siano acicliche e i componenti in numero finito) e confluenza (ordini diversi degli stessi passi portano a stati equivalenti, anche qui sotto ipotesi esplicite sui componenti).

Dalla teoria alla libreria

Tutto questo è implementato in Cordis, una libreria TypeScript che gli autori chiamano meta-framework: non serve a un dominio preciso, fornisce solo la semantica della composizione. Il nucleo sono poche primitive (ctx.effect, ctx.get, ctx.set, più isolamento e intercettazione delle chiavi); sopra c’è un caricatore dichiarativo che confronta la configurazione nuova con la vecchia e applica, campo per campo, l’operazione meno invasiva. Cambiare i metadati di intercettazione di un componente non lo ricarica; disabilitarlo lo scarica e basta.

La conseguenza più tangibile è l’hot module replacement. In Webpack o Vite lo sviluppatore deve segnare a mano i punti in cui un modulo accetta di essere sostituito. In Cordis no: poiché ogni componente delimita già tutti i propri effetti, sostituirlo significa scaricare la vecchia istanza, che si porta via tutto quello che aveva installato, e caricarne una nuova. Cache e connessioni del resto del sistema restano dove sono.

La stessa struttura, notano gli autori nella discussione, trasforma in pattern applicativi cose che oggi si fanno a livello di infrastruttura. Un servizio con più fornitori dietro un intermediario permette il bilanciamento del carico e l’aggiornamento graduale: si carica la nuova versione accanto alla vecchia, si sposta il traffico, si scarica la vecchia quando non ha più richieste in volo. È un blue-green deployment dentro un processo solo.

I numeri, e che cosa dimostrano

La validazione è un caso di studio: Koishi, un framework open source per chatbot costruito su Cordis, con oltre 4000 plugin scritti dalla comunità in quattro anni, dagli adattatori per le piattaforme di messaggistica ai driver di database alle console di amministrazione. In Koishi disattivare un plugin dalla console ne annulla gli effetti sul posto, e cambiare il database a caldo riattiva solo i plugin che ne dipendono.

Gli autori sono espliciti su che cosa questo prova e che cosa no. È un risultato «di esistenza e di adozione», non quantitativo: un solo ecosistema, un solo linguaggio, osservazione e non confronto controllato. Il costo dell’astrazione e il suo effetto sulla produttività non sono misurati, e restano lavoro futuro. C’è anche un disallineamento di versione: Koishi usa Cordis v3, il paper presenta la v4, che rivede la semantica e riprogetta il caricatore. Gli autori dicono che il modello di fondo è condiviso, ma la versione descritta nel dettaglio non è quella che ha accumulato i quattro anni di uso.

I limiti dichiarati

L’inverso lo scrive l’autore, e nessuno lo controlla. Il runtime tiene gli inversi e li applica in ordine, ma che l’inverso annulli davvero l’effetto è un obbligo di chi scrive il componente: la libreria non lo verifica. Tutte le garanzie formali poggiano su questa ipotesi.

Il mondo esterno non si riavvolge. Un byte scritto su un file che altri leggono, un pacchetto spedito in rete, un pagamento: una volta usciti dal perimetro del sistema non tornano indietro. Il paper lo dice con chiarezza e rimanda a due vie note, trattenere l’emissione finché lo stato è sicuro oppure compensare (cancellare il file, rimborsare l’addebito). Ma la metateoria non si trasferisce automaticamente alla compensazione, e andrebbe ridimostrata. Per un agente, che nel mondo esterno manda email e chiama API, è il punto che conta di più.

I cicli si pagano in granularità. Se A dipende da B e B da A, entrambi restano inattivi per sempre. Si vede già dalle dichiarazioni e si risolve spezzando i componenti, ma con $n$ componenti che interagiscono fra loro i pezzi di raccordo possono crescere in modo quadratico.

Sicurezza solo fra componenti fidati. Il controllo sugli accessi è a livello di linguaggio; per il codice non fidato serve una sandbox esterna.

Gli agenti restano un’ipotesi. Gli harness che si automodificano sono la motivazione e la prospettiva finale del paper, non un esperimento. Nessun agente è stato messo alla prova.

Perché conta adesso

La conversazione sugli agenti si è spostata dal modello all’harness: il codice che gli dà strumenti, memoria, permessi, sottoagenti. E si immagina sempre più spesso che sia l’agente a riscriverlo. Questo paper non dimostra che si possa fare in sicurezza. Fa una cosa più modesta e più utile: dice quali proprietà un sistema del genere dovrebbe avere, le formalizza, e mostra che un ecosistema reale, fatto di migliaia di plugin scritti da autori indipendenti, da anni li monta e li smonta senza riavviare il processo. Resta da vedere se regge quando a scrivere i componenti non è una comunità di sviluppatori ma un modello, a ritmo continuo e con poca supervisione. Che è esattamente il banco di prova che gli autori indicano come prossimo passo.

I commenti sono riservati agli iscritti.

Accedi per commentare