HearAble

Sottotitolazione italiana in diretta · DVB-T2 · tutto in casa

Sottotitoli per il televisore che hai già

HearAble mette i sottotitoli in italiano sulla televisione in diretta, circa un secondo dopo la voce, per uno spettatore che ci sente poco. Gira su un ricevitore terrestre di consumo e su un mini PC senza ventola, collegati da un cavo privato. Niente esce di casa, non c'è niente da sottoscrivere, e il telecomando continua a funzionare.

Un'avvertenza, prima che qualcosa qui somigli a una ricetta

Qui si descrivono due macchine, costruite in modo incrementale nell'arco di settimane. Dove i documenti somigliano a una procedura, è quella storia ricostruita dopo — non è mai stata eseguita da zero su una terza macchina, quindi è probabilmente incompleta. Le lacune non saranno le parti interessanti: saranno le cose fatte a mano una volta e mai scritte, un'opzione del BIOS, un permesso, un file unito a un altro file. Se ne incontri una, apri una issue sul repository: è l'unico modo in cui viene scritta.

Ritardo del sottotitolo
~1,0 s
Fattore di tempo reale
0,4848
Audio sul filo
26 kB/s
Sintonizzatori consumati
0
01

A che cosa serve

Uno spettatore, un televisore, e un buco che la sottotitolazione televisiva non copre.

Le emittenti italiane sottotitolano alcuni programmi e altri no. Il telegiornale in diretta, le finestre regionali, lo sport, i talk show, quasi tutto il pomeriggio: arrivano senza sottotitoli, oppure con sottotitoli così in ritardo da descrivere una frase diversa da quella sullo schermo. Per chi ci sente poco è la differenza fra guardare la televisione e guardare delle persone che muovono la bocca.

HearAble nasce esattamente per quel caso: sottotitolare quello che c'è adesso, in italiano, sul televisore stesso — non su un telefono, non su un tablet appoggiato allo schermo, e senza chiedere allo spettatore di imparare niente oltre a un tasto.

Tre vincoli hanno deciso tutto quello che viene dopo.

By Nunzio Raciti

HearAble · Avvio...

Il saluto, come appare sul televisore. Quattro secondi, poi il primo sottotitolo vero lo sostituisce.

02

La prima domanda: da dove viene l'audio?

Tutto quello che sta a valle è ordinario. Tirare fuori l'audio pulito del programma da un decoder chiuso, senza pagare pegno, è la parte che è stata inventata.

Un riconoscitore ha bisogno dell'audio del programma. Le strade ovvie sono state provate, e ciascuna chiedeva un prezzo che il progetto non poteva pagare.

Sorgenti audio candidate
StradaEsitoPerché
Microfono vicino al televisoreScartataRumore della stanza, e il fischio dell'apparecchio acustico dello spettatore stesso. Daremmo al riconoscitore la versione peggiore di un segnale che dentro il box esiste perfetto.
Estrattore audio HDMIScartataHardware in più in salotto, e l'audio arriva già decodificato e ricodificato — cioè dopo il buffer di uscita del decoder, che è proprio il ritardo che stiamo cercando di non pagare.
Streaming Enigma2 sulla porta 8001ScartataFunziona, e trattiene il sintonizzatore. Cambiando canale verso un altro multiplex il box restava senza servizio. Misurato, non supposto.
Filtro PID sul demux DVBSceltaLeggere il PID audio direttamente dal demux del servizio già sintonizzato. Non costa un sintonizzatore, non ricodifica niente, e arriva prima dell'immagine.

Il tap sul demux

Il ricevitore monta uno stack DVB Hisilicon ed espone l'API DVB standard di Linux. Enigma2 tiene aperti ventiquattro filtri PID su demux0 mentre mostra un canale; quello di HearAble è il venticinquesimo. È solo userspace — nessun modulo kernel, nessuna immagine modificata, niente di persistente.

# tutto il meccanismo, in cinque chiamate
open("/dev/dvb/adapter0/demux0", O_RDWR | O_NONBLOCK)
DMX_SET_BUFFER_SIZE   1 MiB
DMX_SET_PES_FILTER    pid    = <il PID audio scelto dallo spettatore>
                      input  = DMX_IN_FRONTEND
                      output = DMX_OUT_TSDEMUX_TAP
                      flags  = DMX_IMMEDIATE_START
read()                pacchetti MPEG-TS da 188 byte

Le tre modalità di uscita sono state provate sul box vero invece che dedotte dall'header, e la differenza conta: DMX_OUT_TS_TAP si apre senza errori e consegna zero byte — manda al device dvr, non a questo descrittore. DMX_OUT_TAP funziona a 127,3 kbit/s con il primo dato dopo 0,27 s. DMX_OUT_TSDEMUX_TAP funziona a 132,8 kbit/s con il primo dato dopo 0,03 s, e ha vinto su quel numero.

Perché DMX_IN_FRONTEND è tutto il trucco

Il filtro legge il flusso che entra nel box, non quello che il decoder sta presentando. HearAble sta quindi davanti alle orecchie dello spettatore, e ogni millisecondo di quel vantaggio è un millisecondo regalato al riconoscitore. È anche il motivo per cui immagine e sottotitoli non possono separarsi per una ragione nostra: nel percorso dell'immagine non ci siamo proprio.

03

Le scelte che l'hanno formato

Quattro decisioni spiegano quasi tutto l'aspetto del sistema, ognuna con la misura che ha dietro — una scelta di progetto senza un numero è una preferenza.

Il riconoscitore gira sulla CPU, e non c'è nessuna GPU

Nemotron 3.5 ASR Streaming 0.6B, quantizzato q8_0, su NeMo-Speech.cpp. Una GPU è più veloce in pura portata, ma sotto ritmo — alimentata al passo con cui l'audio arriva davvero, che è l'unica modalità che conti per la diretta — il suo vantaggio crolla da 5,7× a 2,2×, perché non può sovrapporre lavoro che non ha ancora ricevuto. Un N95 senza ventola arriva a un fattore di tempo reale di 0,4848 su trenta minuti di televisione vera senza averne una.

Il governor, non il compilatore

Nessuna riga di codice di calcolo è tarata per questa macchina. La velocità viene da una riga di sysfs: il riconoscitore lavora a raffiche di circa 105 ms ogni 160, e intel_pstate in powersave non vede mai una raffica abbastanza lunga da salire di frequenza.

Fattore di tempo reale · più basso è più veloce, 1,0 è il limite
CondizioneRTF
Governor powersave0,6741
Governor performance0,4896
Dieci minuti di televisione vera0,4962
Trenta minuti di torture deliberate0,4848

È il 27,6 % del fattore di tempo reale

Vale più di -march=native e AVX-VNNI messi insieme, di un fattore venti. Se stai tarando un carico di inferenza a raffiche, guarda il governor prima di leggere una riga di assembly.

Il ritardo di pubblicazione è zero

Il tap legge il flusso che entra nel ricevitore, quindi corre 64 ms davanti all'immagine — misurato leggendo due orologi nello stesso istante, AUDIO_GET_PTS contro il PTS del pacchetto che il filtro PID sta consegnando. Non c'è niente da compensare, e infatti non si compensa niente.

La trascrizione è portabile

Gli stessi sorgenti, compilati su un'architettura diversa con un compilatore diverso e kernel SIMD diversi, producono una trascrizione identica bit per bit: le stesse 74 parole, WER 0,00 %. Niente nella catena dipende dalla macchina su cui gira, ed è per questo che l'appliance si è potuta scegliere per consumo e prezzo invece che per compatibilità.

04

Come sta insieme

Due macchine, un cavo privato, due piccoli protocolli che vanno in direzioni opposte.

DECODER · SF8008 DVB-T2 frontend1 demux0 tap sul PID +64 ms pannello due righe relay ffmpeg MINI PC · INTEL N95 decodifica AAC + resample Nemotron 0.6B q8_0 RTF 0,4848 stabilizzatore → due righe 26 kB/s AAC MPEG-TS su TCP subtitle_state WebSocket 10.77.0.0/24 cavo privato · niente router, niente DHCP televisore
L'audio esce dal decoder compresso e non torna mai indietro; rientrano soltanto due righe di testo. Il televisore è alimentato dal decoder esattamente come è sempre stato: HearAble disegna sopra l'immagine e non sta mai nel suo percorso.

La divisione è voluta. Il decoder è un apparecchio chiuso con un kernel 4.4 e non ha spazio per un modello di riconoscimento; il mini PC ha la potenza ma non sa disegnare sul televisore. Ciascuno fa quindi l'unica cosa che può: il box preleva e dipinge, il mini PC ascolta e riconosce.

05

Il lato decoder

Un plugin Enigma2, circa duemila righe, che fa quattro mestieri: preleva, rilancia l'audio, dipinge, e sveglia l'altra macchina.

Hardware
Octagon SF8008 V3 Supreme Combo (Hisilicon), un sintonizzatore DVB-T2/C su frontend1, un DVB-S2X su frontend0
Immagine
openATV 7.5.1, Linux 4.4.35, Enigma2
Plugin
/usr/lib/enigma2/python/Plugins/Extensions/HearAbleOSD, caricato a WHERE_SESSIONSTART
In ascolto su
:8770 — /hearable (WebSocket, sottotitoli in ingresso) e /control (HTTP, controllo del relay)
Stato persistente
/etc/enigma2/hearable_look.json, hearable_sync.json, hearable_wol.json

Disegnare su un televisore

Il pannello è una skin Enigma2 costruita a runtime, e quasi ogni sua riga racchiude un difetto trovato su uno schermo vero.

Il byte alto è la trasparenza

I colori di Enigma2 sono #AARRGGBB dove AA è la trasparenza, non l'opacità. Il bianco scritto #ffffffff è la definizione che la skin dà di «invisibile»: i glifi venivano disegnati trasparenti e prendevano il colore di quello che avevano dietro — verdi sopra la barra verde, blu sopra quella blu. Il bianco è #00ffffff.

La finestra è la banda, non lo schermo

Una finestra a schermo intero e trasparente sembra identica e si comporta in modo diverso: si porta via il telecomando. Il volume continuava a funzionare, perché è gestito globalmente, ma MENU non faceva niente — il televisore sembrava rotto. Ora la finestra è grande esattamente quanto ciò che disegna.

Il pannello è due righe di testo bianco centrato su una banda nera all'85 % di opacità, ciascuna alta circa il 7,5 % dello schermo, attaccate, appoggiate al 7 % dal bordo inferiore per restare dentro l'area sicura a qualsiasi dimensione. Quella geometria viene dalla pratica televisiva, non da quello che ci stava: si legge come un blocco solo dall'altra parte della stanza. La tela dell'OSD è 1280 × 720 anche su un servizio HD, ed è una trappola che va detta: disporre la banda in coordinate 1080p la manda sotto il bordo dello schermo.

Che cosa può cambiare lo spettatore

Configurazione dell'aspetto · /etc/enigma2/hearable_look.json
ChiaveIntervalloIn usoEffetto
font_scale0,8 – 1,61,2Dimensione del carattere, con la scatola dimensionata dopo il testo, così le discendenti non perdono la coda
line_gap0,25 – 1,00,25Distanza fra le due righe. Dimezzata due volte su indicazione dello spettatore
background_opacity0,0 – 1,00,85Opacità della banda. Sotto ~0,8 il bianco sparisce dentro un'immagine chiara
background_enabledbooltrueBanda accesa o spenta del tutto
padding0,0 – 0,50,0Spazio in più dentro ogni riga

Una modifica si applica subito: il dialogo viene distrutto e ricreato, invece di richiedere un riavvio di Enigma2 che farebbe sparire l'immagine.

Il telecomando

Tre tasti, e nient'altro tolto a Enigma2.

CodiceTastoChe cosa fa
62F4HearAble acceso / spento. All'accensione manda anche il magic packet che sveglia il mini PC.
61F3Ritardo di pubblicazione in su, 100 ms per pressione
60F2Ritardo di pubblicazione in giù

HearAble parte spento a ogni avvio. Lo stato non è persistito di proposito: i sottotitoli sono una cosa che si chiede, e un box che torna da un black-out già disegnando sullo schermo è un box che ha deciso al posto dello spettatore.

HearAble 1.5.3

Arrivederci

Allo spegnimento. La versione compare qui perché è l'unico posto dove uno spettatore senza terminale può leggerla.

Il relay: mandare l'audio senza mandare il programma

Un progetto precedente mandava tutto il contenitore — video compreso — e chiedeva alla macchina ricevente di tenere una copia identica bit per bit del file, così da ricostruire la posizione del decoder confrontando un fotogramma preso dal suo schermo. È insostenibile su una macchina piccola, e inutile per la diretta.

Il relay manda invece solo la traccia audio scelta, ancora compressa: 26 kB/s di MPEG-TS prodotti da un processo ffmpeg fuori da Enigma2, così un ricevitore lento o assente non può mai bloccare l'interfaccia.

Svegliare l'altra macchina

Premere F4 manda un magic packet Wake-on-LAN sul link privato — in broadcast su 10.77.0.255, porte 9 e 7, ripetuto fino a quindici volte ogni venti secondi, che dà una finestra di cinque minuti. Tempo di risveglio misurato da spento via software: 32,0 s, tre cicli su tre.

Il Wake-on-LAN era misurato, e non collegato

Per un po' il pacchetto era dimostrato in un banco di prova e il plugin non lo mandava mai. Il primo uso vero se ne è accorto subito. Ora fa parte dell'accensione di HearAble, e anche il contrario è gestito: spegnere il decoder manda un datagramma di commiato, così il mini PC non aspetta la scadenza del suo timer di inattività.

06

Il lato mini PC

Un box N95 senza ventola in cui nessuno entra: si sveglia quando glielo si chiede, riconosce, e si spegne da solo quando il televisore smette di parlare.

Hardware
T9 Plus, Intel N95 — 4 core / 4 thread, 800 MHz – 3,40 GHz, L1d 128 KiB · L2 2 MiB · L3 6 MiB, 15 GiB di RAM
SIMD
sse4_2, avx, avx2, fma, f16c, bmi2, avx_vnni
Sistema
Debian 13 trixie, Linux 6.12.107
Modello
Nemotron 3.5 ASR Streaming 0.6B, q8_0, 741 548 352 byte, sha256 a5c435f2…f429ae
Runtime
NeMo-Speech.cpp a 4f96762, ggml, solo CPU — nella macchina non c'è GPU e non ne serve
Rete
enp1s0 = 10.77.0.2 statico, cavo privato verso il decoder. Wi-Fi solo per la manutenzione

Che cosa l'ha resa davvero veloce

Nessuna riga di codice di calcolo è stata ottimizzata per questa macchina. La velocità è venuta da una riga di sysfs.

Fattore di tempo reale · più basso è più veloce, 1,0 è il limite
CondizioneRTF
Baseline, governor powersave0,6741
Governor performance0,4896
Dieci minuti di televisione vera0,4962
Trenta minuti di torture deliberate0,4848

Il governor vale il 27,6 % del fattore di tempo reale

Il riconoscitore lavora a raffiche — circa 105 ms di calcolo ogni 160 — e intel_pstate in powersave non vede mai una raffica abbastanza lunga da salire di frequenza. Cambiare il governor vale più di -march=native e AVX-VNNI messi insieme, di un fattore venti. L'istruzione AVX-VNNI che la CPU dichiara ridurrebbe a una sola vpdpbusd il prodotto int8 che oggi costa vpmaddubsw + vpmaddwd: resta una leva non tirata, e piccola.

Le quattro unit che ne fanno un apparecchio

systemd
UnitMestiereDa sapere
hearable-governorMette tutti i core su performance all'avvio, e li rimette su powersave allo stopÈ una dipendenza della catena, non un accessorio
hearable-t9La catena di riconoscimentoRestart=always, mai on-failure
hearable-idle-watchdogSpegne la macchina quando nessuno guardaGira come root, indipendente dal riconoscitore
hearable-rgbL'anello di stato sul caseSe manca pyserial lo dice una volta e continua senza

Due dettagli di systemd che sono costati inattività vera

StartLimitIntervalSec sotto [Service] viene ignorato in silenzio: il limite di riavvii semplicemente non esiste. Va in [Unit].

E Restart=on-failure è sbagliato per un apparecchio: uno strumento di misura ha fermato la catena con SIGINT, systemd ha visto il codice di uscita 0, e il servizio è rimasto morto ventitré minuti senza che nessuno se ne accorgesse. Un'uscita pulita è comunque un apparecchio che ha smesso di fare sottotitoli.

Spegnersi da solo

Il watchdog fa due domande e per agire gli servono entrambe le risposte: c'è qualcosa attaccato alla porta audio (letto da /proc/net/tcp sulla porta 9010), e il decoder sta ancora guardando (il suo /api/powerstate, con ripiego sul ping)? Senza sessione audio fa partire un timer — venti minuti di default, tre quando il decoder è andato in standby, entrambi in /etc/default/hearable — e spegne la macchina. Una sessione che torna lo annulla.

La conseguenza pratica è che lo spettatore al mini PC non pensa mai. Compare quando si preme F4 e sparisce qualche minuto dopo che il televisore è tornato silenzioso.

L'anello di stato

Il case ha un anello RGB su un ponte seriale CH340. Il protocollo è una trama da cinque byte — 0xFA, modo, luminosità, velocità, checksum — a 10 000 baud, con luminosità e velocità invertite rispetto a quello che verrebbe da pensare.

La mappa dei colori ha preso 0 su 5

La prima corrispondenza fra stati e colori era stata dedotta dalla documentazione del controller e provata alla cieca con la persona che l'anello lo guarda davvero. Era sbagliata su tutti e cinque gli stati. Quella in uso è la mappa letta dall'hardware dallo spettatore: fa 6 su 6. La documentazione descrive le intenzioni, gli occhi descrivono l'anello.

Sopravvivere alla rete

L'unico difetto vero trovato dalla campagna di torture da mezz'ora era nel ricevitore audio, e solo un cavo staccato fisicamente lo ha fatto emergere: un timeout di socket veniva ingoiato con continue, quindi una connessione morta restava in mano per sempre — diciotto respawn, tre socket semiaperti, 80 kB non letti. Ora il ricevitore rinuncia dopo 15 s di silenzio e imposta SO_KEEPALIVE con 10 s di inattività, 5 s di intervallo e 3 sonde.

06b

Sottotitola anche quello che riproduci dal box

Un film dallo storage del ricevitore passa dalla stessa catena — nessun componente in più, nessun secondo percorso di codice.

La diretta è il caso difficile ed è quello di cui ha parlato tutta questa pagina. Ma il relay è un secondo lettore di quello che il decoder sta riproducendo: il demux per la diretta, il file per un file. In entrambi i casi manda avanti solo la traccia audio scelta, compressa, da un punto più avanti rispetto allo spettatore. Il ricevitore vede source_type: file invece di dvb nella risposta di controllo, e tira dritto.

Riproduzione da file · otto controlli col telecomando
ControlloEsitoRipresa
Primo sottotitolo dopo l'avvioPass36,1 s
PausaPassrelay paused, 0 stantii
RipresaPass1,2 s
Salto avantiPass19,1 s
Salto indietroPass64,9 s
Cambio filmPassepoca 41 → 42
F4 spento e riaccesoPass5,4 s
Cambio traccia audioNon provabileil film ha una traccia sola

FILE_STALE_SUBTITLES: 0 su tutta la corsa: niente di precedente a una pausa, a un salto o a un cambio di file è mai stato dipinto dopo. Una regressione alla v1.2.0 aveva già chiuso lo stesso percorso.

Due cose volutamente diverse

I tasti di sincronia sono rifiutati su una sorgente file. F2 e F3 regolano il ritardo di pubblicazione, che compensa quanto il tap corre davanti all'immagine. Su un file quell'anticipo non esiste, quindi i tasti non fanno niente e lo dicono, invece di applicare in silenzio una correzione priva di significato.

Il primo sottotitolo tarda di più — 36,1 s contro i circa 4 della diretta, perché far partire un film significa il relay che nasce, il flusso che comincia da un confine di contenitore, e il riconoscitore che non ha ancora sentito niente. Una volta avviato si comporta allo stesso modo.

Misurato con il film sullo storage USB del box (/media/hdd). Un NVMe o un disco interno è lo stesso percorso per HearAble — legge quello che Enigma2 sta riproducendo e lo storage non lo tocca mai — ma non è stato misurato e qui non viene affermato.

07

I due protocolli

Piccoli di proposito, separati di proposito, e ciascuno con una regola che decide tutto il resto.

Sottotitoli: hearable-enigma2/1

Un WebSocket persistente che porta un oggetto JSON per frame di testo. Il produttore si connette verso l'esterno, il renderer sta in ascolto. Niente TLS e niente autenticazione: il confine di fiducia è il cavo privato.

MessaggioDirezioneScopo
helloentrambiRuolo, progetto, versione del protocollo
capabilitiesentrambiNumero di righe, lunghezza, supporto agli ACK
subtitle_stateproduttore → rendererLe due righe da mostrare
clear_subtitlesproduttore → rendererPulisci lo schermo adesso
source_changedproduttore → rendererIl canale è cambiato: comincia una nuova epoca
heartbeatproduttore → rendererSegno di vita mentre non si dice niente
render_ackrenderer → produttoreQuesto numero di sequenza è arrivato sullo schermo

Non mandare mai la trascrizione cumulativa. Un subtitle_state porta le due righe da mostrare e nient'altro; il validatore rifiuta esplicitamente una trascrizione progressiva, perché mandarla renderebbe traffico e memoria quadratici nella durata della sessione. E il produttore non aspetta mai. Gli ACK sono osservativi: un renderer lento costa freschezza del sottotitolo, mai contropressione sulla catena di riconoscimento. C'è esattamente uno stato in attesa, e uno più nuovo lo sostituisce.

Audio: hearable-audio-relay/1

Due canali in direzioni opposte, perché un ricevitore lento non possa mai bloccare Enigma2.

ControlMedia
Direzionericevitore → boxbox → ricevitore
TrasportoHTTP GET su :8770TCP, MPEG-TS, porta scelta dal ricevitore
Chi si connetteil ricevitoreil box
Cadenzaogni 500 mscontinua, al ritmo di riproduzione
Dentro Enigma2sì, il pluginno, un ffmpeg separato

La richiesta di controllo è anche l'annuncio e il battito: il ricevitore dice dove vuole l'audio, quanto anticipo vuole, e quanto è risultato avanti rispetto allo spettatore. Questi ultimi due sono numeri diversi e non vanno confusi: uno è una richiesta, l'altro è una misura.

08

Dove va quel secondo

Il sottotitolo arriva circa un secondo dopo la parola pronunciata. Quasi tutto è il riconoscitore che decide, ed è una scelta, non un incidente.

Misurato da capo a fondo: p50 1,072 s fra l'audio consumato e lo stato di sottotitolo emesso (n = 1461, p05 0,893 s). Ricostruito dalle impostazioni in uso:

Bilancio del ritardo
VoceCostoChe cosa compra
chunk_ms: 160~80 ms mediL'audio arriva al riconoscitore a blocchi
rnnt_right_context: 1~160 msIl modello guarda avanti di un blocco prima di decidere
Calcolo ASR74 msNemotron sul processore, p50
Conferme dello stabilizzatore320–480 msUna parola diventa «stabile» solo dopo N passaggi concordi
Trattenuta della coda≤450 msL'ultima parola è trattenuta finché non ne arriva un'altra
Tetto di ridisegno≤166 msSei ridisegni al secondo, così le correzioni non lampeggiano
Ritardo di pubblicazione0 msNiente — ed è proprio quella la correzione

Più di metà di quel secondo è spesa a non mostrare qualcosa che potrebbe essere sbagliato. Lo stabilizzatore aspetta che una parola sia confermata, e la coda non confermata non si mostra affatto. Un sottotitolo più veloce che si riscrive davanti a chi legge è peggio di uno più lento che sta fermo — e per un lettore che dal testo dipende, invece di darci un'occhiata, è molto peggio.

Uno strumento contro un occhio, sciolto

Spostare il sottotitolo di 3 s era nettamente visibile in tre domini di orologio indipendenti — 3018,9 ms sul monotonic, 3008,0 ms sul PTS, +3,31 s su un marcatore ripreso — e completamente invisibile sullo schermo. Il motivo è che il pannello si ridisegna solo ogni 0,55 s e il rumore di arrivo del riconoscitore è largo 3,75 s da p05 a p95: il rumore è più largo dello spostamento. Il verdetto è stato registrato come metodo di misura non valido, e non è stata cambiata una riga per inseguirlo.

09

Che cosa non è finito, e che cosa non è mai stato misurato

Scritto come lacuna invece che omesso in silenzio, perché una misura mancante che sembra un risultato è la cosa più costosa di questo progetto.

VoceStatoDettaglio
Prova sul campoIn corsoIl sistema è in uso quotidiano. Resta un punto aperto, ancora da caratterizzare.
AVX-VNNIDisponibileLa CPU la dichiara e la build non la usa. Attesa piccola, accanto al governor.
Indirizzo predefinito negli strumentiPer sceltaCirca 33 strumenti puntano ancora al vecchio indirizzo del decoder. Non sostituito di proposito: un indirizzo cablato sarebbe di nuovo sbagliato al prossimo cambio.
Riavvio completo all'installazioneOsservatoInstallare il plugin riavvia tutto il box, non il solo Enigma2 come dichiara il comando. Visto, non indagato.

Che cosa invece ha ricevuto risposta

L'avvio a freddo ha trovato un difetto, che è il motivo per cui si fa

Il plugin dichiarava 78 minuti di vita su un decoder acceso da 12. Il box corregge il proprio orologio da parete dopo l'avvio di Enigma2 — 88 minuti di orologio consumati in due minuti reali, misurati direttamente — quindi ogni durata si portava dietro il salto. L'uptime era l'estremità innocua: lo stesso orologio reggeva anche i quattro secondi che il saluto deve restare sullo schermo, e la regola che toglie un sottotitolo vecchio. Ora tutte le durate stanno sull'orologio monotonic, con un test che vieta di misurarne una sul wall clock.

10

Come è stato costruito

Di una persona, con un modello come assistente allo sviluppo, e ogni fase passata da test e misure.

HearAble è di Nunzio Raciti, costruito con Claude (il modello Opus di Anthropic) come assistente allo sviluppo. Lui ha posto l'obiettivo e i vincoli, ha preso ogni decisione di progetto, possiede l'hardware e ha fatto le prove che contavano di più; Claude ha scritto codice, test e strumenti di misura sotto la sua direzione.

La divisione si vede nei risultati. Diversi difetti che contano non li ha trovati un test, ma la persona che usava la cosa vera:

Trovato daChe cosa ha trovato
I tasti del telecomando premutiDue difetti che una matrice automatica da diciannove casi aveva dichiarato verdi
Il cavo staccato fisicamenteUn socket morto che ip link down non riproduceva
La corrente tolta dalla presaChe il Wake-on-LAN ci sopravvive — domanda a cui nessuno spegnimento via software poteva rispondere
L'anello di stato guardato a occhioUna mappa dei colori che faceva 0 su 5 contro la documentazione da cui era stata dedotta
Il televisore ascoltatoChe i sottotitoli erano in ritardo, prima che lo strumento fosse d'accordo

Niente è andato avanti su un'opinione

246 test automatici, tutti eseguibili senza un decoder in stanza: il protocollo sul filo, il renderer lato ricevitore col rifiuto per epoca e sequenza, lo stabilizzatore, le regole di commit, i caricatori di configurazione, la disciplina degli orologi, e la coerenza della versione fra pacchetto e plugin.

Gate costruiti apposta per tutto ciò che richiede hardware vero — il gate LAN, la sessione dal vivo, il ciclo di vita dell'interfaccia, i cicli di avvio, il Wake-on-LAN, il timer di inattività, il lettore di file, una matrice di guasti da diciannove casi. Ognuno produce un verdetto e un blocco leggibile a macchina, non un log da interpretare.

Rapporti di campagna con ogni riga etichettata MEASURED, DERIVED o NOT_MEASURED, così una lacuna non può mai essere letta come un risultato.

Verdetti a cui è permesso dire di no. Due indagini sono state chiuse dai numeri che le hanno chiuse, e un gate che produce troppe poche prove dichiara NON_MISURATO invece di passare sul nulla.

E quando una misura non era d'accordo con lo strumento, ha perso lo strumento

Si credeva che il tap corresse 2,4 s davanti all'immagine, e la catena era stata costruita per compensarlo. Chiedendolo al decoder direttamente — due orologi letti nello stesso istante, pacchetto in mano — sono venuti fuori 64 ms. Sbagliato di un fattore quaranta, e sbagliato nella direzione che peggiorava il prodotto.