feat: StateStore.loadAll({ maxParseBytes }) — stat-only parse budget for sub-linear startup - #186
feat: StateStore.loadAll({ maxParseBytes }) — stat-only parse budget for sub-linear startup#186ranxianglei wants to merge 2 commits into
Conversation
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)In your adapter project: npm install acp-kernel@pr-186Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf acp-kernel-pr186.tgz
npm install ./packageThis comment is automatically updated on each push. |
[bot] 🏷 独立评审通过(附 2 处已修复的文档/测试问题,已推送到 PR 分支) 查重:本 PR 是 #185 的实现产出,仓库内无其他相似 issue/PR(已按 loadAll budget / statAll / startup cost 检索)。 独立验证(本会话全新上下文,未复用实现时的结论)
发现的问题(已修复,commit
|
Closes #185.
Motivation
Startup cost of
loadAllgrows linearly with corpus size: every boot doesreadFileSync+JSON.parseover all surviving records, even after startup GC caps the corpus (billion-context#478). At GB-scale corpora that is 100ms~seconds of synchronous parsing per boot, and it keeps growing with session count.billion-context cannot work around this in-repo: selective loading would require replicating the kernel's canonical/spill (
<name>.fb.json) savedAt reconciliation ("freshest wins") — a fragile copy of kernel internals.What this PR does
Implements suggestion 1 from the issue (purely additive, default behavior unchanged):
Suggestion 2 (
statAll()) was rejected: flat filenames are one-way hashes (sha256(id)[:24].json) and the id lives inside the envelope, so id-keyed metadata would require reading content anyway; a path-keyed variant would push canonical/spill pairing and freshest-wins onto the consumer — exactly the fragile duplication the issue rejects.Semantics
maxParseBytes: pass 1 is readdir + stat only (no content reads). Each canonical<stem>.jsonis paired with its<stem>.fb.jsonspill under a dir+stem key (same stem in different dirs = different records). Group size = sum of member sizes; group freshness = max mtimeMs. Groups are filled newest-first while the running total stays within budget (skip-and-continue).Mapplus a warn log[persist] loadAll budget <N> bytes: parsed K/M record groups (skipped ...). Skipped files are never deleted and remain loadable vialoadSync(id, hint).maxParseBytesthrowsTypeErrorfail-fast.The hard constraint from the issue is honored: a record's canonical and spill variants are selected together or not at all, so freshest-wins semantics can't break on a half-parsed pair.
Tests (tests/persist.test.ts, +5)
loadAll()still parses everything; skipped files stay on disk and remainloadSync-able (skip ≠ delete).-1/NaN→TypeError.Verification
npm run typecheck✅npm test— 577 pass / 0 fail ✅npm run build✅No version bump (feature branch; release workflow handles that separately).
Release ordering (cross-repo rule)
This must land and publish to npm first; billion-context then bumps its exact-version dependency on
acp-kerneland consumesloadAll({ maxParseBytes })fromSessionStore.boot()to turnBILI_MAX_SESSIONSinto a true load budget.Per AGENTS.md §6: requires review by at least 2 separate agents before merge.