Repository navigation
Pin the Prose Gate and Its Data to One Commit via git ls-remote - #3420
Conversation
Where the API lookup of main's commit fails, hub_fetch_run.py resolves it through git ls-remote, so prose_lint.py and prose-gate.json are fetched at one commit and always pair. Where neither lookup resolves, the gate still runs against main, since a hook with no network cannot fetch the gate at all and the CI gate is the enforcement.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
|
A recorded local strict-review pass covers head |
There was a problem hiding this comment.
🟢 Approval recommended
The reviewed changes have no approval-blocking issues; one minor documentation nit remains.
No open issues 🎉
What changed in this PR
This pull request ensures the prose gate script and companion data are fetched from the same resolved commit, using a validated git ls-remote fallback when the GitHub API lookup fails.
Changes:
- Adds bounded, non-interactive Git commit resolution with strict output validation.
- Pins both prose-gate files and their provenance to one commit.
- Preserves fail-open behavior when neither lookup resolves.
- Expands fallback, failure, timeout, and environment tests.
- Updates governance and hook documentation.
| File | Summary |
|---|---|
tests/test_hub_fetch_run.py |
Adds coverage for fallback resolution, commit pinning, validation, failures, timeouts, and subprocess configuration. |
GOVERNANCE.md |
Documents API and Git lookup behavior for downstream hooks. |
catalog/snippets/pre-commit/README.md |
Documents the Git fallback for pre-commit users. |
catalog/snippets/husky/README.md |
Documents the Git fallback for Husky users. |
catalog/snippets/hub_fetch_run.py |
Adds Git-based commit resolution and commit-pinned fetching for the prose gate files. |
Review effort: Lite
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #3420 +/- ##
========================================
Coverage 80.78% 80.78%
========================================
Files 23 23
Lines 8848 8848
========================================
Hits 7148 7148
Misses 1700 1700
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Answer to the headline of the Copilot round on 9b492290, "one minor documentation nit remains". The round names no nit in a thread or in its body, so nothing locates it. The documentation nit on record for this head is the module docstring of |
…#3417) ## Summary Promotes the pull requests merged into develop since release 2.0.1148. Each carries a maintainer decision of 2026-10-23 recorded on #3391. - [#3407](#3407): rewrites the write guard as a small lexer of 1,653 lines. It fails open under its stated threat model and fails closed only on requirement 4. A test holds it at 2,500 lines or fewer (item 1). - [#3409](#3409): adds CODESTYLE rules. Tests live in `tests/`, and a maintained parser replaces a hand-written one. A script declares its dependencies in PEP 723 metadata and runs as `uv run --no-project --script`. It switches the callers to that spelling and adds a managed allow rule to the agent-safety installer (item 1 follow-ups). - [#3410](#3410): splits `pr_review.py` into the gate, a Copilot adapter reading its vocabulary from JSON, and `pr_cleanup.py`. It collapses the exit codes and adds `tests/requirements.txt` and the CI runners. - [#3411](#3411): rebuilds the prose gate on Pygments and markdown-it-py, with its vocabulary and exemptions in `prose-gate.json` and a repo-local override. - [#3415](#3415): holds the Merge Gate on a part of a Copilot review body the tooling cannot place. The hold lasts until an owner acknowledges it with outcomes (item 4 follow-up). - [#3416](#3416): moves the audit self-test to `tests/` and reads YAML and Markdown with PyYAML and markdown-it-py. It adds the check registry `spec/checks.json` and splits out `spec/audit_markdown.py`. It shares `spec/carried_text.py` with carry, `build_dist`, and `canonical_review`. - [#3418](#3418): fixes the findings this promotion's first review round raised on the content above. It aligns the drive-pr escalation line with pr-review-conduct and names `tests/requirements.txt` where the prose said the tests need nothing installed. It also restores the `uvx` launcher in a release-guard assertion. - [#3419](#3419): fixes the finding the second review round raised. The Copilot adapter's prose path reads a coverage count longer than `COUNT_DIGITS` as `unknown`, sharing `count_state` with the marker path. - [#3420](#3420): fixes the finding the third review round raised, under the maintainer's ruling. `hub_fetch_run.py` falls back to `git ls-remote` where the API lookup of `main` fails, so the prose gate and its data are fetched at one commit. Where neither lookup resolves, the documented fail-open against `main` stays. - [#3421](#3421): fixes the findings the fourth review round raised. The Copilot adapter reads a finding count longer than `COUNT_DIGITS` as unknown rather than zero, through one length check and one None-aware sum. The host-setup gates-and-tests row says `uv` installs the test requirements. Closes #3408 ## Constituent coverage The Copilot rounds on this promotion ran at Lite effort and state no full coverage, so Merge Gate item 2 rests on the promotion case. Each change this promotion carries had full coverage on its own pull request into develop, at its merged head: | Pull request | Merged head | Coverage | | --- | --- | --- | | [#3407](#3407) | `9efc1002` | attested local pass, `coverage=local` | | [#3409](#3409) | `bcc7a9e1` | attested local pass, `coverage=local` | | [#3410](#3410) | `00cec726` | attested local pass, `coverage=local` | | [#3411](#3411) | `bd128136` | attested local pass, `coverage=local` | | [#3415](#3415) | `5be9db87` | attested local pass, `coverage=local` | | [#3416](#3416) | `b914f083` | attested local pass, `coverage=local` | | [#3418](#3418) | `3a86cb51` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | | [#3419](#3419) | `6e7b868d` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | | [#3420](#3420) | `9b492290` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | | [#3421](#3421) | `743010e6` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Summary
Fixes the finding the third Copilot round on the develop -> main promotion #3417 raised against
catalog/snippets/hub_fetch_run.py, under the maintainer's ruling on it.Where the API lookup of
main's commit failed, the snippet fetchedprose-gate.jsonandprose_lint.pyfrom the movingmainref in separate requests. The two could then come from different commits, pairing a new vocabulary with an old parser. That happens when a commit lands between the requests or when the raw CDN serves one file from cache.lookup_via_git()runsgit ls-remote https://github.com/ptr727/ProjectTemplate refs/heads/mainunderLOOKUP_TIMEOUT, withGIT_TERMINAL_PROMPT=0.resolve_main_commit()calls it only after the API lookup fails. It accepts exactly one<sha>\trefs/heads/mainline, and every other shape returns a named cause.main. The docstring says why: a hook with no network cannot fetch the gate at all, and the CI gate is the enforcement.GOVERNANCE.md"Running the Linters Locally (Known-Working Invocations)" and the husky and pre-commit snippet READMEs name thegit ls-remotecall beside the API lookup.Tests
Constructed in
tests/test_hub_fetch_run.py, with the network andgitstubbed:test_git_fallback_pins_the_script_and_its_data_to_one_commit: a rate-limited API lookup with a resolvinggit ls-remotefetches both files at the git commit, in order, and prints nothing.test_git_fallback_is_not_run_when_the_api_resolves, andtest_lookup_only_for_the_prose_gateasserting no git call for another script.test_fallback_causes_print_a_line_and_the_gate_still_runsasserts the git cause in the one line, and both files fetched atmain.GitLookupTestscovers the accepted line, the command, timeout, and prompt setting, and each failure shape. Those are a non-zero exit, a missinggit, a timeout, and unexpected output (empty, a short hash, two lines, upper case).Local review
Three recorded passes at the
frontiertier, the edit budget spent on the second round.sha, and a Windows wait on a remote helper's stderr pipe after a timeout. The third is aGOVERNANCE.mdsentence whose "those" bound only touv. The fourth is declined below.introducedfindings, open under the spent budget:tests/test_hub_fetch_run.py:196,introduced:DATA_PATHrepeats a path the test at line 370 spells locally andhub.COMPANIONSholds. Declined. A test pins the literal path rather than reading the module's own constant. A rename in the snippet then fails the test instead of passing with it.tests/test_hub_fetch_run.py:2,introduced: the module docstring's subject list does not name thegit ls-remotefallback. Declined asstyle. The list stays true, since the fallback feeds the provenance path it names.Declined from the first pass: a host's global
url.insteadOfcan rewritehttps://github.com/to SSH. Therels-remotecan prompt for a key or a host key on the terminal. That host configuration is the maintainer's own, the prompt is visible rather than silent, and it is reached only after the API lookup fails.GOVERNANCE.md"Trust Boundaries and Hardening Effort" rules out hardening for it.Verification
uv run --no-project --with-requirements tests/requirements.txt python -m unittest discover -s tests->Ran 2860 tests,OK (skipped=7).uvx ruff@latest format --check .,uvx ruff@latest check, anduvx mypy@latest-> clean.python3 scripts/build_dist.py --check->Generated skill distributions are current.🤖 Generated with Claude Code