Repository navigation
feat(host): back up hosted and compute channels and restore backups as new channels - #435
Merged
Merged
Conversation
…s new channels `ace backup` now takes a hosted or cloud compute channel's pi state from its service with a new `backup` transfer action, which reads one consistent snapshot without freezing the channel. `ace restore` verifies a backup and adds it as a new local channel with a new ID and lane prefix. Why: packages/channel/src/transfer.ts#function backupSnapshot | the read stays one transaction on the channel's DurableSqlite, which serializes every pi read and write, so a backup needs no freeze Why: apps/host/src/backup.ts#function restore | a restored copy always gets a new ID and lane prefix so it can never run as the original channel Why: apps/host/src/backup.ts#function exported | the service is asked before the destination exists, so a refusal or an older service leaves nothing behind
6 tasks
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.
Fixes #178.
ace backup <channel> <dir>now works for hosted and cloud compute channels as well as local ones (option B: export-based backups).ace restore <dir>adds any backup as a new local channel.Design
backupaction to the existingPOST /channels/:id/transfer. It runsbackupSnapshot, which reads every pi table in onedb.transaction. All pi reads and writes on a hosted channel go through the sameDurableSqlite, which runs that transaction on its own insidestorage.transaction. So the snapshot is a consistent point in time withoutfreeze: clients stay connected and runs keep going. Nothing is frozen, so a failed backup can't leave the channel frozen.activeandfrozenchannels can be backed up. Aninactiveimported copy from an unfinished move is refused.exportSnapshotfor moves, a backup doesn't refuse a busy channel. It records unfinished runs, as a localVACUUM INTOsnapshot does.snapshot.jsonis the same version 1 transfer snapshot, with its SHA-256 digest of the canonical encoding.backup.json(format 1) adds the service URL and that digest next to the per-file SHA-256 checksums. Over 32 MiB is refused with "The channel is larger than the 32 MiB snapshot limit, so it cannot be moved or backed up".hostedAuth()(the team'sACE_SECRET) and the service's existing bearer check. A service without the action answers 400 "Unknown transfer action". The host reports that as "<url>predates hosted channel backups; redeploy it to back this channel up." The service is asked before the destination is created, so a refusal leaves nothing behind.ace restore <backup> [--project <dir>]checks every file againstbackup.json, then creates a new local channel with a new ID and a new lane prefix. A hosted snapshot goes throughimportSnapshot, which verifies the digest and refuses a non-empty store. A local backup'schannel.sqliteis copied. The catalog record is written last. The copy can never run under the original's ID, whether that channel is still live locally or on its service. The in-place same-ID recovery for local channels indocs/data.mdis unchanged. A hosted channel is never replaced in place.docs/data.mdsays so.transfer.tsnow treats localwrangler dev's__miniflare_do_nametable as internal. Without this, local exports (including moves) were refused with "unknown tables". It doesn't affect deployed Workers.Redeploy needed: the
backuptransfer action is new. Bothservices/channel(ace-channel) andservices/compute(ace-compute-pilot, which serves the sameHostedChannel) need redeploying beforeace backupworks against them. Until then, hosts report the redeploy message above. I did not deploy anything.Verified locally
bun typesandbun run cipass.wrangler devofservices/channelandservices/compute(containers off). The source host ranace serve --loopbackwith its ownACE_HOME, keychain service and a stubtailscale. Runs used realopenai/gpt-5-mini. No request went to a deployed Worker.compute.create, i.e./workspaces/:id/init). Each got a message and a real model run, and the hosted one also got abashtool run.ace backupsucceeded on both while they were active. A third backup, taken mid-run on the hosted channel, took about 1.6 s. It recorded taskswaiting/runningwhile the live run finished, and a message posted during that run was admitted.ace restoreon each made new local channels. Their pi tables re-hashed to the backup digests (counts matched, e.g. 8 entries, 4 tasks, 10 revisions).ace watchreplayed the same history, including the tool call and result.bashtool and reran it to completion.thawrequest returned "Only a frozen channel can be thawed (state: active)" for both, so neither was frozen.object.ts,ace backupprinted the redeploy message and created no directory.Not verified
HostedChannel.Built in Ace
No — built with Claude Code outside Ace by an overnight issue watcher, because this Mac's Ace Canary is a participant in the running two-person study (#218); dogfooding gap tracked in #5.