Expand description
Compound artifacts: owned bytes plus an application-owned semantic report.
§Why this exists
A command that produces a file — an export, a bundle, a database dump — has to keep four things apart:
- the artifact bytes, which must survive byte-for-byte;
- metadata about where the bytes would like to land;
- application-owned facts about the operation (counts, warnings, partial-success notes);
- the success report, which can only be truthful once the concrete destination is known.
Output::Binary carries (1) and a filename hint,
but has nowhere to put (3) and renders nothing after the write. Artifact
carries all four: the application produces exact bytes and domain facts, and
the framework selects the destination, performs the final write, and only
then renders the report enriched with an ArtifactReceipt naming the
destination that actually completed.
§Ownership boundary
| Concern | Owner |
|---|---|
| Artifact bytes | Application |
| Suggested destination | Application (a suggestion) |
| Semantic report / warning taxonomy | Application |
| Destination selection | Framework |
| The final write and its failure | Framework |
| Receipt (completed destination) | Framework |
§Destination policy
The framework selects the destination deterministically, in this order:
- an explicit output-file override (
--output-file-path, when the app enabled that flag); - the artifact’s suggested destination, if the application opted in with
Artifact::suggest_destination; - stdout, if the application opted in with
Artifact::allow_stdout.
If none applies the run fails with
RunErrorKind::FinalWrite(OutputKind::Artifact)
rather than inventing a file or silently discarding the bytes. Every step
shares that single framework-owned failure path.
Note that a suggested destination on Output::Binary does not authorize a
write: only Artifact::suggest_destination does. The opt-in is the
difference between the two shapes.
§Report channel
Mixing the report into the artifact bytes would corrupt them, so the channel follows the destination:
| Artifact destination | Report goes to |
|---|---|
| File | stdout |
| Stdout | stderr (the diagnostic channel) |
§Example
use serde::Serialize;
use standout_dispatch::{Artifact, HandlerResult, Output};
#[derive(Serialize)]
struct ExportReport {
entries: usize,
warnings: Vec<String>,
}
fn export() -> HandlerResult<ExportReport> {
let bytes = b"id,title\n1,buy milk\n".to_vec();
Ok(Output::Artifact(
Artifact::new(bytes)
.suggest_destination("export.csv")
.with_report(ExportReport {
entries: 1,
warnings: vec!["1 entry had no due date".into()],
}),
))
}Structs§
- Artifact
- Owned artifact bytes with an optional destination suggestion and report.
- Artifact
Receipt - The framework’s record of a completed artifact write.
- Artifact
Run - A completed artifact run: the framework’s outcome for
Output::Artifact.
Enums§
- Artifact
Destination - A destination the framework can complete an artifact write to.