Context
Operator-approved quick win from the #13938 ADR-19 correction loop.
On 2026-06-23, #13938 still contained this ADR-19 B2/B5-shaped pattern after review preparation:
bridgeConfig = AiConfig.orchestrator.deploymentStateBridge,
limit = Math.max(0, Number(bridgeConfig.recoveryRunLimit) || 0)
The operator correctly challenged why this keeps recurring. Live V-B-A found that the turn-loaded rule already exists in AGENTS.md, but it is too soft for the observed failure mode:
AGENTS.md is 24,473 bytes; hard 24 KiB cap is 24,576 bytes; only 103 bytes remain.
- Current
AGENTS.md line 185 points to ADR 0019 and says to read resolved leaves, but it does not front-load the concrete recurring mistake: subtree aliases/destructuring and config pass-through.
learn/agentos/AGENTS_ATLAS.md does not carry a deeper AiConfig entry; ADR 0019 is the maintainer payload.
ai/scripts/lint/lint-config-template-ssot.mjs currently catches config-template inline env-default violations, not B2/B5 implementation aliases/pass-throughs.
Release classification: boardless quick win; this reduces future review churn but is not a deployment gate.
The Problem
ADR 0019 is loaded, but agents still miss it because the turn-loaded trigger reads like a reference note. The exact recurring code smell is not made visually loud enough before code/review starts.
Relying on reviewer memory has already failed. ADR 0019 itself documents that careful review missed the AiConfig antipattern cluster, so this should be made more mechanical: a sharper 24 KiB-safe AGENTS trigger plus lint coverage for the B2/B5 class.
The Architectural Reality
Authority:
- ADR 0019:
learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.md
- Turn-loaded trigger:
AGENTS.md line 185
- Current lint:
ai/scripts/lint/lint-config-template-ssot.mjs
- Existing owning epic: #12456
- Separate existing B4 leaf: #12435
ADR 0019 already defines the relevant banned patterns:
- B2:
const X = AiConfig.Y pointers; sanctioned form is inline leaf reads except legitimate high-reuse local scope.
- B5: passing AiConfig values/config-shaped objects into consumers; sanctioned form is consumer reads the leaf directly, except explicitly named ADR-19 bootstrap boundaries.
- B3/B4/A1 remain relevant guardrails, but this quick win is driven by the B2/B5 recurrence.
The Fix
- Replace the current
AGENTS.md AiConfig bullet with a shorter, louder trigger that fits under the 24 KiB cap. Proposed wording:
- **AiConfig / ADR-0019 (`ai/` config touch):** STOP before code/review: read `learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.md`. `AiConfig` is the reactive SSOT; read resolved leaves inline. Forbidden unless an ADR-19 boundary is named: subtree aliases/destructure (`const xConfig = AiConfig...`), config pass-through, re-derive/env-read, defensive `?.`, runtime mutation.
This is about 27 characters shorter than the current line and makes the #13938 mistake visible at turn start.
- Extend ADR-19 lint coverage with a focused implementation-file detector for new B2/B5-shaped regressions in
ai/:
const <name>Config = AiConfig.<subtree> / destructuring from AiConfig.<subtree>
- exported config values/subtrees from
AiConfig
- obvious config-shaped pass-throughs where a consumer is handed values derived from
AiConfig
Keep the detector conservative enough to avoid false-positive noise. Allow explicitly documented ADR-19 boundaries or baselines only where needed.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
AGENTS.md AiConfig trigger |
ADR 0019 + ADR 0007 compaction taxonomy |
Compact STOP-style trigger names B2/B5 failure shape while staying under 24 KiB |
If wording grows, compress elsewhere or do not merge |
AGENTS.md, ADR 0019 |
byte-count check |
| ADR-19 lint |
ADR 0019 §3/§5 |
Detect new B2/B5 implementation aliases/pass-throughs in ai/ |
conservative baseline for existing debt, if any |
lint JSDoc + tests |
lint unit tests + preflight |
| Agent PR/review behavior |
#12456 |
Fail earlier on AiConfig alias/pass-through before review cycles |
reviewer still reads ADR 0019 for nuanced boundary cases |
PR body evidence |
targeted regression fixture mirroring #13938 pattern |
Decision Record impact
Depends-on ADR 0019. Aligned-with ADR 0007 because the AGENTS.md change must be byte-neutral or byte-negative under the 24 KiB cap.
Acceptance Criteria
Out of Scope
- Rewriting ADR 0019.
- Full cleanup of every historical AiConfig SSOT antipattern under #12456.
- The B4 shared-singleton mutation work tracked by #12435.
- Adding more AGENTS.md bytes without offsetting compression.
Avoided Traps
- Do not append another reminder to AGENTS.md; the file only has about 103 bytes of headroom.
- Do not rely on reviewer diligence; ADR 0019 exists because that already failed.
- Do not make the lint so broad that it blocks legitimate ADR-19 bootstrap boundaries or pure-defaults helpers.
Related
Parent: #12456.
Related: #12435, #13938, ADR 0019, ADR 0007.
Live latest-open sweep: checked latest 25 open issues on 2026-06-23; no equivalent leaf found. Existing #12456 is the owning epic; #12435 is the separate B4 mutation leaf.
A2A in-flight claim sweep: list_messages({status: 'all', limit: 30}) returned 0 messages.
Semantic/local sweep: Knowledge Base and rg confirmed ADR 0019 + current AGENTS trigger; no existing B2/B5 lint leaf found.
Origin Session ID: 02b1972b-2925-4458-89c7-287df50c726e
Retrieval Hint: ADR 0019 AiConfig AGENTS trigger lint B2 B5 alias pass-through
Context
Operator-approved quick win from the #13938 ADR-19 correction loop.
On 2026-06-23, #13938 still contained this ADR-19 B2/B5-shaped pattern after review preparation:
bridgeConfig = AiConfig.orchestrator.deploymentStateBridge, limit = Math.max(0, Number(bridgeConfig.recoveryRunLimit) || 0)The operator correctly challenged why this keeps recurring. Live V-B-A found that the turn-loaded rule already exists in
AGENTS.md, but it is too soft for the observed failure mode:AGENTS.mdis 24,473 bytes; hard 24 KiB cap is 24,576 bytes; only 103 bytes remain.AGENTS.mdline 185 points to ADR 0019 and says to read resolved leaves, but it does not front-load the concrete recurring mistake: subtree aliases/destructuring and config pass-through.learn/agentos/AGENTS_ATLAS.mddoes not carry a deeper AiConfig entry; ADR 0019 is the maintainer payload.ai/scripts/lint/lint-config-template-ssot.mjscurrently catches config-template inline env-default violations, not B2/B5 implementation aliases/pass-throughs.Release classification: boardless quick win; this reduces future review churn but is not a deployment gate.
The Problem
ADR 0019 is loaded, but agents still miss it because the turn-loaded trigger reads like a reference note. The exact recurring code smell is not made visually loud enough before code/review starts.
Relying on reviewer memory has already failed. ADR 0019 itself documents that careful review missed the AiConfig antipattern cluster, so this should be made more mechanical: a sharper 24 KiB-safe AGENTS trigger plus lint coverage for the B2/B5 class.
The Architectural Reality
Authority:
learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.mdAGENTS.mdline 185ai/scripts/lint/lint-config-template-ssot.mjsADR 0019 already defines the relevant banned patterns:
const X = AiConfig.Ypointers; sanctioned form is inline leaf reads except legitimate high-reuse local scope.The Fix
AGENTS.mdAiConfig bullet with a shorter, louder trigger that fits under the 24 KiB cap. Proposed wording:- **AiConfig / ADR-0019 (`ai/` config touch):** STOP before code/review: read `learn/agentos/decisions/0019-aiconfig-reactive-provider-ssot.md`. `AiConfig` is the reactive SSOT; read resolved leaves inline. Forbidden unless an ADR-19 boundary is named: subtree aliases/destructure (`const xConfig = AiConfig...`), config pass-through, re-derive/env-read, defensive `?.`, runtime mutation.This is about 27 characters shorter than the current line and makes the #13938 mistake visible at turn start.
ai/:const <name>Config = AiConfig.<subtree>/ destructuring fromAiConfig.<subtree>AiConfigAiConfigKeep the detector conservative enough to avoid false-positive noise. Allow explicitly documented ADR-19 boundaries or baselines only where needed.
Contract Ledger Matrix
AGENTS.mdAiConfig triggerAGENTS.md, ADR 0019ai/Decision Record impact
Depends-on ADR 0019. Aligned-with ADR 0007 because the AGENTS.md change must be byte-neutral or byte-negative under the 24 KiB cap.
Acceptance Criteria
AGENTS.mdAiConfig trigger is rewritten to explicitly say STOP before code/review and name subtree alias/destructure/pass-through as forbidden unless an ADR-19 boundary is named.AGENTS.mdremains under 24 KiB after the rewrite.const xConfig = AiConfig.../bridgeConfig = AiConfig...alias regression in implementation code.npm run ai:lint-config-template-ssotor the successor lint command remains wired through the existing preflight path.Out of Scope
Avoided Traps
Related
Parent: #12456. Related: #12435, #13938, ADR 0019, ADR 0007.
Live latest-open sweep: checked latest 25 open issues on 2026-06-23; no equivalent leaf found. Existing #12456 is the owning epic; #12435 is the separate B4 mutation leaf. A2A in-flight claim sweep:
list_messages({status: 'all', limit: 30})returned 0 messages. Semantic/local sweep: Knowledge Base andrgconfirmed ADR 0019 + current AGENTS trigger; no existing B2/B5 lint leaf found.Origin Session ID: 02b1972b-2925-4458-89c7-287df50c726e Retrieval Hint:
ADR 0019 AiConfig AGENTS trigger lint B2 B5 alias pass-through