cgcardona / muse public
muse_merge_base.py python
51 lines 1.4 KB
12901c5a Initial extraction from tellurstori/maestro cgcardona <gabriel@tellurstori.com> 4d ago
1 """Muse Merge Base — find the lowest common ancestor of two variations.
2
3 Equivalent to ``git merge-base A B``. Walks both lineages and returns
4 the closest common ancestor variation_id.
5
6 Boundary rules:
7 - Must NOT import StateStore, executor, MCP tools, or handlers.
8 - May import muse_repository (for lineage queries).
9 """
10
11 from __future__ import annotations
12
13 import logging
14
15 from sqlalchemy.ext.asyncio import AsyncSession
16
17 from maestro.services import muse_repository
18
19 logger = logging.getLogger(__name__)
20
21
22 async def find_merge_base(
23 session: AsyncSession,
24 a: str,
25 b: str,
26 ) -> str | None:
27 """Find the lowest common ancestor of two variation lineages.
28
29 Walks ``parent_variation_id`` chains for both ``a`` and ``b``,
30 then returns the most recent variation_id that appears in both
31 lineages. Returns None if the variations share no common history.
32
33 Deterministic: for the same inputs, always returns the same result.
34 """
35 lineage_a = await muse_repository.get_lineage(session, a)
36 lineage_b = await muse_repository.get_lineage(session, b)
37
38 if not lineage_a or not lineage_b:
39 return None
40
41 ids_a = {n.variation_id for n in lineage_a}
42
43 for node in reversed(lineage_b):
44 if node.variation_id in ids_a:
45 logger.info(
46 "✅ Merge base found: %s (between %s and %s)",
47 node.variation_id[:8], a[:8], b[:8],
48 )
49 return node.variation_id
50
51 return None