assay doctor¶
Diagnose environment/config/trace issues and optionally apply automated fixes.
Synopsis¶
Common Options¶
| Option | Description |
|---|---|
--config <PATH> | Config file to inspect (default behavior: use eval.yaml when present). |
--trace-file <PATH> | Trace file used for deep diagnostics. |
--baseline <PATH> | Baseline file to inspect. |
--db <PATH> | DB path to inspect. |
--replay-strict | Enable strict replay checks in diagnostics. |
--format <text\|json> | Output format (default: text). |
--fix | Enable auto-fix mode for known issues. |
--yes | Apply available fixes without prompt (used with --fix). |
--dry-run | Preview fixes without writing files (used with --fix). |
Notes: - --fix currently supports text output mode. - --yes and --dry-run require --fix. - --dry-run previews fixes but still returns non-zero when blocking diagnostics remain. - Without --yes or --dry-run, --fix prompts. If stdin is not a terminal the prompt cannot be shown: the command refuses with exit 2 and names --yes.
Examples¶
# Basic doctor run
assay doctor --config eval.yaml --trace-file traces/golden.jsonl
# Diagnose and auto-apply available fixes
assay doctor --config eval.yaml --trace-file traces/main.jsonl --fix --yes
# Preview fixes only
assay doctor --config eval.yaml --trace-file traces/main.jsonl --fix --dry-run --yes
Fix Behavior¶
assay doctor --fix currently supports: - Creating a missing trace file for a trace-path error. On doctor's own diagnostics this is the only repair reachable today. The patch arms of the shared suggestion builder key on codes that assay_core::validate and assay_core::doctor never emit, and the one code they do share, E_PATH_NOT_FOUND, needs a file/field context that neither attaches — so --fix prints No auto-fixable diagnostics found for everything else. assay fix is where that machinery has reachable inputs. - Renaming a misspelled config key when the config will not parse, if one expected key is a close enough match, and previewing that rename as a unified diff under --dry-run. - Preserving doctor exit semantics in dry-run mode: diagnostics that remain exit with the class doctor returns for them without --fix, not with a class of their own. - Reporting a repair that could not be written as a config fault — the same class assay fix returns for a patch it could not apply — with the specific failure on stderr. - Re-loading the config after writing repairs, and reporting one that no longer loads as a config fault rather than as the outcome of the repair.
After apply, doctor re-runs diagnostics and reports remaining error count.
Exit Codes¶
Every row was measured on this version, one tree per condition. Where the code has a route that no invocation reaches, the row says so rather than describing it as behaviour.
| Code | Meaning |
|---|---|
0 | No error-severity diagnostic remains, or the fixes resolved them. Measured identical on the text channel, under --format json and under --fix --yes, because all three read the class from one function. It also covers the run that checked no config at all, so read config_check.status before data_diagnostics[]; see below. |
1 | An error-severity diagnostic whose registered class is a test failure. No input reaching this route has been measured; see below. |
2 | Configuration or invocation failure. Argument misuse — --fix under --format json, or --yes/--dry-run without --fix — exits the invalid-args class. The JSON request publishes one assay.doctor_report.v0 with E_INVALID_ARGS; the text request keeps the existing rejection on stderr and empty stdout. An explicit --config that will not load exits this class with or without --fix, including when no repair is available, a repair is declined or previewed, or a repair leaves the config unloadable. Error-severity diagnostics registered as config faults and repairs that cannot be written also exit this class. |
Four things the table does not say, which a reader would otherwise have to find out:
- No
1has been observed here. Its route to1is an error-severity diagnostic whose registered class is not a config fault, and every code doctor names deliberately is registered a config fault. That leaves the bareE_UNKNOWNraised as a fallback for a trace error the mapper does not recognise, and no input reaching it has been constructed. Argument misuse and unloadable configs use the classes documented on2. - A repair request does not reclassify an unloadable config.
doctor --config nope.yamland the same config under--fix --yesboth exit2, whether the repair is unavailable, declined, previewed, or insufficient. The repair flag changes what doctor attempts, not what condition it observed. - A failed repair and the diagnostics behind it cannot disagree today. A repair is offered only for
E_PATH_NOT_FOUNDorE_TRACE_MISS, both error-severity and both a config fault, so any tree where a write can fail already exits2. The two are still decided by separate functions, anddecide_repair_failure_exit's doc comment gives the reason: they answer different questions, and coupling them would let a change to the class table redefine what a failed write reports. That separation is a guard against a future change, not a difference this version can show — a tree whose findings are only advisory is offered no repair at all, so none can fail. - Exit
0also covers the run that checked no config at all. With no--configand noeval.yamlin the invocation directory, the text path printsPolicy Check: SKIPPEDand the JSON report carriesconfig_check.status: "skipped"and nodata_diagnosticskey.checkedis the only status under which an empty or absent diagnostics list describes a clean config;failedis the exit-2row above.