feat: Lumiverse .lvbak backup import, proven against a real 4.75 GiB backup - #14
Merged
Coneja-Chibi merged 25 commits intoAug 8, 2026
Conversation
…n honest report out
… its own size A real 4.75 GiB .lvbak imported fine and then died in the reply: 1,708 entities serialized into one 3.77 GiB JSON response, past the engine's ~2 GiB string ceiling (RangeError: Out of memory), reported to the user as 'not a Lumiverse backup archive'. Entities now stage on disk server side (token-keyed, bounded, cleared on shutdown), the sheet gets summary rows carrying receipt, refs, and entry count, and each checked row commits through POST /api/studio/save-staged into the same saveBundle core, with knowledgeRefs rewritten server-side under the exact keep-both and dropped-ref semantics the entity path had. Unexpected inspect errors now say so honestly instead of blaming the backup, and the loopback-only gate covers the new route (tested on both untrusted doors; server-remote tests split at the 500-line cap). Live-proven against the real backup: response 0.94 MiB in 14.2s, zero entity payloads, staged commits on the shelf, plus an adversarial review pass whose findings (multi-archive staging, dead link caveat, dead entry count, temp cleanup) are all fixed and re-proven.
# Conflicts: # docs/generated/summary-queue.json # docs/generated/summary-review.json # docs/summaries/reference/ui.json # docs/summary-reviews/reference/ui.json # src/ui/switch/storage-shape-tripwire.test.ts
… make one Creating a symlink on Windows needs elevation or Developer Mode, so the fixture threw EPERM and took the suite red for every Windows contributor - a test failing because it could not build its own setup, which says nothing about the code it guards. CI runs ubuntu, so the assertion still runs on every push.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
The Lumiverse
.lvbakbackup importer, taken from spec to working against a real backup: a 4.75 GiB archive with 32,951 entries that fans out into 1,708 entities (935 characters, 720 lorebooks, 18 presets, 14 personas, 17 regex sets). The branch carries the whole feature: the streaming ZIP64 reader, the lvbak table walk and codecs, the drop filter and import sheet, and the final piece this PR completes - commit by reference, because the naive design could not survive a real backup's size.The bug the last commit fixes
The import itself worked. The response killed it: serializing all 1,708 entities into one JSON body produced a 3.77 GiB string attempt, past the JS engine's ~2 GiB ceiling, and the resulting
RangeError: Out of memorywas reported to the user as "not a Lumiverse backup archive" while ~20 GB of RAM burned. Even without the crash, a browser could neither hold those rows nor re-upload them at commit.Now: entities stage on disk server-side (token-keyed per archive so multi-
.lvbakdrops work, bounded at 8 stagings with oldest-first eviction, cleared on shutdown),/api/inspect-archivereturns summary rows (receipt, kind, parse report, staging ref,knowledgeRefs,entryCount- the real response is 0.94 MiB), and each checked row commits through the new loopback-onlyPOST /api/studio/save-stagedinto the samesaveBundlecore, withknowledgeRefsrewritten server-side under the exact keep-both/dropped-ref semantics the entity path had. Unexpected inspect failures now say "something went wrong on Hoplight's side" instead of blaming the backup.Verification
bun run verify:ci: all gates pass. One caveat for local runs only:src/kit/providers/plan-usage.live.test.ts(pre-existing, credential-gated, untouched by this branch) hits Anthropic's live usage API and 429s when the machine is rate-limited; it skips wherever credentials are absent, including CI.Deliberately out of scope here, but worth a maintainer's eyes before users hit it. After importing the full backup above, on a fast desktop:
Happy to file these as separate issues if that's preferred.
Disclosure
AI-assisted: written with Claude Fable 5 (Claude Code), driven and live-tested by @Livingooal against his own real Lumiverse backup. The adversarial review passes were run by an independent Claude agent with fresh context.