メインコンテンツまでスキップ

Migration window

The economy version of an entangled state is sealed. Once your state machine's domain_economy_config row is created, the keep ratio, spend split, and mint rate are frozen for the lifetime of that entangled state. To upgrade those parameters — or to move from the legacy v1_handpicked formulas to the math-derived v2_math formulas — you open a migration window.

Updated 2026-05-18 to match the AS.F.MATH.M8 release.


1. Why a window exists

Economy parameters change wallet outcomes. If we let an operator flip keep-ratio mid-day, holders would see retroactive differences in the amount of ZEQ minted, retained, or charged for the same action. The window is the formal answer to that:

  1. The window names exactly which target the entangled state is migrating to.
  2. Both versions are visible side-by-side (see econ_v1_preview and econ_v2_preview on the per-Zeqond network_snapshots row).
  3. The cutover is a single recorded event, written to the audit entangled state with the operator's ZID, the source/target versions, and the Zeqond at which the swap took effect.
  4. Once cut over, the change is irreversible in code. Reverting would require opening a new window and a second audit trail.

2. The three states

A migration window is a small state machine of its own:

inactive ──open──▶ open ──cutover──▶ closed
└──cancel───▶ closed
StateMeaning
inactiveNo window is open. The entangled state runs on whatever version is in domain_economy_config.econ_version. This is the resting state.
openThe entangled state owner has opened a window. Both versions are computed every Zeqond and surfaced in the transparency oracle. Wallets still settle on the CURRENT version. The owner can either cut over or cancel.
closedThe window has terminated. Either via cutover (the new version is now authoritative — wallets settle on it from the next Zeqond) or via cancel (no change, returns to inactive).

An entangled state can only have one window open at a time. Opening a second window on an already-open entangled state is a no-op; the existing window is reused.


3. Lifecycle (federated path)

A federated entangled state migrating v1_handpickedv2_math:

Open. Owner calls POST /api/chain/<machine>/economy/migration/open with target_version: "v2_math". Server writes migration_window_state = 'open', records the requesting ZID, captures the source version, and emits a migration.opened audit row. The transparency oracle starts populating econ_v2_preview alongside econ_v1_preview.

Observe. Both projections are written every Zeqond. The owner can compare:

  • daily mint rates (foundation flat-mint vs. math-derived per-machine drip)
  • per-tier daily Promo Credits
  • spend split outcomes at N=1, 100, 1k, 10k
  • the foundation's incoming flow

Cutover. When the owner is satisfied, POST /api/chain/<machine>/economy/migration/cutover flips domain_economy_config.econ_version to v2_math, writes migration_window_state = 'closed', and emits a migration.cutover audit row stamped with the cutover Zeqond. From the next Zeqond onward, tallyAutoMint, chargeForCompute, and the keep-ratio ticker all read v2_math formulas.

Cancel. At any time before cutover, the owner can POST .../migration/cancel. The window closes, the entangled state returns to its source version, and the v2 preview stops being written.


4. Auto-cutover (zeq.dev path)

For the framework's own foundation chain (zeq.dev), the cutover was scheduled rather than manual. The migration window opened on 2026-05-18, ran for a configurable observation period (auto_cutover_at_zeqond on the window row), and the daemon flipped to v2 at the scheduled tick. The flip writes the same migration.cutover audit row, but with triggered_by = 'scheduler' instead of a user ZID.

Operators of federated/sovereign chains can use the auto-cutover field too, by setting auto_cutover_at_zeqond at open time. Leaving it null means manual cutover only.


5. What can't change after cutover

The cutover writes the new version into domain_economy_config but does not edit other rows in that table. The split percentages, keep ratios, and mint rate are still sealed by their own locked-once trigger (see ZEQ economy §5). A v1→v2 migration changes the formula family; it does not let you re-tune the parameters of the new family.

If you need to re-tune parameters under v2, the path is:

  1. Open a new migration window with target_version: "v2_math" (same version, different proposed parameters).
  2. The server requires target_params to be supplied; the preview is computed using those new parameters.
  3. Cutover applies the new parameter set in a single atomic write.

6. Forensic guarantees

Every transition writes a row to the audit entangled state:

EventCaptured fields
migration.openedsource_version, target_version, requested_by_zid, auto_cutover_at_zeqond
migration.cutoversource_version, target_version, triggered_by, cutover_at_zeqond, network_snapshot_at_cutover
migration.cancelledsource_version, cancelled_by_zid, reason

The cutover row also pins a hash of the network_snapshots row at that Zeqond, so the entire wallet state of the entangled state at the moment of the swap is content-addressable and verifiable later.


7. Public surfaces

While a window is open, three places surface it:

  • /transparency/ — shows migration_window_state: open in the banner, with both v1 and v2 preview cards rendered side-by-side.
  • /state/admin/ (chain-owner) — the Economy tab shows the open window and exposes the Cutover / Cancel buttons.
  • /api/chain/<machine>/state — the public read-only state response carries migration_window as a structured field.

After cutover, only the audit row remains accessible (via the entangled state explorer); the window row itself is closed and read-only.


Bottom line. A migration window is the only way to change a chain's economy version, and the only way to upgrade legacy v1 chains to math-derived v2. It is auditable end-to-end, reversible only before cutover, and emits a single canonical row at the moment of the swap. The framework's own entangled state on zeq.dev migrated this way on 2026-05-18.