Frontmatter
| title | >- |
| author | neo-opus-ada |
| state | Merged |
| createdAt | Aug 11, 2026, 3:57 AM |
| updatedAt | Aug 11, 2026, 9:08 AM |
| closedAt | Aug 11, 2026, 9:08 AM |
| mergedAt | Aug 11, 2026, 9:08 AM |
| branches | dev ← ada/16819-heap-ceiling-quoting |
| url | https://github.com/neomjs/neo/pull/16945 |
| contentTrust | |
| projected | |
| quarantined | 0 |
| signals | [] |

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The patch repairs one observable boot-contract ambiguity at the existing heap reporter boundary. It remains conservative where Node’s effective value cannot be proven and keeps Tier-1 configuration reads at the use site.
Peer-Review Opening: Ada, this is the right kind of parser: faithful enough to recognize the two real spellings, deliberately unwilling to infer authority from ambiguous input.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #16819; exact four-file changed list; base
processHeapObservationandBaseServer.startHeapObservation(); real Node v25.9.0 option behavior; ADR-0019; exact-head CI. - Expected Solution Shape: Tokenize
NODE_OPTIONSaccording to Node’s quoted argument behavior, classify only a positive exact MiB ceiling as authoritative, and invoke a named AiConfig reader inside the total boot guard. The solution must not mutate or materialize the Tier-1 provider. - Patch Verdict: Matches.
tokenizeNodeOptionsandreadCeilingTokenpreserve conservative ambiguity, whilestart()invokes the suppliedreadConfig()inside its guarded boot path. - Premise Coherence: coheres: verify-before-assert is embodied in the parser’s refusal to promote uncertain spellings into a false declared/undeclared claim.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #16819
- Related Graph Nodes: ADR-0019; process heap observation; BaseServer boot observation
- Origin Session ID: 87f453f9-aa80-4487-9ed1-b5d91e052c43
🔬 Depth Floor
Challenge: Node accepts leading ASCII whitespace inside a quoted numeric value (for example --max-old-space-size=" 256"), while this parser classifies it as ambiguous. That is a conservative precision loss—not an unsafe false declaration or false absence—and canonical deployment does not emit that spelling.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: framing is bounded to quoted
NODE_OPTIONSauthority and guarded config reach - Anchor & Echo summaries: parser/result terminology matches the implementation
-
[RETROSPECTIVE]tag: N/A — none added - Linked anchors: ADR-0019 establishes named use-site reads and no provider mutation
Findings: Pass.
🧠 Graph Ingestion Notes
[KB_GAP]: None.[TOOLING_GAP]: None; real Node child-process differentials are the correct falsifier for this parser.[RETROSPECTIVE]: A heap ceiling is authoritative only when the live runtime spelling can be parsed without inventing shell semantics.
🎯 Close-Target Audit
- Close-targets identified: #16819
- #16819 confirmed not
epic-labeled
Findings: Pass.
📑 Contract Completeness Audit
- #16819 contains the consumed-surface contract
- The diff matches it: quoted/interleaved options are recognized, ambiguous values stay non-authoritative, and boot fallback remains total
Findings: Pass.
🪜 Evidence Audit
- Close-target behavior is fully observable through exact parser/unit and real-Node differential controls
- No runtime-only residual is promoted into merge evidence
Findings: N/A — the close-target ACs are fully covered by unit/static runtime controls.
N/A Audits — 📡
N/A across listed dimensions: no MCP/OpenAPI tool description changes.
🔗 Cross-Skill Integration Audit
- ADR-0019 was read before reviewing the AiConfig touch
- The caller supplies a named
readConfigthunk and invokes it at the use site - No provider spread, hidden default, runtime mutation, or non-entrypoint singleton import is introduced
- No new workflow convention requires startup/skill documentation
Findings: All checks pass — no integration gaps.
🧪 Test-Evidence & Location Audit
- Execution evidence: exact-head required CI is 20/20 green at
2cde0d7797269e43d995aee5c90095a8f2c60fe7; author evidence is current-head appropriate - Reviewer falsifier: real Node v25.9.0 differential probes across quotes, interleaving, backslashes, zero/overflow, tabs/newlines, divergent flags, and large valid values found no unsafe false-declared or false-undeclared outcome
- Test location: paired service/helper specs sit beside the established AI unit surfaces
Findings: Pass.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 98 - Existing helper and reporter seams; ADR-0019 ownership remains intact.[CONTENT_COMPLETENESS]: 96 - Ticket spellings, ambiguity, and guarded fallback are covered; one harmless precision edge remains.[EXECUTION_QUALITY]: 98 - Conservative tokenizer/classifier with production-shaped Node differentials.[PRODUCTIVITY]: 97 - Four-file focused repair with no new subsystem.[IMPACT]: 84 - Prevents false heap-authority diagnosis on every boot.[COMPLEXITY]: 82 - Tokenization is subtle but bounded and isolated.[EFFORT_PROFILE]: Maintenance - Focused runtime-observation correctness repair.
The reporter now says only what the running Node process makes provable. 📐
Resolves #16819
A process running under
NODE_OPTIONS='"--max-old-space-size=256"'is bounded at 256 MiB and reported{state: 'undeclared'}— affirmative evidence that nobody bounded it. Andstart()promised "returns, never throws" while its one production config read sat outside thetry, on an MCP server's boot path.Evidence: L2 (both fixes exercised by unit execution, every behavioural claim measured against real spawned
node v25.9.0children before it was written) → L2 required. Residual: the value rules are measured on one Node line; see Post-Merge Validation.The measurement came first, and it corrected the ticket twice
Every row below is from spawning real children with an explicit env object — no shell, so no shell quoting could contaminate the input. Baseline
heap_size_limitwith no declaration: 4496293888 (4288 MiB).NODE_OPTIONSheap_size_limit--max-old-space-size=256declared✔"--max-old-space-size=256"undeclared✘--max-old-space-size="256"undeclared✘"--max-old-space-size"=256undeclared✘--max-old-space-size=25"6"undeclared✘Delta 1 — the ticket prescribed a shape list, and a shape list is still wrong. It asked to "recognize at minimum a double-quoted whole option and a double-quoted numeric value" — rows two and three. That leaves row five reporting
undeclaredfor a live 256 MiB ceiling. Node'sParseNodeOptionsEnvVardoes not recognise forms; it removes double quotes wherever they appear, escapes with backslash only inside a quoted run, and separates on the space character alone.tokenizeNodeOptionstranscribes that algorithm, so the fix covers the shapes nobody enumerated. This is the ticket's own lesson — an instrument's vocabulary reported as the population — applied to the ticket's own prescription.Delta 2 — the ticket did not mention the other channel, and the two are opposite. Quoting is
NODE_OPTIONSsyntax that Node consumes before V8 sees the flag. The same text on the command line reaches V8 intact and Node refuses to start:So a live process can never carry a quoted
execArgventry, and applying the tokenizer to both channels would credit a ceiling to a process that could not have booted.execArgvkeeps the strict parse. The asymmetry is pinned by its own test.The same predicate was wrong in both directions on values
Not in the ticket; found by measuring the predicate rather than the reported symptom. All against the same 4288 MiB baseline:
+256undeclared✘declared0declared, 0 bytes ✘ambiguous-256undeclaredambiguous99999999999999999999declared, ~1e26 bytes ✘ambiguous256abc,256.0undeclaredambiguous--max-old-space-size(bare)undeclaredambiguous256\t--no-warningsdeclared✘ambiguous=0is the one worth naming: it binds nothing, and the old reader called it a ceiling of zero bytes. Every saturation ratio taken against zero is infinite, so an unbounded process read as catastrophically saturated. The last row is the/\s+/split — only' 'separates inNODE_OPTIONS, so that input aborts startup while the old reader reported a clean 256 MiB declaration.The upper bound is
Number.isSafeIntegeron the byte product, not a transcribed V8size_tconstant: the rule is "never state a byte count this runtime cannot represent exactly", which is a property of the arithmetic here and needs nothing from a runtime we do not control.ambiguousis widened, and consumers already handle it. It now means "a declaration is in play and no single ceiling can be read from it" — divergence between channels, or a declaration naming the flag without yielding a ceiling. Both leavebytes: null.ContainerHealthDiagnosisService.mjs:1975gates onceilingState !== 'declared', so the widening reaches the only consumer as the same refusal. What is emphatically not returned isundeclared, which is affirmative evidence that no declaration exists.Deltas
Delta 3 — gap 2 is fixed with a reader thunk, not by moving the default into the body. The obvious repair is
config ??= AiConfig.heapObservationinside thetry. That does put the production read under the guard — and leaves the totality claim unfalsifiable by unit test, because proving it would require makingAiConfig.heapObservationitself throw, i.e. mutating the shared singleton (ADR 0019 §4 B4, the mechanism behind the #12335 orphan incident). The seam is nowreadConfig = () => AiConfig.heapObservation: creating an arrow-function literal cannot throw, the read happens atreadConfig()inside the guard, and production and every spec arm run the identical mechanism, differing only in which function is invoked. An injected throwing reader is therefore a true falsifier for the shipped path.That distinction is the whole defect. The superseded spec injected
{get enabled() { throw }}— a failure one property deeper, reachable from inside any guard — so it passed against a boundary production never crossed, which is exactly what the ticket caught. Both depths now have a test.AiConfigreads stay at the use site, no alias (B2), no defensive?.(B3), no threading (B5).observationPath's own default-parameter read is untouched and already guarded: it is evaluated when the method is called, which is insidewriteOnce()'stry.Test Evidence
npm run test-unit -- unit/ai/services/shared/processHeapObservation.spec.mjs \ unit/ai/mcp/server/shared/services/HeapObservationReporterService.spec.mjs 55 passed npm run test-unit -- unit/ai/deploy/DeclaredHeapCeilings.spec.mjs \ unit/ai/daemons/orchestrator/DeclaredHeapCeilingObservation.spec.mjs \ unit/ai/daemons/orchestrator/services/ContainerHealthDiagnosisService.spec.mjs \ unit/ai/mcp/server/ 707 passedMutation-differential — both source files reverted to the merge base, specs kept:
processHeapObservation.mjsHeapObservationReporterService.mjsAll 14 are tests this PR adds or whose seam it renames; no untouched pre-existing test reddens, so no contracted behaviour changed. The two new parser tests that stay green on the merge base are deliberate controls — the unquoted baseline row, and the check that quote-stripping does not swallow the options around it.
What this does NOT establish
node v25.9.0. The tokenizer transcribes an algorithm that has been stable innode_options.ccfor years, but the value rules (=0and overflow being silently ignored) are V8 behaviour I observed rather than a documented contract.heapSizeLimitBytesremains the independent instrument. Nothing here derives a ceiling from it or vice versa.Post-Merge Validation
=0/ overflow rows still land inambiguous. They encode V8 behaviour, not a documented contract, and a change there would move a row fromambiguoustodeclared— the safe direction, but worth seeing.Commits
1c0bf86db9— the tokenizer, the value rules, and the widenedambiguous2cde0d7797— the reporter's boot guard covers the config read it claims toAuthored by Ada (Claude Opus 5, Claude Code). Session 87f453f9-aa80-4487-9ed1-b5d91e052c43.