diff --git a/docs/specs/2026-09-14-visione-stato-e-specifica.md b/docs/specs/2026-09-14-visione-stato-e-specifica.md new file mode 100644 index 0000000..bbb3715 --- /dev/null +++ b/docs/specs/2026-09-14-visione-stato-e-specifica.md @@ -0,0 +1,289 @@ +# La visione in TieMeasureFlow — stato verificato e specifica del lavoro che manca + +> Progetto: TieMeasureFlow, ramo **`V3.0.0`** (HEAD `39a6f62`, 17/08/2026) +> Data: 14 settembre 2026 +> Stato: specifica da approvare +> Sostituisce, come documento operativo: il piano `docs/superpowers/plans/2026-08-16-vision-fondamenta-server.md` +> (eseguito) e la corsia `A1-tiemeasureflow.md` del piano ferie (eseguita, cancellata dal disco il 01/09 e +> recuperabile con `git show 874a7a4^:docs/plans/corsie-fase2/A1-tiemeasureflow.md` nel repo AI-OS). +> **Resta in vigore** `docs/superpowers/specs/2026-08-16-visionsuite-integration-design.md`: le sue otto +> decisioni architetturali non vengono riscritte qui, vengono richiamate. + +## 1. Perché questo documento + +Fra il 16 e il 17 agosto sono entrate in TieMeasureFlow le fondamenta della visione: ventiquattro commit, +sette file di test nuovi, tre migrazioni. Da allora il lavoro si è fermato. Nel frattempo VisionSuite è +andato avanti di sessantasette commit, la scheda di commessa non registra nulla dopo il 25 agosto, e +l'installazione a Tràfilo, prevista per settembre, è alle porte insieme alla fiera del 27-29 ottobre. + +Questo documento fa due cose. Prima dichiara, verificandolo sul codice e non sui piani, **che cosa esiste +davvero** sul ramo `V3.0.0`. Poi specifica **che cosa manca** per arrivare a ciò che il cliente ha chiesto +il 27 luglio: pattern matching, confronto del profilo con il disegno DXF e due o tre quote lineari, dentro +l'interfaccia di TieMeasureFlow, con l'esito OK/warning/fail che il prodotto già sa dare. + +La distanza fra le due cose è più grande di quanto i documenti di agosto lascino credere, e la ragione è +una sola, spiegata al capitolo 3. + +## 2. Quello che esiste, verificato sul ramo V3.0.0 + +Ogni riga di questa tabella è stata controllata aprendo il file indicato nel clone del ramo `V3.0.0` il +14/09/2026. Non è lo stato dichiarato da un piano: è lo stato del disco. + +| Cosa | Stato | Dove si vede | +|---|---|---| +| VisionSuite come sottomodulo git, su commit fisso | ✅ | `.gitmodules`, pin `f095fcc` (15/08) | +| Runner unico, senza HTTP né database | ✅ | `src/vision/runner.py`, 129 righe | +| Versione del motore timbrata su ogni numero prodotto | ✅ | `runner.engine_version()`, errore se non risolve | +| Vision worker come servizio separato nel compose | ✅ | `src/vision_worker/main.py`, `Dockerfile.vision`, servizio `vision` | +| Il server non importa mai VisionSuite | ✅ e **sorvegliato** | `src/backend/tests/test_vision_boundary.py` | +| Grafo di visione sul task (`vision_json`) | ✅ | migrazione `011`, `models/orm/task.py` | +| Legame quota del grafo → quota della ricetta (`vision_output`) | ✅ | migrazione `011`, `recipe_subtasks` | +| `camera` fra i metodi di ingresso misura | ✅ | migrazione `011`, enum `input_method` | +| Tabella `vision_results`, una riga per acquisizione | ✅ | migrazione `012`, `models/orm/vision.py` | +| Immagini di riferimento con provenienza | ✅ | migrazione `013`, `vision_reference_images` | +| Il verdetto lo dà TieMeasureFlow, non il grafo | ✅ | `vision_service` chiama `measurement_service` | +| Gate del fuori tolleranza valutato per acquisizione | ✅ | `enforce_tolerance_gate=False` più gate a monte | +| Copy-on-write delle ricette che copia anche il grafo | ✅ | `test_vision_copy_on_write.py` | +| Il refuso `xf_compare` corretto in `dxf_compare` | ✅ | migrazione `011`, prima che una riga lo usasse | +| Limiti di tipo e dimensione sugli endpoint di upload | ✅ | `test_vision_upload_limits.py` | +| Il guasto del worker resta del worker | ✅ | `vision_service._call_worker`, 502/504 nominati | +| L'applicazione parte senza internet | ✅ | `static/vendor/`, `test_offline.py` | +| API `POST /api/vision/execute`, `/preview`, `/reference-images` | ✅ | `api/routers/vision.py` | + +Trentanove test di visione fra `src/backend/tests/test_vision_*.py`, `src/vision/tests/` e +`src/vision_worker/tests/`. ⚠️ **Non li ho eseguiti**: l'albero della visione richiede Python 3.13 e il +sottomodulo inizializzato, cioè un'installazione da alcuni gigabyte che su questa macchina non c'è. Il +conteggio è dei file; la loro verdezza è dichiarata dai commit del 16-17 agosto e va riverificata da chi +riprende, prima di scriverci sopra. + +**In sintesi: le fondamenta ci sono e sono fatte bene.** Il confine architetturale è difeso da un test +invece che da una buona intenzione, la provenienza di ogni numero è tracciata, e il modello dati regge il +resto del lavoro senza ristrutturazioni. + +## 3. Il buco strutturale: pattern matching e DXF compare non sono eseguibili dal grafo + +È il punto che i documenti di agosto non dicono, ed è quello che decide il calendario. + +Il runner esegue **un grafo `vs-task`**: `Task.from_dict(graph)`, poi `task.run(context)`. Gli strumenti +che un grafo può contenere sono quelli registrati in `vs-task`, e al 14/09 — sia sul commit fissato +`f095fcc`, sia sull'ultimo commit di VisionSuite — sono **dieci, tutti geometrici**: + +`DetectLine`, `DetectCircle`, `CircleCenter`, `PointIntersectionLL`, `Distance2P`, `DistancePL`, +`DistanceCL`, `Angle2L`, `Radius`, `Diameter`. + +Nessuno strumento di pattern matching. Nessuno strumento di confronto DXF. Una ricerca di `pm2d`, +`shape_model` o `dxf` dentro `packages/vs-task/src` non trova nulla. + +Coerentemente, in `pyproject.toml` gli extra `vision` e `vision-worker` installano `visionsuite` (core), +`vs-task`, `vs-measure`, `vs-pm2d` e `numpy`: **`vs-dxf` non è installato affatto**, e `vs-pm2d` è +installato ma il grafo non ha modo di chiamarlo. + +I due motori esistono, e sono buoni: `visionsuite.pm2d` ha il matcher e l'auto-tune, `visionsuite.dxf` ha +`DXFCompare`, l'`ICPAligner`, il ricampionamento, il controllo di tolleranza e il generatore di rapporto. +Ma sono **librerie**, non strumenti di grafo. Fra loro e TieMeasureFlow manca un ponte, e il ponte va +costruito **in VisionSuite**, non qui: la decisione 4 della spec di agosto — il server non importa mai +VisionSuite — e il criterio di accettazione della corsia A1 — *«`grep` non trova algoritmi di visione dentro +il repo di TieMeasureFlow»* — rendono illegittima qualunque scorciatoia che scriva visione dentro questo +repository. + +🔑 **La conseguenza commerciale, detta chiara:** oggi TieMeasureFlow sa eseguire un grafo che misura +distanze, angoli, raggi e diametri su un'immagine. Le due cose che Menoncin ha chiesto per nome — il +confronto DXF, che il suo cliente finale non ha, e il pattern matching, che il loro «funziona male» — non +sono ancora raggiungibili da nessun percorso del prodotto. + +## 4. Le altre lacune, in ordine di peso + +1. **Nessuna interfaccia.** Nel frontend Flask la visione compare in due sole righe di + `templates/measure/task_list.html`, le etichette «Confronto profilo» e «Misura camera». Non esiste la + schermata del Maker per comporre un grafo, scegliere un'immagine di riferimento, agganciare un'uscita a + una quota o premere «prova»; non esiste la schermata dell'operatore che acquisisce e vede l'esito. Oggi + un grafo entra solo via `POST /api/tasks` scrivendo il JSON a mano. +2. **Nessun agente di stazione, nessun registro dei device.** La tabella `station_devices` della spec non + esiste in nessuna migrazione; il WebSocket `/api/stations/agent` non esiste; `vs-camera`, cioè il + pacchetto che contiene il driver Itala, non è montato. L'unico modo di far entrare un'immagine è un + upload HTTP. +3. **L'immagine di produzione non viene conservata.** `vision_results.image_path` e `overlay_path` + migrano e restano vuote: nessuna riga le scrive. Una misura contestata non ha prova materiale, e + l'overlay — l'immagine con sopra le zone dove il sistema ha guardato — non esiste. +4. **La prova di non regressione è promessa e non mantenuta.** `expected_json` esiste sulla tabella delle + immagini di riferimento; nessun percorso la scrive, `preview` compreso. È la rete di sicurezza che + rende sostenibile aggiornare il sottomodulo con il motore installato su due host: senza, ogni + aggiornamento di VisionSuite è un salto al buio. +5. **Il sottomodulo è indietro di 67 commit**, dal 15/08 al 10/09. Fra questi c'è almeno una correzione di + `vs-core` sulla ricomposizione dei mosaici. Aggiornare il pin non è manutenzione facoltativa: è la + decisione 2 della spec, che vuole server e stazione sullo stesso commit, e va fatta con la prova di non + regressione già in piedi — cioè dopo il punto 4, non prima. +6. **Le tre verifiche a monte non sono mai state fatte**, e la spec di agosto le poneva come condizione + d'ingresso: lo stato reale di VisionSuite rispetto al suo README, il test di calibrazione dato per + rosso (focale recuperata a 373 contro 456 attesi, tolleranza 5%) e il peso effettivo del sottoinsieme + di pacchetti che il worker installa. La seconda pesa più delle altre: **tutte le quote in millimetri + poggiano sulla calibrazione**, e finché quel test non è verde o spiegato, i millimetri che il sistema + produce non hanno garanzia. + +## 5. Che cosa si vuole ottenere + +Un operatore apre un task di visione su una postazione, appoggia il profilato sul piano, e il sistema: + +- riconosce il pezzo e la sua posa (**pattern matching**); +- ne confronta il profilo con il **DXF di riferimento**, dichiarando lo scarto massimo e dove sta; +- ne ricava **due o tre quote lineari** (le quote massima e minima che il cliente chiede); +- applica le tolleranze della ricetta e dà **OK / warning / fail**, con il gate del fuori tolleranza e + l'autorizzazione del capoturno come per qualunque altra misura; +- registra tutto in `measurements` e `vision_results`, con immagine, overlay, versione del motore e + taratura in vigore. + +Nulla di quanto il prodotto già fa — ricette, SPC, Cp/Cpk, carta di controllo, export, tracciabilità — +deve cambiare. Una quota da camera resta una misura come le altre: è la decisione 7, e va tenuta. + +## 6. Il lavoro, in sei fasi + +Le fasi sono ordinate per dipendenza. Le prime due sono il cammino critico verso la fiera; la terza è il +cammino critico verso l'installazione a Tràfilo. Non sono stimate in ore: una stima si scrive dopo aver +guardato il codice dei due motori, e quella lettura fa parte della fase V0. + +### V0 — Le verifiche a monte, prima di scrivere righe + +Le tre della spec di agosto (capitolo 4, punto 6), più una quarta che nasce da questo documento: leggere +`visionsuite.pm2d.matcher` e `visionsuite.dxf.compare` per sapere **che forma hanno gli ingressi e le +uscite** dei due motori, perché è quella forma che decide la firma degli strumenti della fase V1. + +*Fatto quando:* il test di calibrazione è verde o il suo scarto è spiegato per iscritto; il peso +dell'ambiente del worker è un numero misurato; esiste una nota di due pagine con le firme reali dei due +motori. + +### V1 — Il ponte: pattern matching e DXF compare diventano strumenti del grafo + +**Si lavora in VisionSuite, non in TieMeasureFlow.** In `vs-task` nascono gli strumenti nuovi, con la +stessa forma dei dieci esistenti: + +- `MatchPattern` — ingresso: immagine più modello; uscite: presenza, punteggio, posizione e rotazione + dell'istanza trovata. È anche ciò che fornisce la posa alle quote successive, invece di pretendere che + il pezzo sia appoggiato sempre uguale. +- `CompareDXF` — ingressi: immagine, disegno di riferimento, fattore di scala; uscite: scarto massimo, + scarto medio, numero di zone fuori tolleranza, e l'esito zona per zona. + +Due vincoli che decidono se il ponte è fatto bene: + +1. **Gli strumenti espongono numeri, non verdetti.** `vs-dxf` ha di suo un `ToleranceChecker` e un + `CompareResult` con il proprio giudizio: quel giudizio va ignorato, esattamente come la decisione 7 + impone già per le quote di `vs-measure`. Due giudici sullo stesso valore è il modo più rapido per + ottenere un CSV che si contraddice. +2. **`vs-dxf` si porta dietro PyTorch (~2,5 GB) per una riga** (`config.py:53`, annotato nella scheda + VisionSuite). Prima di aggiungerlo agli extra del worker, quella riga va tolta: altrimenti il container + della visione triplica, e con lui i tempi di ogni deploy a Tràfilo. + +In TieMeasureFlow cambia **soltanto** `pyproject.toml`: `vs-dxf` entra negli extra `vision` e +`vision-worker`, il pin del sottomodulo avanza al commit che contiene i due strumenti nuovi. Nessuna riga +di algoritmo entra in questo repository. + +*Fatto quando:* un grafo JSON che contiene `MatchPattern` e `CompareDXF` viene eseguito da +`POST /api/vision/preview` su un'immagine caricata, e restituisce le uscite attese. Senza camera, senza +interfaccia. E `test_vision_boundary.py` continua a passare. + +### V2 — L'authoring nel Maker + +La schermata che oggi non esiste. Il Maker, alla scrivania: + +- carica o sceglie un'**immagine di riferimento** per il task (l'API esiste già); +- compone il grafo — e qui va deciso *come*, vedi il capitolo 7, decisione A; +- preme **prova** e vede le uscite (`/preview` esiste già); +- **aggancia** ciascuna uscita a una quota della ricetta, scrivendo `vision_output` sulla subtask (il + campo esiste già), e su quella quota mette nominale e tolleranze come su qualunque altra; +- **promuove le uscite della prova a `expected_json`**, che è ciò che accende la prova di non regressione + (lacuna 4) e chiude una promessa che la spec di agosto ha fatto e non ha mantenuto. + +*Fatto quando:* una ricetta con un task di visione si compone interamente dall'interfaccia, senza scrivere +JSON a mano, e rieseguendo l'intero parco ricette su immagini di riferimento si vede quali quote si sono +mosse. + +### V3 — L'agente di stazione, i device, la camera + +È il cammino critico per Tràfilo, perché è ciò che rende il sistema utilizzabile in reparto. + +- Tabella `station_devices` e migrazione, così com'è descritta nella spec di agosto (specchio in sola + lettura, popolato dall'agente; un device che non si dichiara più è **offline**, non cancellato). +- WebSocket `/api/stations/agent`: **è l'agente che apre la connessione**, il server non bussa mai a un PC + di reparto. È la scelta che evita di aprire porte in fabbrica. +- L'agente: sottile, monta `vs-core` e `vs-camera` e basta; acquisisce e carica il fotogramma. Camera + **Itala** di Opto Engineering, il cui producer GenTL è già stato provato in VisionSuite e ha richiesto + mezz'ora invece delle sei-dieci ore stimate. +- `vision_results.image_path` e `overlay_path` finalmente scritte (lacuna 3), con l'overlay prodotto dal + worker. + +*Fatto quando:* un operatore misura un pezzo da una postazione vera, e la riga in `vision_results` porta +immagine, overlay, device, taratura e versione del motore. + +### V4 — L'esecuzione sulla stazione + +La policy per stazione, il ripiego in locale quando il server non risponde, e il **rifiuto di misurare** +quando la versione del motore non concorda con quella del server. Quest'ultimo non è un dettaglio di +build: è la garanzia metrologica su cui poggia tutto il resto. + +*Fatto quando:* una stazione con un pin discorde si rifiuta di misurare e lo dichiara, invece di produrre +numeri plausibili. + +### V5 — Il task `dxf_compare` come tipo a sé + +Il valore `dxf_compare` esiste già nell'enum. Qui prende il suo comportamento: quote sintetiche derivate +dal confronto (scarto massimo, numero di zone fuori tolleranza) trattate come misure normali, e il +**rapporto allegato** che `visionsuite.dxf.report` sa già generare, archiviato accanto all'immagine. + +## 7. Le decisioni che restano da prendere + +Nessuna di queste si può dedurre dal codice: vanno chiuse da Adriano, alcune con il cliente. + +**A. Come si compone un grafo.** L'editor visuale a nodi (TieWorkflow) è stato **revocato il 09/08** con +una motivazione che vale ancora: un editor ha senso solo se a comporre le pipeline è qualcuno che non +programma, e il cliente aveva chiesto misure, non un editor. Ma qualcosa deve pur esserci, perché scrivere +JSON a mano non è un prodotto. Le tre strade: un modulo per tipo di task con i soli parametri in chiaro +(il minimo che funziona); una libreria di grafi preconfezionati che il Maker sceglie e tara; l'editor, +che è la strada cara. **Questa decisione decide la fase V2 per intero.** + +**B. La scala: pixel o millimetri.** Il 09/08 si era deciso che le quote potessero restare **in pixel**, e +che per il DXF compare servisse un fattore di scala ricavato da una quota nota misurata col calibro. Va +confermato: sono due prodotti diversi da spiegare al cliente, e il secondo dipende dal test di +calibrazione della fase V0. + +**C. Il dimensionamento del server di Tràfilo.** Con l'esecuzione lato server come default, il pattern +matching contende la CPU fra tutte le stazioni. La domanda alla D-4 non è più solo quale macchina e quanto +disco: è anche quanti core e quanta RAM. Venti postazioni non sono tre. + +**D. La conservazione delle immagini.** Quelle di riferimento sono poche e vivono quanto la ricetta; +quelle di produzione sono una per pezzo e crescono senza limite. Serve una scadenza, o una regola del tipo +«si conservano solo quelle dei pezzi fuori tolleranza». Senza, il disco del cliente si riempie e nessuno +lo ha avvertito. + +**E. Che cosa fa la stazione se la rete cade** e non è configurata per elaborare in locale: si blocca, o +consente il calibro segnando il task come non eseguibile? È una domanda per Tràfilo. + +**F. Chi paga.** L'ampliamento nasce dentro una commessa venduta come setup più canone. Un modulo di +visione non sta in quel perimetro, e non c'è offerta. La domanda è aperta dal 06/08 e ogni fase di questo +documento la rende più costosa da rimandare. + +## 8. Quello che non va fatto + +- **Non scrivere algoritmi di visione in questo repository.** Il confine è sorvegliato da un test; se + domani il server importasse VisionSuite per una scorciatoia, il vantaggio si perderebbe in silenzio. +- **Non rifare l'interfaccia** oltre le schermate nuove che le fasi V2 e V3 richiedono. +- **Non toccare SPC, ricette e integrazione GAIA.** GAIA è il gestionale del cliente finale e non è in + questo perimetro. +- **Non aggiungere il modulo AI** di cui si è parlato in call: è perimetro nuovo, senza offerta. +- **Non far giudicare il grafo.** I verdetti di `vs-dxf` e di `vs-measure` restano inutilizzati: decide + `measurement_service`. +- **Non avanzare il pin del sottomodulo senza la prova di non regressione in piedi.** Con il motore + installato su due host, un aggiornamento non verificato sposta i numeri senza che nessuno se ne accorga + fino alla contestazione. + +## 9. Il calendario, per capire le priorità + +La catena è **Tielogic produce → Ricerca e Misure (Menoncin) rivende → Tràfilo usa**, venti postazioni. +Due scadenze esterne, entrambe vicine: + +- **Installazione a Tràfilo**, attesa per settembre. La serve la fase V3, ed è la ragione per cui l'agente + di stazione non può aspettare la fiera. +- **Fiera del 27-29 ottobre**, banchetto Tielogic nella zona Opto Engineering. La serve la fase V1, perché + è lì che si mostrano il confronto DXF e il pattern matching, cioè le due cose che a Menoncin interessano + commercialmente. + +Se le due si contendono le stesse ore, la V1 è quella che non ha alternative: un'installazione può +slittare di due settimane, una fiera no.