LearnNewsExamplesServices
Frontmatter
title>-
authorneo-opus-ada
stateMerged
createdAtMay 30, 2026, 3:12 AM
updatedAtMay 30, 2026, 6:55 AM
closedAtMay 30, 2026, 6:55 AM
mergedAtMay 30, 2026, 6:55 AM
branchesdevagent/12107-env-retraction
urlhttps://github.com/neomjs/neo/pull/12189
Merged
neo-opus-ada
neo-opus-ada commented on May 30, 2026, 3:12 AM

Summary

Stage 5 of Epic #12101Neo.util.Env becomes genuinely BaseConfig-internal. The Env.parseX('NEO_X') ?? AiConfig.X consumer doctrine + the bulk applyEnvBindings are retracted; the lone external consumer (the orchestrator's swarmHeartbeatIdentity) is migrated off the parsers. After this, BaseConfig is the sole prod importer of Env.mjs.

Deltas

  • Env.mjs — top JSDoc reframed from "canonical env-parsing home for all consumers" to "internal typed-parser registry for BaseConfig; not consumer-facing" (links learn/agentos/AiConfigModel.md). Deleted applyEnvBindings (0 prod callers). Fixed the parseNumber note that referenced the ?? AiConfig.X consumer pattern. The 6 parser fns stay — BaseConfig's typeParsers map wires them into the meta-leaf registry.
  • Orchestrator.mjsswarmHeartbeatIdentity now reads process.env.NEO_AGENT_IDENTITY?.trim() directly (behaviour-equivalent to Env.parseString), matching the 6 other NEO_AGENT_IDENTITY consumers; NEO_AGENT_IDENTITY is a runtime identity, not a config-tunable. Removed the now-dead import Env; refreshed the stale (D) operator-policy class-doc (Stage-3 inlined the intervals it described).
  • Env.spec.mjs — dropped the applyEnvBindings describe (73 lines); the parser tests are unchanged.

Net −140 lines.

Intake correction

The ticket's premise — "ZERO Env.parseX consumers remain" — was false: BaseConfig's typeParsers map + the orchestrator's swarmHeartbeatIdentity keeper both used the parsers. So AC1 ("retract consumer-facing exports") cannot mean unexport (BaseConfig imports them) — the retraction is of the consumer doctrine/framing, reframing the fns as internal, which makes AC4 literally true (BaseConfig is the sole prod importer). The parser-registry restructure (Env.parsers vs BaseConfig-internal) is Stage-1 OQ5, which this ticket explicitly defers — so it is left untouched here.

Test Evidence

95 specs pass (test-unit): Env.spec (parsers), BaseConfig.spec (leaf-parser wiring), Orchestrator.spec, Orchestrator.invariants.spec.

Evidence: node --check clean on all three files; grep confirms 0 residual Env.parse*/applyEnvBindings in prod outside Env.mjs/BaseConfig; BaseConfig still references all 6 parsers (8 hits = map + 2 fallbacks); Env.mjs still defines all 6.

Post-Merge Validation

Behaviour-equivalent: swarmHeartbeatIdentity returns the trimmed NEO_AGENT_IDENTITY or undefined, identical to the retired Env.parseString path. No config-template or env-contract change.

FAIR-band: n/a — operator-directed epic lane (#12101 Stage 5).

Resolves #12107.

Authored by Claude Opus 4.8 (Claude Code, 1M context).