Skip to content

Il pavimento dei check diventa un'impostazione, e parte da 3 GB invece di 6 - #89

Merged
zorahrel merged 3 commits into
mainfrom
topics/pavimento-configurabile
Sep 17, 2026
Merged

zorahrel merged 3 commits into
mainfrom
topics/pavimento-configurabile

Conversation

@zorahrel

Copy link
Copy Markdown
Contributor

Cosa

Il freno davanti a un comando di check confrontava la memoria libera con DISPATCH_MEM_FLOOR_NATIVE_GB = 6 GB: una costante, montata una volta per tutto il server. Ora è un'impostazione della macchina sulla riga '*' di board_settings, con default 3 GB, configurabile dal pannello impostazioni accanto alla fetta di macchina. 0 spegne il freno.

Perché 6 era il numero sbagliato

Quei 6 GB sono il pavimento dell'ammissione di un agente (GB_PER_AGENT_NATIVE = 1.5 accanto): il freno dei check se l'era preso in prestito e nessuno l'aveva mai misurato contro un check.

Misurato il 17/09 campionando l'albero di processi ogni 250 ms, un comando alla volta:

comando picco a freddo a caldo
bun run lint 1,91 GB 0,53
bun run typecheck 1,31 GB 0,77
check:deadcode 0,33 GB
static-rails 0,31 GB

Il freddo è il numero che conta: .cache/checks non è tracciata, la worktree di un agente parte sempre senza. Su 1828 letture [memsig] il pavimento a 6 tratteneva l'86,2% del tempo, con la lettura più bassa dell'intero log a 2,7 GB. A 3 GB trattiene l'1,0%.

E la giustificazione scritta in intestazione era falsa: dancerooms-intq6i dichiarerebbe pnpm verify:all --only typecheck,unit, ma in quel repo esistono solo verify e verify:product — esce 254 in 275 ms con 2 MB. Anche il «tsc 460 MB / vite 316 MB» non aveva misura dietro.

Due strade chiuse da una verifica avversaria

Scritte in intestazione perché non si riaprano.

  • Cancellare il pavimento: rigiocando le 1828 letture dentro releaseDecision, fra floorGB: 6 e floorGB: 0 la decisione cambia in 1157 casi (63,3%), tutti a swap=calm, e quegli stati hanno swap usato p50 7,8 GB contro 3,4 dove lascia passare. È l'unico freno vivo dove lo swap tace.
  • Far leggere al freno swap il picco invece dell'ultimo campione: quello che un SIGKILL restituisce è il footprint corrente. Un tsc che ha piccato 1,31 GB e ora sta a 0,4 ridà 0,4 — ucciderlo brucerebbe uno dei due tentativi della consegna per niente.

Forma

MemoryFloor.floorGB è una funzione e non un numero, come held e swap accanto: si rilegge a ogni poll, quindi spostare il campo ha effetto sul giro dopo e non al riavvio. releaseDecision continua a ricevere un numero e resta pura. 0 spegne l'intero ramo memoria, measuring compreso.

Prove

Dieci mutazioni, dieci morte. Una era sopravvissuta — «non ancora letto» dipinto come 0 nella casella — e ha richiesto di estrarre checksFloorBoxValue: lo store è di modulo, quindi quello stato non è osservabile su un componente montato.

Sbarra «Static guard rails» in locale, tutti exit 0: emdash, migrations, identifier-language, comment-language, untraced-tests, spec-coverage, sleeps, test-skips, ui-language, bloat, security. Più typecheck 0, lint 0, deadcode 0, e 191 test verdi sui moduli toccati. L'e2e DROP-07 è scritto ma non eseguito in locale: gli e2e girano sul server di test isolato in CI.

La baseline di bloat è alzata a mano su una riga sola, non con --update-baseline: quel flag rimisura e riordina ogni riga e avrebbe assolto la crescita pregressa di novanta file in un diff da 95 righe.

…mpostazione, e parte da 3

Il freno davanti a un comando di check confrontava la memoria libera con
`DISPATCH_MEM_FLOOR_NATIVE_GB` = 6 GB, costante, montata una volta per tutto il
server. Quei 6 GB sono il pavimento dell'AMMISSIONE di un agente, tarato accanto
a `GB_PER_AGENT_NATIVE = 1.5` su quanto spazio serve per una sessione in piu':
il freno dei check se l'era preso in prestito e nessuno l'aveva mai misurato
contro un check.

Misurato campionando l'albero di processi ogni 250 ms, un comando alla volta:
`lint` a freddo 1,91 GB (il piu' caro della macchina), `typecheck` a freddo 1,31,
`static-rails` 0,31, `check:deadcode` 0,33. Il freddo e' il numero che conta,
`.cache/checks` non e' tracciata e la worktree di un agente parte sempre senza.
Su 1828 letture `[memsig]` il pavimento a 6 tratteneva l'86,2% del tempo, con la
lettura piu' bassa dell'intero log a 2,7 GB: ogni giro pagava fino a 3 minuti di
valvola per una penuria che non e' mai successa. A 3 GB trattiene l'1,0%.

E la ragione scritta per tenere i 6 era falsa: l'intestazione sosteneva che
`dancerooms-intq6i` dichiara `pnpm verify:all --only typecheck,unit`, «l'albero
da 4-11 GB che questo freno esiste per tenere fuori». In quel repo esistono solo
`verify` e `verify:product` — quel comando esce 254 in 275 ms con 2 MB, rosso a
ogni giro da giorni. Anche il «tsc 460 MB / vite 316 MB» non aveva misura dietro.
Un numero difeso da una ragione inventata dopo e' un numero che nessuno corregge
quando il carico cambia: per questo non torna costante, diventa un campo che si
vede, con accanto il carico misurato che lo giustifica.

Due strade sono state chiuse da una verifica avversaria e sono scritte in
intestazione perche' non si riaprano. CANCELLARE il pavimento: rigiocando le 1828
letture dentro `releaseDecision`, fra 6 e 0 la decisione cambia in 1157 casi
(63,3%), tutti a `swap=calm`, e quegli stati hanno swap usato p50 7,8 GB contro
3,4 dove lascia passare — e' l'unico freno vivo dove lo swap tace. Far leggere al
freno swap il PICCO invece dell'ultimo campione: quello che un SIGKILL
restituisce e' il footprint corrente, quindi un tsc che ha piccato 1,31 e ora sta
a 0,4 ridarebbe 0,4, bruciando uno dei due tentativi della consegna per niente.

`MemoryFloor.floorGB` e' una funzione e non un numero, come `held` e `swap`
accanto: il valore si rilegge a ogni poll, cosi' spostare il campo ha effetto sul
giro dopo invece che al riavvio. `releaseDecision` continua a ricevere un numero
e resta pura. `0` spegne l'intero ramo memoria, «measuring» compreso: aspettare
che una finestra si riempia per confrontarla con zero e' aspettare un numero che
nessuno leggera'.

Dieci mutazioni, dieci morte: la guardia dello zero, la cattura del pavimento al
mount, la lettura fallita che diventa 0, il default che torna a 6, lo zero
inghiottito dal default, la colonna assente letta come 0, NULL letto come 0, il
null dipinto come 0 nella casella, la bozza vuota scavalcata, il campo nascosto
in modalita' risorse. Una era sopravvissuta — «non ancora letto» dipinto come 0 —
e ha richiesto di estrarre `checksFloorBoxValue`: lo store e' di modulo, quindi
quello stato non e' osservabile su un componente montato.

Sbarra «Static guard rails» in locale, tutti exit 0: emdash, migrations,
identifier-language, comment-language, untraced-tests, spec-coverage, sleeps,
test-skips, ui-language, bloat, security; piu' typecheck 0, lint 0, deadcode 0.
191 test verdi sui moduli toccati. L'e2e DROP-07 e' scritto ma non eseguito qui:
gli e2e girano sul server di test isolato in CI.

La baseline di bloat e' stata alzata a mano su una riga sola, non con
`--update-baseline`: quel flag rimisura e riordina ogni riga e avrebbe assolto la
crescita pregressa di novanta file in un diff da 95 righe che nessuno leggerebbe.
Dei 137 lines di `dispatch-capacity.ts` solo 27 sono di questa tornata.
…aseline

`dbConImpostazioni` viveva in `dispatch-capacity.test.ts` da prima del cancello
sui nomi, quindi stava nella baseline. Spostandone una copia nel file nuovo
`dispatch-capacity.checks-floor.test.ts` e' diventato un nome NUOVO, e
`check:identifier-language` lo ha rifiutato: `settingsDb`.

E la ragione per cui l'ho visto solo in CI vale piu' del rename. La riga
`static-rails` della board lancia 11 check; il passo «Static guard rails» della
CI ne lancia 18 — in piu' ci sono `check:any`, `check:any-budget`,
`check:ref-callbacks`, `check:nul`, `check:eslint-disable`, `check:typography`,
`check:tmp-canonical`, `check:module-mock-restore`. Avevo eseguito la riga della
board e riportato «sbarra completa, tutti exit 0»: erano le 11, non le 18. Il
resto del job `check` era verde al primo giro, unit e integration compresi.
… e non la riporta

Due difetti nel test, non nel prodotto, letti dallo screenshot della CI e non
indovinati.

IL PRIMO: dopo `page.reload()` l'app ripristina il layout che la finestra aveva,
che dopo le prove prima di questa e' una finestra di progetto con il pannello dei
file accanto alla board. La barra degli strumenti finisce tagliata al bordo
destro e il ⚙ non diventa mai cliccabile: il call log diceva «waiting for
getByTestId('kanban-board').getByTitle('Impostazioni auto-dispatch')» e lo
screenshot mostra il ⚙ a x=1256 su 1280, con il pannello dei file a occupare
meta' schermo. `openBoard` e' idempotente — esce subito se la pane della board
c'e' gia' — quindi ristabilisce la pane invece di fidarsi del ripristino.

IL SECONDO, che non era ancora esploso ma sarebbe esploso: il campo committa sul
blur e NON aspetta la chiamata (`void saveChecksFloor`). Un `reload()` subito dopo
puo' annullare il PATCH in volo, e l'asserzione dopo starebbe misurando una corsa
del test invece del giro attraverso SQLite. `writeFloor` aspetta la risposta del
PATCH e che la casella torni abilitata.

Il resto del job `check` era verde: la sola rossa su entrambi gli shard era
DROP-07.
@zorahrel
zorahrel marked this pull request as ready for review September 17, 2026 18:45
@zorahrel
zorahrel merged commit 3cd999e into main Sep 17, 2026
9 checks passed
@zorahrel
zorahrel deleted the topics/pavimento-configurabile branch September 17, 2026 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant