Skip to content

type_bridge.migration.sidecar

sidecar

Checked JSON sidecar generation for Python-only migration histories.

The native (Rust) migration path executes only NNNN_name.json sidecars; a .py-only migration that 1.5.x ran through dynamic import has no executable representation there. This module converts such histories by loading each migration through the released :class:MigrationLoader (dynamic import fallback intact) and lowering it with the released :func:~type_bridge.migration._lower.lower_migration — the exact lowering the Python executor uses — so the generated sidecar and the historical execution semantics agree by construction.

Conversion preflights every collision before publication and uses a retained journal for resumability. A late interruption can leave only immutable, plan-identical partial artifacts plus that journal; rerunning the same command resumes them, while native adoption fails closed until completion. Every recognized migration-shaped source receives separate archival adoption metadata read through the frozen trusted Python loader. Sources that V1 ignored because they expose no public Migration subclass receive checksum-bound ignored-source evidence and stay out of the graph. Migrations whose operations are serializable also receive an executable sidecar; nonportable operations such as ops.RunPython deliberately receive only the archive because adoption verifies already-applied history and never replays them. Released empty migrations are archived as checksum-bound no-ops that inherit one exact snapshot authority from all of their parents.

Usage::

python -m type_bridge.migration.sidecar path/to/migrations

SidecarConversionError

SidecarConversionError(blockers)

Bases: Exception

A migration history cannot produce trustworthy archival artifacts.

blockers maps each migration or artifact identity to the failed trust/integrity condition. Preflight failures write nothing. A failure after the conversion journal is published can leave resumable immutable artifacts, and native adoption rejects the history until a retry clears the journal.

Source code in type_bridge/migration/sidecar.py
def __init__(self, blockers: dict[str, str]) -> None:
    self.blockers = dict(blockers)
    details = "; ".join(f"{name}: {reason}" for name, reason in sorted(self.blockers.items()))
    super().__init__(
        f"checked adoption metadata conversion did not complete. Blockers: {details}."
    )

generate_sidecars

generate_sidecars(migrations_dir)

Generate checked JSON sidecars for every py-only migration in a directory.

Discovers the history through the released loader's frozen Python import path, lowers each executable migration with the released execution lowering, and binds every migration-shaped source to its .py checksum.

Returns:

Type Description
list[Path]

Paths of the adoption records and executable sidecars written, in

list[Path]

source order. Empty when every required artifact already exists.

Raises:

Type Description
SidecarConversionError

When the graph is invalid, a schema-affecting migration lacks its exact immutable snapshot, or a schema-neutral RunPython/no-op migration cannot inherit one converged parent authority. Nothing is written in that case.

MigrationLoadError

When discovery itself fails (unreadable file, stale existing sidecar, broken migration module).

Source code in type_bridge/migration/sidecar.py
def generate_sidecars(migrations_dir: Path) -> list[Path]:
    """Generate checked JSON sidecars for every py-only migration in a directory.

    Discovers the history through the released loader's frozen Python import
    path, lowers each executable migration with the released execution
    lowering, and binds every migration-shaped source to its ``.py`` checksum.

    Returns:
        Paths of the adoption records and executable sidecars written, in
        source order. Empty when every required artifact already exists.

    Raises:
        SidecarConversionError: When the graph is invalid, a schema-affecting
            migration lacks its exact immutable snapshot, or a schema-neutral
            RunPython/no-op migration cannot inherit one converged parent
            authority. Nothing is written in that case.
        MigrationLoadError: When discovery itself fails (unreadable file,
            stale existing sidecar, broken migration module).
    """
    try:
        authority = AdoptionDirectoryAuthority.open(migrations_dir)
    except OSError as error:
        raise SidecarConversionError(
            {migrations_dir.name: "migration directory authority cannot be retained"}
        ) from error
    with authority:
        try:
            return _generate_sidecars_in(migrations_dir, authority)
        except AdoptionDirectoryError as error:
            if error.errno == errno.EILSEQ:
                raise SidecarConversionError(
                    {
                        migrations_dir.name: (
                            "a migration-shaped filename is not valid UTF-8; "
                            "the native JSON identity cannot represent this released-Unix "
                            "filename safely"
                        )
                    }
                ) from error
            raise SidecarConversionError(
                {migrations_dir.name: "migration authority changed during conversion"}
            ) from error