Skip to content

fix(cli): reconcile stale selector System IDs without World upgrades - #2

Closed
JackieXu wants to merge 4 commits into
mainfrom
codex/native-system-migrations
Closed

fix(cli): reconcile stale selector System IDs without World upgrades#2
JackieXu wants to merge 4 commits into
mainfrom
codex/native-system-migrations

Conversation

@JackieXu

@JackieXu JackieXu commented Aug 17, 2026

Copy link
Copy Markdown

Summary

Fix mud deploy so an existing World selector that points at a stale System ID is reconciled through the World’s existing Store API. This does not upgrade the World, replace its RegistrationSystem, or change protocol 2.0.2.

The fork release remains CLI-only: @latticexyz/cli@2.2.24-floki.1 depends on the official MUD 2.2.23 packages, including @latticexyz/world@2.2.23.

Root cause

ensureFunctions previously treated any existing World selector as registered. It warned when the configured System ID differed, but skipped the selector anyway. Because System IDs contain the configured System name, renaming a System could permanently leave old selectors routed to the obsolete implementation.

Reconciliation behavior

ensureFunctions now reads the complete FunctionSelectors tuple directly from the World at an authoritative latest block and classifies each configured route:

  • missing tuple: use the existing function-registration path;
  • exact (System ID, System function selector) tuple: skip;
  • wrong System ID with the exact configured System function selector: update only field 0 (systemId) through World.setField;
  • partial/malformed tuple or a different System function selector: abort without overwriting it.

Before a repair, the CLI requires the destination Systems row to be active and verifies that the deployer has Store access to either the world namespace or the FunctionSelectors table. It re-reads the exact source route immediately before every write, waits for receipts, and verifies all configured route tuples afterward. Authoritative block snapshots explicitly bypass viem's short-lived block-number cache so an immediate post-receipt check cannot inspect the pre-write block.

The protocol-2.0.2 Store API has no compare-and-swap write, so the latest read and setField transaction cannot be atomic. Deployments that can mutate routes or Systems must remain serialized. Config is authoritative for same-selector System-ID reconciliation.

Existing-World permission prerequisite

The current application namespace owners on Valhalla’s dev, testnet, staging, and production Worlds do not have direct access to the world/FunctionSelectors table. The existing world namespace owner must therefore grant the normal deployment identity access to that table once before the first repairing deployment. If it has not, the CLI fails with the exact deployer, table ID, and grant instruction before submitting a repair transaction.

This PR does not retire legacy Systems. Calls routed through the affected World selectors are fixed, but an obsolete public System can remain reachable through World.call(oldSystemId, ...) until handled as a separate, explicitly reviewed operation.

Fork compatibility and release packaging

Fork builds normalize forge-generated source links back to the existing canonical Lattice documentation URLs, avoiding generated-doc churn caused solely by the GitHub repository owner.

The tag-triggered fork release workflow:

  • builds, tests, and packages only @latticexyz/cli;
  • pins all 13 @latticexyz/* dependencies to official 2.2.23;
  • installs the final tarball into a fresh consumer and smoke-tests mud --help;
  • validates runtime version and fork repository metadata;
  • emits a deterministic tarball plus SHA256SUMS;
  • separates the read-only build job from the write-enabled GitHub Release job.

The workflow creates no tag. No package or GitHub Release is published by this PR.

Validation

  • CLI: TypeScript, ESLint, 16 Vitest tests, and 6 Forge tests pass.
  • World regression: a real protocol-2.0.2 World test proves field-0 repair preserves the System function selector, changes dispatch to the target, and rejects an unauthorized caller.
  • Full CLI dependency build: 16/16 packages pass with a forced, uncached build.
  • Release packager: 4/4 tests pass; two final rebuilt tarballs are byte-identical.
  • Live read-only simulation: the exact setField repair succeeds from the dev World namespace owner and reverts from the current application owner, matching the permission preflight.

Final rebuilt CLI artifact SHA-256: f71d456bca199e0be799340ecca348bd905ace87fb1817dd196df119131e5d4e.

@JackieXu JackieXu changed the title feat(world,cli): add native fail-closed selector and System migrations fix(cli): reconcile stale selector System IDs without World upgrades Aug 17, 2026
@JackieXu JackieXu closed this Aug 17, 2026
@JackieXu

Copy link
Copy Markdown
Author

Superseded by the versioned application migration in Liquid-Ice-Studios/valhalla-services#356.

Live access verification showed that the world namespace owners are non-forwarding WorldFactory contracts, so neither the root/application owner nor the normal deployer can grant or exercise the Store access this CLI repair requires. The replacement uses the existing installRootModule kernel path from the signable root owner, repairs all audited routes atomically, and requires no World or RegistrationSystem upgrade. No fork package release is needed for this incident.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant