# Destination State Contract Audience: operators, integrators, and maintainers who inspect or reason about destination `.distributor.json` files. Each managed destination bundle path contains `.distributor.json`. This file is the destination sentinel and state record used for comparison, skip, replacement, and recovery decisions. ## State Schema Current schema version: `1`. ```json { "schema_version": 1, "distributor_version": "dev", "pipeline_id": "reports", "destination_id": "archive", "published_at": "2026-06-04T12:00:00Z", "source": { "manifest": { "schema_version": 1, "id": "reports.example.2026-06-04", "digest": "sha256:...", "created": "2026-06-04T11:55:00Z", "files": [ {"path": "report.md", "sha256": "sha256:...", "size": 1234} ] } }, "links": { "primary_url": "https://reports.example.com/archive/report.html" }, "outputs": [ { "path": "report.html", "kind": "generated", "source_path": "report.md", "transform": "markdown_to_html", "url": "https://reports.example.com/archive/report.html", "sha256": "sha256:...", "size": 2345 } ] } ``` Required fields: - `schema_version`: must be `1`. - `pipeline_id`: configured pipeline id that wrote the state. - `destination_id`: configured destination id that wrote the state. - `published_at`: RFC3339 publication timestamp. - `source.manifest`: embedded source bundle manifest. - `outputs`: output records array; empty is allowed, but the field is required. Optional fields: - `distributor_version`: application version string when available. - `links.primary_url`: absolute HTTP or HTTPS URL selected by destination link policy. ## Output Records Each output record has: - `path`: destination-relative output path. - `kind`: `source` or `generated`. - `source_path`: source manifest path used for the output. - `transform`: required for `generated` outputs; omitted for copied source outputs. - `url`: optional absolute HTTP or HTTPS URL for the output. - `sha256`: lowercase `sha256:<64 hex>` digest of the output bytes. - `size`: output byte size, zero or greater. Output paths must be unique and use clean relative slash-separated path rules. ## Comparison Semantics `distributor` compares the current source manifest to destination state before writing: - No state and no content: publish new outputs. - No state and existing content: treat the destination as unmanaged. - Matching embedded source manifest: skip. - Same source id with older `created`: replace if policy allows. - Same source id with newer `created`: skip by default. - Same source id and same `created` with different digest: conflict. - Different source id, pipeline id, or destination id: conflict. - Invalid state JSON or invalid state fields: conflict. Normal replacement deletes only managed output paths recorded in `outputs` plus `.distributor.json`. Forced replacement deletes the bounded destination bundle path. ## Boundaries Destination state is internal managed state written by `distributor`. Operators may inspect it during recovery, but normal workflows should not edit it by hand. Source `manifest.json` is not copied as destination state. ## Tests Before changing this contract, inspect and run: ```sh go test ./internal/state ./internal/publish ```