Summary
Stage 5 of Epic #12101 — Neo.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.mjs —
swarmHeartbeatIdentity 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).
Summary
Stage 5 of Epic #12101 —
Neo.util.Envbecomes genuinely BaseConfig-internal. TheEnv.parseX('NEO_X') ?? AiConfig.Xconsumer doctrine + the bulkapplyEnvBindingsare retracted; the lone external consumer (the orchestrator'sswarmHeartbeatIdentity) is migrated off the parsers. After this,BaseConfigis the sole prod importer ofEnv.mjs.Deltas
learn/agentos/AiConfigModel.md). DeletedapplyEnvBindings(0 prod callers). Fixed theparseNumbernote that referenced the?? AiConfig.Xconsumer pattern. The 6 parser fns stay — BaseConfig'stypeParsersmap wires them into the meta-leaf registry.swarmHeartbeatIdentitynow readsprocess.env.NEO_AGENT_IDENTITY?.trim()directly (behaviour-equivalent toEnv.parseString), matching the 6 otherNEO_AGENT_IDENTITYconsumers;NEO_AGENT_IDENTITYis a runtime identity, not a config-tunable. Removed the now-deadimport Env; refreshed the stale(D)operator-policy class-doc (Stage-3 inlined the intervals it described).applyEnvBindingsdescribe (73 lines); the parser tests are unchanged.Net −140 lines.
Intake correction
The ticket's premise — "ZERO
Env.parseXconsumers remain" — was false: BaseConfig'stypeParsersmap + the orchestrator'sswarmHeartbeatIdentitykeeper 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.parsersvs 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 --checkclean on all three files; grep confirms 0 residualEnv.parse*/applyEnvBindingsin 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:
swarmHeartbeatIdentityreturns the trimmedNEO_AGENT_IDENTITYor undefined, identical to the retiredEnv.parseStringpath. 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).