Every run leaves a directory containing the results, the description that produced them, and a record of the conditions. The point is that a result six months old can be understood without anyone's memory.
~/cosmos-artifacts/ofdm-ber-sb5-20260804T005824Z/
├── run.json the reproducibility record
├── description.yml verbatim copy of what ran
└── node1-2.sb5.cosmos-lab.org/ one directory per node
└── run/cosmos/fr3-ofdm/
├── ofdm_qpsk.csv the measurement
├── ofdm_qpsk.sigmf-meta SigMF metadata
└── noise_awgn.sigmf-meta
Node paths are preserved under a per-node directory, so collect: [/run/cosmos/fr3-ofdm] from two nodes does not collide.
run.json{
"experiment": {
"name": "ofdm-ber-sb5",
"api_version": "cosmos/v1",
"description_path": "/usr/share/cosmos-experiments/sdr/ofdm-ber-sb5.description.yml",
"description_sha256": "843644b8245f470ca8b4fa04c1e0c337d61d069766a4bc9d145381d4dc981037"
},
"parameters": { "sub": "qpsk", "amplitude": 0.06, "tx_gain": 89, "snr_db": "20:20:1" },
"collection": { "version": "0.1.0", "path": "/usr/share/ansible/collections/…" },
"controller": { "ansible_version": "2.16.3", "host": "localhost" },
"node_details": { "node1-1.sb5.cosmos-lab.org": { "cosmos_kind": "node", "cosmos_power": "POWERON",
"cosmos_subdomain": "sb5",
"cosmos_capabilities": { "…": "…" } } },
"finished_utc": "2026-08-04T02:30:37Z"
}
Each field answers a question that otherwise needs archaeology:
| Field | Answers |
|---|---|
description_sha256 |
Has the description changed since this ran? |
parameters |
What values were actually used — see the note below |
collection.version |
Which framework version produced this |
node_details |
Which nodes, and what they could do at the time |
finished_utc |
When, for correlating against other users' activity |
node_details carries each node's full capability set as reported at run time, not just its name. That is what lets you tell later whether a result came from a B210 or an X310 without trusting a lab notebook.
parametersrecords the values that were in force, not the description's defaults. This distinction is not academic: before it was fixed, a manifest recordedsub: bpsk, amplitude: 0.15, tx_gain: 70for a run that actually usedqpsk, 0.06, 89— every field wrong, because one of the two override forms bypassed the validator the record was built from. A reproducibility record that is confidently wrong is worse than none: it sends the next person to run a different experiment believing it is the same one.
cd ~/cosmos-artifacts/ofdm-ber-sb5-20260804T005824Z
sha256sum description.yml # compare against description_sha256
cosmos-run description.yml -e '{"cosmos_parameters": <the parameters block>}'
Two things the record cannot promise:
node_details tells you what was true, which is usually enough to explain a difference.dB above floor alongside the result.One row per sweep point. The columns that matter for interpretation:
| Column | Meaning |
|---|---|
snr_db |
what was asked for |
snr_eff_db |
what the link delivered — signal / (injected + link noise) |
errors, bits, ber |
the measurement |
perfect, packets |
frames with zero bit errors, and frames seen |
seconds |
dwell — a point at the cap did not reach its error target |
snr_db and snr_eff_db diverging is the single most useful diagnostic in the file. They agree while the injected noise dominates and separate once you ask for more SNR than the link has. Points where they have separated are measuring the link's own ceiling, not the value you asked for.
Recordings carry a .sigmf-meta sidecar with sample rate, centre frequency, hardware, and the capture time — so a recording remains interpretable when separated from the run that made it.
~/cosmos-artifacts/ — in your home directory, which on COSMOS consoles is one shared NFS filesystem. Results from an experiment run on console.sb5 are visible from console.grid, and there is no per-console copy to hunt for.
Last verified: 2026-08-04 on console.sb5.cosmos-lab.org.