en un clic
dual-replay
// Run Sui dual execution replay between base and tip commits, recover failed steps, build, and commit replay instrumentation.
// Run Sui dual execution replay between base and tip commits, recover failed steps, build, and commit replay instrumentation.
Cherry-pick a commit from main to a Sui release branch, create the release PR, and report the PR URL.
Safely modify or verify Sui protocol config changes, including version bumps, release-branch checks, guards, and snapshots.
Debug deterministic Sui simtest failures with structured experiments, logging-only changes, and NOTEBOOK.md observations.
Prepare, validate, and send or update a pull request with full due diligence
| name | dual-replay |
| description | Run Sui dual execution replay between base and tip commits, recover failed steps, build, and commit replay instrumentation. |
Instruments the latest execution path to run every transaction twice — once with a base executor (built from an execution-layer cut taken at <base-sha>) and once with the tip executor at <tip-sha> — and diffs the two outputs. The base result is committed; the tip result is for comparison only.
Most of the work is handled by scripts/dual_replay/. This skill is the contract for invoking that script and the playbook for when its happy path fails.
/dual-replay <base-sha> <tip-sha> [diff-mode] [cut-name]
diff-mode (optional, default strict): one of strict, status-only, gas-only, status-and-gas.cut-name (optional, default replay_cut).Additional knobs (pass through if the user supplied them):
--gas-tolerance <percent>: tolerated gas delta as a percentage (default 0, i.e. exact equality). Only meaningful for diff modes that compare gas.--output-dir <path>: where effects-diff artifacts go (default target/dual-replay/).--timings-file <path>: where per-tx execution timings are appended as CSV (default <output-dir>/timings.csv).Every transaction's base and tip execution is timed and appended as one CSV row to --timings-file (default <output-dir>/timings.csv). Columns: digest,base_ns,tip_ns,base_gas,tip_gas,status_match. Writes are buffered and flushed every 500 rows. The file is opened in append mode, so resumed runs accumulate into the same file — delete it between runs if a clean dataset is needed.
If either SHA is missing or does not resolve to a commit, ask the user for clarification. Do not prompt for other arguments — fall back to defaults.
Run the script's run subcommand. It does everything end-to-end and creates a commit on the current branch:
python3 scripts/dual_replay.py run \
--base <base-sha> --tip <tip-sha> \
--cut-name <cut-name> \
--diff-mode <diff-mode> \
[--gas-tolerance <percent>] \
[--output-dir <path>]
On success, report the commit SHA produced (git rev-parse HEAD) and stop. Do not open a PR.
The script never prompts. If you need to override the dirty-tree refusal because the user explicitly said so, pass --force-dirty.
If run exits non-zero, the script prints which subcommand failed. Drive the remaining steps individually — they read persisted state from .dual-replay.json so you don't need to re-pass flags:
python3 scripts/dual_replay.py cut --base <sha> --tip <sha> --cut-name <name>
python3 scripts/dual_replay.py inject
python3 scripts/dual_replay.py build
python3 scripts/dual_replay.py commit
cut failedUsually environmental: dirty tree, unresolvable SHA, or scripts/execution_layer.py cut itself errored. Read the script's stderr, surface it to the user, and stop. Do not attempt code edits — the working tree may be on an unexpected commit.
inject failed (anchor not found)The script reports the file and the regex it tried. The tip has likely renamed or moved a symbol since the templates were written. Do not refresh the templates speculatively. Instead:
TPL_* template constants in scripts/dual_replay.py. Substitute ${cut_pkg} → the underscored cut name (e.g. replay_cut → sui_adapter_replay_cut).python3 scripts/dual_replay.py build, then commit.scripts/dual_replay.py should be updated — but only after confirming the new symbol name is stable.build failedcargo check -p sui-execution -p sui-types failed. The script already handles the common scaffolding (Clone derives on the gas types it knows about, the serde_json dep on sui-execution). What's left is genuinely case-by-case. Read the captured stderr and apply the smallest fix that compiles:
Clone derives. The script derives Clone on SuiGasStatus (gas.rs), gas_v2::SuiGasStatus, gas_v2::SuiCostTable, gas_v2::ComputationBucket, and tables::GasStatus. If a new field type in any of these (or a transitively-reached type) is not Clone, add #[derive(Clone)] to it — and if this becomes a recurring fix, add the type to GAS_CLONE_TARGETS in scripts/dual_replay.py so the script handles it directly.set_gas_model_version on SuiGasStatus and the method doesn't exist, add a narrow one. Keep it minimal.external-crates/move/Cargo.toml so the generated cut crates are either members or explicitly excluded — keep the metadata consistent. Don't skip formatting.After each fix, re-run python3 scripts/dual_replay.py build. When it passes, run commit.
commit failedAlmost always pre-commit hook failure. Read the hook output, fix the cited issue (often cargo fmt or cargo xclippy complaints), and re-run commit. Never use --no-verify.
git checkout -m for exactly this reason.instrument dual execution replay from <base-short-sha> to <tip-short-sha>. The script produces this automatically.