From 7a384b897c10d8bba927671ea432b575529645c9 Mon Sep 17 00:00:00 2001 From: Brett Date: Wed, 22 Apr 2026 18:13:49 -0500 Subject: [PATCH] feat(v0.1.3): resolve 26 ce-review findings + unify audience to kebab-case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies every finding from the post-merge ce-review of commit dc5d74168577: the P1 coverage-summary inflation fix, the full Check::label() trait migration, the Pattern 2 extraction, the audience_reason field, the audit_profiles matrix section, the codified regression guards, and the audience kebab-case unification (post-review decision — see the v0.1.3 H5 plan's Implementation Log for rationale). ## Changelog ### Changed - Scorecard JSON `audience` values now serialize as kebab-case (`agent-optimized` / `mixed` / `human-primary`) to match `audit_profile`'s kebab-case within the same document. Consumers keying on the v0.1.2 `null` fallback are unaffected; any v0.1.3 consumer must pin on the kebab-case shape. - `coverage_summary.{must,should,may}.verified` no longer counts `--audit-profile`-suppressed Skips. Suppression means the requirement was not verified, so the metric now matches what the site leaderboard renders per tool. ### Added - `audience_reason` field on scorecard JSON, populated only when `audience` is `null`: `"suppressed"` (signal check masked by `--audit-profile`) or `"insufficient_signal"` (signal check never produced, e.g. source-only run). Additive to v1.1; omitted when `audience` has a label. - Top-level `audit_profiles` array in `coverage/matrix.json` — each entry carries `{name, description, suppresses[]}`, letting agents enumerate the four categories and their per-category suppressions without scraping `--help`. - `Check::label()` trait method; every check now exposes its human label at the trait level. `--audit-profile`-suppressed and errored results now show the human label (e.g., "Respects NO_COLOR") instead of falling back to the check id. - `EnvHintSource` enum (`clap_annotation` / `proximity` / `env_section`) on every emitted `EnvHint` so agents debugging a Pattern 2 false positive can see which branch matched. `audit_profile` descriptions in the coverage-matrix artifact explain each suppression category. ### Fixed - `p1-env-hints` Pattern 2 no longer matches `$PAGER` in flag prose (added to `SHELL_ENV_BLACKLIST`; the doc comment always cited it as the archetypal exclusion but the slice omitted it). Also no longer captures uppercase-underscored section-header lines such as `DOCKER_CONFIG:` as env hints. ## Type of Change - [x] `feat`: New feature (non-breaking for v1.1 consumers that feature-detected `audience`/`audit_profile` as null) ## Testing - Unit tests: 402 passing (net +8 new vs. v0.1.3-rc) - Integration tests: 50 passing (net +3 new) - `cargo clippy --all-targets -- -Dwarnings`: clean - `cargo fmt --check`: clean - `cargo deny check`: clean - `scripts/hooks/pre-push` (full local CI mirror): all checks passed - `anc generate coverage-matrix --check`: no drift - Dogfood: `anc check . --output json` returns `schema_version: "1.1"`, `audience: "agent-optimized"`, `audit_profile: null`, with `audience_reason` omitted. - Dogfood under profile: `anc check . --audit-profile human-tui` returns `audience: null`, `audience_reason: "suppressed"`, `coverage_summary.must.verified` drops from 17 → 15 (no longer counts the suppressed P1 checks). ## Key ce-review findings resolved - **P1 #1** — `build_coverage_summary` excluded suppressed Skips via `audience::is_audit_profile_suppression`; regression test added. - **P2 #2** — `PAGER` added to `SHELL_ENV_BLACKLIST`; negative test covers the full trio (`$PATH`, `$HOME`, `$PAGER`). - **P2 #3** — `SUPPRESSION_EVIDENCE_PREFIX` extracted in `src/principles/registry.rs`; producer (`main.rs`), consumer (`scorecard::audience::is_audit_profile_suppression`), and filter (`build_coverage_summary`) all reference the single constant. - **P2 #4, #5** — README.md and AGENTS.md rewritten for the shipped v0.1.3 JSON surface, including the `--audit-profile` flag example and the committed `audit_profiles` matrix pointer. - **P2 #6** — `Check::label()` abstract trait method + full migration across all 40 check impls + `main.rs` error/suppression branches + `FakeCheck` stubs in matrix.rs and scorecard/mod.rs test modules. - **P2 #7 / P3 #11** — `help_probe.rs` (931 LoC) extracted to `help_probe/mod.rs` (~540) + `help_probe/env_hints_bash.rs` (~440) via `git mv` (history preserved); `EnvHintSource` enum introduced at parent scope so both patterns can tag emitted hints. - **P2 #8, #9, #10** — tightened `test_audit_profile_diagnostic_does_not_panic_on_self` to assert p5-dry-run suppression; added `test_audience_non_null_on_self_dogfood` + two `AuditProfile ↔ ExceptionCategory` parity drift tests. - **P3 #12** — `audit_profiles` section in `coverage/matrix.json`. - **P3 #13** — `audience_reason` field + `classify_reason()` helper. - **P3 #15** — shared `is_section_header_line` predicate used by both `find_env_section` and `extract_env_tokens`. - **P3 #18** — `test_scorecard_json_has_stable_top_level_keys` locks the v1.1 JSON shape bidirectionally. - **P3 #23** — `debug_assert!` in `classify()` against duplicate signal IDs; `#[should_panic]` test pins the invariant. - **P3 #25** — `test_principle_filter_forces_audience_null` covers `--principle` + audience interaction. - **P3 #26** — Pattern 2 negative fixtures reject `$Path`, `[FILES]`, `