Skip to content

Gate the Required Check Name, Latest Flag, Lint Interpreter, and .NET Workspaces - #3796

Merged
ptr727 merged 6 commits into
developfrom
feature/burn-3334
Nov 2, 2026
Merged

ptr727 merged 6 commits into
developfrom
feature/burn-3334

Conversation

@ptr727

@ptr727 ptr727 commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fixes five pull-request-gate and release-task defects, each the way its recorded maintainer answer chose.

  • A Dispatch of the Smoke Pull Request Stub Can Mask a Pull Request's Required Check #3334: a dispatch run can mask a pull request's required check. Each aggregator's name: is now an expression that gives the ruleset-bound Check pull request workflow status job only when github.event_name == 'pull_request'. Any other run reports Check workflow status job. That applies to both catalog stubs, the docs example, and the hub's own test-pull-request.yml. spec/audit.py check_interface now accepts that expression as naming the required check. It reports a literal name in a workflow that any other event also triggers. WORKFLOW.md D1.5 and spec/fidelity-model.md state the rule. The ruleset context: does not change, so no live ruleset needs editing.
  • Adopting the Gates omits three preconditions of validate-task, and each fails silently or confusingly #1516: adoption preconditions and the base-branch filter. The pull_request base-branch filter is gone from both stubs, the docs example, and the hub's own stub. A retarget fires edited, so the filter left a retargeted stacked pull request with no run. "Adopting the Gates" now says what the task expects of the repo it gates: a mypy target (files), one type checker with the validate hook as the route to a second, and a pull_request trigger for the prose gate. The operational walkthrough in WORKFLOW.md section 6 and the branch.operational.prtriggers assertion in spec/project-types.json are updated to match.
  • Keep a Re-run Release From Taking the Latest Flag Over a Newer Release #3487: a re-run release takes the Latest flag. A new Decide latest release step passes make_latest. A main release takes the flag only where its version sorts at or above the current Latest release's tag. A prerelease never takes it. A 404 (no Latest release yet) lets the release take it, and any other read failure fails the step with a named cause.
  • validate-task.yml's lint job pins Python 3.13, narrowing the type check and blocking a uv.lock repo above that floor #1485: the lint job's pinned interpreter. The lint job's Python steps now run under the first python-versions entry. A new Resolve lint Python version step reads it with a named-cause refusal. The Sync, Lint, Format, and Type check steps each set UV_PYTHON to that version, so a uv.lock whose floor is above 3.13 syncs. setup-uv stays at 3.13, the floor the hub's own uv scripts declare, so the prose and repo gates still run under it. The pip path's separate UV_PYTHON override and its check are removed, since these four steps now carry the interpreter.
  • validate-task Runs dotnet format at the Root Where No Project or Solution Sits There #1938: dotnet format and dotnet test at a root with no workspace. Both steps keep the bare call where the root tracks a .sln, .slnx, or .csproj. Otherwise the style step runs once per tracked solution, or once per .csproj where the tree has no solution. The test step runs once per tracked *Tests*.csproj, the glob its own hashFiles guard uses. It names no solution, because dotnet test --project on a solution or project holding no test project exits 1 ("No test projects were found"), measured on SDK 10 under the testing platform with the coverage flags.

Closes on promotion: #3334, #1516, #3487, #1485, #1938

Verification

  • The full unittest suite, spec/audit.py --selftest, spec/validate.py, scripts/build_dist.py --check, ruff format and check, and mypy all pass locally.
  • docker_lint.py passes for actionlint, markdownlint, cspell, and editorconfig-checker.
  • New tests run each changed step's own script against stand-in tools:
    • The make_latest decision covers newer, older, numeric-order, refresh, v-prefixed, 404, prerelease, and 502 cases.
    • The lint interpreter resolution covers good and malformed values.
    • The per-workspace .NET steps cover a root solution, solutions below the root, and projects with no solution, in real git repos. A check also confirms the resolver text is the same in both jobs.
    • A test confirms no shipped stub or docs block filters a base branch.
    • The check_interface cases cover the expression form, a literal name under a dispatch trigger, the list-form on:, an expression that names the check on every event, and one gated on the wrong event. A test also confirms every shipped stub meets the carried contract in spec/files.json.
  • dotnet format style <solution|project> was measured on SDK 10 against a subdirectory-only tree, and so was dotnet test --project on a solution and on a project that hold no test project.

Downstream effect

Every downstream test-pull-request.yml whose aggregator still has the literal name will show check_interface DRIFT until its next resync. The audit now reports a literal name in any stub that workflow_dispatch or push also triggers, and that is every adopted stub today. A resync clears it by replacing the aggregator's name: line with the expression from the snippet. No ruleset changes, since the context: string a pull request run posts is unchanged.

Introduced findings from the local passes, and their outcomes

  • tests/test_release_guards.py test_lint_runs_under_the_first_named_interpreter, introduced: Git Bash collapses the doubled backslash in the jq filter in a bash -c argument. Fixed in f6fd08a, which runs the script from a file.
  • .github/workflows/validate-task.yml Run unit tests step, introduced: a solution holding no test project fails dotnet test. Fixed in 4ecb00d, which names test projects instead.
  • .github/workflows/validate-task.yml Run unit tests step, introduced: in a tree with no root workspace, a non-test helper project whose name contains Tests is passed to dotnet test --project, which exits 1. Declined under GOVERNANCE.md "Trust Boundaries and Hardening Effort". The layout is the maintainer's own and the failure is loud rather than silent. The step's own hashFiles('**/*Tests*.csproj') guard already treats that name as a test project.
  • spec/audit.py check_interface, introduced: the function re-parsed the text to read on:. Fixed in f6fd08a, which reads the composed tree.
  • spec/audit.py PR_ONLY_NAME, introduced: only the shipped operand order is accepted. Declined: the carried snippet's form is what a resync delivers, and recognizing every boolean rewrite answers no requirement. f6fd08a makes the DRIFT message name both accepted forms.
  • WORKFLOW.md D1.6, introduced: the per-workspace --project form was not mentioned. Fixed in f6fd08a and 4ecb00d.
  • The lint job's comment and the docs said the whole job runs under the first interpreter, although only its Python steps do. Fixed in 4ecb00d.
  • .github/workflows/validate-task.yml Check C# style step, introduced: where the root holds no workspace and the tree tracks a solution, a .csproj no tracked solution references is not style-checked. Declined: the validate-task Runs dotnet format at the Root Where No Project or Solution Sits There #1938 maintainer answer chose "once per tracked .sln/.slnx, else per .csproj", and this is that rule's stated behavior.

Pre-existing findings, filed

Out-of-claim findings, filed

🤖 Generated with Claude Code

ptr727 and others added 4 commits November 1, 2026 15:12
… Workspaces

Give the pull request aggregator an expression name that yields the
ruleset-bound context only on a pull_request run, so a dispatch or push
run on a pull request's head cannot mask its required check, and teach
the audit's interface check that shape. Drop the base-branch filter that
stranded a retargeted pull request, and document what validate-task
expects of an adopting repository.

Decide make_latest against the current Latest release so a re-run of an
older release cannot take the flag, run the lint job under the first
python-versions entry, and run dotnet format and dotnet test once per
tracked workspace where the root holds none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lint job's Python steps now take the caller's first python-versions
entry through a step-scoped UV_PYTHON, so the prose and repo gates keep
running under the interpreter floor the hub's own uv scripts declare.
The audit reads a workflow's triggers through one helper, and the
release guard tests reuse spec/git_env.py's location-free environment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tubs

The branch.operational.prtriggers assertion now names an unfiltered
pull_request trigger, and the fidelity model says the ruleset-bound
check name is given only on a pull_request run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Resolve lint Python version step now runs only where a Python step
reads its output. The aggregator-name matcher reuses the audit's
unquoted-space normalizer, and the new release and lint tests read step
keys through workflow_steps.py, asserting the latest decision and the
release create share one condition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings November 1, 2026 23:41
@ptr727 ptr727 added the comments Permits the comment lines the pull request adds or edits, which the prose gate otherwise refuses label Nov 1, 2026
@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@ptr727

ptr727 commented Nov 1, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 28f55296a80ae8dffad62e957197ee9e7cf4d072, the content this pull request carries at that commit against develop, and it recorded 6 findings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Several moderate active findings remain, including unreliable project discovery and workflow parsing plus a Windows test invocation issue, so changes are needed before approval.

5 open issues
What changed in this PR

This pull request hardens pull-request validation and release workflows, updates workflow contracts and documentation, aligns linting with the caller’s Python version, and adds workspace-aware .NET checks with regression coverage.

Changes:

  • Gates the required check name to pull-request runs and removes base-branch filters.
  • Adds version-aware release Latest selection and lint interpreter resolution.
  • Supports .NET formatting and testing across repository workspaces.
  • Updates workflow audits, contracts, documentation, generated guidance, and tests.
  • Unresolved findings remain around workspace detection, test-project filtering, pull-request retarget triggers, Windows test execution, and related documentation/audit handling.

This pull request requires changes.

File Description
WORKFLOW.md Documents event-specific required-check names and operational trigger behavior.
tests/​test_release_guards.py Tests release Latest selection, trigger filters, lint interpreter selection, and .NET workspace execution.
tests/​test_audit_helpers.py Tests required-check expressions and shipped pull-request stub conformance.
spec/​project-types.json Updates the operational pull-request trigger contract.
spec/​fidelity-model.md Documents the conditional required-check interface.
spec/​audit.py Recognizes conditional aggregator names and validates workflow events.
docs/​reusable-workflows.md Updates adoption guidance, trigger behavior, interpreter behavior, and task preconditions.
catalog/​snippets/​workflows/​test-pull-request.yml Removes the base filter and uses an event-specific aggregator name.
catalog/​snippets/​workflows/​test-pull-request-smoke.yml Removes the base filter and uses an event-specific aggregator name.
.github/​workflows/​validate-task.yml Resolves the lint interpreter and runs .NET checks against discovered workspaces.
.github/​workflows/​test-pull-request.yml Updates the hub pull-request workflow trigger and aggregator name.
.github/​workflows/​build-release-task.yml Computes and passes the release make_latest decision.
.github/​skills/​workflow-ci-contract/​references/​d-guarantees.md Regenerated workflow-contract guidance.
.claude-plugin/​fleet-skills/​skills/​workflow-ci-contract/​references/​d-guarantees.md Regenerated Claude workflow-contract guidance.
.claude-plugin/​fleet-skills/​.source-digests/​workflow-ci-contract Updates the generated skill source digest.
.agents/​skills/​workflow-ci-contract/​references/​d-guarantees.md Updates the authored workflow-contract guidance.

Review effort: Lite

Comment thread .github/workflows/validate-task.yml Resolved
Comment thread .github/workflows/validate-task.yml Resolved
Comment thread spec/audit.py Resolved
Comment thread spec/audit.py Resolved
Comment thread tests/test_release_guards.py Resolved
@codecov

codecov Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 82.35%. Comparing base (27d1ca4) to head (4ecb00d).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
spec/audit.py 91.66% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #3796   +/-   ##
========================================
  Coverage    82.34%   82.35%           
========================================
  Files           28       28           
  Lines         9454     9462    +8     
========================================
+ Hits          7785     7792    +7     
- Misses        1669     1670    +1     
Flag Coverage Δ
python-3.13 82.35% <91.66%> (+<0.01%) ⬆️

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.

ptr727 and others added 2 commits November 1, 2026 15:47
…D1.6

The lint interpreter test hands its jq script to bash as a file, since
Git Bash collapses the filter's doubled backslash in a -c argument. D1.6
names the per-workspace dotnet test form, the interface check reuses the
workflow it already composed to read triggers, and its missing-name
message names both accepted forms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A solution holding no test project fails dotnet test under the testing
platform with no test projects found, measured on SDK 10 with the
coverage flags. So where the root holds no workspace, the test step
names each tracked test project, while the style step still names each
solution. The lint job's comment and docs now say only its Python steps
take the caller's first interpreter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 4ecb00d8f78461516badb25f0b056c759a5cb6ee, the content this pull request carries at that commit against develop, and it recorded 1 finding.

@ptr727
ptr727 merged commit 9e06417 into develop Nov 2, 2026
13 checks passed
@ptr727
ptr727 deleted the feature/burn-3334 branch November 2, 2026 00:11
ptr727 added a commit that referenced this pull request Nov 2, 2026
…ings With an Acknowledgment Record, and Mark Direct-Push Closures (#3797)

Promotes the changes merged into `develop` since promotion #3778 to
`main`, the second round of a backlog burndown.

- [#3784](#3784) has the
write guard read a push option attached to `-o` as that option's value,
as git does, rather than as more short flags. It also walks a
short-option cluster carrying a digit, such as `-4f`.
- [#3796](#3796) fixes
five pull-request-gate and release-task defects:
- Each aggregator's `name:` gives the ruleset-bound required check name
only on a `pull_request` run, so a dispatch run cannot mask it.
`spec/audit.py` `check_interface` reads that expression.
- The stubs drop the `pull_request` base-branch filter, and "Adopting
the Gates" states the task's preconditions.
- A re-run release takes the Latest flag only where its version sorts at
or above the current Latest release.
- The `lint` job runs its Python steps under the first `python-versions`
entry.
- `dotnet format` and `dotnet test` run per tracked workspace where the
root holds no solution or project.
- [#3793](#3793) has
`pr_review.py merge` read an acknowledgment record, posted with `comment
--ack KEY=OUTCOME`, for findings no thread carries and for a verdict
naming no counted finding. Every `merge` run ends on one `next=` line
the skills follow, and the digest reads the excluded-files refusal as
`refusal=EXCLUDED`.
- [#3792](#3792) has a
direct push to `develop` on an operational-model repository name the
issues it fixes in its commit message's on-promotion line.
`backlog-burndown` assembles the promotion body from the pull request
that merged each commit, falling back to a direct push's own message.
Its claim lookup matches only claim comments, and
`git-commit-conventions` names the abandon-discard exception.
- [#3798](#3798) has
`has_prose` read an inline token's text children outside code, so an
inline-code span alone no longer counts as prose. It answers this
promotion's first review round.
- [#3799](#3799) has
`check_interface` read each job by its key on a workflow a non-PR event
triggers. A job whose off-PR name is the required check gets its own
DRIFT. It answers this promotion's first review round.

## Downstream effect

From #3796: once this reaches `main`, every downstream
`test-pull-request.yml` whose aggregator carries a literal `name:` shows
`check_interface` DRIFT. It shows that until its next resync. A resync
clears it by replacing the aggregator's `name:` line with the
expression. No ruleset changes, since the `context:` a pull request run
posts is unchanged.

Fixes #3720
Fixes #3334
Fixes #1516
Fixes #3487
Fixes #1485
Fixes #1938
Fixes #3718
Fixes #3724
Fixes #3777
Fixes #3773
Fixes #1276
Fixes #1307
Fixes #3780

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comments Permits the comment lines the pull request adds or edits, which the prose gate otherwise refuses

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants