bib: Store.upsert clobbers curated tags/collections on URL-dedupe update (wipe-and-replace _sync_tags) #624
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Root cause of the CY2027-NPRM-missing-from-Zotero incident (see the milestone for the full chain).
Store.upsert(src/bib/store.py:207) dedupes by URL and, on the existing-item path, callsself.update(ekey, tags=item.tags, collections=item.collections)→_sync_tags(src/bib/store.py:423), which doesDELETE FROM item_tags WHERE item_id = ?and rewrites only the incoming set. The# Merge tagscomment merges thetags=parameter into the incoming item — it never merges with the tags already stored on the existing row._sync_collectionshas the identical wipe-and-replace hazard.Observed damage (2026-08-14): the comment-farm re-ingest (
store.upsert(rule)at src/cli/bib.py:241,251) rebuilt rule items from the FR API and wiped curated tags:5ITGVDJV(CY2027 NPRM) lostsup:2027_PFS_NPRM+file:rvu+year:2027at 05:58:13Z — added 5h earlier byfetch_nprm_addenda --year 2027 --register2KVJ2HKX(CY2026 NPRM) lostsup:2026_PFS_NPRM+file:rvu+year:2026at 00:27:43Zsup:*_PFS_NPRMtags now have zero item associations in bib; Zotero still showssup:2026_PFS_NPRMon 2KVJ2HKX only as a stale pre-wipe snapshotpfs.nprm._addendum_b_pathdiscovers Addendum B bysup:<year>_PFS_NPRMtag (NPRM_SOURCES), soload_rvu_proposedre-runs now raise "No Addendum B attachment found" for both yearsFix: on the upsert dedupe path, union the existing row's tags and collections with the incoming ones before calling
update().Store.update(tags=...)keeps its explicit replace semantics (documented); deliberate removal staysremove_tag. Regression tests: existing curated tag survives a URL-dedupe upsert; same for collection membership.Data repair is #625; Zotero catch-up sync is #626; nightly prevention is #627.