LearnNewsExamplesServices
Frontmatter
id15692
titleStream vector restores with bounded importer batches
stateClosed
labels
enhancementaitestingarchitectureperformance
assigneesneo-gpt-emmy
createdAtJul 22, 2026, 11:45 AM
updatedAtJul 22, 2026, 9:10 PM
githubUrlhttps://github.com/neomjs/neo/issues/15692
authorneo-gpt-emmy
commentsCount3
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[ ] 15639 Cloud deployment: opt-in first-boot restore from latest backup bundle, [ ] 15693 Implement orchestrator-governed restore-delta-merge
closedAtJul 22, 2026, 9:10 PM

Stream vector restores with bounded importer batches

Closed Backlog/active-chunk-8 enhancementaitestingarchitectureperformance
neo-gpt-emmy
neo-gpt-emmy commented on Jul 22, 2026, 11:45 AM

Context

The cloud-scale bottleneck in ai:restore is now measured. The Knowledge Base importer reads every JSONL row into records[] before its first 500-row write; Memory Core does the same before 250-row writes and, in merge mode, also retains file-wide existing/missing sets.

The disposable matrix in #15695 measured 20,000 preserved 4,096-dimensional vectors at 1,232.9 MiB Node RSS for MC and 1,332.2 MiB for KB, before counting the separate Chroma process. Neither importer made its first store request before EOF. Provider healthy/cold/unreachable produced zero embedding calls, so the pressure is parse retention plus store serialization, not re-embedding.

The Problem

Downstream Chroma writes are chunked, but upstream parsing is not. A constrained Agent OS deployment can therefore exhaust its Node budget before making useful restore progress. MC merge also defeats the intended bound by retaining whole-file ID sets after parsing.

The Architectural Reality

  • KB_DatabaseService.importDatabase({file, mode, confirmation}) owns KB JSONL ingestion and currently returns {message, imported, mode}.
  • Memory_DatabaseService.importDatabase({file, mode, reEmbed=false, confirmation, preserveDeliveryReadState=false}) owns MC JSONL ingestion and currently returns {message, imported, mode, counts}.
  • Existing write bounds remain 500 rows for KB and 250 rows for MC; this ticket changes when those batches flush, not their measured sizes.
  • #15691 owns full-file parse/vector/bundle compatibility validation before any restore mutation.
  • #15693 owns the autonomous ADR-0027 envelope: orchestrator selection/admission, durable restore-run state, retry policy, heavy-maintenance lease, writer fencing, resumable shadow identity, validation-clean promotion, rollback, and durable receipts.
  • Explicit vectors stay explicit. This ticket must not call the embedding provider or acquire re-embedding authority.

The Fix

  1. In both DatabaseService importers, parse JSONL asynchronously and flush as soon as the owning batch reaches its existing bound. Do not materialize a whole-file records[].
  2. In MC merge mode, run collection.get({ids, include: []}) for the current batch only, add only that batch's missing records, update aggregate counts, and release all batch-local IDs/rows before reading the next batch.
  3. Preserve current public method arguments and return envelopes. This ticket introduces no resume cursor, checkpoint store, scheduling hook, or durable receipt API.
  4. Preserve current mode semantics and truthful aggregate counts across multiple files. A failed batch must not be reported as imported.
  5. Add deterministic instrumentation/specs proving that live buffered rows and merge-ID state never exceed the owning batch plus constant parser look-ahead.
  6. Re-run the 5,000/20,000 preserved-vector matrix with provider tracing and a disposable collection seam/private Chroma daemon.

Contract Ledger Matrix

Target Surface Current Authority Behavior after this ticket Fallback / failure Docs Evidence
KB_DatabaseService.importDatabase({file, mode='merge', confirmation}) ai/services/knowledge-base/DatabaseService.mjs Same arguments and {message, imported, mode} result; parse/validate/write one ≤500-row batch at a time Current batch fails; no later rows are read or counted Existing method JSDoc, updated with the bounded-buffer invariant Unit seam + 5k/20k fixture
Memory_DatabaseService.importDatabase({file, mode, reEmbed=false, confirmation, preserveDeliveryReadState=false}) ai/services/memory-core/DatabaseService.mjs Same arguments and {message, imported, mode, counts} result; parse/validate/write one ≤250-row batch at a time Merge records a failed batch consistently with the current contract; replace remains fail-fast Existing method JSDoc, updated with the bounded-buffer invariant Unit seam + 5k/20k fixture
MC merge existence filter Current per-ID preserve-live merge semantics get(ids) and missing-row selection are batch-local; no file-wide Set or missing array A failed lookup/write affects only the active batch and is reflected in counts/error behavior MC importer JSDoc Peak batch/ID instrumentation
Restore-run checkpoint / shadow / receipt #15693 + ADR 0027 Unchanged and not implemented here; consumes this bounded primitive later #15693 fails closed without its own validated descriptor/state #15693 / ADR 0027 #15693 crash-point matrix

Decision Record impact

No ADR amendment. This ticket is a bounded data-plane prerequisite for ADR 0027 / #15693; it does not implement an autonomous mutation action or move authority out of the orchestrator.

Acceptance Criteria

  • Neither vector importer accumulates all JSONL rows, all existing IDs, or all missing rows for a file
  • KB buffered rows are bounded by 500 plus constant parser look-ahead; MC rows and merge-ID state are bounded by 250 plus constant parser look-ahead
  • Public importer arguments and return envelopes remain backward compatible
  • MC merge preserves live IDs with batch-local existence checks and truthful inserted/skippedExisting/failed aggregates
  • 5,000- and 20,000-row preserved-vector fixtures complete with zero embedding-provider calls
  • Deterministic tests falsify any store request that receives more than the owning batch bound
  • #15691 remains the full pre-mutation compatibility owner; no partial replace-success claim is introduced here
  • #15693 remains the sole owner of durable resume/checkpoint, retry, shadow/fence/promotion, and orchestrator receipts

Out of Scope

  • Full-file compatibility validation (#15691)
  • Durable checkpoints, resume cursors, transient retry policy, or progress receipts (#15693)
  • Autonomous bundle selection or action selection (#15639 / #15693)
  • Re-embedding missing or incompatible vectors
  • Changing the existing 500/250 write sizes without separate measurements

Avoided Traps

  • Chunked upsert over a whole-file array — bounds transport payload, not process memory.
  • File-wide merge sets — merely move the O(n) retention from rows to IDs.
  • Importer-owned durable checkpoint — would create a second recovery authority and overlap #15693.
  • Implicit re-embed during restore — makes provider availability a restore gate again.

Related

Origin Session ID: cb60301d-74a4-4024-b80d-2f7efdbf9cd1

Retrieval Hint: "bounded streaming vector restore importer 500 250 no records array no file-wide merge set"