LearnNewsExamplesServices
Frontmatter
id14086
titleBackup verification skips KB parity: KB export count is string-only
stateClosed
labels
bugaitestingarchitecture
assigneesneo-opus-vega
createdAtJun 26, 2026, 3:03 PM
updatedAtJun 26, 2026, 3:33 PM
githubUrlhttps://github.com/neomjs/neo/issues/14086
authorneo-opus-vega
commentsCount0
parentIssue14030
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 26, 2026, 3:33 PM

Backup verification skips KB parity: KB export count is string-only

Closed v13.1.0/archive-v13-1-0-chunk-6 bugaitestingarchitecture
neo-opus-vega
neo-opus-vega commented on Jun 26, 2026, 3:03 PM

Context

Discovered closing the #14082 Post-Merge Validation: the 2026-06-26 canonical backup completed, but its integrity report showed kb: status: skipped while mc/graph were pass. The 1.0 GB Knowledge Base bundle is written but never row-count parity-verified — a torn/partial KB export would not be caught, undermining the backup as a trustworthy recovery source (the exact #14030 concern).

The Problem

verifyBundleIntegrity (backup.mjs:311) derives each subsystem's source count as typeof raw === 'number' ? raw : raw?.count. For kb, subsystems.kb is the return of KB_DatabaseService.manageDatabaseBackup({action:'export'}), which is:

// ai/services/knowledge-base/DatabaseService.mjs:121-122
const count = await this.#exportCollection(collection, backupPath, 'knowledge-base-backup');
return {message: `Export complete. Exported ${count} knowledge base chunks.`};

The count exists but is embedded in a string with no numeric field → raw?.count is undefinedverifyBundleIntegrity records skipped ("no numeric source count returned by SDK"). Memory Core's export return exposes a numeric count (which is why mc: pass 24044/24044 works), so KB is the lone unverified subsystem.

The Architectural Reality

  • ai/services/knowledge-base/DatabaseService.mjs:117-122exportDatabase returns {message} only; the numeric count is already computed at :121 but dropped from the return.
  • ai/services/knowledge-base/DatabaseService.mjs:242manageDatabaseBackup forwards exportDatabase's return for action: 'export'.
  • ai/scripts/maintenance/backup.mjs:311 — the verifier reads raw?.count; :329 then streams the bundle file (the #14082 streaming fix already handles KB's >512 MB file, so once a numeric count is present, KB verifies safely).
  • Contrast: ai/services/memory-core/DatabaseService.mjs export returns numeric expected/exported stats that surface as a numeric count.

The Fix

Surface the numeric count on KB's export return so verifyBundleIntegrity resolves a numeric source count for kb and verifies parity (pass/empty/fail) instead of skipped:

return {message: `Export complete. Exported ${count} knowledge base chunks.`, count};

Additive — the existing message is preserved. No verifier change needed (raw?.count already reads it). The #14082 streaming counter handles the 1.0 GB KB bundle.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
KB_DatabaseService.exportDatabase() / manageDatabaseBackup({action:'export'}) return verifyBundleIntegrity raw?.count contract (backup.mjs:311) Add numeric count alongside the existing message n/a — additive, message unchanged exportDatabase JSDoc @returns Unit: KB export return carries numeric count; verifyBundleIntegrity reports pass (not skipped) for a populated KB
verifyBundleIntegrity kb verdict unchanged kb now parity-verified like mc/graph Still skipped if count absent (back-compat) function JSDoc Integration: runBackup integrity[] has kb non-skipped

Decision Record impact

aligned-with #14030 (backup-substrate trustworthiness) / ADR-0025/0026 (backup feeds the recovery source-of-last-resort). No ADR amended.

Acceptance Criteria

  • KB exportDatabase / manageDatabaseBackup({action:'export'}) returns a numeric count (existing message preserved).
  • verifyBundleIntegrity reports kb as pass/empty/fail (parity-verified), not skipped, for a populated KB.
  • A torn/short KB bundle is caught as fail (the trust gap closed).
  • Unit coverage for the KB export return shape and the kb verification path.

Out of Scope

  • Changing the human-readable message string.
  • KB chunking / over-budget skip (#14033 / #14000).
  • The MC-side streaming verification (#14082, shipped) — this consumes it.

Avoided Traps

  • Parsing the count out of the message string in the verifier — brittle; surface a structured numeric field at the source instead.

Related

  • #14030 (parent — backup reliability / verify restorability), #14082 (sibling — the MC-side streaming verification fix that exposed this), #14048 (empty-parity verification), #13999 (the recovery whose completing backup surfaced it).

Handoff Retrieval Hints

  • query_raw_memories("KB backup export numeric count verifyBundleIntegrity skipped parity")
  • Exact anchors: exportDatabase (ai/services/knowledge-base/DatabaseService.mjs:121), verifyBundleIntegrity raw?.count (backup.mjs:311).

Authored by Vega (Claude Opus 4.8, Claude Code) — surfaced closing #14082's PMV during the 2026-06-26 v13.1 backup work. Session c94ea3b2-1ae8-48fd-8f34-1c54d90f5caa.

tobiu referenced in commit 8b0f760 - "fix(ai): surface numeric count on KB backup export for verification parity (#14086) (#14087) on Jun 26, 2026, 3:33 PM
tobiu closed this issue on Jun 26, 2026, 3:33 PM