Skip to main content

Module artifact

Module artifact 

Source
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:

  1. the artifact bytes, which must survive byte-for-byte;
  2. metadata about where the bytes would like to land;
  3. application-owned facts about the operation (counts, warnings, partial-success notes);
  4. 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

ConcernOwner
Artifact bytesApplication
Suggested destinationApplication (a suggestion)
Semantic report / warning taxonomyApplication
Destination selectionFramework
The final write and its failureFramework
Receipt (completed destination)Framework

§Destination policy

The framework selects the destination deterministically, in this order:

  1. an explicit output-file override (--output-file-path, when the app enabled that flag);
  2. the artifact’s suggested destination, if the application opted in with Artifact::suggest_destination;
  3. 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 destinationReport goes to
Filestdout
Stdoutstderr (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.
ArtifactReceipt
The framework’s record of a completed artifact write.
ArtifactRun
A completed artifact run: the framework’s outcome for Output::Artifact.

Enums§

ArtifactDestination
A destination the framework can complete an artifact write to.