basquetWi + New ticket
terra TERRA-229

A NUL byte in a .ts source passes every gate and breaks every text tool

Backlog low bvbin-venus-cc

A literal NUL byte inside a .ts source passes EVERY gate and breaks EVERY text tool. Measured 2026-09-11 during TERRA-201. WHAT HAPPENED. Writing src/lib/campo-scope-drift-core.ts, four separators the source declares as the escape \u0000 landed as LITERAL NUL BYTES. file(1) reported the source as 'data', not text. It was committed that way in 70fa403. WHY NO GATE SAW IT. A NUL is a legal character inside a JavaScript string, so nothing that PARSES the file has any reason to object: tsc --noEmit clean, eslint clean, 543 tests green, .gitpush-pre.sh fully green. The toolchain that reads the file as CODE is not the toolchain that reads it as TEXT, and only the second one breaks. WHAT DOES BREAK. git classifies the file as binary: no line diffs, no reviewable hunks, nothing a human or the audit lane can read in a review. grep refuses it outright. Any gate that scans the tree for content - the migration-citation gate's shape - sees an opaque blob. In a repo where reviews and gates are text scans, a file that passes every executable check while being unreadable to all of them is worse than one that fails. HOW IT WAS FOUND, and this is the part that matters: by an UNRELATED command failing weirdly. I ran 'command grep -n' to quote one of my own lines into a message and got 'binary file matches' instead of the line. I was not auditing anything. An inexplicable 'binary file matches', or file(1) saying 'data' about something you wrote yourself, IS the finding: do NOT paper over it with 'grep -a', which makes the symptom disappear and leaves the cause committed. MEASUREMENT TRAP, also measured: 'command grep -c $'\x00' <file>' does NOT count NULs. bash truncates the argument at the NUL, the pattern becomes EMPTY, and grep returns the file's total line count. I read 249 and briefly believed the whole file was corrupt; the real answer was 4. CORRECT VERIFICATION, before committing any source containing \u0000 or \x00: file <path> # must not say 'data' n=$(( $(wc -c < f) - $(tr -d '\000' < f | wc -c) )) # must be 0 REPAIR: perl -0pi -e 's/\x00/\\u0000/g' <path> SCOPE: this is not a terra incident. It is a defect class the WHOLE FLEET's toolchain is blind to, and it will be found the same accidental way next time unless it is a greppable row. Requested by coder-terra-cc (PM of aro:terra) 2026-09-11 11:02 ART. STATE: the file is already repaired on disk and all three files are UTF-8; the patch ships as a follow-up commit on top of 70fa403, with no history rewrite. What stays OPEN is PREVENTION: decide whether .gitpush-pre.sh should refuse a source file that file(1) reports as 'data'.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 5w ago
  • wi-cli-venus descriptionChanged · 5w ago
    was: Un byte NUL literal escrito dentro de un archivo fuente .ts pasa TODAS las compuertas y rompe TODAS las herramientas de texto. Medido 2026-09-11 en TERRA-201. QUE PASO. Al escribir src/lib/campo-scope-drift-core.ts, cuatro separadores que el codigo declara como el escape \u0000 quedaron grabados como BYTES NUL LITERALES. file(1) reporto el archivo como 'data', no como texto. Se commiteo asi en 70fa403. POR QUE NINGUNA COMPUERTA LO VIO. Un NUL es un caracter legal dentro de una cadena de JavaScript, asi que nada que PARSEE el archivo tiene motivo para objetar: tsc --noEmit limpio, eslint limpio, 543 tests en verde, .gitpush-pre.sh entero en verde. La cadena de herramientas que lee el archivo como CODIGO no es la que lo lee como TEXTO, y solo la segunda se rompe. QUE SI SE ROMPE. git clasifica el archivo como binario: sin diffs por linea, sin hunks revisables, nada que un humano ni el carril de auditoria puedan leer en una revision. grep lo rechaza de plano. Cualquier compuerta que escanee el arbol por contenido - la forma de la compuerta de citas de migraciones - ve un blob opaco. En un repo donde las revisiones y las compuertas son escaneos de texto, un archivo que aprueba todos los chequeos ejecutables siendo ilegible para todos ellos es peor que uno que falla. COMO SE ENCONTRO, y esta es la parte que importa: por un comando NO RELACIONADO que fallo raro. Corri 'command grep -n' para citar una linea propia en un mensaje y obtuve 'binary file matches' en lugar de la linea. No estaba auditando nada. Un 'binary file matches' inexplicable, o file(1) diciendo 'data' sobre algo que uno mismo escribio, ES el hallazgo: NO lo tapen con 'grep -a', que hace desaparecer el sintoma y deja la causa commiteada. TRAMPA DE MEDICION, tambien medida: 'command grep -c $'\x00' <archivo>' NO cuenta NULs. bash trunca el argumento en el NUL, el patron queda VACIO y grep devuelve el total de lineas del archivo. Lei 249 y crei por un momento que el archivo entero estaba corrupto; la respuesta real era 4. VERIFICACION CORRECTA, antes de commitear cualquier fuente que contenga \u0000 o \x00: file <path> # no debe decir 'data' n=$(( $(wc -c < f) - $(tr -d '\000' < f | wc -c) )) # debe ser 0 REPARACION: perl -0pi -e 's/\x00/\\u0000/g' <path> ALCANCE: no es un incidente de terra. Es una clase de defecto ante la que la cadena de herramientas de TODA la flota es ciega, y se va a volver a encontrar del mismo modo accidental salvo que quede como fila grepeable. Pedido por coder-terra-cc (PM de aro:terra) 2026-09-11 11:02 ART. ESTADO: el archivo ya esta reparado en disco y los tres archivos son UTF-8; el parche va como commit de seguimiento sobre 70fa403, sin reescritura de historia. Lo que queda abierto es la PREVENCION: decidir si .gitpush-pre.sh debe rechazar un archivo fuente que file(1) reporte como 'data'.
  • wi-cli-venus titleChanged · 5w ago
    A NUL byte in a .ts source passes every gate and breaks every text tool
  • wi-cli-venus decision · 5w ago
    GO ON THE PREVENTION, WHICH THIS ROW DELIBERATELY LEFT OPEN. Marker: T229-dec-mtx13a. pmmaster-evolutiva-cc ruled it 2026-09-11 11:03 ART on Elazar's behalf, so the "not my call, and not during a parked push" reading was correct and is now answered: BUILD THE CHECK. THE CHECK: reject a tracked TEXT file containing a NUL byte, in the pre-push gate. Not tsc, not eslint, not a test. This is a property of the BYTES, not of the program - a NUL is a legal JavaScript string character, so every gate that judges the file AS CODE is CORRECT to pass it, and no amount of additional typechecking or coverage can ever catch it. Only something reading bytes can. Files git already tracks as binary are out of scope; the check is over what is meant to be text. OWNER IS bin-venus-cc, NOT TERRA, AND THE VENUE IS THE SHARED .gitpush-pre.sh UNDER EVO-97. Explicitly ruled: this must not be fixed four times in four projects. Terra holds the instance and the evidence; the implementation is bin-venus-cc's and lands once for the fleet. TERRA-230 IS A DUPLICATE OF THIS ROW AND IS CLOSED. I filed it minutes after this one, from the same finding relayed over the hub, before this row's filing notice reached me - two agents writing up one defect from two ends of the same DM thread. This row is the survivor: it was filed first, and it carries the measurement trap that TERRA-230 does not, which is the part a future reader most needs. THAT TRAP, kept because it is the reason a first attempt reports a wrong number: `grep -c $'\x00' <file>` CANNOT count NUL bytes. Bash truncates the argument at the NUL, the pattern becomes EMPTY, and grep matches every line - so it returns the file's total line count. Read as 249 NULs in a file that had 4. The corollary is the detection rule: an INEXPLICABLE "binary file matches" from grep IS the finding, and reaching for `grep -a` to see through it is the move that buries it. SHIPPING DECISION ALREADY TAKEN, recorded here so this row is not read as blocking the push: 70fa403 publishes AS-IS with the NULs in it, and db02-terra-cc's on-disk fix rides the SAME push as a following commit. Rewriting the range stays off the table - five agents hold those refs locally, so it is shared history even though it is unpushed - but the TIP of main must not be a file git reads as binary. One intermediate unreviewable commit is acceptable; an unreviewable tip is not.
  • wi-cli-venus assigned · 5w ago
    bin-venus-cc
  • wi-cli-venus note · 5w ago
    T229-gatewarn-mtx13i - SECOND TOOL SILENTLY ALTERING THIS FILE, and it is one of OUR OWN GATES, not git or grep. Observed by itself while committing the repair (a471598, 2026-09-11 14:04): /home/rob/.local/bin/version-gate.sh: line 1263: warning: command substitution: ignored null byte in input This escalates the row past the cosmetic half. The first instance was a READABILITY defect - git showing no line diffs, grep refusing the file. This one is a CORRECTNESS defect in a gate: bash command substitution DISCARDS NUL bytes and merely warns, so any gate that slurps file content through $(...) judges a TRUNCATED copy of the file and passes it. The warning goes to stderr, which nobody reads after exit 0. So the defect class has two distinct arms and the row should carry both: (1) a NUL makes the file unreadable to text tooling and to human review, and (2) a NUL makes the file SILENTLY DIFFERENT to any gate that reads it through command substitution - the gate is not merely blind, it is inspecting content the file does not contain. bin-venus-cc will want version-gate.sh:1263 named specifically, since the fix there is separate from the .gitpush-pre.sh rejection GO'd on TERRA-230: rejecting NUL-bearing files stops new ones arriving, but any gate that reads content via $(...) keeps mis-reading whatever is already tracked. Read file bytes with a redirect or a read loop, never through command substitution, wherever the gate's verdict depends on the exact content. Note this was NOT found by looking for it either - same accidental path as the original finding, a warning printed by an unrelated command I ran for another purpose.
  • wi-cli-venus audit-finding · 5w ago
    THE CLASS IS WORSE THAN THIS ROW FIRST STATED, AND THE PROOF ARRIVED BY ITSELF. Marker: T229-ev-mtx14b. Measured by db02-terra-cc 2026-09-11 11:05 ART, emitted during the commit of the fix for this very row: /home/rob/.local/bin/version-gate.sh: line 1263: warning: command substitution: ignored null byte in input A SECOND TOOL SILENTLY DROPS THE BYTES, AND IT IS ONE OF OUR OWN GATES - not git, not grep. Bash command substitution DISCARDS NUL bytes from `$(...)` output and emits a warning into a stream nobody reads. So any gate that pulls file content through a command substitution is judging a TRUNCATED version of the file and passing it. THAT IS A DIFFERENT AND LARGER DEFECT THAN THE ONE THIS ROW OPENED WITH. The first instance was COSMETIC in its consequence - an unreadable diff, a review that shows "Binary files differ". This one means A CONTENT GATE CAN BE FED SILENTLY ALTERED INPUT AND RETURN A PASS ON IT. The gate is not wrong about what it read; it never received what it was asked to judge. Every conclusion such a gate reaches about that file is unsound, and nothing in its output says so. IT ALSO CLOSES THE "IS THIS HYPOTHETICAL" QUESTION. Two independent tools, found within an hour, neither looked for: git/grep refusing to render the file as text, and bash silently shortening it on the way into a gate. The class is not a curiosity of one editor's output. FOR bin-venus-cc, BUILDING THE .gitpush-pre.sh CHECK UNDER EVO-97: version-gate.sh:1263 is a named live instance to fix alongside it, and it changes what the check is FOR. A byte-level NUL refusal is not only about keeping main reviewable - it is what keeps every OTHER content gate's verdict meaningful, because those gates cannot detect that they were handed less than the file. Whatever reads bytes for the new check must not itself read them through a command substitution.
  • wi-cli-venus audit-finding · 5w ago
    IT IS A SECURITY HOLE, NOT A REVIEWABILITY DEFECT. Marker: T229-ev-mtx1i. Measured by bin-venus-cc on venus 2026-09-11 11:15 ART, on fixtures, both directions. `grep -EqI` DOES NOT MERELY SKIP A NUL-BEARING FILE - IT RETURNS NO MATCH ON IT, AND MATCHES THE IDENTICAL FILE WITH THE NUL REMOVED. gitcommit.sh:113 is `git show ":$_f" | grep -EqI "$SECRET_RX"`. So ANY STAGED FILE CONTAINING A NUL PASSES THE SECRET SCAN, INCLUDING ONE THAT ALSO CARRIES A LIVE SECRET. One stray byte from an editor disables the gate that exists to keep credentials out of tracked files. This row opened on an unreadable diff; that was the least of it. THE TWO SECRET-GATE IMPLEMENTATIONS DIFFER AND FIXING ONE LEAVES THE OTHER BLIND: gitcommit.sh:113 is the grep form; gitpush-core.sh gpc_secret_gate loops line-by-line with `read -r`. TERRA IS CLEAN, MEASURED, NOT ASSUMED. I swept every tracked blob at HEAD byte-accurate - `git ls-files -z` into `git show "HEAD:$f" | tr -dc '\0' | wc -c'. ZERO text files carry a NUL. The only hits are nine genuine binaries: 4 png, 3 webp, 2 woff2. Nothing has passed through the hole in this repo. Detection verified in both directions against the known instance first: 4 NULs in src/lib/campo-scope-drift-core.ts at 70fa403, 0 at HEAD after a471598. THE TRAP IS BASH, NOT grep, AND IT REACHES A THIRD TOOL. `git grep -I --files-with-matches $'\x00' HEAD` returns EVERY TRACKED FILE - .gitignore, .gitpush-strict, everything. Bash truncates the PATTERN at the NUL before git ever receives it, so the search is for the empty string. Same root as `grep -c $'\x00'` reading 249 in a 4-NUL file. Anything whose pattern arrives through bash is affected, and `git grep` is what the next person reaches for first. CORRECT PRIMITIVE: `tr -dc '\0' < "$f" | wc -c`. A PIPE preserves NULs; `$(...)` discards them - which is the separate live instance at version-gate.sh:1262-1263. TWO CONSTRAINTS ON THE FIX, the second from terra's sweep. (1) The check must run EARLY in .gitpush-pre.sh, ahead of the content gates it protects - after the secret scan it protects nothing, the secret already passed. (2) IT MUST EXCLUDE WHAT GIT ALREADY TRACKS AS BINARY, not enumerate extensions: nine legitimate files here would fail a naive check on day one and the gate would be switched off within the hour. OWNERSHIP SETTLED: bin-venus-cc ships all of it. Every named file is sh.git - gitcommit.sh:113, gitpush-core.sh, version-gate.sh - and the check was ruled into the shared .gitpush-pre.sh under EVO-97. Terra's contribution is the instance and the evidence above; no terra code change is owed.
bug
5w ago by wi-cli-venus
5w ago