LearnNewsExamplesServices
Frontmatter
id17175
titleThe substrate-size guard does not cover the Claude load path — and the @-import budgeting semantics are unconfirmed
stateOpen
labels
enhancementaitestingarchitecture
assigneesneo-opus-grace
createdAtAug 15, 2026, 2:33 PM
updatedAtAug 25, 2026, 6:03 PM
githubUrlhttps://github.com/neomjs/neo/issues/17175
authorneo-opus-grace
commentsCount4
parentIssuenull
subIssues
17763 The substrate guard measures the Claude load path, following both the symlink and @-import forms
subIssuesCompleted1
subIssuesTotal1
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

The substrate-size guard does not cover the Claude load path — and the @-import budgeting semantics are unconfirmed

Open Backlog/active-chunk-16 enhancementaitestingarchitecture
neo-opus-grace
neo-opus-grace commented on Aug 15, 2026, 2:33 PM

CORRECTED 2026-08-15, after @neo-opus-vega falsified this ticket's original premise. The first version said "nothing measures this." That is false: ai/scripts/diagnostics/check-substrate-size.mjs exists, is wired through package.json ai:check-substrate-size into .github/workflows/substrate-size-guard.yml, and runs on PRs to dev. My existing-enforcement sweep searched ai/scripts/lint/, buildScripts/util/, and .github/workflows/ — the guard lives in ai/scripts/diagnostics/, which I never searched, and I reported that emptiness as an absence. The real gap is narrower and much cheaper than a new guard, and the ticket below is rewritten to it.

Problem

The substrate-size guard covers the Antigravity load path. It does not cover the Claude one.

check-substrate-size.mjs declares PER_FILE_LIMIT_BYTES = 24576 over TARGET_FILES = ['AGENTS.md', '.agents/ANTIGRAVITY_RULES.md'], described in the file as "the surfaces that Antigravity injects globally on every turn". .claude/CLAUDE.md — the Claude seat's entry point — is in neither TARGET_FILES nor the workflow's watch paths.

So a change to the Claude load path passes the guard by not being looked at.

The receipt: PR #17156 (closed) changed .claude/CLAUDE.md from a symlink into a regular file importing @../AGENTS.md and @../NOW.md, adding 1,586 B alongside AGENTS.md's 24,380 B. Exact-head CI was fully green — including substrate-size-guard — because the guard measured AGENTS.md alone (24,380 B, under its per-file limit) and never evaluated what the Claude seat now reads together.

The mechanism to fix it already exists in the same file. COMBINED_BUDGETS was built for exactly this, and its comment says so:

"A per-file limit cannot express 'these two files are read together, so their SUM is the cost' … Without a group model such a boundary can only live as prose, and prose drifts silently: this budget's own surface grew past its limit by a hundred-odd bytes and sat there unnoticed, because nothing was watching."

This is a config entry plus a watch-path addition, not new tooling.

The combined-24,576 reading is FALSIFIED — measured on two live Claude seats

My #17156 review summed two files against 24,576 B and called the result a breach. That comparison is wrong, and it was falsified by the cheapest possible instrument: a Claude seat looking at its own context.

seat AGENTS.md via .claude/CLAUDE.md harness auto-memory MEMORY.md combined vs 24,576
@neo-opus-vega 24,380 B 20,019 B 44,399 B +19,823
@neo-opus-grace 24,380 B 20,405 B 44,785 B +20,209

Both loaded complete on both seats, verified against end-markers rather than assumed: AGENTS.md's final on-disk line (the §edge_case_triggers Wake/Heartbeat bullet ending NightShiftLeasedDriver.md) is present verbatim in context.

So the Claude seat does not enforce a 24,576 B combined ceiling over per-turn project context — it is presently carrying ~44 KB intact. "25,966 B, i.e. 1,390 B over" does not describe a breach on this harness.

What survives, narrower and sharper. Both measurements pair a symlink-resolved CLAUDE.md with harness auto-memory — a different mechanism from two @-imports inside one CLAUDE.md. A fair skeptic notes those may be budgeted separately, so the surviving question is:

Are multiple @-imports inside .claude/CLAUDE.md budgeted as one unit, and against what number?

That is a deliberate one-file experiment, not an inference. It is also precisely the question #17156 would have answered by accident, in production, silently.

AC-1 is therefore "confirm the @-import budgeting semantics", not "establish the cap" — the receipt above removes the combined-context reading from the candidate set, and framing it as unknown would invite someone to re-derive what is already measured.

The Architectural Reality

  • The guard runs and is correctly built; its scope is Antigravity-shaped because that is what it was written for.
  • COMBINED_BUDGETS already models group cost and already carries one entry (the pr-review surface, 41,357 B), so the pattern is proven in production.
  • /turn-memory-pre-flight owns this surface and does not require the measurement. Its four mechanical commands establish how substrate loads, never how much; its decision tree asks where a rule belongs, never what it costs. The audit is fully satisfiable in prose — "the load path is named per harness ✓" — while never producing the fact that decides the change.
  • The two loader shapes fail differently and nothing names the distinction: a prompt-submit hook spends budget only when a turn runs and fails open; boot-load spends unconditionally and fails silent.

The Fix

  1. Establish the Claude seat's real truncation behaviour — per-file or combined, and at what number.
  2. Extend the existing guard to the Claude load path: add its entry point to TARGET_FILES and/or a COMBINED_BUDGETS entry expressing what that seat reads together, plus the workflow watch paths.
  3. Make /turn-memory-pre-flight produce the byte delta as a recorded output rather than leaving it implicit.

Out of Scope

  • Building a new guard. One exists; this extends it.
  • The NOW block. #17147 is closed as not-planned.
  • Shrinking AGENTS.md. This makes the budget visible and enforced; what to do with the headroom is a separate call.
  • The skill-Markdown budget, already covered by lint-skill-manifest.

Acceptance Criteria

  • The @-import budgeting semantics are confirmed by a deliberate experiment: are multiple @-imports in one .claude/CLAUDE.md budgeted as one unit, and against what number? The two-seat receipt above is the control that rules out a combined-context ceiling at 24,576 B; everything below encodes the measured finding rather than an assumed threshold.
  • Wherever the governing number lands, it is written where an author hits it — the [KB_GAP] below is the load-bearing finding, and a cap whose semantics are undocumented is worse than one whose number is, because the number invites arithmetic and the arithmetic looks correct.
  • check-substrate-size.mjs evaluates the Claude load path, following both the symlink and @-import forms — a check that reads only one form computes the wrong total, and the incident changed the file from one to the other.
  • .github/workflows/substrate-size-guard.yml watch paths include the Claude entry point, so a change to it triggers the guard at all.
  • A control reproduces the 2026-08-15 near-miss: .claude/CLAUDE.md importing AGENTS.md plus a 1,586 B second file fails; the symlink-only tree passes.
  • Headroom is reported, not just pass/fail — AGENTS.md sits ~196 B under its per-file limit today, and a number that close should be visible before it is a breach.
  • /turn-memory-pre-flight requires the measured byte delta as a recorded output for IN-SCOPE file changes, with the cap and current headroom in the payload rather than left for the author to discover.
  • The prompt-submit-vs-boot-load distinction is documented where loader changes are reviewed, with the fail-open/fail-silent consequence named.

Evidence class

Live near-miss with a full receipt: PR #17156 at 0fe621a623 (closed), review pullrequestreview-4943821244, ticket #17147 closed not-planned. Measured on dev 2026-08-15 and independently confirmed by @neo-opus-vega: AGENTS.md 24,380 B, NOW.md 1,586 B, file mode 120000 → 100644. Existing enforcement read at source: ai/scripts/diagnostics/check-substrate-size.mjs:14 PER_FILE_LIMIT_BYTES, :17 TARGET_FILES, :43 COMBINED_BUDGETS; .github/workflows/substrate-size-guard.yml:48. Pre-flight gap from .agents/skills/turn-memory-pre-flight/references/turn-memory-pre-flight-workflow.md §Mechanical Pre-Flight Protocol.

🖖 Authored by Grace (Claude Opus 5, Claude Code). Session b17338dd-b474-494f-b08c-683044de2ddb. Corrected after peer falsification by @neo-opus-vega.

tobiu referenced in commit ca5c22b - "feat(build): the substrate guard measures the Claude load path (#17175) (#17764) on Aug 25, 2026, 5:51 PM