Skip to content

feat: snapshot-on-push + npm run rollback#21

Open
dhruva-reddy wants to merge 1 commit intodhruva-reddy/feat/push-drift-detectionfrom
dhruva-reddy/feat/snapshot-rollback
Open

feat: snapshot-on-push + npm run rollback#21
dhruva-reddy wants to merge 1 commit intodhruva-reddy/feat/push-drift-detectionfrom
dhruva-reddy/feat/snapshot-rollback

Conversation

@dhruva-reddy
Copy link
Copy Markdown
Contributor

ELI5

Problem. The README documented "rollback" as git revert + push.
That restores local content to a previous git state, but it does
not restore a known platform snapshot — the subsequent push has
all the same drift problems, so a "rollback" can clobber unrelated
dashboard edits made since the bad deploy. There's also no engine-
level record of what was on the dashboard before the push, so even
in principle you can't put the platform back exactly the way it was.

What this fix does. Before each PATCH, the engine writes both:

  • the outgoing payload (what we're about to send), AND
  • the current platform payload (what's there right now)

to a per-push directory:

.vapi-state.<env>.snapshots/<ISO-timestamp>/<resource-type>/<id>.json

Snapshots are operator-local (gitignored) and recreated each push.
A single timestamped directory pins one push run, so rollback can
target an entire push, not individual PATCHes.

npm run rollback -- <env> --to <ISO-timestamp> re-applies each
platform payload from the snapshot as a PATCH. --list prints all
available timestamps.

Outcome you'll notice. Real undo. After a bad push, run
npm run rollback -- <env> --list to see your snapshots, pick the
one from before the bad push, and --to <timestamp> puts the
dashboard back to that state. No more "I hope git revert does
what I want."


Real undo. Before each PATCH, write the outgoing (local) payload AND
the current platform payload to a per-push directory. npm run rollback -- <env> --to <ISO-timestamp> re-applies each platform payload as a
PATCH, restoring the dashboard to its state at the moment of the
snapshot.

Snapshots are operator-local state (.vapi-state..snapshots/),
gitignored, and recreated on every push. Each push pins one timestamped
directory so rollback can target an entire push, not individual PATCHes.

Files:

  • src/snapshot.ts (NEW): writeSnapshot, listSnapshotTimestamps,
    loadSnapshot. Pins a single timestamp per push run (getRunSnapshotDir
    is idempotent within the process). Reuses sortedKeysReplacer so
    snapshot files have deterministic key order too.
  • src/rollback-cmd.ts (NEW): npm run rollback -- --to
    re-applies each platform payload as a PATCH. --list prints available
    snapshots.
  • src/push.ts: writeSnapshot call after drift check passes. Costs one
    extra GET per resource (acceptable for the safety guarantee — follow-
    up: plumb drift's GET result through to avoid the duplicate fetch).
    Snapshot failures don't block the push.
  • package.json: rollback script.
  • .gitignore: .vapi-state.*.snapshots/ already covered.
  • AGENTS.md: document npm run rollback / --list.
  • tests/snapshot.test.ts: writeSnapshot creates the right path,
    multi-resource snapshots share a timestamp, listSnapshotTimestamps
    sorted, loadSnapshot round-trips.

Closes improvements.md #3.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Contributor Author

dhruva-reddy commented May 1, 2026

@dhruva-reddy dhruva-reddy force-pushed the dhruva-reddy/feat/snapshot-rollback branch from fdf7bfb to c916a21 Compare May 1, 2026 22:56
@dhruva-reddy dhruva-reddy force-pushed the dhruva-reddy/feat/push-drift-detection branch 2 times, most recently from 05675a0 to c1d9632 Compare May 2, 2026 01:23
@dhruva-reddy dhruva-reddy force-pushed the dhruva-reddy/feat/snapshot-rollback branch from c916a21 to 34ae2cb Compare May 2, 2026 01:24
@dhruva-reddy dhruva-reddy force-pushed the dhruva-reddy/feat/push-drift-detection branch from c1d9632 to 09af67e Compare May 2, 2026 01:28
@dhruva-reddy dhruva-reddy force-pushed the dhruva-reddy/feat/snapshot-rollback branch from 34ae2cb to 9667011 Compare May 2, 2026 01:29
@dhruva-reddy dhruva-reddy force-pushed the dhruva-reddy/feat/push-drift-detection branch from 09af67e to 4b8d8b8 Compare May 2, 2026 01:33
## ELI5

**Problem.** The README documented "rollback" as `git revert + push`.
That restores local *content* to a previous git state, but it does
**not** restore a known *platform* snapshot — the subsequent push has
all the same drift problems, so a "rollback" can clobber unrelated
dashboard edits made since the bad deploy. There's also no engine-
level record of *what was on the dashboard before the push*, so even
in principle you can't put the platform back exactly the way it was.

**What this fix does.** Before each PATCH, the engine writes both:

  - the *outgoing* payload (what we're about to send), AND
  - the *current platform* payload (what's there right now)

to a per-push directory:

```
.vapi-state.<env>.snapshots/<ISO-timestamp>/<resource-type>/<id>.json
```

Snapshots are operator-local (gitignored) and recreated each push.
A single timestamped directory pins one push run, so rollback can
target an entire push, not individual PATCHes.

`npm run rollback -- <env> --to <ISO-timestamp>` re-applies each
`platform` payload from the snapshot as a PATCH. `--list` prints all
available timestamps.

**Outcome you'll notice.** Real undo. After a bad push, run
`npm run rollback -- <env> --list` to see your snapshots, pick the
one from before the bad push, and `--to <timestamp>` puts the
dashboard back to that state. No more "I hope `git revert` does
what I want."

---

Real undo. Before each PATCH, write the *outgoing* (local) payload AND
the *current platform* payload to a per-push directory. `npm run rollback
-- <env> --to <ISO-timestamp>` re-applies each platform payload as a
PATCH, restoring the dashboard to its state at the moment of the
snapshot.

Snapshots are operator-local state (.vapi-state.<env>.snapshots/),
gitignored, and recreated on every push. Each push pins one timestamped
directory so rollback can target an entire push, not individual PATCHes.

Files:
- src/snapshot.ts (NEW): writeSnapshot, listSnapshotTimestamps,
  loadSnapshot. Pins a single timestamp per push run (getRunSnapshotDir
  is idempotent within the process). Reuses sortedKeysReplacer so
  snapshot files have deterministic key order too.
- src/rollback-cmd.ts (NEW): npm run rollback -- <env> --to <timestamp>
  re-applies each platform payload as a PATCH. --list prints available
  snapshots.
- src/push.ts: writeSnapshot call after drift check passes. Costs one
  extra GET per resource (acceptable for the safety guarantee — follow-
  up: plumb drift's GET result through to avoid the duplicate fetch).
  Snapshot failures don't block the push.
- package.json: rollback script.
- .gitignore: .vapi-state.*.snapshots/ already covered.
- AGENTS.md: document npm run rollback / --list.
- tests/snapshot.test.ts: writeSnapshot creates the right path,
  multi-resource snapshots share a timestamp, listSnapshotTimestamps
  sorted, loadSnapshot round-trips.

Closes improvements.md #3.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@dhruva-reddy dhruva-reddy force-pushed the dhruva-reddy/feat/snapshot-rollback branch from 9667011 to 866b910 Compare May 2, 2026 01:33
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