Skip to content

studio: config-drift dashboard (live vs declared, one-click re-apply) - #175

Merged
robercano-ghbot merged 5 commits into
mainfrom
feat/issue-153-config-drift-reapply
Aug 8, 2026
Merged

studio: config-drift dashboard (live vs declared, one-click re-apply)#175
robercano-ghbot merged 5 commits into
mainfrom
feat/issue-153-config-drift-reapply

Conversation

@robercano-ghbot

Copy link
Copy Markdown
Collaborator

Closes #153.

Summary

  • deploy-server: POST /api/verify/config runs verifyConfig's config-drift check against the live chain via ChainReader, network-aware (?network=, mirroring /api/apply-config).
  • studio: drift badges (match/drift/error) on each config step in the Inspector, a drift detail panel (expected vs actual + message), and a one-click "Re-apply" action wired to the apply-config endpoint for a single drifted/errored step.
  • Security-hardening follow-ups applied during review: the re-apply POST narrows the sent spec to just the target step (so re-applying one step can never broadcast transactions for other not-yet-applied steps), and the drift check reads from the same network the forced re-apply writes to (previously the drift check always read the server's default network, which could let a "Re-apply" click act on a mismatch computed against the wrong chain).

Review

Routed through all four required lenses (correctness, tests, security, performance) with consensus "all" — security's initial reject (drift check not network-aware) was fixed and re-reviewed to approve.

Test plan

  • pnpm -r build
  • pnpm -r lint
  • pnpm -r typecheck
  • pnpm -r test (packages/config 159, apps/studio 1229, apps/deploy-server 304, plus forge test)
  • pnpm -r coverage — packages/config 95.58%, apps/studio 97.14%, apps/deploy-server 97.59% (threshold 80%)

🤖 Generated with the reDeploy autonomous PR loop.

robercano and others added 5 commits August 6, 2026 20:55
…ail panel + one-click re-apply (issue #153)

Adds forceStepIds to @redeploy/config's applyConfig() to allow re-executing
already-journaled steps on demand, threads it through deploy-server's
POST /api/apply-config as a validated ?forceStepIds= query param (never in
the body, which is already the spec), and wires a studio drift detail panel
(expected vs actual) with a confirm-gated per-step "Re-apply" button that
refreshes drift badges via runVerifyConfig on success.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…rift re-apply (issue #153)

Fixes B1-B5 from the review of feat/issue-159... err feat/issue-153-config-drift-reapply:

- B1 (correctness+security, most serious): the re-apply confirm modal claimed
  "1 step, all others unaffected" while POSTing the studio's ENTIRE config
  spec — applyConfig() executes every not-yet-applied step in the POSTed
  spec regardless of forceStepIds. Now narrows the POSTed spec to just the
  target step (narrowConfigToStep), making the modal's claim structurally
  true, and rewords the "already applied" claim which was false for
  never-journaled drifted steps.
- B2: pin that a forced step whose executor throws does not double-journal.
- B3: cover the `if (applying) return;` guard in onReapplyStep — the only
  thing preventing a second real broadcast from a second click in flight.
- B4: cover the untested `driftOutcome.ok` false branch on the post-re-apply
  drift refresh, and document the deliberate on-failure behaviour (leave
  driftResults stale rather than clearing, unlike handleVerify).
- B5: fix the forceStepIds comma round-trip — client now sends one repeated
  query param per id (rejecting any id containing a comma before sending)
  instead of comma-joining; server merges repeated params via
  URLSearchParams.getAll() instead of dropping all but the first.

Also folds in the non-blocking cleanup items from the same review pass
(fresh completedAt assertion, full-apply verify-call-count test, Inspector
keyboard/stringify branch coverage, constant drift-badge style objects, and
a corrected doc comment on the forceStepIds cap-before-dedupe ordering).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ply (issue #153)

- App.reapplyNarrowing.test.tsx: T1 (blocking) — the B1 regression test was
  vacuous because the canvas config was empty, making the narrowed-vs-full
  spec comparison trivially true. Add a real canvas step before triggering
  re-apply and assert directly on the POSTed request body (no step id other
  than the re-apply target may appear), independent of the narrowConfigToStep
  spy. Mutation-verified: fails when the narrowed spec is computed then
  discarded, passes against the real implementation.
- execute.test.ts: strengthen the fresh-completedAt assertion with a
  controlled clock so a stale-copy regression (not just a genuinely newer
  timestamp) is caught, instead of toBeGreaterThanOrEqual which a byte-copy
  would also satisfy.
- narrow-config.test.ts: add a case for the same step id appearing in both
  `steps` and `orderedSteps`, pinning that narrowConfigToStep keeps both
  entries (de-duplication/rejection happens downstream via validateConfig's
  DUPLICATE_STEP_ID check).
- Inspector.tsx: guard DRIFT_BADGE_STYLES lookup with Object.hasOwn so a
  server-supplied drift.status of "constructor"/"toString" can't return an
  inherited Object.prototype function instead of falling through to the
  default badge style (security lens nit, assessed harmless but cheap to fix).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
#153)

Security review (finding H1) caught that POST /api/verify/config always
read the server's default-network deployment while the forced re-apply it
gates writes to the user-selected network — a wrong-network drift reading
could let a one-click "Re-apply" broadcast a real transaction for a
mismatch that doesn't exist (or hide one that does) on the network
actually being written to. Thread the same ?network= convention already
used by /api/apply-config through /api/verify/config and runVerifyConfig,
and fix a route-matching bug (matching the query-string-bearing url
instead of pathname) that this change exposed.
…sue #153)

Assert the rpcUrl half of network isolation in the new verify/config
multi-network test (previously only deploymentDir was checked, so a
revert of the rpcUrl line would have gone undetected), and update the
handleRequest route doc comment to list /api/verify/config among the
pathname-matched, ?network=-aware routes.
@robercano-ghbot robercano-ghbot added the needs-human Loop escalated: manual triage required label Aug 6, 2026
@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

studio: config-drift dashboard (live vs declared, one-click re-apply) (not yet reviewed)

@robercano-ghbot robercano-ghbot removed the needs-human Loop escalated: manual triage required label Aug 8, 2026
@robercano-ghbot
robercano-ghbot merged commit 195a3bb into main Aug 8, 2026
6 checks passed
@robercano-ghbot
robercano-ghbot deleted the feat/issue-153-config-drift-reapply branch August 8, 2026 11:46
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.

[wave 2] studio: config-drift dashboard (live vs declared, one-click re-apply)

2 participants