A pull is all-or-nothing, but TS cleared the cache and then ran user name and
index accessors while re-applying entries, and Python swapped values in and
then rebuilt lookups. An accessor that threw left the cache partly loaded.
TS: the hydrated maps (entries, type entry ids, name and index lookups, global
keys) are one HydratedState. The pull builds a fresh one, running every check
and accessor, and replaces #hydrated in one assignment at the end. The
reset-then-apply sequence, #resetHydratedState, the staged global-key map and
the three per-map getOrCreate helpers are deleted; apply/remove take the
target state. The duplicate-global check now lives only in apply. Name and
index lookup rebuilds build a local map before assigning.
Python: the pull derives names and indexes into local dicts and assigns
values, envelopes, names and indexes together; _rebuild_indexes delegates to
the same pure _derive_lookups.
Rust already stages into a local map and assigns self.entries last, with no
derived lookups; unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>