2026-07-16 | Pinperepette

Non Esiste Il Contesto

Una teoria task-indotta del context engineering: perche' il contesto e' una proprieta' del task, non dell'input.

Un agente che risolve un task e' una funzione. Due contesti che gli fanno dare la stessa risposta sono, per quel task, lo stesso contesto. Da questa banalita' esce un plugin che proietta il repository sul minimo indispensabile, e misura di averlo fatto senza rompere la risposta.

Agenti AI Contesto Matematica Claude Code

In breve, senza formule

Lavori con un agente su un repository vero e ti accorgi che il contesto che serve davvero e' una briciola. Tutto il resto e' rumore, e lo paghi due volte, in token e nell'attenzione del modello. Poi noti una cosa che sembra ovvia solo dopo averla vista: due contesti che portano l'agente alla stessa risposta, per quel task, sono lo stesso contesto. Quindi il contesto non e' assoluto, e uno piu' piccolo esiste.

Ho scritto il codice che se ne approfitta. Si chiama context-kernel, e' un plugin per Claude Code, proietta il repository sul minimo che serve al task e poi controlla di non aver spostato la risposta. Su una sessione reale sono 79% di token in meno, fino al 97% in meno sui file, e su sessanta bug veri il taglio non ha mai buttato via cio' che serviva a risolverli.

// Due Contesti Diversi, Stessa Risposta

Sezione 00. L'articolo determinativo che nessuno guarda

Qualche settimana fa ho misurato una cosa spiacevole: quando lavori con un agente su un repository vero, la parte utile del contesto e' una briciola. Il resto e' l'harness che si racconta addosso, file riletti identici, output di comandi lunghi come romanzi. In Sei lo 0,1% ho messo i numeri sotto la lamentela. Bene. Questo e' il pezzo in cui smetto di lamentarmi e costruisco il pezzo di codice che rimette a posto la faccenda. Ma la parte che mi interessa non e' l'ottimizzazione, e' l'osservazione da cui esce. Parte da un articolo determinativo che nessuno guarda: il contesto.

La molla, per onesta', non e' stata il codice. E' stato un libro: Spectral Theory and Quantum Mechanics di Valter Moretti (Springer), un mattone sulla teoria degli operatori negli spazi di Hilbert, roba di meccanica quantistica che con gli agenti non c'entra niente. Leggendo di proiettori, kernel e decomposizioni spettrali mi e' venuta in mente la cosa che sto per raccontarti: e' lo stesso vocabolario che serve a dire cosa un agente puo' buttare via senza cambiare risposta. Metto le mani avanti subito, prima di riempire l'articolo di formule. Prendo in prestito le parole, proiezione, kernel, classe di equivalenza, non pretendo che qui viva un isomorfismo con quella matematica. E' un'analogia, la uso con cautela: serve a pensare la cosa giusta, non a fare le pulci a un teorema.

Prendi un agente che risolve un task. Chiamalo \( Q \). Dagli in pasto un contesto, cioe' il repository, la conversazione, gli output dei tool, e lui produce una risposta. Questa e' una funzione, niente di piu':

$$A_Q : X \longrightarrow Y$$

La mappa risposta. X = spazio dei contesti possibili, Y = spazio delle risposte, Q = il task

Adesso la mossa. Una funzione manda robe diverse sullo stesso valore in continuazione. Due contesti diversi possono darti la stessa identica risposta per quel task. E se ti danno la stessa risposta, per \( Q \) sono la stessa cosa. Questa e' una relazione di equivalenza, la scrivi cosi':

$$x \sim_Q x' \iff A_Q(x) = A_Q(x')$$

Due contesti sono equivalenti sotto Q quando producono la stessa risposta

Da qui esce la frase che regge tutto l'articolo, e il plugin: non esiste "il" contesto. Il contesto non e' una cosa che l'agente riceve, e' una cosa che il task ritaglia. Esistono infinite rappresentazioni equivalenti sotto il task, una classe intera, \( [x]_Q \). L'agente non ha bisogno del documento. Ha bisogno di un rappresentante qualsiasi della classe. Se sai scegliere un rappresentante piccolo, hai vinto senza aver toccato la risposta. Non stai buttando via informazione, stai scegliendo un altro elemento della stessa classe. Questa mossa ha un nome preciso, ed e' astrazione, non compressione.

La distinzione con la compressione non e' un cavillo, e' il cuore della cosa. gzip ti rende il testo piu' piccolo e illeggibile: butta via i bit e per rileggerli devi decomprimere. Qui non butti via niente, scegli un altro elemento della stessa classe di equivalenza, quello piu' piccolo. E' la stessa mossa che sta sotto l'abstract interpretation, la minimizzazione degli automi, le ottimizzazioni dei compilatori: tieni solo cio' che distingue i comportamenti che ti interessano, il resto collassa. L'output resta codice, resta leggibile, resta sufficiente. Dove si puo' per costruzione, dove non si puo' per misura.

// Il Projector, E Cosa Butta Via

Sezione 01. Idempotente e answer-preserving

Scegliere un rappresentante piccolo e' applicare una mappa. La chiamo projector indotto dal task, \( \pi_Q \), e le chiedo due sole proprieta':

$$\pi_Q(\pi_Q(x)) = \pi_Q(x) \qquad\qquad A_Q(\pi_Q(x)) = A_Q(x)$$

Idempotente (normalizzare due volte non cambia niente) e answer-preserving (la risposta resta quella)

Il pedice \( Q \) non e' decorazione. Cambia la domanda e cambia cosa puoi buttare via. Quello che e' invisibile a "sistema questo KeyError" puo' essere l'unica cosa che conta per "controlla le intestazioni di licenza". Un projector senza indice del task o e' banale o e' sbagliato. Il projector non fa altro che applicare trasformazioni che stanno nel kernel del task:

$$\ker Q = \{\, T : A_Q(T(x)) = A_Q(x)\ \ \forall x \,\}$$

Il kernel del task: le trasformazioni T del contesto che non muovono mai la risposta, qualunque sia il punto di partenza

Ho scritto \( T \) e non "\( x + \delta \)" apposta. Sommare due repository non vuol dire niente, non esiste un piu' tra due codebase. Una trasformazione si': tagliare un file, deduplicare un log, buttare una pagina di documentazione. Una \( T \) sta nel kernel del task quando, applicata a qualunque contesto, non sposta mai la risposta. Il kernel e' l'insieme di queste mosse gratis. Le millequattrocento pagine di documentazione di pandas che un errore su una merge non guardera' mai. I ventitre installer nella cartella Download quando il task e' rinominare le bollette. Applichi le trasformazioni del kernel, tieni il resto, la risposta non si accorge di niente.

// Due Kernel Di Natura Diversa

Sezione 02. Sintattico e semantico

Il kernel si spezza in due pezzi, e la forma del plugin viene tutta da questa spaccatura. C'e' la roba invisibile a ogni task, e la roba invisibile solo a questo task.

$$\ker_{\mathrm{syn}} = \bigcap_{Q} \ker Q \;\subseteq\; \ker Q$$

Il kernel sintattico e' l'intersezione su tutti i task: sta dentro il kernel di qualunque Q

Il kernel sintattico non dipende dalla domanda. Sono i codici ANSI di colore, le barre di avanzamento che si ridisegnano venti volte, le righe duplicate consecutive, un file riletto identico a quello che hai gia' in contesto. Roba che nessun task guardera' mai. Poiche' non serve sapere cosa stai facendo per sbatterla fuori, la togli in modo ambientale, con un hook che gira sempre e non chiede niente a nessuno.

Il kernel semantico e' invisibile solo a questo task. Le millequattrocento pagine di pandas per il KeyError. Qui devi sapere qual e' \( Q \), e infatti questa e' la parte difficile. Il primo pezzo lo togli gratis e ovunque. Il secondo lo togli quando c'e' un sintomo che ti dice quale task stai risolvendo: uno stack trace, un messaggio d'errore, dei file indiziati. Non c'e' un caso in cui questa distinzione non decida l'architettura. Chi mescola i due finisce per tagliare il codice sorgente prima di aver capito cosa serve, e a quel punto ha rotto la risposta senza accorgersene.

// Il Task State, In Quattro Operatori

Sezione 03. T1 ambientale, T2-T4 indotti dal sintomo

Definisci lo stato del task come il rappresentante canonico piccolo, quello su cui l'agente lavora davvero:

$$\mathrm{TS}(Q) := \pi_Q(C)$$

Il task state. C = il contesto pieno (repo + dialogo), TS(Q) = quello che l'agente vede davvero

L'agente non lavora mai sul repository. Lavora sul task state. Il projector \( \pi_Q \) lo fabbrico passando per quattro operatori, ognuno con un mestiere preciso. Il primo agisce sul dialogo, gli altri tre sul codice, e agiscono su fattori diversi del contesto: per questo commutano e l'ordine non fa danni.

OperatoreCosa faCome lo fa
T1 normalizza
compress.py
Ripulisce gli output dei tool (Bash, Grep, Read) mantenendo il segnale. Ambientale, gira sempre. Dedup, taglio dei codici ANSI e delle barre di avanzamento, elisione testa piu' segnale piu' coda. Su una rilettura identica collassa a un marcatore di tre righe; su un file cambiato ti da' il diff contro la copia gia' in contesto.
T2 repo slice
kernel-scout
Proietta l'intero repository sul working set rilevante per il sintomo. Indotto dal task. Slicer deterministico sul grafo degli import, con budget in token e discesa a livello di simbolo quando il file da solo e' troppo grosso. Ordina seed, dipendenze, importatori, test correlati.
T3 carta del task
kernel-extractor
Estrae i vincoli che il fix deve rispettare, ognuno con citazione file:riga. Converte la massa di codice in proposizioni verificabili: contratti, invarianti, comportamenti presi dai test. Non "leggi tutto", ma "questi dieci vincoli, e da dove vengono".
T4 verifica
kernel-verifier
Giudica il fix contro la carta, vincolo per vincolo. E giudica l'invarianza della risposta. In sessione, zero chiamate API: la verifica di \( A(x) = A(\pi(x)) \) usa l'abbonamento che gia' paghi, non una chiave nascosta.

T1 e' un hook PostToolUse: intercetta l'output di un comando dopo che e' stato eseguito e prima che arrivi al modello. Ecco cosa vede l'agente quando lancio un pip3 list su una macchina piena:

absl-py 2.1.0 aiohttp 3.9.5 ... 1047 righe come queste, ordinate, tutte uguali nella forma ... tensorflow 2.16.1 # riga tenuta: pacchetto citato nel task urllib3 2.2.1 [context-kernel: 14900 -> 995 token, -93%]

Millecinquantatre righe reali diventano novecentonovantacinque token. Il footer non e' cosmetico, e' un contratto: ti dice esattamente quanto e' stato tolto, cosi' sai che e' successo e quanto. Su una sessione vera, misurata dal contatore che scrive un log a parte, il risparmio complessivo si e' assestato intorno al meno settantanove per cento di token, con il segnale intatto.

-93%
pip3 list
14.900 -> 995 token
-96%
pandas
sotto il pavimento a file
30 / 1048
lodash
file nel working set
46x
slice ripetuto
piu' veloce (cache)

T2 e' quello che mi ha insegnato di piu'. Misurare il budget in file nasconde un muro: certi file sono monoliti da migliaia di righe, e un working set di "tre file" puo' essere piu' pesante di trenta. Misurato in token, il muro si vede. Li' ho smesso di contare i file e ho iniziato a contare i token. La risposta e' scendere sotto il file, al singolo simbolo. Su pandas questo porta il task state al meno novantasei per cento sotto il pavimento che avresti tagliando a livello di file. Su lodash, un vero stack trace di node su millequarantotto file diventa un working set di trenta, con tutti e quattro i frame dello stack tenuti a ogni profondita' di taglio.

Qui la parola "projector" nasconde un pezzo che vale la pena tirare fuori. Quel budget in token non e' un parametro di comodo, cambia la proiezione. Con un milione di token di finestra puoi tenere molto, dipendenze lontane e qualche file di contorno. Con ottomila devi essere spietato, il seed e poco altro. Il projector quindi non dipende solo dal task, dipende anche dalle risorse:

$$\pi_{(Q,\,B)} : X \longrightarrow X$$

Il projector dipende dal task Q e dal budget B. Stesso bug, finestra diversa, rappresentante diverso

Stesso bug, stesso repository, ma la fetta giusta a ottomila token e la fetta giusta a un milione non sono la stessa fetta. Lo slicer lo affronta scendendo una scala: chiusura piena, poi dipendenze fino a due salti, poi uno solo, finche' non sta nel budget. La proiezione e' relativa al task e alla tasca.

// Il Duale Mancante: Il Supporto Del Task

Sezione 04. Non il working set, il motivo della risposta

Ho definito il task state, cioe' quello che l'agente vede. Gli manca il duale, e il duale e' la parte piu' interessante. Chiamalo supporto del task:

$$\mathrm{Supp}(Q, x) \;\subseteq\; \mathrm{TS}(Q) \;\subseteq\; x$$

Il supporto: l'insieme minimo di informazioni che giustificano la risposta. Sta dentro il working set, che sta dentro il contesto

Il supporto non e' il contesto, e non e' nemmeno il working set. E' il motivo per cui la risposta e' quella: le poche proposizioni che, se le togli, la risposta cambia davvero. Il task state e' generoso, tiene anche roba di contorno per sicurezza. Il supporto e' avaro, tiene solo cio' che giustifica. Qui T3 smette di essere un operatore tra i quattro e diventa il piu' ambizioso: la carta del task, i vincoli con citazione file:riga, e' un tentativo di costruire proprio \( \mathrm{Supp}(Q,x) \). Non "leggi tutto il working set", ma "ecco le dieci proposizioni che reggono la risposta, e da dove vengono". Un fix che le rispetta tutte e' corretto per costruzione, nei limiti di cio' che la carta ha saputo vedere.

// Non Prometto Che Basti, Lo Misuro

Sezione 05. Sessanta bug veri, zero persi per strada

Answer-preserving e' facile da scrivere in una formula e difficile da garantire con l'analisi statica pura. Un import dinamico, un container di dependency injection, una configurazione che sceglie la classe a runtime: tutte cose invisibili al grafo degli import. Quindi il plugin non da' per scontato che la fetta basti, lo verifica misurando.

Sembra una precisazione da poco. Non lo e', e' un cambio di paradigma. Lo schema che oggi si vede quasi ovunque, e quello di qui, sono le stesse parole in ordine diverso:

compressione -> LLM -> speriamo trasformazione -> misura -> LLM

Nella prima riga comprimi, passi il risultato al modello e incroci le dita: se hai buttato via la cosa sbagliata te ne accorgi dalla risposta storta, quando ormai e' tardi. Nella seconda trasformi, misuri che la trasformazione non abbia spostato la risposta, e solo dopo passi al modello. Il punto di controllo si sposta prima dell'LLM invece che dopo. La differenza sembra piccola perche' sono le stesse tre parole. In pratica e' la distanza tra un sistema che speri funzioni e uno che sai dove sbaglia.

Il benchmark e' l'atto del misurare. Prendi sessanta bug veri, di quelli con uno stack trace e un fix noto. Per ognuno lasci che context-kernel tagli il contesto, poi controlli una cosa sola: nella fetta rimasta c'e' ancora tutto quello che serve per risolvere quel bug? In termini dell'articolo, la fetta contiene il supporto?

La risposta e' si' in tutti e sessanta i casi, a ogni livello di taglio. Il dato interessante e' il perche'. Quello che rovina la fetta non e' quanto tagli in profondita', e' sbagliare il punto di partenza. Tagliare la chiusura del grafo, che sembra la cosa aggressiva, e' quasi gratis. Sbagliare il seed, che sembra un dettaglio, ti fa perdere il caso. E il benchmark si e' ripagato da solo. La prima volta ne risolveva cinquantuno su sessanta. Ho guardato i nove che mancavano, e non era la profondita' del taglio: era un bug vero di seeding, path assoluti ambigui dentro la root del progetto. Corretto, con un test di regressione che adesso lo tiene fermo.

C'e' un punto che ho sottovalutato a lungo. Di tutti i pezzi, quello che conta di piu' non e' il projector, e non e' lo slicer. E' \( T_4 \), la verifica. Il resto della teoria e' elegante, e potrebbe essere sbagliato: "answer-preserving" resta una parola finche' qualcuno non prova a mostrarti che la risposta e' cambiata. \( T_4 \) e' quel qualcuno. La verifica di invarianza, il benchmark dei sessanta casi, il canary, sono l'apparato che puo' dire di no. Senza, avrei una teoria che non si puo' smentire, cioe' la peggior specie di teoria. Con, ho qualcosa che un esperimento puo' rompere. Tengo la seconda.

Centodiciassette test, solo libreria standard, girano in circa sette secondi. Zero dipendenze, zero chiamate API. La verifica dell'invarianza della risposta gira dentro la sessione, con l'abbonamento che gia' hai. Nessuna chiave nel repository, controllato con un grep. Questa non e' una scelta di stile, e' la condizione perche' uno strumento che decide cosa l'agente vede sia esso stesso ispezionabile e ripetibile.

// L'Inverso Non Esiste, Esiste L'Accesso

Sezione 06. L'onesto indebolimento: page fault

Qui va detta la cosa scomoda. Gli operatori si concatenano senza attriti: applichi \( T_2 \) dopo \( T_1 \), scrivi \( T_2(T_1(C)) \), e ne componi quanti ne vuoi, il risultato e' ancora una proiezione valida. Quello che non puoi fare e' tornare indietro. Non esiste un \( \pi_Q^{-1} \) che ti ridia quello che hai tolto: l'inverso di una proiezione non e' un'operazione, e' un percorso di accesso. Se ti serve una cosa proiettata via, non la "decomprimi", la vai a prendere. Questo e' il page fault, e nel plugin e' un meccanismo di prima classe, non un errore.

Le esclusioni sono dichiarate, non silenziose. Lo slicer, quando taglia, scrive cosa ha lasciato fuori e perche'. Se poi si scopre che serviva, la si recupera con una lettura mirata, e il conto di quella lettura e' piccolo e visibile. L'ho misurato su un bug vero, usando i bug del plugin stesso come task \( Q \):

1 / 14
slice statica
-93% sui sorgenti
4 / 14
con i page fault
working set reale, -71%
2 / 2
fault
riparati, ~15 righe lette
12 / 12
vincoli
verdetto PASS

Lo slicer statico da solo aveva sotto-sliciato: i test caricavano il modulo via importlib e subprocess, un arco che il grafo degli import non vede. I due page fault dichiarati hanno corretto il working set da uno a quattro sorgenti su quattordici, senza che la slice andasse invalidata. La carta del task, i dieci vincoli con citazione, ha intercettato due cose che il fix fatto a mano aveva sbagliato: una tensione con un test legacy, e una deviazione su un invariante che il primo tentativo aveva calpestato. Il verificatore ha chiuso con dodici vincoli su dodici rispettati. La lezione e' che l'onesta' sulle esclusioni costa meno del rumore che eviti.

// Lo Strumento Che Si E' Morso La Coda

Sezione 07. Il canary, e tre bug veri

Un hook che riscrive quello che l'agente vede e' pericoloso in un modo particolare: il contratto con l'harness non e' documentato, e puo' cambiarti sotto i piedi. Se un giorno la forma dell'output cambia e la tua sostituzione non viene applicata, il modello riceve la roba integrale e tu non te ne accorgi. Per questo ogni sostituzione lascia un canarino: registra il footer esatto che dovrebbe comparire, e poi controlla che sia comparso davvero. Non e' una garanzia che il contratto tenga, e' una difesa che ti avvisa nell'istante in cui si rompe.

Ha funzionato per davvero. Un allarme del canary ha segnalato una compressione che risultava applicata ma non lo era. Tirando il filo sono usciti tre bug veri. Il primo era il peggiore: le Read non venivano mai compresse. Per una Read la risposta del tool e' annidata in un modo diverso da Bash, e l'estrazione cercava la chiave nel posto sbagliato, quindi il testo estratto era vuoto e la compressione un no-op da sempre. Il secondo: il canary si dichiarava soddisfatto per un match troppo generoso, scattava anche sui contenuti che citavano il footer, tipo i log del progetto o i transcript riletti dalle sessioni headless. Il terzo, trovato mentre sistemavo i primi due: un output che veniva solo da stderr finiva distrutto invece che compresso.

Mentre scrivevo questo articolo ho aperto il README del plugin per controllare un numero. L'hook di compressione ha eliso i passaggi di prosa piu' densi e mi ha lasciato un footer in fondo, [context-kernel: ... -78%]. Lo strumento ha compresso la mia lettura della sua stessa documentazione. Ho letto i file a pezzi piccoli per stare sotto la soglia. Un tool che decide cosa vedi, applicato a te che lo studi: e' esattamente il motivo per cui il footer e il canary non sono optional.

Messa in fila, la corsa completa di quel bug, dal repository al verdetto, e' questa. Numeri veri, presi dalla telemetria della pipeline:

Task: "il canary segnala una compressione mai applicata, c'e' un test rosso. Trova il bug e sistemalo."
Repository14 sorgenti del plugin
↓   T1 normalizza gli output, il kernel sintattico
Output ripulitiuna Read 2.464 → 832 token
↓   T2 slice del repo dal sintomo
Working set14 → 4 sorgenti (1 statico + 3 page fault)
↓   T3 carta del task
Supporto10 vincoli citati file:riga
↓   l'LLM lavora sul supporto
Fixi tre bug sistemati
↓   T4 verifica adversarial
Verdetto12 / 12 vincoli, PASS

Il modello non ha mai visto i quattordici sorgenti, ne le migliaia di righe dei log di quella sessione. Ha visto quattro file, dieci vincoli e un test rosso. Ha prodotto il fix, e un altro giro di pipeline lo ha promosso a dodici vincoli su dodici. Questa e' la teoria di sopra applicata una volta sola, dall'inizio alla fine.

// L'Oggetto: context-kernel

Sezione 08. Cosa installi, e il conto che torna

Fin qui l'idea. L'implementazione si chiama context-kernel, e' un plugin nativo per Claude Code con un ripiego per Codex, e non ha niente sotto che non puoi leggere: solo libreria standard di Python, zero dipendenze, zero chiavi API. Registra da solo l'hook \( T_1 \), cioe' la compressione ambientale col canary, due tool MCP per lo slice (kernel_slice e kernel_repo_slice), cinque skill e tre agent per la pipeline \( T_2 \)-\( T_4 \). Versione 0.9.1, licenza MIT, il codice sta su GitHub.

# dal marketplace, due righe /plugin marketplace add pinperepette/context-kernel /plugin install context-kernel

Adesso il conto. La parte che importa non e' "quanto taglia", e' "quanto taglia senza spostare la risposta". Sui token il risparmio e' quello che hai gia' visto pezzo per pezzo, messo in fila:

-79%
token
su sessione reale
-93%
pip3 list
14.900 -> 995
60 / 60
bug reali risolti
anche dopo il taglio
0
chiavi API
tutto in sessione

Gli stessi numeri, caso per caso, cosi' non devi fidarti sulla parola:

Caso realePrimaDopoTask riuscito
pip3 list (output di un comando)14.900 token995 tokensegnale tenuto
Read di un file sorgente2.464 token832 tokenfile leggibile
lodash, stack trace di node1.048 file30 file4/4 frame tenuti
repo del plugin, bug del canary14 sorgenti4 sorgentiverifier 12/12
sessione di lavoro interabaseline-79% tokenlavoro finito

L'agente continua a risolvere gli stessi casi. Il modo pulito di vederlo e' mettere la proiezione indotta dal task accanto al troncamento cieco, quello che tanti strumenti fanno tagliando testa e coda a naso:

Contesto rimossoProiezione (context-kernel)Troncamento cieco
fino al 40%risposta intattarisposta intatta
oltre il 40%risposta intattainizia a perdere la risposta
fino al 75%risposta intattagia' crollato

Curva rate-distortion misurata: la proiezione lascia nella fetta tutto il necessario anche togliendo il settantacinque per cento del contesto; tagliare alla cieca perde la risposta gia' oltre il quaranta per cento.

Questo e' il senso di risparmiare senza perdere performance. Il risparmio arriva perche' togli solo quello che il task non usera' mai, e la risposta resta identica: per costruzione dove si puo', per misura dove non si puo'. In piu' due regali. Lo slice ripetuto va quarantasei volte piu' veloce grazie alla cache del manifest, e la verifica non costa una chiamata in piu' perche' gira in sessione. Centodiciassette test in circa sette secondi ti dicono se qualcosa si e' rotto prima che lo scopra l'agente.

Una cosa, per onesta', che forse leggendo hai gia' pensato. La teoria di sopra e' piu' generale del plugin. La proiezione indotta dal task non ha niente di specifico a Claude Code: ovunque un modello riceve piu' contesto di quanto il task ne chieda, la stessa mossa vale, con altri hook, un altro linguaggio, un altro harness. context-kernel e' dove l'ho misurata, non dove finisce. Se preferisci vederlo come l'implementazione particolare di un'idea piu' grande, lo vedi giusto.

Non esiste "il" contesto.
Esiste la classe delle cose che danno la stessa risposta, e il rappresentante piu' piccolo che scegli tu.

Se dovessi dirti qual e' la cosa originale, non ti direi "il projector", ne "il kernel", ne i quattro operatori. Ti direi questa, la stessa di apertura: il contesto non e' un input assoluto, e' un oggetto relativo al task. Se questa premessa non ti convince, probabilmente non ti convincera' nemmeno il resto. Se invece la accetti, i quattro operatori, il page fault, la discesa al simbolo vengono quasi da soli: c'e' una classe di contesti equivalenti, ne scegli uno piccolo, e il lavoro diventa astrarre, poi misurare di non aver spostato la risposta. I numeri li puoi rifare tu, e' tutto deterministico e offline.

E' anche il motivo per cui la chiamo un'idea e non un pacchetto di feature: non sposta la soluzione, sposta la definizione del problema. Chi la prende sul serio non si chiede piu' "come comprimo il contesto", si chiede "cosa, di questo contesto, e' il task a renderlo tale".

Nota. context-kernel e' un plugin nativo per Claude Code, con un ripiego per Codex. Tutto e' libreria standard di Python, deterministico e offline; la sola cosa che usa il modello e' la verifica di invarianza, che gira in sessione con l'abbonamento e non con una chiave. I numeri vengono da misure ripetibili: pip3 list reale (14.900 -> 995 token), il benchmark di sessanta bug veri (in tutti la fetta tagliata bastava a risolverli), pandas e lodash su stack trace veri, e la telemetria della pipeline su un bug reale del plugin stesso. Centodiciassette test in circa sette secondi. Licenza MIT. I blocchi qui sopra sono estratti, condensati per leggibilita'; il codice integro sta nel repo. Panna, come al solito, non ha letto una riga e sta benissimo.