runtime: put el_runtime.c on a ratchet, and actually run the guards #161

Merged
will.anderson merged 1 commits from fix/runtime-growth-guard into fix/runtime-shim-retire 2026-08-17 00:56:48 +00:00
Owner

Stacked on #160 — base is fix/runtime-shim-retire. Merge #160 first, then this retargets to dev cleanly. This PR's own diff is 8 files.

Root cause

Same two causes as #160a temporary shim nobody retired, kept growing by a false instruction in the instruction file — but this PR addresses the part that let it go unnoticed for 3.5 months.

scripts/check-single-runtime.sh guards against el_runtime.c being COPIED. It was written after a lagging fork shipped to prod and dropped learned hebb edges. Nothing guarded against it GROWING. So it grew: 10,607 → 20,527 lines, +94% in 3.5 months — the whole time under an explicit commit-message promise that it was a temporary shim about to be deleted.

And the copy guard was never wired in. Its own footer described the CI wire-in as a TODO, and the TODO had never been done — the script existed but ran in no workflow and no hook. It had caught nothing for as long as it has been in the tree.

A guard that does not run is a comment.

What changed

lang/runtime/BUDGET — a ratchet, not a limit.

  • max_lines 20527 — set at the current size with no headroom. The file cannot grow by one line.
  • max_engram_fns 279 — top-level engram_*/eg_*/cog_* definitions in el_runtime.c. ~47.5% of the file is engram code and engram already owns six sibling .c files, so this is the scoreboard for moving it out.
  • Both may only ever go DOWN.

scripts/check-runtime-growth.sh — enforces the ratchet, plus three invariants that keep the multi-file runtime honest:

  1. Every .c in lang/runtime/ is in SOURCES or explicitly platform-optional. An unaccounted .c is compiled by nothing and is silently dead code.
  2. install.sh's hardcoded download list matches SOURCES. It cannot call the helper — it runs where there is no checkout — so that copy is checked, not trusted. This is precisely the duplicate that drifted before.
  3. An advisory nudge to lower the budget when you have earned it, so ground gained is not quietly given back.

Both guards now actually run — early steps in ci-dev.yaml, ci-stage.yaml, sdk-release.yaml, and in .githooks/pre-commit.

The failure message is the point

The guard that existed said what was wrong but not where the code should go — which makes it easy to "fix" by arguing with the guard, or by raising the number. This one names the destination, and prints the nm command that proves the argument is already settled:

nm lang/dist/platform/elc | grep -E 'T _(engram_think|vindex_insert)'

Placement is a link-time concern; the shipped compiler already links from ten translation units. So it names the six concern files, then SOURCES (one line), then c_source in a program's manifest.el. Every runtime file except el_runtime.c is deliberately uncapped — that is where code is supposed to go.

Negative controls

Per lang/AGENTS.md step 5, each was shown FAILING, not merely passing:

Control Result
+1 line to el_runtime.c FAIL20528/20527, over by 1
+1 engram fn, net-zero lines FAIL280/279
new unaccounted lang/runtime/el_stray.c FAIL — names it, says how to fix
engram_store.c removed from install.sh FAILOnly in SOURCES: engram_store.c
el_runtime.c truncated to 20,000 lines PASS + nudge — "lower max_lines to 20000"
baseline, tree unmodified OK, both guards green

el_runtime.c is byte-identical after the controls (git status clean). This PR changes zero lines of it.

Before / after

Before After
Guard against el_runtime.c being copied existed, ran nowhere runs in 3 workflows + pre-commit
Guard against el_runtime.c growing none line ratchet + engram-fn ratchet
install.sh vs SOURCES drift undetectable fails the build
Unaccounted lang/runtime/*.c silently dead fails the build
lang/runtime/el_runtime.c 20,527 lines 20,527 — capped here

What remains

Stage 3: move engram code out of el_runtime.c into the six sibling files — ~9,700 lines, ~279 functions. max_engram_fns is the scoreboard; the guard prints the new number to ratchet to after each move.

Recommended next, not attempted: make elc emit #include el_seed.h and drop elb's hardcoded runtime path, finishing the 2026-05-03 migration. Correct long-term fix, but it touches codegen and self-hosting.

Coordination

Does not touch engram/src/server.el, peripheral/, or elp/. lang/AGENTS.md edit is confined to the Layer 2 section, away from PR #157's "Rebuilding the Compiler" block.

**Stacked on #160** — base is `fix/runtime-shim-retire`. Merge #160 first, then this retargets to `dev` cleanly. This PR's own diff is 8 files. ## Root cause Same two causes as #160 — **a temporary shim nobody retired, kept growing by a false instruction in the instruction file** — but this PR addresses the part that let it go *unnoticed for 3.5 months*. `scripts/check-single-runtime.sh` guards against `el_runtime.c` being **COPIED**. It was written after a lagging fork shipped to prod and dropped learned `hebb` edges. **Nothing guarded against it GROWING.** So it grew: **10,607 → 20,527 lines, +94% in 3.5 months** — the whole time under an explicit commit-message promise that it was a temporary shim about to be deleted. **And the copy guard was never wired in.** Its own footer described the CI wire-in as a TODO, and the TODO had never been done — the script existed but ran in **no workflow and no hook**. It had caught nothing for as long as it has been in the tree. > A guard that does not run is a comment. ## What changed **`lang/runtime/BUDGET`** — a **ratchet, not a limit**. - `max_lines 20527` — set at the current size with **no headroom**. The file cannot grow by one line. - `max_engram_fns 279` — top-level `engram_*`/`eg_*`/`cog_*` definitions in `el_runtime.c`. ~47.5% of the file is engram code and engram **already owns six sibling `.c` files**, so this is the scoreboard for moving it out. - **Both may only ever go DOWN.** **`scripts/check-runtime-growth.sh`** — enforces the ratchet, plus three invariants that keep the multi-file runtime honest: 1. Every `.c` in `lang/runtime/` is in `SOURCES` or explicitly platform-optional. **An unaccounted `.c` is compiled by nothing and is silently dead code.** 2. `install.sh`'s hardcoded download list matches `SOURCES`. It cannot call the helper — it runs where there is no checkout — so that copy is **checked, not trusted**. This is precisely the duplicate that drifted before. 3. An advisory nudge to lower the budget when you have earned it, so ground gained is not quietly given back. **Both guards now actually run** — early steps in `ci-dev.yaml`, `ci-stage.yaml`, `sdk-release.yaml`, and in `.githooks/pre-commit`. ## The failure message is the point The guard that existed said *what* was wrong but not *where the code should go* — which makes it easy to "fix" by arguing with the guard, or by raising the number. This one names the destination, and prints the `nm` command that proves the argument is already settled: ``` nm lang/dist/platform/elc | grep -E 'T _(engram_think|vindex_insert)' ``` Placement is a **link-time** concern; the shipped compiler already links from **ten translation units**. So it names the six concern files, then `SOURCES` (one line), then `c_source` in a program's `manifest.el`. **Every runtime file except `el_runtime.c` is deliberately uncapped — that is where code is supposed to go.** ## Negative controls Per `lang/AGENTS.md` step 5, each was shown **FAILING**, not merely passing: | Control | Result | |---|---| | `+1` line to `el_runtime.c` | **FAIL** — `20528/20527`, over by 1 | | `+1` engram fn, **net-zero lines** | **FAIL** — `280/279` | | new unaccounted `lang/runtime/el_stray.c` | **FAIL** — names it, says how to fix | | `engram_store.c` removed from `install.sh` | **FAIL** — `Only in SOURCES: engram_store.c` | | `el_runtime.c` truncated to 20,000 lines | **PASS + nudge** — "lower `max_lines` to 20000" | | baseline, tree unmodified | **OK**, both guards green | `el_runtime.c` is byte-identical after the controls (`git status` clean). **This PR changes zero lines of it.** ## Before / after | | Before | After | |---|---|---| | Guard against el_runtime.c being **copied** | existed, **ran nowhere** | runs in 3 workflows + pre-commit | | Guard against el_runtime.c **growing** | **none** | line ratchet + engram-fn ratchet | | `install.sh` vs `SOURCES` drift | undetectable | fails the build | | Unaccounted `lang/runtime/*.c` | silently dead | fails the build | | `lang/runtime/el_runtime.c` | 20,527 lines | **20,527 — capped here** | ## What remains **Stage 3**: move engram code out of `el_runtime.c` into the six sibling files — ~9,700 lines, ~279 functions. `max_engram_fns` is the scoreboard; the guard prints the new number to ratchet to after each move. **Recommended next, not attempted:** make `elc` emit `#include el_seed.h` and drop `elb`'s hardcoded runtime path, finishing the 2026-05-03 migration. Correct long-term fix, but it touches codegen and self-hosting. ## Coordination Does not touch `engram/src/server.el`, `peripheral/`, or `elp/`. `lang/AGENTS.md` edit is confined to the *Layer 2* section, away from PR #157's "Rebuilding the Compiler" block.
will.anderson added 1 commit 2026-08-16 21:48:41 +00:00
scripts/check-single-runtime.sh guards against el_runtime.c being COPIED — it
was written after a lagging fork shipped to prod and dropped learned hebb edges.
Nothing guarded against it GROWING. So it grew: 10,607 -> 20,527 lines, 94% in
3.5 months, the whole time under an explicit commit-message promise that it was
a temporary shim about to be deleted.

Worse, the copy guard was never wired in. Its own footer described the CI
wire-in as a TODO, and the TODO had never been done — the script existed but ran
nowhere, in no workflow and in no hook, so it had caught nothing for as long as
it has been in the tree. A guard that does not run is a comment.

This adds the missing guard and runs both.

  * lang/runtime/BUDGET — a RATCHET, not a limit. max_lines is set at the
    current 20,527 with NO headroom: the file cannot grow by one line. A second
    cap, max_engram_fns (279), counts top-level engram_/eg_/cog_ definitions in
    it — ~47.5% of the file is engram code and engram already owns six sibling
    .c files, so this is the scoreboard for moving it out. Both may only go DOWN.

  * scripts/check-runtime-growth.sh — enforces the ratchet, and three
    invariants that keep the multi-file runtime honest: every .c in
    lang/runtime/ is either in SOURCES or explicitly platform-optional (an
    unaccounted .c is compiled by nothing and is silently dead); install.sh's
    hardcoded download list matches SOURCES (it cannot call the helper — it
    runs where there is no checkout — so that copy is checked, not trusted);
    and an advisory nudge to lower the budget when you have earned it.

  * Both guards now run as early steps in ci-dev.yaml, ci-stage.yaml and
    sdk-release.yaml, and in .githooks/pre-commit.

The failure message is the point. The guard that existed said what was wrong but
not where the code should go, which makes it easy to "fix" by arguing with the
guard. This one names the destination: the concern-owning .c, or a new .c plus
one line in SOURCES, or c_source in a program's manifest.el — and it prints the
`nm` command that proves placement is link-time and that the shipped compiler
already links from ten translation units. Every runtime file except el_runtime.c
is deliberately uncapped, because that is where code is supposed to go.

Proven with negative controls, per lang/AGENTS.md step 5 — each shown FAILING:
  * +1 line to el_runtime.c                  -> FAIL (20528/20527)
  * +1 engram fn, net-zero lines             -> FAIL (280/279)
  * a new unaccounted lang/runtime/*.c       -> FAIL
  * engram_store.c removed from install.sh   -> FAIL, names the missing file
  * el_runtime.c truncated to 20,000 lines   -> PASS + "lower max_lines to 20000"
  * baseline, tree unmodified                -> OK, and both guards green

el_runtime.c is byte-identical after the controls; this commit changes zero
lines of it.
will.anderson merged commit d99dd17f74 into fix/runtime-shim-retire 2026-08-17 00:56:47 +00:00
Sign in to join this conversation.