Skip to content

Bind container deletion and exit callbacks to instances - #2201

Open
sturdy4days wants to merge 5 commits into
apple:mainfrom
sturdy4days:codex/force-removal-instance-token-20260827
Open

Bind container deletion and exit callbacks to instances#2201
sturdy4days wants to merge 5 commits into
apple:mainfrom
sturdy4days:codex/force-removal-instance-token-20260827

Conversation

@sturdy4days

@sturdy4days sturdy4days commented Aug 27, 2026

Copy link
Copy Markdown

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

Addresses #2116.

Container IDs can be explicitly reused. A delayed delete or exit callback that only carries an ID can therefore act on a replacement container after the original instance has gone away. Force deletion makes the ownership boundary especially important because stopping and cleanup span asynchronous work.

This change:

  • generates and persists a server-owned token for every container instance, overwriting any caller-supplied token;
  • returns the authoritative container ID and instance token from the same create operation through a result-capable API route;
  • adds container create --format json for orchestrators that need to retain that exact ownership token without a later inspect;
  • adds container delete --if-instance-token TOKEN ID and validates the token while holding the container lifecycle lock;
  • advertises result-capable create and conditional-delete support through the health check, with no unsafe fallback;
  • reserves an ID across forced stop/cleanup, revalidates the selected instance before final cleanup, and rejects bootstrap/start once force deletion has reserved the instance;
  • binds exit-monitor tasks and callbacks to registration generations so cancelled work from an old instance cannot invoke a replacement callback; and
  • treats bundle removal as the cleanup commit point, retaining or reconstructing an ID reservation when residual state cannot be removed safely.

Backward compatibility is preserved. The legacy create route and ordinary create output remain supported. The public Swift ContainerClient.create(...) API retains its exact legacy async throws -> Void signature; createWithResult(...) is the distinct result-returning API. The exact legacy ContainerClient.delete(id:force:) and ContainersService.delete(id:force:) entry points also remain present, while deleteIfInstance(id:force:expectedInstanceToken:) provides the distinct required-token path.

An older client can ignore the optional result returned by a newer server. Result-capable create and conditional delete check server capabilities and use distinct routes, so a newer client fails before an unsafe operation when connected to an older server. Typed ContainerizationError, including .unsupported, is preserved rather than being reclassified as an internal error.

Credit and overlap: @nassersala documented the reusable-ID race and an earlier local token-precondition proof of concept in this #2116 comment. This PR does not claim origin of that model. The comment describes an unpublished 9-file local patch; no public branch or PR is linked. This implementation covers the same ownership concern while also handling force-delete ID reservation/revalidation, mixed-version capability negotiation, atomic machine-readable create results, cleanup-failure identity retention, start/bootstrap reservation checks, and stale exit-callback generation ownership.

This is a source proposal only. It is not merged, released, or active in a shipped runtime.

Current Revision

  • Rebased onto apple/container main at b8ffd38c734448af49cab87c537075f0a803222b.
  • Current head: 69d609498bce690a04346d48b34379b9ed33edb0.
  • All commits, including the final Review correction, are signed.

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

Validation on exact head 69d609498bce690a04346d48b34379b9ed33edb0:

  • make swift-fmt-check
  • make build
  • make build-tests
  • focused unit suites: 40/40 tests passed across client, service, command, configuration, managed-container, and exit-monitor coverage
  • make test: 799 non-integration tests in 89 suites passed
  • isolated integration warmup: 4/4 image cases passed
  • selected integration suites: 9/9 tests passed
    • TestCLICreateCommand: 6/6
    • TestCLIRmRaceCondition: 3/3
  • deterministic cleanup-failure regression proves retained identity, blocked same-ID recreation, restart reservation, and stale-token rejection while residual state remains
  • compile-time function references and built symbols verify the exact legacy delete APIs alongside the distinct conditional APIs
  • typed-error regressions verify .unsupported preservation and unknown-error conversion to .internalError
  • git diff --check, signed-history verification, and git fsck --full --no-dangling

An independent exact-object source review of this head completed with P0=0, P1=0, P2=0, and P3=0. That review is local source evidence only; it is not maintainer approval, CI, merge, release, or runtime activation.

The isolated integration service and disposable test root were removed after validation. No Docker or NanoClaw runtime was selected or activated.

Return the server-generated ID and instance token from container creation, expose safe JSON CLI output with mixed-version fail-closed negotiation, and reject start/bootstrap after force-deletion reservation. Add deterministic ownership, compatibility, integration, and command-reference coverage.
Keep ContainerClient.create source-compatible as async throws -> Void while discarding the optional server reply internally. Expose create results only through createWithResult and compile-check both exact function types.
@sturdy4days
sturdy4days force-pushed the codex/force-removal-instance-token-20260827 branch from 5a1500c to 69d6094 Compare September 2, 2026 19:24
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