--- id: SAND-WP-0009 type: workplan title: "TTL enforcement and operational hardening" domain: infotech repo: sand-boxer status: finished owner: codex topic_slug: custodian created: "2026-06-24" updated: "2026-06-24" state_hub_workstream_id: "59dfa58d-313e-4c06-83af-7e4f4ff95e99" --- # TTL enforcement and operational hardening Close the largest post-v0 functional gap: **disposable-by-default TTL** with `extend_ttl`, automated expire/reap, and platform hygiene (classification, registry, HTTP parity). Gap analysis: `history/2026-06-24-post-wp0007-intent-scope-gap-analysis.md` **Predecessor:** SAND-WP-0007 (snapshots — finished) **Follow-on:** SAND-WP-0010, SAND-WP-0011, SAND-WP-0012 (workplans filed 2026-06-24) --- ## TTL duration parser ```task id: SAND-WP-0009-T01 status: done priority: high state_hub_task_id: "44cee754-2874-40eb-9cb3-168e5bc8dd54" ``` Module `src/sandboxer/lifecycle/ttl.py`: parse profile `ttl.default` / `ttl.max` and request override strings (`4h`, `30m`, `1d`). Unit tests for edge cases and max-cap enforcement. ## expires_at on create ```task id: SAND-WP-0009-T02 status: done priority: high state_hub_task_id: "a5a6503c-56a3-4876-8211-e06b9eed6292" ``` Add `expires_at: datetime | None` and optional `ttl: str` on `SandboxStatus`. `SandboxManager.create` sets expiry from profile default or `SandboxCreateRequest.ttl`. Persist in `SandboxStore`. Emit expiry in State Hub `detail`. ## extend_ttl API ```task id: SAND-WP-0009-T03 status: done priority: high state_hub_task_id: "ff32a3e5-0bf6-479c-8373-d601588461e7" ``` `SandboxManager.extend_ttl(sandbox_id, duration)` — cap at profile `ttl.max`, reject destroyed/expired sandboxes. CLI: `sandboxer extend-ttl --duration 2h`. HTTP: `PATCH /v1/sandboxes/{id}/ttl` with body `{"duration": "2h"}`. ## Expire and TTL reap ```task id: SAND-WP-0009-T04 status: done priority: high state_hub_task_id: "ce597f28-a2f3-44ed-8e85-f8bd254bc4ce" ``` CLI `sandboxer expire` — list sandboxes past `expires_at`; dry-run default; `--apply` transitions to `expired` then `destroy` (reuse destroy path). Optional `idle_reap` hook using `updated_at` when profile sets `ttl.idle_reap`. Integrate with existing `reap-stale` docs (host inventory vs TTL are distinct concerns). ## activity-core integration contract ```task id: SAND-WP-0009-T05 status: done priority: medium state_hub_task_id: "9ad34d90-bbc7-4ede-8549-f4291e27ba22" ``` `docs/integrations/activity-core.md`: how a scheduled job invokes `sandboxer expire --apply` (or HTTP equivalent); lifecycle events for `expired` state; no Temporal code in this repo. ## Repo classification and registry refresh ```task id: SAND-WP-0009-T06 status: done priority: medium state_hub_task_id: "ffde8196-18e3-4762-8cfd-1b69874e51e1" ``` Add `.repo-classification.yaml` (clears State Hub C-24). Update `registry/capabilities/execution.sandbox-provision.md` maturity to reflect v0 (A4/C4). Document `reuse-surface validate` operator steps in `registry/README.md`; run validate if reuse-surface CLI available in environment. ## HTTP API parity ```task id: SAND-WP-0009-T07 status: done priority: medium state_hub_task_id: "69b192c7-8599-46e7-bb63-8457bfb72a81" ``` Add `POST /v1/sandboxes/{id}/recreate` and TTL endpoints to `api/app.py`. Align OpenAPI with CLI surface from SAND-WP-0007. ## Documentation ```task id: SAND-WP-0009-T08 status: done priority: medium state_hub_task_id: "69d1a23f-b3a3-4aa7-846c-e953f02977f3" ``` `docs/ttl.md` — semantics, extend, expire, profile fields. Update `docs/meta-framework.md`, `SCOPE.md`, `docs/migration-gaps.md`. Brief security note in `docs/security.md`: sandbox limits blast radius, not intent enforcement. ## Tests ```task id: SAND-WP-0009-T09 status: done priority: high state_hub_task_id: "0683b09a-0dd9-4880-9bd0-13003e3621a6" ``` `tests/test_ttl.py` (parser, extend cap), manager expire flow with mocked backend, API tests for extend/recreate. `make check` green. --- ## Out of scope (deferred) | Item | Track | |------|-------| | Real E2B / Modal / BYOK / fin-hub | SAND-WP-0010 (WP-0006-T06) | | ops-bridge tunnel descriptor | SAND-WP-0011 | | glas-harness / snuggle consumer profiles | SAND-WP-0011 | | Packer build from `create` | SAND-WP-0012 (WP-0005-T06) | | Cross-host snapshot transfer | Future | | sandboxer01 host provisioning | Operator / infra | | wise-validator T09 remote smoke | wise-validator repo | --- ## Acceptance criteria - Ready sandbox has `expires_at`; `extend_ttl` respects `ttl.max` - `sandboxer expire --apply` destroys expired sandboxes idempotently - `.repo-classification.yaml` present; C-24 warn cleared on fix-consistency - HTTP exposes recreate + extend_ttl - `docs/ttl.md` published; gap analysis P1–P4 addressed