Skip to content

Promote the pr_review.py Wait Rework, the Semicolon Gate Fix, and Doc Corrections to Main - #2740

Merged
ptr727 merged 20 commits into
mainfrom
develop
Oct 10, 2026
Merged

ptr727 merged 20 commits into
mainfrom
develop

Conversation

@ptr727

@ptr727 ptr727 commented Oct 10, 2026

Copy link
Copy Markdown
Owner

Summary

Promotes 20 changes from develop to main:

Closes #1396
Closes #2731
Closes #2723
Closes #2725
Closes #2724
Closes #2685
Closes #1308
Closes #2191
Closes #1862
Closes #2711
Closes #2025
Closes #1243
Closes #1237
Closes #1115
Closes #1156
Closes #1757
Closes #1593
Closes #1732
Closes #1509
Closes #1404

🤖 Generated with Claude Code

ptr727 and others added 20 commits October 9, 2026 21:59
## Summary

`pr_review.py` filtered open review threads by a set of known reviewer
logins before counting them. A thread opened under a login outside that
set dropped out of `unresolved=`, so `status` and `wait` printed a
digest that read clean while a finding sat open. This implements the
disposition recorded on #1404, direction 1: count every unresolved
thread whoever opened it, and use the known logins only to attribute a
thread in the breakdown.

- `open_reviewer_threads` becomes `open_threads`, which keeps every
unresolved thread regardless of author.
- The breakdown beside `unresolved=` names any author outside the known
set as `other`. It prints whenever more than one group contributes, or
whenever `other` contributes at all, since that is the count a reader
cannot assume.
- `unresolved_threads()`, the `reply` command's paginated walk, now
reuses `open_threads` instead of repeating the same filter.
- The module docstring, the `threads_truncated` docstring, and the test
summary in `scripts/README.md` now describe the new rule.

## Callers re-checked

- `digest()` counts and lists every open thread. Both of its callers,
`status` and `wait`, throw away the count it returns, so no `wait` exit
code changes. Exit 0 still means a review covers the head, not that the
merge gate passed.
- `uncounted_verdict()` (exit 50) now holds off while any thread is
open, whoever opened it. Before, it held off only for a known reviewer's
thread. It reports again once the thread is resolved, as it already did.

## Tests

- A thread from an unknown login is counted and shows as `unresolved=1
(other=1)`. The digest that `status` and `wait` print carries it.
- A thread from a deleted account is counted as `other`.
- A maintainer's own open thread is counted and listed. The old test
asserted the opposite and has been turned around.
- `uncounted_verdict` holds off for an unknown login's open thread.
- With the old filter put back, all six affected cases fail.

Closes on promotion: #1404

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Review digests now count all open review threads, including those from
unknown or missing authors, and attribute them to the appropriate
reviewer category.
* Verdict checks now use the same all-thread counting rules, preventing
uncounted-verdict alerts when a thread’s author is unknown.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary

The `--branch` paragraph in `AUDIT.md` named two outcomes of a
`--branch` value: a ref that resolves, and a ref that does not resolve.
It did not name the third, a value off the `groundTruthBranch` grammar,
which `spec/audit.py` refuses before any read with exit `2` and one
stderr line. This adds one sentence naming that outcome and where the
grammar lives, `GROUND_TRUTH_BRANCH_PATTERN` in `spec/validate.py`.

The issue places the paragraph in section 1. It sits in section 8
("Report"), and the edit is made where the paragraph actually is.

## Verification

- `python3 spec/audit.py --branch 'a/../zen' ProjectTemplate` printed
one stderr line and exited `2`, before any read.
- `scripts/prose_lint.py --diff origin/develop`, `scripts/repo_gate.py
--check eol`, `spec/validate.py`, and `scripts/docker_lint.py`
(markdownlint, cspell) all pass.
- Two `local-strict-review` passes ran over the branch diff and are
recorded. The first found the new sentence over the 25-word cap, so it
is split in two. The second found nothing.

Closes on promotion: #1509

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Three assertions in `tests/test_pr_review.py` pinned a needle against
the raw source of `scripts/pr_review.py`, so a rewrap broke them and one
failed with a message claiming the comment was deleted.

- A `comment_flowed_text` reader strips each line's leading `#` marker
before collapsing whitespace, and the vetted-list-size assertion reads
through it.
- The backoff `delays` read uses a regex tolerant of an annotation or a
rewrap, and fails with a named message when the assignment is gone.
- The `n in blob` pin reads through `flowed_text`.

Verified by mutating `scripts/pr_review.py`: a rewrap of each pinned
line passes, an annotated `delays` passes, and removing each subject
fails with a message naming it. The full `python3 -m unittest discover
-s tests` suite passes. A local strict review pass found nothing.

Closes on promotion: #1732

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
…e Live Channel (#2701)

`skills_install.py --report` now carries `live.plugin` with `installed`
and `enabled`, read from `claude plugin list --json` for the user-scope
`fleet-skills@projecttemplate-fleet` entry (null where the listing
cannot be read), only when the marketplace is registered. A shared
`claude_json` helper backs both listings. The `check-this-repo` skill
and `scripts/README.md` name the field.

Closes on promotion: #1757

Remaining local-review findings after the two-round edit budget (class
introduced):

- `enabled` is read from the directory `--report` runs in, so a
project-level `enabledPlugins` override in that directory changes it.
The skill and README present it as machine-wide.
- A project- or local-scope-only install reads `installed: false`, which
the skill and README word as "serves nothing".
- No test asserts `claude_json` passes `timeout=SUBPROCESS_TIMEOUT`
(small).

Not changed: Windows `claude.cmd` resolution via bare `claude`
(pre-existing in `marketplace_entry`).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
…ell-codestyle Claim (#2703)

Removes the five `# shellcheck disable=SC2016` directives in
`repo-config/configure.sh` that suppress nothing, then makes the
`shell-codestyle` "Rules" sentence citing that file true of every
directive that remains.

## Measurement

Replacing every SC2016 directive in a copy of the file with `:` (line
numbers kept) and running shellcheck flags only the commands behind the
remaining directives, under both 0.10.0 and the CI image
`koalaman/shellcheck:stable` (0.11.0). None of the removed sites is
flagged:

- Three pass a single-quoted program straight to `jq`, which shellcheck
already exempts.
- Two are double-quoted with an escaped `\$t`, where SC2016 never fires.

Every remaining directive guards a single-quoted `jq` program handed to
the `jqr` or `jq_has` wrappers or held in a variable, or a single-quoted
GraphQL query passed to `gh api graphql`. Each carries its reason on the
same line, and the file stays shellcheck clean.

## Skill

The worked-example sentence now says the disables sit only where
shellcheck flags a single-quoted `jq` program or GraphQL query that must
stay unexpanded. Generated copies rebuilt with `scripts/build_dist.py`.

Closes on promotion: #1156

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Drops the one remaining `driftNotes` entry on the `Utilities` registry
entry. It says the repository has no `get-version-task` and relies on
`validate-task`. Both release-bearing stubs on `Utilities` `main` call
the hub's `build-release-task.yml`, which reaches
`get-version-task.yml`, so the note describes finished work, which
`RESYNC.md` section 3 deletes rather than leaves standing. The
`configLayout` half of the issue was already done.

Verified: `spec/validate.py` passes, `spec/audit.py Utilities` raises
nothing from this edit, and the spec validator, configure model, and
configure archived tests pass. A local strict review pass raised no
findings.

Closes on promotion: #1115

Related: #1145. The `LanguageTags` entry carries the identical stale
note and is left for its own change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
…d Wording (#2707)

Brings the two remaining surfaces #1237 names into line with the wording
`GOVERNANCE.md` "Verification Discipline" now carries. The third
surface, `agent-conduct`, already matched on develop.

- The `comment-and-doc-style` line-endings reference said `write_text()`
writes `\n` back and offered `newline=''` on `Path.read_text()`. It now
says `write_text()` translates each `\n` to `os.linesep`, and the fix is
bytes or `open()` with `newline=''` on both the read and the write,
since `Path.read_text()` accepts `newline` only on Python 3.13 and
newer. The two generated copies are regenerated by
`scripts/build_dist.py`.
- The `tests/test_repo_gate.py` docstring blamed a shell heredoc, which
a quoted heredoc disproves. It now names `printf`, `echo -e`, and
`$'...'`. The local review pass also found that the pattern loop only
compiled each pattern, which a control character survives, so the loop
now also asserts each pattern is printable ASCII. A mutant pattern
carrying a backspace fails the test, and the real patterns pass.

Verified: ruff format and check, mypy, `prose_lint.py` with and without
`--check sentence-length`, `build_dist.py --check`, `spec/validate.py`,
and `tests.test_repo_gate` (144 tests) all pass. Two local strict review
passes ran, the first raising three findings that the second commit
fixes, the second raising none.

Closes on promotion: #1237

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Clarified guidance for preserving line endings during text edits,
including how newline handling varies across Python versions.
* **Tests**
* Expanded checks to verify that key patterns compile and contain only
printable ASCII characters.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…kill Description (#2709)

Brings the `workflow-ci-contract` entry's Trigger line in line with the
skill's frontmatter description, and drops the false "largest law doc"
superlative from the G9 Gap.

Closes on promotion: #1243

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
## Summary

`python-codestyle` described the build profile's CI type check in ways
the hub validator's "Type check Python step" does not match. This states
what the validator actually runs.

- **One checker per directory.** The validator runs at most one checker
in each Python directory, mypy where both are configured. The skill said
CI may run pyright, mypy, or both. It now says that, and that a repo
enforcing pyright beside mypy runs pyright from its own
`.github/actions/validate/action.yml` hook, which starts from a bare
checkout. Mirrored in `references/profiles.md`.
- **No path target.** The skill gave `uv run mypy src` as the command CI
runs. CI passes the checker no path where the config sits in the project
directory, so a mypy config with no target setting passed locally and
failed in CI. The skill now gives `uv run mypy`, says the config's own
target settings decide what is checked, and gives the root-config
fallback CI uses for a declared subdirectory with no config of its own,
`uv run --project <dir> <checker> <dir>` from the root.
- **CI-gate bullet.** "Linter cleanliness" no longer says every command
runs from the project directory, since the root-config case runs from
the root.
- Generated copies rebuilt with `scripts/build_dist.py`.

## Verification

- `uvx mypy@latest` with `[tool.mypy] strict = true` and no target exits
2 with "Missing target module, package, files, or command.", and with
`files = ["src"]` it checks `src`. Constructed probe, run in scratch.
- `scripts/build_dist.py --check`, `scripts/prose_lint.py --diff`,
`scripts/repo_gate.py --check eol`, `spec/validate.py`, and
`scripts/docker_lint.py` all clean.
- Three `local-strict-review` passes, the last raising no finding. A
pre-existing gap the passes found in the pip-form paragraph is filed as
#2711.

Closes on promotion: #2025

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…le (#2714)

## Summary

The pip-form paragraph under `python-codestyle` "Local development loop"
gave its type-check commands with no path argument and no word on where
to run them. The hub validator's "Type check Python step" falls a
declared subdirectory with no checker config of its own back to the
repository root's config, then runs the checker from the root with the
directory as its path and that directory's `.venv` interpreter. A
pip-form subdirectory relying on the root config, following the skill,
ran its checker inside the subdirectory and checked a different file set
than CI, or none.

- The paragraph now states that CI runs the checker in the project
directory with no path where the config sits there, and from the root
with `<dir>` as its path and `<dir>/.venv/bin/python` as the interpreter
where the config is the root's, with `<dir>/.venv/bin/python -m mypy
<dir>` as the example. The uv-form paragraph already states the same
fallback.
- The Windows sentence now covers every interpreter path the paragraph
names rather than only `.venv\Scripts\python.exe` at the directory.
- Generated copies rebuilt with `scripts/build_dist.py`.

## Verification

- Each stated command checked against
`.github/workflows/validate-task.yml` "Type check Python step":
`targets` is empty when the config sits in the directory, `find_checker
. true` supplies the root fallback, and the interpreter is the
directory's own `.venv/bin/python`, for the venv mypy, `uvx mypy
--python-executable`, and `uvx pyright --pythonpath` forms alike.
- `scripts/build_dist.py --check`, `scripts/prose_lint.py --diff` with
and without `--check sentence-length`, `scripts/repo_gate.py --check
eol`, `spec/validate.py`, and `scripts/docker_lint.py` all clean.
- Two `local-strict-review` passes. The first raised one over-long
sentence, fixed in the second commit, and the second raised no finding.

Closes on promotion: #2711

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Updated Python type-checking instructions to distinguish project-level
configurations from subdirectories that inherit the repository
configuration. For inherited configurations, the documented CI and local
commands run the checker from the repository root, target the
subdirectory, and use its interpreter. Windows interpreter paths are
documented separately.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Two test harnesses built a child's PATH from an empty fallback, so with
PATH unset the child lost the default search path that the parent's
lookup used.

- `tests/test_skills_install.py`: both child environments now use
`os.environ.get("PATH", os.defpath)`.
- `tests/test_local_review.py` `fake_cli`: the stub directory is
prepended to `os.defpath` when PATH is unset, and the cleanup now
restores the true previous state (unset is popped, not set to empty).
- `tests/test_local_review.py`
`test_a_missing_binary_is_a_boundary_through_main`: judged correct as
is. It deliberately replaces PATH with an empty directory, so no
fallback applies.

Verification with `env -u PATH /usr/bin/python3 -m unittest
test_skills_install`: before, 1 failure and 4 errors; after, OK.
`test_local_review` under unset PATH still errors in setUp where it runs
bare `git` (outside the three sites; 105 failing before, 102 after).
With PATH set both modules pass.

Closes on promotion: #1862

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
## Summary

The skills refresh cadence was stated on several surfaces that disagreed
on the flag. This applies the decision recorded on #2191:
`docs/host-setup.md` "Fleet Skills Install" owns the cadence and keeps
the full install, and the other surfaces point to it.

- `skill-lifecycle` step 8 drops its `--snapshot-only` restatement and
points to "Fleet Skills Install".
- `check-this-repo` "Refresh cadence" keeps `--snapshot-only` for its
own freshly fetched checkout and no longer claims host-setup states the
same cadence. It now names the symptom it triggers on rather than one
"below" that the file does not hold.
- `docs/fleet-map.md` G6 (item 3 and the resolution) now says the
cadence has one home that `check-this-repo` points to.
- Generated copies rebuilt with `scripts/build_dist.py`.

The declined alternative, `--snapshot-only` everywhere with a
full-install exception, is not reopened. `merge-and-release` step 7's
own `--snapshot-only` refresh from a detached worktree is unchanged,
since it is not the host cadence.

## Verification

- `scripts/build_dist.py --check`: current.
- `scripts/prose_lint.py --diff <merge-base>`, with and without `--check
sentence-length`: clean.
- `spec/validate.py`, `scripts/repo_gate.py --check eol`, markdownlint:
clean.
- `local-strict-review`: two recorded passes. Round 1 found the
fleet-map item 3 contradiction and a sentence-length overrun, both
fixed. Round 2 found nothing.

Closes on promotion: #2191

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…g-burndown (#2720)

## Summary

`backlog-burndown` "Grouping and File Claims", in the "Verify the
prediction before dispatching" bullet, named `gh pr diff <number>
--name-only` per open pull request but no command that enumerates the
open set. This adds the listing command, a `gh pr list` with an explicit
`--limit` (gh lists 30 by default) and a jq filter that drops only this
repository's own `develop -> main` promotion pull request. The filter
checks `isCrossRepository` too, so a fork's `develop -> main` pull
request stays in the listing. The clause points at the bullet's existing
"Exclude the open promotion pull request" sentence rather than stating
the exclusion a second time.

- Generated copies rebuilt with `scripts/build_dist.py`.
- #1275's other defects in the same bullet are out of scope and
untouched.

Closes on promotion: #1308

## Verification

- The jq filter, run on constructed input (same-repo develop -> main,
fork develop -> main, feature -> develop, hotfix -> main), drops only
the first.
- The full command runs cleanly against this repository on gh 2.102.0
(no open pull requests at the time, so empty output).
- `scripts/build_dist.py --check`: current.
- `scripts/prose_lint.py --diff <merge-base>`: clean. With `--check
sentence-length`, the two sentences it reports both predate this change
(the opening sentence shortened from 50 to 45 words, the `git worktree
list` sentence unchanged and only moved).
- `spec/validate.py`: OK.
- `local-strict-review`: three recorded passes. The first found the
exclusion restated (fixed), the second found a fork's `develop` would be
dropped (fixed), the third found nothing.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary

On a pull request into a branch other than the default, a fix push
covered by an attested local pass took the held branch of `pr_review.py
wait`. That branch returned exit `0` at once with no `status=` line
while checks were still running, which a caller reading only the exit
code took as ready.

The held branch now polls the head's checks (the full query, since the
liveness query carries none) while `held_checks_open` reads that they
can still move the merge:

- `Q_FULL` reads each rollup member's `isRequired(pullRequestNumber:)`
and the pull request's `state`. A missing key reads as required or open.
- The poll ends once the merge reads `CLEAN`, `UNSTABLE`, or
`HAS_HOOKS`, or the pull request is no longer open. A `BLOCKED` merge
carrying a stuck required check ends it too, its `44` already decided.
- It holds on a required check still settling (one running long
included), on any settling check while no required one has posted (a
required aggregator behind `needs:` enters the rollup only once its
dependencies finish), on an empty readable rollup under `BLOCKED`,
`BEHIND`, or `DRAFT`, and on a merge still `UNKNOWN`. An unrecognized
review shape ends it, its `43` already decided.
- `checks_settling` is the complement of `checks_stuck`, leaving the
state taxonomy to `check_shape`.

A covered head still open at the timeout exits `30` with
`status=CHECKS_PENDING`, ranked ahead of the `44` arm. The poll stops at
once where the head is no longer covered: a push exits `49`, and a
requested round exits `30` with `status=PENDING` unless a `46` or `47`
quota reading outranks it. The `wait` help text and `scripts/README.md`
state the new readings. The Copilot (non-held) path is unchanged.

Closes on promotion: #2685

## Remaining Local-Review Findings

Each finding still open after the local passes, with its class and
outcome:

- `introduced`, design: the held poll loop is a second inline copy of
the Copilot loop's backoff shape. Deferred to #2723.
- `introduced`: the 44 arm still fires on any stuck check under
`BLOCKED`, and its README and code-comment rationale cites a ruleset
read this change now makes for free. Deferred to #2724.
- `introduced`: the seconds-long gap after a `needs:` dependency
finishes, or before a slower workflow's jobs register, can end the poll
early if a read lands in it. Every fleet ruleset measured requires a
single aggregator, and the measured gap is one to three seconds against
a poll interval of fifteen or more.
- `introduced`: a `BEHIND` merge with a failed required check ends the
poll with exit `0`, since the `44` arm requires `BLOCKED`. That arm's
scope is #2724's.
- `introduced`: the held poll reads the full `Q_FULL` document each
iteration where a narrower one would do. Deferred to #2723.
- `introduced`: `scripts/README.md`'s `30` paragraph does not name the
immediate `44` a stuck required check gives, and `check_nodes`'s
docstring does not name the `required` key. Deferred to #2725.

## Verification

- `python3 -m unittest discover -s tests`: 2445 tests OK on the head.
- Each guard in `held_checks_open` and the loop was mutation-tested:
removing it fails a named test. The first tests fail against the unfixed
script.
- `isRequired` and `state` were read live on this pull request and on
merged ones.
- `ruff format --check`, `ruff check`, `mypy`, `prose_lint.py --diff`,
`repo_gate.py --check eol`, `spec/validate.py`: clean. `--check
sentence-length` reports only sentences older than this change.
- `local-strict-review`: a recorded pass before every push, seventeen in
all, each push's findings fixed within its edit budget or listed above.

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* The `wait` command now continues polling checks that could affect a
held pull request, even when a local pass has been attested.
* If checks remain unsettled at timeout, `wait` reports `CHECKS_PENDING`
with exit code 30. Closed pull requests and terminal merge states end
polling.
* Long-running checks are no longer treated as stuck. Exit code 44 is
reserved for stuck required checks when the merge state is `BLOCKED`.

* **Documentation**
* Clarified polling outcomes and the distinction between pending checks,
pending reviews, and other results.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary

`scripts/pr_review.py wait` took exit `44`
(`status=CHECKS_NOT_MERGEABLE`) on any stuck check while the merge read
`BLOCKED`. A merge blocked by an unresolved thread or a missing
approval, carrying a failed check nothing requires, therefore still
exited `44`. The full query already reads `isRequired` on every rollup
member, so the `44` arm now counts only a stuck check marked required,
and still requires `BLOCKED`.

- The `44` line names each required stuck check, since the digest block
above it prints optional stuck checks too.
- The module docstring, the code comment above the arm, and the
`scripts/README.md` paragraphs state the `isRequired` reading instead of
the call-cost rationale.
- A test pins that a stuck optional check on a `BLOCKED` merge exits `0`
and a stuck required one exits `44`. Another pins that the `44` line
names only the required check. The CLEAN-merge test is renamed to the
`BLOCKED` half of the condition it pins.

The change rewrites the code comment above the `44` arm, which the issue
asks for, so it carries the `comments` label.

Closes on promotion: #2724

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#2729)

Documents the immediate `44` beside the held `30` conditions in
`scripts/README.md`, and names every key a `check_nodes` node can carry
(`required`, `unreadable`) in its docstring.

Closes on promotion: #2725

Remaining local-review finding after the two-round edit budget (class:
introduced, wording): in the README sentence the clause "either one past
`--check-grace`" follows a list of three states and could be read as
also applying to a failed check, which gets no grace in `check_shape`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
…2732)

## Summary

- `scripts/pr_review.py wait` now runs both of its polls through one
`backoff` helper on the `POLL_DELAYS` schedule, so a fix to the timeout
check or the delay schedule lands once. The Copilot poll passes in its
initial `(done, answer, drift)` tuple, so the `--ignore-quota-signal`
path that forces `done` false still holds for the first evaluation, and
re-reads through `live_state`, now extended to return those three
readings rather than left as an unused sibling.
- The held-head check poll re-reads a narrower `Q_HELD` document, the
fields its readers use, sharing one `HELD_FIELDS` fragment with
`Q_FULL`. A `Q_HELD` read that would end the poll is re-read as `Q_FULL`
first, so the poll stops only on the full payload the verdict then
grades, and a poll that never sleeps grades its first read with no extra
call. On the timeout the verdict takes a fresh `Q_FULL`.
- Tests: two new `backoff` cases pin the delay schedule and the timeout
bound, a case pins `Q_HELD` leaving out the threads and files, and two
`wait` cases pin the query sequence and the full-read confirmation. The
existing `wait` tests pass unchanged. Two other existing tests changed:
the contract test that scraped a local `delays` list now reads
`POLL_DELAYS`, and the two `live_state` tests take its new return shape.

Closes on promotion: #2723

## Local review

Three `local-strict-review` passes ran, and the edit budget is spent.
Disposed of so far:

- PEP 695 `def backoff[Polled]` needs Python 3.12. Declined:
`spec/host-tools.json` sets the interpreter floor at 3.13, and ruff's
default rules under `target-version = "py313"` (UP047) refuse the
`TypeVar` form.
- Two duplications that predate this change, the liveness triple
computed both inline and per iteration and a held wait's back-to-back
`Q_FULL` reads, are filed as #2731.

Still open, each `introduced`:

- **Test gap.** The `answer` fake ignores the query, so every `Q_HELD`
read in the suite carries `reviewThreads` and `files`. Replacing `final
= polled if any(polled is f for f in fulls) else None` with `final =
polled` passes the suite, although on a held timeout ending on a
`Q_HELD` read the digest would raise a `KeyError` on `reviewThreads`.
- **Design.** The `fulls` list and its identity scan do more than the
job needs, since only the last full read can be the returned value.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… Its Snapshot (#2734)

## Summary

Two duplications in `scripts/pr_review.py wait` are removed.

- **One helper computes the liveness readings.** `liveness(pr,
min_rounds)` returns the three stop readings (`head_review_done`,
`answered_outside_review`, `reviewer_login_drift`). `main`'s first
`Q_LIVE` evaluation and every `live_state` re-read both call it, so a
reading added to one site cannot be missing from the other. The drift
rationale that sat as a comment in `main` now lives in the helper's
docstring.
- **A held wait opens its poll on `snapshot`.** It no longer makes a
second, back-to-back `Q_FULL` read, which saves one GraphQL call per
held wait. An `assert` narrows `snapshot` for the type checker. `held`
already requires a non-None snapshot.

## Tests

- The held-wait tests that count reads or queue responses now expect one
`Q_FULL` read fewer.
- The test that modeled a push between the two `Q_FULL` reads now models
a push before the snapshot read, and is renamed to match. Once only one
read is left, that is the window that remains.
- Two tests are new. The first checks that the first stop evaluation and
every poll go through the same helper. Mutating `main` back to computing
the readings inline makes it fail. The second checks that `live_state`
returns `liveness` of the same payload.

## Verification

- `python3 -m unittest discover -s tests`: 2455 tests, OK (6 skipped).
- `ruff format --check`, `ruff check`, `mypy`, `prose_lint.py --diff`,
`repo_gate.py --check eol`, and `spec/validate.py` all pass.
- `local-strict-review` ran twice, with each pass recorded. The first
raised one introduced finding, a stale test name and docstring, which is
fixed in a170f96. The second raised none.

Closes on promotion: #2731

🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Pull request review waiting now applies the same checks at startup and
during polling, including review completion, answers outside a formal
review, and reviewer login changes.
* When the pull request’s head has changed, the hold decision uses the
current head’s review status. Rechecking a completed review with
`--ignore-quota-signal` continues to honor the existing refusal check.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…2737)

## Summary

The prose gate's semicolon check exempted any sentence holding a colon
before its first semicolon and a comma, so a colon that explains rather
than labels let a clause-joining semicolon through (#1396). Per the
decision on #2736 (option 1), a lone semicolon now counts as a list
separator only between two labeled items, as in `Inputs: a, b; outputs:
c`. Two or more semicolons plus a comma stay exempt.

- `prose_lint.py`: `LABELED_ITEM` (built from `LABEL_WORD`) must match
both the first item, past any list marker, and the item after a single
semicolon. A label is up to three words, emphasis or a code span
allowed, with `.`, `/`, `-` only between word characters, so `D1.2:`
labels while `e.g.`, `/tmp`, and a quotation do not.
- Tests: the old colon-arm exemptions now assert a report, the
abbreviation test is rebuilt as a series, and new tests cover labeled
items, both halves of the condition, and the three non-label shapes.
Each new negative fails with the previous pattern restored.
- Tree recasts for the six lines the narrower exemption reports:
`WORKFLOW.md` lines 54, 181, 247, 294 (plus generated skill-reference
copies) and `catalog/snippets/vscode/README.md` lines 17-18.
- Rule text: the maintainer chose to narrow the stated exception in this
PR, so `comment-and-doc-style` and `scripts/README.md` now say a single
semicolon separates a list only between two labeled items.

Closes on promotion: #1396

## Known Residual

A short labeled first clause followed by a short labeled tail still
passes (`It fails: it reads x, y; it stops: the run halts.`), since
shape cannot tell a three-word clause from a label. Requiring a label on
both sides, per Copilot's finding, narrowed this from any colon-bearing
first clause.

## Local-Review Findings

The four findings the first push listed here were fixed in 91a438e and
a4d38d6, the same ones Copilot raised. The rule text's opening-label
clause was narrowed to a bold label in b58540b. The last pass found
that the gate strips only the `**` bold spellings, so `__Label__:` and
`***Label***:` openers still count as a first label. That is the gate
falling short of the rule rather than the rule being wrong, so it is
deferred to #2738 with the pre-existing `+`/`N)` marker gap.

Carries the `comments` label for the added code comments.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 10, 2026 17:11
@coderabbitai

coderabbitai Bot commented Oct 10, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

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

⚙️ Run configuration
  • Configuration used: Repository: ptr727/ProjectTemplate/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7dfd34dc-a5af-42aa-bbeb-26e7b45bfaf0

  • 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

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Oct 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.83%. Comparing base (a762b07) to head (043a10e).
⚠️ Report is 357 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2740      +/-   ##
==========================================
+ Coverage   59.58%   59.83%   +0.25%     
==========================================
  Files          16       16              
  Lines        8316     8368      +52     
==========================================
+ Hits         4955     5007      +52     
  Misses       3361     3361              
Flag Coverage Δ
python-3.13 59.83% <100.00%> (+0.25%) ⬆️

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.

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.

🔵 Needs a closer look

Merge-gate control flow and required-check decisions have changed alongside fleet-wide guidance, warranting final human validation.

0 open findings

What changed in this PR

This PR promotes a set of develop changes to main, updating the fleet’s review tooling, prose gate, audit reporting, and guidance.

Changes:

  • Reworks pr_review.py wait to poll checks on attested heads and distinguish pending from blocked checks.
  • Narrows the prose gate’s single-semicolon exemption and updates its tests.
  • Corrects audit and development guidance, then refreshes distributed skill copies.
File Description
WORKFLOW.md Corrects CI contract prose.
tests/​test_skills_install.py Tests plugin state and PATH fallbacks.
tests/​test_repo_gate.py Strengthens pattern assertions.
tests/​test_prose_lint.py Tests semicolon exemptions.
tests/​test_pr_review.py Tests wait behavior and thread counts.
tests/​test_local_review.py Adds a default PATH fallback.
scripts/​skills_install.py Reports installed and enabled plugin state.
scripts/​README.md Documents wait and installer behavior.
scripts/​pr_review.py Reworks polling, check verdicts, and thread counts.
reports/​_template.md Aligns audit dimensions and verdict guidance.
repo-config/​configure.sh Removes inert ShellCheck directives.
registry/​repos.json Removes a stale drift note.
docs/​fleet-map.md Updates skill scope and cadence descriptions.
catalog/​snippets/​vscode/​README.md Clarifies extension descriptions.
AUDIT.md Documents invalid --branch handling.
.github/​skills/​workflow-ci-contract/​references/​test-methodology.md Refreshes generated CI prose.
.github/​skills/​workflow-ci-contract/​references/​d-guarantees.md Refreshes generated retention prose.
.github/​skills/​workflow-ci-contract/​references/​architecture.md Refreshes generated architecture prose.
.github/​skills/​skill-lifecycle/​SKILL.md Refreshes generated cadence guidance.
.github/​skills/​shell-codestyle/​SKILL.md Refreshes generated ShellCheck guidance.
.github/​skills/​python-codestyle/​SKILL.md Refreshes generated type-check guidance.
.github/​skills/​python-codestyle/​references/​profiles.md Refreshes generated profile guidance.
.github/​skills/​comment-and-doc-style/​SKILL.md Refreshes generated semicolon guidance.
.github/​skills/​comment-and-doc-style/​references/​line-endings.md Refreshes generated line-ending guidance.
.github/​skills/​check-this-repo/​SKILL.md Refreshes generated install guidance.
.github/​skills/​backlog-burndown/​SKILL.md Refreshes generated PR enumeration guidance.
.github/​actions/​prose-gate/​prose_lint.py Narrows the semicolon exemption.
.claude-plugin/​fleet-skills/​skills/​workflow-ci-contract/​references/​test-methodology.md Mirrors CI prose.
.claude-plugin/​fleet-skills/​skills/​workflow-ci-contract/​references/​d-guarantees.md Mirrors retention prose.
.claude-plugin/​fleet-skills/​skills/​workflow-ci-contract/​references/​architecture.md Mirrors architecture prose.
.claude-plugin/​fleet-skills/​skills/​skill-lifecycle/​SKILL.md Mirrors cadence guidance.
.claude-plugin/​fleet-skills/​skills/​shell-codestyle/​SKILL.md Mirrors ShellCheck guidance.
.claude-plugin/​fleet-skills/​skills/​python-codestyle/​SKILL.md Mirrors type-check guidance.
.claude-plugin/​fleet-skills/​skills/​python-codestyle/​references/​profiles.md Mirrors profile guidance.
.claude-plugin/​fleet-skills/​skills/​comment-and-doc-style/​SKILL.md Mirrors semicolon guidance.
.claude-plugin/​fleet-skills/​skills/​comment-and-doc-style/​references/​line-endings.md Mirrors line-ending guidance.
.claude-plugin/​fleet-skills/​skills/​check-this-repo/​SKILL.md Mirrors install guidance.
.claude-plugin/​fleet-skills/​skills/​backlog-burndown/​SKILL.md Mirrors PR enumeration guidance.
.claude-plugin/​fleet-skills/​.source-digests/​workflow-ci-contract Updates the skill digest.
.claude-plugin/​fleet-skills/​.source-digests/​skill-lifecycle Updates the skill digest.
.claude-plugin/​fleet-skills/​.source-digests/​shell-codestyle Updates the skill digest.
.claude-plugin/​fleet-skills/​.source-digests/​python-codestyle Updates the skill digest.
.claude-plugin/​fleet-skills/​.source-digests/​comment-and-doc-style Updates the skill digest.
.claude-plugin/​fleet-skills/​.source-digests/​check-this-repo Updates the skill digest.
.claude-plugin/​fleet-skills/​.source-digests/​backlog-burndown Updates the skill digest.
.agents/​skills/​workflow-ci-contract/​references/​test-methodology.md Corrects CI prose at its source.
.agents/​skills/​workflow-ci-contract/​references/​d-guarantees.md Corrects retention prose at its source.
.agents/​skills/​workflow-ci-contract/​references/​architecture.md Corrects architecture prose at its source.
.agents/​skills/​skill-lifecycle/​SKILL.md Points refresh guidance to its source.
.agents/​skills/​shell-codestyle/​SKILL.md Corrects ShellCheck guidance.
.agents/​skills/​python-codestyle/​SKILL.md Clarifies CI type-check commands.
.agents/​skills/​python-codestyle/​references/​profiles.md Clarifies the two-checker profile.
.agents/​skills/​comment-and-doc-style/​SKILL.md Clarifies the semicolon exception.
.agents/​skills/​comment-and-doc-style/​references/​line-endings.md Corrects Python line-ending advice.
.agents/​skills/​check-this-repo/​SKILL.md Clarifies its refresh scope.
.agents/​skills/​backlog-burndown/​SKILL.md Names the open-PR enumeration command.

🧠 Review effort: Lite


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ptr727

ptr727 commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

Merge-gate control flow and required-check decisions have changed alongside fleet-wide guidance, warranting final human validation.

This is a caution rather than a finding. It names no defect, opens no thread, and counts no finding. The changes it points at are the pr_review.py wait rework (#2722, #2727, #2729, #2732, #2734), each reviewed and merged on its own pull request. The final human validation it asks for is the maintainer's explicit go-ahead, which merging this promotion already requires.

@ptr727
ptr727 merged commit d5a2f60 into main Oct 10, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment