Il piano che l’esecuzione ha smentito: Predicted vs Observed

I pacchetti si componevano e l’app partiva, ma ogni operazione falliva. Ho tenuto la previsione sbagliata accanto all’osservato, senza riscrivere il piano.

In breve. In un progetto con agenti AI ho scritto che comporre tre pacchetti del framework era «il prerequisito di tutto». Eseguito il primo passo, la premessa era falsa: i pacchetti si compongono e l'app parte, ma ogni operazione fallisce con NOT_FOUND: Module not found: <record>. Invece di riscrivere il piano in silenzio ho aggiunto una sezione Predicted vs Observed accanto alla previsione sbagliata. Vale per questo episodio, non come regola generale.

Il fatto, prima dell'interpretazione

Separo i due piani, perché è il punto dell'articolo.

FACT. La documentazione del piano è stata corretta in accordo-platform PR #81 (solo documentazione, commit aac72a1). La prova eseguibile è in accordo-arvo-pilot PR #46, nel test tests/framework-composition.test.js.

  • Predicted. Comporre customer-data, work e intelligence nel pilota è «il prerequisito di tutto il resto».
  • Observed. Tutti e tre si compongono, l'applicazione parte, dieci operazioni e azioni si registrano. Tutte e dieci rifiutano l'esecuzione con NOT_FOUND: Module not found: <record>.

La causa osservata: ogni pacchetto possiede moduli di record generati da un manifest, letti con modules.get(name). La factory sincrona li registra. La factory asincrona, quella che usano tutti i deployment gestiti, registra solo company, contact, opportunity e approval, e non offre un modo di aggiungere gli altri. Un modulo passato lì viene scartato senza errore.

Cosa è stato escluso

  • Il pin del framework non è la causa. Su origin/main del framework ci sono 38 commit oltre il pin 5d13c4b, con zero righe di diff nei pacchetti coinvolti.
  • Comporli comunque non aiuta. Non darebbe nessun comportamento in più e cambierebbe l'impronta del repository che ogni tenant attesta all'avvio.

Il blocker che non ho provato

C'è un secondo ostacolo, e nelle PR è marcato come letto nel sorgente, non dimostrato. deciding() chiama service.listWhere(filters) e indicizza il risultato in modo sincrono, mentre cloneGraph timbra solo il numero di contratto e non porta nulla in asincrono. Anche con i moduli registrati, quelle letture richiederebbero una porta asincrona.

Non l'ho eseguito perché sta dietro il primo: non si raggiunge empiricamente. Quindi resta un'ipotesi dal sorgente. Se la tratto come fatto, il prossimo piano si regge su un'altra premessa non verificata, che è l'errore da cui sono partito.

INTERPRETATION: perché lasciare l'errore visibile

Questa è una lettura mia, non un dato. Riscrivere il piano in silenzio produce un documento pulito e perde l'informazione più utile: quale ipotesi era sbagliata e come l'abbiamo scoperto. Con la previsione accanto all'osservato, chi arriva dopo (persona o agente) vede il punto esatto in cui il piano ha incontrato il codice.

Il costo è reale: il documento sembra meno sicuro di sé. Per me è un prezzo accettabile, perché ha cambiato il lavoro successivo. La fetta «vista unica del cliente» risulta bloccata nel framework, non rimandata. Il Lead, che appartiene al prodotto, diventa tutta la base e non solo il primo record mancante. Il porting nel framework è descritto in tre pezzi e lasciato come decisione del proprietario, non come silenzio.

Un'altra cosa che non ho nascosto: la CI di quelle PR non era verde. GitHub Actions restituiva startup_failure con zero job nei due repository privati, e lo dichiaro come non verde, senza attribuirlo al diff.

Limite dell'episodio

È un caso: un framework, un pilota, una premessa. Non dimostra che i piani scritti prima dell'esecuzione siano sbagliati, né che i pacchetti modulari si compongano male. Dimostra una cosa più piccola: un piano può essere falso in un punto che si scopre solo eseguendolo, e conviene lasciare quel punto scritto.

Sul modo in cui una factory autonoma tratta i propri fallimenti ho scritto in una fabbrica che ripara software mentre dormiamo; sulla differenza tra problemi veri e rumore, in Backlog Zero; sull'errore come materiale di apprendimento, in Marginal Gains per le macchine.

Domande frequenti

Che cosa significa «Predicted vs Observed» in un piano?

È una sezione che affianca ciò che il piano prevedeva a ciò che l'esecuzione ha mostrato, senza cancellare la previsione. Rende visibile quale ipotesi era sbagliata.

I pacchetti del framework non funzionano?

Non è questa la conclusione. In quel pilota i tre pacchetti si compongono e l'app parte, ma con la factory asincrona i moduli di record generati dal manifest non vengono registrati e le operazioni falliscono con NOT_FOUND. Vale per quel caso e quella configurazione.

Il secondo blocker è dimostrato?

No. È letto nel sorgente e non eseguito, perché sta dietro il primo. Nelle PR è dichiarato così.