feat(deploy-server): simulate-first interlock + preflight SSE surfacing — part 2 of #156 - #171
Open
robercano-ghbot wants to merge 2 commits into
Open
feat(deploy-server): simulate-first interlock + preflight SSE surfacing — part 2 of #156#171robercano-ghbot wants to merge 2 commits into
robercano-ghbot wants to merge 2 commits into
Conversation
Adds an opt-in pre-broadcast safety phase: expectedChainId, minBalanceWei,
and maxGasPriceWei checks run against the live RPC/account BEFORE any
transaction is sent, aborting with a typed DeployError("PREFLIGHT_FAILED")
on failure. Effective policy is a per-field merge of DeploymentSpec.preflight
and DeployOptions.preflight; the phase is fully skipped (zero extra RPC
calls) when no policy is configured, keeping the happy path unaffected.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ng (#156) Add requireSimulate and preflight to NetworkConfig so a network can refuse POST /api/deploy until an identical spec (by stable hash) has been successfully simulated, and so DeployError("PREFLIGHT_FAILED", ...) from @redeploy/core's new preflight phase surfaces as a structured SSE error the studio can render. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
robercano
approved these changes
Jul 29, 2026
robercano
approved these changes
Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Part 2 of 2 for #156 — the
@redeploy/deploy-serverhalf. Stacked on #170 (the@redeploy/corepreflight PR); merge #170 first. Until #170 merges, this PR's diff includes the core commit; GitHub will recompute it to the deploy-server-only delta once #170 lands.Delivers the two deploy-server behaviors from the ticket:
1. Simulate-first interlock
requireSimulate?: booleanon a network's config (networks.ts). Default off — omitting it preserves current behavior exactly.POST /api/simulatesuccess records a stable spec hash for that network (under the server-controlled per-networkdeploymentDir, bounded to the 50 most-recent).POST /api/deployon arequireSimulate:truenetwork REFUSES pre-broadcast unless a matching simulate was recorded for the SAME spec on the SAME network, emitting a structured SSE errordone{success:false, errors:[{code:"SIMULATE_REQUIRED", …}]}— no provider built, no tx sent. Fail-closed: missing/corrupt/unreadable state ⇒ refuse.spec-hash.ts): SHA-256 over a canonical, recursively key-sorted serialization, so cosmetic key-reordering between simulate and deploy still satisfies the interlock; any semantic change does not.2. Preflight failures surfaced as structured SSE
preflightpolicy, forwarded intocore.deploy()'spreflightoption (the per-network-overridable path; the server policy wins the per-field merge, so a clientspec.preflightcan only tighten it).DeployErrorcodePREFLIGHT_FAILEDfrom core is mapped to structured SSE errors carrying{ code, message, check, expected, actual }per failure, so the studio can render exactly which check failed. Non-secret fields only (chain ids, wei amounts, deployer address). OtherDeployErrorcodes keep their existing behavior.New files
src/spec-hash.ts,src/simulate-state.ts(+ their unit tests).Security posture (unchanged boundary)
deploymentDir/rpcUrl/keys come only from trusted server config; the client supplies just a?network=allowlist name + the spec body. No client input reaches any filesystem path; the simulated record is keyed to the server-onlydeploymentDirand can only be created by a genuine successful simulate. No secrets in SSE frames or logs.Gates (apps/deploy-server)
build / lint / typecheck / test / coverage — all green. 289 tests. deploy-server coverage 90.37% (threshold 80);
spec-hash.ts+simulate-state.ts100%.Review
All four reviewer lenses approved (high confidence). The tests lens verified non-vacuity by mutation (disabling the interlock and removing canonical key-sorting both break the suite). Non-blocking follow-ups noted: switch
canonicalizeto a null-prototype accumulator (__proto__key hygiene), and drop a redundantmkdirSync.Closes #156.
🤖 Generated with Claude Code