# Export AirGap Prep — PREP-EXPORT-AIRGAP-58-001 Status: **Ready for implementation** (2025-11-20) Owners: Exporter Service Guild · Notifications Guild Scope: Emit deterministic notifications/timeline events when portable evidence export (57-001) completes, without requiring enclave connectivity. ## Dependencies - Portable export artefact from 57-001: `export-portable-bundle-v1.tgz` (contains `portable-bundle-v1.tgz`). - Notification envelope decisions in Wave 150/140 (orchestrator/notifications), but this prep provides a concrete payload to unblock implementation. - EvidenceLocker bundle contracts: `docs/modules/evidence-locker/bundle-packaging.md`, `docs/airgap/portable-evidence.md`. ## Event contract (v1) - **Subject / type**: `export.airgap.ready.v1` - **Channel**: NATS topic `export.airgap.ready.v1` and mirrored to optional webhooks (`application/json`). Transport must be retryable with backoff and DLQ. - **Payload (canonical key order shown)**: ```json { "type": "export.airgap.ready.v1", "export_id": "...", "bundle_id": "...", "tenant_id": "...", "profile_id": "airgap-evidence", "portable_version": "v1", "root_hash": "sha256:...", "artifact_uri": "/v1/exports/airgap/evidence/{exportId}/download", "artifact_sha256": "...", "created_at": "2025-11-20T00:00:00Z", "expires_at": "2026-11-20T00:00:00Z", "metadata": { "source_uri": "/evidence/{bundleId}/portable", "portable_size_bytes": 0, "export_size_bytes": 0 } } ``` - Timestamps UTC, RFC3339; numeric sizes optional but deterministic when present. - `artifact_sha256` is the SHA-256 of `export-portable-bundle-v1.tgz`; `root_hash` is the Merkle root from `checksums.txt` (same as portable bundle root). - `expires_at` is optional; when omitted, receivers assume standard retention from EvidenceLocker policy. ## Determinism & delivery rules - Serialize JSON without whitespace changes that affect ordering; server must sort top-level keys alphabetically before emission. - When delivering via webhooks, include headers: `X-Stella-Event-Type`, `X-Stella-Signature` (HMAC-SHA256), `X-Stella-Sent-At` (UTC ISO-8601). - Retries: exponential backoff (1s, 2s, 4s, 8s, 16s) with maximum 5 attempts; failed deliveries go to DLQ topic `export.airgap.ready.dlq` with failure reason. ## API linkage - Notifications reference the download endpoint defined in 57-001: `GET /v1/exports/airgap/evidence/{exportId}/download`. - Optional timeline event mirror (`timeline.export.airgap.ready`) may be emitted once orchestrator envelope schema lands; payload mirrors the notification without headers. ## Acceptance criteria - Notification emits once per successful export; idempotent on replays (same `export_id` + hash). - Payload fields match the portable export artefact (hashes, URIs, versions) and require no further network calls for verification. - DLQ captures failed deliveries with reason and last response status. - Documentation of headers, payload, and retry guarantees is published for consuming guilds. ## Handoff - Implement emission in ExportCenter Worker when export job transitions to `Completed`. - Add webhook signature secret to configuration surface; default to disabled for air-gap unless explicitly allowed. - Link this document from Sprint 0162 Delivery Tracker entry P5.