Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
107a481
Read an Uppercase Markdown Suffix as Markdown at Every Prose Gate Bra…
ptr727 Oct 15, 2026
356c6aa
Track Composite Action Pins in Dependabot (#3098)
ptr727 Oct 15, 2026
579a419
Prefer the Venv's Ruff and Pyright for a Declared Pip Directory (#3100)
ptr727 Oct 15, 2026
8931e9e
Add a Pip Ecosystem to the Carried Dependabot Snippet (#3103)
ptr727 Oct 16, 2026
df8775d
Accept .codecov.yml as an Alternative to codecov.yml (#3105)
ptr727 Oct 16, 2026
2a37637
Move workflow_reuse fetch onto audit.contents_text (#3109)
ptr727 Oct 16, 2026
97255b7
Test the Alternatives Wiring at the audit_repo and fidelity_pass Call…
ptr727 Oct 16, 2026
c181165
Add a Catalog Snippet for the Release-With-Smoke Caller (#3113)
ptr727 Oct 16, 2026
5d369fd
Stop the Doc Gates' Printed Names Forging Workflow Commands (#3116)
ptr727 Oct 16, 2026
0a0660d
Move the Release-Guard Tests' Workflow-Command Checks Onto runner_com…
ptr727 Oct 16, 2026
0b9ec4f
State the Subprocess Encoding Rule Where Carriers Read Python Style (…
ptr727 Oct 16, 2026
c5ecaa6
Name the Carried Skill and the Skipped Review Correctly (#3122)
ptr727 Oct 16, 2026
ddaeefb
Log the Docker Task's Build-Base Leg In to Docker Hub (#3124)
ptr727 Oct 16, 2026
40a131c
Reconcile VSCode-Server-DotNetCore in the Hub After Its Resync (#3126)
ptr727 Oct 16, 2026
ddd7ddb
Read CodeRabbit's Command-Reply Rate Limit in pr_review.py (#3128)
ptr727 Oct 16, 2026
722a458
Match Tool Names and the all Keyword by Case in the Windows Agents Lo…
ptr727 Oct 16, 2026
19cfddc
Release the Bootstrap Lock When a bootstrap.ps1 Run Ends (#3139)
ptr727 Oct 16, 2026
4ce0bf5
Read a gh Write's Subcommand and Target the Way gh Parses Them (#3135)
ptr727 Oct 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/pr-review-conduct/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description: >-
nothing about whether the review covered the current head SHA, read the full diff, or left a
suppressed low-confidence finding, which opens no thread at all, unanswered. Also triggers when
a review loop looks stuck (no review landing, findings that keep reappearing) or when deciding a
finding is real, false, deferred, or a deliberate decline, or when a reviewer looks missing or
finding is real, false, deferred, or a deliberate decline, or when a review looks missing or
skipped. This skill is the contract that `scripts/pr_review.py`, `drive-pr`, and
`merge-and-release` implement: running the loop hands-off is `drive-pr` and merging main is
`merge-and-release`, each winning for its own action while this skill still binds the gate.
Expand Down
19 changes: 13 additions & 6 deletions .agents/skills/python-codestyle/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ default baseline on first-party code (a repo may instead run mypy with its stric
and keep pyright editor-only via Pylance, per the next paragraph): `[tool.pyright]`
`strict = ["src"]`, or the integration package for a Home Assistant repo, with tests run in
standard mode. pyright is the anchor because Pylance embeds it, so where CI runs pyright, the
editor and the CLI/CI (`uv run pyright` in the uv form, `uvx pyright@latest` in the pip form,
pointed at the environment in a declared directory) run the same engine and never disagree.
editor and the CLI/CI run the same engine. A pyright the requirements pin can lag the one Pylance
bundles, though. The CLI/CI form is `uv run pyright` in the uv form. In the pip form a declared
directory runs the environment's own pyright, or `uvx pyright@latest` pointed at the environment
where it installs none.
The standalone `ms-pyright.pyright` extension stays in
`unwantedRecommendations` because Pylance covers it. Relax strictness on third-party code only
when a dependency has no usable types and no alternative (e.g. `pandas`): a targeted, commented
Expand Down Expand Up @@ -124,6 +126,7 @@ carries a `[project]` table it then installs the directory itself as editable, w
uv venv --clear # creates .venv, replacing an existing one
uv pip install -r requirements.txt -r requirements-dev.txt # one -r per requirements*.txt
uv pip install -e . # only where pyproject.toml has a [project] table
# in a declared directory whose .venv installs ruff, .venv/bin/python -m ruff replaces uvx ruff@latest
uvx ruff@latest format # auto-format
uvx ruff@latest check --fix # auto-fix lint
uvx ruff@latest check # verify lint clean
Expand All @@ -134,10 +137,14 @@ uvx ruff@latest format --check # verify format clean
Its type checker runs against that environment. mypy runs as `.venv/bin/python -m mypy` where the
environment installs it, and otherwise as `uvx mypy@latest --python-executable .venv/bin/python`,
adding `--python-version` with the environment's version unless the mypy config pins one. pyright
runs as `uvx pyright@latest --pythonpath .venv/bin/python`. Where the config sits in the project
directory, CI runs the checker there with no path, as in the uv form. A declared subdirectory with
no config of its own uses the repository root's instead. CI then runs the checker from the root
with the directory as its path and the interpreter as `<dir>/.venv/bin/python`. Run it the same
runs as `.venv/bin/python -m pyright --pythonpath .venv/bin/python` where the environment installs
it, and otherwise as `uvx pyright@latest --pythonpath .venv/bin/python`. ruff follows the same
precedence, as `.venv/bin/python -m ruff` where the environment installs it, in place of the
`uvx ruff@latest` above. In a directory the validator's `python-directories` input declares, a tool
the requirements pin is then the version CI runs. Where the config
sits in the project directory, CI runs the checker there with no path, as in the uv form. A
declared subdirectory with no config of its own uses the repository root's instead. CI then runs
the checker from the root with the directory as its path and the interpreter as `<dir>/.venv/bin/python`. Run it the same
way, as in `<dir>/.venv/bin/python -m mypy <dir>`. On Windows each interpreter path ends in
`.venv\Scripts\python.exe` instead. Those ruff commands and that type checker are the pip form's
clean-compile, run with pytest before committing.
Expand Down
10 changes: 10 additions & 0 deletions .agents/skills/python-codestyle/references/code-style.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@
- **Don't use exceptions for expected control flow.** Exceptions are for unexpected states.
- **Don't suppress errors silently** (`except Exception: pass`). Either handle the specific
exception and document why it's safe, or let it propagate.
- **Don't leave a text-mode `subprocess` call to the locale's encoding.** Every call that reads
or writes a pipe as text (`text=True`, `universal_newlines=True`, or an `errors` argument) names
the encoding its child uses on that pipe. Below Python 3.15, a call that names none encodes and
decodes with the locale encoding unless UTF-8 Mode is on. That encoding follows the host's
locale, usually UTF-8 on Linux and the ANSI code page on Windows. The omission therefore looks
correct on a UTF-8 host. On any other, a Windows host being the common case, it misreads or
rejects non-ASCII output from a child writing UTF-8. No static check in the ruff, pyright, or
mypy toolchain looks for the omission in a subprocess call. Naming the encoding settles how the
bytes are translated, not what a byte or character outside that encoding is worth. Each call
decides that with its own `errors` argument, and the strict default decides it by raising.

<!-- External -->

Expand Down
12 changes: 6 additions & 6 deletions .agents/skills/python-codestyle/references/profiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ configuration alone marks the lint-only one:
`[project.optional-dependencies]` extra. The pip form is a `pyproject.toml` beside a
`requirements*.txt`, installed with pip, whether or not it carries a `[project]` table. A
committed `uv.lock` makes a directory the uv form even where a `requirements*.txt` sits beside it.
In the pip form CI builds the environment as `SKILL.md` "Local development loop" shows, runs
pytest from it as `.venv/bin/python -m pytest`, and runs ruff through `uvx`. In a directory
declared in the hub validator's `python-directories` input it runs the type checker through
`uvx` pointed at that environment, or runs mypy from the environment where it is installed
there, while the undeclared default root runs a bare `uvx <checker>@latest` with nothing
installed.
In the pip form CI builds the environment as `SKILL.md` "Local development loop" shows, and runs
pytest from it as `.venv/bin/python -m pytest`. A directory declared in the hub validator's
`python-directories` input runs ruff and the type checker from that environment where it
installs them. It otherwise runs them through `uvx`, with the checker pointed at that
environment. The undeclared default root runs `uvx ruff@latest` and a bare
`uvx <checker>@latest`, with nothing installed.
- **Scripts** (the `lint-only` profile): stdlib-only utility scripts embedded in a non-Python repo
(e.g. a Python tooling subtree of a `csharp` app). Run the tools with `uvx` (no project install,
no lockfile): the `pyproject.toml` carries only tool config (`[tool.ruff]`, `[tool.mypy]`, and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The required behaviors, organized by domain. Each is a **MUST**, and its `Output
- **D1.3 Smoke never publishes and never uploads.** Input: `smoke: true`. Output: full compile/lint/test, but no registry/image push, no release, and **no** artifact uploads (every `upload-artifact`, including any aggregation job, is gated on smoke being false, written `!inputs.smoke` at the workflow layer and `inputs.smoke != 'true'` in a composite action, whose inputs are strings). *Prevents: a PR publishing, and orphaned artifacts churning the storage quota.*
- **D1.4 Workflow-file changes are not smoke-built.** Input: a PR changing only `.github/workflows/**`. Output: the paths-filter marks no target, so smoke-build skips. An inclusion list satisfying D1.1 reaches this by leaving workflow paths out of every target's entry. *Implication: a workflow-only change is not smoke-built, but actionlint still validates it in CI.*
- **D1.5 One required aggregator gates merge.** Input: any PR. Output: a single aggregator job must **succeed**, run under `if: always()` so a failed or skipped dependency cannot skip the gate itself, `needs:` the validation job, and the `changes` and `smoke-build` jobs too wherever the repo has a smoke build, treat a **skipped** smoke build as pass, and **block** on `failure`/`cancelled`. Its name is ruleset-bound: the job `name:` and the ruleset `context:` are the same string and MUST be renamed together, never independently. *Prevents: a paths-filter error letting a target-changing PR merge unbuilt.*
- **D1.6 Coverage is reported to Codecov (C# and Python).** Input: a C# or Python repo that has tests for that type. Output: the validation job runs those tests under coverage collection (`dotnet test --coverage --coverage-output-format cobertura --results-directory ./coverage`, leaving `--coverage-output` unset so each test project writes its own report rather than overwriting a shared one, `pytest --cov-report=xml` in a Python directory with its own `uv.lock` or `requirements*.txt`, whose own `pyproject.toml` selects what to measure, or `coverage run -m unittest discover -s tests` then `coverage xml` in a `lint-only` one) and a `codecov/codecov-action` step uploads the report, **best-effort** (`continue-on-error` and/or `fail_ci_if_error: false`, so a Codecov outage or an absent token never reds the gate). Each leg **fails its test step when the run wrote no report**, since the best-effort upload reads a missing report exactly as it reads a healthy run, and on the Python leg `--cov-report=xml` alone selects nothing to measure. The C# leg renames each report to `coverage-<guid>.cobertura.xml` before the upload step reads the directory, `codecov-cli`'s own finder not matching the default name, and a repo owning its validator rather than calling the hub's owes that rename itself. `CODECOV_TOKEN` lives in the repo's **actions** and **dependabot** secret stores, the second because a run triggered by a Dependabot pull request reads the Dependabot store and the upload would otherwise skip silently on every bot pull request. A caller reaching the reusable validator across repositories names the secret it passes (`secrets:` with `CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}`), on its pull request path and its publisher path alike, because `secrets: inherit` is documented for a caller in the same organization or enterprise, which a personal account is not. A call by local path stays inside one repository, where the caller's own store is the one the callee reads, so `secrets: inherit` is available there instead of naming each secret. The repo ships a **`codecov.yml`** setting the project and patch statuses to **`informational: true`** so a coverage delta never gates a pull request (a repo whose quality bar requires a threshold may turn that off), and excluding intentionally-untested, non-shipped code (an example or benchmark project) from the denominator via `ignore`. Coverage output is a build artifact, so `.gitignore` excludes it. The C# invocation runs under **Microsoft.Testing.Platform**, and the runner declaration, package references, and version floor an MTP-based test project needs are `CODESTYLE.md`'s .NET side. The Python invocation needs **`pytest-cov`** and a coverage selector, which are `CODESTYLE.md`'s Python side. A Python directory declared in the validator's `python-directories` input owes a `tests/` suite whatever its profile, so the validator fails one that has none. N/A for a repo carrying no tests for that type. *Prevents: coverage silently going unreported, and a coverage regression blocking an unrelated pull request.*
- **D1.6 Coverage is reported to Codecov (C# and Python).** Input: a C# or Python repo that has tests for that type. Output: the validation job runs those tests under coverage collection (`dotnet test --coverage --coverage-output-format cobertura --results-directory ./coverage`, leaving `--coverage-output` unset so each test project writes its own report rather than overwriting a shared one, `pytest --cov-report=xml` in a Python directory with its own `uv.lock` or `requirements*.txt`, whose own `pyproject.toml` selects what to measure, or `coverage run -m unittest discover -s tests` then `coverage xml` in a `lint-only` one) and a `codecov/codecov-action` step uploads the report, **best-effort** (`continue-on-error` and/or `fail_ci_if_error: false`, so a Codecov outage or an absent token never reds the gate). Each leg **fails its test step when the run wrote no report**, since the best-effort upload reads a missing report exactly as it reads a healthy run, and on the Python leg `--cov-report=xml` alone selects nothing to measure. The C# leg renames each report to `coverage-<guid>.cobertura.xml` before the upload step reads the directory, `codecov-cli`'s own finder not matching the default name, and a repo owning its validator rather than calling the hub's owes that rename itself. `CODECOV_TOKEN` lives in the repo's **actions** and **dependabot** secret stores, the second because a run triggered by a Dependabot pull request reads the Dependabot store and the upload would otherwise skip silently on every bot pull request. A caller reaching the reusable validator across repositories names the secret it passes (`secrets:` with `CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}`), on its pull request path and its publisher path alike, because `secrets: inherit` is documented for a caller in the same organization or enterprise, which a personal account is not. A call by local path stays inside one repository, where the caller's own store is the one the callee reads, so `secrets: inherit` is available there instead of naming each secret. The repo ships a **`codecov.yml`** setting the project and patch statuses to **`informational: true`** so a coverage delta never gates a pull request (a repo whose quality bar requires a threshold may turn that off), and excluding intentionally-untested, non-shipped code (an example or benchmark project) from the denominator via `ignore`. Codecov also reads a **`.codecov.yml`** at the repository root, so that name serves too. Coverage output is a build artifact, so `.gitignore` excludes it. The C# invocation runs under **Microsoft.Testing.Platform**, and the runner declaration, package references, and version floor an MTP-based test project needs are `CODESTYLE.md`'s .NET side. The Python invocation needs **`pytest-cov`** and a coverage selector, which are `CODESTYLE.md`'s Python side. A Python directory declared in the validator's `python-directories` input owes a `tests/` suite whatever its profile, so the validator fails one that has none. N/A for a repo carrying no tests for that type. *Prevents: coverage silently going unreported, and a coverage regression blocking an unrelated pull request.*

### D2 - Input/State Validation at Entry

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5aaa06a65aadb606
97815b2d2157b2a4
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7bbaad0be74556f3
a54a634cf8810359
Original file line number Diff line number Diff line change
@@ -1 +1 @@
76921cd09044d019
82e59e34aeb7fac2
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ description: >-
nothing about whether the review covered the current head SHA, read the full diff, or left a
suppressed low-confidence finding, which opens no thread at all, unanswered. Also triggers when
a review loop looks stuck (no review landing, findings that keep reappearing) or when deciding a
finding is real, false, deferred, or a deliberate decline, or when a reviewer looks missing or
finding is real, false, deferred, or a deliberate decline, or when a review looks missing or
skipped. This skill is the contract that `scripts/pr_review.py`, `drive-pr`, and
`merge-and-release` implement: running the loop hands-off is `drive-pr` and merging main is
`merge-and-release`, each winning for its own action while this skill still binds the gate.
Expand Down
19 changes: 13 additions & 6 deletions .claude-plugin/fleet-skills/skills/python-codestyle/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ default baseline on first-party code (a repo may instead run mypy with its stric
and keep pyright editor-only via Pylance, per the next paragraph): `[tool.pyright]`
`strict = ["src"]`, or the integration package for a Home Assistant repo, with tests run in
standard mode. pyright is the anchor because Pylance embeds it, so where CI runs pyright, the
editor and the CLI/CI (`uv run pyright` in the uv form, `uvx pyright@latest` in the pip form,
pointed at the environment in a declared directory) run the same engine and never disagree.
editor and the CLI/CI run the same engine. A pyright the requirements pin can lag the one Pylance
bundles, though. The CLI/CI form is `uv run pyright` in the uv form. In the pip form a declared
directory runs the environment's own pyright, or `uvx pyright@latest` pointed at the environment
where it installs none.
The standalone `ms-pyright.pyright` extension stays in
`unwantedRecommendations` because Pylance covers it. Relax strictness on third-party code only
when a dependency has no usable types and no alternative (e.g. `pandas`): a targeted, commented
Expand Down Expand Up @@ -124,6 +126,7 @@ carries a `[project]` table it then installs the directory itself as editable, w
uv venv --clear # creates .venv, replacing an existing one
uv pip install -r requirements.txt -r requirements-dev.txt # one -r per requirements*.txt
uv pip install -e . # only where pyproject.toml has a [project] table
# in a declared directory whose .venv installs ruff, .venv/bin/python -m ruff replaces uvx ruff@latest
uvx ruff@latest format # auto-format
uvx ruff@latest check --fix # auto-fix lint
uvx ruff@latest check # verify lint clean
Expand All @@ -134,10 +137,14 @@ uvx ruff@latest format --check # verify format clean
Its type checker runs against that environment. mypy runs as `.venv/bin/python -m mypy` where the
environment installs it, and otherwise as `uvx mypy@latest --python-executable .venv/bin/python`,
adding `--python-version` with the environment's version unless the mypy config pins one. pyright
runs as `uvx pyright@latest --pythonpath .venv/bin/python`. Where the config sits in the project
directory, CI runs the checker there with no path, as in the uv form. A declared subdirectory with
no config of its own uses the repository root's instead. CI then runs the checker from the root
with the directory as its path and the interpreter as `<dir>/.venv/bin/python`. Run it the same
runs as `.venv/bin/python -m pyright --pythonpath .venv/bin/python` where the environment installs
it, and otherwise as `uvx pyright@latest --pythonpath .venv/bin/python`. ruff follows the same
precedence, as `.venv/bin/python -m ruff` where the environment installs it, in place of the
`uvx ruff@latest` above. In a directory the validator's `python-directories` input declares, a tool
the requirements pin is then the version CI runs. Where the config
sits in the project directory, CI runs the checker there with no path, as in the uv form. A
declared subdirectory with no config of its own uses the repository root's instead. CI then runs
the checker from the root with the directory as its path and the interpreter as `<dir>/.venv/bin/python`. Run it the same
way, as in `<dir>/.venv/bin/python -m mypy <dir>`. On Windows each interpreter path ends in
`.venv\Scripts\python.exe` instead. Those ruff commands and that type checker are the pip form's
clean-compile, run with pytest before committing.
Expand Down
Loading
Loading