Skip to content

finding(tooling): the qa/http-conformance TEST_DEBT re-measure already needs ~4.4 GB of tsc heap on main — it passes the 4096 MB ceiling only through GC pressure, so any spec declaration growth tips Type Check · debt ledger to OOM #14569

Closed

Description

@hotlong

Found while driving PR #14513 (#14439) to green. Filed for the maintainer because the ceiling is a pinned policy (CI_TSC_HEAP_CEILING_MB = 4096, #12856) and changing what the program checks changes what the ledger measures.

Measured

scripts/check-type-check-coverage.mjs --re-measure builds one tsc --noEmit program per ledger entry under --max-old-space-size=4096. For the packages/qa/http-conformance TEST_DEBT entry (8 source files, 5 of them tests, but importing @objectstack/core, @objectstack/objectql, @objectstack/runtime, @objectstack/plugin-hono-server, @objectstack/driver-sqlite-wasm, @objectstack/spec), the same program shape run with an 8 GB cap and --extendedDiagnostics:

main @ 53d36892 (base worktree, closure built)
Files 906
Lines of Definitions 691,580
Types 1,801,110
Instantiations 7,342,314
Memory used (tsc's own count) 4,473,321 K
Check time 68.9 s

Under the 4096 MB ceiling the program still completes on main (merge-queue Lint & Type Check runs are green through 53d36892 and later), but only because V8 collects harder near the limit: a local run on a main-based worktree peaked at 3,961 MB RSS and spent minutes in GC before finishing. The headroom is therefore a few percent, not a margin.

PR #14513 showed what that means in practice: a spec change that added 42,622 lines of definitions to this program (the whole ObjectStackDefinitionSchema declaration, pulled in through a new chunk edge — fixed in the PR) moved the count to 4,875,249 K and the lane went red twice. The next spec PR that grows the declaration graph seen by @objectstack/spec/system will hit the same wall without having done anything wrong.

Options

Option Cost Note
A Raise CI_TSC_HEAP_CEILING_MB to 6144 for the re-measure Policy change; the file's own comment says 4096 is pinned to the CI runner's measured old-space and "if 4096 is wrong, it is wrong DOWNWARD" — ubuntu-latest has 7 GB, so 6144 needs a measurement of what else runs in that job Restores headroom without changing what is measured
B Shrink the program: skipLibCheck: true in the re-measure project only Changes the measurement semantics of every TEST_DEBT number (declaration files stop being checked); the frozen numbers would need a wholesale re-measure Large heap win (declaration files dominate: 691k lines of definitions vs 17k of TypeScript)
C Shrink the program's inputs: have http-conformance type its tests against narrower entries (it imports whole packages for a handful of names) Per-package edit; recurs for the next heavy entry Local, no policy change
D Leave as is; treat each OOM as the offending PR's to fix Every spec PR pays a debugging cycle for a ceiling it did not set What happened on #14513

Not decided here. The four-axis reading favours A with a measured number (long-term consistency: the ceiling exists to make numbers portable, and a ceiling with 3% headroom makes them fragile instead; scope: one constant, one measurement of the runner). B is the only option that changes ledger semantics and should not ride a spec PR.

Activity

  1. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Triage — sweep repair, two rounds overdue. Added the missing domain:devx and priority:p2; tooling and needs-user-decision kept as filed. Applied and read back first.

    ⛔ This is a lane repair only. I am not grading the decision itself — the card asks whether to raise a ceiling, restructure the ledger, or something else, and a heap ceiling on a required gate is spend-shaped and gate-shaped at once. That stays the maintainer's.

    Routing

    domain:devx. The surfaces are the Type Check · debt ledger job and the TEST_DEBT ledger it runs — scripts/check-type-check-coverage.mjs is one of three scripts/ files carrying TEST_DEBT at origin/main 75adf11, and the ceiling itself is job configuration. Root scripts/ gates whose subject is code quality are devx by the lane table; the governed-face carve-out to domain:skills does not apply, since the subject here is type-check debt rather than the governed surface.

    Why p2 and not lower

    The card's own number is the argument: ~4.4 GB measured against a 4096 MB ceiling, passing today only through GC pressure. That is not a margin, it is an absence of one — the gate is already over its declared budget and is being carried by the collector.

    ⚠️ And the failure mode is the bad kind: a gate that OOMs does not report "the ledger is wrong", it reports a crashed job, which reads as infrastructure rather than as a finding. On a required check that means a red nobody can act on, on every PR, until someone recognises it.

    p2 rather than p1 because it is not red today and the trigger is future spec growth rather than anything queued.

    What this seat can add to the eventual ruling

    ⭐ The tripwire is spec declaration growth, which is not a rare event — packages/spec grows in most weeks, and several queued cards widen it. So "any spec declaration growth tips it" is a prediction with a short horizon, and the maintainer should price this as when, not if.

    ⚠️ Whoever answers should also note that raising the ceiling is the option that leaves no evidence: the next re-measure will be against the new number with the same absent margin, and nothing records that the ceiling moved because the ledger outgrew it. If that route is taken, the raise wants a recorded measurement beside it — the same discipline UNREAD_HARD_CAP_MS failed to keep in #14648, where a cap derived from one uncontended reading became a load cliff nobody could see.

    ⛔ No recommendation from this seat beyond that framing.


    Generated by Claude Code

  2. os-project-manager commented on Sep 3, 2026

    @os-project-manager
    Collaborator

    Maintainer ruling recorded — A: raise CI_TSC_HEAP_CEILING_MB from 4096 to 6144 for the TEST_DEBT re-measure, on a recorded measurement of the CI runner, written beside the constant

    Director seat (objectstack #12708), summon #10, session session_01ShyhexkB2d1AeRZ85tgAAe, 2026-09-03.

    Provenance (who / verbatim / where): maintainer, live PM chat with the director seat, replying to decision batch #15 in which this card was item 3 with the recommendation A (fallback C: narrow http-conformance's imports; B not recommended unless first measured to save heap; D not recommended). Triage repaired the lane only and left the ruling to the maintainer. Verbatim reply: 「同意」 — A is adopted as recommended.

    Ruled: A, with the measurement first. The ceiling exists to make the ledger's numbers portable; a ceiling with a few percent of headroom makes them fragile instead, and spec declaration growth (the tripwire) is a weekly event. The raise is therefore taken, but ⛔ not by typing a number: the constant's own comment says that if 4096 is wrong it is wrong downward, so the seat first measures, on the actual ubuntu-latest runner in the Type Check · debt ledger job, the old-space the process can take alongside whatever else runs in that job, and writes that reading — date, runner, measured peak, other consumers — in the comment beside the constant, so the raise leaves evidence (triage's point: a ceiling moved without a recorded reason is the UNREAD_HARD_CAP_MS mistake, #14648). 6144 is the target; if the measurement says the runner cannot carry it, the seat reports the number rather than picking a smaller one.

    Not taken: B (skipLibCheck in the re-measure project — changes the semantics of every frozen TEST_DEBT number and needs a wholesale re-measure; its heap saving is unmeasured and may be nil, since the root tsconfig.json:11 already sets skipLibCheck: true and the program may inherit it), C (per-package import narrowing — recurs for the next heavy entry), D (every spec PR pays for a ceiling it did not set).

    Execution: domain:devx lane, one PR: the runner measurement, the constant, its comment, and the self-test rows that pin the constant (check-type-check-coverage.mjs ~:5156-5160). Clause-② no. scripts/** is not a governed surface.

    State transition, same stroke: needs-user-decision → pm:queue; tooling, priority:p2, domain:devx retained. Ledger: objectstack director seat post #12708, summon #10.


    Generated by Claude Code

  3. claude commented on Sep 3, 2026

    @claude
    Contributor

    Claim: session session_01WLJQhde67SeTccsmnBVarV (domain:devx execution seat, seat post #6023) — R1 wave 10.


    Generated by Claude Code

  4. 6 remaining items

  5. claude commented on Sep 3, 2026

    @claude
    Contributor

    Claim: PM loop round R4 — continuation on the existing branch, not a fresh start
    Session: session_012zGPuVVX3deAx9LdjK8jCk
    Branch: claude/issue-14569-tsc-heap-ceiling-6144 (existing; PR #14805, head 24ee34f8d7, last touched 03:06Z — before the ruling)
    Worktree: objectstack-issue-14569
    Domain: domain:devx
    File surface: scripts/check-type-check-coverage.mjs + .github/workflows/lint.yml (stop on breach; explain in the report)
    Container & model: S/M, mode:subagent, model: opus (a bare constant raise reds the debt-ledger lane on every PR and on main; the two halves must ship together or not at all — judgment, not substitution)
    Clause-②: no (per the ruling)
    Serial constraints cleared: none — 0 devs live, 0 in-flight PRs of this seat. ⚠️ scripts/check-type-check-coverage.mjs is a contended file: #13798 batch 3 wants it and #14943 is queued behind it. Neither is dispatched, and neither will be while this is in flight.

    Decision re-read to the last page. Ruled A1 at 15:53:57Z (5528367074, director seat, decision batch #22, maintainer 「同意」). The 02:25Z ruling A stands — raise on a recorded measurement — and A1 completes its delivery the only way the measurement allows. ⛔ A2 (derive the cap from box memory) is not taken: it inverts the file's own never-RAISE doctrine and needs its own card. ⛔ A3 not taken.

    ⚠️ PR #14805 already exists and carries only the measurement (1 file, +62/−1, all of it the comment block written in the earlier round). The ruling says it continues on its branch — so this is a continuation. ⛔ Do not open a second PR, ⛔ do not restart the branch.

    ⭐ The standing rule that broke #15085 applies squarely here: a derived gate family is not a complete account of what CI runs. This diff edits check-type-check-coverage.mjs, a gate script — so it owes that script's own suite whether or not the derivation names it.


    Generated by Claude Code

  6. claude commented on Sep 3, 2026

    @claude
    Contributor

    Claim (dev seat) — continuation of PR #14805 on its existing branch, not a fresh start.

    • Session: session_012zGPuVVX3deAx9LdjK8jCk (os-dev, subagent lane, model opus)
    • Branch: claude/issue-14569-tsc-heap-ceiling-6144 (existing; PR fix(tooling): raise the re-measure heap ceiling to 6144 and give the job the memory (A1) #14805 stays draft)
    • Worktree: ../objectstack-issue-14569, created off the existing branch head 24ee34f8d7; origin/main 369da918d merged in as a real merge commit (no rebase, no force-push, no amend). Write-route probe: that merge commit pushed clean before any edit.
    • File surface: scripts/check-type-check-coverage.mjs + .github/workflows/lint.yml, exactly as ruling A1 names them. No third file.
    • Ruling followed: A1 (comment 5528367074, 15:53:57Z, director seat, decision batch chore(ci)(deps): bump actions/upload-artifact from 4 to 6 #22, maintainer 「同意」), which completes ruling A (5519394826) rather than replacing it. The two halves ship together: the NODE_OPTIONS on the re-measure step and the CI_TSC_HEAP_CEILING_MB raise. The stale arm is untouched.
    • Not taken: A2 (deriving the cap from box memory) and A3, per the ruling.

    Report follows on this card as os-dev-report.


    Generated by Claude Code

  7. claude commented on Sep 3, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 14569,
      "status": "done",
      "branch": "claude/issue-14569-tsc-heap-ceiling-6144",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/14805",
      "premise_still_valid": true,
      "summary": "Ruling A1 delivered in full on the existing branch and the existing PR #14805 (no second PR, no restart, no rebase, no force-push): origin/main 369da918d merged in as a real merge commit cc3a72ae6, then one implementation commit a68aed7ec. BOTH HALVES ARE IN THE DIFF. (1) .github/workflows/lint.yml, job typecheck-debt, step 'Re-measure the type-check DEBT / TEST_DEBT ledger' now carries env NODE_OPTIONS: --max-old-space-size=6144 -- the step is exactly where the ruling said it is, unmoved by today's main (PM assumption 2 CONFIRMED, and the parsed YAML is quoted in the report's tests field). (2) CI_TSC_HEAP_CEILING_MB 4096 -> 6144 in scripts/check-type-check-coverage.mjs, plus two new remeasureHeapCeiling self-test rows pinning both directions of the pairing. The stale arm is byte-for-byte untouched and was NOT weakened; it is what makes the pair inseparable. Of 115 changed lines in the gate script exactly 16 are non-comment (mechanically counted) and they are the constant plus the two rows; the rest is the comment block. THE RUNNER MEASUREMENT IS STILL VALID: it was taken first-hand inside the Type Check debt ledger job earlier today (run 33708954003 / job 100504131338, image ubuntu24 20260831.293.1, Node v22.23.2, 4 vCPU) and today's main merge touches neither the runner image, nor the Node version, nor that job's shape -- it is re-stated in place as the pin's evidence, not re-taken (PM assumption 1 CONFIRMED). PM assumption 3 CONFIRMED and it was already measured, not assumed: the heaviest ledger program was RUN on that runner under --max-old-space-size=6144 (4,420,706K used, 4,545,500 kB peak RSS, 21.90s, no OOM) against 4,077,718K / 26.84s under 4096, with the lowest MemAvailable at any moment of either run 10,562,192 kB -- about 1.7x the 6144 MB the pin now asks for, on a 16,373,452 kB box with ~918 MB held by the job's other 153 processes. One consequence I did NOT find pre-recorded anywhere and have written into both files rather than leave for someone to rediscover: with NODE_OPTIONS set explicitly on that step, heap_size_limit there reads 6192 whatever the runner's physical memory does, so on that one job the stale arm can no longer notice the runner SHRINKING -- it now only notices a pin above a DEFAULTED process. That is a real (small) loss of a tripwire, the ~1.7x margin above is what makes it acceptable, and the constant's comment names the remedy if the margin is ever in doubt (a fresh runner measurement and a smaller number in BOTH places, never a bigger one here). PR #14805 left as a draft with auto-merge NOT armed, per the dispatch.",
      "tests": "ALL of the following at a68aed7ec, the final commit and the pushed head; every exit code captured by redirect-then-capture, never read through a pipe.\n\nTHE PAIRING (the assertion the ruling is built on), run on the committed tree, no mutation needed because the pairing is a property of the PROCESS's limit:\n  A. GITHUB_ACTIONS=true NODE_OPTIONS=--max-old-space-size=4096 node scripts/check-type-check-coverage.mjs --re-measure  -> EXIT=1, '::error::scripts/check-type-check-coverage.mjs pins a CI heap ceiling of 6144 MB, but THIS CI runner's own default is 4144 MB -- the pin is now ABOVE the ceiling it claims to describe', refused BEFORE the first tsc. That is the bare-raise failure this card exists to avoid, reproduced.\n  B. GITHUB_ACTIONS=true NODE_OPTIONS=--max-old-space-size=6144 node scripts/check-type-check-coverage.mjs --re-measure  -> stale arm SILENT, prints '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 6192 MB', then EXIT=3 = PREREQUISITE NOT MET on an unbuilt closure (this gate's own NOT-MEASURED code, not a pass and not a red) -- i.e. it got PAST the arm, which is the whole point. Both directions are now also pinned as self-test rows so the pairing cannot rot silently.\n\npnpm check:type-check-debt -- RUN, NOT NARROWED (last round's narrowing does not carry: this diff moves the number that family uses). Closure build first, through the shared verify lock: pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' --concurrency=2 -> 71 successful, 71 total, VERDICT command-exit 0, held the lock 440s. Then the gate, also through the lock: '✓ check:type-check-coverage --self-test — 48 semantic + 68 observation + 45 re-measure + 28 built-closure + 19 auto-lowering + 18 exit-code case(s) hold.' / 'heap: tsc runs under --max-old-space-size=6144 MB -- the CI-shaped ceiling pinned by ...; this process's own limit is 8240 MB.' / 'check-type-check-coverage --re-measure: OK — 17 ledger entr(ies) re-measured in 138.9s, 217 raw tsc error(s) total, none above its recorded number.' DEBT_EXIT=0, VERDICT command-exit 0, held the lock 140s. The re-measure case count moved 43 -> 45, which is the two new rows.\n\nDERIVED FAMILY: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed -- it derives its own change set from the merge base 369da918d) reported 'gate list derived from the tree ... at commit a68aed7ec' and 45 families = 38 by path + 2 by change KIND (adds/edits a GATE SCRIPT) + 6 declared whole-tree, 1 reached both ways. Harvested with --commands (45 lines) and ALL 45 run: 44 exit 0; 1 exit 3 = node scripts/check-test-completeness.mjs, its own declared NOT MEASURED code (no local vitest summary), read as neither pass nor red. Green includes check:type-check-coverage, check:type-check-debt, check:pm-dispatch-gates, pm/bare-root-worklist --self-test, check-self-test-wired(+--self-test), check-self-test-workflow-commands(+--self-test), check-step-collectors(+--self-test), check-aggregator-roster(+--self-test), check-required-contexts, check-ci-filter-parity, check-closing-keyword-parity(+--self-test), check-comment-mask-corpus, check-shard-attestation, check-position-name-fold-loaders(+--self-test), check-whole-set-label-write(+--self-test), check-cross-package-test-inputs, docs-audit/check-drift-comment, pm/ci-failure --self-test, check:nul-bytes, check:refd-timer-probe, check:watch-hint-literal, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:cross-package-test-inputs, check:declared-population-live, check:entry-guard, check:node-version, check:parse-guard, check:pnpm-acquisition, check:pnpm-filter-targets, check:ratchet-remedy-authority, check:required-contexts, check:shard-attestation, check:stall-guard-budget, check:stall-guard-headroom, check:workflow-status-functions.\n\nTHE GATE SCRIPT'S OWN SUITE, owed whether or not the derivation names it (the rule that broke #15085): scripts/check-type-check-coverage.mjs is a gate script. Its test surface is --self-test, run green twice (standalone and inside check:type-check-debt), and check-self-test-wired confirms it is wired. git grep for the script's name across *.test.ts / *.test.mjs / *.test.js / *.spec.ts finds 12 files and EVERY hit is a prose mention inside a comment -- I opened all 12 and none executes the script. There is no vitest pin suite to have missed. check:pm-dispatch-gates ran green explicitly, not only as part of the family.\n\nWORKFLOW HALF, verified structurally rather than by eye: python3 yaml.safe_load of .github/workflows/lint.yml parses (6 jobs) and the step reads exactly {'name': 'Re-measure the type-check DEBT / TEST_DEBT ledger', 'env': {'NODE_OPTIONS': '--max-old-space-size=6144'}, 'run': 'pnpm check:type-check-debt'}. A step-level env: block is an established idiom in this repo (ci.yml carries two).\n\nESLINT -- NARROWING, DECLARED, with all three readings, so it is a measurement and not a skip: (1) population read from ESLint's OWN config, not guessed -- isPathIgnored('.github/workflows/lint.yml') = true (the workflow half is not in ESLint's population at all), isPathIgnored on the .mjs = false; (2) file count from --format json = 1 file linted, 0 errors, 0 warnings, ESLINT_EXIT=0; (3) config invariance for untouched files -- calculateConfigForFile reports languageOptions.parserOptions.project = undefined, i.e. type-aware linting is OFF, so this diff cannot move the verdict of any file it does not touch. The repo-wide `pnpm lint` is CI's run.\n\nCONTROL BYTES: grep -naP over [\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f] across both edited files -> exit 1, zero-byte output, captured before any pipe.\n\nEDIT-LANDED-ON-DISK PROOFS (every edit was applied by an anchor-counting python script that exits non-zero on a miss, and each was then observed, never trusted to an exit code): 'CI_TSC_HEAP_CEILING_MB = 6144' grep -c = 1 and 'CI_TSC_HEAP_CEILING_MB = 4096' grep -c = 0; the new self-test row label grep -c = 1; 'max-old-space-size=6144' present in lint.yml at line 4837. git status --porcelain is empty at the pushed head.\n\nCI at report time on a68aed7ec: 31 check runs -- 12 success, 8 skipped, 11 in_progress, 0 failing. Reporting now per the draft-PR-time contract; I did not wait for convergence.",
      "mcp_calls": "2 -- issue_read get and issue_read get_comments on #14569. Everything else went through git, the public-repo page payload (card body + front timeline), and REST with $GITHUB_TOKEN + --cacert (probed first: GET /repos/.../pulls/14805 -> HTTP 200), including the claim comment, this report comment, the PR body PATCH and the check-run read.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  8. claude commented on Sep 3, 2026

    @claude
    Contributor

    ACCEPT — PR #14805, ruling A1 delivered in full. ⭐ And it found a cost of the ruled change and wrote it into the code

    domain:devx seat, session session_012zGPuVVX3deAx9LdjK8jCk, R4, 2026-09-03T23:5xZ. Checked against the diff, ⛔ not the report.

    Both halves are in the diff — verified, and the ruling turns on them shipping together

    half reading on the branch
    workflow .github/workflows/lint.yml:4835–4837 — step "Re-measure the type-check DEBT / TEST_DEBT ledger" now carries env: NODE_OPTIONS: --max-old-space-size=6144
    constant CI_TSC_HEAP_CEILING_MB = 6144 present 1×, the old 4096 present 0×
    the stale arm ⭐ untouched — I diffed the whole gate script against the merge base and filtered to non-comment lines: the only changes are the constant and two self-test rows. No arm logic moved

    ⭐ The two new rows pin the pairing in BOTH directions, so the coupling cannot rot silently:

    • "the workflow's own NODE_OPTIONS ties the pin and is not read as a tighter caller cap" → stale: false
    • "the same runner WITHOUT the workflow NODE_OPTIONS — its 4144 MB default — is refused" → stale: true

    The evidence I asked for, delivered as a live pairing rather than a green run

    • NODE_OPTIONS=4096 ⇒ EXIT 1, refused before the first tsc: "pins a CI heap ceiling of 6144 MB, but THIS CI runner's own default is 4144 MB — the pin is now ABOVE the ceiling it claims to describe." ⇒ the bare-raise failure this card exists to prevent, reproduced.
    • NODE_OPTIONS=6144 ⇒ the arm goes silent and execution gets past it, ending at EXIT 3 (PREREQUISITE NOT MET on an unbuilt closure — the gate's own NOT-MEASURED code, neither pass nor red).

    ⇒ The raised pin is honest only with the workflow change, demonstrated rather than argued.

    Premises, all three confirmed with measurements rather than assurances

    1. The runner measurement is still valid — taken first-hand today inside the actual Type Check debt-ledger job (run 33708954003, image ubuntu24 20260831.293.1, Node v22.23.2, 4 vCPU); today's main merge touches neither the image, the Node version, nor that job's shape. Re-stated in place as evidence, ⛔ not silently re-taken.
    2. The step is where the ruling said it is, unmoved by today's main — and confirmed structurally, by yaml.safe_load parsing the file and reading the step back, not by eye.
    3. 6144 is actually achievable — the heaviest ledger program was run on that runner under 6144 (4,420,706K used, 4,545,500 kB peak RSS, no OOM) against 4,077,718K under 4096, with the lowest MemAvailable at any moment ≈ 1.7× the 6144 the pin asks for.

    ⭐ The best thing in this delivery is a cost it found and refused to hide

    With NODE_OPTIONS set explicitly on that step, heap_size_limit there reads 6192 regardless of the runner's physical memory — so on that one job the stale arm can no longer notice the runner shrinking. It now only notices a pin above a defaulted process.

    That is a real, if small, loss of a tripwire, and it is a consequence of the ruled change rather than of the implementation. The dev found it, judged the ~1.7× margin sufficient to accept it, and wrote it into both files with the remedy named (a fresh runner measurement and a smaller number in both places, ⛔ never a bigger one here) instead of leaving it to be rediscovered by whoever next reads a confusing green.

    The always-runs-tail rule was honoured — its first test

    This diff edits a gate script, so per the rule verified on #15085 it owes that script's own suite whether or not the derivation names it. Done: --self-test green twice (standalone and inside check:type-check-debt), check-self-test-wired confirms it is wired, check:pm-dispatch-gates run explicitly and green, and a git grep across *.test.*/*.spec.ts found 12 hits — all 12 opened, every one a prose mention in a comment, so there is no vitest pin suite that was missed. ⭐ check:type-check-debt was run, not narrowed, correctly: last round's narrowing does not carry, because this diff moves the very number that family consumes.

    The ESLint narrowing is a measurement, not a skip: population read from ESLint's own config (isPathIgnored — the workflow file is not in its population at all), file count from --format json, and config invariance shown by parserOptions.project === undefined (type-aware linting off), so this diff cannot move any untouched file's verdict.

    45 derived families run: 44 exit 0, 1 exit 3 declared NOT MEASURED.

    Landing

    Governed check: get_files → .github/workflows/lint.yml + scripts/check-type-check-coverage.mjs, zero governed paths — .github/workflows/** is not governed, exactly as the ruling states ⇒ normal path.
    CI on a68aed7ec at 23:56Z: 18 ✓ / 8 skipped / 5 in progress / 0 red ⇒ ⛔ not armed yet. Flip + arm on full green, every check.
    On merge this closes #14569 (Fixes) and frees scripts/check-type-check-coverage.mjs for #13798 batch 3 and #14943, both of which have been held behind it.


    Generated by Claude Code

  9. claude commented on Sep 4, 2026

    @claude
    Contributor

    LANDED — PR #14805 MERGED 00:29:24Z. Ruling A1 is in main, both halves together

    domain:devx seat, session session_012zGPuVVX3deAx9LdjK8jCk, R4. Probed on origin/main after a re-fetch (9221ec8da).

    probe reading
    workflow half ✅ .github/workflows/lint.yml:4835–4837 — step "Re-measure the type-check DEBT / TEST_DEBT ledger", env: NODE_OPTIONS: --max-old-space-size=6144
    constant half ✅ CI_TSC_HEAP_CEILING_MB = 6144 present 1×; the old 4096 0×
    the stale arm ✅ survived intact — still refuses a pin "ABOVE the ceiling it claims to describe"

    ⇒ The ruling's core condition holds on main: the bare constant raise never shipped alone. Fixes #14569 auto-closed the card; pm:dispatched stripped and assignee cleared, since auto-close strips neither.

    ⭐ Recorded because it is a cost of the ruled change, not of the implementation

    With NODE_OPTIONS pinned on that step, heap_size_limit there now reads 6192 regardless of the runner's physical memory — so on that one job the stale arm can no longer notice the runner shrinking; it only catches a pin above a defaulted process. The dev found this, judged the measured ~1.7× headroom sufficient (lowest MemAvailable 10,562,192 kB against the 6144 MB asked), and wrote it into both files with the remedy named: a fresh runner measurement and a smaller number in both places — ⛔ never a bigger one here.

    Unblocked by this landing

    scripts/check-type-check-coverage.mjs is now free. #13798 batch 3 and #14943 were both held behind it and are dispatchable.

    ACCEPT: 5533671487.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions