Repository navigation
Commit f0b2db3
fix(scripts): let the type-check debt gate declare the heap its tsc needs (#18192)
Fixes #17708
Clause-②: no
No `packages/spec` schema, no declared contract and no authorable key
moves here. The diff changes which heap ceiling ONE root gate hands the
tsc children it spawns, and the reading it produces is identical to the
one CI already takes.
## The defect, re-derived rather than recalled
`pnpm check:type-check-debt` runs `scripts/check-type-check-coverage.mjs
--re-measure` (the filename does not match the task name). Its ceiling
was the MINIMUM of three numbers: the CI-shaped pin
`CI_TSC_HEAP_CEILING_MB = 6144`, this process's own `heap_size_limit`,
and an explicit `NODE_OPTIONS` cap the caller had set.
The last two describe the process running the gate — which walks a
manifest and allocates almost nothing — and not the tsc children, whose
heaviest program held 4,420,706K live on the CI runner. So a lane whose
resource discipline prefixes heavy commands with
`--max-old-space-size=4096` handed 4096 straight through, and the gate
refused, correctly, on every run it has ever made in that lane.
⭐ The two numbers are the SAME number, which is why removing only the
caller arm would have fixed nothing: V8 reports the old space plus ~48
MB of other spaces, so a caller capping this process at 4096 also makes
its `heap_size_limit` read 4144 — and 4144 OOMs exactly as 4096 does.
## Before / after, at the ceiling the callers impose
Both runs on this container (MemTotal 16,461,028 kB, no swap, no cgroup
memory limit), same tree, same warm turbo closure, via
`scripts/pm/os-verify-lock.sh`:
| run | before (ba9b498) | after (e504ea9) |
| --- | --- | --- |
| `NODE_OPTIONS=--max-old-space-size=4096 pnpm check:type-check-debt` |
**exit 3** — `FATAL ERROR: Ineffective mark-compacts near heap limit`,
103s burned | **exit 0** — 5 ledger entr(ies) re-measured in 72.6s, 55
raw tsc error(s) total, none above its recorded number |
| `pnpm check:type-check-debt` (no caller cap) | exit 0 — 5 entr(ies),
55 raw tsc error(s), 73.8s | unchanged |
The **control that makes the pair discriminate** is the second row: the
card's own "exit 0 at 8192" reading was never a run at 8192. The roomier
cap was already refused by the pin, so that run measured at 6144 — the
same ceiling the repaired run now uses under a 4096 caller cap. Before
and after therefore produce the SAME ledger reading (5 entries, 55
errors); what changed is only whether the lane can obtain it.
The gate's own heap line says so now:
```
heap: tsc runs under --max-old-space-size=6144 MB -- the CI-shaped ceiling pinned by
scripts/check-type-check-coverage.mjs; this process's own limit is 4144 MB and this box can bear
15051 MB. ... Your NODE_OPTIONS caps THIS process at 4096 MB; tsc is handed 6144 MB anyway,
because that cap describes this process and not the ~4.4 GB program the ledger measures (#17708).
```
## What the repair is — and why it measures nothing less
The minimum is now over TWO numbers:
1. `CI_TSC_HEAP_CEILING_MB` — unchanged at 6144, still the top of the
minimum, still refusing every roomier caller cap. ⛔ A local run is still
never roomier than CI.
2. What this BOX can bear — `os.totalmem()` and the cgroup limit (v1 and
v2, both "no limit" sentinels handled), less a 1 GB reserve. That is
where the "⛔ never promise V8 memory the machine does not have / exit
137 carries no diagnostic" lesson actually lives, and unlike
`heap_size_limit` no caller overwrites it by exporting an environment
variable. Inside a container `totalmem()` reports the HOST, so the
cgroup read is the half that sees the threshold the kernel kills at.
The caller's `NODE_OPTIONS` cap is now **reported and never obeyed, in
either direction**.
The argument that this is not a weakening, stated as the file now states
it: a tighter-than-CI ceiling **cannot change a number** — the ledger
counts tsc diagnostics, and heap does not change what tsc reports, only
whether tsc lives to report it — so it **can only ever refuse**. It had
no upside to weigh against the exit 3 it causes. Every ledger entry is
still counted, `--re-measure`'s OOM at the real 6144 (the type graph
outgrowing the memory CI has) still lands, and nothing was narrowed,
dropped or converted into an exit 3 to make it fit.
1 parent 14f274c commit f0b2db3
1 file changed
Lines changed: 349 additions & 52 deletions
0 commit comments