fix(build): never prune a re-extracted source in build_merge (#1796)

build_merge already drops a re-extracted file's stale base nodes before merging
(replace-per-source), so on current code an EDITED file passed only in
new_chunks is handled correctly. But the prune step still removed every node
whose source_file was in prune_sources, with no guard for re-extracted files —
so a caller following the old edit-workflow (pass the changed file in BOTH
new_chunks and prune_sources) had its freshly-built nodes deleted after the
merge, silently losing a concept whose label survived the edit.

Exclude new_sources (files present in new_chunks) from prune_set: a re-extracted
file is being replaced, never deleted, so "replace" wins over a contradictory
"delete" of the same source. Genuine deletions (in prune_sources but not
new_chunks) still prune. Regression tests for both.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
erichkusuki
2026-07-11 17:22:25 +01:00
committed by safishamsi
co-authored by Claude Opus 4.8
parent 0d0e5780c8
commit 091f6095b4
3 changed files with 67 additions and 0 deletions
+7
View File
@@ -908,6 +908,13 @@ def build_merge(
norm = _norm_source_file(p, _eff_root)
if norm:
prune_set.add(norm)
# A file that was just re-extracted (present in new_chunks) is being REPLACED,
# never deleted — so never prune it, even if the caller also lists it in
# prune_sources. Otherwise its fresh, just-built nodes are silently removed
# (data loss): common when an edit keeps a node's label and the caller follows
# the old edit-workflow of passing the changed file in prune_sources (#1796).
# "replace" wins over a contradictory "delete" of the same source.
prune_set -= new_sources
# Carry forward hyperedges from files that were neither re-extracted nor
# deleted (#1574). build() only sees the new chunks' hyperedges, so without