Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions contracts/agents-api/environment-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -906,5 +906,6 @@ published protocol maxima. [File resource qualification](file-resource-semantics
records default-selected unversioned content and descriptive metadata, default
deletion rejection with multiple versions, and nondefault latest pointer fallback.
Core updates the default pointer and top-level name/description atomically, while
concrete version bytes and previously frozen Sessions remain immutable. Last-version
deletion, version-number reuse and complete errors/visibility timing remain gaps.
concrete version bytes and previously frozen Sessions remain immutable. Deleting the
last version deletes the Skill; version numbers are intentionally never reused.
Complete errors and visibility timing remain gaps.
47 changes: 46 additions & 1 deletion contracts/agents-api/file-resource-semantics.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ The Skill probe observed an acknowledged version deletion followed about two
seconds later by a list and exact GET that still exposed that version, while the
parent latest pointer had already changed. It stopped and cleaned up. Core does
not emulate this inconsistent visibility. Fresh/reduced sole-version deletion was
not reached; the guide's default-versus-last-version precedence remains unresolved.
not reached in this probe; the later [sole-version deletion](#sole-version-deletion--september-23-2026)
batch records that observation.
Upload `default:true` was not separately probed: updating descriptive metadata
there is the same pointer-consistency rule, covered by Core tests rather than a
new official wire claim. No newer schema or integer selector form was adopted.
Expand Down Expand Up @@ -100,3 +101,47 @@ the neighboring test's initial-focus wait corrected that test synchronization;
the final full Web gate passed without weakening assertions or changing credential
business behavior. Private logs and original artifacts remain under the evidence
root above. These results do not close the remaining protocol gaps.

## Sole-version deletion — September 23, 2026

Evidence: campaign scan 1, `~/.parsar/remediation/20260923/campaign-scan-1/skills-files-templates/findings.json`
SFT-01 to SFT-04, with raw records in the adjacent `official-ledger.jsonl` (labels
`s1-*`, `s2-*`, `s3-*`). The scan owned three Skills and created no Sessions or
model calls.

| # | Case | Official observation | Core rule |
| --- | --- | --- | --- |
| V1 | Delete the only remaining version, which is also the default | 200 `{"id": "skillver_…", "object": "skill.version.deleted", "deleted": true, "version": "1"}`; retrieve and versions.list then return 404 (SFT-01) | Same body; the Skill is deleted in the same transaction. The reduced case (delete v2, then v1 is the only version) applies the same rule; official evidence covers only a fresh single-version Skill |
| V2 | Delete the default while another version is visible | 400 invalid_request_error, invalid_value, param version (SFT-04) | Unchanged |
| V3 | Delete a nondefault or latest version | 200; latest falls back | Unchanged |
| V4 | Foreign or missing Skill or version | 404 | Unchanged, indistinguishable |

`DeleteSkillVersion` keeps the owning Skill row lock. When the target is the
default, it deletes the Skill only if no other version row exists, through the
same cascade as `skills.delete`, so every encrypted version row is removed in the
same commit; otherwise the 400 remains. Uploads take the same lock: an upload
committed first makes the default undeletable, and a deletion committed first
makes the later upload return 404. Frozen Session installations keep their own
snapshot, and Templates keep their stored reference intent, exactly as after
`skills.delete`. No schema, query or numbering change is involved.

Recorded decisions:

- **SFT-02, number reuse: intentional difference.** After the latest nondefault
version 2 was deleted, the next official upload was numbered "2" again (one
sample, so max+1 and latest+1 are indistinguishable). Core keeps immutable,
monotonically increasing numbers because exact Template and Session selectors
reference numbers; reusing one could re-point a stored exact selector to other
bytes and make a frozen Session's concrete version ambiguous. A sole-version
deletion removes the Skill, so numbering never restarts within a Skill.
- **SFT-03, upstream anomaly: never emulated.** Deleting default version 1 about
four seconds after an acknowledged version 2 upload returned 200 and removed the
whole Skill, including version 2. The same request with version 2 visible
returned 400 (SFT-04). Core serializes both operations on the Skill row, so a
version deletion never removes an acknowledged upload.

Core acceptance: real-PostgreSQL store tests prove atomic Skill removal without
orphaned version rows, unchanged frozen Session contents, creation retry and
Template intent, and both lock orders of a concurrent upload; a real HTTP test
covers V1 to V4 across two tenants, and `official_skills.py` checks V1 with the
pinned SDK and raw HTTP. None of these run a model.
4 changes: 3 additions & 1 deletion contracts/agents-api/list-query-semantics.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@ unsampled inputs:

These remain registered differences and are not changed here: repeated Files
`purpose` values (SFT-18); unsampled overflowing limits; Skill sole-version
deletion and number reuse (SFT-01/02); Session deletion lifecycle (SES-29/30);
deletion and number reuse (SFT-01/02, since resolved or recorded in
[file resource semantics](file-resource-semantics.md#sole-version-deletion--september-23-2026));
Session deletion lifecycle (SES-29/30);
whitespace input (SES-01..04); Template network forms (SFT-21/22); and response
defaults (VA-11, SES-23/25). Malformed path IDs (SES-28), metadata and name error
fields (VA-07/08/09), U+0000 (VA-10) and Template network codes (SFT-20) are
Expand Down
4 changes: 3 additions & 1 deletion contracts/agents-api/official-semantics-alignment.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ Deferred and unchanged: accepting and storing U+0000; hostname forms accepted
officially (SFT-21) and `disabled` with domains, which the official service
accepts (SFT-22); non-canonical UUID spellings such as uppercase, braces or
`urn:uuid:` still resolve to the same resource; Skill sole-version deletion and
number reuse; Session deletion lifecycle; whitespace input; response defaults;
number reuse (since resolved or recorded in
[file resource semantics](file-resource-semantics.md#sole-version-deletion--september-23-2026));
Session deletion lifecycle; whitespace input; response defaults;
and the Files `limit=abc` code. The Environment Files list query parser is aligned
for unknown and repeated keys by the [Environment Files wire batch](environment-files.md#wire-alignment--september-23-2026);
it still rejects malformed query encoding locally.
Expand Down
5 changes: 3 additions & 2 deletions contracts/agents-api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5569,8 +5569,9 @@ paths:
- Skills
/skills/{skill_id}/versions/{version}:
delete:
description: Rejects deletion of the current default version. Exact hosted last-version/default
deletion precedence is not verified.
description: Deleting the only remaining version also deletes the Skill; existing
Session installation snapshots remain independent. The default version cannot
be deleted while other versions remain. Version numbers are never reused.
parameters:
- description: Skill ID
in: path
Expand Down
6 changes: 3 additions & 3 deletions contracts/agents-api/operation-evidence.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,19 @@ Paths in the appendix include `/v1`. SDK names here omit `client.`. `P` means pa
| 49 | skills.retrieve | P: safe metadata follows default version | E missing-ID404; W distinct names/descriptions follow default1→2→1 | Skill store and joint resource acceptance | Other error/visibility behavior remains unqualified |
| 50 | skills.update | P: atomic default pointer and descriptive metadata update | V default mutation/frozen Sessions; W default1→2→1 name/description changes | Skill store and joint resource acceptance; retained frozen Session regression | Complete errors and concurrent official behavior |
| 51 | skills.list | P: scoped resource list; limit 0 empty page with has_more, 0–100 with observed range and duplicate codes | L SFT-08/09/10/11 | K recorded DB resources; L DB tenant A/B | Non-integer and overflowing limits unsampled |
| 52 | skills.delete | P: remove owned source, retain committed Session content | None located | K recorded DB and Live source deletion/continuation | Exact hosted deletion/idempotence/default/latest semantics |
| 52 | skills.delete | P: remove owned source and every encrypted version, retain committed Session content; sole-version deletion uses the same cascade | [sole-version deletion](file-resource-semantics.md#sole-version-deletion--september-23-2026) SFT-01 sole-version deletion then Skill 404; SFT-06 repeat delete 404; SFT-07 retrieve/version reads 404 | K recorded DB and Live source deletion/continuation; sole-version store, HTTP tenant A/B and pinned-SDK DB tests | Official 404 message names the Skill, Core keeps a generic message; physical erasure and concurrent hosted deletion unobserved |
| 53 | skills.content.retrieve | P: unversioned content selects default | W distinct default1/latest2 bytes and default2 transition | K recorded DB plus joint resource acceptance | Headers/errors and source deletion/read races |
| 54 | skills.versions.create | P: immutable increasing version; optional default change | V second version default=false preserves default1/latest2 | K recorded DB resources | Broader numbering/default/top-level metadata/error/null semantics; upload limits |
| 55 | skills.versions.retrieve | P: owned immutable version metadata; malformed version path equals missing | V immediate version1 read404, bounded delayed read200 | K recorded DB resources and Live concrete Session freeze | Visibility timing is observational; full selector/metadata/error parity unqualified |
| 56 | skills.versions.list | P: scoped version cursor list; limit 0 empty page with has_more | V delayed owned list contains created versions; L SFT-08/09 | K recorded DB resource checks; L DB zero page | Exact ordering/cursors/default and concurrent version mutation |
| 57 | skills.versions.delete | P: nondefault deletion; default rejects invalid_value/version | W two-version default400; latest200 with parent pointer fallback | Skill store and joint resource acceptance | Sole deletion/number reuse unverified; observed stale official version reads are not emulated |
| 57 | skills.versions.delete | P: nondefault deletion; default rejects invalid_value/version while other versions remain; deleting the only version deletes the Skill in the same locked transaction | W two-version default400; latest200 with parent pointer fallback; [sole-version deletion](file-resource-semantics.md#sole-version-deletion--september-23-2026) SFT-01 sole200 then Skill 404, SFT-04 default400 with visible v2 | Skill store (atomic removal, frozen Session, upload lock order), HTTP tenant A/B and joint resource acceptance | SFT-02 number reuse is an intentional difference (numbers stay immutable); SFT-03 whole-Skill removal and stale official version reads are not emulated |
| 58 | skills.versions.content.retrieve | P: decrypt/read immutable concrete bundle | W v1/v2 ZIP members and markers | K recorded DB/live consumption; joint resource acceptance | Content headers/errors and source deletion/read races |

## Remaining gaps without task ordering

1. **Public generic semantics:** sampled create/event/envelope/error/no-op corrections are merged. L aligns unknown/repeated list keys, sampled limit bounds and single-resource unknown keys. X gives malformed path IDs on every Beta, Files and Skills route the exact missing-resource response, reports metadata/name field errors with official code and param, maps Template network rejections to `invalid_request_error`, and rejects U+0000 in stored strings as a documented local limit (the official service stores it). G aligns Environment Files list query tolerance and the sampled Files.create/list errors. Other resource-by-resource omissions/null/default/error params, overflowing limits, list caps, concurrent mutation and deletion require separate evidence.
2. **Session differences:** The Session admission batch removes idle `none` creation and empty metadata update. Local durable creation idempotency remains an explicit difference. Whitespace-only input succeeds officially but is rejected by the existing Core message validator; this newly observed difference is queued separately. Session agent updates, newer Environment shapes and root Item turn_id are baseline-upgrade questions.
3. **Template/Skill composition:** shared env/files/setup/packages selection is covered by the composition batch; template-reference null network/capability lists are covered by the null-selection batch. Official derived capability-directory projection remains different. Skill content/default metadata are covered by file-resource-semantics.md; sole-version deletion, visibility and broader numbering/error behavior remain unverified.
3. **Template/Skill composition:** shared env/files/setup/packages selection is covered by the composition batch; template-reference null network/capability lists are covered by the null-selection batch. Official derived capability-directory projection remains different. Skill content/default metadata and sole-version deletion are covered by file-resource-semantics.md; number reuse is an intentional difference; visibility and broader error behavior remain unverified.
4. **Execution coverage:** use T's qualified matrix, not a blanket missing-image/structured-output claim. MiniMax functions/service MCP, optional tool combinations, unsupported images/placements and broader native lifecycle are explicit restrictions. PTC omission retains approved native behavior; Claude/MiniMax public Usage remains null; child settlement cadence/native close limits remain visible. No second executor/model loop or guessed counters are justified.
5. **Workspace and resources:** live Files bounds, recursion and parent creation (G aligns the sampled envelope, empty pages and path errors), artifact capture edges for hard links/special files and cancellation (Y aligns output symlinks, republication and the list envelope), full Environment metadata/lifecycle and Vault archive/in-flight-token semantics remain partial or unknown. Retired Core-managed E2B acceptance cannot qualify current user enrollment.

Expand Down
2 changes: 1 addition & 1 deletion services/agents-api/internal/api/skills.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func (h *Handler) getSkillVersion(w http.ResponseWriter, r *http.Request) {
}

// @Summary Delete a Skill version
// @Description Rejects deletion of the current default version. Exact hosted last-version/default deletion precedence is not verified.
// @Description Deleting the only remaining version also deletes the Skill; existing Session installation snapshots remain independent. The default version cannot be deleted while other versions remain. Version numbers are never reused.
// @Tags Skills
// @Produce json
// @Security BearerAuth
Expand Down
Loading
Loading