Pinning
An artifact is addressed by path and identified by digest. The path says where to look; the digest says whether what you found is what was meant.
artifacts: - id: results path: analysis/results.json digest: algorithm: sha256 value: 9f635f9af47215608565dd489ff7e193937cc7cde3781b89346cf811611aafa7Artifacts are pinned, not immutable. Nothing stops a file from changing after it was
recorded — the digest is what makes the change visible. That is why broken_pin exists as a
distinct validity rather than an error: the comparison still runs, its result is reported, and
the report says the bytes are not the ones declared.
Addressing a value
Section titled “Addressing a value”Locators are typed, and each format is addressed the way that format is already addressed:
| kind | addresses | example |
|---|---|---|
tree |
JSON and YAML, by RFC 6901 JSON Pointer | /metrics/accuracy |
table |
CSV, TSV, by column and a key predicate | column: accuracy, where: {model: resnet} |
table_position |
a row number, reported with a warning | row: 37 |
sqlite |
a table, column and key predicate | |
array |
.npy / .npz, by name and index |
index: [0, 1] |
The pointer syntax is RFC 6901 — /metrics/accuracy — which JSONPath’s $.metrics.accuracy
resembles closely enough to be mistaken for. Array indices carry no leading zeros, so /xs/0
addresses a value and /xs/00 addresses nothing.
Exactly one scalar
Section titled “Exactly one scalar”Every adapter enforces the same invariant:
0 matches -> absent1 scalar -> resolved2 or more -> ambiguousa container -> not scalarNo adapter takes the first match, and none falls back to searching a file for the printed
number: a search finds that number wherever it appears, including places that have nothing to
do with the claim. A format with no adapter reports format_unsupported and stops.