mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[GH-ISSUE #432] Interrupted template deletes leave deleting tombstones that shadow aliases: start-by-name 400s, re-registration refused (v0.2.4) #104
Labels
No labels
bug
documentation
enhancement
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/AgentENV#104
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @mingfang on GitHub (Oct 24, 2026).
Original GitHub issue: https://github.com/kvcache-ai/AgentENV/issues/432
Summary
v0.2.4's routing refactor ("Route sandbox and build paths from one table") makes sandbox start-by-name resolve exclusively through the alias table (
catalog/aliases/<name>.json→ snapshot ID → record).If a template delete is interrupted mid-flight, the registration record stays behind as a
deleting: truetombstone. That tombstone:400 template <name> not found, while the same payload with the registration UUID returns201(UUID start bypasses the alias table).claim_aliastreats the tombstone as a live owner and rejects with an alias conflict, so affected templates cannot be re-pinned.deletingrecords, soDELETE /templates/<name>reports "not found".GET /templates— the list filters outdeletingrecords, so operators can't see what's wrong.alias_owneronly releases a stale alias when the owner record is completely missing; adeletingrecord still exists, so the heal never fires.In our production deployment (v0.2.4, OSS repository backend), 10 of 16 templates hit this over ~2 days of template churn. The failures tracked exactly the templates whose aliases pointed at tombstones; templates whose aliases pointed at live registrations (or were re-claimed fresh) worked normally throughout.
Code refs (v0.2.4)
src/snapshot/catalog.rsdelete(): marksdeleting=true, then deletes blobs → build log → record → alias. An interrupted run leaves the record marked. The comment says "A delete that failed partway leaves the record marked; retrying finishes it" — retrying by ID does finish it (verified: all our tombstones cleared with204), but nothing retries automatically, and retry by name cannot even find the tombstone (resolution skips it).resolve_alias()→alias_owner(): the self-heal (cleaning up stale alias pointing to missing snapshot) fires only whenread_record()returnsNone. Adeletingowner short-circuits the heal; the caller's!record.deletingfilter then yieldsNone→404on the aliases endpoint /400on start.claim_alias():read_record(existing).is_some()→alias_conflict, even when the existing record is adeletingtombstone.SnapshotListFilter::templates(): excludesdeletingrecords fromGET /templates.Reproduction
DELETE /templates/{id}for a template that owns an alias.GET /templatesno longer lists the template;POST /sandboxes {"templateID": "<alias>"}→400 template <alias> not found(single-digit ms);POST /v3/templatesre-pin → alias conflict;GET /templates/aliases/<alias>→404 template alias not foundeven though the alias document still exists in the store pointing at the tombstoned ID.Recovery that worked
DELETE /templates/{tombstone_id}by UUID — the delete retry path resumes and finishes the partial delete.Suggested fix
resolve_alias/alias_owner: treat adeletingowner as absent — self-heal (release the alias, optionally finish the interrupted delete) instead of shadowing it.claim_alias: allow stealing an alias whose owner record isdeleting, same as the completely-missing case.