Reading Reports#
This page describes where a run writes its output, how to read outcomes and exit codes, and the benchmark receipt written into each source USD asset.
Output Layout#
By default, a run writes output under _testing/ at the project root that
simready-benchmark is configured to use, typically your SimReady Foundation clone.
You can override the output directory in engine configuration.
Top-level reports and artifacts under _testing/ belong to the run. The
benchmark receipt is written into each source USD asset and travels with
that asset after the run output is deleted or archived. The subsections below
cover run output first, then the asset receipt.
Run Output Under _testing/#
Every run produces the same top-level folder layout. The following subsections describe how that layout is populated for different command patterns.
_testing/
├── index.html the HTML report
├── test_results.json pass/fail summary per test
├── report/
│ └── test_results_index.json grouped index into per-asset artifacts
├── batch_jobs/
│ └── local_test_<platform>.json job plan for the current run
└── job_outputs/
└── <runner>/<job_id>/<asset_id>/ per-asset artifacts (XML, screenshots, logs)
Open index.html to view per-test outcomes, screenshots, and stamping status from
the run. Folder names under job_outputs/ (runner prefix, job ID, asset ID) depend
on runner configuration and how tests are batched. Refer to
report/test_results_index.json for the paths used in the current report.
Single Asset, Single Command#
This is the default case: one asset on one simready-benchmark command.
simready-benchmark --assets path/to/asset.usd
One pipeline run writes one job plan, one set of reports, and one artifact folder.
index.html and test_results.json describe that asset only. Artifacts land
under a single folder such as job_outputs/<runner_name>/job_00001/asset_0000/.
Multiple Assets, Single Command#
When you specify more than one asset on a single simready-benchmark command, one pipeline
run writes one job plan and one set of reports. The plan in
batch_jobs/local_test_<platform>.json schedules every asset on the command line.
After tests execute, index.html and test_results.json aggregate pass/fail outcomes
for all of them. Under job_outputs/, each asset gets its own folder, typically as siblings under
the same job:
job_outputs/
└── <runner_name>/
└── job_00001/
├── asset_0000/ first asset (test_results.xml, logs, …)
└── asset_0001/ second asset
The exact IDs can differ; treat the index JSON as the source of truth for paths.
Multiple Assets, Multiple Commands#
Each simready-benchmark invocation runs the full pipeline again. The example below uses
two successive commands with one asset each:
simready-benchmark --assets path/to/apple.usd
simready-benchmark --assets path/to/orange.usd
Each run writes the same batch_jobs/local_test_<platform>.json filename, so
index.html and test_results.json reflect the latest command’s asset in the
typical case. The keep_outputs flag controls what is cleaned under _testing/
between runs.
If you specify
keep_outputs,simready-benchmarkkeeps prior files underbatch_jobs/andreport/instead of clearing those folders. Each run writes a new job plan, refreshesindex.htmlandtest_results.json, and replaces artifacts in the current runner’s folder underjob_outputs/. The latest pass/fail results are in those top-level reports; extra files from earlier runs might remain on disk:_testing/ ├── index.html latest asset (orange) ├── test_results.json ├── report/ │ ├── test_results_index_prior.json existing report from an earlier session │ ├── test_results_index_apple.json from the apple command │ └── test_results_index.json from the orange command (latest) ├── batch_jobs/ │ ├── local_test_<platform>.json overwritten each run (same platform) │ └── local_test_<other_platform>.json other platform (unchanged by this run) └── job_outputs/ └── <runner_name>/ └── job_00001/ └── asset_0000/ same path each run; contents replacedUse
index.htmlortest_results.jsonfor the latest command. Older files underreport/orbatch_jobs/might not match those reports.If you do not specify
keep_outputs(the default), the plan stage clearsbatch_jobs/before writing a new job file. The run stage clears all ofjob_outputs/. The report stage regeneratesindex.htmlandtest_results.jsonand removes and recreatesreport/. Only the latest command’s plan and artifacts remain:_testing/ ├── index.html latest asset (orange) ├── test_results.json ├── report/ │ └── test_results_index.json ├── batch_jobs/ │ └── local_test_<platform>.json └── job_outputs/ └── <runner_name>/ └── job_00001/ └── asset_0000/index.htmlandtest_results.jsonreflect the latest command only. No output from earlier commands remains under_testing/.
To reset _testing/ completely (for example, when using keep_outputs), remove
the folder before the next run.
Asset Plan, Artifacts, and Reports#
When troubleshooting or reporting a problem, trace one asset across the job plan, its artifact folder, and the JSON report. The plan assigns paths, tests write XML and other files into those folders, and the report stage reads the XML and fills in pass/fail fields.
Plan (batch_jobs/local_test_<platform>.json): each job lists its assets and
output folder names. A multi-asset run uses sibling folders such as asset_0000 and
asset_0001:
"job_output_dir": "<runner_name>/job_00001",
"assets": [
{
"asset": "assets/apple.usd",
"asset_output_dir": "asset_0000",
"matched_features": [{ "id": "FET001", "version": "1.0" }]
},
{
"asset": "assets/orange.usd",
"asset_output_dir": "asset_0001",
"matched_features": [{ "id": "FET001", "version": "1.0" }]
}
]
Artifacts (job_outputs/<runner_name>/job_00001/asset_0000/): the test run
writes results here. The report generator looks for test_results.xml or
report.xml; other files (screenshots, videos, logs) depend on the test:
job_outputs/<runner_name>/job_00001/asset_0000/
├── test_results.xml pass/fail source for the report
└── … other artifacts the test produced
Report (test_results.json): one object per asset path, with a tests array
built from the XML in each artifact folder. The output_folder field points back
to that folder:
{
"asset_path": "assets/apple.usd",
"tests": [
{
"test_name": "FET001 Visual Pivot",
"test_passed": true,
"output_folder": "job_outputs/<runner_name>/job_00001/asset_0000",
"features": [{ "id": "FET001", "version": "1.0" }]
}
]
}
Refer to Verify a Clean Pass for how to read test_passed.
Runtime Stamp on the Asset#
The durable output of a run is also written into each source USD asset. Unlike
_testing/, that receipt travels with the asset. Refer to
The Runtime Stamp.
Outcomes and Exit Codes#
Each test ends in a pass or a fail outcome, aggregated in both reports. The
simready-benchmark command returns an exit code that a pipeline can gate on. For
pass-or-fail gating, treat only exit code 0 as success.
Exit Code |
Meaning |
|---|---|
|
Clean pass. |
|
Failures or a runtime error. |
|
Command-line usage error. |
|
Missing plan or results. |
|
Setup not ready. |
|
Interrupted with Ctrl-C. |
Verify a Clean Pass#
A benchmark run passes when every planned test for the asset records
test_passed: true. A test with Kit warnings can still pass; only explicit
failures or missing results count against the run. Use the checks below in
order. For CI, the exit code alone is enough. For a local run, open the HTML
report to inspect failures, screenshots, and warnings.
Check the command exit code. After
simready-benchmarkfinishes, confirm the shell reports exit code0. Any other code means the run did not pass cleanly. Refer to Outcomes and Exit Codes for the full table.simready-benchmark --assets path/to/asset.usd echo Exit code: $?
On Windows PowerShell, use
$LASTEXITCODEinstead of$?.Review the HTML report. Open
_testing/index.html. One HTML report covers every asset in the run. When the run lists more assets than fit on one page, open the additional pages under_testing/report/(for example,assets_page_2.html). On each page, every asset appears as its own section with an entry for each test planned for that asset. At the top, the summary cards show counts for the run: Passed, Failed, and Not Tested. A clean pass has Failed and Not Tested both at0. A feature that did not pass static validation appears in the amber validation failed state and runs no benchmark. A validation-failed feature does not by itself turn its asset red, so an asset can still show a passing verdict while one of its features is amber. Confirm that no feature shows the validation-failed state. Kit warning indicators can appear without failing the run. Scroll to your asset and confirm every listed test shows a pass outcome. Open a failing test to read the error message, screenshots, and engine logs.Confirm in JSON (optional). For automation or scripting, read
_testing/test_results.json. Each asset has atestsarray with one entry for every test in the plan for that asset. Every entry must have"test_passed": true. A planned test that produced no XML still appears as an entry with"test_passed": false._testing/report/test_results_index.jsongroups the same tests with paths to per-test artifact folders (XML results, videos, logs).Confirm the runtime stamp (optional). If you did not specify
--no-stamp, the stamp stage writes a receipt into the source USD asset before the command exits. Open the asset in a USD viewer and inspectcustomLayerData["SimReady_Metadata"]["runtime_testing"]. For each feature exercised in the run, find its entry under the run’s timestamp intested_featuresand confirm"passed": true. Refer to Interpreting Multiple Timestamps when earlier runs left older entries in the file. If stamping failed but the tests themselves passed, the reports and exit code still reflect the test outcome; fix the stamp problem and re-run with stamping enabled before relying on the receipt downstream.
The Runtime Stamp#
The benchmark receipt is the durable result of a completed
simready-benchmark run. In the stamp stage, after tests execute, the stamper builds
it from _testing/test_results.json and writes it into each tested asset’s
customLayerData (unless you specify --no-stamp). Downstream pipelines read
this metadata to confirm which features passed benchmarking without
re-running the engine.
The receipt is stored under
customLayerData["SimReady_Metadata"]["runtime_testing"]. It is distinct from
the schema-validation stamp written by simready-validate under
SimReady_Metadata.validation (refer to the SimReady Validation Workflow).
Structure#
The receipt is grouped by feature under tested_features. Each successful stamp
run adds one ISO timestamp key (taken from test_results.json metadata). Under
that key, each feature entry includes:
Field |
Meaning |
|---|---|
|
|
|
Feature version recorded for this run (highest semver seen among its tests) |
|
Map of test definition files to per-test |
Example (one feature, one run):
"runtime_testing" = {
"tested_features" = {
"2026-06-10T14:30:00.123456" = {
"FET001" = {
"passed" = true
"version" = "1.0"
"tests" = {
"fet001_visual.toml" = { "passed" = true }
}
}
}
}
}
Re-running benchmarks on a later date appends a new timestamp entry. Earlier entries remain, so the asset preserves a history of benchmark outcomes.
Interpreting Multiple Timestamps#
Each stamp run adds one timestamp key. Older keys are not removed. To determine the current benchmark status for a feature, use the newest timestamp that includes that feature, not an older entry from a previous run.
List the timestamp keys under
tested_features.Sort them chronologically (ISO-8601 strings sort in run order when the format is consistent).
From newest to oldest, find the first timestamp that contains the feature ID.
Read that feature entry’s
passedflag. A feature passes only whenpassedistrueand every test listed under it passed.
Examples: The scenarios below apply the rule above.
Pass, then fail. Run 1 stamps FET001 with passed: true. After an asset
change, run 2 stamps FET001 with passed: false. The current status for
FET001 is failed. The earlier pass remains in the file as history but does
not override the newer result.
Pass, then pass again. The newest entry wins; current status is passed.
Fail, then pass. Run 1 stamps FET001 with passed: false. After a fix,
run 2 stamps FET001 with passed: true. The current status for FET001 is
passed. The earlier failure remains in the file as history but does not
override the newer result.
Fail, then fail again. The newest entry wins; current status is failed.
Feature not in the latest run. Each timestamp lists only the features exercised in that run. If the newest stamp run tested a different feature set, a feature omitted from that run keeps the status recorded under its own most recent timestamp until it is tested again.
Example with two runs on the same feature:
"tested_features" = {
"2026-06-01T10:00:00" = {
"FET001" = { "passed" = true ... }
}
"2026-06-10T14:30:00" = {
"FET001" = { "passed" = false ... }
}
}
Current status for FET001: failed (use 2026-06-10T14:30:00, not the
June 1 entry).
Example with two runs on different features:
"tested_features" = {
"2026-06-01T10:00:00" = {
"FET001" = { "passed" = true ... }
}
"2026-06-10T14:30:00" = {
"FET002" = { "passed" = false ... }
}
}
The newest stamp run lists only FET002, not FET001. Current status for
FET001 is passed (its newest entry is 2026-06-01T10:00:00). Current
status for FET002 is failed (use 2026-06-10T14:30:00).
Who Reads It#
Downstream tools treat a feature as runtime-validated only when passed is
true for that feature and for every test listed under it, using the per-feature
rule in Interpreting Multiple Timestamps.
simready-benchmark does not read this receipt to plan or execute tests. Test
selection comes from the asset’s declared features and profiles. The receipt is
written for pipelines, catalogs, and other tools that consume the asset after
testing.
Stamping runs as a separate step after the tests finish. Although it is unlikely,
the stamper can fail to write the receipt even when every test passed
(for example, if the USD file is not writable or the USD library is unavailable).
In that case, _testing/index.html and test_results.json still reflect the
test outcome, and per-test stamping fields in the report show the error. Fix
the stamp problem and re-run with stamping enabled before relying on the receipt
downstream.