Skip to content

Let a migration opt in to a prerequisite in another writer's namespace #159

Description

@thedavidmeister

IMigrationRegistryV1 orders migrations within one writer's namespace: applyMigration(expectedHead, migration) refuses unless the namespace is at expectedHead, so a skipped predecessor is a revert. There is no way to say that a migration may only be applied once a migration in another writer's namespace has been applied.

That is the shape of every ordering problem in S01-Issuer/st0x.deploy's current rollout, and each one is enforced today by a script re-deriving the other script's post-state, or by a runbook:

  • the orchestrator cutover bundle (Safe writer) must not apply until the fleet upgrade of the receipt and receipt-vault beacons (Safe writer, different script, different day) has applied; the script reads the beacons' implementation() and reverts FleetNotUpgraded;
  • the direct-role retirement must not apply until the cutover has applied and burned in; the script reads four hasRoles;
  • the governance-timelock migration (Safe writer) must not apply until the orchestrator beacon's owner migration (deploy-EOA writer) has applied; nothing enforces it, so the timelock bundle either skips or refuses on the beacon.

Reading the other migration's state is the "bookkeeping vs pins" layering the interface already describes; what is missing is the index half for the cross-writer case, so the applying script can name its prerequisite as a fact the registry checks instead of re-implementing the other script's post-state read.

Ask

An opt-in prerequisite on apply. Something like:

struct Prerequisite { address writer; bytes32 migration; }

/// Reverts `PrerequisiteNotApplied(writer, migration)` for the first entry
/// whose `applied(writer, migration)` is zero. Otherwise identical to
/// `applyMigration`.
function applyMigrationAfter(bytes32 expectedHead, bytes32 migration, Prerequisite[] calldata prerequisites) external;

and the same for applyMigrationHistory. The check is a precondition on the write, not a record: nothing new is stored, in keeping with "MUST NOT record anything about the state a migration produced". Emitting the prerequisites in Migrated (or a sibling event) would let an indexer reconstruct the cross-namespace order without a storage footprint.

A prerequisite is still an index, not proof: it says the other writer recorded its migration, not that the state it produced holds. Consumers keep their pins. What it removes is each dependent script carrying a hand-written copy of its prerequisite's post-state.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions