Skip to content

feat(audits): expand standard verb list and add .anc.toml domain_verbs - #76

Merged
brettdavies merged 1 commit into
devfrom
feat/p6-domain-verbs-config
Jun 2, 2026
Merged

feat(audits): expand standard verb list and add .anc.toml domain_verbs#76
brettdavies merged 1 commit into
devfrom
feat/p6-domain-verbs-config

Conversation

@brettdavies

Copy link
Copy Markdown
Owner

Summary

The p6-may-standard-names audit penalized every CLI shipping its native platform vocabulary. An X CLI's post / like / repost, a Slack CLI's dm, a GitHub CLI's block / mute — none were in the built-in verb list, so the ratio fell below 70 percent and the audit warned. Renaming those verbs to posts create / likes add would worsen agent ergonomics; the right fix is to teach anc the vocabulary.

Two changes:

  • Expand STANDARD_VERBS with 18 widely-understood social/notification verbs.
  • Read .anc.toml at the audit target root and honor [p6] domain_verbs = [...] as per-CLI extensions. Recognition becomes builtin OR domain; the existing pass/warn semantics stay intact.

Changelog

Added

  • Recognize 18 social/notification platform verbs in p6-may-standard-names (archive, block, bookmark, dm, follow, like, mute, post, quote, reply, repost, subscribe, unarchive, unblock, unfollow, unlike, unmute, unsubscribe).
  • Load .anc.toml at the audit target root. Honor [p6] domain_verbs = [...] as per-CLI vocabulary extensions to the built-in standard-verb list.

Fixed

  • Drop a duplicated "audit" entry from STANDARD_VERBS (HashSet semantics masked the dup; no behavior change).

Type of Change

  • feat: New feature (non-breaking change which adds functionality)

Related Issues/Stories

  • Plan: /home/brett/dev/xurl-rs/docs/plans/2026-06-02-001-feat-anc-100-percent-compliance-plan.md (U2)

Testing

  • 9 unit tests in src/anc_toml.rs covering: absent path, loaded with domain_verbs, empty list, missing [p6] section, wrong-type domain_verbs, syntactically broken TOML, file-as-target, fallback behavior, evidence accessor.
  • 5 new unit tests in src/audits/behavioral/standard_names.rs covering: the expanded built-in list, mentions-without-vs-with domain_verbs, empty-slice regression, duplicate-with-builtin harmlessness.
  • 3 integration tests in tests/standard_names_integration.rs exercising the full pipeline through the anc binary: pass via domain_verbs, warn on malformed .anc.toml, regression-warn when absent.

Test Summary:

  • cargo test: 817 passed, 2 ignored (8 suites)
  • cargo clippy --all-targets -- -D warnings: clean
  • cargo fmt: clean

Files Modified

Modified:

  • src/main.rs — register mod anc_toml;.
  • src/audits/behavioral/standard_names.rs — expanded built-in verb list (alphabetized new subgroup); refactored audit_standard_names(help, domain_verbs); StandardNamesAudit::run loads .anc.toml and surfaces parse errors as Warn(msg); existing tests adapted to pass &[] as the new arg; dropped duplicated "audit" entry.

Created:

  • src/anc_toml.rs — loader for .anc.toml. ANC_TOML_FILENAME, AncConfig { p6: P6Config }, P6Config { domain_verbs: Vec<String> }, AncConfigLoad::{Absent, Loaded, Invalid}, pub fn load(repo_root: &Path) -> AncConfigLoad.
  • tests/standard_names_integration.rs — end-to-end coverage through the anc binary.

Schema

.anc.toml at the audit target's repo root, optional:

[p6]
domain_verbs = [
  "mentions",
  "timeline",
  "whoami",
  # ...per-CLI platform vocab the built-in list deliberately omits
]

Loader contract:

  • Missing file -> Absent (additive, never required).
  • Parse error -> Invalid(msg) surfaced as the audit's primary signal (Warn with "could not parse .anc.toml: <reason>").
  • Non-directory target (binary-mode audits) -> Absent.

Before / After on xurl-rs

anc audit /home/brett/dev/xurl-rs --output json \
  | jq '.results[] | select(.id == "p6-may-standard-names") | {status}'

Before this PR: "status": "warn" (7/35 subcommands matched the standard list).

After this PR (with xurl-rs's committed .anc.toml declaring its X-platform vocabulary): "status": "pass".

Benefits

  • Stops penalizing CLIs whose platform vocabulary is the canonical agent-facing surface (X, Slack, GitHub, billing APIs, package registries).
  • Establishes .anc.toml as the per-CLI extension point — additive, opt-in, audit-side parse errors surfaced rather than swallowed.
  • Built-in list grows conservatively; verbs that don't cleanly cross platforms stay out and land in per-CLI config instead.

Breaking Changes

  • No breaking changes

The audit's id, evidence string format, and pass/warn thresholds are unchanged. CLIs without .anc.toml and without vocab in the new social subgroup get identical verdicts.

Deployment Notes

  • No special deployment steps required

Checklist

  • Code follows project conventions and style guidelines
  • Commit messages follow Conventional Commits
  • Self-review of code completed
  • Tests added/updated and passing
  • No new warnings or errors introduced
  • Changes are backward compatible

… from .anc.toml

Teach `p6-may-standard-names` two things:

(a) Recognize the common social/notification platform verbs that previously
penalized any CLI shipping the X, Slack, GitHub, etc. native vocabulary.
Eighteen verbs land in a new alphabetized subgroup of `STANDARD_VERBS`:
archive, block, bookmark, dm, follow, like, mute, post, quote, reply,
repost, subscribe, unarchive, unblock, unfollow, unlike, unmute,
unsubscribe. Scope kept conservative — verbs that are unambiguous across
platforms and don't read as domain jargon. Vocabulary that's genuinely
X-specific (mentions, timeline, whoami) stays out of the built-in list
and lands in `.anc.toml` instead.

(b) Load `.anc.toml` at the audit target's repo root and honor
`[p6] domain_verbs = [...]` as per-CLI vocabulary extensions. Recognition
becomes `builtin OR domain` — additive, never subtractive. The new
`crate::anc_toml` module owns the loader contract: missing file -> Absent,
parse error -> Invalid(msg) surfaced as the audit's primary signal,
non-directory target -> Absent.

Also drops a duplicated `"audit"` entry from `STANDARD_VERBS` — a pre-existing
typo from when the action-style subgroup was hand-merged. HashSet semantics
masked the duplication; no behavior change beyond cleaning the source list.

Verification: `anc audit /home/brett/dev/xurl-rs --output json` now reports
`p6-may-standard-names` as `pass` (was `warn` with 7/35 standard verbs).
xurl-rs ships `.anc.toml` declaring its X-platform vocab; the loader picks
it up and the verb-set membership check carries the audit past threshold.

Tests:
- 9 unit tests in `src/anc_toml.rs` covering absent, loaded, empty,
  missing section, wrong-type, syntactically broken, file-target,
  fallback accessor.
- 5 new unit tests in `standard_names.rs` covering the expanded
  built-in list, mentions-without-vs-with domain_verbs, empty-slice
  regression, and the duplicate-with-builtin harmlessness.
- 3 integration tests in `tests/standard_names_integration.rs`
  exercising the full pipeline through the `anc` binary: pass via
  domain_verbs, warn on malformed `.anc.toml`, regression-warn when
  absent.
@brettdavies
brettdavies merged commit 9263c5c into dev Jun 2, 2026
8 checks passed
@brettdavies
brettdavies deleted the feat/p6-domain-verbs-config branch June 2, 2026 19:35
brettdavies added a commit that referenced this pull request Jun 3, 2026
…llow-up plans

Adds five plans surfaced by the post-merge adversarial review of PRs #73, #76, #77, and #79:

- 2026-06-03-001 (umbrella, P1): structure-over-vocabulary audit philosophy.
  Spec is canonical; closed-vocabulary lookups (COMMON_VERBS, STANDARD_VERBS,
  DISCRIMINANT_FIELD_NAMES, SUCCESS_VALUE_STRINGS) are failed quality proxies;
  per-PR redesigns of p6-consistent-naming and p2-must-json-errors land under
  this plan.
- 2026-06-03-002 (P1): PR #73 follow-up. Probe-failure now Warns instead of
  silent Pass, leaf non-verb requires a successful probe, drop emit from
  COMMON_VERBS, add 4 negative-case tests.
- 2026-06-03-003 (P1): PR #76 follow-up. Scorecard transparency for
  .anc.toml domain_verbs (using_domain_verbs flag + domain_match_count +
  evidence string showing built-in vs domain ratio), trim 7 platform-specific
  verbs out of built-in STANDARD_VERBS, document the social-CLI .anc.toml
  pattern.
- 2026-06-03-004 (P0): PR #77 follow-up. cfg(not(test)) is treated identically
  to cfg(test) in the new cfg-args parser, silently exempting production-only
  code from code-unwrap. Thread polarity through the recursive call site,
  add 8 negative-case tests, correct an inner-attribute comment.
- 2026-06-03-005 (P1): PR #79 follow-up. Close three role-based-validator
  bypasses: numeric discriminant on info-coded values, success synonyms outside
  the 8-string closed set, and nested-recursion harvesting roles from a
  success-coded outer envelope. Add 6 adversarial tests.

Plans 002, 003, and 005 are tactical stopgaps that stop active misclassification
while plan 001 owns the long-term redesign. Plan 004 is a correctness bug fix
and ships independently.
brettdavies added a commit that referenced this pull request Jun 4, 2026
… platform verbs (#83)

## Summary

Follow-up to merged PR #76 addressing two coupled gaps surfaced during
the post-merge adversarial review.

`.anc.toml [p6] domain_verbs` lets any CLI declare its own subcommand
vocabulary as "standard," but the scorecard row gave no signal whether
the Pass was assisted. A domain-verb-assisted Pass was byte-identical in
JSON to a built-ins-only Pass. Separately, of the 18 verbs PR #76 added
to `STANDARD_VERBS`, 7 are X/Mastodon-specific (`post`, `repost`,
`unrepost`, `quote`, `like`, `unlike`, `dm`). Their inclusion encoded
one platform's vocabulary as universal, and let any social CLI Pass
without exercising the `.anc.toml` opt-in PR #76 introduced.

This PR adds scorecard transparency for domain-verb-assisted Passes and
trims the platform-specific verbs out of the built-in list. Schema bumps
`0.7 → 0.8` (additive).

## Changelog

### Added

- Schema `0.8`: `using_domain_verbs: Option<bool>` and
`domain_match_count: Option<usize>` on each `AuditResultView` row.
Populated when `p6-standard-names` Passes via `.anc.toml [p6]
domain_verbs` recognition; absent (not `null`) for rows that did not
consult `domain_verbs`.
- `MitigationInfo` carrier on `AuditResult` (typed, audit-agnostic)
tracking built-in vs domain match counts and the first 5 matched
domain-verb names in encounter order.
- Pass row's `evidence` field is populated with the built-in vs domain
ratio when assisted by `domain_verbs`, e.g. `"7/8 subcommands standard
(3 via .anc.toml [p6].domain_verbs: [post, like, repost])"`. Rows
without mitigation keep the historical `evidence: null` on Pass.

### Changed

- `STANDARD_VERBS` no longer recognizes `post`, `repost`, `unrepost`,
`quote`, `like`, `unlike`, `dm`. Social and platform-specific CLIs that
previously Passed via built-ins must now declare these in `.anc.toml
[p6] domain_verbs` (documented).
- `audit_standard_names` returns a `StandardNamesResult` struct (status
+ optional `MitigationInfo`) instead of bare `AuditStatus`.
- Warn evidence on `p6-standard-names` includes a pointer to
`docs/solutions/architecture-patterns/anc-toml-domain-verbs-pattern-2026-06-03.md`
so authors discover the opt-in.
- `CLAUDE.md` schema history block updated to document the `0.6`, `0.7`,
and `0.8` additions (the inline history had drifted at `0.5`).

### Fixed

- Audit-identity collapse from PR #76: a `.anc.toml`-assisted Pass is
now distinguishable in the scorecard JSON from an unassisted one.
- Verb-list dilution from PR #76: platform-specific vocabulary no longer
inflates the cross-CLI built-in list.

## Type of Change

- [x] `fix`: Bug fix (non-breaking change which fixes an issue)

## Related Issues/Stories

- Plan:
`docs/plans/2026-06-03-003-fix-pr76-domain-verbs-scorecard-transparency-plan.md`
- Origin: adversarial review of merged PR #76 (commit 9263c5c).
- Umbrella plan (audit philosophy, supersedes plans #2 and #5 at the
design level):
`docs/plans/2026-06-03-001-refactor-audit-philosophy-structure-over-vocabulary-plan.md`
- Pattern documentation:
`docs/solutions/architecture-patterns/anc-toml-domain-verbs-pattern-2026-06-03.md`
(already committed and pushed to the symlinked `solutions-docs` repo,
commit `402354b`).

## Testing

- [x] Unit tests added/updated
- [x] Integration tests updated
- [x] All tests passing

**Test Summary:**

- `cargo test`: 855 passed, 2 ignored (8 suites). Net +7 from baseline:
5 new R5 adversarial tests in `audit_standard_names`, 2 new
format-evidence tests pinning the 5-example truncation contract.
- `cargo clippy --all-targets -- -Dwarnings`: clean.
- `cargo fmt --check`: clean.
- `anc emit coverage-matrix --check`: clean.
- Dogfood: `anc audit . --output json | jq '.results[] | select(.id ==
"p6-may-standard-names")'` returns `status: "pass"` with
`using_domain_verbs` and `domain_match_count` absent from the row keys
(`anc` itself has no `.anc.toml`).

## Files Modified

**Modified:**

- `src/types.rs`: new `MitigationInfo` struct; new optional `mitigation:
Option<MitigationInfo>` field on `AuditResult`.
- `src/audits/behavioral/standard_names.rs`: refactored
`audit_standard_names` to return `StandardNamesResult`; bifurcated
built-in vs domain match counting; populates `MitigationInfo` on
domain-assisted Pass; trimmed 7 platform-specific verbs from
`STANDARD_VERBS`; appends docs URL to Warn evidence; 13 unit tests (8
updated to the new return shape + 5 new adversarial + 2 format-evidence
pinning tests).
- `src/audits/behavioral/mod.rs`: made `standard_names` `pub(crate)` so
the scorecard view layer can call `format_pass_evidence`.
- `src/scorecard/mod.rs`: `SCHEMA_VERSION` bumped to `"0.8"`;
`AuditResultView` gains `using_domain_verbs` and `domain_match_count`;
`from_row` reads `r.mitigation`, populates the fields, and synthesizes
Pass evidence prose via `format_pass_evidence`.
- `schema/scorecard.schema.json`: `$id` pinned to `scorecard-v0.8`.
- `tests/standard_names_integration.rs`: fixture retuned to `archive` +
`follow` + `mentions` so the `.anc.toml` loader is genuinely exercised
after the platform-verb trim.
- `tests/integration.rs`, `tests/scorecard_metadata_security.rs`,
`tests/scorecard_schema_v05.rs`: schema-version assertions bumped to
`"0.8"`; the v0.7 → v0.8 schema `$id` rename pinned by
`schema_v05_target_path_carries_no_separators` regression test.
- `CLAUDE.md`: schema history block updated (was stuck at `0.5`); new
`MitigationInfo` semantics block mirrors the existing per-version
addition pattern.
- ~77 audit and test files: mechanical `mitigation: None` insert in
every `AuditResult { ... }` constructor. This is the unavoidable churn
of adding a typed transparency field to the canonical result carrier.
`cargo check` verified the sed hit only valid sites.

**Created:**

- None.
(`docs/solutions/architecture-patterns/anc-toml-domain-verbs-pattern-2026-06-03.md`
lives in the symlinked `solutions-docs` repo and was committed there
separately.)

**Renamed:**

- None.

**Deleted:**

- None.

## Breaking Changes

- [x] No breaking changes (schema `0.8` is additive)

The 7 platform verbs removed from `STANDARD_VERBS` are a behavior
tightening, not a contract break. CLIs that relied on them being
built-ins were exploiting PR #76's overly broad vocabulary; the
remediation path is `.anc.toml [p6] domain_verbs` (documented).

## Deployment Notes

- [x] No special deployment steps required

## Checklist

- [x] Code follows project conventions and style guidelines
- [x] Commit messages follow Conventional Commits
- [x] Self-review of code completed
- [x] Tests added/updated and passing
- [x] No new warnings or errors introduced
- [x] Changes are backward compatible
brettdavies added a commit that referenced this pull request Jun 4, 2026
PR #83 (#83) ships the
work described in plan #3 with green CI. Flip the plan's frontmatter
status to completed; body unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant