LearnNewsExamplesServices
Frontmatter
id12474
titleconfig.template.mjs SSOT lint: ban inline process.env in leaf defaults (+ baseline)
stateClosed
labels
enhancementai
assignees[]
createdAtJun 4, 2026, 4:53 AM
updatedAtJun 4, 2026, 10:13 AM
githubUrlhttps://github.com/neomjs/neo/issues/12474
authorneo-claude-opus
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 4, 2026, 10:13 AM

config.template.mjs SSOT lint: ban inline process.env in leaf defaults (+ baseline)

Closed Backlog/active-chunk-17 enhancementai
neo-claude-opus
neo-claude-opus commented on Jun 4, 2026, 4:53 AM

Context

config.template.mjs is the declarative config SSOT — each value is leaf(default, envVarName, type). Several leaves embed imperative process.env.UNIT_TEST_MODE === 'true' ? test : prod branching in the default expression — env-resolution leaking into the canonical config (the same root as the resolveAiDataRoot over-engineering). Reviews can't reliably catch this class.

This is the lint-guard half of #12451 (which also covers the declarative reshape of the existing instances). Split per the 1-PR-per-ticket close-target contract (#12367): this leaf is fully delivered by PR #12472; #12451 stays open for the reshape.

The Fix (delivered in PR #12472)

ai/scripts/lint/lint-config-template-ssot.mjs — bans inline process.env reads in leaf() defaults across every config.template.mjs under ai/. Lands enforcing via a frozen BASELINE of the 4 known instances (NEW occurrences fail; the historical debt burns down; a stale baseline row also fails — burndown hygiene). Wired as npm run ai:lint-config-template-ssot + a CI gate. Matches the repo's existing GRANDFATHERED_* baseline idiom.

Contract Ledger

Target Surface Source of Authority Enforced Behavior Fallback Docs Evidence
ai:lint-config-template-ssot / lint-config-template-ssot.mjs the lint script scans every config.template.mjs under ai/; flags inline process.env in a leaf() default env access must use the leaf env-var-name arg script JSDoc node ai/scripts/lint/lint-config-template-ssot.mjsOK - 4 baselined (exit 0)
Baseline (4 known inline-env leaves) BASELINE frozen array the 4 historical instances are suppressed so the build stays green; each row carries its reshape shape BASELINE JSDoc spec: a baselined violation is suppressed
Fresh (unbaselined) violation lintConfigTemplateSsot().newViolations a NEW inline-env leaf default → exit 1 (un-mergeable) leaf(default, 'ENV', type) + relocate the test branch to the test layer FIX_HINT spec: a fresh violation fails → exit 1
Stale baseline row lintConfigTemplateSsot().staleBaseline a baseline row with no live violation (reshape landed) → exit 1 drop the row report message spec: a stale baseline row fails → exit 1
CI gate .github/workflows/config-template-ssot-lint.yml runs the lint on PRs/pushes touching config.template.mjs / the lint / its workflow workflow file workflow + lint-pr-body green on PR #12472

Acceptance Criteria

  • Lint flags any inline process.env in a config.template.mjs leaf default; the 4 known instances are baselined so the build stays green. (PR #12472)
  • A NEW inline-env leaf default fails the lint (enforcing). (spec)
  • A stale baseline row (reshape landed, no live violation) fails the lint (burndown hygiene). (spec)
  • Wired as an npm script + a CI workflow gate scoped to config.template.mjs / the lint / its workflow. (PR #12472)

Scope

The lint guard only. The declarative reshape of the 4 existing instances (zeroing the baseline; the dynamic per-worker collection-name case is the harder sub-case) remains on #12451.

Refs #12451 (broader: reshape + lint). Part of Epic #12456 (AiConfig reactive Provider SSOT cleanup).

Origin Session ID: 3ecb40bf-bfef-40b1-8693-a8aae5afa1b7 Authored by Claude Opus 4.8 (Claude Code), /lead-role.

tobiu closed this issue on Jun 4, 2026, 10:13 AM