LearnNewsExamplesServices
Frontmatter
id12103
titleStage 1: BaseConfig extends state.Provider + Option F 5-sub-point contract
stateClosed
labels
enhancementaiarchitecture
assigneesneo-opus-ada
createdAtMay 27, 2026, 10:13 PM
updatedAtMay 29, 2026, 11:35 AM
githubUrlhttps://github.com/neomjs/neo/issues/12103
authorneo-opus-ada
commentsCount1
parentIssue12101
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 29, 2026, 11:35 AM

Stage 1: BaseConfig extends state.Provider + Option F 5-sub-point contract

Closed v13.0.0/archive-v13-0-0-chunk-14 enhancementaiarchitecture
neo-opus-ada
neo-opus-ada commented on May 27, 2026, 10:13 PM

Parent: Epic #12101 · Stage 1 of 7 · Depends on: none (foundation) · Blocks: #12104 (Stage 2); transitively the #12105 / #12106 codemods.

What

Build a new ai/BaseConfig.mjs that extends Neo.state.Provider (Body-tier reactive substrate), replacing the current hand-rolled Neo.core.Base + standalone createConfigProxy (which never properly extended Provider). This is the architectural choke point for the meta-leaf migration: Stages 2–6 consume this contract.

The 5-sub-point Option F contract (epic AC-Epic-3)

  1. set(path, value) — explicit mutation API; routes through Provider's setData(path, value)internalSetData (Provider.mjs:497, the single write funnel).
  2. setEnvOverride(path, value) — env-layer write into a private #runtimeEnvOverrides Map; takes precedence over a leaf's default at compile/read time.
  3. observeConfig(path, fn) → cleanup — path-scoped reactive subscription returning a cleanup fn (built on the per-leaf Neo.core.Config.subscribe; full effect-system integration is explicitly out of scope per the epic).
  4. Direct assignment via Provider's set trapaiConfig.data.x.y = z routes to setData through createHierarchicalDataProxy's set trap (createHierarchicalDataProxy.mjs:81); preserves 157+ existing test mutation sites without rewrite (per @neo-gemini-pro V-B-A).
  5. compileMetaLeaves(tree) — compiles the single meta-leaf tree ({env, default, parse} per leaf, Stage 2 shape) into (a) the data defaults object and (b) the separate #leafMetadataRegistry, applying env-overlay-merge against process.env + #runtimeEnvOverrides.

Acceptance Criteria

  • AC1 — extend, don't reinvent (AC-Epic-1): BaseConfig extends Neo.state.Provider; no parallel reactivity machinery. Reuse Neo.util.Env parsers (parseBool / parseNumber / parsePort / parseKeepAlive / parseString / parseUrl) — V-B-A confirmed no competing parser/validation layer exists in src/state / src/core.
  • AC2 — parser-validation at the internalSetData() choke point (AC-Epic-5): override internalSetData with the metadata-path-first rule — validate/coerce ANY value at a known leaf path (looked up in #leafMetadataRegistry); namespace-recursion intermediates pass through unchanged.
  • AC3 — separate #leafMetadataRegistry (AC-Epic-5): the parser/env-var metadata registry is independent of Provider's reactive #dataConfigs (full-dotted-path → Config). Two registries, distinct responsibilities.
  • AC4 — hierarchical deep-merge (AC-Epic-5): via Provider's existing data_: {[isDescriptor]:true, merge:'deep', value:{}} descriptor — no custom merge.
  • AC5 — Body-tier lineage cited (AC-Epic-4): the implementation PR cites #6131 (base class) / #6965 + #6973 (createHierarchicalDataProxy) / #6974 (Effect reactivity) / #6981 (set-trap→setData) / #6985 (deep-merge data_).
  • AC6 — Option F mutation surface (AC-Epic-3): all 5 sub-points implemented + unit-tested, including a direct-assignment test that proves the set-trap path.

Contract Ledger

Surface Consumer Contract Verification
BaseConfig class Stage 2 template + all aiConfig readers extends Neo.state.Provider; AiConfig.X.Y direct read at point of use unit: instance instanceof Neo.state.Provider
set(path,value) / setEnvOverride(path,value) Stage 3 / 4 codemod sites mutation API → internalSetData; env layer wins over default unit: set→read roundtrip + env-precedence assertion
observeConfig(path,fn) reactive consumers path-scoped subscription returning cleanup fn unit: fires on change; cleanup stops firing
direct assignment data.x = y 157+ test mutation sites set-trap → setData unit: direct-assignment routes through validation
compileMetaLeaves(tree) Stage 2 meta-leaf tree tree → data defaults + #leafMetadataRegistry; env-overlay-merge unit: compile prototype tree, assert both outputs

Dependency chain (for downstream tickets)

  • #12104 (Stage 2) consumes the compileMetaLeaves meta-leaf tree shape from this ticket's PR (number TBD on open).
  • #12105 (Stage 3) / #12106 (Stage 4) codemods consume the set / setEnvOverride / direct-assignment surface + the AiConfig.X.Y read path from this ticket's PR.

Discussion #12100 criteria linkage

Stage-1 ACs trace to Discussion #12100 §9 Criterion 4 (OQ9 21-leaf prototype validated compileTree end-to-end) + the three STEP_BACK-convergence Stage-1 ACs (parser-validation choke point + separate metadata registry + hierarchical deep-merge), preserved per Discussion #12100's ## Discussion Criteria Mapping.

tobiu referenced in commit 1b378a0 - "feat(ai): aiConfig meta-leaf tree + Provider-based BaseConfig (#12103) (#12164) on May 29, 2026, 11:35 AM
tobiu closed this issue on May 29, 2026, 11:35 AM