scripts.migration.build_mapping

Reference › scripts › migration › build_mapping

scripts/migration/build_mapping.py parses section 2 ("Full module mapping") of MODULE-MIGRATION-MAP.md into a machine-readable table, mapping.json, of the form {"moves": [{old, new, line}], "count": N}. It belongs to the package restructuring described in architecture migration 2026-09. A human ran it as part of that migration; it has no functions to import and does its work when run. The two arguments are the map path and the output path, both with defaults.

Each list line of the form "old path in backticks, an arrow, target package in backticks" becomes one move. dotted turns a file path into a dotted module name; a package __init__ maps onto the target package itself, and other modules map to the target package plus their base name. Old names get an orchestrata_ultimate. prefix unless they already start with orchestrata_ultimate, orchestrata_ast or orchestrata_tools. Section 3 special moves, section 4 known-dead modules and the AST packages of section 6 are excluded. An assertion stops the run on a duplicate source module. It prints the number of moves parsed and the most common target packages.

At a glance

Source scripts/migration/build_mapping.py
Lines of code 73
Classes 0
Functions 1
Imports (internal) none
Imported by none
Tests that import it none

Class diagram

No classes; see Functions.

Dependency diagram

No internal imports and no importers.

API

Functions

Function Signature Summary
dotted dotted(path: str) -> str

Source

Permalink: https://gitlab.com/MSamy/orchestrata-ultimate-architecture/-/blob/a4cbc2bdf/scripts/migration/build_mapping.py

#!/usr/bin/env python3
"""Parse MODULE-MIGRATION-MAP.md §2 into a machine-readable mapping table.

Output: mapping.json — {"moves": [{old, new, source_line}], "count": N}
§3 special moves and §4 known-dead modules are EXCLUDED (handled separately).
AST packages (§6) are excluded (own section).
"""

from __future__ import annotations

import json
import re
import sys
from collections import Counter
from pathlib import Path

MAP = Path(
    sys.argv[1]
    if len(sys.argv) > 1
    else "/home/mohamed/workspace/orchestrata-review-2026-09-17/design/MODULE-MIGRATION-MAP.md"
)
OUT = Path(sys.argv[2] if len(sys.argv) > 2 else "mapping.json")

LINE = re.compile(r"^- `([^`]+\.py)` → `([^`]+)`")


def dotted(path: str) -> str:
    return path.removesuffix(".py").replace("/", ".")


text = MAP.read_text()
# §2 only — §3 special-move lines share the `- \`x\` → \`y\`` shape (with a
# prose suffix on the target), and §5/§6 tables use backticks too.
section = text.split("## 2. Full module mapping", 1)[1].split("## 3.", 1)[0]

moves = []
for lineno, raw in enumerate(section.splitlines(), 1):
    m = LINE.match(raw.strip())
    if not m:
        continue
    src, target_pkg = m.groups()
    if " — " in target_pkg:  # special-move prose target, not a dotted package
        continue
    old = dotted(src)
    base = old.rsplit(".", 1)[-1]
    if base == "__init__":
        # package __init__ maps onto the target package itself
        new = target_pkg
    else:
        new = f"{target_pkg}.{base}"
    old_full = (
        old
        if old.startswith(
            ("orchestrata_ultimate", "orchestrata_ast", "orchestrata_tools")
        )
        else f"orchestrata_ultimate.{old}"
    )
    moves.append({"old": old_full, "new": new, "line": lineno})

# dedupe guard
seen = {}
for mv in moves:
    assert (
        mv["old"] not in seen
    ), f"duplicate source: {mv['old']} (lines {seen.get(mv['old'])}, {mv['line']})"
    seen[mv["old"]] = mv["line"]

OUT.write_text(json.dumps({"moves": moves, "count": len(moves)}, indent=1) + "\n")
print(f"parsed {len(moves)} moves -> {OUT}")
pkgs = Counter(
    mv["new"].split(".")[1] for mv in moves if mv["new"].startswith("orchestrata.")
)
print("top targets:", pkgs.most_common(8))