LearnNewsExamplesServices
Frontmatter
id16204
titleClassify all 45 devDependencies against post-cut importers, then pick an install tier
stateClosed
labels
enhancementaiarchitecture
assigneesneo-kimi-iris
createdAtJul 31, 2026, 1:07 AM
updatedAtAug 2, 2026, 4:52 PM
githubUrlhttps://github.com/neomjs/neo/issues/16204
authorneo-opus-vega
commentsCount2
parentIssuenull
subIssues
16363 Remove the four devDependencies the census proved unreachable
16364 Implement the two-path install tier: Body default, Brain opt-in
subIssuesCompleted2
subIssuesTotal2
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 2, 2026, 4:35 PM

Classify all 45 devDependencies against post-cut importers, then pick an install tier

Closed Backlog/active-chunk-11 enhancementaiarchitecture
neo-opus-vega
neo-opus-vega commented on Jul 31, 2026, 1:07 AM

Context

Operator direction, 2026-07-30: "if chroma and better-sqlite now run inside docker, package.json (neo root level) no longer needs it. probably more now obsolete dependencies. vba." Filed as an audit-and-decide ticket rather than a removal ticket, because the V-B-A showed the two named packages are not equivalent and the blocker is not the one the framing assumed.

Live latest-open sweep at 2026-07-30T23:05Z: searched open issues for dependency / devDependencies / better-sqlite3 / chromadb; nothing equivalent (#14192 and #14079 are Chroma store concerns, not dependency placement). A2A claim sweep at the same time: no competing claim. Sweep caveat: ChromaDB is down (see #16167), so semantic retrieval was unavailable; live-GitHub-and-source only, no semantic-memory miss claimed.

What the V-B-A established

dependencies is empty — 0 keys. Everything heavy is in devDependencies (45 entries). That placement is already correct and load-bearing, and it is why the flexibility the operator wants already partly exists:

install surface gets the heavy deps? native compile
npx neo-app@latest workspace (declares neo.mjs as a dependency — buildScripts/create/app.mjs:60) no — npm never installs a dependency's devDependencies none
Body-only consumer no none
contributor cloning neomjs/neo yes yes

So exactly one audience pays the compile cost, and the operator's Body-only-user rationale for dev placement is already satisfied by construction.

The two named packages are not comparable:

  • chromadb (^3.5.0) — pure-JS HTTP client, no native build step. 12 real importers, 9 non-test: 3 container-side managers, 5 ad-hoc maintenance scripts, 1 test-isolation helper. No host daemon. Removing it saves install weight and zero compile pain.
  • better-sqlite3 (^12.11.1) — the native one, and the actual Windows prize. 56 real importers: 26 non-test, 30 test. Note a static-import grep undercounts it; several call sites use dynamic await import().

The blocker is the test surface, not the daemons. Daemon-side importers are being handled elsewhere: #16180 removes the wake path, #16202 relocates the NL recorder. But npm install pulls devDependencies regardless, so 30 specs needing a local SQLite driver keeps the native compile for every contributor no matter what the daemons do.

The Problem

Two distinct problems wear one label:

  1. Nobody knows which of the 45 devDependencies survive the cut. Only the two the operator named have been examined. "Probably more now obsolete" is a well-founded hunch with no census behind it, and a removal PR built on a hunch will either miss packages or break a lane.
  2. There is one install tier for two audiences. A Body-contributor and a Brain-contributor run the same npm install despite needing different things. That is the same Body/Brain split already applied to consumers — just never applied to contributors.

Framing "obsolete" is slightly wrong and worth correcting: post-cut these packages are still needed by Brain work and by the test suite. They are correctly placed and still compiled. The missing thing is a tier, not a deletion.

The Architectural Reality

  • package.jsondependencies: {}, devDependencies with 45 entries.
  • ai/configBase.mjs, ai/graph/storage/SQLite.mjs, ai/services/memory-core/**, ai/services/knowledge-base/**, ai/mcp/server/memory-core/helpers/** — container-side better-sqlite3 importers; correct where they are post-cut.
  • ai/daemons/wake/queries.mjs — host-side importer, owned by #16180.
  • ai/services/neural-link/RecorderService.mjs — host-side importer, owned by #16202.
  • ai/scripts/{maintenance,migrations,diagnostics,fleet}/** — ~15 real importers, invoked ad hoc; post-cut they would target a graph no longer on the host (see OQ3).
  • 30 spec files under test/playwright/** import better-sqlite3 for real.
  • buildScripts/create/app.mjs:60 — generated apps declare npmPackages: ['neo.mjs'], which is what insulates consumers.

The Fix

  1. Census. Classify all 45 devDependencies by whether a real importer (static or dynamic) survives the cut, and on which side — container, host, ad-hoc script, test, build. Mechanical, and it is the deliverable that makes any later removal safe.
  2. Report the compile-cost subset separately: which entries have native build steps, since those are the only ones that cause the pain the operator actually cares about.
  3. Decide the install tier (OQ1) — the architectural half.
  4. Remove only what the census proves unreachable, in a follow-up, once 1–3 land.

Open Questions

  • OQ1 — what is the install-tier mechanism? Candidates: (a) optionalDependencies plus capability gating so absent natives degrade rather than fail; (b) two documented install paths (npm install for Body work, an opt-in script for Brain work); (c) leave one tier and accept the compile. Falsifier for (a): capability gating only works if every consumer checks — a bare import of an absent optional dependency still throws, so this needs a real audit of call sites, not a package.json edit. Falsifier for (c): it forfeits the stated Windows win, which is the reason parity existed.
  • OQ2 — how do the 30 test importers get satisfied without a local driver? Run those specs against a container graph, gate them behind the Brain tier, or keep the driver for tests only (which reinstates the compile). This is the load-bearing question and OQ1 depends on it.
  • OQ3 — do the ~15 ad-hoc scripts move into the container, or reach the graph over HTTP? They are invoked deliberately, so requiring a Brain-tier install for them may be acceptable — but post-cut they point at a graph that no longer lives on the host, which is a quieter version of the divergence #16167 exists to prevent.
  • OQ4 — is chromadb worth removing on its own? It is genuinely removable once its 5 maintenance scripts reach Chroma over HTTP (which is what the client already does), but the payoff is install weight only. Possibly a cheap standalone win, possibly not worth a separate PR.

Acceptance Criteria

  • Every one of the 45 devDependencies is classified: real importers (static and dynamic), which side of the cut each importer lands on, and whether the package has a native build step.
  • The census distinguishes real imports from mentions; a positive control demonstrates the detection finds a known dynamic importer, since a static-only pattern undercounts (this was verified to happen).
  • The compile-cost subset is reported separately from the total.
  • OQ1 and OQ2 are answered with the rejected alternatives and their falsifiers recorded.
  • No dependency is removed in this ticket; removals follow the census.
  • The census is reproducible — a script or documented command, not a one-off table that goes stale on the next dependency change.

Out of Scope

  • Removing any dependency. This ticket produces the evidence and the tier decision; removal follows.
  • The host-side importers already owned: #16180 (wake) and #16202 (NL recorder).
  • Chroma store size concerns — #14079, #14192.
  • dependencies placement. It is empty and correct; consumers are already insulated.

Avoided Traps

  • "They're obsolete, delete them." They are correctly placed and still needed by Brain work and 30 specs. The problem is the absence of a tier, not the presence of the packages.
  • Treating chromadb and better-sqlite3 as one job. One is a pure-JS HTTP client with no compile; the other is the native module that is the entire point. Bundling them hides which work delivers the win.
  • Using a static-import grep as the census. Verified to undercount — SQLite.mjs and the NL recorder both use dynamic await import() and were invisible to a ^import .*'pkg' pattern.
  • Counting git grep -l <pkg> as importers. It matches comments and strings; the raw count over-reported by roughly 40% on one package and under-reported on another once test/** was included.

Related

  • #16167 — the cut that makes the container-side importers correct
  • #16180 — graphless wake receiver (removes the wake-path importer)
  • #16202 — NL recorder data relocation (removes the other host importer)
  • #16040 — deployment-guide rewrite, a natural consumer of the install-tier decision
  • D#16193 — contributor provisioning ideation; OQ1 overlaps its "what is a contributor's target" question

Origin Session ID: 0a7f5f1d-cf12-4698-984c-17b64eea5178

Retrieval Hint: 45 devDependencies census real importers dynamic await import better-sqlite3 native compile contributor install tier optionalDependencies capability gating chromadb pure JS

tobiu referenced in commit 2e3bf1a - "feat(ai): the devDependency census — real importers, sides of the cut, native truth (#16204) (#16354) on Aug 2, 2026, 4:35 PM
tobiu closed this issue on Aug 2, 2026, 4:35 PM
tobiu referenced in commit 6c317b9 - "build(deps-dev): remove four devDependencies the census proved unreachable (#16363) (#16369) on Aug 2, 2026, 5:43 PM