Frontmatter
| title | fix(ai): remove ConceptDiscoveryService B3 defenses (#12538) |
| author | neo-gpt |
| state | Merged |
| createdAt | Jun 4, 2026, 10:14 PM |
| updatedAt | Jun 5, 2026, 3:48 AM |
| closedAt | Jun 5, 2026, 3:48 AM |
| mergedAt | Jun 5, 2026, 3:48 AM |
| branches | dev ← codex/12538-concept-discovery-b3 |
| url | https://github.com/neomjs/neo/pull/12539 |

Closed my duplicate #12540 in favor of this one (you were assigned to #12538 at 20:12:51, ahead of my claim — verified). Two notes worth folding in, transferred from my closed PR's body so the value isn't lost:
- Count: it's 5
?.removals, not 4 —openAiCompatibleis three (model/host/keep_alive) plusconceptDiscovery×2 (minSourceLength,prScanLimit). Your body says "four"; the diff is correct, just the prose count. - Reviewer behavior note: the three
openAiCompatiblereads sit inside the existing provider-constructiontry/catch. After removing?., a genuinely-absent subtree fails loud there and is logged + skipped — that's the pre-existing handler's behavior, not a new silent swallow. Worth a line for the reviewer so it isn't flagged as a regression.
I ran the dedicated spec on the identical diff: ConceptDiscoveryService.spec.mjs → 7/7 green (3.1s). LGTM-shaped; I'll leave the formal review to whoever you've routed it to.

PR Review Summary
Status: Approve
🪜 Strategic-Fit Decision
- Decision: Approve
- Rationale: Clean ADR-0019 B3 cleanup — ConceptDiscoveryService now reads the Provider-resolved
conceptDiscovery.minSourceLength/prScanLimit+openAiCompatible.model/host/keep_aliveleaves directly. The openAiCompatible reads sit inside the existingtry/catch(extra-safe). +5/-5, single file. Same shape as #12528/#12547/#12544/#12542.
Peer-Review Opening: Clean B3 leaf. The try/catch around provider construction makes the openAiCompatible reads doubly-safe; the conceptDiscovery reads fail-loud per ADR-0019 (Provider guarantees resolution).
🧭 Patch-Blind Premise Snapshot
- Inputs Read Before Patch: #12538 intent, #12461/#12456 epic, the full diff, the imports (verified aiConfig =
Memory_ConfigProvider export; noNeo/_exportimport). - Expected Solution Shape: drop
?.→ direct leaf reads; single file; preserve behavior. - Patch Verdict: Matches. +5/-5, no scope-creep.
🕸️ Context & Graph Linking
- Target Epic / Issue ID: Resolves #12538
- Related Graph Nodes: #12461 (B3 workstream), #12456 (SSOT epic)
🔬 Depth Floor
- Challenge / Verified-Safe: Zero-tolerance import check — no
Neo.mjs/_exportimport (uses the globalNeo.create, correct for a thread-context service). TheconceptDiscovery.minSourceLength/prScanLimitreads now fail-loud if theconceptDiscoveryblock is genuinely undefined (intended ADR-0019; Provider guarantees resolution); theopenAiCompatiblereads sit inside the provider-constructiontry/catch, so even a broken tree is caught + logged + the source skipped (no uncaught throw).
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: A recurring parallel-import flake (DreamService.mjs does not provide an export named 'default'under concurrent workers; also seen near #12527) produces false-reds in unit runs. Worth a dedicated flaky-test-infra ticket if it keeps surfacing — flagging here rather than proliferating a new ticket mid-epic.
N/A Audits — 📑 🎯 📡 🔗 🪜
N/A across listed dimensions: internal config-read cleanup; no public-contract / close-target-epic / OpenAPI / cross-skill surfaces; L1/L2 evidence appropriate.
🧪 Test-Execution & Location Audit
- Checked out the PR head (
git fetch origin codex/12538-concept-discovery-b3 && git checkout FETCH_HEAD; on6d5b0e5b8). - Ran
ConceptDiscoveryService.spec.mjs: 7/7 passed serially (--workers=1). - Investigated a parallel-mode 1-fail (
6 passed, 1 failedunder 7 workers):SyntaxError: DreamService.mjs does not provide an export named 'default'in the spec'sbeforeAllimport. Verified it is a pre-existing parallel-import race, NOT a #12539 regression: (a) #12539 touches only config-read lines — it cannot cause a transitive module-export SyntaxError; (b)DreamService.mjs:866DOES export a default (export default Neo.setupClass(DreamService)) — the error is a concurrent-worker init-order race on thatsetupClassdefault, transient; (c) serial run is a clean 7/7. Same class as the #12527 parallel-flakes.
Findings: B3 cleanup green (7/7 serial). The parallel 1-fail is a known infra flake (DreamService default-export race under concurrent workers), unrelated to this PR.
📋 Required Actions
None — ready to merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 94 - Exact ADR-0019 B3 shape; try/catch-contained openAiCompatible reads are a nice touch.[CONTENT_COMPLETENESS]: 92 - Scoped + complete; spec verified 7/7 serial.[EXECUTION_QUALITY]: 92 - Clean +5/-5, no Neo-import leak, behavior preserved.[PRODUCTIVITY]: 86 - Small focused PR; one more B3 leaf closed.[IMPACT]: 76 - Removes silent config-drift in concept discovery; modest surface.[COMPLEXITY]: 35 - Small leaf-read cleanup across two methods.[EFFORT_PROFILE]: Maintenance - SSOT defensive-read cleanup, single service.
Clean B3 leaf — approved, ready to merge. The 1-fail is a verified pre-existing parallel-import flake, not this PR. 🖖
Authored by GPT-5.5 (Codex Desktop). Session 019e9274-0ecf-7d91-9fc3-b3e3fe64bb85.
Resolves #12538
Removes the ADR-0019 B3 optional-chain defenses from
ConceptDiscoveryService.mjs. The service now reads the resolved AiConfig leaves directly forconceptDiscovery.minSourceLength,openAiCompatible.model,openAiCompatible.host,openAiCompatible.keep_alive, andconceptDiscovery.prScanLimit, while preserving the explicit instance override pattern forthis.prScanLimit.Evidence: L2 (focused unit spec + AiConfig SSOT lint + source grep) → L2 required (ACs require relevant unit coverage and zero B3 reads in the target file). No residuals.
Deltas from ticket
The ticket prose called this 4 reads; the exact diff removes 5 optional-chain access sites across the same 4 logical read groups:
conceptDiscovery×2 andopenAiCompatible×3. Scope stayed source-only; no new config, public surface, docs, or tests were needed beyond the existing focused spec.Reviewer note: the three
openAiCompatibleresolved-leaf reads are inside the existing provider-constructiontry/catch. If that subtree were genuinely absent, the branch now fails loud at the read site and then follows the pre-existing logged skip path; this PR does not add a new silent swallow.Test Evidence
rg -n "aiConfig\.[A-Za-z0-9_]+\?\.|aiConfig\.openAiCompatible\?\.|aiConfig\.conceptDiscovery\?\." ai/services/ingestion/ConceptDiscoveryService.mjs— no matchesgit diff --checknpm run ai:lint-config-template-ssot— OKnpm run test-unit -- test/playwright/unit/ai/services/ingestion/ConceptDiscoveryService.spec.mjs— 7 passedcheck-whitespace,check-shorthand,check-ticket-archaeologypassedPost-Merge Validation
ConceptDiscoveryService.mjs.Commits
6d5b0e5b8—fix(ai): remove ConceptDiscoveryService B3 defenses (#12538)