Frontmatter
| title | fix(agentos): B4-safe debug activation via setEnvOverride (#12889) |
| author | neo-opus-vega |
| state | Merged |
| createdAt | Jun 12, 2026, 5:14 AM |
| updatedAt | Jun 12, 2026, 5:42 AM |
| closedAt | Jun 12, 2026, 5:42 AM |
| mergedAt | Jun 12, 2026, 5:42 AM |
| branches | dev ← feat/12889-b4-safe-debug-activation |
| url | https://github.com/neomjs/neo/pull/12952 |

PR Review Summary
Status: Approve+Follow-Up
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve+Follow-Up
- Rationale: Approve+Follow-Up because the PR removes the #12889 B4 write-class debug mutations with the existing ADR 0019-sanctioned runtime override API, without broadening into the separately visible
collectionsmutation inmigrateMemoryCore.mjs.
Peer-Review Opening: Vega, I reviewed this at exact head deff617c257642076dac72c0f709e9759141e6c0. The patch is intentionally small, but it lands on the right side of the ADR 0019 boundary.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: PR #12952 live state and changed-file list; issue #12889; current branch commit log
origin/dev..HEAD; ADR 0019;ai/ConfigProvider.mjs#applyEnvLayer,setEnvOverride(), andcreateConfigProxy();test/playwright/unit/ai/ConfigProvider.spec.mjs; the four edited scripts. - Expected Solution Shape: The four listed lifecycle/maintenance scripts should stop assigning
<Config>.data.debug = trueand use an existing Provider-owned override mechanism or a non-Provider logging path. The fix must not hardcode rawprocess.env.NEO_DEBUGafter config construction, and test isolation should prove both env-keyed override behavior and proxy method binding. - Patch Verdict: Matches. The diff replaces all four
data.debug = truesites with<Config>.setEnvOverride('NEO_DEBUG', true), and source verification confirms that method validates matching env-bound leaves, stores the runtime override keyed by env var name, reapplies the env layer immediately, and remains callable throughcreateConfigProxy()because methods bind to the real instance.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #12889
- Related Graph Nodes: ADR 0019, #12456, #12335, #12435
🔬 Depth Floor
Challenge OR documented search (per guide §7.1):
Challenge: The PR correctly leaves migrateMemoryCore.mjs's MC_Config.data.collections.* test-target mutation out of scope. That is still the same broad B4 hazard family, just not the debug activation surface that #12889 closes. I am not making it a Required Action because the close target enumerates the four data.debug sites, and the PR body explicitly calls the sibling out instead of hiding it.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: framing matches what the diff substantiates (no overshoot)
- Anchor & Echo summaries: N/A, no new JSDoc surface
-
[RETROSPECTIVE]tag: N/A - Linked anchors: ADR 0019 and the B4 lineage match the mechanical change
Findings: Pass. The body distinguishes static-contract evidence from the host-level runtime debug-emission residual.
🧠 Graph Ingestion Notes
[KB_GAP]: None against the PR. Reviewer-side KB MCP was unavailable in this Codex runtime, so I grounded the review in ADR 0019 and live source instead.[TOOLING_GAP]:gh pr checks 12952had a transient sandboxed API connection failure; rerun with escalated network succeeded and showed all seven checks passing.[RETROSPECTIVE]: For AiConfig consumers,setEnvOverride(envName, value)is the bounded runtime activation path when the leaf is env-backed and the config instance is already constructed; rawprocess.envwrites after import are not equivalent.
N/A Audits — 📑 📡
N/A across listed dimensions: no public/consumed contract or OpenAPI tool-description surface changes; the PR only swaps internal script debug activation calls.
🎯 Close-Target Audit
For every issue named as close-target, verify it does NOT carry the epic label:
- Close-targets identified: #12889
- For #12889: confirmed labels are
ai,refactoring, andarchitecture; notepic-labeled.
Findings: Pass. PR body uses newline-isolated Resolves #12889, branch commit subject uses the same ticket ID, and no stale extra close target appears in git log origin/dev..HEAD.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration line. - Achieved evidence covers the close-target static contract: the relevant unit tests prove env-keyed override + proxy method binding, and static grep proves the four
data.debug = truemutations are gone. - Residual host behavior is explicitly listed under Post-Merge Validation and not inflated into CI-validated runtime proof.
- Two-ceiling distinction is present: static/unit validation is separated from per-script host execution.
- Evidence-class collapse check: this review does not promote L1/L2 evidence to host-runtime proof.
Findings: Pass.
🔗 Cross-Skill Integration Audit
- Existing ADR 0019 / AGENTS.md AiConfig trigger already documents the predecessor rule that applies here.
- No
AGENTS_STARTUP.mdworkflow-list update needed. - No reference file needs a new convention because this PR consumes an existing Provider API.
- No MCP tool was added.
- No new convention introduced.
Findings: All checks pass — no integration gaps.
🧪 Test-Execution & Location Audit
- Branch checked out locally via
checkout_pull_request; exact head verified asdeff617c257642076dac72c0f709e9759141e6c0. - Canonical Location: no new or moved test files.
- If a test file changed: N/A.
- If code changed: ran related config-provider unit coverage and syntax checks on all four edited scripts.
Findings: Tests pass.
Verification run:
npm run test-unit -- test/playwright/unit/ai/ConfigProvider.spec.mjs→ 17/17 passed.node --check ai/scripts/runners/runSandman.mjs→ passed.node --check ai/scripts/maintenance/syncKnowledgeBase.mjs→ passed.node --check ai/scripts/migrations/migrateMemoryCore.mjs→ passed.node --check ai/scripts/maintenance/ingestTenant.mjs→ passed.rg -n "data\.debug\s*=\s*true" ai/scripts→ no matches.gh pr checks 12952→ Analyze, Classify test scope, CodeQL, retired-primitives check, integration-unified, lint-pr-body, and unit all pass.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 96 - 4 points deducted only because a same-family B4 mutation remains visible nearby as an intentionally deferred sibling; the shippeddebugfix itself follows ADR 0019.[CONTENT_COMPLETENESS]: 95 - 5 points deducted because the host-runtime residual remains post-merge/manual rather than ticket-annotated, but the PR body clearly states evidence, residuals, affected sites, and thesetEnvOverriderationale.[EXECUTION_QUALITY]: 96 - 4 points deducted for not directly executing the host scripts, which is reasonable for side-effecting maintenance CLIs; exact-head unit/static verification covers the code contract.[PRODUCTIVITY]: 100 - I actively checked the issue's four enumerateddata.debugsites, branch close targets, and static mutation sweep; the close target is fully delivered.[IMPACT]: 70 - Solid safety cleanup: removes a known B4 runtime-write class from lifecycle scripts without changing user-facing product behavior.[COMPLEXITY]: 20 - Low mechanical footprint across four script call sites, with moderate conceptual dependency on ADR 0019 and ConfigProvider env-layer behavior.[EFFORT_PROFILE]: Quick Win - High safety return for a small diff, backed by existing unit coverage and direct static checks.
Approved for human merge.
Resolves #12889
Replaces the ADR-0019 B4 write-class consumer mutation of the read-only reactive AiConfig Provider singleton (
<Config>.data.debug = true) with the Provider's sanctioned runtime env-override API (<Config>.setEnvOverride('NEO_DEBUG', true)) at the 4 remaining lifecycle/maintenance scripts. PR #12885 (#12812) removed this hazard from the two summary/backfill children; this completes the cleanup. Same observable behavior (debug logging activates) via the read-only-safe path, eliminating the #12335/#12435 shared-singleton-bleed hazard class.Authored by Claude Opus 4.8 (Claude Code). Session 3e808a22-50ef-484b-83c9-477ad47e9087.
Decision Record impact: aligned-with ADR 0019 (reactive Provider SSOT — consumers read resolved leaves, never mutate).
Evidence: L2 (
setEnvOverrideunit-green — 17/17ConfigProvider.specincl. the keyed-override-wins +createConfigProxymethod-binding cases; 4×node --check) → L1 required for the static-contract ACs (no baredata.debugconsumer-mutation remains; grep-clean). Residual: per-script runtime debug-emission is host-behavior (Post-Merge manual).Why
setEnvOverride, not a rawprocess.env.NEO_DEBUGsetThe
debugleaf IS env-backed (leaf(false, 'NEO_DEBUG', 'boolean')), but env resolution is bounded, not live-per-read (ai/ConfigProvider.mjs— re-resolved only at construct /setEnvOverride/load). The Config is already constructed at import (before the script body runs), so a raw runtimeprocess.env.NEO_DEBUGset would silently no-op.setEnvOverride(envName, value)validates against the leaf type, registers the override in the runtime-override registry, and re-applies the env layer immediately — and it's reachable on the imported default export (createConfigProxybinds instance methods through the proxy).data.debugreadstrueafterward, so no read-back regression.Affected sites
ai/scripts/runners/runSandman.mjsai/scripts/maintenance/syncKnowledgeBase.mjsai/scripts/migrations/migrateMemoryCore.mjsai/scripts/maintenance/ingestTenant.mjsDeltas from ticket
migrateMemoryCore.mjsalso mutatesMC_Config.data.collections.{memory,session}(same B4 consumer-mutation class, but test-collection targeting, not debug-activation). Flagging for a separate follow-up rather than folding in.Test Evidence
npm run test-unit -- test/playwright/unit/ai/ConfigProvider.spec.mjs→ 17/17 passed, includingsetEnvOverride() is keyed by env var name and wins over the default,createConfigProxy: .data getter + method calls bind to the real instance, andrefreshEnv() re-resolves env; runtime override persists.node --checkon all 4 edited scripts → clean.grep -nE "data\.debug\s*=\s*true"across the 4 scripts → 0 remaining bare consumer-mutations.Post-Merge Validation
node ai/scripts/runners/runSandman.mjs,syncKnowledgeBase,migrateMemoryCore,ingestTenant) — debug-level lines appear as before.Commits
deff617c2— B4-safe debug activation viasetEnvOverrideacross the 4 lifecycle scripts.