LearnNewsExamplesServices
Frontmatter
id17182
titlenpm run ai:build-kb-faqs has been unrunnable since the KB flat-SDK migration, and no gate reports it
stateClosed
labels
bugaiai-generated
assigneesneo-kimi-phoebe
createdAtAug 15, 2026, 4:43 PM
updatedAtAug 15, 2026, 9:12 PM
githubUrlhttps://github.com/neomjs/neo/issues/17182
authorneo-opus-vega
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 15, 2026, 9:12 PM

npm run ai:build-kb-faqs has been unrunnable since the KB flat-SDK migration, and no gate reports it

Closed Backlog/active-chunk-16 bugaiai-generated
neo-opus-vega
neo-opus-vega commented on Aug 15, 2026, 4:43 PM

Context

Found by the capability-closure walker built for #16929 on its first full run over ai/scripts. The walker reports unresolved import edges as named findings rather than defaulting them, and this one turned out not to be a limitation of the tool — the import genuinely does not resolve.

The Problem

npm run ai:build-kb-faqs cannot start. It has been dead since the KB flat-SDK migration, and nothing anywhere reports it.

package.json:39   "ai:build-kb-faqs" : "node ./ai/scripts/maintenance/buildKbAgentFaqs.mjs"

buildKbAgentFaqs.mjs:3
  import KBRecorderService from '../../mcp/server/knowledge-base/services/KBRecorderService.mjs';
                                  ^ no such path

actual location: ai/services/knowledge-base/KBRecorderService.mjs

Confirmed by execution, not by inspection:

node -e "import('./ai/scripts/maintenance/buildKbAgentFaqs.mjs')"
→ ERR_MODULE_NOT_FOUND

The path stopped existing at #10991 / PR #10995"migrate KB services to flat SDK boundary". The script has not been touched since a comment cleanup (#11925), so it has been unrunnable for months.

CORRECTED 2026-08-15 by the author. This section originally claimed ready() was ABSENT at the new location and that the repair therefore needed a lifecycle decision rather than a corrected specifier. Both claims were false, and @neo-kimi-phoebe caught it while dispositioning the ticket.

ready() is defined on Neo.core.Base:963, and KBRecorderService extends Base — so it is inherited. My check was grep -qE "(^|\s|\.)ready\s*[(:=]" against the subclass file alone, which cannot see an inherited member and never could have. I tested for the absence of a string in one file and reported the absence of a capability on an object.

The consequence was not cosmetic: it framed the repair as larger than it is, and would have sent whoever claimed this ticket looking for a lifecycle contract that did not need changing. The disposition is REPAIR, and the specifier fix is the substance of it.

Both members the script calls resolve at the new location:

call site member at the new location
buildKbAgentFaqs.mjs:26 KBRecorderService.ready() present — inherited from Neo.core.Base:963
buildKbAgentFaqs.mjs:28 KBRecorderService.buildAgentFaqs({…}) present

Why nothing caught it

The same silence #17151 exists to break, one layer over: a script nobody runs cannot fail. There is no spec referencing buildKbAgentFaqs, no other importer, and an npm script's existence is never asserted anywhere. ERR_MODULE_NOT_FOUND only surfaces at invocation, and nothing invokes it — so the failure has no reporter.

This is also why it is worth a ticket rather than a quiet fix: the interesting part is not the wrong path, it is that a published entrypoint can rot for months with a green board.

The Fix (shape — the disposition is the deliverable)

Two honest options, and picking is the work:

  1. Repair. Repoint the import at ai/services/knowledge-base/KBRecorderService.mjs and resolve ready() — either it maps onto the migrated lifecycle, or the call is dropped because the flat SDK initialises differently. Requires reading what replaced it rather than deleting the line to make the import work.
  2. Retire. If FAQ-building is superseded, remove the script and its ai:build-kb-faqs entry together. A dead npm script is a trap: it reads as a supported capability.

Whichever wins, the useful generalisation is a mechanical one — every ai:* npm script should be provably import-resolvable, which is a cheap check over package.json and does not need this ticket's outcome.

Acceptance Criteria

  • A disposition is recorded (repair / retire) with the rejected alternative and why.
  • If repaired: node ./ai/scripts/maintenance/buildKbAgentFaqs.mjs --help (or the equivalent no-side-effect invocation) exits 0, evidenced by pasted output — not by inspection of the import line.
  • If repaired: the ready() call is resolved against what the flat SDK actually exposes, and the resolution is stated. Deleting the call to make the module load is only acceptable with a reason.
  • If retired: the script and its package.json entry are removed in the same commit, and the removal accounts for where the capability went.
  • A guard proves every ai:* entry pointing into ai/scripts resolves its static imports — red-proved by pointing one entry at a nonexistent module and observing the failure.
  • The guard runs in CI and is registered in the workflow scan-root parity registry.

Out of Scope

  • #16929's plane derivation. This ticket is the finding; that lane is the tool that found it.
  • Any change to KBRecorderService's own API.
  • Auditing non-ai:* npm scripts.

Avoided Traps

  • Fixing the specifier alone. The import would resolve and the script would then fail at ready(). Retired — this trap was my own false finding. ready() is inherited and resolves fine; see the correction above. Keeping the strike rather than deleting it, because the failure it records — grepping one file for an inherited member — is the more useful artifact.
  • Reading a single-file grep as an object's API. A member can arrive by inheritance, and a subclass file will never mention it. Resolve the member on the object, or read the base class.
  • Deleting ready() to make it start. That converts "does not run" into "runs without initialising", which is worse: it would produce FAQ output from an unready service and look successful.
  • Treating this as one bad path. The generalisable defect is that no gate asserts an npm entrypoint can load; that is the piece that stops the next one rotting.

Evidence class

L4 — the failure is reproduced by executing the module in-process (ERR_MODULE_NOT_FOUND), and the member survival is read from the migrated source. Reproducible on any checkout of dev.

Related

#16929 (the closure walker that surfaced it) · #10991 / PR #10995 (the migration that broke the path) · #11925 (last touch, comment-only) · #17151 (same silence class: a defect with no reporter)

Live latest-open sweep at 2026-08-15T14:36Z plus a targeted search for buildKbAgentFaqs / build-kb-faqs / KBRecorderService across open issues: the only near hit is #16649 (SDK barrel resolving better-sqlite3 eagerly), which is a different subject. No competing A2A [lane-claim].

Origin Session ID: 5cd926fa-77e1-4309-8bbf-ca563ab07403

Retrieval Hint: query_raw_memories("ai:build-kb-faqs dead npm script ERR_MODULE_NOT_FOUND KBRecorderService flat SDK") · falsification anchor: import('./ai/scripts/maintenance/buildKbAgentFaqs.mjs') throws ERR_MODULE_NOT_FOUND on dev.

tobiu referenced in commit f299c8c - "feat(build): repair the ai:build-kb-faqs entrypoint and gate every ai:* script's import resolvability (#17182) (#17199) on Aug 15, 2026, 9:12 PM
tobiu closed this issue on Aug 15, 2026, 9:12 PM