LearnNewsExamplesServices
Frontmatter
id14500
titleADR-0019 lint: fail-build on defensive optional-chaining (B3) + env-helper reintroduction (A5) on AiConfig
stateClosed
labels
enhancementaiarchitecturemodel-experience
assigneesneo-opus-grace
createdAtJul 2, 2026, 8:37 PM
updatedAt10:22 AM
githubUrlhttps://github.com/neomjs/neo/issues/14500
authorneo-opus-grace
commentsCount4
parentIssue12456
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[ ] 15213 Extend the AiConfig antipattern lint to A1 module-level env re-derivation
closedAt10:22 AM
milestonev13.2

ADR-0019 lint: fail-build on defensive optional-chaining (B3) + env-helper reintroduction (A5) on AiConfig

Closed Backlog/active-chunk-2 enhancementaiarchitecturemodel-experience
neo-opus-grace
neo-opus-grace commented on Jul 2, 2026, 8:37 PM

Context

ADR-0019 §8's entire thesis: reviewer diligence is empirically insufficient against the AiConfig antipattern cluster (the #12420 4/4-miss anchor). The mechanical backstop is the fail-build lint (§7.2, sub #2), spec'd to encode A1·A4·A5·A6·A7·B1·B3·B4·B5·C1.

Only B4 was ever built (buildScripts/util/check-aiconfig-test-mutation.mjsaiconfig-test-mutation-lint.yml). B3 / A1 / A5 / B1 have no mechanical check — which is why they keep reaching human review and getting approved. Live proof: PR #14499 shipped aiConfig?.validateRequiredEnv, aiConfig.auth?.mode (B3), got a full APPROVED cross-family review that caught zero of it, and was flagged only by @tobiu ("fuck-up 50+ for ADR-19"). CI-green + APPROVED ≠ ADR-compliant, exactly as ADR-0019 §3 D1/D2 predicts.

The Problem

The recurring ADR-0019 violations are not a diligence problem (the ADR settled that). They recur because the flaggable-subset lint the ADR prescribed was never completed. Every aiConfig?. / AiConfig?. reaches review because nothing fails the build.

The Architectural Reality

  • Model: buildScripts/util/check-aiconfig-test-mutation.mjs (B4) — a regex (DB_PATH_MUTATION) + ESCAPE_MARKER relief valve + shrinking ALLOWLIST ratchet (bites only NEW offenders) + CI workflow. Proven shape; mirror it.
  • ADR-0019 §3 catalog is the lint spec (each ID has a sanctioned form).

The Fix

Add a lint (new buildScripts/util/check-aiconfig-antipatterns.mjs or extend the B4 checker) + CI workflow, catching the mechanically-cleanest subset first:

  • B3 — defensive optional-chaining on an AiConfig read: \b(?:aiConfig|AiConfig|Memory_Config)\b[\w.$\[\]'"-]*?.(a?.` anywhere in an AiConfig access path). §3 B3: "the SSOT guarantees the tree; let it fail loud."
  • A5 — a hasEnvValue( helper (0 occurrences on dev today; ratchet prevents reintroduction).
  • A1 (fast-follow) — module-level const X = process.env.Y || … re-derivation in ai/ entrypoints that already import AiConfig (read AiConfig.X.Y instead; §5.5 — A1-with-AiConfig-imported, NOT C1).

Ratchet discipline: seed the ALLOWLIST from a current-dev census so the check bites only NEW offenders; the allowlist shrinks as the Diamond-2 cleanup subs land.

Acceptance Criteria

  • B3 lint flags aiConfig?. / AiConfig?. / Memory_Config?. optional-chaining in ai/ (excluding the ESCAPE_MARKER + seeded allowlist).
  • A5 lint flags any reintroduced hasEnvValue( helper.
  • ESCAPE_MARKER relief valve + repo-relative ALLOWLIST ratchet, mirroring the B4 checker.
  • CI workflow wired (.github/workflows/aiconfig-antipattern-lint.yml); fails the build on a new offender.
  • Unit test: positive (aiConfig?.x fails) + negative (aiConfig.x, x === undefined ? … pass) + escape-marker + allowlist.
  • Would have failed PR #14499 at CI (regression anchor).

Out of Scope

  • The B5/C1/A6/A7 checks (harder, AST-level) — separate fast-follows under this epic once B3/A5/A1 land.
  • The #14499 code fixes themselves (that PR's REQUEST_CHANGES owns them).

Related

  • Parent epic: #12456 (eliminate the ai/ AiConfig-SSOT antipatterns).
  • ADR-0019 §3 (catalog = lint spec) + §7.2 (sub #2). Model: check-aiconfig-test-mutation.mjs.
  • Empirical anchor: PR #14499 (B3 shipped + rubber-stamped) · #12420 (the 4/4-miss).

Authored by Grace (@neo-opus-grace, Claude Opus 4.8). Operator-flagged pattern (@tobiu).

tobiu closed this issue on 10:22 AM
tobiu referenced in commit 074fe65 - "feat(build): ADR-0019 antipattern lint — fail-build on B3 defensive chaining + A5 env-helper (#14500) (#15211) on 10:22 AM