# Storage lifecycle contract fixtures

This directory is the executable oracle for private object keys, authorization, signed downloads, Library projection, ZIP delivery, archive safety, deletion, and reconciliation. It models the host orchestration boundary; platform adapters remain dependencies and are never reimplemented here.

## Normative rules

- Source key: `sources/{owner_uuid}/{upload_uuid}/source.pdf`.
- Package key: `packages/{owner_uuid}/{conversion_uuid}/attempt-{attempt_no}/output.zip`.
- UUIDs are canonical lowercase RFC 4122 strings. Attempt numbers are positive JSON-safe integers. Original filenames never enter keys.
- Source expiry is immutable `accepted_at + 48h`; ZIP expiry is independently immutable `completed_at + 48h`. API denial and deletion become due at `now >= expires_at`.
- Configured download TTL is an integer from 30 through 300 seconds. Effective expiry is `min(now + configured_download_ttl, zip_expires_at)`. An effective TTL below exactly five seconds returns the exact `410 ARTIFACT_EXPIRED` envelope without invoking the signer.
- Authentication and database ownership checks precede object existence, expiry, and signing. Foreign and nonexistent conversions are indistinguishable `404 NOT_FOUND`. Every signed URL binds exactly one key and `GET`.
- The Library is owned-only and newest-first with a stable ID tie-break. Downloads cost zero, expose no raw key, and exist only for complete, present, unexpired ZIPs.
- One self-contained ZIP is the sole delivery representation. Archive validation rejects all vectors enumerated in `cases.json`; ceilings are represented only as booleans, never as exhaustion payloads.
- Lifecycle is primary. Hourly bounded reconciliation verifies exact objects and counts, accepts absence as convergence, retries and alerts on inaccessible/unknown state, deletes nothing outside its declared namespace, measures lag, and blocks readiness after two hours.

## Machine contract

`case.schema.json` uses Draft 2020-12 and dispatches a closed input shape by `operation`. `suite.schema.json` fixes exact ordered membership. `manifest.json` fixes count, IDs, dependencies, safety assertions, and the required `BLOCKED` dependency failure state. `expected` contains only typed runner assertions: outcome, HTTP status/error envelope, complete state, exact call counts/arguments, and exact mutations. No prose evidence is an oracle.

A runner must compare the entire `expected` object. Omitted calls and mutations mean none. It must reject duplicate IDs, unknown properties, malformed RFC 3339 timestamps, noncanonical UUIDs, unordered membership, referential mismatches, and count disagreement.

## Remote-only validation

Validation must run on `debian1`; `debian2` and then `debian3` are fallbacks. Use an explicit direct SSH route (`ssh -F /dev/null ...`), copy only this synthetic directory, and install Python validators only on the remote host. Missing SSH, Python, `jsonschema>=4.18`, `referencing`, schema resources, or format-check support produces `BLOCKED`, never success. Retain sanitized exact stdout/stderr and exit status. Do not validate or install dependencies on the workstation.

The suite contains no customer data, PDF bytes, credentials, secrets, signed URLs, public object URLs, or executable resource-exhaustion payloads.
