mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[GH-ISSUE #448] Template soft-delete stalls permanently after marking deleting=true — re-issuing DELETE is a no-op, and deleting records still own aliases (blocks rebuilds, invisible to resolution) #110
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#110
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 28, 2026).
Original GitHub issue: https://github.com/kvcache-ai/AgentENV/issues/448
Summary
Follow-up to #447 (separate failure mode, same production deployment, 2026-10-27→28). Five templates (
system,app-sandbox,fn-node,fn-extraction,fn-python) entered a state where:400 — alias 'X' already points to '<owner>', cannot rebind to '<new>'(therequestBuildpre-validation reads the alias row raw).GET /templates/aliases/X→404 template alias not foundbecauseresolve_aliasfilters outdeletingrecords (catalog.rs:281), so clients see the name as free while rebuilds see it as taken.DELETE /templates/{id}returns 204 but does nothing.Root cause 1 — the stalled deletion has no resumer
The delete pipeline (
catalog.rs:246-274) marks the recorddeleting=true, then deletes files → build log → record → releases the alias. In production the pipeline stalled immediately after the mark (the runtime process died mid-delete on 2026-10-27 ~18:49). Nothing retries it: no boot-time sweep, no reaper processesdeleting=truerecords.Root cause 2 — re-issuing DELETE is a silent no-op
catalog.rs:252treats an already-deletingrecord as "another delete finished first" and returnsOk(())early:The code comment at
catalog.rs:264-265("Files go before the record, and the alias after it, so a failed delete can be retried by ID or alias") describes intent the implementation does not fulfill: a delete that failed after the mark cannot be retried — the retry seesdeleting=trueand returns success without cleaning anything. We verified this in production: fiveDELETE /templates/{id}calls returned 204 while the OSS documents were untouched (mtimes unchanged).Observed end state (before manual repair)
For each of the five snapshots:
catalog/records/{id}.jsonpresent,deleting: true(36h stale)catalog/aliases/{alias}.jsonpresent, pointing at the deleting idWe repaired by completing the pipeline manually against OSS (delete
artifacts/{id}/, build log, record, then the alias row — the pipeline's own order).Suggested fixes
deleting=true, proceed with steps 2-5 (they are all idempotent — blob prefix delete, document deletes,release_alias). This single change makes the documented "retried by ID or alias" true.catalog/records/fordeleting=truerecords older than a threshold, completing the pipeline (protects against a crash between mark and completion forever).claim_alias's owner check should treat adeletingowner the wayresolve_aliasdoes (or at least therequestBuild400 should say "alias owned by a snapshot that is being deleted — retry when deletion completes"), so clients don't deadlock between a refusal and a deletion that never finishes.Environment: v0.2.4, single node + gateway, OSS (S3-compatible) repository, k8s deployment with the gateway and scheduler as separate services.
@yingdi-shan commented on GitHub (Oct 28, 2026):
Thanks for your report! This should have been fixed by commit
d3818b085a.