Il freno dei check sparava sempre la valvola: era un timer, non un freno - #88
Merged
Merged
Conversation
Il freno davanti a un comando di check confrontava il minimo su 2 minuti con un pavimento di 6 GB che su questa macchina non si raggiunge mai: held2m >= 6 GB zero volte su 1455 letture in 25,7 ore. Cosi' non frenava, scadeva. Misurato sulla card c4f53a85, il primo giro che passa dalle righe CI (16/09 23:41:29Z - 17/09 00:26Z): 1800 s di attesa, cioe' l'intero budget del giro, contro circa 195 s di esecuzione dei quattro comandi locali - 9,2 volte tanto. typecheck rilasciato dopo 372 s, check:deadcode e static-rails solo dalla valvola dei 30 minuti, ed e' per questo che la stessa riga "no room after 30 min" nomina due comandi di fila: spentMs e' per GIRO, il secondo non ha aspettato. Sui 46 campioni [memsig] di quel giro held2m era sotto 6 GB in 43, e 41 di quei 43 leggevano swap=calm. Ora il pavimento e' letto dentro il ramo sostenuto, dove il giro e' trattenuto comunque e i GB dicono quanto e' profondo; a verdetto calmo una lettura sotto il pavimento fa partire il comando. Restano invariati: la valvola per giro, la spaziatura di 120 s fra giri (la mandria del 15/09), il turno, il non partire su una lettura sola e il non aspettare mai dove la memoria non si misura. Conseguenza da dire: su un Mac calmo la finestra di 2 minuti non decide piu' un rilascio, decide solo la riga di log dentro un episodio di swap. I test che provavano il pavimento da solo sono stati riportati sul verdetto sostenuto.
La premessa diceva "[memsig] scriveva swap=calm per tutta la durata". Non e' esatto: 3 campioni su 46 sono sostenuti, e durante l'attesa di check:deadcode la ragione ha alternato 5 volte fra swap e pavimento. La conclusione regge lo stesso - basta un poll calmo sotto il pavimento per rilasciare, e i poll calmi erano 41 dei 43 sotto il pavimento - ma il numero va scritto com'e', non come faceva comodo.
# Conflicts: # openspec/changes/coda-che-riparte-da-sola/tasks.md
La regola che avevo scritto - «a swap calmo il pavimento non trattiene» - non indeboliva il pavimento, lo cancellava: sotto swap sostenuto `releaseDecision` usciva gia' prima di leggerlo, quindi calmo era l'unico stato in cui decidesse qualcosa. Provato su 160 stati, `floorGB` 0 e 1000 davano la stessa decisione in tutti. E il pavimento serve ancora: e' montato una volta per tutto il server, non per board, e `dancerooms-intq6i` ha come unico check locale una suite unit - proprio l'albero da 4-11 GB che il freno esiste per tenere fuori da un Mac vuoto; su topics-app non lo prenderebbe nemmeno `createSwapBrake`, che vuole alberi da 1 GB mentre tsc ne tiene 460 MB. Quindi il pavimento resta com'era e cambia il BUDGET: tre minuti quando a trattenere e' il pavimento su un Mac calmo, i trenta di sempre sotto swap sostenuto. Sotto thrash aspettare compra memoria davvero; a swap calmo la lettura non migliora da sola (`held2m >= 6 GB` zero volte su 1455 letture in 25,7 ore), quindi trenta minuti e tre finiscono uguali tranne che per ventisette. Tre e non meno perche' `swapVerdict` pretende un campione base vecchio 60 s e la porta del soffitto un'altra finestra prima: un thrash che nasce dopo un rilascio resta invisibile per 60-120 s. La valvola corta vale solo sul pavimento: spaziatura e turno si sciolgono da soli entro 120 s e tagliarli rifarebbe la mandria del 15/09. La riga del fail-open ora nomina la condizione letta in quell'istante invece dell'ultima che quel comando aveva stampato: per un comando che non ha aspettato nemmeno un poll quella era nessuna, ed e' il motivo per cui il 17/09 il log diceva «no room after 30 min» due volte su un Mac in swap.
… giro Le due valvole spendevano un contatore solo. Un giro fermo dieci minuti sotto swap sostenuto, con la lettura immobile a 5,2 GB sotto un pavimento di 6, partiva nell'istante in cui il verdetto tornava calmo: i dieci minuti spesi sullo swap avevano gia' coperto la valvola da tre e il pavimento non l'aveva trattenuto per un secondo. Il freno premiava chi aveva appena fatto annaspare la macchina. Adesso ogni budget ha il suo orologio e ogni tratto d'attesa e' addebitato alla condizione in vigore mentre passava, non a quella su cui l'attesa finisce: lo stesso caso parte al tredicesimo minuto. E la riga del fail-open diceva la condizione giusta con la durata sbagliata, perche' stampava il budget del giro al posto dell'attesa: «dopo 3 minuti» per tre comandi che avevano atteso tre, zero e zero. Il log degli errori non ha timestamp, quindi quella riga e' l'unica traccia che resta del giro: ora dice quanto ha atteso QUEL comando e, accanto, quanto il giro aveva speso di quel budget. Tolto `calmMaxWaitMs`, dichiarato seam di test e senza un solo call site. Corretto il numero che reggeva la valvola: «held2m >= 6 GB mai su 1455 letture» e' falso sul log di oggi (241 su 1553, il 15,5%). Quello che regge la valvola e' il tratto continuo sotto il pavimento, 854 campioni, circa quattordici ore.
…tipo `testo.match(EMAIL) ?? []` e' `RegExpMatchArray | never[]`, quindi il parametro del filter diventa `string & never` e `a.toLowerCase()` non compila. Il file arriva da main intatto — nessun ramo lo tocca — ma blocca `bun run typecheck` per chiunque ci rebasi sopra, e la consegna successiva se lo porta in referto come proprio rosso.
# Conflicts: # openspec/changes/coda-che-riparte-da-sola/specs/kanban/spec.md
Su main le due condizioni pescavano dallo stesso `spentMs`, quindi spostare `room` prima di `spacing` dentro `holdReason` cambiava solo la parola scritta nel log. Con un orologio per valvola quell'ordine sceglie quale valvola misura lo stato, e la mutazione passava: 29 pass / 0 fail, suite intera verde. Il comportamento pero' cambiava dove fa male: un giro sotto il pavimento mentre gira il comando di un ALTRO giro passa da `heldBy: "spacing", budgetMs: 1800000` a `heldBy: "room", budgetMs: 180000`, e con la valvola calma gia' spesa - che e' esattamente come ci arriva, dopo aver aspettato il pavimento - parte ATTRAVERSO i 120 secondi di spaziatura. Quella e' la mandria del 15/09, quattro comandi di consegne diverse rilasciati sullo stesso poll, cioe' proprio cio' che la spaziatura esiste per impedire. Nessun test teneva insieme `held < floorGB` e un rilascio altrui in corso; adesso due, uno sulla decisione e uno sul waiter con due giri dove il secondo parte a 300 s invece di 180. E due conseguenze dei due orologi che non avevo dichiarato, scritte nel requisito e fissate da un test invece che annullate. Il tetto di un giro non e' piu' `maxWaitMs` ma la somma delle due valvole, `maxWaitMs + min(3 min, maxWaitMs)`: 33 minuti in produzione, dove il pavimento monta senza un tetto suo. E' il prezzo di non far pagare una condizione all'altra - uno swap che finisce al ventinovesimo minuto lascia un pavimento che non ha trattenuto niente - e il caso peggiore vale tre minuti. Il secondo: il tetto del chiamante puo' solo accorciare la valvola calma, mai allungarla, e non c'e' un seam per alzarla perche' nessun chiamante ne ha chiesto uno. Rimisurate anche le cifre del commento e delle tasks sul log intero (1654 righe `[memsig]`, 16/09 07:27Z - 17/09 12:33Z): 241 letture su 1589 sopra i 6 GB, cioe' 15,2% e non 15,5% di 1553, e il tratto continuo sotto il pavimento e' 854 campioni ma 16,2 ore, non quattordici: la percentuale era contata sulle righe invece che sulle letture, le ore erano i campioni convertiti a uno al minuto. Il file di test passa gli 800 righe di `check:bloat` (867) ed e' registrato in `scripts/bloat-baseline.json` nello stesso commit che lo ha fatto crescere.
…ano niente Avevo scritto nel referto che `typecheck:e2e` falliva su `origin/main` e avevo annotato due espressioni di `tests/unit/no-third-party-emails.test.ts` per sistemarlo. Falso: con il tsc pinnato dal repo e la cache pulita, `tsc -p tsconfig.e2e.json --ignoreDeprecations 5.0` esce 0 sul file originale, e il file e' dentro il program. Le annotazioni erano inerti, quindi tornano via: un diff che dice di riparare qualcosa che non era rotto fa perdere tempo a chi lo legge dopo. Verificato riportando il file a main ed eseguendo il rail (exit 0), poi `bun run typecheck` intero (exit 0).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Change approvata:
openspec/changes/coda-che-riparte-da-sola(KANBAN-15 modificato).Il numero
Misurato sulla prima consegna passata dalle righe CI, leggendo i
msdichecks_json: typecheck 12,7 s, lint 55,3 s, deadcode 4,4 s, static-rails 7,8 s. Ottanta secondi di esecuzione dentro un giro durato trentadue minuti, con[memsig]che scrivevaswap=calmper tutta la durata e la lettura fra 4,8 e 5,9 GB contro una riga a 6. Il giro e' uscito dalla valvola dei trenta minuti, non dalla condizione.Cosa cambia, e cosa NON cambia
Il pavimento resta, a swap calmo come a swap sostenuto. Cambia la valvola: tre minuti quando lo swap e' calmo, i trenta di oggi quando e' sostenuto. Sotto thrash aspettare serve davvero, la macchina sta restituendo memoria; a swap calmo la lettura migliora solo se una persona libera qualcosa a mano, e in un tratto continuo di 16,2 ore non ci e' mai arrivata.
E i due orologi sono separati: il tempo speso ad aspettare lo SWAP non conta contro la valvola del PAVIMENTO. Senza questa separazione un episodio di thrash regalava l'esenzione per tutto il resto del giro — sostenuto per dieci minuti, poi calmo con la memoria immutata, e il comando partiva all'istante.
La riga del fail-open adesso dice la condizione vera e il tempo vero: «no room after 30 min» su un Mac che ha scambiato per mezz'ora era l'unica traccia che sopravvive, ed era falsa in entrambe le meta'.
La prima stesura era sbagliata, e la correzione e' il punto
Avevo scritto «a swap calmo il pavimento non trattiene, a swap sostenuto vale pieno». Una verifica avversaria l'ha smentita eseguendola: sotto swap sostenuto il freno usciva gia' prima di guardare il pavimento, quindi l'unico momento in cui il pavimento aveva forza era proprio lo swap calmo. Quella regola non lo indeboliva, lo cancellava — provato su 160 stati,
floorGBa 0 controfloorGBa 1000 identici in tutti. E serve ancora a qualcuno: e' montato una volta per tutto il server, non per board, edancerooms-intq6iha come unico check locale una suite unit, cioe' l'albero da 4-11 GB che il freno esiste per fermare.Adesso il pavimento e' di nuovo osservabile: 126 stati su 704 differiscono fra
floorGB0 e 1000, tutti a swap calmo.Verifica
Barra intera: 18 rail su 18 a zero, typecheck 0, lint 0. Venti mutazioni oltre a quelle dichiarate; le sopravvissute sono mutanti equivalenti, verificati uno per uno. Una guardia che il giro prima non era coperta — l'ordine
spacingprima diroom, che adesso decide il budget e non piu' solo l'etichetta del log — ora muore sotto la sua mutazione: senza di lei un comando parte attraverso la spaziatura dei 120 s, che e' la mandria del 15/09.