Follow-up from PR #597 (chemical-mapping retraction pass). The pass is safe today, but two design limitations are worth hardening before the retraction list grows.
1. Object-granular retraction depends on a frozen external analysis
apply_retractions drops at the object level (del self.chemicals[oid]), but the underlying data is name→object groundings. If a listed stale object is also the correct grounding for some name that is not in the retraction list — now or as the synced upstream (UNIFIED_INGREDIENT_MAPPING.tsv, the MIM SSSOM) evolves — that name is silently orphaned. The sole-source guard can't prevent this (the legitimate name would also be sole-sourced from culturebotai_reviewed).
Mitigations already in place (PR #597 review round): a non-fatal orphan guard warns if any now_asserted target is absent after the pass. Verified 0 orphans on the current 161-row list.
Possible further hardening:
- Move to name-level retraction (drop the specific
(name, object) grounding, keep the object if other names still point to it), or
- Make the orphan guard fatal in CI once we trust it, or
- Regenerate/re-verify the retraction list from a diff of consecutive
culturebotai_reviewed inputs rather than a frozen file.
2. del self.chemicals[oid] leaves dangling name_index / formula_index entries
The drop removes only the self.chemicals record; name_index[norm_name] / formula_index[formula] still point at the deleted CURIE. Harmless today (export_unified_sssom and propagate_synonyms_via_xrefs both iterate/snapshot self.chemicals and don't consult name_index afterward), but a latent trap for any future code that resolves a name via name_index after this pass. Cheap fix: prune those indices in the drop loop.
3. Test coverage
Added in review: idempotency, curator-qualified sole-source, empty-source-not-dropped. Still worth adding: an explicit orphan-detection test (a listed object that is also the sole-source correct target of a second unlisted name).
Context: root cause of 3 of the 16 stale objects is upstream and filed at CultureBotAI/MediaIngredientMech#138.
Follow-up from PR #597 (chemical-mapping retraction pass). The pass is safe today, but two design limitations are worth hardening before the retraction list grows.
1. Object-granular retraction depends on a frozen external analysis
apply_retractionsdrops at the object level (del self.chemicals[oid]), but the underlying data is name→object groundings. If a listed stale object is also the correct grounding for some name that is not in the retraction list — now or as the synced upstream (UNIFIED_INGREDIENT_MAPPING.tsv, the MIM SSSOM) evolves — that name is silently orphaned. The sole-source guard can't prevent this (the legitimate name would also be sole-sourced fromculturebotai_reviewed).Mitigations already in place (PR #597 review round): a non-fatal orphan guard warns if any
now_assertedtarget is absent after the pass. Verified 0 orphans on the current 161-row list.Possible further hardening:
(name, object)grounding, keep the object if other names still point to it), orculturebotai_reviewedinputs rather than a frozen file.2.
del self.chemicals[oid]leaves danglingname_index/formula_indexentriesThe drop removes only the
self.chemicalsrecord;name_index[norm_name]/formula_index[formula]still point at the deleted CURIE. Harmless today (export_unified_sssomandpropagate_synonyms_via_xrefsboth iterate/snapshotself.chemicalsand don't consultname_indexafterward), but a latent trap for any future code that resolves a name vianame_indexafter this pass. Cheap fix: prune those indices in the drop loop.3. Test coverage
Added in review: idempotency, curator-qualified sole-source, empty-source-not-dropped. Still worth adding: an explicit orphan-detection test (a listed object that is also the sole-source correct target of a second unlisted name).
Context: root cause of 3 of the 16 stale objects is upstream and filed at CultureBotAI/MediaIngredientMech#138.