--- id: ARTIFACT-STORE-WP-0002 type: workplan title: "Ingestion API And Manifest Surface" repo: artifact-store domain: stack status: done owner: codex topic_slug: stack planning_priority: high planning_order: 2 created: "2026-05-15" updated: "2026-05-16" state_hub_workstream_id: "cedbfe03-363c-43fd-a5cb-bef52b29af7e" --- # ARTIFACT-STORE-WP-0002: Ingestion API And Manifest Surface ## Purpose Expose the WP-0001 library as a complete HTTP API. Producers can create packages, ingest files (single-shot or via the upload-session resource shape), finalise to produce a manifest, list and search packages, download files, and tail the event stream. ## Constraints - ADR-0001, ADR-0002, ADR-0003, ADR-0004, ADR-0005, ADR-0006. - `docs/ARCHITECTURE-BLUEPRINT.md` API shape section. - All handlers must be thin: translate transport → `registry.*` calls. ## Prerequisites - WP-0001 done (library is functional against local backend). ## D2.1 - Package CRUD Endpoints ```task id: ARTIFACT-STORE-WP-0002-T001 status: done priority: high state_hub_task_id: "197e22ff-0003-433d-bfa0-2323152b85dc" ``` Acceptance: - `POST /packages`, `GET /packages` (filterable by producer / subject / retention_class / metadata key), `GET /packages/{id}`, `POST /packages/{id}/files` (single-shot multipart), `POST /packages/{id}/finalize`. - `GET /packages/{id}/manifest` (`Accept: application/cbor`) and `GET /packages/{id}/manifest.json` (JCS projection). - Validation errors return RFC 7807 problem documents. - OpenAPI is generated automatically (FastAPI default) and served at `/openapi.json` + `/docs`. ## D2.2 - File Download And Range Reads ```task id: ARTIFACT-STORE-WP-0002-T002 status: done priority: high state_hub_task_id: "9c8c3853-2090-42be-9995-0b8ce4a76104" ``` Acceptance: - `GET /files/{file_id}` returns metadata. - `GET /files/{file_id}/download` streams bytes; supports `Range` request headers (single contiguous range; multi-range is out of scope for v1). - ETag is the file's primary content address; `If-None-Match` returns `304`. - Streaming uses `AsyncIterator[bytes]` end-to-end; no full-file buffering. ## D2.3 - Upload Session Resource (Wire Shape Pinned) ```task id: ARTIFACT-STORE-WP-0002-T003 status: done priority: medium state_hub_task_id: "710bbd2f-9bc1-4395-bbd1-2b22c1b7eb37" ``` Acceptance: - `POST /uploads` opens a session, returns an upload id and content upload URL. - `PATCH /uploads/{upload_id}` accepts a body with `Content-Range`; v1 implementation may accept the whole body in one call. - `POST /uploads/{upload_id}/complete` promotes the upload into a file under a given package id and relative path. - Implementation is allowed to be single-shot internally; the wire shape and resource lifecycle must be the final one (per PLATFORM-AMBITION A6). ## D2.4 - Event Stream Long-Poll ```task id: ARTIFACT-STORE-WP-0002-T004 status: done priority: medium state_hub_task_id: "d848bc41-edfa-48fc-bb2c-f2526f422c50" ``` Acceptance: - `GET /events?since=&limit=N` returns events in order with a long-poll wait when the tail is reached. - Events are CBOR by default; `Accept: application/json` returns the JCS projection of each event payload. - Test: a consumer that tails from sequence 1 never misses an event produced during the test. ## D2.5 - Auth Scaffolding (Shared-Secret Bearer) ```task id: ARTIFACT-STORE-WP-0002-T005 status: done priority: medium state_hub_task_id: "27d33e90-6b31-4c1f-832b-870cd2c5fbe5" ``` Acceptance: - Bearer token auth on all mutating endpoints; configurable per-tenant token list via env / config file. - Read endpoints are also gated by default; an explicit `ARTIFACTSTORE_ANON_READ=true` opt-in for dev. - Health endpoint remains anonymous. ## D2.6 - Integration Tests Through The Full HTTP Surface ```task id: ARTIFACT-STORE-WP-0002-T006 status: done priority: high state_hub_task_id: "f422696f-a206-4030-be05-c342f94e9efd" ``` Acceptance: - httpx-based test suite exercises every endpoint. - A scripted test ingests a 50-file package, finalises it, downloads every file, verifies digests, and tails events. - A property-based test fuzzes the upload session lifecycle. ## Success criteria - A producer can run the full ingest-and-retrieve flow against `make dev` with curl. - All blueprint endpoints in the v1 native surface are implemented. - The CLI gains `artifactstore push ` and `artifactstore manifest ` subcommands as thin clients over the HTTP API.