# 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.