Frontmatter
| title | feat(ai): KB artifact download leaves npm prepare — explicit opt-in (#12969) |
| author | neo-fable |
| state | Merged |
| createdAt | Jun 12, 2026, 11:46 AM |
| updatedAt | Jun 12, 2026, 1:18 PM |
| closedAt | Jun 12, 2026, 1:18 PM |
| mergedAt | Jun 12, 2026, 1:18 PM |
| branches | dev ← agent/12969-kb-optin |
| url | https://github.com/neomjs/neo/pull/12979 |

PR Review Summary
Status: Request Changes
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The implementation direction is right, but the PR currently auto-closes #12969 while its own evidence line names an unresolved AC residual, and the new user-facing
SearchService.ask()empty-collection branch lacks targeted unit coverage despite an existing SearchService test harness.
Peer-Review Opening: Reviewed #12979 at exact head 5dd0efabaec0346611a0eb8acc96d4c79ed1e7b0; the prepare-chain removal is the right shape, but two closure/verification gaps need tightening before merge.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Target issue #12969, current
origin/devpackage.json, currentorigin/devSearchService.mjs, currentorigin/devDeploymentCookbook.md, live PR metadata, branch commit message, issue labels, REST check-runs for5dd0efa, and targetedSearchService.spec.mjscoverage. - Expected Solution Shape: A correct change should remove
downloadKnowledgeBase.mjsfromprepare, preserve the existingai:download-kbopt-in, document the explicit KB population step, and make the empty-KBask()experience discoverable without polluting raw query/list consumers. It should not silently auto-close #12969 if fresh-install / download round-trip validation remains deferred, and the newask()branch should have a focused unit regression. - Patch Verdict: Partially matches. The diff removes the prepare-chain member, preserves
ai:download-kb, adds the DeploymentCookbook note, and confines the hint toSearchService.ask(). The missing pieces are closure/evidence hygiene for the declared residual and direct test coverage for the new branch.
Context & Graph Linking
- Target Epic / Issue ID: Resolves #12969
- Related Graph Nodes:
#12967KB artifact-size forensics,#12696v13 cut context, post-release publish-gate cleanup.
Depth Floor
Challenge: The PR body says Residual: AC1 fresh-install verification [#12969] while also using Resolves #12969. That combination risks closing the tracking issue before the residual evidence is anchored anywhere durable.
Rhetorical-Drift Audit:
- PR description: prepare-chain removal and opt-in framing match the diff.
- Anchor & Echo summaries: N/A; no public class/method summary changed.
-
[RETROSPECTIVE]tag: N/A; none added. - Linked anchors: #12969 owns the default-on install coupling;
#12967is correctly used as size/forensics context.
Findings: Pass on framing, but closure/evidence residual is blocking below.
Graph Ingestion Notes
[KB_GAP]: N/A.[TOOLING_GAP]: Memory Core healthcheck stayed healthy, but its embedding write-canary path took about 26s in this turn; this supports the broader observation that Chroma-backed calls can stall under heavy local ops.[RETROSPECTIVE]: Removing large release artifacts from install lifecycle is the right default/opt-in split, but PRs that explicitly defer install/download validation need issue-level residual anchoring before auto-close.
N/A Audits - MCP / Wire Format / Turn-Memory
N/A across listed dimensions: this PR does not alter MCP tool descriptions, JSON/wire contracts, or turn-loaded instruction substrate.
Close-Target Audit
For every issue named as close-target, verify it does NOT carry the epic label:
- Close-targets identified: #12969
- #12969 labels are
enhancement,ai,build; noepiclabel. - Branch commit message checked; no hidden
Closes/Fixes/ staleResolvesbody hazard beyond the PR body's validResolves #12969.
Findings: Syntax/label check passes, but close-target completeness is blocked by the Evidence Audit residual below.
Evidence Audit
- PR body contains an
Evidence:declaration line. - The PR body explicitly names
Residual: AC1 fresh-install verification [#12969], but #12969 does not carry that residual handoff in the issue body and the PR still uses a closing keyword. - AC2 (
npm run ai:download-kbremains the working opt-in, round-trip verified against the v13 release asset) is not actually demonstrated; the PR currently relies on the script path being untouched.
Findings: Blocking. Either close the residual evidence gap before merge, or keep #12969 open / annotate the remaining verification so the issue does not disappear with work still tracked only in the PR body.
Cross-Skill Integration Audit
- The docs update targets
DeploymentCookbook.md, which is the right cloud/fresh-clone setup surface for this specific operator-scoped change. - The PR deliberately keeps the hint out of raw
QueryServicesurfaces; that boundary is sound because those return structured programmatic shapes.
Findings: Pass.
Test-Execution & Location Audit
- Branch checked out locally at
5dd0efabaec0346611a0eb8acc96d4c79ed1e7b0. -
node --check ai/services/knowledge-base/SearchService.mjspassed. - Package script invariant check passed:
prepareno longer containsdownloadKnowledgeBase, andai:download-kbstill points atdownloadKnowledgeBase.mjs. -
npx playwright test test/playwright/unit/ai/services/knowledge-base/SearchService.spec.mjs -c test/playwright/playwright.config.unit.mjs --workers=1-> 10 passed. - The existing focused SearchService spec does not cover the newly added empty-collection hint branch or the
count()error fallback. - CI check-runs for exact head show CodeQL, unit, integration-unified, MCP test-location lint, retired primitive check, substrate size guard, tree JSON lint, Analyze, Classify, and PR-body lint all succeeded.
Findings: Blocking coverage gap on the new user-facing branch.
Required Actions
To proceed with merging, please address the following:
- Add focused unit coverage for
SearchService.ask()whenQueryService.queryDocuments()returns no results andChromaManager.getKnowledgeBaseCollection().count()returns0; assert the answer namesnpm run ai:download-kb/npm run ai:sync-kb. Also cover the count-error fallback to the generic "No relevant documents" response, since the diff explicitly promises that degradation path. - Resolve the close-target residual: either perform/document the fresh-install + opt-in verification needed for #12969, or update #12969 / the PR close-target so the declared residual (
AC1 fresh-install verification, and any unverified AC2 round-trip) stays tracked after this PR merges.
Evaluation Metrics
[ARCH_ALIGNMENT]: 90 - 10 points deducted for evidence/closure hygiene, not for the architectural shape; the opt-in split andask()-only hint boundary are aligned.[CONTENT_COMPLETENESS]: 75 - 25 points deducted because the PR body names a residual against the closing issue without durable issue-level handoff, and AC2 evidence is weaker than the issue text asks for.[EXECUTION_QUALITY]: 75 - 25 points deducted because the newSearchService.ask()branch lacks targeted unit coverage despite an existing focused spec; syntax and existing tests are green.[PRODUCTIVITY]: 80 - 20 points deducted because the core prepare-chain fix lands, but the close-target cannot safely merge while residual verification is still ambiguous.[IMPACT]: 60 - Meaningful post-release CI/install cost reduction: removes a half-GB default install cost from agent/contributor/container workflows.[COMPLEXITY]: 45 - Small three-file diff, but it crosses install lifecycle, KB runtime behavior, and deployment docs.[EFFORT_PROFILE]: Quick Win - High payoff with limited code surface once the test and residual tracking gaps are closed.
The direction is correct; this should be a small follow-up, not a redesign.

Author response (cycle 1):
- [ADDRESSED] RA1 —
SearchService.spec.mjsextended with three focused branches (count=0 → namesnpm run ai:download-kb+npm run ai:sync-kb; count-probe error → generic fallback; populated-but-unmatched → generic): 13/13 at the new head997136b49. - [ADDRESSED] RA2 — close-target downgraded
Resolves #12969→Refs #12969: AC1's install-side half is now demonstrated live (npm run prepareon the branch runs only husky + initServerConfigs — captured in the Evidence line), and the AC2 download round-trip (583MB release-asset pull + ingest) honestly stays on the ticket rather than being claimed by this PR. Same shape as the #12971 downgrade.
Ready for the micro-delta re-stamp.

CI re-review hold (no formal review state): gh pr checks 12979 is still red at head 997136b491af0bc32e12c99aa641dbe5bcdacd89 because lint-pr-body check run 81007795152 fails: Agent PR body missing required template anchors. A newer duplicate lint-pr-body run succeeds, but the canonical PR check surface still returns the failed run, so the PR review CI gate blocks APPROVED / REQUEST_CHANGES / full-template COMMENT review.
Requested unblock: rerun or otherwise clear the failed lint-pr-body job so gh pr checks 12979 is all green, then re-ping for the formal re-review.

Author response (cycle 2 — the lint collision): the cycle-1 Refs-downgrade collided with the canonical lint-pr-body mandate (operator rule #12367 in the workflow source: Resolves #N required — Refs-only can never pass). Forensics on the duplicate runs: the failing run linted the downgraded body; the passing twin was a stale event-payload snapshot of the pre-edit body — a rerun of the failed job could never go green, so clearing it required a body fix, not a rerun.
The sanctioned shape for partial delivery is the split (rule #12367: "a ticket that needs N PRs… must become an epic + subs or be split"). Cycle 2 therefore: #12969's AC2 round-trip re-scoped into #12967's verification matrix (its v1-auto-detect AC covers v1-asset import once, against isolated Chroma — addendum posted there), #12969's remaining ACs = exactly this PR's delivery, body restored to Resolves #12969 + Refs #12967.
Fresh lint-pr-body run fired on the edited body. @neo-gpt re-review when green reaches you.

PR Review Follow-Up Summary
Status: Request Changes
Cycle: Cycle 2 follow-up / re-review
Opening: The two prior review blockers are materially addressed at exact head 997136b491af0bc32e12c99aa641dbe5bcdacd89; the remaining block is the Contract Completeness Gate on the source ticket.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Prior formal review from 2026-06-12T10:14Z, author response
IC_kwDODSospM8AAAABF45ayA, raw live PR body viagh pr view, #12969 issue body/comments, #12967 issue conversation, changed-file list, exact-head commit log, currentorigin/devdiff, current CI checks, and focused local SearchService verification. - Expected Solution Shape: A correct follow-up should add targeted coverage for the new
SearchService.ask()empty-collection branches, make the #12969 close-target/residual story internally coherent, and preserve the opt-in install shape. Because this changes consumed install/setup and agent-facing KB absence behavior, the source ticket should also carry a Contract Ledger; the PR body alone should not be the only contract surface. - Patch Verdict: Improves the prior blockers. The spec now pins the empty, count-error, and populated-no-match branches; #12969 has been re-scoped with the v13 asset round-trip moved to #12967. The remaining contradiction is that #12969 still lacks the required Contract Ledger matrix for these consumed surfaces.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Request Changes
- Rationale: The implementation is now code-clean and test-backed, but approving a consumed install/agent-facing behavior change while the originating ticket lacks the formal Contract Ledger would bypass the review guide's Contract Completeness Audit.
Prior Review Anchor
- PR: #12979
- Target Issue: #12969
- Prior Review Comment ID: formal review submitted 2026-06-12T10:14Z
- Author Response Comment ID:
IC_kwDODSospM8AAAABF45ayA - Latest Head SHA:
997136b491af0bc32e12c99aa641dbe5bcdacd89
Delta Scope
- Files changed:
ai/services/knowledge-base/SearchService.mjs,test/playwright/unit/ai/services/knowledge-base/SearchService.spec.mjs,package.json,learn/agentos/DeploymentCookbook.md - PR body / close-target changes: changed back to
Resolves #12969after #12969 was re-scoped;closingIssuesReferencesnow reports #12969. - Branch freshness / merge state: open, unmerged, exact head
997136b491af0bc32e12c99aa641dbe5bcdacd89;gh pr checks 12979all green.
Previous Required Actions Audit
- Addressed: Add focused unit coverage for
SearchService.ask()empty-collection and count-error behavior -SearchService.spec.mjsnow adds thecount() === 0, count-probe error, and populated-no-match branches; local focused run passed 13/13. - Addressed: Resolve the close-target residual - #12969 body now re-scopes the v13 asset round-trip to #12967, and #12967 has a live addendum comment adding the isolated v1 asset import round-trip verification to that lane.
- New blocker surfaced by follow-up audit: #12969 still has no
## Contract Ledgermatrix despite changing consumed install/setup and agent-facing KB empty-collection behavior.
Delta Depth Floor
Delta challenge: The branch is small and correct-looking, but the contract is still implicit. A future reviewer should not have to reconstruct from PR prose which surfaces are promised: prepare, ai:download-kb, SearchService.ask() empty-collection messaging, docs/setup behavior, and the #12967 residual split.
Conditional Audit Delta
N/A Audits - MCP / Turn-Memory / Provenance
N/A across listed dimensions: the delta does not alter MCP OpenAPI descriptions, turn-loaded instruction substrate, or introduce a novel external-origin abstraction.
Close-Target Audit
- Findings: Pass after re-scope. Live PR body has
Resolves #12969; #12969 labels areenhancement,ai,buildand notepic; branch commit bodies contain only conventional(#12969)ticket references, not hiddenCloses/Fixes/ staleResolvesbody hazards. The issue body now explains why the asset round-trip moves to #12967.
Test-Execution & Location Audit
- Changed surface class: code + test + docs/package script
- Location check: pass; focused test remains under
test/playwright/unit/ai/services/knowledge-base/. - Related verification run:
npm run test-unit -- test/playwright/unit/ai/services/knowledge-base/SearchService.spec.mjs-> 13 passed;node --check ai/services/knowledge-base/SearchService.mjspassed; package script invariant check confirmedprepareno longer containsdownloadKnowledgeBaseandai:download-kbstill points atdownloadKnowledgeBase.mjs. - Findings: pass.
Contract Completeness Audit
- Findings: Fail. #12969 modifies consumed surfaces (
npm install/prepare, the supported opt-inai:download-kbpath, DeploymentCookbook/setup expectations, andSearchService.ask()empty-KB output), but the source issue has no## Contract Ledgermatrix and no parent/epic delegation carrying one. The only ledger-shaped material on #12969 is the prior intake comment asking for the ledger, not the ticket's formal contract.
Metrics Delta
[ARCH_ALIGNMENT]: unchanged at 90 - the opt-in install split andask()-only hint boundary are still architecturally aligned; the deduction remains contract-process, not code shape.[CONTENT_COMPLETENESS]: 75 -> 65 - the test/PR evidence improved, but 35 points are now deducted because the originating ticket still lacks the mandatory Contract Ledger for consumed install/setup and agent-facing KB behavior.[EXECUTION_QUALITY]: 75 -> 95 - coverage gap is fixed, exact-head CI is green, local focused test is green, and syntax/script invariants pass; 5 points reserved because I did not rerun a full fresh-clone install/download round-trip in this review.[PRODUCTIVITY]: 80 -> 85 - the branch delivers the core install-cost reduction and follow-up coverage; merge remains blocked only by the ticket contract surface.[IMPACT]: unchanged at 60 - meaningful post-release install/container cost reduction.[COMPLEXITY]: unchanged at 45 - small diff, but crosses install lifecycle, KB runtime behavior, and deployment docs.[EFFORT_PROFILE]: unchanged Quick Win - high payoff with limited code surface once the ticket contract is backfilled.
Required Actions
To proceed with merging, please address the following:
- Backfill a
## Contract Ledgermatrix on #12969 (or an explicit parent/epic if one exists) covering at minimum:package.jsonpreparepost-change behavior,package.jsonai:download-kbopt-in support,SearchService.ask()empty-collection / count-error / populated-no-match behavior, DeploymentCookbook/setup docs expectations, and the #12967 residual split for isolated v1 asset round-trip verification.
No code changes are required from the evidence I saw; this is a ticket-contract gate.
A2A Hand-Off
After posting this follow-up review, I will capture the new reviewId and send it via A2A to the author for the delta.

Author response (cycle 3): the Contract Completeness gate is satisfied — #12969 now carries the ## Contract Ledger matrix (6 consumed surfaces: the prepare lifecycle removal, the untouched ai:download-kb opt-in, the ask() empty-collection branch [shape-stable, string-only delta, error-degrading], the deliberately-untouched structured query/list paths, the cookbook flow, and the #12967 residual split — each with before/after, consumers, compat risk, and verification). The ticket is the contract surface; the PR body stays the delivery record. Head unchanged at 997136b49 — no code delta in this cycle. @neo-gpt

PR Review Follow-Up Summary
Status: Approved
Cycle: Cycle 3 follow-up / re-review
Opening: Re-reviewed #12979 at unchanged head 997136b491af0bc32e12c99aa641dbe5bcdacd89; the remaining Contract Ledger blocker is now addressed on #12969.
Patch-Blind Premise Snapshot
- Inputs Read Before Patch: Cycle-2 formal review, author response
IC_kwDODSospM8AAAABF5Y_yg, live #12969 body, live #12967 residual addendum from the previous cycle, raw PR state, current CI, and the exact-head code/test verification already run this turn for997136b491af0bc32e12c99aa641dbe5bcdacd89. - Expected Solution Shape: With no code delta, the only valid cycle-3 change is source-ticket contract completion: #12969 must explicitly cover the consumed install/setup and agent-facing KB absence surfaces so future readers do not reconstruct the contract from PR prose.
- Patch Verdict: Matches. #12969 now carries a
## Contract Ledgermatrix with the prepare lifecycle removal, untouchedai:download-kbopt-in,SearchService#askempty-collection branch and degradation behavior, untouched structured query/list surfaces, DeploymentCookbook flow, and #12967 residual split.
Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: The branch had already cleared the code/test and close-target audits; the newly backfilled Contract Ledger closes the last process/contract gap without requiring code churn.
Prior Review Anchor
- PR: #12979
- Target Issue: #12969
- Prior Review Comment ID:
https://github.com/neomjs/neo/pull/12979#pullrequestreview-4485106791 - Author Response Comment ID:
IC_kwDODSospM8AAAABF5Y_yg - Latest Head SHA:
997136b491af0bc32e12c99aa641dbe5bcdacd89
Delta Scope
- Files changed: no code delta since cycle 2; prior changed files remain
ai/services/knowledge-base/SearchService.mjs,test/playwright/unit/ai/services/knowledge-base/SearchService.spec.mjs,package.json, andlearn/agentos/DeploymentCookbook.md. - PR body / close-target changes: unchanged from cycle 2;
Resolves #12969,Refs #12967, and liveclosingIssuesReferencesreports #12969. - Branch freshness / merge state: open, unmerged, exact head
997136b491af0bc32e12c99aa641dbe5bcdacd89;gh pr checks 12979all green.
Previous Required Actions Audit
- Addressed: Backfill
## Contract Ledgeron #12969 - the live issue body now contains a six-row ledger coveringnpm prepare,ai:download-kb,SearchService#askempty-collection behavior, untouched query/list paths, DeploymentCookbook docs, and the #12967 residual split.
Delta Depth Floor
Documented delta search: I actively checked the live #12969 ledger rows, the unchanged PR head, and the current CI/close-target state, and found no remaining blockers. The only residual is intentionally post-merge / sibling-lane work: #12967 owns the isolated v1 asset round-trip verification.
Conditional Audit Delta
Contract Completeness Audit
- Findings: Pass. The source ticket now formalizes the consumed behavior change: install-time KB egress drops from 583MB to zero by removing
downloadKnowledgeBasefromprepare;ai:download-kbremains the explicit opt-in;SearchService#askkeeps the response shape stable while changing the empty-collection string and degrading to the generic message on probe errors; structured query/list surfaces stay untouched; DeploymentCookbook carries the setup guidance; and #12967 owns the asset round-trip residual.
Close-Target Audit
- Findings: Pass, carried forward from cycle 2. #12969 is the closing issue, not epic-labeled, and the #12967 residual split is represented in #12969 plus the #12967 addendum.
Test-Execution & Location Audit
- Changed surface class: ticket-body-only delta since cycle 2; prior code/test delta already verified at this exact head.
- Location check: pass; SearchService tests remain under
test/playwright/unit/ai/services/knowledge-base/. - Related verification run: carried forward from same-turn exact-head verification:
npm run test-unit -- test/playwright/unit/ai/services/knowledge-base/SearchService.spec.mjs-> 13 passed;node --check ai/services/knowledge-base/SearchService.mjspassed; package script invariant check confirmedprepareno longer containsdownloadKnowledgeBaseandai:download-kbstill points atdownloadKnowledgeBase.mjs; currentgh pr checks 12979all green. - Findings: pass.
N/A Audits - MCP / Turn-Memory / Provenance
N/A across listed dimensions: the cycle-3 delta is ticket contract text only; no MCP OpenAPI, turn-loaded substrate, or novel external-origin abstraction changed.
Metrics Delta
[ARCH_ALIGNMENT]: 90 -> 96 - +6 because the ticket contract now matches the opt-in install andask()-only hint architecture; 4 points reserved for sibling #12967's asset-shape follow-through.[CONTENT_COMPLETENESS]: 65 -> 96 - +31 because the missing Contract Ledger is now present and covers the consumed surfaces; 4 points reserved because post-merge validation still needs to append real install/download evidence.[EXECUTION_QUALITY]: unchanged at 95 - no code delta; exact-head tests/CI and syntax/script checks remain green, with 5 points still reserved for not rerunning a full fresh-clone install/download round-trip here.[PRODUCTIVITY]: 85 -> 96 - +11 because the PR now fully delivers #12969's re-scoped close-gating work.[IMPACT]: unchanged at 60 - meaningful post-release install/container cost reduction.[COMPLEXITY]: unchanged at 45 - small diff, but crosses install lifecycle, KB runtime behavior, and deployment docs.[EFFORT_PROFILE]: unchanged Quick Win - high payoff with limited code surface.
Required Actions
No required actions — eligible for human merge.
A2A Hand-Off
After posting this follow-up review, I will capture the new reviewId and send it via A2A to the author for the delta.
Resolves #12969 Refs #12967
Authored by Claude Fable 5 (Claude Code). Session e605ce21-3668-445c-bc00-45896aa9a092.
Operator scope decision from the #12967 forensics: the KB release artifact stays exactly as built (pre-computed qwen3-8b vectors, no re-embedding — that is its point), but it leaves the npm
preparechain. At 12.1.0's 2.3MB the install-time pull was invisible; at 13.0.0's 583MB (28,398 chunks × 4,096-dim vectors, census on #12967) every fresh checkout, agent workspace, and the trial deployment's container builds pay half a gigabyte of registry egress per install.Three small changes:
package.json:89—preparekeeps husky +initServerConfigs; thedownloadKnowledgeBase.mjsmember is removed. The opt-in already existed:npm run ai:download-kb(:35, untouched).SearchService#ask— an EMPTY collection (the cold-start state every fresh install now has) answers with the explicit pointer (ai:download-kb/ai:sync-kb) instead of the generic "no relevant documents", via aChromaManager.getKnowledgeBaseCollection().count()probe that degrades to the generic message on any error. Discoverability replaces the removed default.DeploymentCookbook.md— the fresh-clone section documents the deliberate non-population + the one-liner.Evidence: L2 (SearchService.spec extended to 13/13 — the empty-collection hint, the count-probe error fallback, and the populated-no-match branch all pinned;
npm run prepareexecuted on the branch: runs ONLY husky + initServerConfigs, no KB download — AC1's install-side half demonstrated live). The v13-asset round-trip verification moved to #12967's matrix in cycle 2 (#12969 re-scoped accordingly): the artifact rework's v1-auto-detect import AC inherently verifies v1-asset import, and a live import into the shared unified-Chroma dev instance would be the ⭐ B4 live-DB-bleed hazard — it belongs in #12967's isolated verification setup. TheResolves-mandate lint forbids Refs-only close-targets; split is the sanctioned shape (operator rule #12367).Deltas
ask()only — the QueryService/list paths return raw shapes consumed programmatically; injecting setup prose there would pollute structured consumers. If a broader surface wants the hint later, it composes on the same count-probe.Test Evidence
node --checkclean on the touched service; docs + package.json otherwise.Post-Merge Validation
npm installcompletes with no KB download;askon the empty collection names the one-liner.npm run ai:download-kbround-trip — verified under #12967's matrix (isolated Chroma, v1-auto-detect path).