Rollback and unpublish
Rollback and unpublish
Section titled “Rollback and unpublish”Rollback restores routing pointers to existing immutable snapshots. It is not a source-control checkout, database rollback, provider-message recall, trigger rollback or restore of users/resources/secrets. Publish rights (effective project Owner/Admin) are required for both rollback APIs and endpoint history/unpublish. Project revision history/show only require membership. Do not confuse the two rollback scopes.
All examples are source-derived/unexecuted. These operations change what callers execute and may warm workers/reload routes. Real rollback, smoke requests and external cleanup require explicit approval.
Choose the correct recovery
Section titled “Choose the correct recovery”| Need | Entry point | Exact scope |
|---|---|---|
| Stop new calls to one leaf | POST /projects/<slug>/endpoints/<id>/unpublish | Removes active snapshot pointer, keeps history. Protected built-in auth leaves refuse. |
| Restore that leaf’s previous version | POST …/endpoints/<id>/rollback | Chooses highest snapshot version less than the currently active version; not an arbitrary version/id selector. Requires a suitable prior active/history state. |
| Undo most recent active publication revision | POST /projects/<slug>/publish/rollback | Locks latest not-yet-rolled-back project revision and restores each recorded before pointer. Newly published leaves with before=null become unpublished. |
No body, version/id option, warning acknowledgement or test expectation is needed by rollback. Null/omitted body is not “choose latest arbitrary historical release”; the route determines selection. There is no native publish rollback <revision-id> or forward promotion-by-snapshot API. viat publish show <id-or-prefix> only reads.
Inspect before changing traffic
Section titled “Inspect before changing traffic”GET /projects/<slug>/publish/history?limit=20&offset=0 returns project_slug,total,limit,offset,revisions. Limit clamps 1–100, offset >=0. Each revision has id,created_at,created_by_email,endpoint_count,rolled_back_at,rolled_back_by_email,summary. GET …/publish/revisions/<uuid-or-prefix> returns id,project_slug,created_at,created_by_email,rolled_back_at,rolled_back_by_email,endpoints,warnings?; warnings is omitted when none. Each endpoint contains node_id,method,path,before_snapshot_id,before_snapshot_version,after_snapshot_id,after_snapshot_version,target_kind,target_name. Prefix must uniquely identify one project revision, otherwise 400; unknown is 404.
For one endpoint GET …/endpoints/<id>/history returns an array of complete SnapshotView, not source blobs. Compare active id/path/method and target versions before running rollback. A plan/history response is not a traffic lock; coordinate operators and stop concurrent publish/edit automation.
Complete project example
Section titled “Complete project example”POST /projects/demo/publish/rollbackAuthorization: Bearer <console-token>Content-Type: application/json
{}{"project_slug":"demo","revision_id":"00000000-0000-4000-8000-000000000010","rolled_back_count":1,"endpoints":[{"id":"00000000-0000-4000-8000-000000000001","method":"GET","path":"/hello","restored_snapshot_id":"00000000-0000-4000-8000-000000000003","restored_snapshot_version":1}]}This marks that revision rolled back, refreshes the project registry, purges affected endpoint cache generations and reconciles worker pools. A null restored_snapshot_id/version means unpublished, not deleted. “nothing to roll back” is 400. Repeating a successful project rollback can undo the next older active revision, so it is not idempotent; on lost response inspect history/current pointers before retrying. There is no request Idempotency-Key contract on this management route.
Single endpoint POST /projects/demo/endpoints/<id>/rollback {} returns the SnapshotView directly:
{"id":"00000000-0000-4000-8000-000000000003","node_id":"00000000-0000-4000-8000-000000000001","version":1,"method":"GET","path_pattern":"/hello","target_kind":"script","script_name":"echo","script_version":1,"workflow_name":null,"workflow_version":null,"proxy_resource_name":null,"created_by":"00000000-0000-4000-8000-000000000004","created_at":"2026-11-06T00:00:00Z"}It selects a previous snapshot, not a new snapshot, then reloads routes and invalidates cached answers. It revalidates restored project_users_grant/current_user_grant against current role/capability restrictions; old validity is not sufficient. Project rollback is a separate bulk pointer-restoration path, not a promise to rerun every per-endpoint publish/grant/regression check. Review restored security bindings and current policy explicitly. Rollback does not run the saved-case publication gate.
What recovery cannot promise
Section titled “What recovery cannot promise”- Draft script/endpoint rows remain drafts; rollback does not rewrite them to historical source. A later apply can republish a still-dirty unwanted draft. Inspect plan and fix the repo/draft deliberately.
- Ordinary frozen script dependency graphs restore with their snapshot;
(live)dependency graphs and workflow step uses (including nested) are still live. Restoring main source does not restore those modules. - Resource credentials/config, authorizer configuration, authorization rules, project users, DB migrations/data, cache-invalidating external changes and trigger settings remain current. A schema-incompatible old script may still fail.
- In-flight HTTP/async runs keep already accepted payloads; existing WS connections/current message effects are not a transactional global cutover. Rollback/timeout/cancel cannot retract committed writes or sent messages.
- Project revision history is bounded by configured retention (default 20 revisions); snapshot persistence and project revision retention are different. A deleted endpoint is not automatically recreated by pointing at an old revision. Export of drafts is not a backup of snapshot history or business data.
CLI, verification and cleanup
Section titled “CLI, verification and cleanup”viat publish history --limit 20 --offset 0 --jsonviat publish show 00000000-0000-4000-8000-000000000010 --jsonviat publish rollback --yes --jsonviat endpoint rollback 00000000-0000-4000-8000-000000000001Commands are alternatives, not a sequence to execute together. Normal project rollback prompts unless —yes/—json; declining can exit 0 without doing anything. Endpoint rollback has no revision argument. See CLI publication and CLI endpoint for literal flags.
After success verify current pointers/versions, build/env health, an allowed and forbidden caller, expected public path/method and cache freshness on each relevant instance. For a timeout do not automatically retry: an operation may have committed before response loss. If previous snapshot cannot run under today’s resources/schema, unpublish the affected leaf to stop new traffic, repair compatible config/code and deliberately republish. Re-enabling triggers or replaying tasks is separate approval. Clean isolated test endpoints via unpublish/delete after drains; preserve recovery/audit evidence and do not delete production snapshots/logs to hide a failed rollout.
Evidence: crates/viat-api/src/handlers/{publish,snapshots}.rs; crates/viat-db/src/{revisions,snapshots}.rs (before=null and pointer rollback tests); crates/viat-core/src/types/snapshot.rs; CLI publish/endpoint implementations. No rollback, build, test or provider action was executed.