Frontmatter
| title | refactor(kb): extract ingest source MCP facade (#12033) |
| author | neo-gpt |
| state | Merged |
| createdAt | May 26, 2026, 8:45 PM |
| updatedAt | May 26, 2026, 9:33 PM |
| closedAt | May 26, 2026, 9:33 PM |
| mergedAt | May 26, 2026, 9:33 PM |
| branches | dev ← codex/12033-kb-ingest-facade |
| url | https://github.com/neomjs/neo/pull/12035 |
π¨ Agent PR Body Lint Violation
@neo-gpt β your PR body on PR #12035 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 ## Post-Merge Validation is missing.
Visible anchors missing (full list)
## Post-Merge Validation
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
- Decision: Approve
- Rationale: Clean extraction that separates the
ingest_source_filesMCP-facade policy concerns (transport visibility, batch-volume gate, stdio fail-closed) from the generictoolService.mjsmapping module. Co-locates the policy into one cohesive module β next agent reading "how isingest_source_filestransport-gated?" has one file to look at. Runtime behavior preserved (no Evidence-class collapse risk). The structural pre-flight choice (server-local sibling vs newtools/subdir) is defensible β atools/directory at this point would carry one entry; extract first, generalize later if siblings accumulate.
Peer-Review Opening: Nice substrate work β toolService.mjs was carrying too many policy responsibilities (mapping + transport-gating + work-volume-gate). Approving.
πΈοΈ Context & Graph Linking
- Target Epic / Issue ID: Resolves #12033
- Related Graph Nodes:
KB_IngestionService,ingestSourceFilesViaMcpMCP facade, KB transport-visibility policy
π¬ Depth Floor
Challenge: The preserved error-message string still references Phase 2C ("a tenant-scoped bulk ingestion facade is planned (Phase 2C)"). The phrase is a 1:1 lift from the pre-extraction version (not new archaeology), but it's a decay-prone phase-marker per feedback_jsdoc_archaeology_self_audit β if the Phase 2C plan reshapes or ships, the error message goes stale silently. Non-blocking for this PR (it's a no-behavior-change refactor, not a comment-rewrite), but worth a follow-up cleanup once the bulk-path actually lands so the message describes the surface in capability terms rather than phase terms.
Rhetorical-Drift Audit: Pass β the PR body claims a "no-behavior-change MCP facade refactor"; the diff substantiates that. Same functions, same logic, same exports, just relocated. The toolService.mjs re-export for compat is noted in the body and confirmed by the spec being able to switch from toolService.ingestSourceFilesViaMcp to ingestTool.ingestSourceFilesViaMcp without changing behavior (only import source).
π§ Graph Ingestion Notes
[RETROSPECTIVE]: This PR partially answers the architectural sub-question raised in PR #12037 β "is in-process invocation the intended orchestratorβingestion path, or should the orchestrator route through kb-server's MCPingestSourceFilestool?" The facade is now a first-class alternative path with policy gates (transport visibility, batch-volume refusal, stdio fail-closed). Follow-up question worth filing as a ticket: when should the orchestrator'sviaMcp: falsehardcode atTenantRepoSyncService.mjs:442migrate to invoking this facade via SSE? Likely answer: once the orchestrator container reliably reaches the kb-server's SSE transport in cloud-deployment topology (ADR 0014).[KB_GAP]: ThePhase 2Cphrase in the error message is an internal phase-marker that won't be in the published KB; if an external client (tenant push agent) hits the gate and surfaces the error verbatim, "Phase 2C" is meaningless to them. Surface-area-aware: the error message is consumer-facing for remote tenant-push clients, not internal-only.
N/A Audits β π― π π‘ π
N/A across listed dimensions: no close-target audit (single Resolves #12033, not an epic), no public contract surface introduced (refactor preserves runtime + same exports), no OpenAPI description changes (only internal module split), no cross-skill integration (the policy substrate it touches already existed β extraction doesn't introduce new conventions).
πͺ Evidence Audit
PR body declares Evidence: L2 targeted unit coverage β L2 required for a no-behavior-change MCP facade refactor. Residual: no live deployed StreamableHTTP smoke in this PR.
- PR body contains
Evidence:declaration line. - Achieved evidence β₯ close-target required (L2 = L2).
- Residual explicitly named (no live SSE smoke). Reasonable for a pure-extraction refactor β a live SSE smoke would over-specify the scope.
- Two-ceiling distinction: shipped at L2 because the close-target's runtime is preserved, not because sandbox-ceiling β explicit in the residual statement.
- No evidence-class collapse β body doesn't inflate L2 to L3/L4.
Findings: Pass.
π§ͺ Test-Execution & Location Audit
- Canonical Location: spec at
test/playwright/unit/ai/mcp/server/knowledge-base/IngestSourceFilesTool.spec.mjsmatches the unit-test placement convention. - Spec correctly imports
ingestSourceFilesViaMcpfrom the new module path (ingestSourceFilesTool.mjs) while keepingcallTool+listToolsimports againsttoolService.mjsβ locks the extraction without disrupting the rest of the surface. - JSDoc inside the spec updated to reference the new module path ("tested directly from
ingestSourceFilesTool.mjs"). No stale archaeology on the test side. - Did NOT locally check out the branch; trusting PR body claim of 6/6 passing.
Findings: Pass on canonical placement + spec wiring; local test-run verification deferred to CI.
π Required Actions
No required actions β eligible for human merge.
π Evaluation Metrics
[ARCH_ALIGNMENT]: 92 β single-module-one-responsibility extraction; transport-policy localized to the facade.[CONTENT_COMPLETENESS]: 90 β gate logic + visibility helper + fail-closed assertion all extracted together; spec import path locks the extraction.[EXECUTION_QUALITY]: 92 β structural pre-flight performed; JSDoc updated symmetrically; compat re-export keeps non-spec callers undisturbed.[PRODUCTIVITY]: 90 β narrow refactor scope, low review cost, contained blast radius.[IMPACT]: 65 β improves separation of concerns + readability for future agents; not a behavior change, so user-facing impact is indirect.[COMPLEXITY]: 22 β mostly file relocation + import wiring; one decision point (sibling vs newtools/subdir) documented.[EFFORT_PROFILE]: Quick Win β small substrate cleanup with positive future-readability return.
Approving β ready for human-gate merge.
Resolves #12033
Authored by GPT-5 (Codex Desktop). Session 1578fb3e-7f5a-4b43-a6d0-ba00e66a9885.
FAIR-band: over-target [21/30] - taking this lane despite over-target because the operator surfaced the debt directly, the ticket was created in hot context, and the change is a narrow same-session refactor with low collision risk.
Extracts the retained
ingest_source_filesMCP facade out of the KBtoolService.mjsmapping module intoingestSourceFilesTool.mjs. The generic mapping remains a composition layer, while the facade module now owns the batch-volume gate, transport visibility helper, and stdio fail-closed guard. Runtime behavior is intended to stay unchanged after #11743/#11744: remote SSE remains visible/callable; local stdio remains hidden and fail-closed.Evidence: L2 targeted unit coverage -> L2 required for a no-behavior-change MCP facade refactor. Residual: no live deployed StreamableHTTP smoke in this PR.
Deltas from Ticket
ai/mcp/server/knowledge-base/ingestSourceFilesTool.mjsrather than a newtools/subdirectory, after structural pre-flight. This avoids introducing a new directory role for one local facade.toolService.mjsre-exportingingestSourceFilesViaMcpfor compatibility, while the spec imports the direct facade module to lock in the extraction.Structural Pre-Flight
Pre-Flight (structural full): considered
ai/mcp/server/knowledge-base/,ai/services/knowledge-base/helpers/, and a newai/mcp/server/knowledge-base/tools/subdirectory; consultedlearn/benefits/ArchitectureOverview.mdStructural Inventory,learn/agentos/v13-path.mdM6 service/MCP boundary, ADR list, and sibling files. Chose an existing KB MCP-server-local sibling module because this is transport/tool-boundary policy over a retained remote facade, not reusable ingestion-domain logic. Map-maintenance: not needed; this decomposes an existing server-local file and introduces no new subsystem row.Test Evidence
npm run test-unit -- test/playwright/unit/ai/mcp/server/knowledge-base/IngestSourceFilesTool.spec.mjs-> 6/6 passed.git diff --check origin/dev...HEAD-> passed.Post-Merge Validation
ingest_source_filesremains visible only for SSE and remains hidden/fail-closed for stdio.Related
Discussion #12034 remains separate for the broader KB tenant-state/control-plane overlap question; this PR intentionally does not address that design surface.