Skip to content

Delete a Skill with its only remaining version - #56

Merged
SaladDay merged 4 commits into
mainfrom
codex/skill-version-deletion
Sep 23, 2026
Merged

SaladDay merged 4 commits into
mainfrom
codex/skill-version-deletion

Conversation

@SaladDay

@SaladDay SaladDay commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Deleting a Skill's only remaining version used to return 400 (invalid_value, the default version cannot be deleted). The official service deletes that version and removes the Skill. This batch aligns that case. The pinned baseline is unchanged (SDK 3.13.0 / d7c41ef / agents=v1).

Behavior

  • Deleting the sole version: DELETE /v1/skills/{id}/versions/{v}, when v is the only remaining version (and therefore the default), returns the official skill.version.deleted body. The Skill and its encrypted version rows are removed in the same transaction, under the existing Skill row lock. Skill and version reads then return 404 and the list omits the Skill. Frozen Session and Template snapshots keep their committed contents, just as with skills.delete.
  • Unchanged:
    • deleting the default while other versions remain is still a 400;
    • non-default and latest deletion;
    • tenant isolation.
  • Decisions recorded:
    • Core keeps immutable, increasing version numbers rather than the official number reuse (SFT-02), because exact selectors refer to numbers.
    • The official deletion of a whole Skill shortly after an upload (SFT-03) is an upstream anomaly that Core never copies.
    • The reduced case (delete v2, then delete v1 as the only version) applies the same rule; official evidence covers only a fresh single-version Skill.

Evidence

Campaign scan 1 finding SFT-01, from owned official Skill requests (all deleted). Recorded in contracts/agents-api/file-resource-semantics.md and operation-evidence.md rows 52 and 57.

Validation

  • Independent coordinator replay: a real Core with PostgreSQL, over raw HTTP. On main beb18fd, deleting the sole version returned 400 and the Skill remained. On this batch, it returned 200 with body fields equal to the official record; the Skill, its version and its list entry were gone; a repeated delete returned 404; the default-with-others 400 was unchanged; and a foreign Skill got the same response as a missing one.

  • Real-PostgreSQL store tests:

    • atomic removal with no orphaned rows;
    • frozen Session contents and retries intact;
    • upload vs delete serialized in both orders; the lock was proven necessary by a mutation test.

    HTTP tests cover two tenants. The pinned-SDK official_skills.py passes.

  • Integration: rebased onto main e3d6b95 (Add Runtime observability and lightweight PostgreSQL history #30, feat: manage hosted sandboxes across local and remote nodes #46); the patch series is unchanged and make openapi is byte-identical. The later main commits Add Session runtime metrics tab #51 and docs: add OpenAgentCore branding and README banner #54 touch no files of this batch.

  • Server gate on this head: make -o check-web check plus Web typecheck, core-doctor, unit tests and the build all pass. The Playwright browser cases were not run on the server (no Google Chrome; skip approved by the user). make openapi is byte-identical.

  • No live model run: this is a resource-level change.

  • Independent focused review by a fresh Claude Code subagent: no blockers. It probed concurrent deletes, default updates and Session creation races. Its doc follow-ups are in the last commit, which is docs only.

Deferred

  • A Template's live selector that points at a deleted Skill fails new Session creation with 404, the same as after skills.delete. The official behavior is unobserved.
  • The official 404 message names the Skill; Core's message is generic.

No full protocol compatibility is claimed.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

Deleting the default version is still rejected while other versions remain.
When the default is the Skill's only version, the delete now removes the Skill
under the existing owner row lock through the skills.delete cascade, as the
official service does (SFT-01). Real-PostgreSQL tests cover atomic removal
without orphaned encrypted rows, unchanged frozen Session contents and
Template intent, and both lock orders of a concurrent upload.
Document the deletion rules on the handler and regenerate the OpenAPI schema.
A real HTTP and PostgreSQL test covers V1 to V4 across two tenants, and the
pinned-SDK Skills acceptance checks the observed deleted-version body and the
Skill's disappearance.
Add the SFT-01 behavior to the File and Skill resource semantics, keep
immutable version numbers as an intentional difference (SFT-02) and record
SFT-03 as an upstream anomaly that Core never emulates. Update operation
evidence rows 52 and 57 and the stale Template gap sentence.
@SaladDay
SaladDay merged commit f0b930f into main Sep 23, 2026
2 of 3 checks passed
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