2026-05-23 04:51:16 +00:00
|
|
|
# Stage: publish
|
2026-05-18 22:03:59 -05:00
|
|
|
|
|
|
|
|
## Purpose
|
2026-08-09 21:50:21 +00:00
|
|
|
|
2026-05-23 12:57:59 +00:00
|
|
|
Upload run/session outputs to object storage and atomically advance remote current state.
|
|
|
|
|
|
|
|
|
|
## Inputs
|
2026-08-09 21:50:21 +00:00
|
|
|
|
|
|
|
|
- successful preceding stages from the [canonical stage set](overview.md#pipeline-stage-set)
|
2026-09-03 04:22:19 +00:00
|
|
|
- declared run-local diagnostic files
|
2026-08-09 21:50:21 +00:00
|
|
|
- resolved publish output rules
|
2026-09-05 13:04:08 +00:00
|
|
|
- independent per-source remote lock objects read at planning start
|
|
|
|
|
- the validated prior current commit when an initially locked source may carry
|
2026-08-09 21:50:21 +00:00
|
|
|
- durable previous-session cache files when present
|
2026-05-23 12:57:59 +00:00
|
|
|
|
|
|
|
|
## Outputs
|
2026-08-09 21:50:21 +00:00
|
|
|
|
2026-09-03 04:22:19 +00:00
|
|
|
- uploaded session manifest, declared run-local diagnostics, and selected
|
|
|
|
|
publish outputs;
|
2026-08-09 21:50:21 +00:00
|
|
|
- uploaded durable previous-session cache files when present;
|
2026-08-10 20:05:24 +00:00
|
|
|
- immutable run-scoped commit manifest; and
|
|
|
|
|
- current commit pointer, written last.
|
2026-08-09 21:50:21 +00:00
|
|
|
|
|
|
|
|
Exact remote placement and the operator workflow belong in
|
|
|
|
|
[Operations](../operations.md#publish-workflow).
|
2026-05-23 12:57:59 +00:00
|
|
|
|
|
|
|
|
## Key Behavior
|
2026-08-09 21:50:21 +00:00
|
|
|
|
2026-09-05 12:43:27 +00:00
|
|
|
`publish.go` retains the transaction-owning `Run` path. Source discovery,
|
|
|
|
|
manifest-derived archive metadata, confined opening, and checksum validation
|
|
|
|
|
live in `publish_sources.go`; artifact-catalog matching, selection, required
|
|
|
|
|
and optional rules, destination resolution, and collision inputs live in
|
2026-09-05 12:48:12 +00:00
|
|
|
`publish_outputs.go`. Copying, hashing, immutable upload, reuse checks, and
|
|
|
|
|
remote verification live in `publish_transfer.go`; committed-manifest,
|
|
|
|
|
immutable-commit, and current-pointer encoding and writes live in
|
2026-09-05 12:52:55 +00:00
|
|
|
`publish_commit.go`. `publish_output_plan.go` owns the deterministic, I/O-free
|
|
|
|
|
five-outcome model and its secret-free metadata projection.
|
2026-09-05 12:43:27 +00:00
|
|
|
|
2026-08-10 23:18:29 +00:00
|
|
|
- when publishing or run upload is disabled, completes successfully with no
|
|
|
|
|
outputs and records explanatory metadata. This is not an explicit self-skip:
|
2026-09-03 04:22:19 +00:00
|
|
|
the session manifest records success. Enablement and upload policy are
|
|
|
|
|
fingerprinted, so changing either automatically makes the prior result
|
|
|
|
|
non-resumable.
|
2026-05-23 12:57:59 +00:00
|
|
|
- validates prerequisite stage success and object-store availability.
|
2026-09-03 04:00:25 +00:00
|
|
|
- derives a deterministic run-archive allowlist from the session manifest's
|
|
|
|
|
declared current-run outputs, logs, and generated configurations. References
|
|
|
|
|
outside the current run root, including canonical session files and prior-run
|
2026-09-03 04:22:19 +00:00
|
|
|
diagnostics, are not archive candidates. No distinguished diagnostic file is
|
|
|
|
|
read or uploaded.
|
2026-08-10 19:16:18 +00:00
|
|
|
- opens each archive candidate beneath its archive root without following
|
|
|
|
|
symlinked ancestors or leaf entries, verifies that it is a regular file and
|
|
|
|
|
checks a declared checksum when present, then streams the opened descriptor.
|
|
|
|
|
- derives the durable previous-cache archive from its validated manifest using
|
|
|
|
|
the same confinement and regular-file checks.
|
2026-08-29 18:46:40 +00:00
|
|
|
- resolves publish output sources through runtime artifact catalog and
|
|
|
|
|
manifest-aware resolution. Configured Scriptorium outputs are publishable
|
|
|
|
|
only from validated `current` per-artifact analyze evidence; an incidental
|
2026-09-02 14:09:32 +00:00
|
|
|
canonical file, aggregate output, stale/failed/unselected record, or
|
|
|
|
|
mismatched path, size, or checksum remains unavailable. Built-in and
|
|
|
|
|
extraction sources likewise require their own current manifest evidence.
|
2026-08-10 02:10:37 +00:00
|
|
|
- publishes extraction lanes only through explicit configured output rules;
|
|
|
|
|
neither run-local nor durable Notarius bundles are scanned or uploaded wholesale.
|
2026-05-23 12:57:59 +00:00
|
|
|
- selected artifact filter applies to configured artifact sources only.
|
2026-09-05 13:04:08 +00:00
|
|
|
- plans every configured output into exactly one source-sorted outcome:
|
|
|
|
|
`published`, `carried_locked`, `locked_unpublished`, `optional_missing`, or
|
|
|
|
|
`unselected`.
|
|
|
|
|
- an initially locked selected output carries its exact prior
|
|
|
|
|
`published_output` declaration when one exists. The declaration may point to
|
|
|
|
|
an earlier run in the same session and retains its source, key, checksum,
|
|
|
|
|
size, and generation; the bytes are not copied.
|
|
|
|
|
- verifies a carried object's exact key, size, and generation through object
|
|
|
|
|
metadata without downloading or opening the local output source.
|
|
|
|
|
- an initially locked source with no prior declaration remains absent even
|
|
|
|
|
when the output rule is required. Optional missing unlocked outputs remain
|
|
|
|
|
absent; required missing unlocked outputs fail.
|
2026-08-10 20:05:24 +00:00
|
|
|
- creates one complete immutable source-to-destination mapping before upload;
|
|
|
|
|
- uploads and verifies every declared immutable object and the commit manifest;
|
2026-09-05 13:04:08 +00:00
|
|
|
- writes the immutable commit from the combined new and exact carried
|
|
|
|
|
declarations.
|
|
|
|
|
- rereads every initially unlocked participating source after the immutable
|
|
|
|
|
commit. A newly present lock aborts selection, leaving the uploaded immutable
|
|
|
|
|
attempt unselected. Removing an initial lock may conservatively produce one
|
|
|
|
|
carry because the initial snapshot controls the plan.
|
|
|
|
|
- updates `current/commit-pointer.json` exactly once, last, and writes no other
|
|
|
|
|
mutable publication control record.
|
2026-05-23 12:57:59 +00:00
|
|
|
|
|
|
|
|
## Metadata Signals
|
2026-08-09 21:50:21 +00:00
|
|
|
|
2026-05-23 12:57:59 +00:00
|
|
|
Includes counts/lists for:
|
|
|
|
|
- run uploads
|
|
|
|
|
- published output uploads
|
|
|
|
|
- previous uploads
|
2026-09-05 13:04:08 +00:00
|
|
|
- one `publish_output_outcomes` collection containing all five output states,
|
|
|
|
|
exact declared keys, and key-derived origin runs where applicable
|
2026-08-10 20:05:24 +00:00
|
|
|
- remote commit and current-pointer key paths
|
2026-08-10 20:29:00 +00:00
|
|
|
- the run identifier selected by the commit
|
2026-05-23 12:57:59 +00:00
|
|
|
|
|
|
|
|
## Invariants
|
2026-08-09 21:50:21 +00:00
|
|
|
|
2026-08-10 20:05:24 +00:00
|
|
|
- `current/commit-pointer.json` is the remote commit marker and is written last.
|
|
|
|
|
- run files, selected outputs, previous-cache files, and the committed session
|
|
|
|
|
manifest are all declared by an immutable commit under the run prefix.
|
2026-08-10 19:16:18 +00:00
|
|
|
- run and previous uploads contain only manifest-declared regular files opened
|
|
|
|
|
from verified descriptors; symlinks, special files, replacement races, and
|
|
|
|
|
undeclared entries are rejected or ignored before uploads begin.
|
|
|
|
|
- run-local diagnostics, including Notarius receipt and stderr files, are
|
2026-09-03 04:00:25 +00:00
|
|
|
archived only when recorded by the session manifest. A run with no declared
|
|
|
|
|
current-run diagnostics legitimately uploads none.
|
2026-09-05 13:04:08 +00:00
|
|
|
- independent publish locks are not overridden by `--force`; every initially
|
|
|
|
|
unlocked relevant source is reread immediately before current-state
|
|
|
|
|
selection.
|
2026-09-05 15:27:08 +00:00
|
|
|
- successful uploaded publication records the exact run ID, remote commit key,
|
|
|
|
|
and current-pointer key consumed by the later cleanup stage.
|
2026-08-09 21:50:21 +00:00
|
|
|
|
2026-08-30 13:14:33 +00:00
|
|
|
## Resume Semantics
|
|
|
|
|
|
|
|
|
|
The versioned semantic fingerprint covers enabled behavior, run-upload policy,
|
2026-09-05 13:17:46 +00:00
|
|
|
normalized source/destination/required output rules, and the remote backend,
|
|
|
|
|
bucket, region, endpoint, and root-prefix identity. Rule ordering is
|
|
|
|
|
canonicalized. Credential
|
2026-09-05 13:04:08 +00:00
|
|
|
environment names, path-addressing transport mode, local workspace placement,
|
|
|
|
|
and run identifiers are excluded. Independent remote locks remain mutable state
|
|
|
|
|
and are read directly by publish at planning and commit boundaries; semantic
|
|
|
|
|
evidence does not replace those safety checks.
|
2026-08-30 13:14:33 +00:00
|
|
|
|
2026-09-05 15:27:08 +00:00
|
|
|
The commit boundary and cleanup authorization are normative architecture invariants; see
|
2026-08-09 21:50:21 +00:00
|
|
|
[Architecture](../policy/architecture.md#publish-commit-boundary).
|
|
|
|
|
|
2026-09-05 15:27:08 +00:00
|
|
|
Publish never deletes local state. The standalone `publish` command selects
|
|
|
|
|
only this stage; a full run selects notify and cleanup afterward.
|
|
|
|
|
|
2026-08-09 21:50:21 +00:00
|
|
|
## Related Contracts And Tests
|
|
|
|
|
|
2026-09-05 13:04:08 +00:00
|
|
|
- [Configuration](../config.md#publish-configuration-summary) owns output
|
|
|
|
|
rules.
|
2026-08-09 21:50:21 +00:00
|
|
|
- [Operations](../operations.md#publish-locks) owns remote lock lifecycle and
|
|
|
|
|
physical remote state.
|
|
|
|
|
- [Artifact Internals](artifacts.md) explains source resolution and current-state
|
|
|
|
|
helpers.
|
|
|
|
|
- Implementation and tests: `internal/stage/publish.go`,
|
2026-09-05 12:43:27 +00:00
|
|
|
`internal/stage/publish_sources.go`, `internal/stage/publish_outputs.go`,
|
2026-09-05 12:52:55 +00:00
|
|
|
`internal/stage/publish_output_plan.go`,
|
2026-09-05 12:48:12 +00:00
|
|
|
`internal/stage/publish_transfer.go`, `internal/stage/publish_commit.go`,
|
2026-08-30 13:14:33 +00:00
|
|
|
`internal/stage/publish_test.go`,
|
|
|
|
|
`internal/stage/semantic_contracts_delivery.go`,
|
|
|
|
|
`internal/app/operator_helpers_test.go`, and
|
2026-09-05 15:27:08 +00:00
|
|
|
`internal/app/cleanup_orchestration_test.go`
|