gabriel / musehub public
Open #204 Bug
filed by gabriel human · 33 days ago

CRDTPlugin.join() is unreachable from muse merge — schema().merge_mode is never consulted by CLI routing

0 Anchors
— Blast radius
— Churn 30d
0 Proposals
No description provided.
◎ Activity1
●
gabriel opened this issue 33 days ago
○
gabriel 33 days ago

Confirmed while building Episode 12 ("CRDT Primitives") demo material.

Finding: the CRDT convergent-merge subsystem is real, well-designed, and heavily unit-tested (163 tests across tests/test_crdt.py, tests/test_crdts.py, tests/test_stress_crdts_exhaustive.py — including an exhaustive lattice-law stress test for commutativity/associativity/idempotency) — but it is completely disconnected from the actual muse merge command.

Root cause: muse core.merge_engine.crdt_join_snapshots() has zero callers anywhere in the codebase outside its own module docstring, which claims it "is the CRDT entry point for the muse merge command." It isn't.

muse merge's real CLI routing (muse/cli/commands/merge.py) picks its MergeEngine purely from STRATEGY_MAP.get(strategy or "recursive"), where strategy is a --strategy flag with values recursive/overlay/snapshot/ replay/ours/theirs. Nothing in merge.py or run_merge() (muse/core/merge_engine.py) ever reads plugin.schema()["merge_mode"]. DomainSchema.merge_mode: Literal["three_way", "crdt"] exists and is documented ("route to CRDT convergent join when merge_mode is 'crdt'" — muse/core/schema.py:10), but nothing actually branches on it.

Compounding this: no registered domain plugin even declares merge_mode="crdt" today. ScaffoldPlugin (the plugin-authoring template) implements crdt_schema()/join()/to_crdt_state()/from_crdt_state() fully, but its own schema() still returns merge_mode="three_way" with an explicit # TODO: change to "crdt" if implementing CRDT convergent merge comment — so even the one plugin with a working join() doesn't opt into it.

Suggested fix: in run_merge() (or its caller in merge.py), check isinstance(plugin, CRDTPlugin) and plugin.schema()["merge_mode"] == "crdt" before falling into the three_way/AddressedMergePlugin branch, and route to crdt_join_snapshots() when true. Needs a decision on where CRDT state (vclock, crdt_state) gets persisted across commits — currently no commit metadata field carries it, so to_crdt_state()/from_crdt_state() round-trip has no real storage backing yet either.

Not data-integrity risk — nothing currently exercises this path, so nothing is silently wrong for users. It's an unfinished integration, not a regression. Deferred per usual until after the season wraps.