| name | interpret-validators |
| description | Read saved validator artifacts and present a tier-classified report with per-rule prim lists and fix recommendations. Use when interpreting a saved run. |
| version | 1.0.0 |
| allowed-tools | Bash, Read |
| metadata | {"author":"NVIDIA Corporation","tags":["validation","reporting","analysis"]} |
interpret-validators — Read, present, and answer
Invocation. This is the interpret-validators skill. In Claude Code it's
also available as the alias /interpret-validators. In Codex or other agents,
invoke it by name.
Python invocation. Examples below use python3 (POSIX). On Windows use
py -3 (Python launcher) or the bundled interpreter at
_build\target-deps\python\python.exe. The helper scripts referenced
below (resolve_artifacts.py, summarize_csv.py) work under any Python 3
— no agent- or shell-specific extensions, no third-party packages.
Windows shell. Snippets target PowerShell (Claude Code's and Codex's
default Windows shell). For cmd.exe, replace $Var with %VAR% and
backtick line continuations with ^.
Companion to run-validators. Reads the CSV/JSON artifacts that the validator
driver produces, presents a structured report, and answers follow-up questions
without re-running.
The CSV is the source of truth — it contains issues from both rule
families:
- Base —
usd_validation_nvidia's DefaultPlugin rules (Kind, DefaultPrim,
OmniOrphanedPrim, etc.). The driver's stdout summary hides these; the CSV does not.
- Usd Optimize —
UsdOptimize*Checker rules from this repo. Each wraps an analysis-mode
operation in source/operations/.
For the CSV schema, the entry-point allow-list, and other infrastructure details,
see the validators skill.
What this skill covers
Each section below is load-bearing — read past Step 4 before concluding info is missing. Search for keywords like family, base, Usd Optimize, REQUIRES_MESH, Tier, T1, T2, T3, headline takeaway, findings, Rule reference to jump.
- Usage — what arguments are accepted, what follow-up questions it answers.
- Step 1 — resolve the input (asset / CSV / summary JSON), including branching
to partial-report derivation when summary mode lacks a sibling CSV but carries
findings.
- Step 2 — fresh / stale / missing decision for replay vs re-run.
- Step 3 — summarize the CSV via
summarize_csv.py when a CSV exists
(bypass: project embedded findings analysis payloads when CSV is
missing — § Partial-report mode). Summarizer already lowercases severity,
classifies family, normalizes locations, groups failures, sorts rules.
- Step 4 — present the report (header + summary table with
family column showing both base and Usd Optimize rules, failure details, headline takeaway).
- Step 5 — follow-up questions, including "Show me only base rules / only Usd Optimize rules" and the "How do I fix
<RuleName>?" answer flow.
- Rule reference — full Rule → backing op → tier table for both UsdOptimize rules and base usd-validation-nvidia rules. Base rules are not an afterthought — they get equivalent Usd Optimize-op mappings where one exists.
- Error handling — what to say when artifacts are missing/corrupt.
Companion skills:
run-validators — produces the artifacts this skill reads.
validators — reference doc for the underlying infrastructure.
run-operations — runs the fix ops this skill recommends in Step 5.
tune-parameters — interactive parameter iteration when defaults don't fully resolve a T2 rule.
For multi-op chains organized by bottleneck (memory, load time, mesh count, data quality), see .agents/operations/PIPELINES.md. For the canonical Python invocation reference, see .agents/operations/INVOCATION.md.
Usage
The skill takes one positional argument — the path to either an asset or a
saved artifact:
| Argument | Behavior |
|---|
<path/to/asset.usd> | Asset mode. Looks up saved artifacts for this asset. |
<path/to/issues.csv> | Direct CSV mode. |
<path/to/summary.json> | Summary mode. Prefer sibling issues.csv: when present, run Step 3 on the CSV. When the CSV sibling is missing (or unreadable), use partial-report derivation below if findings is populated. |
Partial-report summary mode (missing issues.csv)
The CSV carries base + Usd Optimize rows and is the authoritative source when
present. Sometimes only summary.json exists beside the artifact directory —
for example standalone analysis-mode output from run-validators, or a
driver-written summary augmented with serialized operation analysis payloads.
Treat all of these as one analysis-derived partial report path — one set of
rules for building Step 4. Do not fork separate presentation templates for
envelope quirks; only fingerprinting differs.
When partial-report derivation applies
- Triggered by: summary mode (
<path/to/summary.json>) and
sibling issues.csv absent or unreadable.
- Prerequisite: the JSON exposes a non-empty mapping at top-level
findings
with per-operation payloads shaped like {…, "output": {"analysis": {…}}}
beneath each findings[<operation_key>]. If the trigger fires but there is no
usable findings, Step 4 cannot reconstruct failure groups — explain that the
artifact lacks row-level CSV and analysis payloads and ask the user to
re-run run-validators (Kit path) rather than improvising totals from bare
total/by_rule alone.
Fingerprint envelopes (shared downstream)
Use this only for logging/context; both feed the same derivation afterwards.
Envelope A — Standalone analysis-mode (run-validators Python/API fallback):
- Identified by
validator_path, typically "standalone-analysis-mode",
alongside top-level findings. This artifact usually omits Kit timing fields.
Envelope B — Kit/driver summary envelope with embedded findings:
- Fingerprint Kit-style
--summary output (for example JSON from the repo
driver's perf_validators.py): top-level keys such as asset,
validate_secs, open_secs, total, by_rule (Usd Optimize-filtered
counts — see §Step 3 note on summary.json), and by_severity.
- Combined case: envelope B keys plus a top-level
findings object
(same layout expected by interpret-validators as standalone: derive from
findings[<op>].output.analysis).
issues.csv missing: even though total/by_rule summarize Usd Optimize rules,
you still take this partial-report path so prim-level failure narratives match
the analysis payloads instead of pretending CSV-backed detail exists.
Shared derivation (findings → Step 4)
For envelopes A and B, perform identical processing:
-
For each <operation_key> in findings, read findings[op].output.analysis
and map emitted rule-like entries onto the summarizer-aligned columns using
the corresponding .agents/operations/<key>.md Analysis Mode section as
the schema reference (same field paths as standalone — do not diverge logic
per envelope).
-
If two shapes appear in one file (validator_path and Kit timing keys),
still unify on this single derivation over findings; use Kit fields only
for the Step 4 header's timing lines (validate_secs / open_secs) when
present.
-
Render Step 4 — header + summary table + failure details — in the normal
format (family, severity columns, expandable failure blocks). Omit rules with
zero issues as usual once derived.
-
Fix tier / Operation: leave Fix tier blank and use — / ? per
Step 4 rules when no Rule reference mapping exists (same allowance as CSV
path).
-
Headline takeaway: must include exactly this line verbatim (characters
and hyphen length as shown):
(standalone fallback — base usd_validation_nvidia rules not covered)
— for either envelope when CSV-derived detail is unavailable, because
row-level/base rule coverage depends on CSV + full usd-validation-nvidia emission
and this branch does not recreate base plugin issues.
Adapt the Step 4 Header source line when CSV is absent (e.g. cite
summary.json / artifact dir replay instead of CSV path).
When sibling issues.csv exists
Prefer Step 3 (summarize_csv.py / ephemeral temporary stdlib-only fallback
summarizer beside the CSV) and ordinary Step 4 — do not substitute
findings-only interpretation when the CSV is present.
Follow-up questions (no re-run needed):
- "Which prims are affected by
<RuleName>?"
- "How do I fix
<RuleName>?"
- "Show all
<RuleName> failures" (when truncated in the initial report)
- "Show me only base rules" / "Show me only Usd Optimize rules"
- "Show me
<RuleName> issues on <prim_path>"
- "Re-run validation"
Step 1 — Resolve the input
Determine what kind of path the user gave:
- Ends in
.usd / .usda / .usdc / .usdz → asset mode (Step 2).
- Ends in
.csv → direct CSV mode (jump to Step 3 with the user's CSV).
- Ends in
.json → summary mode. Read the JSON; look for sibling
issues.csv in the same directory. When the CSV exists, continue with
Step 3 using that CSV. When the sibling CSV is missing, follow §
Partial-report summary mode (missing issues.csv) in Usage above:
fingerprint standalone vs Kit envelopes, require findings, then skip CSV
summarization and synthesize Step 4 from findings[op].output.analysis instead
of dumping raw summaries.
If no path is given, ask which asset / artifact to interpret.
Step 2 — Run vs. replay decision (asset mode)
If the selected Usd Optimize environment provides the optional artifact resolver, use it:
python3 tools/perf_validators/resolve_artifacts.py "<asset>"
# Windows (PowerShell)
py -3 tools\perf_validators\resolve_artifacts.py "<asset>"
When used, it returns the same JSON shape on all OSes. Parse the state field:
-
fresh — Saved CSV is newer than the asset. Tell the user:
Found a saved validation run from <csv_mtime>. Replaying is much faster
than re-running. Should I replay, or re-run validation?
Default to replay if the user doesn't specify — jump to Step 3 with the
reported csv path.
-
stale — Asset has been edited since the saved run. Tell the user:
The asset has been modified since the last validation run (saved
<csv_mtime>). I recommend re-running. Should I re-run, or replay the
older results?
If they ask to re-run, invoke the run-validators skill. If they pick
replay, proceed to Step 3 but flag the staleness in the report header.
-
missing — No saved run. Tell the user we need to run first; offer
the run-validators skill (don't run it inline without confirmation,
since validation can take minutes on large assets).
Step 3 — Summarize the CSV
Bypass: When § Partial-report summary mode (missing issues.csv) in
Usage applies — sibling CSV absent but findings contains operation analysis
bundles (findings[<op>].output.analysis) — skip CSV summarization here.
Instead project those analysis objects into the same compact totals /
rules / failures intermediate representation Step 4 expects (mirror the cap
spirit of --max-failures-per-rule 10; do not replay thousands of primitives),
then proceed directly to Step 4 using the unified partial-report playbook.
Don't read the CSV into context directly. A real validator output is
thousands of rows and pulling it inline wastes tokens and is fragile across
quoting / encoding edge cases. Prefer the packaged summarizer when it is
present, then parse its compact JSON. For the initial report, always pass
--max-failures-per-rule 10 so a pathological asset (e.g. one rule with
hundreds of unique-message failures) doesn't flood context. Re-run uncapped
for the "show all failures" follow-up.
If tools/perf_validators/summarize_csv.py is missing, build a temporary
stdlib-only fallback summarizer beside the artifact (for example
<artifact_dir>/_summarize_validator_csv.py) and run that instead of reading
the CSV. The fallback script is a local run artifact, not repository content,
unless the user explicitly asks to add tooling. It must:
- Stream rows with Python's
csv.DictReader; do not load the whole CSV into
memory or print raw rows.
- Emit compact JSON matching the packaged summarizer (required
top-level keys:
totals, sorted rules, and capped grouped failures; see
shape below).
- Normalize severity, rule, message, suggestion, and location fields
defensively because usd-validation-nvidia column names vary by version.
- Optionally add sibling metadata keys
report_path, report_bytes, and
truncated (boolean) — these are not emitted by repo
tools/perf_validators/summarize_csv.py, only useful for the ephemeral
fallback when you want explicit provenance/size/truncation in the JSON blob.
- Cap examples to 10 locations per failure group for the initial report.
If the fallback cannot parse the CSV, report blocked_large_artifact with the
CSV path, byte size, detected columns, and at most the first 10 lines. Do not
paste the full artifact.
python3 tools/perf_validators/summarize_csv.py "<csv_path>" --max-failures-per-rule 10
# Windows (PowerShell) — initial report
py -3 tools\perf_validators\summarize_csv.py "<csv_path>" --max-failures-per-rule 10
The output is a single JSON object. Always emit the three core sections below
(required for both the packaged script and any fallback summarizer):
{
"totals": {
"rows": 3690,
"rules": 25,
"by_severity": {"failure": 147, "warning": 3543},
"by_family": {"Usd Optimize": 3251, "base": 439},
"failures_by_rule": {"MissingReferenceChecker": 80, ...}
},
"rules": [
{"rule": "<Name>", "family": "Usd Optimize|base",
"by_severity": {"failure": N, "warning": N, "error": N, "info": N},
"affected_prims": <distinct location count>},
...
],
"failures": [
{"rule": "<Name>", "message": "<text>",
"suggestion": "<text or empty>",
"locations": ["<bare path or '(stage)'>", ...]},
...
]
}
Optional fallback-only top-level extensions (omit if redundant): report_path
(normalized CSV path summarized), report_bytes (source size in bytes), and
truncated (boolean — whether capped output omitted rows). Add these when they
help explain a locally generated <artifact_dir>/_summarize_validator_csv.py; the
packaged summarize_csv.py does not emit them by default.
Notes on what the summarizer does for you:
- Severity casing — already lowercased (CSV uses title case
Warning/Failure,
summary.json uses upper case WARNING/FAILED_CHECK; the summarizer
collapses both to lowercase keys: warning, failure, error, info).
- Family classification —
family is "Usd Optimize" for UsdOptimize* rules
and "base" for everything else.
- Location normalization — strips
Prim </…> / Stage </…> /
Attribute (…) Prim </…> wrappers so locations contains bare paths.
Empty / None cells become the literal string "(stage)". Lines that don't
fit the wrapper format (e.g. layer-spec Sdf.Find('a', 'b')) are kept as-is.
- Failure grouping —
failures is a flat list grouped by
(rule, message, suggestion). Locations sharing the same message group
collapse into one entry's locations array.
- Sort order —
rules is sorted by max severity weight (failure > error
warning > info) then by issue count descending.
If a summary.json is also available alongside the CSV, read its
validate_secs / open_secs for the report header. Note: summary.json's
total / by_rule are filtered to Usd Optimize rules only (perf_validators.py filters
before writing summary). Always derive the real totals from the summarizer's
totals section, not from summary.json.
Step 4 — Present the report
The report has three sections: header, summary table, and failure details.
Always print all three (when failures exist). Use full column names — never
abbreviate to single letters in user-facing output.
Header
File: <asset (basename)>
Source: replayed from <csv_path> (saved <csv_mtime>) # or "fresh run"
Validate time: X.Xs (open Y.Ys) # if summary.json present
Summary: <N> failures, <N> warnings, <N> errors across <N> rules
(base: <count>, UsdOptimize: <count>)
Partial-report / missing CSV: omit the CSV replay line unless a CSV existed;
instead use Source: text that cites summary.json / artifact-directory replay
(or asset.txt), e.g. analysis-derived from <summary.json> (sibling CSV
missing; findings[op].output.analysis payload) — keep timing lines when the
summary envelope exposes validate_secs / open_secs (Envelope B).
Summary table
Iterate the summarizer's rules array (already sorted). Omit rules with zero
total issues (the summarizer doesn't emit them, so this is automatic). Use
full column names:
| Rule | Family | Failures | Warnings | Errors | Affected prims | Fix tier | Operation |
|------|--------|----------|----------|--------|----------------|----------|-----------|
| ... | Usd Optimize/base| N | N | N | N | T1/T2/T3 | <op> or — |
- Affected prims =
affected_prims from the summarizer (distinct
Location values; a single prim with multiple issues counts once).
- Fix tier and Operation come from the Rule reference below. For
unknown rules, leave
Fix tier blank and Operation ? — don't guess.
Failure details
Failures are the actionable signal — always expand them in the initial report.
Iterate the (already-capped) failures array from the summarizer. For each
rule with at least one failure, print:
**<RuleName>** — <N> failures
- <Message>
Suggestion: <Suggestion> # only if non-empty
• `<location_or_(stage)>`
• `<location_or_(stage)>`
...
The --max-failures-per-rule 10 flag in Step 3 already caps each rule at 10
total failure rows, so no further truncation is needed in this step. To
detect when the cap dropped rows, sum the locations array lengths across
the rule's groups (each group can contain multiple locations sharing one
message) and compare to the unfiltered row count in
totals.failures_by_rule[<rule>]. Don't compare group count vs row count
— a single message affecting 3 prims is one group / 3 rows and would always
falsely trigger.
shown_locs = sum(len(g["locations"]) for g in failures if g["rule"] == rule)
total_locs = totals["failures_by_rule"].get(rule, 0)
if shown_locs < total_locs:
print(f'(+ {total_locs - shown_locs} more failures — '
f'ask "show all {rule} failures" to see them)')
Do not expand warnings in the initial report; they're often in the
hundreds-to-thousands and would bury the failures. Warnings are surfaced via
the "Which prims are affected by …?" follow-up.
Headline takeaway
After the failure details, add a 1–2 sentence synthesis identifying the
dominant pattern in the failures and the action that would resolve the most
issues. This converts the long table into a clear next step. Examples:
The 147 failures are dominated by 138 missing-reference paths from a Windows
export — fixable by re-flattening on a machine with the textures or rewriting
absolute paths to relative ones.
86% of warnings come from UsdOptimizeEmptyLeafChecker and
UsdOptimizeUnusedUVsChecker — pruneLeaves + removeUnusedUVs would
clear most of them.
All 198 issues are base usd-validation-nvidia rules; 0 Usd Optimize issues
fired because the asset has no UsdGeomMesh prims (mesh-only Usd Optimize rules
short-circuit via REQUIRES_MESH — see validators/SKILL.md
§Performance behavior). Six Usd Optimize hierarchy / materials / animation rules
still ran and passed. The fix path is upstream (CAD export, references)
rather than Usd Optimize.
Footer
You can ask follow-up questions like:
- "Which prims are affected by <RuleName>?"
- "How do I fix <RuleName>?" — I'll print concrete commands then.
- "Show all <RuleName> failures" — expands the truncated list.
- "Show me only base rules" / "only Usd Optimize rules"
- "Re-run validation"
Don't print fix commands eagerly. Wait for the user to ask.
Step 5 — Follow-up questions
Use the parsed JSON in context. Don't re-run the validator unless asked.
The detailed playbook for each follow-up — exact summarizer invocations,
T1/T2/T3/base fix-question response templates, "show all", per-prim
filtering, family filters, "re-run", and "only check <Rule>" — lives
in references/follow-ups.md. Read that file when answering any
of these:
- "Which prims are affected by
<RuleName>?" — --locations mode.
- "How do I fix
<RuleName>?" — tier-aware response template.
- "Show all
<RuleName> failures" — re-summarize uncapped.
- "Show me
<RuleName> issues on <prim_path>" — --locations + substring filter.
- "Show me only base rules" / "only Usd Optimize rules" — family filter on Step 4.
- "Re-run validation" — hand off to the
run-validators skill.
- "Only check
<RuleName>" — explain there's no --rule flag; filter post-hoc.
Rule reference
The full Rule → backing op → tier table — for both UsdOptimize rules
and base usd-validation-nvidia rules — lives in references/rule-reference.md.
Read that file when populating the Fix tier and Operation columns of the
Step 4 summary table, and when answering "How do I fix <RuleName>?" follow-ups
in Step 5.
The reference covers:
- UsdOptimize rules — every
UsdOptimize*Checker registered with its backing op and tier.
- Base usd-validation-nvidia rules — stage / metadata / external-reference
rules with no Usd Optimize equivalent (T3 / manual), plus geometry rules that
do map cleanly onto an Usd Optimize op (labelled
T1-equiv / T2-equiv).
For rules not listed in the reference, treat as T3 / manual and
surface the CSV Suggestion column verbatim. Don't invent fix
commands.
Error handling
| Symptom | Response |
|---|
Summary JSON without sibling CSV and no usable top-level findings payloads | Artifact has rollups only (total / by_rule) — cannot rebuild Step 4 failure groups or prim lists. Ask the user to re-run run-validators (emit issues.csv or a summary that embeds findings[<op>].output.analysis). |
| User passes an asset with no saved run | "No saved validation found at <artifact_dir>. Run the run-validators skill on this asset first." |
summarize_csv.py reports csv not found | The artifact dir is empty or the path is wrong. Re-run the run-validators skill, or check <artifact_dir>/ contents. |
summarize_csv.py reports CSV missing required columns | The file is from a different tool. Show the first 10 lines and ask the user to confirm. |
Summarizer succeeds but totals.rows == 0 | "The validation completed with no issues — the asset passed every rule that ran." |
| User asks about a rule not in the summarizer output | "No issues were emitted for <RuleName> in this run." |
| User asks "how do I fix" a rule we don't recognise | Treat as base rule (T3 / manual); surface the Suggestion column from the CSV. |
Purpose
Read the CSV / summary JSON artifacts produced by run-validators and
present a structured, tier-classified report — header, summary table
(per-rule severity counts + affected prims + fix tier + backing op),
failure details, and a headline takeaway — without re-running the
validator. Then answer follow-up questions ("which prims are affected
by X?", "how do I fix Y?", "show all failures", base-only /
Usd Optimize-only filters) from the parsed JSON in context.
Prerequisites
- A USD asset that has already been run through
run-validators
(or a CSV / summary JSON path the user supplies directly).
- A Python interpreter for the helper scripts (
resolve_artifacts.py,
summarize_csv.py) — pure stdlib, so any Python 3 works (no pxr
required).
- The repo's
tools/perf_validators/ directory accessible from the
current working directory.
Limitations
- This skill is read-only. It never re-runs the validator; if the
user asks for a fresh run, hand off to
run-validators.
- It never executes fix operations. Fix commands are recommended via
the Rule reference table; the user invokes
run-operations to apply
them.
- The CSV is the source of truth —
summary.json's total /
by_rule are filtered to Usd Optimize rules only. The skill always derives
totals from the summarizer's totals section.
- The initial report caps each rule at 10 failure rows
(
--max-failures-per-rule 10) to keep context manageable. The
"show all " follow-up re-runs uncapped.
- Warnings are not expanded in the initial report (often hundreds-to-thousands).
Surface them via the "Which prims are affected by …?" follow-up.
Troubleshooting
The Error handling section above already covers the artifact-shape
failure modes. Additional meta-troubleshooting:
| Symptom | Likely cause | Fix |
|---|
Summary numbers don't match summary.json totals | summary.json is Usd Optimize-filtered; the CSV is unfiltered. | Always derive totals from summarize_csv.py against the CSV — never read summary.json.total directly. |
| "Show all " output truncates again | Forgot to drop --max-failures-per-rule on the re-run. | Omit the flag; alternatively pass --limit 0. |
| Rule appears in CSV but not in the Step 4 table | Rule emitted only info / warning rows (no failure) and the user asked for failures only. | Re-render the table without severity filter; or use --locations to enumerate. |
Fix tier shows ? for a rule | Rule isn't in references/rule-reference.md. | Treat as T3 / manual and surface the CSV Suggestion column verbatim. Don't guess. |
| User asks "fix everything" | Some rules are T3 / analysis-only and have no automated fix path. | Filter the recommended chain to T1 + T2; explain that T3 rules need DCC/manual review. |