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.
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 actualmuse mergecommand.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 themuse mergecommand." It isn't.muse merge's real CLI routing (muse/cli/commands/merge.py) picks itsMergeEnginepurely fromSTRATEGY_MAP.get(strategy or "recursive"), wherestrategyis a--strategyflag with valuesrecursive/overlay/snapshot/ replay/ours/theirs. Nothing inmerge.pyorrun_merge()(muse/core/merge_engine.py) ever readsplugin.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) implementscrdt_schema()/join()/to_crdt_state()/from_crdt_state()fully, but its ownschema()still returnsmerge_mode="three_way"with an explicit# TODO: change to "crdt" if implementing CRDT convergent mergecomment — so even the one plugin with a workingjoin()doesn't opt into it.Suggested fix: in
run_merge()(or its caller inmerge.py), checkisinstance(plugin, CRDTPlugin) and plugin.schema()["merge_mode"] == "crdt"before falling into the three_way/AddressedMergePlugin branch, and route tocrdt_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, soto_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.