Skip to content

feat(prose): import prose pipeline; un-vendor orchestrator; doc-hygiene pass#52

Merged
brettdavies merged 17 commits into
devfrom
feat/prose-pipeline-and-doc-hygiene
May 21, 2026
Merged

feat(prose): import prose pipeline; un-vendor orchestrator; doc-hygiene pass#52
brettdavies merged 17 commits into
devfrom
feat/prose-pipeline-and-doc-hygiene

Conversation

@brettdavies
Copy link
Copy Markdown
Owner

Summary

Imports the shared prose-check pipeline from agentnative-spec into this repo, lands the linter-channel voice doc, and runs an adjacent doc-hygiene pass (RELEASES split, new CONTRIBUTING.md, expanded issue templates).

Changelog

Added

  • New PRODUCT.md at repo root codifies linter-channel voice: second-person imperative register, three-part error shape (what failed, why, what to do), no marketing voice in CLI surface. Inherits universal rules from vendored BRAND.md.
  • New CONTRIBUTING.md documents the three-tier intake (signal / proposal / code), routes principle-level discussion to the spec repo, and names the dev-setup gates.
  • New add-tool-to-registry issue template for proposing CLI tools to the anc100 registry.

Changed

  • RELEASES.md slims to operational runbook (95 lines); rationale moves to companion RELEASES-RATIONALE.md (243 lines). Each runbook section ends with a section-pointer at the rationale.
  • Issue-template config adds agentnative-skill as a fourth cross-repo destination; renames "CLI grading" to "grading findings" to match spec-repo terminology.

Documentation

  • AGENTS.md gains a "Voice and prose rules" section pointing at PRODUCT.md for the linter-channel register and scripts/prose-check.sh for the local gate.
  • scripts/SYNCS.md documents the new sync-prose-tooling.sh row and the consumer-owned status of scripts/prose-check.sh.

Type of Change

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

Related Issues/Stories

  • Story: n/a
  • Issue: n/a
  • Architecture: docs/plans/2026-05-07-002-feat-prose-tooling-import-plan.md (this branch's execution log captures the deltas from the original plan)
  • Related PRs: tracks agentnative-spec .context/.../010-pending-p0-prose-check-consumer-exclusion-config.md for the upstream sidecar-config migration that will let the un-vendored orchestrator re-vendor.

Files Modified

Modified:

  • .github/ISSUE_TEMPLATE/{00-blank,config}.yml: surface the new tool-registry template, add skill repo destination.
  • .gitignore: exclude vale-runtime-fetched styles/{proselint,write-good,.vale-config}/ (mirrors upstream).
  • AGENTS.md: voice-rules pointer at PRODUCT.md.
  • CLAUDE.md: backtick the include! macro reference (silenced LT.A_INFINITIVE).
  • RELEASES.md: slim to runbook; point prose-scrub at the lt_check helper.
  • scripts/SYNCS.md: new sync row, reference link, consumer-owned status for prose-check.sh.
  • docs/plans/2026-05-07-002-feat-prose-tooling-import-plan.md: execution log + unit status markers.

Created:

  • PRODUCT.md, CONTRIBUTING.md, RELEASES-RATIONALE.md, BRAND.md, .vale.ini
  • scripts/{sync-prose-tooling.sh,prose-check.sh,test-prose-check.mjs,generate-pack-readme.mjs}
  • styles/brand/{FillerAdjectives,HedgeWords,MarketingRegister}.yml + README.md
  • styles/config/vocabularies/{brand,cli}/{accept,reject}.txt
  • .github/ISSUE_TEMPLATE/add-tool-to-registry.yml

Renamed:

  • None.

Deleted:

  • None.

Testing

  • Unit tests added/updated: n/a (no Rust changes).
  • Integration tests added/updated: n/a.
  • Manual testing completed: full local gate suite green (pre-push hook covers fmt, clippy, test, deny, Windows compat, Windows cross-clippy).
  • All tests passing.

Test Summary:

  • cargo test: 588 passing across 7 binaries, 0 failed, 2 ignored.
  • cargo fmt --check: clean.
  • cargo clippy -Dwarnings: clean.
  • cargo deny check: advisories ok, bans ok, licenses ok, sources ok.
  • Windows libc grep + cargo clippy --target x86_64-pc-windows-gnu: clean.
  • bash scripts/sync-prose-tooling.sh --check: byte-equal upstream main @ 1625416.
  • bash scripts/prose-check.sh: 0 blocking, 457 stylistic warnings (non-blocking).
  • bash scripts/test-prose-check.mjs: vendored harness from upstream, runs clean.
  • shellcheck -S warning on all bash scripts: clean.
  • actionlint: clean.
  • anc generate coverage-matrix --check: clean.

Breaking Changes

  • No breaking changes

Deployment Notes

  • No special deployment steps required

scripts/prose-check.sh now sources ~/dotfiles/config/shell/languagetool.sh for the LanguageTool integration. Contributors without the dotfiles checkout get a clear pointer (exit 2 with path to brettdavies/dotfiles) rather than a confusing sourcing error. CI is unaffected since it doesn't run prose-check yet; that gate is deferred to a future PR.

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

Additional Context

scripts/prose-check.sh is intentionally consumer-owned (un-vendored 2026-05-13). The orchestrator's find-expression exclusions are CLI-LOCAL (src/principles/spec/, docs/ideation/, tests/fixtures/, coverage-matrix.md) and cannot live in the upstream until the spec-side sidecar-config migration lands. Universal pipeline changes (new check stage, severity routing) require coordinated PRs across spec + site + cli + skill until then.

scripts/generate-pack-readme.mjs carries a one-line CLI-LOCAL adaptation (drops spec from DEFAULT_PACKS since this repo doesn't vendor styles/spec/); the sync --check skips it the same way it used to skip the un-vendored prose-check.sh.

Codifies the linter channel's three-tier waterfall (BRAND.md universal,
PRODUCT.md channel delta, src/ implementation) so the inheritance shape
is explicit at the top of the channel design doc rather than implied.

Mirrors the parallel Inheritance section landing in agentnative-spec,
agentnative-site, and agentnative-skill as part of the coordinated
.impeccable.md to PRODUCT.md migration. The CLI channel never had a
.impeccable.md committed; this branch only adds the Inheritance section
to the in-flight PRODUCT.md draft sitting on feat/prose-tooling-import.

Also retitles the H1 from "# PRODUCT.md" to
"# PRODUCT.md: linter channel design context" to match the spec/site/
skill PRODUCT.md naming convention.

No vendored files touched (BRAND.md, styles/brand/, src/principles/spec/,
sync scripts all unchanged).
Vendor the shared prose-linting tooling from `agentnative-spec` (BRAND.md,
brand rule pack, brand + CLI vocab, prose-check orchestrator, test harness,
generator) via a new `scripts/sync-prose-tooling.sh`. Add a CLI-local
`.vale.ini` (the upstream one references the `spec` rule pack which is wrong
for CLI prose). Gitignore the runtime-fetched proselint/write-good packs
that vale downloads on first invocation, mirroring upstream.

Wire references into AGENTS.md (voice rules pointer) and scripts/SYNCS.md
(upstream sync table row + diagram edge). Narrow scope: markdown surfaces
only. Clap help text, error messages, and panic strings remain unlinted
until U6 of the prose-tooling-import plan ships.

CLI-LOCAL DIVERGENCE: scripts/prose-check.sh carries a patch block adding
CLI-specific path exclusions (src/principles/spec/, docs/ideation/,
tests/fixtures/, coverage-matrix.md). The orchestrator is intentionally
excluded from `--check` byte-equivalence verification until upstream lands
`--exclude PATTERN` (agentnative-spec todo #10).
Mark U1+U2+U3 of the prose-tooling-import plan as complete/in-progress
(narrow-scope 2026-05-12 session) and U4/U5/U6 as deferred to follow-up
PRs. Add an Execution log section documenting the four plan deviations
discovered during implementation:

- Tag-pinned sync, not branch-pinned (matches site repo + sync-spec.sh
  precedent).
- Manifest reality: proselint/write-good are runtime-fetched by vale,
  not vendored.
- Upstream parameterization did not land; followed site repo precedent
  of vendoring verbatim with a marked CLI-LOCAL DIVERGENCE block.
- Filename migration `.impeccable.md` to PRODUCT.md triggered by the
  impeccable skill loader's auto-rename.
The cross-channel references in the Status section used `~/dev/...`
machine-local paths that only resolve on the author's filesystem. Switch
to repo-relative naming (`agentnative-spec/PRODUCT.md`,
`agentnative-site/PRODUCT.md`) so the references read correctly anywhere
the file is rendered.
… tag

The prose-tooling stack is shared infrastructure with a faster cadence than
the principle contract. Consumers do not pin to versions of it: there is no
"v0.4.0 BRAND.md" semantic the way there is a v0.4.0 principles set. Switch
the resolver from `git ls-remote --tags` plus `--branch <tag>` to `git
ls-remote refs/heads/main` plus `--branch main`, and switch the local
fallback from "latest v* tag" to "main HEAD".

Tag-pinning stays in scripts/sync-spec.sh, where it belongs: that script
covers the principle contract, where consumers pin to a released spec
version.

Updates throughout: rename `spec_tag` to `spec_ref`, change status messages
("resolved main (sha)" / "wrote N file(s) from main @ sha"), update the
`--check` summary to reference upstream main HEAD, refresh the script
header (resync cadence, manifest preamble, tracking rationale), and update
scripts/SYNCS.md row to match (cadence, drift-check description). The
sync-spec.sh row stays tag-pinned as before.

Local fallback now requires a `main` branch in $SPEC_ROOT and surfaces a
clear error if the user's local checkout lacks one.

Syntax-checked via `bash -n`. Not executed (waiting for the spec-side PR
that introduces this stack on main).
The vendored upstream kept clobbering the CLI-LOCAL DIVERGENCE block (consumer-specific path exclusions and LT denylist additions) on every sync. The inline edits cannot be reversibly bracketed because the upstream `find` invocation and `grep -v -E` regex are single multi-line expressions; representing both upstream and CLI variants inline would require either duplicate executions or post-strip code restructuring, neither of which earns its complexity.

Resolution: prose-check.sh moves to consumer-owned. Universal pipeline changes (new check stage, LT URL change, severity routing) now need coordinated PRs across all four channel repos (spec, site, cli, skill) until the spec-side sidecar-config migration lands. Drift workflow no longer covers this file.

Adds CONSUMER-OWNED header to scripts/prose-check.sh; removes the file from the sync manifest in scripts/sync-prose-tooling.sh; updates scripts/SYNCS.md to document the un-vendor.
Default URL changes from `http://pool.tail42ba87.ts.net:8081` (Tailscale FQDN) to `http://languagetool:8081` (local docker network hostname). Possible now that the orchestrator is consumer-owned (un-vendored 2026-05-13); a sync no longer overwrites this line. Existing override via `LANGUAGETOOL_URL` env var remains the supported way to point at a different LT endpoint.
Re-runs `scripts/sync-prose-tooling.sh` to pick up upstream changes since the initial vendor at v0.4.0:

- BRAND.md propagates the ecosystem-wide `.impeccable.md` → `PRODUCT.md` rename in cross-references, adds a vendoring source-of-truth callout naming the four consumer repos.
- styles/brand/README.md regenerated with the same rename in the channel reference line.
- styles/config/vocabularies/brand/accept.txt picks up three new universal-vocab terms (`heredoc`, `renderer`, `renderers`).

All three files are byte-equal to upstream `main` HEAD. The fourth vendored file in the manifest (`scripts/generate-pack-readme.mjs`) is intentionally divergent on this branch and lands in a sibling commit.
The CLI doesn't vendor `styles/spec/` (RFC 2119 register is wrong for the linter channel; see PRODUCT.md). Running `bun scripts/generate-pack-readme.mjs` with the upstream default `DEFAULT_PACKS = ["brand", "spec"]` would crash on the missing pack directory. Drop `spec` from the array so the local default targets only what this repo actually ships.

Also updates the channel-doc reference in the generated README's preamble from `.impeccable.md` to `PRODUCT.md` to match the rest of the ecosystem rename.

This is a CLI-LOCAL DIVERGENCE: the file remains in the sync-prose-tooling.sh manifest but is no longer byte-equal to upstream. `bash scripts/sync-prose-tooling.sh --check` will report drift on this file until either the upstream sidecar-config migration lands (lets consumers override `DEFAULT_PACKS` without forking) or this file moves to consumer-owned alongside scripts/prose-check.sh.
RELEASES.md was carrying both the operational runbook (commands, paths, decision tables a contributor needs in front of them during a release) and the rationale behind every rule (why we branch this way, why CHANGELOG.md is generated not authored, why heredoc bodies are banned, etc). At 396 lines, the runbook had become hard to scan during an actual release because the WHY paragraphs sat between the WHAT commands.

Split into two files:

- RELEASES.md (95 lines): runbook only. Branching table, daily dev flow, PR body shape, release-dev-to-main steps, tag/publish commands, prose-scrub procedure, branch protection setup, required secrets table. Each section ends with a `→ Rationale: [RELEASES-RATIONALE.md § ...](./RELEASES-RATIONALE.md#anchor)` pointer.
- RELEASES-RATIONALE.md (243 lines, new): all the WHY content. Branching model, PR body conventions, triple-diff verification (including false-positive triage), CHANGELOG generation, release pipeline, spec-vendor pipeline, prose-scrubbing scope, branch protection pitfalls.

No process change; reorganization only. Existing cross-repo references to RELEASES.md keep working (the operational steps stay at the same headings); deeper rationale references move to RELEASES-RATIONALE.md and the section pointers route readers there.
Adds repo-local contributing guide for `agentnative-cli`. Codifies the three-tier intake (signal / proposal / code), routes principle-level discussion to the spec repo, points dev-setup at the existing scripts, names the test gates, and surfaces the branch model + commit conventions without duplicating the deeper RELEASES.md / RELEASES-RATIONALE.md content (links instead).

Issue templates added in a separate commit reference this file as the procedural authority. The cross-repo navigation entry at anc.dev/contribute remains the visitor-facing landing page; this file is the in-repo procedural reference.
Adds `.github/ISSUE_TEMPLATE/add-tool-to-registry.yml` for proposing a CLI tool for inclusion in the anc100 registry + leaderboard at anc.dev/scorecards. The template names the canonical path (issue → triage → PR against `src/principles/registry.rs`) and routes spec-level feedback ("the spec got it wrong here") to the spec repo's `grading-finding` template so the two pressure-test paths stay separated.

Updates the surrounding issue-intake surface to match:

- `.github/ISSUE_TEMPLATE/00-blank.yml`: the structured-template list now names tool-registry submissions; the wrong-repo block names `brettdavies/agentnative-skill` as a fourth destination; the CONTRIBUTING.md link points at this repo's copy now that one exists.
- `.github/ISSUE_TEMPLATE/config.yml`: adds the skill repo as a cross-repo navigation entry; renames "CLI grading" to "grading findings" to align with the spec repo's terminology.
After the recent commits landed, `bash scripts/prose-check.sh --vale-only` was reporting five blocking findings:

- `runbook` (Vale.Spelling, three occurrences across RELEASES.md and RELEASES-RATIONALE.md): legitimate dev jargon, missing from the CLI vocab. Added to styles/config/vocabularies/cli/accept.txt.
- `resolve_host` (Vale.Spelling, RELEASES-RATIONALE.md): Rust identifier appearing in prose without backticks. Backtick-wrapped the surrounding identifier list `SkillHost / KNOWN_HOSTS / resolve_host` so vale masks them as code spans.
- `sha` lowercase (Vale.Spelling, scripts/SYNCS.md): should be capitalized `SHA`. Fixed in place.

Prose-check now exits 0 blocking on the active markdown surface. The 87 warnings are stylistic (write-good.Passive, write-good.TooWordy, proselint.Typography) and non-blocking by design.
The previous commit landed a CLI-LOCAL adaptation in `scripts/generate-pack-readme.mjs` (dropped `spec` from `DEFAULT_PACKS` since this repo doesn't vendor `styles/spec/`). That file remains in the sync manifest so future universal changes still flow down, but byte-equivalence against upstream is no longer the invariant.

Mirrors the pattern the un-vendor commit used for `scripts/prose-check.sh` before that file left the manifest entirely: add a guard at the top of `check_blob` that returns early for the CLI-local file, with an inline comment naming the divergence. `bash scripts/sync-prose-tooling.sh --check` now exits 0 against upstream `main` HEAD; universal pipeline changes to the generator still arrive via re-sync + manual diff review.
…les helper

Replaces the inline LanguageTool reachability probe, per-file POST loop, category whitelist, and per-rule denylist with calls to `lt_check` from `~/dotfiles/config/shell/languagetool.sh`. Cuts ~85 lines from prose-check.sh and pulls the LT integration to a single source of truth that the prose-check stack across spec, site, cli, and skill can all consume.

The shared helper defines `LT_DENY_RULES_BASELINE` (10 rules covering RFC 2119 modal-verb false positives, parenthetical-subject agreement misfires, and CLI-domain noun lexicon gaps); consumers extend it via `LT_DENY_RULES="${LT_DENY_RULES_BASELINE}|EXTRA_RULE"`. Category whitelist `^(TYPOS|GRAMMAR|CONFUSED_WORDS)$` and exit-code contract (0/1 findings, 2 skip, other unexpected) also live in the helper.

prose-check.sh fails fast with exit 2 if `$LT_LIB` is missing, so a contributor without the dotfiles checkout gets a clear pointer to brettdavies/dotfiles rather than a confusing sourcing error.
LanguageTool's A_INFINITIVE rule flagged "the include! macro" as ungrammatical (verb "include" after article "the"). Backticking `include!` masks the identifier as a code span so both Vale and LT skip it. Pre-existing finding; surfaced now that prose-check runs the full Vale + LT pipeline rather than `--vale-only` in this session's earlier sweeps.
Counterpart to the LanguageTool extraction (commit 3ac58a7). The prose-scrub procedure in RELEASES.md previously documented a raw `curl + jaq` invocation against `$LANGUAGETOOL_URL/v2/check` with an inline category filter. After scripts/prose-check.sh moved to calling `lt_check` from `~/dotfiles/config/shell/languagetool.sh`, the contributor-facing scrub flow should use the same helper. Updates step 3 to `lt_check /tmp/body.md` and points readers at `lt_rules`/`lt_info` for inspection plus the spec repo's voice-enforcement contributing notes for the install-vs-required nuance.
@brettdavies brettdavies merged commit 434e546 into dev May 21, 2026
7 checks passed
@brettdavies brettdavies deleted the feat/prose-pipeline-and-doc-hygiene branch May 21, 2026 16:54
brettdavies added a commit that referenced this pull request May 21, 2026
…tmatter; fix badge slug + P8 filter (#54)

## Summary

Closes the dogfood gaps surfaced by `anc check .` at the v0.4.0 release
candidate, plus the silent slug-derivation bug
behind the scorecard's badge URLs. Self-check after this branch: 44
checks, 37 pass, 3 warn, 0 fail, 0 error. Score 93%
(up from 85% at the v0.4.0 RC).

## Changelog

### Added

- Add `anc schema` top-level subcommand. Prints the embedded JSON Schema
(draft 2020-12) describing the shape of `anc check --output json`
scorecards. Closes the `p2-must-schema-print` FAIL surfaced by
self-check.
- Add `schema/scorecard.schema.json` committed at the repo root and
embedded into the binary via `include_str!`. Hand-written coverage of
the 0.5 shape (Scorecard plus ToolInfo, AncInfo, RunInfo, PlatformInfo,
TargetInfo, BadgeInfo, LevelCounts, CoverageSummary, Summary,
CheckResultView). Closes the `p2-should-schema-file` WARN.
- Add YAML frontmatter to `AGENTS.md` naming the tool, binary,
description, homepage, and repository so agent runtimes can index the
bundle. Closes the `p8-should-bundle-exists` WARN.

### Changed

- `derive_tool_name` now follows the four-tier fallback chain
`command_name -> binary basename -> manifest package name -> directory
basename`. The old shape returned the project directory basename,
producing 404-bound badge URLs for any tool whose registry slug differed
from its directory name. `anc check .` now emits `badge_url:
https://anc.dev/badge/anc.svg` (HTTP 200, matches the site's
`registry.yaml`).
- `matches_principle` gains the `(CheckGroup::P8, 8)` arm. Pre-fix,
`--principle 8` silently filtered out every P8 check because the match
table predated the new principle.
- README refreshed for v0.4.0: principle count 7 -> 8 with a P8 row,
"Example Output" rewritten against the current 44-check self-check (P2
schema, P6 standard-names + SIGTERM, P8 bundle results), "Three Check
Layers" lists Python alongside Rust under Source, JSON sample dropped
the stale `anc.commit` field. README em-dash density scrubbed from
20.5/1000 to 0/1000.
- README "Reporting issues" section folded into "Contributing" as a
three-tier intake (signal / proposal / code) that points at the shipped
`CONTRIBUTING.md` for the full breakdown. Cross-repo routing preserved.

### Documentation

- Update `--principle <PRINCIPLE>` doc from `(1-7)` to `(1-8)` in both
README and `src/cli.rs`.

## Type of Change

- [x] `feat`: New feature (non-breaking change which adds functionality)

## Related Issues/Stories

- Story: n/a
- Issue: n/a
- Architecture: Schema follow-up plan on `dev` at
`docs/plans/2026-04-30-002-feat-scorecard-json-schema-plan.md` (full
schemars-derive implementation; this PR ships the hand-written first
cut).
- Related PRs: #50, #51, #52, #53

## Testing

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

**Test Summary:**

- New `src/main.rs::tests` module covers all four tiers of
`derive_tool_name_inner` (command, binary, `Cargo.toml` manifest,
`pyproject.toml` manifest, directory fallback).
- `cargo test`: 593 passed, 2 ignored across 7 suites.
- `cargo clippy --release --all-targets -- -Dwarnings`: clean.
- `cargo fmt --check`: clean.
- `./target/release/anc check .`: 44 checks, 37 pass, 3 warn, 0 fail, 4
skip, 0 error. Score 93%.
- Live URL probe: `https://anc.dev/badge/anc.svg` returns 200.

## Files Modified

**Modified:**

- `AGENTS.md`, `README.md`, `src/cli.rs`, `src/main.rs`.
- All five `completions/anc.*` files (regenerated for the new `schema`
subcommand).

**Created:**

- `schema/scorecard.schema.json`.

**Renamed:**

- None.

**Deleted:**

- None.

## Breaking Changes

- [x] No breaking changes

## Deployment Notes

- [x] No special deployment steps required. After merge to `dev`,
cherry-pick the squash commit onto `release/v0.4.0` (PR #53) and
regenerate `CHANGELOG.md` before the release tag.
brettdavies added a commit that referenced this pull request May 21, 2026
…tmatter; fix badge slug + P8 filter (#54)

## Summary

Closes the dogfood gaps surfaced by `anc check .` at the v0.4.0 release
candidate, plus the silent slug-derivation bug
behind the scorecard's badge URLs. Self-check after this branch: 44
checks, 37 pass, 3 warn, 0 fail, 0 error. Score 93%
(up from 85% at the v0.4.0 RC).

## Changelog

### Added

- Add `anc schema` top-level subcommand. Prints the embedded JSON Schema
(draft 2020-12) describing the shape of `anc check --output json`
scorecards. Closes the `p2-must-schema-print` FAIL surfaced by
self-check.
- Add `schema/scorecard.schema.json` committed at the repo root and
embedded into the binary via `include_str!`. Hand-written coverage of
the 0.5 shape (Scorecard plus ToolInfo, AncInfo, RunInfo, PlatformInfo,
TargetInfo, BadgeInfo, LevelCounts, CoverageSummary, Summary,
CheckResultView). Closes the `p2-should-schema-file` WARN.
- Add YAML frontmatter to `AGENTS.md` naming the tool, binary,
description, homepage, and repository so agent runtimes can index the
bundle. Closes the `p8-should-bundle-exists` WARN.

### Changed

- `derive_tool_name` now follows the four-tier fallback chain
`command_name -> binary basename -> manifest package name -> directory
basename`. The old shape returned the project directory basename,
producing 404-bound badge URLs for any tool whose registry slug differed
from its directory name. `anc check .` now emits `badge_url:
https://anc.dev/badge/anc.svg` (HTTP 200, matches the site's
`registry.yaml`).
- `matches_principle` gains the `(CheckGroup::P8, 8)` arm. Pre-fix,
`--principle 8` silently filtered out every P8 check because the match
table predated the new principle.
- README refreshed for v0.4.0: principle count 7 -> 8 with a P8 row,
"Example Output" rewritten against the current 44-check self-check (P2
schema, P6 standard-names + SIGTERM, P8 bundle results), "Three Check
Layers" lists Python alongside Rust under Source, JSON sample dropped
the stale `anc.commit` field. README em-dash density scrubbed from
20.5/1000 to 0/1000.
- README "Reporting issues" section folded into "Contributing" as a
three-tier intake (signal / proposal / code) that points at the shipped
`CONTRIBUTING.md` for the full breakdown. Cross-repo routing preserved.

### Documentation

- Update `--principle <PRINCIPLE>` doc from `(1-7)` to `(1-8)` in both
README and `src/cli.rs`.

## Type of Change

- [x] `feat`: New feature (non-breaking change which adds functionality)

## Related Issues/Stories

- Story: n/a
- Issue: n/a
- Architecture: Schema follow-up plan on `dev` at
`docs/plans/2026-04-30-002-feat-scorecard-json-schema-plan.md` (full
schemars-derive implementation; this PR ships the hand-written first
cut).
- Related PRs: #50, #51, #52, #53

## Testing

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

**Test Summary:**

- New `src/main.rs::tests` module covers all four tiers of
`derive_tool_name_inner` (command, binary, `Cargo.toml` manifest,
`pyproject.toml` manifest, directory fallback).
- `cargo test`: 593 passed, 2 ignored across 7 suites.
- `cargo clippy --release --all-targets -- -Dwarnings`: clean.
- `cargo fmt --check`: clean.
- `./target/release/anc check .`: 44 checks, 37 pass, 3 warn, 0 fail, 4
skip, 0 error. Score 93%.
- Live URL probe: `https://anc.dev/badge/anc.svg` returns 200.

## Files Modified

**Modified:**

- `AGENTS.md`, `README.md`, `src/cli.rs`, `src/main.rs`.
- All five `completions/anc.*` files (regenerated for the new `schema`
subcommand).

**Created:**

- `schema/scorecard.schema.json`.

**Renamed:**

- None.

**Deleted:**

- None.

## Breaking Changes

- [x] No breaking changes

## Deployment Notes

- [x] No special deployment steps required. After merge to `dev`,
cherry-pick the squash commit onto `release/v0.4.0` (PR #53) and
regenerate `CHANGELOG.md` before the release tag.
brettdavies added a commit that referenced this pull request May 21, 2026
## Summary

Cuts v0.4.0 by cherry-picking four PRs from `dev`: #50 (spec sync, 11
new requirement IDs across P1/P2/P4/P6/P8), #51
(binary-discovery mtime fix), #52 (prose pipeline import + un-vendor of
orchestrator + doc-hygiene pass), and #54
(post-RC dogfood fixes that lift score from 85% to 93%). Adds an entire
new principle (P8 Discoverable Skill Bundle), a
P1 secret-handling check, the `anc schema` subcommand backing P2's
runtime-discoverable-schema MUST, and a fix for the
silent badge-slug bug uncovered during release polish.

## Changelog

### Added

- Add P1 secret-handling check (`p1-must-secret-non-leaky-path`): scans
target CLIs' `--help` for secret-bearing flag families (`--token`,
`--password`, `--api-key`, `--secret`, `--auth`, `--credential`) and
verifies each has either a `--*-file` companion or stdin path
advertised. Vacuous Pass when no secret-bearing flag is detected.
- Add P2 schema trio (`p2-must-schema-print`, `p2-should-schema-file`,
`p2-should-json-aliases`): runtime-discoverable output schema via
`schema` subcommand or `--schema` flag, file-export of schemas
(`schema/*.json`, `*.schema.json` at repo root), and `--json` /
`--jsonl` short aliases for `--output`.
- Add P4 closed-set rejection check (`p4-should-enumerate-valid-set`,
Rust + Python): detects clap `ValueEnum`, `PossibleValuesParser`,
`value_parser!`, and Python `argparse.choices=` / `click.Choice()`.
- Add P6 lifecycle and naming checks (`p6-must-sigterm`, Rust + Python;
`p6-may-standard-names`): SIGTERM-handler detection across
`signal_hook`, `tokio::signal::unix`, `signal.signal`, and
`loop.add_signal_handler`; community-standard-verb allow-list applied to
top-level subcommands.
- Add P8 skill-bundle suite (`p8-should-bundle-exists`,
`p8-must-bundle-install`, `p8-may-install-all`, `p8-may-bundle-update`):
repo-root detection of `AGENTS.md` / `SKILL.md` with YAML frontmatter,
plus help-surface probes for `skill install`, `skill install --all`, and
`skill update` / `skill upgrade`. Brand-new principle in the registry.
- Add `anc schema` top-level subcommand. Prints the embedded JSON Schema
(draft 2020-12) describing the shape of `anc check --output json`
scorecards. Closes the `p2-must-schema-print` FAIL surfaced by `anc
check .` self-check.
- Add `schema/scorecard.schema.json` committed at the repo root and
embedded into the binary via `include_str!`. Hand-written coverage of
the 0.5 shape (Scorecard plus ToolInfo, AncInfo, RunInfo, PlatformInfo,
TargetInfo, BadgeInfo, LevelCounts, CoverageSummary, Summary,
CheckResultView). Closes the `p2-should-schema-file` WARN.
- Add YAML frontmatter to `AGENTS.md` naming the tool, binary,
description, homepage, and repository so agent runtimes can index the
bundle. Closes the `p8-should-bundle-exists` WARN.

### Changed

- Bump CLI from 0.3.1 to 0.4.0 (MINOR; meaningful coverage growth across
five principles, including a brand-new principle).
- Binary discovery in `src/project.rs::discover_rust_binaries` now picks
the newer of `target/release/<bin>` and `target/debug/<bin>` by mtime
when both exist. Ties and metadata failures fall back to debug (matches
cargo's dev-flow default). CI scenarios where only one profile is built
are unchanged.
- `RELEASES.md` slims to operational runbook; rationale moves to
companion `RELEASES-RATIONALE.md`. Each runbook section ends with a
section-pointer at the rationale.
- `derive_tool_name` now follows the four-tier fallback chain
`command_name -> binary basename -> manifest package name -> directory
basename`. The old shape returned the project directory basename,
producing 404-bound badge URLs for any tool whose registry slug differed
from its directory name. `anc check .` now emits `badge_url:
https://anc.dev/badge/anc.svg` (HTTP 200, matches the site's
`registry.yaml`).
- `matches_principle` gains the `(CheckGroup::P8, 8)` arm. Pre-fix,
`--principle 8` silently filtered out every P8 check because the match
table predated the new principle.
- README refreshed for v0.4.0: principle count 7 -> 8 with a P8 row,
"Example Output" rewritten against the current 44-check self-check (P2
schema, P6 standard-names + SIGTERM, P8 bundle results), "Three Check
Layers" lists Python alongside Rust under Source, JSON sample dropped
the stale `anc.commit` field. README em-dash density scrubbed from
20.5/1000 to 0/1000.
- README "Reporting issues" section folded into "Contributing" as a
three-tier intake (signal / proposal / code) that points at the shipped
`CONTRIBUTING.md`. Cross-repo routing preserved.

### Documentation

- New `PRODUCT.md` at repo root codifies linter-channel voice:
second-person imperative register, three-part error shape (what failed,
why, what to do), no marketing voice in CLI surface. Inherits universal
rules from vendored `BRAND.md`.
- New `CONTRIBUTING.md` documents the three-tier intake (signal /
proposal / code), routes principle-level discussion to the spec repo,
and names the dev-setup gates.
- New `add-tool-to-registry` issue template for proposing CLI tools to
the anc100 registry.
- Document prose-scrubbing runbook in `RELEASES.md` for release-flow
artifacts using Vale + LanguageTool + unslop.
- `AGENTS.md` gains a "Voice and prose rules" section pointing at
`PRODUCT.md` for the linter-channel register and
`scripts/prose-check.sh` for the local gate.
- `scripts/SYNCS.md` documents the new `sync-prose-tooling.sh` row and
the consumer-owned status of `scripts/prose-check.sh`.
- Update `--principle <PRINCIPLE>` doc from `(1-7)` to `(1-8)` in both
README and `src/cli.rs`.

## Type of Change

- [x] `feat`: New feature (non-breaking change which adds functionality)

## Related Issues/Stories

- Story: n/a
- Issue: n/a
- Architecture: Spec sync to `agentnative-spec@v0.4.0` (vendored at
`src/principles/spec/`). Scorecard JSON Schema
follow-up plan lives on `dev` at
`docs/plans/2026-04-30-002-feat-scorecard-json-schema-plan.md` (full
schemars-derive
  implementation; this release ships the hand-written first cut).
- Related PRs: #50, #51, #52, #54

## Testing

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

**Test Summary:**

- CI green on each upstream PR (#50, #51, #52, #54) prior to dev merge.
- Triple-diff verification on release branch: ship surface matches
expected; no missed picks outside `docs/`; phantom-commit count
consistent with prior squash-merge history.
- `cargo test`: 593 passed, 2 ignored across 7 suites. New
`src/main.rs::tests` module covers all four tiers of
`derive_tool_name_inner` (command, binary, `Cargo.toml` manifest,
`pyproject.toml` manifest, directory fallback).
- `cargo clippy --release --all-targets -- -Dwarnings`: clean.
- `cargo fmt --check`: clean.
- `cargo run -- generate coverage-matrix --check`: exits 0 against the
committed artifacts.
- `bash scripts/sync-skill-fixture.sh --check`: confirms fixture matches
`agentnative-site@dev` head (`4efa8ec`).
- `./target/release/anc check .`: 44 checks, 37 pass, 3 warn, 0 fail, 4
skip, 0 error. Score 93%.
- Live URL probe: `https://anc.dev/badge/anc.svg` returns 200.
- Local pre-push hook (fmt, clippy `-Dwarnings`, test, cargo-deny,
Windows compatibility check) passes.

## Files Modified

**Modified:**

- `Cargo.lock`, `CHANGELOG.md`, `AGENTS.md`, `CLAUDE.md`, `README.md`,
`RELEASES.md`, `Cargo.toml`, `coverage/matrix.json`,
`docs/coverage-matrix.md`, `scripts/SYNCS.md`.
- `src/cli.rs`, `src/main.rs`, `src/principles/registry.rs`,
`src/project.rs`, `src/scorecard/mod.rs`, `src/types.rs`.
- `src/checks/{behavioral,project,source/{python,rust}}/mod.rs`.
- `src/principles/spec/CHANGELOG.md`, `src/principles/spec/VERSION`,
`src/principles/spec/principles/p1-p7*.md`.
- All five `completions/anc.*` files.
- `.github/ISSUE_TEMPLATE/{00-blank.yml,config.yml}`, `.gitignore`.
- `tests/build_parser.rs`, `tests/dogfood.rs`.

**Created:**

- `BRAND.md`, `PRODUCT.md`, `CONTRIBUTING.md`, `RELEASES-RATIONALE.md`,
`.vale.ini`.
- `.github/ISSUE_TEMPLATE/add-tool-to-registry.yml`.
- `scripts/prose-check.sh`, `scripts/sync-prose-tooling.sh`,
`scripts/generate-pack-readme.mjs`, `scripts/test-prose-check.mjs`.
- `schema/scorecard.schema.json`.
-
`src/checks/behavioral/{bundle_install,bundle_update,install_all,json_aliases,schema_print,secret_non_leaky_path,standard_names}.rs`.
- `src/checks/project/{bundle_exists,schema_file}.rs`.
- `src/checks/source/python/{enumerate_valid_set,sigterm}.rs`,
`src/checks/source/rust/{enumerate_valid_set,sigterm}.rs`.
- `src/principles/spec/principles/p8-discoverable-skill-bundle.md`.
- `styles/brand/{FillerAdjectives,HedgeWords,MarketingRegister}.yml`,
`styles/brand/README.md`.
- `styles/config/vocabularies/{brand,cli}/{accept,reject}.txt`.

**Renamed:**

- None.

**Deleted:**

- None.

## Breaking Changes

- [x] No breaking changes

## Deployment Notes

- [x] No special deployment steps required. After merge: tag `v0.4.0`,
push, then run `./scripts/sync-dev-after-release.sh v0.4.0` to backport
release artifacts to `dev`.
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