# Ledger Packs Snapshot Prep — PREP-LEDGER-PACKS-42-001 Status: Prep complete (2025-11-20) Owners: Findings Ledger Guild · Mirror Creator Guild Scope: Snapshot/time-travel contract for packs simulation and offline CLI execution (PREP-LEDGER-PACKS-42-001). ## Goals - Provide deterministic, tenant-scoped snapshots that let pack runners/CLI replay ledger state offline. - Allow “time-travel” queries (choose exact ledger sequence/cycle) to debug policy outcomes. - Reuse existing export shapes where possible and avoid redundant DB projections. ## Surfaces - `GET /v1/ledger/packs/snapshots` - Headers: `X-Stella-Tenant` (required), bearer scope `ledger.packs.read`. - Query: `atSequence` (long, optional), `atCycleHash` (string, optional), `sinceSequence` / `untilSequence` (long, optional), `page_size` (default 100, max 1000), `page_token`. - Returns: list of available snapshot descriptors (JSON or NDJSON) sorted by `sequence ASC`. - `GET /v1/ledger/packs/snapshots/{snapshotId}/download` - Streams a gzip tarball containing the snapshot bundle (see layout). - Supports `Accept: application/vnd.stella.pack-snapshot+tar` (default) or `application/x-ndjson` for manifest-only dry-run (no payload files) when `Prefer: return=representation` is absent. ## Snapshot descriptor fields - `snapshot_id` (uuid, stable) - `tenant` - `base_sequence` (long) — earliest ledger event included - `upper_sequence` (long) — last ledger event included (inclusive) - `cycle_hash` (string) — Merkle cycle hash at `upper_sequence` - `policy_version`, `projector_version`, `generator_version` - `created_at` (ISO-8601 UTC) - `approx_uncompressed_size_bytes` - `content` summary: counts for `findings`, `vex`, `advisories`, `sboms` ## Bundle layout (tar.gz) - `manifest.json`: descriptor above plus SHA-256 digests and lengths for each payload file. - `findings.ndjson`: canonical finding shape matching `/ledger/export/findings`. - `vex.ndjson`, `advisories.ndjson`, `sboms.ndjson`: same shapes/filters as export endpoints. - `indexes/`: optional bloom/filter helpers for fast CLI lookup (`component_purl`, `advisory_id`, `risk_profile_version`). - `provenance.json`: DSSE envelope with bundle hash, generator inputs (seed, source commit, policy version). ## Determinism and filters - Snapshot is deterministic for a given `(tenant, base_sequence, upper_sequence, cycle_hash, policy_version)`. - Page tokens: base64url JSON `{ "last": { "upper_sequence": long, "snapshot_id": uuid }, "filters_hash": sha256 }`. - When `atCycleHash` is provided, server resolves the closest <=matching cycle and emits one descriptor; otherwise uses `untilSequence` or latest committed. - No wall-clock dependence; `created_at` reflects generator runtime but is stored once and signed in provenance. ## Validation rules - Reject overwrite if snapshot with identical `(tenant, upper_sequence, cycle_hash)` already published (idempotent response with existing `snapshot_id`). - Reject if requested window crosses projector gap (missing sequences) with error `409` and `X-Stella-Gap-From/To`. - Enforce `page_size` consistency across tokens; 400 on mismatch. ## Artefact location - This prep: `docs/modules/findings-ledger/prep/2025-11-20-ledger-packs-42-001-prep.md`. - Bundle schema is derived from export shapes in `docs/modules/findings-ledger/export-http-surface.md`; SDK/OAS plumbing to be added in LEDGER-PACKS-42-001 implementation.