FAC: Add members package (step A) — mediated membership container#234
Closed
fumitoh wants to merge 7 commits into
Closed
FAC: Add members package (step A) — mediated membership container#234fumitoh wants to merge 7 commits into
fumitoh wants to merge 7 commits into
Conversation
Introduce modelx.core.members as the keystone of the separation-of-concerns refactor. MemberContainer replaces the raw cells/own_refs/named_spaces dicts on BaseSpaceImpl with a single observable, defined/derived-aware surface so composition, inheritance and namespace assembly stop sharing raw dicts and faking notifications. NamespaceSource/NamespaceComposer realize the already-documented-but-dead "subjects in priority order" design in NamespaceServer, enabling step B. Not yet wired into space.py — this is the reviewable interface artifact that steps B and C hang off. https://claude.ai/code/session_01WiPQBiJXuU4DRgCicANTd7
Swap the three raw member dicts on BaseSpaceImpl and ModelImpl for MemberContainer. MemberContainer now subclasses dict so this change is byte-for-byte behavior-preserving: every existing call site (item access, del, pop, dict.__setitem__ in _rename_item, sort_dict, use as a CustomChainMap layer, the file serializers, pickling of the space<->member reference cycle) keeps working unchanged. The notifying mutation API (set/remove/move_to_end/sort/rename/flush) and Subject nature remain additive for steps B/C; notification still flows through the existing on_notify path in step A. Verified: 746 core+serialize and 164 io/managers tests pass; inheritance propagation and file-serializer round-trip exercised end to end. https://claude.ai/code/session_01WiPQBiJXuU4DRgCicANTd7
Replace the hardcoded three-phase assembly in BaseSpaceImpl.on_update_ns (named_spaces / refs isinstance-ladder / cells) with a one-line delegate to members.fill_space_namespace. The ordering, per-kind value projection, and the refs isinstance ladder now live in members/source.py expressed via the NamespaceSource abstraction, realizing the "subjects in priority order" design NamespaceServer already documented. The refs chainmap is passed directly so its collapsed .items() is byte-for-byte the old loop; the existing on_notify invalidation path is unchanged (persistent composer/observer wiring is deferred to step C). Verified: 910 core/serialize/io/managers tests pass; nested-space namespace, inherited refs, and the ItemSpace 5-layer refs chainmap projection exercised end to end. https://claude.ai/code/session_01WiPQBiJXuU4DRgCicANTd7
…r API Untangle the namespace<->inheritance coupling at its core: the space now observes its own cells/own_refs MemberContainers, so the notifying container API (set/remove) drives the existing NamespaceServer.on_notify invalidation. on_del_cells/on_create_ref/on_del_ref (and on_change_ref via the latter two) drop their manual ``self.on_notify(self.cells)`` / ``on_notify(self.own_refs)`` calls and mutate through .remove()/.set(). Behavior is preserved: the observer edge triggers exactly the same on_notify path the explicit calls did, at the same point, with the same notification count. on_rename is left raw (its pop+reinsert moves the entry to the end, unlike MemberContainer.rename which is position-preserving). __setstate__ re-establishes the space->container observation that MemberContainer.__setstate__ resets, mirroring the dynamic_cache pattern. Verified: 910 core/serialize/io/managers tests pass; live ref-change and cell-redefine invalidation and a full file-serializer round-trip (restored model still invalidates correctly) exercised end to end. https://claude.ai/code/session_01WiPQBiJXuU4DRgCicANTd7
…tance pkg Move the body of UserSpaceImpl.on_inherit into modelx.core.inheritance. inherit_members; on_inherit is now a one-line delegate. The algorithm (diff member container vs bases, create derived placeholders, reorder base-before-defined, recurse into derived members, drop stale derived) is relocated verbatim and operates on the space's MemberContainers. This is a behavior-preserving move: the container mutations stay the original raw dict operations (MemberContainer is a dict subclass, so notification timing is unchanged); converting them to the notifying API is deliberately deferred. space.on_del_cells/on_del_ref remain on the space and are invoked from the extracted function exactly as before. No import cycle: inheritance imports cells/reference/chainmap, none of which import space. Verified: 910 core/serialize/io/managers tests and 121 inheritance-focused tests pass; multi-level derivation, defined-overrides-derived, base-member add/remove propagation exercised end to end. https://claude.ai/code/session_01WiPQBiJXuU4DRgCicANTd7
…tance pkg Move the node-path helpers and the seven engine classes (SpaceGraph, Instruction, InstructionList, SharedSpaceOperations, SpaceManager, SpaceUpdater, ReferenceManager) verbatim from the tail of model.py into modelx.core.inheritance.manager. Logic is untouched -- only the location changes. The model<->engine import cycle is broken by referencing the model class lazily as _model.ModelImpl (runtime attribute access on the partially-initialized model module; the engine only needs it inside method bodies). model.py re-exports all moved names so modelx.core.model.SpaceManager etc. remain valid (identity preserved). inheritance/__init__ deliberately does NOT import manager, so space.py -> inheritance -> updater stays cycle-free. Verified: 910 core/serialize/io/managers + 138 inheritance/copy/graph/mro tests pass; add_bases/remove_bases/copy_space/MRO/nested derivation and a full file-serializer round-trip (spmgr and _graph reconstructed) exercised end to end. https://claude.ai/code/session_01WiPQBiJXuU4DRgCicANTd7
…dependency Introduce modelx.core.execution.invalidation, an execution-owned port (invalidate_object / invalidate_attr_referrers). The inheritance/ composition hooks that used to reach directly into the TraceManager (self.model.clear_obj / clear_attr_referrers) now call this port instead: on_del_cells, on_sort_cells, on_change_ref, on_del_ref, on_rename (space.py), CellsImpl.on_inherit (cells.py), ReferenceImpl.on_inherit (reference.py). The knowledge of how trace invalidation maps onto TraceManager calls now lives in the execution package, mirroring how members.fill_space_namespace owns the namespace rule. Dispatch is synchronous and the underlying calls and their timing are byte-for-byte unchanged -- only the direction of the dependency is inverted. An async publish/subscribe variant was deliberately not done: it would move when invalidation happens relative to member detachment, risking silently stale dependency graphs. Out-of-scope execution-internal self-invalidation (Cells.reload/set_formula/on_set_property) is left as-is. Verified: 910 core/serialize/io/managers + 178 inheritance/ref tests pass; derived-cell formula change, derived-ref change, cell deletion and ref change all invalidate correctly through the new port end to end. https://claude.ai/code/session_01WiPQBiJXuU4DRgCicANTd7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduce modelx.core.members as the keystone of the separation-of-concerns refactor. MemberContainer replaces the raw cells/own_refs/named_spaces dicts on BaseSpaceImpl with a single observable, defined/derived-aware surface so composition, inheritance and namespace assembly stop sharing raw dicts and faking notifications. NamespaceSource/NamespaceComposer realize the already-documented-but-dead "subjects in priority order" design in NamespaceServer, enabling step B. Not yet wired into space.py — this is the reviewable interface artifact that steps B and C hang off.
https://claude.ai/code/session_01WiPQBiJXuU4DRgCicANTd7