fix(chunking): stable content-defined chunking with hash-based reuse planning - #1650
MauryaQbit wants to merge 2 commits into
Conversation
…planning Mid-file edits to upserted documents re-embed nearly all chunks because fixed-position boundaries shift every downstream chunk, defeating the per-chunk content-hash reuse check (appends diff fine since nothing shifts). Add @repo/chunking: structural (heading/fence) resync points plus FastCDC-style content-hash anchored cuts within sections, and planChunkReuse() which matches old/new chunks by content hash instead of position. A mid-file sentence edit on a 45KB doc now re-embeds 1 chunk instead of ~half the document. Fixes supermemoryai#1649
- bun.lock: add packages/chunking workspace so bun install --frozen-lockfile stays green - ci.yml: run chunking unit tests + type checking when packages/chunking changes (same pattern as tools/ai-sdk)
|
Update: pushed lockfile + CI wiring so this is merge-ready pending review. Second commit (\9d22f5e)
Verified locally with the exact CI toolchain (bun 1.3.6)
Note: the Actions runs for this fork PR show \�ction_required, so CI needs a maintainer to approve the workflow runs. Ready for review. |
🔎 TracePull — evidence-guided merge review@MauryaQbit @Dhravya @MaheshtheDev @Prasanna721 Go / No-Go: GO WITH CHECKSThe new stable chunking pipeline is well structured: it preserves section boundaries, splits oversized individual units, derives stable content-defined cuts, and uses content hashes for reuse. One behavior warrants validation before relying on Area to check — final chunk may exceed
|
Fixes #1649.
Problem
On the self-hosted server, updating an existing document via the /v3/documents\ customId upsert path re-embeds nearly all chunks when the edit is anywhere but the tail: a one-paragraph mid-file edit to a 105 KB doc re-embedded 1007 of 1102 chunks (~21 min CPU on 2 vCPU with local embeddings). Append-only documents diff perfectly, which points at position-sensitive chunk boundaries defeating the per-chunk reuse check for mid-file edits: an early insertion/deletion shifts every downstream boundary, so every downstream chunk hash changes and reuse never hits.
Fix
New zero-dependency shared package @repo/chunking\ (\packages/chunking) implementing exactly the two mitigations suggested in the issue:
Intended adoption on the upsert path: \chunks = stableChunkText(content)\ then \plan = planChunkReuse(storedChunks, chunks)\ and embed only \plan.embedIndices. Pure TS, no
ode:crypto, runs in Node/Bun/Workers.
Verification
14 new vitest tests (\packages/chunking/src/stable-chunking.test.ts, \�un run test\ in the package after install; verified here with vitest 3.2.4 — 14/14 pass). On a generated 45 KB / 90-chunk markdown doc:
Also covered: determinism, sequential positions + hash identity, sentence-boundary cuts, intact code-fence lines, duplicate-chunk FIFO pairing, position-independent matching, empty-input edge cases. \ sc --noEmit --strict\ (incl.
oUncheckedIndexedAccess\ + \exactOptionalPropertyTypes) and \�iome check\ are clean.
Note: the ingestion/embedding pipeline itself lives outside this monorepo, so this PR provides the algorithm + tested reference implementation for the pipeline to adopt; no existing behavior in this repo changes.