Skip to content

feat(anvil): publish scheduled failures as issues - #65

Merged
Martin Taillefer (geeknoid) merged 20 commits into
mainfrom
martin-kolinek/anvil-issue-publishing
Aug 21, 2026
Merged

feat(anvil): publish scheduled failures as issues#65
Martin Taillefer (geeknoid) merged 20 commits into
mainfrom
martin-kolinek/anvil-issue-publishing

Conversation

@martin-kolinek

@martin-kolinek martin-kolinek commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

🤖

Summary

  • publish scheduled Anvil failures through a bounded, best-effort marker-owned GitHub issue upsert
  • comment on the open incident for later failures; maintainers close incidents manually after resolution
  • share the same incident identity with the legacy nightly mutation workflow to prevent duplicate notification records
  • allow publication to be disabled with the ANVIL_PUBLISH_FAILURE_ISSUE=false Actions repository variable
  • scope reusable-workflow write permissions to the jobs that publish issues or PR comments; the failure publisher receives no repository-content access
  • keep source fallbacks behind declared prerequisites while ordinary tools retain cargo-binstall's normal compile strategy
  • execute contract tests for publisher behavior and installer fallback ordering/error propagation
  • document the Teams integration, bounded uniqueness and lifecycle contracts, permission boundary, and generated workflow design

Validation

  • cargo test -p cargo-anvil --test recipe_contracts
  • cargo test -p cargo-anvil anvil::artifacts::
  • cargo test -p cargo-anvil --test snapshots
  • cargo run -p cargo-anvil -- --backend github --dry-run
  • cargo +nightly fmt --all --check
  • cargo clippy -p cargo-anvil --all-targets -- -D warnings
  • cargo doc2readme --check --lib --template ../README.j2
  • just anvil-spellcheck
  • YAML parsing for all changed workflows
  • GitHub Actions across Linux/Windows x64 and ARM64

@codecov-commenter

Codecov Comments Bot (codecov-commenter) commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.9%. Comparing base (826b8e5) to head (827314b).

❌ Your project status has failed because the head coverage (99.9%) is below the target coverage (100.0%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@          Coverage Diff          @@
##            main     #65   +/-   ##
=====================================
  Coverage   99.9%   99.9%           
=====================================
  Files        135     135           
  Lines      17449   17449           
=====================================
  Hits       17448   17448           
  Misses         1       1           
Flag Coverage Δ
linux 99.9% <ø> (ø)
linux-arm 99.9% <ø> (ø)
scheduled ?
windows 99.9% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread crates/cargo-anvil/docs/design/github.md Outdated
@martin-kolinek martin-kolinek added the agency-rocket Touched by a rocket skill label Jul 31, 2026
@martin-kolinek
martin-kolinek marked this pull request as ready for review July 31, 2026 17:39
Copilot AI lite review requested due to automatic review settings July 31, 2026 17:39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends cargo-anvil’s generated scheduled GitHub Actions workflows to publish recurring scheduled failures as a single upserted GitHub issue, and updates the crate docs/design docs accordingly.

Changes:

  • Add a publish-failure job to the scheduled reusable workflow to create/comment on a stable “[Anvil] Scheduled checks failed” issue when any scheduled group fails.
  • Grant issues: write to the scheduled root workflow’s reusable-workflow call to enable issue publishing, with an opt-out via ANVIL_PUBLISH_FAILURE_ISSUE=false.
  • Document the new behavior and permission model in crate docs and the GitHub design doc; update templates and snapshots/tests to match.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
.github/workflows/anvil-scheduled.yml Grants issues: write on the scheduled reusable-workflow call job.
.github/workflows/anvil-scheduled-impl.yml Adds publish-failure job that creates/comments on a stable incident issue based on needs results.
crates/cargo-anvil/templates/github/scheduled-root-workflow.yml Template update to grant issues: write for adopters’ scheduled root workflow.
crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml Template update adding the publish-failure job and issue upsert logic.
crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap Snapshot update reflecting the new scheduled workflow job and permissions.
crates/cargo-anvil/src/anvil/artifacts/github.rs Tightens tests to assert the new workflow fragments are present (job, condition, actions/github-script, issue APIs).
crates/cargo-anvil/src/lib.rs Rustdoc updates describing scheduled failure issue publication and how to disable it.
crates/cargo-anvil/README.md Regenerated README including the new scheduled failure issue publication documentation.
crates/cargo-anvil/docs/design/github.md Design doc updates covering workflow shape, permissions, and the new “scheduled failure issues” behavior.
.anvil.lock Updates catalog checksum and managed-region checksums to reflect regenerated artifacts.
Suppressed comments (1)

.github/workflows/anvil-scheduled-impl.yml:160

  • Fetching all open issues via paginate(listForRepo) can be very expensive on large repositories (extra API calls + more data than needed). Since you only need to know whether a single title exists, prefer the Search API scoped to is:issue is:open and the title string, then exact-match the returned items.
            const openIssues = await github.paginate(
              github.rest.issues.listForRepo,
              {
                owner: context.repo.owner,
                repo: context.repo.repo,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/anvil-scheduled-impl.yml
Comment thread crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml Outdated
Comment thread crates/cargo-anvil/docs/design/github.md Outdated
Copilot AI review requested due to automatic review settings July 31, 2026 18:23

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (4)

.github/workflows/anvil-scheduled-impl.yml:130

  • Because the calling job in anvil-scheduled.yml grants issues: write and this reusable workflow does not set restrictive default permissions, all jobs here (scheduled-test/advisories/runtime-analysis/exhaustive) will run with issues: write, not just publish-failure. To keep least privilege, set permissions: { contents: read } at the reusable-workflow level (or add per-job permissions for the scheduled-* jobs) and grant issues: write only on publish-failure.
    if: ${{ always() && vars.ANVIL_PUBLISH_FAILURE_ISSUE != 'false'
      && contains(needs.*.result, 'failure') }}
    runs-on: ${{ inputs.linux_runner }}
    permissions:
      contents: read
      issues: write

crates/cargo-anvil/docs/design/github.md:678

  • This bullet implies issues: write is effectively scoped only to the publisher. In reusable workflows, permissions granted on the calling job are inherited by all jobs in the called workflow unless the called workflow sets restrictive defaults / per-job permissions. The recommendation should call that out so adopters understand how to keep least privilege.
- `permissions: contents: read` at the workflow level. anvil's default ships with
  this.
- The scheduled reusable-workflow call grants `issues: write` at job scope so its
  publisher can create or comment on the failure issue. The PR workflow never receives
  this permission.

crates/cargo-anvil/docs/design/github.md:750

  • This paragraph currently states issues: write is granted only to the scheduled root call and publishing job, but the generated reusable workflow does not set restrictive defaults—so the scheduled-* jobs would also inherit that permission. Either tighten the generated workflow permissions, or update this section to describe the actual inheritance behavior and the recommended restriction mechanism.
The publisher uses the workflow's short-lived `GITHUB_TOKEN`, with `issues: write`
granted only to the scheduled root call and publishing job. It does not receive repository
contents beyond read access and does not forward logs or environment data into the issue.
This narrow GitHub-native path also lets GitHub's Teams app relay issue notifications
without an external webhook or additional secret.

crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml:130

  • Same least-privilege concern in the template: callers grant issues: write on the reusable-workflow call job, and without restrictive default/job permissions in the called workflow, all scheduled jobs inherit it. Consider adding workflow-level permissions: { contents: read } (or explicit per-job permissions) so only publish-failure receives issues: write.
    if: ${{ always() && vars.ANVIL_PUBLISH_FAILURE_ISSUE != 'false'
      && contains(needs.*.result, 'failure') }}
    runs-on: ${{ inputs.linux_runner }}
    permissions:
      contents: read
      issues: write

Comment thread crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml
Comment thread crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml Outdated
Comment thread crates/cargo-anvil/docs/design/github.md Outdated
Comment thread crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml
Copilot AI review requested due to automatic review settings August 3, 2026 15:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Suppressed comments (4)

crates/cargo-anvil/docs/design/github.md:758

  • This claims issues: write is granted only to the scheduled root call and the publishing job. In GitHub Actions, the GITHUB_TOKEN permissions granted on the reusable-workflow call are inherited by all jobs in the called workflow unless that workflow (or each job) further restricts them. As the generated scheduled reusable workflow only sets permissions on publish-failure, the other scheduled jobs will also run with issues: write, so the doc currently overstates least-privilege.
The publisher uses the workflow's short-lived `GITHUB_TOKEN`, with `issues: write`
granted only to the scheduled root call and publishing job. It does not receive repository
contents beyond read access and does not forward logs or environment data into the issue.
This narrow GitHub-native path also lets GitHub's Teams app relay issue notifications
without an external webhook or additional secret.

.github/workflows/anvil-scheduled-impl.yml:130

  • Job-level permissions are set only on publish-failure, but the scheduled root workflow grants issues: write on the reusable-workflow call. Unless this reusable workflow defines restrictive default permissions (workflow-level or per-job), the other scheduled jobs will also inherit issues: write, expanding token scope beyond what’s needed.
    permissions:
      contents: read
      issues: write

crates/cargo-anvil/src/anvil/artifacts/github.rs:327

  • The new JavaScript harness only asserts that the search query contains in:body, so it wouldn’t catch a regression where the query can never match the marker/issue body (which would lead to duplicate issues). Tighten the assertion to require the marker term used for identity.
  assert.equal(created.search.length, 1);
  assert.match(created.search[0].q, /in:body/);
  assert.equal(created.create.length, 1);

crates/cargo-anvil/src/anvil/artifacts/github.rs:365

  • This test hard-requires a node binary at runtime; in environments where contributors run cargo test without Node installed, it will fail even though the Rust code is fine. Consider skipping this test when Node is unavailable to keep the crate’s unit tests runnable in minimal Rust-only setups.
        let output = Command::new("node")
            .arg(&path)
            .output()
            .expect("Node.js is required to test the generated github-script");
        assert!(

Comment thread .github/workflows/anvil-scheduled-impl.yml
Comment thread crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml
Copilot AI review requested due to automatic review settings August 3, 2026 15:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (4)

.github/workflows/anvil-scheduled-impl.yml:130

  • anvil-scheduled.yml grants issues: write on the reusable-workflow call. In a reusable workflow, jobs without an explicit permissions block inherit those caller permissions; since scheduled-test/scheduled-advisories/etc. have no permissions here, they will also run with issues: write even though only publish-failure needs it. To keep least-privilege, add restrictive default permissions at the reusable-workflow level (or per scheduled job) and leave issues: write only on publish-failure.
    permissions:
      contents: read
      issues: write

crates/cargo-anvil/docs/design/github.md:678

  • This bullet reads as if issues: write is effectively scoped to only the publisher, but with reusable workflows the caller's token permissions are inherited by jobs that don't set their own permissions. Either update the workflows to restrict defaults (so only publish-failure gets issues: write) or clarify here that adopters must do that to achieve least-privilege.
- The scheduled reusable-workflow call grants `issues: write` at job scope so its
  publisher can create or comment on the failure issue. The PR workflow never receives
  this permission.

crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml:130

  • The template adds issues: write for publish-failure, but the calling workflow grants issues: write on the reusable-workflow call. Unless this reusable workflow sets restrictive default permissions, every job in the reusable workflow inherits that permission. If the intent is least-privilege, set workflow-level permissions: { contents: read } (or per scheduled job) and keep issues: write only for publish-failure.
    permissions:
      contents: read
      issues: write

crates/cargo-anvil/src/anvil/artifacts/github.rs:364

  • This test unconditionally requires an external node binary. That makes cargo test -p cargo-anvil fail in environments that don't have Node installed (even though the feature being tested is a YAML template string). Consider treating missing Node as a skipped test instead of a hard failure.
        let output = Command::new("node")
            .arg(&path)
            .output()
            .expect("Node.js is required to test the generated github-script");

Copilot AI review requested due to automatic review settings August 3, 2026 15:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (7)

crates/cargo-anvil/docs/design/github.md:756

  • This paragraph says issues: write is granted only to the root call and publishing job, but the current reusable workflow does not restrict default permissions. Unless the called workflow sets minimal defaults (and only publish-failure overrides them), other jobs will also inherit issues: write when the caller grants it.
The publisher uses the workflow's short-lived `GITHUB_TOKEN`, with `issues: write`
granted only to the scheduled root call and publishing job. It does not receive repository
contents beyond read access and does not forward logs or environment data into the issue.

crates/cargo-anvil/docs/design/github.md:678

  • This bullet implies issues: write is effectively scoped only to the publisher, but in GitHub reusable workflows the caller-granted GITHUB_TOKEN permissions are inherited by all jobs unless the called workflow sets restrictive defaults. The doc should either explain that inheritance, or state that adopters should set minimal default permissions in the reusable workflow and grant issues: write only to publish-failure.
- The scheduled reusable-workflow call grants `issues: write` at job scope so its
  publisher can create or comment on the failure issue. The PR workflow never receives
  this permission.

.github/workflows/anvil-scheduled-impl.yml:130

  • The caller grants issues: write to this reusable workflow, and since this workflow does not set restrictive default permissions for the other jobs, scheduled-test/scheduled-advisories/etc will likely inherit issues: write too. Consider setting minimal default permissions (e.g. workflow-level permissions: { contents: read }) and only granting issues: write on publish-failure to keep least-privilege.
    permissions:
      contents: read
      issues: write

.github/workflows/anvil-scheduled.yml:22

  • issues: write is granted on the reusable-workflow call here, and anvil-scheduled-impl.yml does not set restrictive default permissions. That means all jobs in the called reusable workflow will likely inherit issues: write, even though only publish-failure needs it. Consider updating the reusable workflow (and its template) to set a minimal default like permissions: { contents: read } and then grant issues: write only on the publish-failure job, so this call can remain the upper bound without widening privilege for the scheduled jobs.
    uses: ./.github/workflows/anvil-scheduled-impl.yml
    permissions:
      contents: read
      issues: write
    secrets: inherit

crates/cargo-anvil/templates/github/scheduled-root-workflow.yml:22

  • Granting issues: write on the reusable-workflow call here widens the effective GITHUB_TOKEN permissions for all jobs in the called reusable workflow unless that workflow sets restrictive defaults. To keep least-privilege, consider adding minimal default permissions (e.g. permissions: { contents: read }) to the scheduled reusable workflow template and only giving issues: write to the publish-failure job.
    uses: ./.github/workflows/anvil-scheduled-impl.yml
    permissions:
      contents: read
      issues: write
    secrets: inherit

crates/cargo-anvil/src/anvil/artifacts/github.rs:365

  • This unit test hard-requires node to be installed; in environments where Rust tooling is available but Node.js is not (some CI runners / constrained dev boxes), cargo test will fail even though the Rust code is otherwise fine. Consider skipping this test when node is not present, and only failing on actual script-behavior mismatches.
        let output = Command::new("node")
            .arg(&path)
            .output()
            .expect("Node.js is required to test the generated github-script");

crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml:130

  • This template assumes issues: write is only needed for publish-failure, but when adopters grant issues: write on the reusable-workflow call, other jobs will inherit it unless this workflow sets restrictive defaults. Consider adding minimal default permissions (workflow-level or per-job) and only granting issues: write on publish-failure.
    permissions:
      contents: read
      issues: write

Copilot AI review requested due to automatic review settings August 3, 2026 15:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (4)

.github/workflows/anvil-scheduled-impl.yml:130

  • Least-privilege concern: anvil-scheduled.yml grants issues: write on the reusable-workflow call job, and this reusable workflow doesn’t set a restrictive workflow-level permissions:. As a result, all jobs in this called workflow (e.g. scheduled-test, scheduled-advisories, etc.) will also run with issues: write, even though only publish-failure needs it. Consider adding a top-level permissions: { contents: read } in the reusable workflow and leaving issues: write only on publish-failure.
      && contains(needs.*.result, 'failure') }}
    runs-on: ${{ inputs.linux_runner }}
    permissions:
      contents: read
      issues: write

crates/cargo-anvil/docs/design/github.md:756

  • This description doesn’t match the effective GitHub Actions permission model: issues: write granted on the reusable-workflow call is inherited by all jobs in the called workflow unless the called workflow sets a restrictive workflow-level permissions:. As written, readers may assume only publish-failure can write issues even though the current workflow YAML grants that scope to the other scheduled jobs too.
The publisher uses the workflow's short-lived `GITHUB_TOKEN`, with `issues: write`
granted only to the scheduled root call and publishing job. It does not receive repository
contents beyond read access and does not forward logs or environment data into the issue.

crates/cargo-anvil/src/anvil/artifacts/github.rs:366

  • This unit test hard-requires node and fails with NotFound on developer machines/environments that don’t have Node installed. Other cargo-anvil tests that rely on external validators (e.g. actionlint, taplo, just) explicitly skip when the tool isn’t present, so it would be more consistent to degrade gracefully here too.
        let output = Command::new("node")
            .arg(&path)
            .output()
            .expect("Node.js is required to test the generated github-script");

crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml:130

  • Least-privilege concern: the scheduled root workflow now grants issues: write on the reusable-workflow call job, and this reusable workflow template doesn’t set a restrictive workflow-level permissions:. That means all scheduled jobs in the called workflow inherit issues: write, even though only publish-failure needs it. Consider adding a top-level permissions: { contents: read } in this template and keeping issues: write only on publish-failure.
      && contains(needs.*.result, 'failure') }}
    runs-on: ${{ inputs.linux_runner }}
    permissions:
      contents: read
      issues: write

Comment thread crates/cargo-anvil/src/anvil/artifacts/github.rs
Comment thread crates/cargo-anvil/src/anvil/artifacts/github.rs Outdated
Copilot AI review requested due to automatic review settings August 3, 2026 16:01
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Apply the least-privilege workflow change after confirming the restriction only reduces scheduled check job permissions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Default reusable PR workflow jobs to read-only and grant pull-request write access only to pr-fast, where advisory comments are managed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Prevent cargo-binstall from compiling before Anvil's source prerequisite gate, and provision libclang only for GitHub-hosted Linux ARM64 jobs that install cargo-spellcheck.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Update the local and ADO artifact snapshots for the shared cargo-binstall strategy change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
cargo-spellcheck 0.15.1 cannot compile on current Linux ARM64 and crashes on Windows ARM64. Skip its setup, validation, and execution on ARM64 while retaining x64 coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Upgrade cargo-spellcheck to 0.15.7, remove the 0.15.1 ARM64 skip policy and version tripwire, and regenerate Anvil workflows, justfiles, lock metadata, and snapshots.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Copilot AI review requested due to automatic review settings August 20, 2026 16:51
@martin-kolinek
martin-kolinek force-pushed the martin-kolinek/anvil-issue-publishing branch from 28e3ab1 to 3d22490 Compare August 20, 2026 16:51
Explain that the 0.15.7 tokenization change is deliberately accommodated by spellcheck.toml instead of describing the now-pinned release as an unhandled regression.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated no new comments.

Suppressed comments (5)

crates/cargo-anvil/docs/design/github.md:674

  • The root-workflow examples earlier in this document (the anvil-pr.yml and anvil-scheduled.yml snippets around lines 226–252) still omit these required job-level permissions. Following those examples now produces 403s for both the scheduled issue publisher and PR advisory comments, despite this section saying they are part of the recommended shape. Update the snippets alongside this permission-model change, or explicitly show the required permissions blocks there.
- The scheduled reusable-workflow call grants `issues: write` at job scope so its
  publisher can create or comment on the failure issue. The called workflow resets its
  default permissions to `contents: read`, then restores `issues: write` only on the
  publishing job; scheduled check jobs do not inherit write access. The PR workflow
  never receives this permission.

crates/cargo-anvil/docs/design/local.md:286

  • This new design text presents --disable-strategies compile as the install path for every binstall tool, but the shared helper is also used by ordinary tools that have no source_prereq. That broadens the behavior beyond the prerequisite-ordering fix and conflicts with the stated requirement to preserve ordinary tools' strategy; revise this section to describe the flag only for prerequisite-bearing fallbacks once the helper is scoped accordingly.
- `binstall` -- `cargo binstall --no-confirm --locked --disable-strategies compile
  <tool> --version '=<pin>'`. Downloads a prebuilt binary from each tool's GitHub
  Releases when available. If no binary is available, Anvil runs the tool's source
  prerequisite before invoking `cargo install` itself; disabling binstall's compile
  strategy prevents an uncontrolled source build from bypassing that check. The
  binary path cuts the cold-runner install phase from ~30 min to ~1 min.

crates/cargo-anvil/docs/design/github.md:674

  • The earlier scheduled root-workflow example in this document (around lines 239–252) still omits the issues: write permission that this section now requires. An adopter copying that example will invoke the publisher with a read-only token and get a 403 instead of an incident issue; update the example to show the caller job granting contents: read and issues: write.
- The scheduled reusable-workflow call grants `issues: write` at job scope so its
  publisher can create or comment on the failure issue. The called workflow resets its
  default permissions to `contents: read`, then restores `issues: write` only on the
  publishing job; scheduled check jobs do not inherit write access. The PR workflow
  never receives this permission.

crates/cargo-anvil/templates/justfiles/anvil/tools.just:229

  • This shared helper is used by every installer == 'binstall' recipe, so disabling compile here changes ordinary tools such as cargo-delta and cargo-nextest as well: they no longer use binstall's original source strategy and instead always fall through to cargo install when no binary is available. That contradicts the stated goal of leaving ordinary tools' install strategy unchanged; apply the disabled strategy only when $sourcePrereq is set, preserving the original binstall invocation otherwise.
        cargo binstall --no-confirm --locked --disable-strategies compile $name --version "=$version"

justfiles/anvil/tools.just:229

  • This shared helper is used by every installer == 'binstall' recipe, so disabling compile here changes ordinary tools such as cargo-delta and cargo-nextest as well: they no longer use binstall's original source strategy and instead always fall through to cargo install when no binary is available. That contradicts the stated goal of leaving ordinary tools' install strategy unchanged; apply the disabled strategy only when $sourcePrereq is set, preserving the original binstall invocation otherwise.
        cargo binstall --no-confirm --locked --disable-strategies compile $name --version "=$version"

Disable binstall compilation only for tools with source prerequisites and restore executable coverage for fallback ordering, exact pins, prerequisite failures, and ordinary-tool strategy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Copilot AI review requested due to automatic review settings August 20, 2026 20:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 20 out of 21 changed files in this pull request and generated no new comments.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Copilot speaking]

Published 10 findings. 3 findings follow up on existing discussion threads.

See diagnostics
Diagnostic Value
Cache Hit

Comment thread crates/cargo-anvil/README.md Outdated
Comment thread crates/cargo-anvil/src/anvil/artifacts/github.rs
Comment thread crates/cargo-anvil/tests/recipe_contracts.rs
Comment thread crates/cargo-anvil/templates/justfiles/anvil/versions.just
Comment thread crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml
Comment thread crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml Outdated
Comment thread .github/workflows/anvil-scheduled-impl.yml
Comment thread crates/cargo-anvil/docs/design/github.md Outdated
Comment thread crates/cargo-anvil/docs/design/github.md Outdated
Comment thread crates/cargo-anvil/templates/justfiles/anvil/tools.just Outdated
Clarify bounded issue identity and manual lifecycle, converge legacy mutation failures on the shared incident, tighten publisher permissions, document reusable-workflow boundaries, and explain focused test harness behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 1c90ffee-5127-4069-8bb1-cef1492a400c
Copilot AI review requested due to automatic review settings August 21, 2026 11:34

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 24 changed files in this pull request and generated no new comments.

Suppressed comments (9)

.github/workflows/anvil-pr-impl.yml:36

  • This generated workflow comment hard-codes the numbered design-doc reference docs/design/github.md §9. Embedding a section number in emitted workflow source will become stale when the design is renumbered and couples every adopter's generated file to the document layout; keep the permission explanation but remove the section citation.
# request scope below. See docs/design/github.md §9.

.github/workflows/anvil-pr.yml:24

  • This generated workflow comment hard-codes the numbered design-doc reference docs/design/github.md §9. Embedding a section number in emitted workflow source will become stale when the design is renumbered and couples every adopter's generated file to the document layout; keep the permission explanation but remove the section citation.
    # only on pr-fast. See docs/design/github.md §9.

.github/workflows/anvil-scheduled-impl.yml:36

  • This generated workflow comment hard-codes the numbered design-doc reference docs/design/github.md §9. Embedding a section number in emitted workflow source will become stale when the design is renumbered and couples every adopter's generated file to the document layout; keep the permission explanation but remove the section citation.
# issues scope below. See docs/design/github.md §9.

.github/workflows/anvil-scheduled.yml:21

  • This generated workflow comment hard-codes the numbered design-doc reference docs/design/github.md §9. Embedding a section number in emitted workflow source will become stale when the design is renumbered and couples every adopter's generated file to the document layout; keep the permission explanation but remove the section citation.
    # publish-failure. See docs/design/github.md §9.

.github/workflows/nightly.yml:75

  • This jq filter assumes every returned issue has a string body. GitHub can return body: null for bodyless issues, in which case contains(...) errors; with the Actions shell's pipefail, the failure-publication step can fail instead of finding or creating the incident. Coalesce the body to an empty string before calling contains.
            --jq '.[] | select(.body | contains("<!-- anvil scheduled failure -->")) | .number' \

crates/cargo-anvil/templates/github/pr-impl-workflow.yml:36

  • This generated-workflow comment links to a numbered design-doc section. The repository guideline prohibits code comments from coupling to design-document structure, so section renumbering will make this stale; keep the permission explanation but remove the See docs/design/github.md §9 citation.
# request scope below. See docs/design/github.md §9.

crates/cargo-anvil/templates/github/pr-root-workflow.yml:24

  • This generated-workflow comment links to a numbered design-doc section. The repository guideline prohibits code comments from coupling to design-document structure, so section renumbering will make this stale; keep the permission explanation but remove the See docs/design/github.md §9 citation.
    # only on pr-fast. See docs/design/github.md §9.

crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml:36

  • This generated-workflow comment links to a numbered design-doc section. The repository guideline prohibits code comments from coupling to design-document structure, so section renumbering will make this stale; keep the permission explanation but remove the See docs/design/github.md §9 citation.
# issues scope below. See docs/design/github.md §9.

crates/cargo-anvil/templates/github/scheduled-root-workflow.yml:21

  • This generated-workflow comment links to a numbered design-doc section. The repository guideline prohibits code comments from coupling to design-document structure, so section renumbering will make this stale; keep the permission explanation but remove the See docs/design/github.md §9 citation.
    # publish-failure. See docs/design/github.md §9.

@geeknoid
Martin Taillefer (geeknoid) merged commit 12a8155 into main Aug 21, 2026
45 checks passed
@geeknoid
Martin Taillefer (geeknoid) deleted the martin-kolinek/anvil-issue-publishing branch August 21, 2026 12:26
[View workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)"
# Share Anvil's marker-owned incident so overlapping mutation
# failures produce one durable issue and one notification stream.
EXISTING_ISSUE=$(gh issue list \

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖: Non-blocking — I think the goal is right: a nightly mutation failure and an Anvil scheduled failure are one incident operationally, so converging on one durable issue and one notification owner beats two Teams posts.

The part worth weighing is the mechanism's other effect: <!-- anvil scheduled failure --> stops being an Anvil-private key and becomes a repo-wide protocol with two independent implementations — the github-script publisher in templates/github/scheduled-impl-workflow.yml:145+, which is executably tested (src/anvil/artifacts/github.rs runs the extracted script under node and pins the exact search query), and this gh-CLI version, which is hand-maintained, not emitted from a template, not tracked in .anvil.lock, and has no test at all. Three things have to stay identical across the pair — the marker text, the title, and the effective query semantics — and nothing enforces that. If a later change to the template's marker or title lands (it is generated artifact text, so it can move with an anvil update), this file keeps publishing under the old identity and the incident stream silently splits back into two, which is precisely the outcome this change exists to prevent. The failure mode is quiet: two open issues rather than an error.

Two cheap guards would close it, either or both:

  • assert in the existing contract test that SCHEDULED_IMPL_WORKFLOW's marker/title literals also appear in this workflow's text — or at minimum a comment here naming the template as the canonical owner of the marker, so the next person editing either side knows the other exists;
  • extract this failure step and run it against a fake gh: in the convergence case, gh issue list exposes an open issue carrying Anvil's exact marker and the step must comment on it without creating another; in the absent-marker case it must create with the shared title/marker and the current run URL. Have the fake assert the marker-scoped list arguments too — otherwise the two implementations can drift while each stays internally plausible.

Separately, and out of scope for this PR: sharing the output while deliberately keeping the inputs distinct means the repo now runs mutation testing twice (scripts/mutants.rs here, Anvil's scheduled-exhaustive there) under one incident identity. Is folding this config into scheduled-exhaustive and retiring nightly.yml the intended end-state, or is a second hand-maintained publisher of Anvil's protocol something this repo carries permanently? Worth writing the answer down, because it decides whether the duplication above is temporary or not.

@@ -57,19 +58,26 @@ jobs:
env:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖: Non-blocking — this is about .github/workflows/nightly.yml:56, the if: on this step (nearest commentable line). Now that this job publishes into Anvil's marker-owned incident (same title, same <!-- anvil scheduled failure --> marker), it should mirror the publisher's kill switch. anvil-scheduled-impl.yml:139 gates publish-failure on vars.ANVIL_PUBLISH_FAILURE_ISSUE != 'false', and the README / src/lib.rs / docs/design/github.md §11 all advertise that variable as the way to disable failure-issue publication. With the two publishers sharing one identity, setting it to false no longer stops the incident stream in this repo — nightly keeps creating/commenting on the same issue. Suggest adding && vars.ANVIL_PUBLISH_FAILURE_ISSUE != 'false' to this step's if: so both halves of the shared contract respect the same switch.

martin-kolinek added a commit that referenced this pull request Aug 21, 2026
…lisher

#65 landed the generic `publish-failure` job, so `scheduled-benchmarks` joins its
`needs:` list -- without that a benchmark regression fails the scheduled run and
never reaches the tracking issue. A test pins the dependency, since this is
exactly the wiring that rots silently.

The permission grants compose rather than replace: the root workflow keeps
`actions: read` for the history-artifact restore alongside #65's `issues: write`.

The test harness merge keeps main's helpers (including its new versions.just
guard in `fixture`) and adopts its `FAKE_CARGO_PS1` naming, while retaining the
bench-history and git stand-ins; both branches had hoisted the same script into a
const under different names.

Docs no longer say anvil ships no notifier for this -- with #65 merged it does.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a3ecc845-0526-499a-a233-6b82909c4517
martin-kolinek added a commit that referenced this pull request Aug 24, 2026
Integrate #65 (publish scheduled failures as issues) with the local-impact work:

- recipe_contracts.rs: adopt main's FAKE_CARGO_PS1 const refactor (script hoisted
  out of `fixture` + new binstall/install branches) and its conditional
  `versions`/`rust_nightly` guard, while re-applying this branch's
  `seed_include` helper and keeping `set allow-duplicate-recipes` (scoped
  check fixtures legitimately import impact.just alongside an anvil-impact stub,
  so duplicate recipe names must be tolerated). Main's shorter fixture no longer
  trips too_many_lines, so the #[expect] is dropped.
- github.md: keep this branch's accurate ANVIL_IMPACT=off description of the
  scheduled path and fold in main's non-executable-schematic / canonical-YAML note.

Generated artifacts (.anvil.lock, README, snapshots) reconciled from the merged
sources. Full cargo-anvil suite, workspace clippy (-D warnings), fmt, spellcheck green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37923be4-ff18-4207-bf8c-8a49849a657b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agency-rocket Touched by a rocket skill

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants