Skip to content

refactor: enforce check_x → CheckStatus convention + toolchain supply-chain pin - #17

Merged
brettdavies merged 6 commits into
devfrom
refactor/check-status-convention
Apr 16, 2026
Merged

refactor: enforce check_x → CheckStatus convention + toolchain supply-chain pin#17
brettdavies merged 6 commits into
devfrom
refactor/check-status-convention

Conversation

@brettdavies

@brettdavies brettdavies commented Apr 16, 2026

Copy link
Copy Markdown
Owner

Summary

Two related hardening efforts bundled:

  1. Convention enforcement: standardizes all source checks on a single pattern (check_x() returns CheckStatus;
    run() is the sole CheckResult constructor, using self.id()/self.group()/self.layer()). Documents the
    convention in CLAUDE.md, refactors all 16 Rust source checks to match, and adds a Rust-only integration test that
    walks the source tree and fails CI if any check_x() still returns CheckResult.
  2. Toolchain supply-chain pin: rust-toolchain.toml now pins to a specific X.Y.Z release with a trailing rustc
    commit-SHA comment. Rustup verifies component SHA256s from the distribution manifest, so the pin is effectively a
    SHA pin (the manifest is the toolchain's lockfile). Both local and CI read the same file and install identical
    bits. Motivated by a CI-only clippy failure during this PR's own review: local clippy 1.94 passed a lint that CI
    clippy 1.95 rejected.

Convention enforcement was identified during the PR #15 code review.
The 3 new Python checks were fixed in that PR, but the 16 existing Rust checks still used the old pattern. The
toolchain pin was added mid-review after the clippy divergence exposed that floating channel = "stable" leaves
local and CI on different rustc versions.

Changelog

Type of Change

  • refactor: Code refactoring (no functional changes)
  • chore: Maintenance tasks (supply-chain toolchain pin)
  • docs: Documentation update (CLAUDE.md conventions + toolchain policy)
  • test: Adding or updating tests (convention enforcement test)

Related Issues/Stories

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • All tests passing

Test Summary:

  • Unit tests: 304 passing (unchanged count; refactor preserves behavior)
  • Integration tests: 39 passing (+1 new: convention_check_x_returns_check_status_not_check_result)
  • Clippy: clean with -Dwarnings on rustc 1.94.1 (pinned)

Files Modified

Modified:

  • CLAUDE.md: added Source Check Convention section (Tier 1) and Toolchain Pin section documenting the 7-day
    quarantine policy
  • rust-toolchain.toml: pinned channel = "1.94.1" with trailing comment naming the rustc commit SHA and release
    date; bumped from floating channel = "stable"
  • scripts/hooks/pre-push: removed rustup update stable step; pin + rustup's manifest verification now handle
    toolchain integrity
  • 16 files in src/checks/source/rust/: check_x() returns CheckStatus, run() uses self.id()/self.group()/
    self.layer() instead of duplicated string/enum literals
  • src/checks/source/rust/no_pager.rs: collapsed nested if inside a match arm into a match guard (fixes clippy
    collapsible_match lint introduced in clippy 1.95)
  • tests/integration.rs: added convention_check_x_returns_check_status_not_check_result enforcement test

Key Details

Tier 1 (Document): CLAUDE.md now codifies the source check structure. Covers the Check trait impl shape, the
check_x() → CheckStatus separation, and the convention that run() is the sole CheckResult constructor. Also adds
a new Toolchain Pin section explaining the supply-chain pin policy.

Tier 2 (Refactor): All 16 Rust source checks aligned to the convention. Net -132 lines by removing duplicated
CheckResult construction (previously the id / label / group / layer fields were hardcoded in both run()
and every check_x() helper).

Tier 3 (Enforce): Integration test walks src/checks/source/ with std::fs (no shell dependencies), finds every
fn check_ signature (any visibility, single-line or multi-line), and fails if any return CheckResult instead of
CheckStatus. Uses CARGO_MANIFEST_DIR for a stable absolute path.

Toolchain pin format: channel = "1.94.1" # rustc e408947bfd200af42db322daf0fadfe7e26d3bd1, released 2026-03-25.
Comment mirrors the GitHub Actions SHA-pin pattern (action@<sha> # vN.N.N). Policy: bump only via reviewed PR after
the new stable has aged ≥7 days (supply-chain quarantine consistent with UV_EXCLUDE_NEWER / bun
minimumReleaseAge / npm_config_min_release_age in dotfiles).

Benefits

  • Eliminates ID string literal triplication (3 copies per check → 1 authoritative source in fn id())
  • New checks can't drift; the convention is documented AND enforced by CI
  • -132 lines of boilerplate removed
  • Local and CI toolchains are guaranteed identical: no more "local clippy older than CI clippy" false greens
  • Toolchain updates route through reviewed PRs with a 7-day quarantine, matching the broader brettdavies supply-chain
    posture

Breaking Changes

  • No breaking changes

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

…checks

Tier 1: Document the Source Check Convention in CLAUDE.md — check_x()
returns CheckStatus (not CheckResult), run() is the sole CheckResult
constructor using self.id()/self.group()/self.layer().

Tier 2: Apply the convention to all 16 Rust source checks. Each check_x()
function now returns CheckStatus directly, eliminating ID/group/layer
string literal triplication. Net -132 lines.

Tier 3: Add convention_check_x_returns_check_status_not_check_result
integration test that greps source check files for the old pattern and
fails if any check_x() still returns CheckResult.
Rewrite convention_check_x_returns_check_status_not_check_result as
pure Rust using std::fs. The previous implementation shelled out to rg
which is not available in GitHub Actions runners, causing the test to
panic with "No such file or directory" and blocking all CI runs.

The new implementation:
- Uses CARGO_MANIFEST_DIR for a stable absolute path (no CWD fragility)
- Walks src/checks/source/ recursively with only std::fs
- Catches all visibility modifiers (pub, pub(crate), pub(super), private)
- Handles multi-line signatures by accumulating text until the opening {
- Reports specific file:line:code references on failure

Also corrects CLAUDE.md Source Check Convention claims:
- check_x() signature is (source: &str) or (source: &str, file: &str)
- "Every" → "Most" with noted exceptions for output_module.rs and
  error_types.rs which use different helper shapes
clippy 1.95 flags the nested `if` inside `CheckStatus::Pass =>` as
collapsible. Use a match guard instead. Local toolchain was 1.94 so
the lint didn't fire pre-push — ran into this as a CI-only failure.
Run `rustup update stable --no-self-update` before the other checks so
local clippy/rustc match what CI will use. CI reinstalls stable on
every run, so if the local toolchain is behind, a newer lint can fail
CI while pre-push reports green — exactly what happened with the
collapsible_match lint that landed in clippy 1.95.

Fast no-op when already current; takes a few seconds on first push
after a new stable release.
Pin rust-toolchain.toml to a specific release instead of floating
`stable`. Rustup verifies component SHA256s from the distribution
manifest — the version pin is effectively a SHA pin. Trailing comment
documents the rustc commit SHA for audit, mirroring the GitHub Actions
pin pattern (action@<sha> # vN.N.N).

Both local and CI now read rust-toolchain.toml and install identical
bits. Removes the pre-push rustup-update hook introduced earlier in
this branch — pinning is the right fix, not runtime sync.

Policy: bump the channel only via reviewed PR, after the new stable
has aged ≥7 days. This matches the UV_EXCLUDE_NEWER / bun
minimumReleaseAge / npm_config_min_release_age quarantine already in
dotfiles, and guards against the `tj-actions/changed-files`-class
supply-chain attack on the toolchain itself.
@brettdavies
brettdavies merged commit 07091e2 into dev Apr 16, 2026
6 checks passed
@brettdavies
brettdavies deleted the refactor/check-status-convention branch April 16, 2026 17:08
brettdavies referenced this pull request in brettdavies/bird Apr 16, 2026
## Summary

Pin `rust-toolchain.toml` to a specific `X.Y.Z` release with a trailing
rustc commit-SHA comment, replacing the
floating `channel = "stable"`. Rustup verifies component SHA256s from
the distribution manifest, so the version pin is
effectively a SHA pin (the manifest is the toolchain's lockfile). Both
local and CI now read the same file and install
identical bits.

Mirrors the pattern just shipped in [`agentnative` PR
#17](brettdavies/agentnative#17), which
was motivated by a real CI-only clippy failure during PR review: local
clippy 1.94 passed a lint that CI clippy 1.95
rejected because `channel = "stable"` let rustc drift between
environments.

## Changelog

<!-- No user-facing changes — supply-chain hardening only. -->

## Type of Change

- [x] `chore`: Maintenance tasks (supply-chain toolchain pin)

## Related Issues/Stories

- Related PRs:
[brettdavies/agentnative#17](brettdavies/agentnative#17)
— pattern source

## Testing

- [x] All tests passing

**Test Summary:**

- Unit tests: 185 passing
- Integration tests: 38 + 14 = 52 passing
- Live integration tests: 1 ignored (requires live X API)
- Clippy: clean with `-Dwarnings` on rustc 1.94.1 (pinned)
- Fmt: clean
- Pre-push hook: passed (fmt, clippy, test, windows compat)

## Files Modified

**Modified:**

- `rust-toolchain.toml` — pinned `channel = "1.94.1"` with trailing
comment naming the rustc commit SHA and release
date; bumped from floating `channel = "stable"`. Added 4 lines of header
comments documenting the supply-chain
  rationale and the ≥7-day quarantine policy.

## Key Details

**Toolchain pin format:** `channel = "1.94.1" # rustc
e408947bfd200af42db322daf0fadfe7e26d3bd1, released 2026-03-25`.
Comment mirrors the GitHub Actions SHA-pin pattern (`action@<sha> #
vN.N.N`).

**Policy:** bump the channel only via reviewed PR, after the new stable
has aged ≥7 days. Matches the broader
brettdavies supply-chain posture (`UV_EXCLUDE_NEWER`, bun
`minimumReleaseAge`, `npm_config_min_release_age` already
in dotfiles).

**MSRV compatibility:** bird's `rust-version = "1.87"`; 1.94.1 satisfies
it comfortably.

**No hook / workflow changes needed:** neither `scripts/hooks/pre-push`,
`.githooks/pre-push`, nor any
`.github/workflows/*.yml` file references `rustup update` or pins a
specific toolchain version — rustup reads
`rust-toolchain.toml` automatically on every `cargo` invocation, so the
single-file change is sufficient.

## Benefits

- Local and CI toolchains are guaranteed identical — no more "local
clippy older than CI clippy" false greens
- Toolchain updates route through reviewed PRs with a 7-day quarantine
- Consistent with the supply-chain-pin pattern applied across
brettdavies repos (GitHub Actions SHA pins, Docker image
  digest pins, package-manager lockfiles)

## Breaking Changes

- [x] No breaking changes

## Deployment Notes

- [x] No special deployment steps required

## Checklist

- [x] Code follows project conventions and style guidelines
- [x] Commit messages follow [Conventional
Commits](https://www.conventionalcommits.org/)
- [x] Self-review of code completed
- [x] No new warnings or errors introduced
- [x] Changes are backward compatible
brettdavies referenced this pull request in brettdavies/xurl-rs Apr 16, 2026
## Summary

Pins `rust-toolchain.toml` to a specific `X.Y.Z` release instead of
floating `channel = "stable"`. Rustup verifies
component SHA256s from the distribution manifest, so the version pin is
effectively a SHA pin (the manifest is the
toolchain's lockfile). Trailing comment documents the rustc commit SHA
for audit, mirroring the GitHub Actions
SHA-pin pattern (`action@<sha> # vN.N.N`).

Both local and CI now read `rust-toolchain.toml` and install identical
bits. Prevents "local clippy older than CI
clippy" drift.

Matches the pattern applied in [agentnative PR
#17](brettdavies/agentnative#17).

## Changelog

<!-- No user-facing changes — supply-chain hardening + CI reliability.
-->

## Type of Change

- [x] `chore`: Maintenance task (supply-chain toolchain pin)

## Testing

- [x] All tests passing
- [x] Clippy clean with `-Dwarnings`
- [x] `cargo fmt --check` clean

**Test Summary:**

- Unit tests: 17 passing (unchanged — same code, new pinned toolchain)
- Clippy: clean on rustc 1.94.1

## Policy

Bump the channel only via reviewed PR, after the new stable has aged ≥7
days. This matches the `UV_EXCLUDE_NEWER` /
bun `minimumReleaseAge` / `npm_config_min_release_age` quarantine
already in dotfiles. A central automated bump
workflow is tracked as a follow-up in `brettdavies/dot-github` todo
#4.

- [x] No breaking changes
- [x] No special deployment steps required
brettdavies referenced this pull request in brettdavies/xurl-rs Apr 16, 2026
## Summary

Pins `rust-toolchain.toml` to a specific `X.Y.Z` release instead of
floating `channel = "stable"`. Rustup verifies
component SHA256s from the distribution manifest, so the version pin is
effectively a SHA pin (the manifest is the
toolchain's lockfile). Trailing comment documents the rustc commit SHA
for audit, mirroring the GitHub Actions
SHA-pin pattern (`action@<sha> # vN.N.N`).

Both local and CI now read `rust-toolchain.toml` and install identical
bits. Prevents "local clippy older than CI
clippy" drift.

Matches the pattern applied in [agentnative PR
#17](brettdavies/agentnative#17).

## Changelog

<!-- No user-facing changes — supply-chain hardening + CI reliability.
-->

## Type of Change

- [x] `chore`: Maintenance task (supply-chain toolchain pin)

## Testing

- [x] All tests passing
- [x] Clippy clean with `-Dwarnings`
- [x] `cargo fmt --check` clean

**Test Summary:**

- Unit tests: 17 passing (unchanged — same code, new pinned toolchain)
- Clippy: clean on rustc 1.94.1

## Policy

Bump the channel only via reviewed PR, after the new stable has aged ≥7
days. This matches the `UV_EXCLUDE_NEWER` /
bun `minimumReleaseAge` / `npm_config_min_release_age` quarantine
already in dotfiles. A central automated bump
workflow is tracked as a follow-up in `brettdavies/dot-github` todo
#4.

- [x] No breaking changes
- [x] No special deployment steps required
brettdavies referenced this pull request in brettdavies/xurl-rs Apr 16, 2026
## Summary

Pins `rust-toolchain.toml` to a specific `X.Y.Z` release instead of
floating `channel = "stable"`. Rustup verifies
component SHA256s from the distribution manifest, so the version pin is
effectively a SHA pin (the manifest is the
toolchain's lockfile). Trailing comment documents the rustc commit SHA
for audit, mirroring the GitHub Actions
SHA-pin pattern (`action@<sha> # vN.N.N`).

Both local and CI now read `rust-toolchain.toml` and install identical
bits. Prevents "local clippy older than CI
clippy" drift.

Matches the pattern applied in [agentnative PR
#17](brettdavies/agentnative#17).

## Changelog

<!-- No user-facing changes — supply-chain hardening + CI reliability.
-->

## Type of Change

- [x] `chore`: Maintenance task (supply-chain toolchain pin)

## Testing

- [x] All tests passing
- [x] Clippy clean with `-Dwarnings`
- [x] `cargo fmt --check` clean

**Test Summary:**

- Unit tests: 17 passing (unchanged — same code, new pinned toolchain)
- Clippy: clean on rustc 1.94.1

## Policy

Bump the channel only via reviewed PR, after the new stable has aged ≥7
days. This matches the `UV_EXCLUDE_NEWER` /
bun `minimumReleaseAge` / `npm_config_min_release_age` quarantine
already in dotfiles. A central automated bump
workflow is tracked as a follow-up in `brettdavies/dot-github` todo
#4.

- [x] No breaking changes
- [x] No special deployment steps required
brettdavies added a commit that referenced this pull request Apr 16, 2026
…-chain pin (#17)

## Summary

Two related hardening efforts bundled:

1. **Convention enforcement** — standardizes all source checks on a
single pattern (`check_x()` returns `CheckStatus`;
`run()` is the sole `CheckResult` constructor, using
`self.id()`/`self.group()`/`self.layer()`). Documents the
convention in CLAUDE.md, refactors all 16 Rust source checks to match,
and adds a Rust-only integration test that
walks the source tree and fails CI if any `check_x()` still returns
`CheckResult`.
2. **Toolchain supply-chain pin** — `rust-toolchain.toml` now pins to a
specific `X.Y.Z` release with a trailing rustc
commit-SHA comment. Rustup verifies component SHA256s from the
distribution manifest, so the pin is effectively a
SHA pin (the manifest is the toolchain's lockfile). Both local and CI
read the same file and install identical
bits. Motivated by a CI-only clippy failure during this PR's own review:
local clippy 1.94 passed a lint that CI
   clippy 1.95 rejected.

Convention enforcement was identified during the [PR #15 code
review](#15)
— the 3 new Python checks were fixed in that PR, but the 16 existing
Rust checks still used the old pattern. The
toolchain pin was added mid-review after the clippy divergence exposed
that floating `channel = "stable"` leaves
local and CI on different rustc versions.

## Changelog

<!-- No user-facing changes — internal refactor + supply-chain
hardening. -->

## Type of Change

- [x] `refactor`: Code refactoring (no functional changes)
- [x] `chore`: Maintenance tasks (supply-chain toolchain pin)
- [x] `docs`: Documentation update (CLAUDE.md conventions + toolchain
policy)
- [x] `test`: Adding or updating tests (convention enforcement test)

## Related Issues/Stories

- Related PRs: #15 (review finding that identified the convention drift)
- Follow-up: `dot-github` todo #4 — determine the automated bump
workflow for `rust-toolchain.toml` across repos
  (central reusable workflow vs. local script vs. hybrid)

## Testing

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

**Test Summary:**

- Unit tests: 304 passing (unchanged count — refactor preserves
behavior)
- Integration tests: 39 passing (+1 new:
`convention_check_x_returns_check_status_not_check_result`)
- Clippy: clean with `-Dwarnings` on rustc 1.94.1 (pinned)

## Files Modified

**Modified:**

- `CLAUDE.md` — added Source Check Convention section (Tier 1) and
Toolchain Pin section documenting the 7-day
  quarantine policy
- `rust-toolchain.toml` — pinned `channel = "1.94.1"` with trailing
comment naming the rustc commit SHA and release
  date; bumped from floating `channel = "stable"`
- `scripts/hooks/pre-push` — removed `rustup update stable` step; pin +
rustup's manifest verification now handle
  toolchain integrity
- 16 files in `src/checks/source/rust/` — `check_x()` returns
`CheckStatus`, `run()` uses `self.id()`/`self.group()`/
  `self.layer()` instead of duplicated string/enum literals
- `src/checks/source/rust/no_pager.rs` — collapsed nested `if` inside a
`match` arm into a match guard (fixes clippy
  `collapsible_match` lint introduced in clippy 1.95)
- `tests/integration.rs` — added
`convention_check_x_returns_check_status_not_check_result` enforcement
test

## Key Details

**Tier 1 (Document):** CLAUDE.md now codifies the source check
structure. Covers the `Check` trait impl shape, the
`check_x() → CheckStatus` separation, and the convention that `run()` is
the sole `CheckResult` constructor. Also adds
a new Toolchain Pin section explaining the supply-chain pin policy.

**Tier 2 (Refactor):** All 16 Rust source checks aligned to the
convention. Net -132 lines by removing duplicated
`CheckResult` construction (previously the `id` / `label` / `group` /
`layer` fields were hardcoded in both `run()`
and every `check_x()` helper).

**Tier 3 (Enforce):** Integration test walks `src/checks/source/` with
`std::fs` (no shell dependencies), finds every
`fn check_` signature (any visibility, single-line or multi-line), and
fails if any return `CheckResult` instead of
`CheckStatus`. Uses `CARGO_MANIFEST_DIR` for a stable absolute path.

**Toolchain pin format:** `channel = "1.94.1" # rustc
e408947bfd200af42db322daf0fadfe7e26d3bd1, released 2026-03-25`.
Comment mirrors the GitHub Actions SHA-pin pattern (`action@<sha> #
vN.N.N`). Policy: bump only via reviewed PR after
the new stable has aged ≥7 days (supply-chain quarantine consistent with
`UV_EXCLUDE_NEWER` / bun
`minimumReleaseAge` / `npm_config_min_release_age` in dotfiles).

## Benefits

- Eliminates ID string literal triplication (3 copies per check → 1
authoritative source in `fn id()`)
- New checks can't drift — the convention is documented AND enforced by
CI
- -132 lines of boilerplate removed
- Local and CI toolchains are guaranteed identical — no more "local
clippy older than CI clippy" false greens
- Toolchain updates route through reviewed PRs with a 7-day quarantine,
matching the broader brettdavies supply-chain
  posture

## Breaking Changes

- [x] No breaking changes

## 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 Apr 22, 2026
Flip the Key Technical Decision on audience label serialization from
snake_case to kebab-case, update the inline string literals and the
"classify() emits snake_case label" prose, and add an Implementation
Log entry describing why the change landed post-review (the ce:review
pass flagged the mixed snake/kebab casing inside one JSON document as
P3 #17; audit_profile's kebab-case is non-negotiable, audience's
snake_case was convention-inertia, and v0.1.2 / site H6 hadn't yet
pinned on the old values).
brettdavies added a commit that referenced this pull request Apr 22, 2026
…-case (#27)

## Summary

- Applies all 26 findings from the ce-review of commit dc5d741 (P1
coverage_summary filter, P2 Check::label() trait migration, Pattern 2
extraction, P3 audience_reason / audit_profiles matrix / codified
regression tests).
- Unifies `audience` values to kebab-case (`agent-optimized` / `mixed` /
`human-primary`) post-review — closes the mixed-casing asymmetry that
ce-review P3 #17 flagged. Agentnative-site H6 plan already updated for
the pre-regen adaptation.
- 452 tests passing (402 unit + 50 integration, net +11 new). Pre-push
green (fmt, clippy -Dwarnings, test, cargo-deny, windows-compat).
Dogfood on the repo confirms kebab-case emission and suppressed-coverage
filter.

## Reviewer orientation

Big changeset (50 files), but mechanically simple once you understand
the groupings:

- **P1 fix + test:** `src/scorecard/mod.rs::build_coverage_summary` now
filters via `audience::is_audit_profile_suppression`; regression test
pins the behavior.
- **Prefix extraction:** `SUPPRESSION_EVIDENCE_PREFIX` in
`src/principles/registry.rs` is the single source of truth; consumed by
`main.rs`, `audience.rs`, and `build_coverage_summary`.
- **Label trait:** `Check::label()` added abstractly; mechanical
migration across 40 check impls. Suppressed/errored `CheckResult` now
shows the human label instead of the id.
- **Help_probe extraction:** `git mv` rename preserves blame;
`EnvHintSource` enum at parent scope so both patterns can tag their
emissions.
- **Scorecard field additions:** `audience_reason` + `audit_profiles`
matrix section + kebab-case classify() output; all additive to v1.1.
- **Codified tests:** exit_code behavior under suppression, JSON casing
contract, `CheckResult`-only-in-run() convention, Pattern 2 bracketed
rejection, duplicate-signal debug_assert, AuditProfile ↔
ExceptionCategory parity, full-shape JSON snapshot, --principle +
audience interaction.

## Test plan

- [x] `cargo fmt --check` clean
- [x] `cargo clippy --all-targets -- -Dwarnings` clean
- [x] `cargo test` 402 unit + 50 integration passing
- [x] `cargo deny check` clean
- [x] Windows compat check clean
- [x] `anc generate coverage-matrix --check` no drift
- [x] Dogfood `anc check . --output json`: `schema_version: "1.1"`,
`audience: "agent-optimized"`, `audit_profile: null`, `audience_reason`
absent
- [x] Dogfood `anc check . --audit-profile human-tui`: `audience: null`,
`audience_reason: "suppressed"`, `coverage_summary.must.verified` drops
from 17 → 15
- [x] Pre-push hook full local-CI mirror green

## Related

- Plan doc recording the post-review deviation:
`docs/plans/2026-04-21-v013-handoff-5-cli-audience-classifier.md`
(committed directly to dev as `6fdca00`)
- Site-side adaptation plan:
`agentnative-site/docs/plans/2026-04-21-v013-handoff-6-site-leaderboard-launch.md`
(Unit 0.5 covers kebab-case absorption; must land before the v0.1.3
scorecard regen wave)
- CE-review artifacts:
`.context/compound-engineering/ce-review/20260422-134229-565fc6d7/` (10
reviewer JSONs + metadata; local-only)

## Breaking changes

None for v1.1 consumers that pin on `audience: null`. v1.1 consumers
that had pinned on hypothetical snake_case audience values need to
update — the site's H6 renderer hasn't shipped, so the only such
consumer is in-house and tracked by the site-side plan.
brettdavies added a commit that referenced this pull request May 4, 2026
## Summary

Opts agentnative-cli into the two new shared-workflow inputs that landed
in `brettdavies/.github` PR #18, so future
releases ship Alpine/musl artifacts. No source changes; the binary is
identical to v0.3.0.

After this PR merges (and ships via a `release/v0.3.1` cherry-pick to
`main`), every release will produce 7 archives
instead of 5 — adding `agentnative-x86_64-unknown-linux-musl.tar.gz` and
`agentnative-aarch64-unknown-linux-musl.tar.gz`. Alpine and other
musl-libc-host distros gain a first-class install path
beyond `cargo install` and the existing glibc Linux artifact.

Bundled: a small `RELEASES.md` polish that was already dirty in the
working tree (cliff.toml chore-skip warning + "never
hand-written" rule under `Releasing dev to main`), plus the necessary 5
→ 7 target table update.

## Changelog

### Added

- Ship `x86_64-` and `aarch64-unknown-linux-musl` static binaries on
every release. Statically linked against musl libc,
so they run on Alpine and other musl-libc-host distros without glibc,
and on every glibc distro too.

### Documentation

- Document the `cliff.toml` chore-skip footgun and the "CHANGELOG is
generated, never hand-written" rule in
`RELEASES.md` under `Releasing dev to main`. Adds a new review step
(renumbered to 9) and tightens the existing "PRs
  and changelog generation" section.

## Type of Change

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

## Related Issues/Stories

- Story: n/a
- Issue: n/a
- Architecture: n/a
- Related PRs: brettdavies/.github#17 (shared workflow musl rows +
soft-fail input), brettdavies/.github#18 (release of
#17 to main). agentnative-cli `spike/musl-build` (throwaway) was the
validation surface.

## Testing

- [x] Manual testing completed
- [x] All tests passing

**Test Summary:**

- Unit tests: n/a (workflow opt-in only; no Rust source change)
- Integration tests: n/a
- Coverage: n/a

End-to-end validation completed in the throwaway `spike/musl-build`
workflow before either upstream or this PR opened:

- `cross build --release --locked --target x86_64-unknown-linux-musl` —
green, ~1m45s, statically linked
- `cross build --release --locked --target aarch64-unknown-linux-musl` —
green, ~1m45s, statically linked
- `file target/.../release/anc` matched `statically linked` for both
arches
- x86_64 host smoke test (`anc --version`) — `anc 0.3.0`
- Belt-and-suspenders: `docker run --rm --pull always -v
$PWD/target/.../release:/musl-bin:ro alpine:latest
/musl-bin/anc --version` — `anc 0.3.0`. Confirms exec compatibility with
musl-libc host (Alpine), not just static
  linkage.

`actionlint` clean on the modified `release.yml`. The pre-push hook
(`scripts/hooks/pre-push`: fmt, clippy `-Dwarnings`,
test, cargo-deny, Windows compat) passed.

## Files Modified

**Modified:**

- `.github/workflows/release.yml` — passes `linux_musl_required: true`
and `linux_musl_verify_alpine: true` to the
  shared `rust-release.yml` workflow.
- `RELEASES.md` — updates the release-pipeline table from 5 → 7 targets
(naming the two musl rows and the two opt-in
inputs), and bundles a separate cliff.toml chore-skip + "never
hand-written" docs improvement that was already dirty
  in the working tree.

**Created:**

- None.

**Renamed:**

- None.

**Deleted:**

- None.

## Key Features

- Alpine support: musl-static binaries run on Alpine without glibc, and
on every glibc distro too.
- Belt-and-suspenders Alpine exec verification in CI catches
dynamic-link surprises (`dlopen`, NSS, locale) that pass
  the static-link `file` assertion.
- Hard-fail behavior (`linux_musl_required: true`) means a musl
regression blocks the release, not a silent artifact
  omission.

## Benefits

- Closes the install gap for Alpine users — the existing Homebrew bottle
is glibc-linux only, and `cargo install`
  requires the full Rust toolchain. Now: `wget` + `tar xf` + run.
- Distroless / `scratch` containers gain a usable artifact too.
- The Alpine exec check turns a class of "ship now, find out later in a
user bug report" failures into "fail at CI
  time."

## Breaking Changes

- [x] No breaking changes

## Deployment Notes

- [x] Standard release flow per `RELEASES.md`

After this PR squash-merges to `dev`, ship via the standard cherry-pick:

1. Branch `release/v0.3.1` from `origin/main`.
2. Cherry-pick this commit; bump `Cargo.toml` 0.3.0 → 0.3.1; `cargo
update -p agentnative`.
3. Run `./scripts/generate-completions.sh`, `bash
scripts/sync-skill-fixture.sh`, `./scripts/generate-changelog.sh`.
Cross-check the generated CHANGELOG section against this PR's `##
Changelog` bullets per the cliff.toml chore-skip
   warning.
4. Triple-diff verify, push, open `release: v0.3.1` PR.
5. After merge, annotated tag and push triggers the release pipeline
(now with musl).
6. After the release publishes, run `./scripts/sync-dev-after-release.sh
v0.3.1 && git push origin dev` per the new
   convention.

The throwaway `spike/musl-build` branch in this repo can be pruned
(locally + remotely) any time after this PR opens; it
served its purpose and was never merged anywhere.

## 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 (validated via spike workflow
before upstream PR opened)
- [x] No new warnings or errors introduced (`actionlint` clean; pre-push
hook clean)
- [x] Changes are backward compatible
@brettdavies brettdavies mentioned this pull request May 4, 2026
10 tasks
brettdavies added a commit that referenced this pull request May 4, 2026
## Summary

Releases v0.3.1, an artifact-set release: ships
`x86_64-unknown-linux-musl` and `aarch64-unknown-linux-musl` static
binaries on every release. No source change versus v0.3.0 — the binary
is identical; only the artifact set is wider.

Consolidates one dev commit:

- **#48 — `feat(release): opt into linux-musl artifacts via shared
workflow`** — passes `linux_musl_required: true` and
`linux_musl_verify_alpine: true` to the shared `rust-release.yml@main`
(those inputs landed in
brettdavies/.github#18). Bundled with the inputs change is a
`RELEASES.md` polish: 5 → 7 target table update plus a
separate cliff.toml chore-skip + "never hand-written" rule that was
pre-existing dirty in the working tree.

Triple-diff verification before opening: A is exactly the 6 expected
ship-surface files; B contains only release-prep
files (Cargo.toml, Cargo.lock, CHANGELOG.md) plus the always-divergent
completions/; no guarded engineering-doc paths
leaked.

## Changelog

### Added

- Ship `x86_64-` and `aarch64-unknown-linux-musl` static binaries on
every release. Statically linked against musl libc,
so they run on Alpine and other musl-libc-host distros without glibc,
and on every glibc distro too.

### Documentation

- Document the `cliff.toml` chore-skip footgun and the "CHANGELOG is
generated, never hand-written" rule in
  `RELEASES.md` under `Releasing dev to main`.
- Update the release-pipeline target table from 5 → 7 targets, naming
the two musl rows and the two opt-in inputs
  (`linux_musl_required`, `linux_musl_verify_alpine`).

## Type of Change

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

## Related Issues/Stories

- Story: n/a
- Issue: n/a
- Architecture: n/a
- Related PRs: #48 (this release's only consolidated dev commit),
brettdavies/.github#17 (shared-workflow musl matrix
  rows + soft-fail), brettdavies/.github#18 (release of #17 to main)

## Testing

- [x] Manual testing completed
- [x] All tests passing

**Test Summary:**

- Unit tests: pass on dev as part of #48 CI (fmt, clippy, test, audit,
package check, drift-check)
- Integration tests: n/a (no source change vs v0.3.0)
- Coverage: unchanged

End-to-end musl validation completed pre-merge in the throwaway
`spike/musl-build` workflow:

- `cross build --release --locked --target x86_64-unknown-linux-musl` —
green, statically linked
- `cross build --release --locked --target aarch64-unknown-linux-musl` —
green, statically linked
- `file target/.../release/anc` matched `statically linked` for both
arches
- x86_64 host smoke test (`anc --version`) — `anc 0.3.0`
- Belt-and-suspenders: `docker run --rm --pull always -v
".../release:/musl-bin:ro" alpine:latest /musl-bin/anc
  --version` — `anc 0.3.0`

The `release` pipeline (now 7 targets) re-runs all of the above on the
v0.3.1 tag push, so the binaries shipped to the
GitHub Release will be the freshly-built ones, not the spike's.

## Files Modified

**Modified:**

- `.github/workflows/release.yml` — passes the two new shared-workflow
inputs.
- `Cargo.toml` — version 0.3.0 → 0.3.1.
- `Cargo.lock` — `cargo update -p agentnative` regen.
- `CHANGELOG.md` — `scripts/generate-changelog.sh` extracted #48's `##
Changelog` section into a v0.3.1 entry.
Cross-checked: cliff.toml chore-skip didn't drop anything (commit
subject was `feat`, not `chore`).
- `RELEASES.md` — release-pipeline table 5 → 7 targets + bundled
cliff.toml/never-hand-written documentation.
- `src/skill_install/skill.json` — fixture refresh from upstream
agentnative-site dev (caught by drift-check on #48;
  brought along here).

**Created:**

- None.

**Renamed:**

- None.

**Deleted:**

- None.

## Breaking Changes

- [x] No breaking changes

The binary surface is unchanged. New consumers on Alpine gain an install
path; existing consumers see no difference.

## Deployment Notes

After this PR squash-merges to `main`:

```bash
git checkout main && git pull
git tag -a -m "Release v0.3.1" v0.3.1
git push origin main --tags
```

The tag push triggers the now-7-target release pipeline. After the
GitHub Release reaches `published` (homebrew dispatch
and finalize-release flip), backport per the new convention:

```bash
./scripts/sync-dev-after-release.sh v0.3.1
git push origin dev
```

The throwaway `spike/musl-build` branch (local + remote) can be pruned
any time after this PR opens; it served its
purpose.

## Checklist

- [x] Code follows project conventions and style guidelines
- [x] Commit messages follow Conventional Commits
- [x] Self-review of code completed (PR #48 review applies; release-prep
commits are
  bump/completions/CHANGELOG/skill-fixture as scripted)
- [x] Tests added/updated and passing (validated via spike + #48 CI)
- [x] No new warnings or errors introduced
- [x] Changes are backward compatible
brettdavies added a commit that referenced this pull request May 29, 2026
A five-agent parallel audit of the full diff (both directions) plus follow-up sweeps found the rename had over-applied "check"→"audit" to generic verbs, external identifiers, and grammar. Behavior is unchanged; 793 tests pass.

Code:
- Generic verbs restored to "check" in comments and doc-comments: source.rs pattern helpers, color.rs NO_COLOR routing, project.rs binary discovery ("existence check", "[[bin]] entries"), runner condvar/parser comments, several test comments (contract, bidirectional, RFC-3339 shape), and the sys_exit/env_flags/list_style comments.
- `audit_destination` reverted to `check_destination` (a skill-install precondition guard, not an `Audit`-trait audit; dev named it check_destination) along with its doc comments and test message.
- `bin/check-update` doc reference (the real script in agentnative-skill, not `bin/audit-update`).
- "a audit" / "A audit" corrected to "an audit" (article slips from the mechanical rename).
- Restored the perfect-rust test fixture, an arbitrary fake CLI, to its consistent dev form.

Top-level docs:
- CLAUDE.md: "Windows compatibility check", "the pre-push hook checks this", "Check CI status", "existence check".
- RELEASES.md: "required status checks" (GitHub branch-protection term).

Planning docs (historical references the rename falsified):
- PR #17 branch `refactor/check-status-convention`, the design-doc heading "Behavioral Check Error Handling", the `behavioral-checks.md` handoff, `gh pr checks` (not `gh pr audits`), "CI checks passed", and "status checks page".
- Restored `check_destination` and the conflict-check prose in the skill-subcommand plan, and the old-verb did-you-mean examples in the remove-implicit-default-subcommand plan, keeping the genuine domain renames (the `Audit` subcommand variant, behavioral/source audits, the renamed test).
- Re-fixed `audit-version-extract.sh`: the agentnative-site scoring script is correctly named "audit-", distinct from the CLI's `check-version` release job.

The CLI's domain noun stays "audit" throughout: the `anc audit` verb, the `Audit` trait, audit IDs, the `audit_id` field, and behavioral/source/project audits.
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