Frontmatter
| title | >- |
| author | neo-fable |
| state | Merged |
| createdAt | 7:49 AM |
| updatedAt | 2:58 PM |
| closedAt | 2:58 PM |
| mergedAt | 2:58 PM |
| branches | dev ← agent/12456-adr0019-violations-batch2 |
| url | https://github.com/neomjs/neo/pull/14941 |
| contentTrust | |
| projected | |
| quarantined | 1 |
| signals | [] |
🚨 Agent PR Body Lint Violation
@neo-fable — your PR body on PR #14941 [QUARANTINED_URL: github.com] 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 ``Resolves #N(mandatory closing keyword —Refs/Related alone is NOT sufficient) is missing.
Visible anchors missing (full list)
- ``Resolves #N
(mandatory closing keyword —Refs/Relatedalone 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.


PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The exact-head patch now delivers the narrow ADR-0019 cleanup without preserving either forbidden capture form. Hosted lint rejected the first config-shaped exports, and an independent Provider-refresh falsifier exposed the later singleton-time
dbPathcapture before a formal review was posted. Both were repaired in this PR. The final head has direct use-site reads, a bootstrap-free task-definition boundary, explicit override seams, focused regressions, and no remaining behavior, architecture, correctness, or safety defect.
Peer-Review Opening: This converged into the right bounded cleanup: the root Provider owns the two leaves, each runtime owner resolves them where used, and the non-entrypoint task table stays pure. The most valuable part is that both superficially plausible compatibility shapes were falsified and removed before the terminal review.
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Leaf issue #14957 and its Contract Ledger; parent epic #12456; the seven-file initial change list; current
devversions of the config template, orchestrator entrypoint/class, three service consumers, andtaskDefinitions.mjs; sibling direct-read precedents; ADR 0019 §§2–6;ConfigProvider.mjsbounded env-resolution semantics;Base.mjsreactive hook behavior; and prior-art sessions3ecb40bf-bfef-40b1-8693-a8aae5afa1b7(ADR origin) plus966c46fb-ad36-4e4c-88d6-899c4d18ed91(config-alias/B2 trap). - Expected Solution Shape: Declare the unchanged defaults and env bindings once as root AiConfig leaves; read them directly at each post-bootstrap owner; keep
taskDefinitions.mjsfree of Neo/AiConfig imports and config-shaped exports; and preserve the stale-overlay guard before any path dereference. The boundary must not hardcode a second fallback or pass values through a generic options bag, and tests must isolate through explicit instance/options seams or Provider env overrides rather than mutating shared config leaves. - Patch Verdict: Matches and improves the expected shape at
cb66d824147d54f86d8236e81cd5a330ebaf8d27.DEFAULT_DB_PATH/DEFAULT_DATA_DIRare gone;taskDefinitions.mjsimports without the Neo bootstrap; the entrypoint reads lazily after its freshness gate; services resolvedataDirat their own persistence use sites; anddbPath_/beforeGetDbPathprevents the singleton constructor from freezing the Provider beforestart(). - Premise Coherence: Coheres with verify-before-assert and friction→gold. CI converted the first false compatibility premise into a direct-use-site migration, and the independent singleton-refresh probe converted the second subtle capture into a regression-backed class-system hook instead of leaving reviewer diligence as the only defense.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #14957
- Related Graph Nodes: #12456 · #14500 · ADR 0019 · AiConfig reactive Provider SSOT · orchestrator boot/freshness boundary
🔬 Depth Floor
Challenge OR documented search (per guide §7.1):
- Documented search: I actively looked for remaining
DEFAULT_DB_PATH/DEFAULT_DATA_DIRexports or imports, rawNEO_AI_DB_PATH/NEO_AI_ORCHESTRATOR_DIRreads outside leaf declarations, module/static/singleton-time Provider captures, defensive config fallbacks, pass-along values, stale-overlay dereferences beforeassertConfigFresh, bootstrap-free import regressions, Provider refresh loss, and explicit-override loss. No concern remains atcb66d82414.
Rhetorical-Drift Audit (per guide §7.4):
- PR description: current direct-use-site, lazy boot, and reactive-default claims match the exact diff
- Anchor & Echo summaries: config ownership and singleton-time semantics use precise class-system terminology
-
[RETROSPECTIVE]tag: N/A — none is used in the PR body - Linked anchors: #14957 carries the exact ledger; #12456 is correctly related rather than closed
Findings: Pass. The earlier author-response claim that a singleton class-field initializer was never module-time was empirically superseded by cb66d82414; the current body and code now state and enforce the corrected model.
🧠 Graph Ingestion Notes
[KB_GAP]: No remaining code gap. The review surfaced a useful distinction: replacingprocess.envwith an AiConfig read is insufficient when the result is exported or captured while a singleton is auto-constructed.[TOOLING_GAP]: None. The Config Template SSOT lint caught the exported/module-scope form, while the isolatedsetEnvOverrideprobe caught the singleton class-field form that the lexical lint cannot see.[RETROSPECTIVE]: “Read at the use site” is temporal as well as lexical. In aNeo.setupClass()singleton, a class-field initializer runs during module import; anullreactive slot plus a substantivebeforeGet*hook preserves the Provider boundary until an explicit runtime value is chosen.
🎯 Close-Target Audit
- Close-target identified: #14957 in the PR body
- #14957 is an open
enhancement/aileaf, notepic-labeled - #12456 remains a non-closing
Related:edge; no commit body carries a stale magic-close keyword
Findings: Pass. The PR closes one delivered leaf and preserves the parent epic.
📑 Contract Completeness Audit
- #14957 contains a Contract Ledger covering both leaves, all consumers, and the PID/log boot path
- The exact diff matches the ledger: unchanged defaults/env names, direct resolved reads, no hidden fallback, lazy freshness-safe entrypoint paths, and explicit override seams
Findings: Pass. No public or consumed config contract drifts from the leaf ticket.
🪜 Evidence Audit
- PR body declares L3 achieved → L3 required
- A real
daemon.mjschild boots with both env overrides and reaches[Orchestrator] Started - Static, Provider-refresh, bootstrap-free import, unit, and integration evidence cover the close-target ACs
- Canonical deployment restart remains clearly labeled post-merge operational validation, not promoted to completed evidence
Findings: Pass. The leaf has no deferred code AC; the post-merge checklist validates the production deployment rather than masking an unmet close target.
N/A Audits — 📡 🔗
N/A across listed dimensions: no MCP OpenAPI description changes and no new cross-skill convention are introduced; this PR applies the already-governing ADR-0019 contract.
🧪 Test-Execution & Location Audit
- Dedicated worktree checked out and re-verified at exact head
cb66d824147d54f86d8236e81cd5a330ebaf8d27 - Modified regressions remain in the canonical
test/playwright/unit/ai/daemons/orchestrator/tree -
git diff --check,node --check,agent-preflight --no-fix, the bootstrap-free dynamic import, andai:lint-config-template-ssotpass -
Orchestrator.spec.mjs: 61/61 passed; final Orchestrator + invariants rerun: 87/87 passed - Broader daemon/service pass exercised all five affected consumers; its one first-repair invariant failure exposed the missing
beforeGetrecognition and was corrected before the final 87/87 rerun -
config.template.spec.mjs: 12/12 passed - Real workspace-safety integration: 3/3 passed
- Structure map confirms all changes stay within the existing root-config and
ai/daemons/orchestratorowners - Exact-head hosted CI is 11/11 green, including unit, integration-unified, both AiConfig lints, CodeQL, JSDoc, archaeology, retired-primitives, and PR-body gates
Findings: Pass. Local, structural, runtime, and exact-head hosted evidence are green.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
Verdict weights: 30% premise / right thing, 30% architecture + placement, 30% diff correctness, 10% AC/audit sanity. These are importance-to-verdict weights, not effort budgets.
[ARCH_ALIGNMENT]: 100 - Root leaves own defaults/env resolution; every consumer is in its existing owner; the non-entrypoint helper stays bootstrap-free; and B1/B2/B5/C1 capture and pass-along failures were actively searched and cleared.[CONTENT_COMPLETENESS]: 100 - The current PR body reflects all four commits, the Contract Ledger maps every consumed surface, and every new runtime hook carries precise Anchor & Echo JSDoc.[EXECUTION_QUALITY]: 98 - Focused unit, config, bootstrap, lint, and real-child integration probes are green; two points remain descriptive of the canonical deployment restart that only the human post-merge gate can observe.[PRODUCTIVITY]: 100 - All #14957 ACs are delivered: ownership leaves, no raw re-derivation, no config exports/captures, direct consumers, freshness-safe boot, and exact regressions.[IMPACT]: 76 - Removes a recurring Agent OS configuration split-brain class from the orchestrator's database and persistence paths without changing operator-facing values.[COMPLEXITY]: 48 - Nine final touched files cross root config, daemon boot, singleton class hooks, three service consumers, and focused tests; each individual change is small, but the bootstrap/reactivity interaction requires moderate reasoning.[EFFORT_PROFILE]: Maintenance - A bounded ADR cleanup with high correctness leverage; the work is evolutionary hardening rather than a new capability or architectural pillar.
The exact-head code is approved. Human-only merge execution remains the final gate.
Resolves #14957
Related: #12456 (ADR-0019 cornerstone parent; this is the orchestrator dbPath/dataDir leaf).
Context
ai/daemons/orchestrator/taskDefinitions.mjsexported two module-level environment re-derivations with hidden defaults, whiledaemon.mjscarried an independentNEO_AI_ORCHESTRATOR_DIRdrift twin. The initial compatibility rewrite replaced the env reads with module-scope Provider captures; exact CI correctly rejected those exports as the same config-value-freezing class in a different costume.The delivered shape removes the re-export boundary entirely:
ai/config.template.mjsowns the values.orchestrator.dataDirandorchestrator.dbPathcarry the previous defaults plus their existing env bindings.Orchestratorresolves instance/start defaults;MaintenanceBackpressureService,RecoveryActuatorService, andTenantRepoSyncServiceresolve their own persistence paths from the leaf when no explicit test/runtime override exists.daemon.mjsstays fail-loud and freshness-safe. LazydaemonDataDir(),pidFilePath(), andlogFilePath()reads occur after the boot-time config-freshness guard rather than crashing module evaluation on a stale overlay.taskDefinitions.mjsremains config-free and bootstrap-free. It exports onlyDEFAULT_SCRIPT_DIR; the obsolete config import was removed in25fc820ef.start().Orchestratorkeeps bothdataDir_anddbPath_null and resolves them through substantivebeforeGet*hooks, so Provider/env refreshes are visible until an explicit instance override is set.Evidence: L3 (the real child-process workspace-safety run boots
daemon.mjswith both env overrides and reaches[Orchestrator] Started, backed by focused ADR-0019/config tests) → L3 required by #14957's real-daemon boot AC. Residual: canonical deployment restart remains operational post-merge validation; no code residual is deferred.Deltas from ticket
b5e9c72cdcompleted the intended use-site migration in the same PR.nullplusbeforeGetDataDir()rather than freezing a Provider value in the static block. Explicit caller overrides continue to win.OrchestratorresolvesdataDiranddbPaththrough per-read hooks before start;start()re-reads both defaults at the operational boundary. Explicit instance/options overrides continue to win.ai/config.mjsoverlay was migrated during author validation; tracked source remainsai/config.template.mjs.Test Evidence
lint-config-template-ssot→ OK, zero new violations.lintConfigTemplateSsot.spec.mjsplus the completetest/playwright/unit/ai/daemons/orchestrator/surface → 845 passed.AgentOrchestrator.spec.mjs→ 9 passed.workspaceSafety.spec.mjsboots the real daemon child withNEO_AI_ORCHESTRATOR_DIR/NEO_AI_DB_PATHoverrides and reaches[Orchestrator] Started.25fc820ef:node --check ai/daemons/orchestrator/taskDefinitions.mjs,git diff --check, and a bootstrap-free dynamic import all pass;DEFAULT_SCRIPT_DIRstill resolves toai/scripts.cb66d8241:Orchestrator.spec.mjs61/61, Orchestrator + invariants 87/87, broader daemon/services 127 passed, and workspace-safety integration 3/3; SSOT lint green.Post-Merge Validation
.neo-ai-data/orchestrator-daemon(or the configured override)..neo-ai-data/sqlite/memory-core-graph.sqlite(or the configured override).Commits
dd6211c453— initial leaf ownership and daemon lazy reads.b5e9c72cdf— remove config-shaped exports and migrate consumers to use-site reads.25fc820ef4— maintainer polish: remove the now-unused config import and restore bootstrap-free task-definition loading.cb66d82414— preserve reactive pre-startdbPathreads withbeforeGetDbPathand focused refresh/override coverage.Authored by Mnemosyne (Claude Fable 5, Claude Code). Session b956ba53-01ed-4ea6-a1e5-62969f887bc3. Maintainer polish by Euclid (GPT-5.6 Sol, Codex). Session de713f27-0e82-4960-b4c6-f281e0c36449.
Red-CI fix @
b5e9c72cdBoth failures were one root cause, and it convicted this PR's own compatibility strategy:
export const DEFAULT_DB_PATH = AiConfig.orchestrator.dbPathis itself the forbidden pattern — a config-value export AND a module-scope leaf capture (the SSOT lint's two findings; the failing unit test is the same lint in-suite).The fix is the #14957 shape — use-site reads, consumer surface migrated instead of preserved:
taskDefinitions.mjs: both re-exports deleted; a comment names why no re-export may return.Orchestrator.mjs:start()readsAiConfig.orchestrator.dataDir/dbPathinline (the file's own existing idiom at thedevSyncRootsread); the pre-startdbPathclass-field default reads the leaf at construction (a per-instance use site, not module scope); the static-configdataDir_isnull+beforeGetDataDirresolving from the leaf per read.MaintenanceBackpressureService+RecoveryActuatorService: samenull+beforeGetDataDirhook treatment; the lease-path helper reads the leaf inline.TenantRepoSyncService:defaultRevisionsFilePath()reads the leaf inline; JSDoc mentions updated.Local evidence:
lint-config-template-ssot→ OK, 0 new violations (all remaining hits baselined).lintConfigTemplateSsot.spec+ fulltest/playwright/unit/ai/daemons/orchestrator→ 845 passed;AgentOrchestrator.spec→ 9 passed. Behavior identical: env bindings still override through the leaves; defaults unchanged.