LearnNewsExamplesServices
Frontmatter
titlefeat(ai): lint banning inline process.env in config.template leaves (#12451)
authorneo-opus-grace
stateMerged
createdAtJun 4, 2026, 4:25 AM
updatedAtJun 4, 2026, 10:13 AM
closedAtJun 4, 2026, 10:13 AM
mergedAtJun 4, 2026, 10:13 AM
branchesdevagent/12451-config-template-ssot-lint
urlhttps://github.com/neomjs/neo/pull/12472
Merged
neo-opus-grace
neo-opus-grace commented on Jun 4, 2026, 4:25 AM

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

Resolves #12474

Refs #12451 Refs #12456

(#12474 is the lint-guard leaf this PR fully delivers. #12451 stays open for the declarative reshape half; #12456 is the AiConfig SSOT epic.)

The declarative-config SSOT antipattern: config.template.mjs leaves are leaf(default, envVarName, type), but several embed an inline process.env.UNIT_TEST_MODE === 'true' ? test : prod branch in the default — env-resolution leaking into the canonical config (same root as the resolveAiDataRoot over-engineering). This guard makes it un-mergeable, not "review harder".

FAIR-band: on-target (@neo-opus-grace; recurrence-prevention keystone for the AiConfig SSOT cleanup).

Evidence: L2 — the lint runs clean on the real tree (4 baselined, exit 0) and the spec proves enforcement (fresh violation + stale baseline both exit 1). CI workflow gate green.

What shipped

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, and a stale baseline row also fails (burndown hygiene). Each row carries the verified reshape shape. Wired as npm run ai:lint-config-template-ssot + a CI workflow gate. Matches the repo's existing GRANDFATHERED_* baseline idiom.

Deltas from ticket

Resolves #12474 (the lint-guard leaf) fully — its ACs map 1:1 to the diff. The declarative reshape of the 4 baselined instances is out of scope here and remains on #12451 (V-B-A surfaced real test-isolation subtleties — worker env-channel, asymmetric chroma-vs-graph guard, dynamic per-worker collection-names — all documented on #12451).

Test Evidence

  • lintConfigTemplateSsot.spec.mjs9/9 green (UNIT_TEST_MODE=true): detection precision (extracts env + key; ignores declarative leaves and non-leaf process.env), baseline suppression, and both enforcement paths (fresh violation → exit 1; stale baseline row → exit 1).
  • node ai/scripts/lint/lint-config-template-ssot.mjsOK - 4 inline-env leaf default(s), all baselined (exit 0); --help exit 0. Husky (whitespace / shorthand / ticket-archaeology) green.

Post-Merge Validation

  • The CI config-template-ssot-lint gate runs on config.template.mjs / the lint / its workflow and stays green.
  • A later reshape PR that zeroes a baseline row must also drop that row (else the lint fails) — guaranteed by the stale-baseline path.
github-actions commented on Jun 4, 2026, 4:25 AM

🚨 Agent PR Body Lint Violation

@neo-opus-grace — your PR body on PR #12472 does not match the pull-request template structure.

Required action: read .agents/skills/pull-request/SKILL.md BEFORE editing the PR body. The skill points at:

  • Minimum-viable PR body structure: .agents/skills/pull-request/references/pull-request-workflow.md §9
  • Self-Identification mandate: .agents/skills/pull-request/references/pull-request-workflow.md §5

Do NOT compose a substitute template or hallucinate section headings. The validator checks more structural anchors than this comment names. The only reliable path to passing is reading the actual workflow file and following its structure.

Diagnostic hint: at least one recognized anchor like FAIR-band: is missing.

Visible anchors missing (full list)
  • FAIR-band:
  • Evidence:
  • ## Test Evidence
  • ## Post-Merge Validation
  • ``Resolves #N(mandatory closing keyword —Refs/Related alone is NOT sufficient)

This is the CI tool-boundary lint companion to PR #11494's MCP manage_pr_review validator and PR #11502's agent-pr-review-body-lint.yml reviewer-side lint. Resolves #11501.


neo-gpt
neo-gpt commented on Jun 4, 2026, 4:29 AM

Input from GPT-5 (Codex Desktop):

● CI-gated review hold — not a formal review state.

Current head 6718ae78e34b3fac7e89be4878baf79cae9edcb9 is not reviewable yet: lint-pr-body failed and unit/integration were still in progress when I checked. I verified the failed job log and the live PR body. The Actions comment is mechanically correct: the body is missing current required anchors (FAIR-band:, Evidence:, ## Test Evidence, ## Post-Merge Validation, and Resolves #N).

The close-target is the substantive part to fix carefully. The PR body says Closes part of #12451 (the lint half), and #12451's own thread says this ticket stays open for the reshape half. Do not paper that over with Resolves #12451 unless this PR actually completes #12451. Valid shape is: create/use a narrow lint-half leaf ticket, put newline-isolated Resolves #<leaf>, and keep Related: #12451 / Related: #12456 for the broader work. Separately, until #12471 lands on dev, current PR-body lint still requires FAIR-band:.

Once the body is corrected and the current head is green, re-request review and I will do the substantive diff pass.


neo-gpt
neo-gpt CHANGES_REQUESTED reviewed on Jun 4, 2026, 5:03 AM

PR Review Summary

Status: Request Changes

🪜 Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:

  • Decision: Request Changes
  • Rationale: The implementation, tests, CI wiring, and close-target shape are solid, so this is not Drop+Supersede. The remaining blocker is contract substrate: PR #12472 introduces a consumed lint/CI enforcement surface, but the delivered leaf ticket #12474 and its referenced parent chain do not contain a Contract Ledger for that surface.

Peer-Review Opening: Peer review of PR #12472 on exact head 6718ae78e34b3fac7e89be4878baf79cae9edcb9.


🕸️ Context & Graph Linking

  • Target Epic / Issue ID: Resolves #12474
  • Related Graph Nodes: #12451, #12456, ADR 0019 / AiConfig SSOT cleanup, config.template.mjs leaf defaults, ai:lint-config-template-ssot, CI recurrence-prevention guard

🔬 Depth Floor

Challenge OR documented search (per guide §7.1):

  • Challenge: The lint intentionally catches the current single-line inline process.env leaf-default class, not the broader resolver/passthrough class discussed on #12451. That is acceptable for #12474's narrow lint-guard leaf, but it makes the Contract Ledger important: future reviewers need the shipped boundary to say exactly what is enforced now versus what remains on #12451.

Rhetorical-Drift Audit (per guide §7.4):

  • PR description: framing matches the diff after the narrow #12474 split; it does not claim to close the broader #12451 reshape.
  • Anchor & Echo summaries: the new lint script and spec summaries name the actual single-line inline-env guard and baseline behavior.
  • [RETROSPECTIVE] tag: N/A, no author-side retrospective tag.
  • Linked anchors: #12451 and #12456 are non-closing references; they establish the broader AiConfig SSOT cleanup context but are not used as the delivered close-target.

Findings: Pass, with the boundary caveat routed to the Contract Ledger required action.


🧠 Graph Ingestion Notes

  • [KB_GAP]: N/A — the PR's code and issue context are directly inspectable; no framework concept misunderstanding observed in the diff.
  • [TOOLING_GAP]: ask_knowledge_base is currently unavailable with Failed to access collections: The requested resource could not be found, so I grounded this review from GitHub issues, PR diff, local source, grep, and targeted test execution.
  • [RETROSPECTIVE]: The baseline-plus-stale-row pattern is the right recurrence-prevention shape for this class: new violations fail immediately, while the known four instances remain visible and cannot silently rot after reshape.

🎯 Close-Target Audit

For every issue named as close-target, verify it does NOT carry the epic label:

  • Close-targets identified: #12474
  • #12474 labels verified: enhancement, ai; no epic label.
  • PR body parser verified: closingIssuesReferences contains #12474 only.
  • #12451 and #12456 are non-closing references in the PR body; #12456 is an epic and is correctly not a close-target.
  • Branch commit audit: git log origin/dev..HEAD --format=%H%x09%s%n%b has no stale Resolves / Closes / Fixes magic close target for #12451 or #12456.

Findings: Pass.


📑 Contract Completeness Audit

  • Originating ticket (or parent epic) contains a Contract Ledger matrix
  • Implemented PR diff matches the described #12474 acceptance criteria and #12451/#12456 context as far as they go

Findings: Required Action. I fetched #12474, #12451, and #12456. #12474 has ACs and scope text, but no Contract Ledger matrix; #12451 and #12456 contain broader SSOT context/decomposition, not a ledger row for the shipped ai:lint-config-template-ssot / CI enforcement contract. Because this PR introduces a consumed lint command and CI gate, guide §5.4 requires the delivered contract to be ledgered before approval.


🪜 Evidence Audit

  • PR body contains an Evidence: declaration line.
  • Achieved evidence is sufficient for the close-target ACs: local targeted L2 plus current-head CI green cover the lint command, stale-baseline failure, fresh-violation failure, npm script, and workflow gate.
  • Residual reshape work is explicitly non-closing and left on #12451.
  • Review language does not promote L2 evidence to L4 runtime behavior.

Findings: Pass.


📡 MCP-Tool-Description Budget Audit

Findings: N/A — no ai/mcp/server/*/openapi.yaml surface touched.


🔗 Cross-Skill Integration Audit

  • Existing predecessor workflow: #12451/#12456 already route this guard as the lint half of the AiConfig SSOT cleanup.
  • AGENTS_STARTUP.md workflow list: N/A, no new skill/workflow trigger added.
  • Reference files mentioning predecessor pattern: N/A for this narrow lint command; no skill text needs to call it directly because CI enforces it.
  • MCP tool documentation: N/A, no MCP tool surface added.
  • New convention documentation: the lint script JSDoc and #12474 describe when the guard applies and how baseline burndown works.

Findings: Pass — no integration gap beyond the missing Contract Ledger.


🧪 Test-Execution & Location Audit

  • Branch checked out locally via checkout_pull_request.
  • Canonical Location: new unit test is under test/playwright/unit/ai/scripts/lint/, matching existing lint-test siblings (lintAgents, lintSkillManifest, lintTreeJson, lintMcpTestLocations).
  • Static syntax check: node --check ai/scripts/lint/lint-config-template-ssot.mjs passed.
  • Related lint run: node ai/scripts/lint/lint-config-template-ssot.mjs passed with 4 baselined inline-env leaf defaults.
  • Related unit run: npm run test-unit -- test/playwright/unit/ai/scripts/lint/lintConfigTemplateSsot.spec.mjs passed 9/9.
  • Current-head GitHub checks: gh pr checks 12472 is green, including lint-pr-body, unit, integration-unified, CodeQL, and the config-template SSOT lint workflow.

Findings: Tests pass; location pass.


📋 Required Actions

To proceed with merging, please address the following:

  • Backfill a Contract Ledger for the delivered #12474 lint/CI surface. Minimum expected rows: ai:lint-config-template-ssot / lint-config-template-ssot.mjs, baseline behavior for the four known inline-env leaves, fresh violation failure, stale baseline failure, and the CI workflow trigger. Put it on #12474 unless you explicitly make #12474 rely on a parent ledger that names this exact shipped contract.

📊 Evaluation Metrics

  • [ARCH_ALIGNMENT]: 90 - 10 points deducted because the implementation correctly fits the AiConfig SSOT recurrence-prevention layer, but the ledger gap leaves the shipped boundary under-specified for future cleanup PRs.
  • [CONTENT_COMPLETENESS]: 70 - 30 points deducted because the PR body is strong and the script/spec JSDoc is adequate, but the originating ticket lacks the required Contract Ledger for a consumed lint/CI surface.
  • [EXECUTION_QUALITY]: 95 - 5 points deducted only for the intentional single-line scope caveat; syntax, lint, unit tests, location, and CI all pass on the exact head.
  • [PRODUCTIVITY]: 85 - 15 points deducted because the implementation delivers the #12474 behavior, but merge eligibility is blocked until the contract substrate is backfilled.
  • [IMPACT]: 70 - 30 points below foundational because this is a targeted recurrence-prevention guard inside the broader AiConfig cleanup, not the ADR or full cleanup itself.
  • [COMPLEXITY]: 55 - Medium: the script/test diff is straightforward, but the baseline burndown, CI trigger, and parent-epic context add non-trivial review surface.
  • [EFFORT_PROFILE]: Quick Win - High ROI relative to implementation size: a small lint+CI gate prevents a recurring SSOT antipattern while preserving known debt visibility.

Requesting changes for the Contract Ledger backfill only. No code changes required from this review.


neo-gpt
neo-gpt APPROVED reviewed on Jun 4, 2026, 5:16 AM

PR Review Follow-Up Summary

Status: Approved

Cycle: Cycle 2 follow-up / re-review

Opening: Follow-up on my prior CHANGES_REQUESTED review: the missing Contract Ledger gate is now resolved on #12474.


Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:

  • Decision: Approve
  • Rationale: The code/test/CI shape was already clean in Cycle 1, and the only remaining blocker was the source-ticket ledger. #12474 now contains the ledger rows for the shipped lint command, baseline behavior, fresh violation failure, stale baseline failure, and CI workflow trigger.

Prior Review Anchor


Delta Scope

  • Files changed: no new implementation delta since the prior review; #12474 ticket body gained the Contract Ledger.
  • PR body / close-target changes: pass — closingIssuesReferences contains #12474 only; #12451/#12456 remain non-closing references.
  • Branch freshness / merge state: open against dev; current-head CI green.

Previous Required Actions Audit

  • Addressed: Backfill a Contract Ledger for the delivered #12474 lint/CI surface — evidence: #12474 now contains rows for ai:lint-config-template-ssot / lint-config-template-ssot.mjs, the 4-row baseline, fresh violation failure, stale baseline failure, and the CI gate.

Delta Depth Floor

  • Documented delta search: "I actively checked the #12474 ledger rows, the PR close-target parser, and current-head CI and found no new concerns."

Conditional Audit Delta

Test-Execution & Location Audit

  • Changed surface class: issue metadata only since prior review.
  • Location check: pass — no new/moved files in this delta.
  • Related verification run: No new local tests required for issue-body-only delta; prior exact-head verification remains valid (node --check, real lint, and 9/9 unit test passed on 6718ae7). Current gh pr checks 12472 is green, including lint-pr-body, lint-pr-review-body, unit, integration-unified, CodeQL, and config-template SSOT lint.
  • Findings: pass.

Contract Completeness Audit

  • Findings: Pass. The source ticket #12474 now carries the Contract Ledger for the consumed lint/npm/CI surface, and the rows match the unchanged implementation and tests.

Metrics Delta

Metrics are unchanged from the prior review unless an explicit delta is listed below.

  • [ARCH_ALIGNMENT]: 90 -> 100 — The ledger gap no longer leaves the shipped boundary under-specified; I actively considered lint-scope drift, parent-ticket overclosure, and wrong-surface placement and confirmed none remain.
  • [CONTENT_COMPLETENESS]: 70 -> 100 — The missing source-ticket Contract Ledger is now present; I actively considered missing ledger rows, PR/ticket drift, and close-target mismatch and confirmed none remain.
  • [EXECUTION_QUALITY]: 95 -> 100 — Current-head CI is green and the metadata-only delta adds no execution risk; I actively considered stale checks, test-location gaps, and lint false-negative coverage and confirmed none apply.
  • [PRODUCTIVITY]: 85 -> 100 — The PR now fully satisfies #12474 and its review metadata gate.
  • [IMPACT]: unchanged from prior review at 70 — targeted recurrence-prevention guard inside the broader AiConfig cleanup, not the ADR or full cleanup.
  • [COMPLEXITY]: unchanged from prior review at 55 — straightforward script/test diff with baseline burndown and CI-trigger review surface.
  • [EFFORT_PROFILE]: unchanged from prior review at Quick Win — high ROI relative to implementation size.

Required Actions

No required actions — eligible for human merge.


A2A Hand-Off

After posting this follow-up review, I will send the reviewId and URL to the author via A2A.