@@ -2,6 +2,76 @@ |
| 2 | 2 | |
| 3 | 3 | ## Unreleased |
| 4 | 4 | |
| 5 | +### Sprint 06 — CLI & report UX polish |
| 6 | + |
| 7 | +Closes Audit 01 findings D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, |
| 8 | +D13, D14, D15, B16, B17, B18. |
| 9 | + |
| 10 | +- **D3 — extras rollup footer:** terminal + markdown reports now end |
| 11 | + with a single `pip install 'dlm-sway[...]'` line collecting every |
| 12 | + extra mentioned in SKIP messages. Single rollup, no per-row scan. |
| 13 | +- **D4 — `sway check` infers `--base`:** reads |
| 14 | + `base_model_name_or_path` from the adapter's `adapter_config.json` |
| 15 | + when `--base` is omitted; echoes "(inferred base model: …)" so the |
| 16 | + user knows what got picked. Falls back to a clear required-flag |
| 17 | + error when the field is missing. |
| 18 | +- **D5 — `sway autogen` annotates the YAML:** generated specs carry a |
| 19 | + header block (source `.dlm`, dlm_id, base, adapter, generation |
| 20 | + timestamp, sway version) and a one-line `# intent` comment above |
| 21 | + every probe entry. No new dep — pyyaml + a position-based |
| 22 | + post-processor instead of `ruamel.yaml`. |
| 23 | +- **D6 — `sway run --dry-run` + `sway list-probes`:** dry-run validates |
| 24 | + the spec, prints a probe table (#, name, kind, category, enabled), |
| 25 | + and exits 0 without building a backend. `list-probes` prints every |
| 26 | + shipped probe kind with its category and the first line of its |
| 27 | + docstring. |
| 28 | +- **D7 — `sway doctor --json`:** machine-readable doctor payload |
| 29 | + (`sway_version`, `python`, `platform`, `extras`) keyed by extra and |
| 30 | + module. CI-grep-friendly. |
| 31 | +- **D8 — `dlm_source` resolution warns instead of silently swallowing:** |
| 32 | + when the spec sets `dlm_source` but the `[dlm]` extra isn't installed |
| 33 | + (or the bridge errors), the runner emits a yellow stderr warning with |
| 34 | + the install hint and continues with `sections=None`. No more silent |
| 35 | + "why are my section probes SKIPping?" debugging. |
| 36 | +- **D9 — markdown column parity with terminal:** the markdown probes |
| 37 | + table now carries `score`, `raw`, `z`, `duration`, and `note` |
| 38 | + columns. A `Top findings` section follows the table; a `Skipped |
| 39 | + probes` section closes when extras are missing. |
| 40 | +- **D10 — unified number formatters:** `format_score`, `format_raw`, |
| 41 | + `format_z`, `format_duration_s` live in `suite/report.py` and are |
| 42 | + the only numeric formatters used. Thousands separators above 1 000; |
| 43 | + `—` glyph for `None` / non-finite. Single source kills cross-surface |
| 44 | + drift. |
| 45 | +- **D11 — `sway report --format` validated via `StrEnum`:** the |
| 46 | + Typer-level enum rejects unknown formats with the standard |
| 47 | + "Invalid value for '--format'" error. No more silent fallback to |
| 48 | + the terminal renderer on a typo. |
| 49 | +- **D12 — `sway check` verdict banner:** prints |
| 50 | + `✅ adapter is +4.2σ above noise` (green ≥ 3σ), |
| 51 | + `⚠️ adapter is +1.5σ above noise — marginal` (yellow ≥ 1σ), or |
| 52 | + `❌ adapter is +0.3σ — indistinguishable from noise` (red) above |
| 53 | + the full report. Calibrated on the delta_kl z-score; `check` |
| 54 | + now runs `null_adapter` first so the z-score is available. |
| 55 | +- **D13 — `sway diff` regression summary:** after per-probe deltas, |
| 56 | + the diff prints `A→B: N regressed >0.10, M regressed >0.20, |
| 57 | + composite Δ=±X.XX` color-coded by direction. |
| 58 | +- **D14 — adapter paths with spaces render safely:** `_adapter_label` |
| 59 | + wraps the path in double quotes when any whitespace is present. |
| 60 | +- **D15 — long messages wrap, don't truncate:** the terminal probe |
| 61 | + table column uses Rich's `overflow="fold"` instead of an 80-char |
| 62 | + hard cut with an ellipsis. The full message is always visible. |
| 63 | +- **B16 — single markdown renderer:** `report.from_json` round-trips |
| 64 | + saved JSON back into the canonical dataclass pair, so |
| 65 | + `sway report --format md` and `sway run --markdown` both flow |
| 66 | + through `report.to_markdown` with identical output. The legacy |
| 67 | + `_render_markdown_from_json` and `_render_junit_from_json` helpers |
| 68 | + in `cli/commands.py` are deleted. |
| 69 | +- **B17 — `None` scores render as `—`:** the unified formatters cover |
| 70 | + every render path; no more `0.00` masking missing data. |
| 71 | +- **B18 — `baseline` row labeled `(informational, weight=0)`:** in |
| 72 | + both terminal and markdown component breakdowns, matching the |
| 73 | + Sprint 03 explicit-weight-zero decision. |
| 74 | + |
| 5 | 75 | ### Sprint 05 — Probe quality & edge cases |
| 6 | 76 | |
| 7 | 77 | Closes Audit 01 findings B6, B7, B8, B9, B10, B11, B12, B13, B14, B20, |