Files
distributor/docs/roadmap/implementation.md

14 KiB

Catalog State And Workflow Implementation Roadmap

This is the active staged implementation plan for docs/roadmap/catalog.md. The feature roadmap defines the target state model and policy decisions; this document defines the implementation sequence for an LLM coding agent to follow stage by stage.

Future behavior must remain under docs/roadmap/ until implemented. Update current-behavior docs only in the stage that implements the corresponding behavior.

Current Baseline

distributor currently writes destination .distributor.json using single-owner schema version 2 or shared-root schema version 3. Destination behavior is selected through several low-level knobs: state.mode, reconciliation.mode, takeover.mode, and transfer.

The target behavior is a clean alpha break:

  • all newly written destination state uses schema version 4;
  • all destinations use state.mode: catalog internally;
  • user-facing destination behavior is selected by workflow: additive or workflow: replacement;
  • workflow defaults to additive;
  • legacy destination policy fields are rejected, not aliased;
  • legacy state schema versions 1, 2, and 3 are not migrated.

Implementation Principles

  • Keep the source manifest contract unchanged.
  • Keep backend adapters unaware of catalog and workflow policy.
  • Treat workflow as runtime config, not persisted state.
  • Keep unmanaged content protected after catalog state exists.
  • Preserve output created_at when a path changes owner; update only updated_at.
  • Prefer removing legacy state/config paths over compatibility shims.
  • Preserve current public APIs outside destination state/config unless the catalog roadmap explicitly changes them.

Active Implementation Stages

Stage 1: Destination Workflow Config Clean Break

Goal: replace low-level destination policy config with the user-facing workflow switch.

Implementation scope:

  • Add destination workflow config with accepted values additive and replacement.
  • Default omitted workflow to additive.
  • Remove or make unsupported the destination-level config fields state, reconciliation, takeover, and transfer.
  • Ensure configs containing those legacy fields fail clearly. Prefer strict YAML unknown-field failure by removing struct fields; add explicit validation only if clearer errors are needed without weakening strict decoding.
  • Preserve backend, publish, transform, path mapping, links, retention, and other non-policy destination fields.
  • Update example configs only when the implementation stage also updates current docs; otherwise keep this stage focused on config code and tests.

Tests:

  • go test ./internal/config
  • Omitted workflow defaults to additive.
  • workflow: additive and workflow: replacement validate.
  • Unknown workflow values fail.
  • Legacy state, reconciliation, takeover, and transfer fields fail.
  • Existing valid examples are updated or tests are adjusted in the same change if examples currently use legacy fields.

Completion criteria:

  • New configs express destination replacement/additive intent with one field.
  • No normal config path accepts legacy destination policy knobs.

Stage 2: Catalog State Schema Version 4

Goal: implement the schema version 4 catalog state model in internal/state.

Implementation scope:

  • Add catalog state types for top-level schema version 4, state.mode: catalog, and outputs.
  • Add compact per-output source identity with id, digest, and created.
  • Add catalog output records with required path, pipeline_id, destination_id, source, kind, sha256, size, created_at, and updated_at.
  • Add optional source_path, transform, and url, present only where allowed by the catalog roadmap.
  • Validate duplicate paths, invalid owner ids, invalid source identities, invalid output paths, invalid digests, negative sizes, invalid timestamps, invalid kind/transform combinations, and invalid URLs.
  • Marshal catalog state deterministically with the existing JSON formatting conventions.
  • Update ParseDocument so schema version 4 returns catalog state.
  • Treat schema versions lower than 4 as superseded legacy state for publish planning, not as readable/migrated active state. Keep enough detection to identify legacy state and avoid treating it as arbitrary invalid JSON.
  • Reject unsupported future schema versions.

Tests:

  • go test ./internal/state
  • Parse/validate/marshal valid catalog state.
  • Reject malformed catalog state and invalid output records.
  • Detect schema versions 1, 2, and 3 as superseded legacy state.
  • Reject future schema versions.
  • Prove no top-level owners, sources, workflow, source manifest, pipeline id, destination id, or published timestamp is accepted for catalog state.

Completion criteria:

  • State package has one canonical schema version 4 catalog contract for new writes.
  • Legacy state is detected but not migrated.

Stage 3: Catalog Publish Planning

Goal: plan publish actions against catalog state and destination workflow.

Implementation scope:

  • Replace publish request inputs that consume state/reconciliation/takeover and transfer policy with destination workflow.
  • Map workflow to catalog actions:
    • workflow: additive: upsert planned outputs and retain all other managed catalog outputs.
    • workflow: replacement: upsert planned outputs and delete catalog outputs owned by the current pipeline/destination that are omitted from the plan.
  • Planned paths that already exist as catalog-managed outputs may be overwritten and become owned by the current pipeline/destination.
  • Planned path collisions with storage content not recorded in catalog state fail as unmanaged content.
  • Matching planned outputs may skip writes when source identity and output digest already match, if that optimization can be implemented without changing externally visible results; otherwise writing idempotently is acceptable.
  • Existing schema < 4 state is superseded:
    • replacement workflow may plan a bounded destination-root clear before writing planned outputs;
    • additive workflow may plan overwrites for planned paths only and leave unplanned files unmanaged.
  • Invalid JSON or future schema state remains a conflict, not a superseded legacy state.
  • Preserve path mapping, publish policy, transforms, links, fixed-path selection, and output collision checks.

Tests:

  • go test ./internal/publish
  • Additive workflow publishes new catalog state.
  • Additive workflow overwrites an existing managed output and retains unrelated outputs.
  • Replacement workflow removes omitted outputs owned by the current pipeline/destination.
  • Replacement workflow preserves unrelated catalog outputs owned by other pipeline/destination pairs.
  • Managed output ownership moves to the current pipeline/destination when a planned path is overwritten.
  • created_at is preserved when an existing path changes owner; updated_at changes.
  • Unmanaged path collisions fail.
  • Legacy schema < 4 state follows the superseded-state rules above.
  • Invalid/future state fails.

Completion criteria:

  • Publish planning no longer depends on single-owner/shared-root comparison semantics.
  • Workflow behavior is fully driven by workflow.

Stage 4: Catalog Publish Execution

Goal: execute catalog publish plans and write schema version 4 state.

Implementation scope:

  • Write only schema version 4 catalog .distributor.json.
  • Implement additive execution as managed upsert of planned outputs plus catalog state update.
  • Implement replacement execution as managed upsert plus deletion of omitted current-owner catalog outputs.
  • For replacement over superseded legacy state, clear the bounded destination root before writing planned outputs and catalog state.
  • For additive over superseded legacy state, overwrite planned paths and write a catalog containing only planned outputs; leave unplanned files unmanaged.
  • Preserve cleanup behavior on failed writes:
    • additive cleanup removes outputs newly created by the failed attempt where practical;
    • replacement cleanup follows existing managed-replacement safety where practical;
    • state is written only after selected outputs are written.
  • Preserve link metadata, generated output digests, source output digests, content type behavior, and backend-safe writes.

Tests:

  • go test ./internal/publish ./internal/app
  • Additive execution writes planned outputs, overwrites managed planned paths, retains unrelated managed outputs, and writes catalog state.
  • Replacement execution deletes omitted current-owner outputs and preserves unrelated owner outputs.
  • Superseded legacy replacement clears bounded destination root only.
  • Superseded legacy additive leaves unplanned files on disk but out of catalog state.
  • Failed writes do not leave misleading catalog state.
  • Local, fake-backed SSH, and fake-backed S3 app paths exercise the same publish behavior.

Completion criteria:

  • Successful run writes only v4 catalog state.
  • Destination outputs match additive/replacement workflow semantics.

Stage 5: Run Reporting, Notifications, And CLI Surface

Goal: update user-visible run behavior to describe workflow/catalog actions instead of legacy replacement/takeover actions.

Implementation scope:

  • Replace legacy action labels tied to state/reconciliation/takeover/transfer with these stable workflow-oriented labels:
    • publish_new
    • upsert_additive
    • replace_catalog
    • skip_same
    • force_replace
    • fail_unmanaged
    • fail_conflict
  • Ensure text and JSON run summaries include workflow-relevant counters.
  • Include workflow in run action records where useful.
  • Update fixed-path dry-run warnings to describe additive upsert or replacement clearly.
  • Ensure notifications use the new action labels.
  • Remove reporting assumptions that depend on replace_older, replace_newer, replace_conflict, or replace_takeover.

Tests:

  • go test ./internal/app ./internal/cli
  • Text dry-run output distinguishes additive from replacement workflow.
  • JSON output includes workflow and stable action labels.
  • Summary counters are deterministic.
  • Notifications fire for additive and replacement writes.
  • Existing CLI commands still parse and execute with the new config shape.

Completion criteria:

  • Operators can understand from dry-run output whether a destination will upsert or replace managed catalog outputs.

Stage 6: Catalog Prune And Reconcile-State

Goal: update maintenance commands to operate on catalog state with the agreed selector model.

Implementation scope:

  • Prune:
    • selected --pipeline and --destination prune only outputs currently owned by that pipeline/destination;
    • no --all-owners prune mode in the initial catalog implementation;
    • do not add --source-id, --path-prefix, or --kind selectors.
  • Reconcile-state:
    • selected --pipeline and --destination repair only outputs currently owned by that pipeline/destination;
    • --all-owners repairs all catalog outputs;
    • unmanaged reporting compares storage entries to all catalog output paths, not just selected owner paths.
  • Rewrite repaired/pruned state as schema version 4.
  • Remove legacy single-owner/shared-root maintenance branches.

Tests:

  • go test ./internal/state ./internal/app ./internal/cli
  • Prune selects only current-owner catalog outputs.
  • Prune deletes selected outputs and removes their catalog records.
  • Reconcile-state selected owner removes only missing outputs for that owner.
  • reconcile-state --all-owners removes missing outputs for all owners.
  • Unmanaged reporting excludes all catalog-managed paths and reports unrecorded storage entries.
  • JSON/text output remains stable and clear.

Completion criteria:

  • Maintenance commands operate only on catalog state and respect the locked selector rules.

Stage 7: Clean Break Removal And Documentation

Goal: remove legacy state/config behavior and document the implemented catalog workflow model.

Implementation scope:

  • Remove dead code for writing schema version 2 single-owner and schema version 3 shared-root state.
  • Remove legacy config structs/constants/defaults/validation for destination state, reconciliation, takeover, and transfer where no longer used.
  • Remove or rewrite tests that only assert legacy state/config behavior.
  • Update current-behavior docs:
    • docs/config.md
    • docs/cli.md
    • docs/operations.md
    • docs/troubleshooting.md
    • docs/integrations/destination-state.md
    • relevant docs/internal/ docs
    • docs/policy/architecture.md
    • docs/policy/development.md
  • Update examples to use workflow and remove legacy fields.
  • Keep roadmap-only material out of current docs.
  • Once implemented and documented, remove or rewrite docs/roadmap/catalog.md so completed behavior is not described only as future work.

Tests and checks:

  • go test ./...
  • rg -n "state:|reconciliation:|takeover:|transfer:" examples docs --glob '!docs/roadmap/**'
  • rg -n 'single_owner|shared_root|schema version 2|schema version 3' docs internal
  • rg -n "workflow: additive|workflow: replacement|schema_version.*4" docs examples

Completion criteria:

  • Current docs and examples describe the catalog workflow model.
  • Legacy destination policy fields and legacy write paths are gone.
  • Full test suite passes.

Refactors To Avoid

  • Do not add top-level owners or sources catalogs.
  • Do not persist workflow in .distributor.json.
  • Do not keep deprecated config aliases for legacy destination policy fields.
  • Do not implement state migration from schema versions 1, 2, or 3.
  • Do not add catalog-specific prune/reconcile selectors beyond the agreed initial ownership scope.
  • Do not move catalog policy into storage adapters.

Open Questions

No open questions are known. The catalog roadmap locks the state shape, workflow values, default workflow, clean-break policy, legacy-state behavior, output field selection, created_at preservation, and maintenance command scope.