Repository navigation
Conversation
…3399) ## Summary States the write guard's threat model once, where a reader meets the hooks' purpose, and records two maintainer decisions as documented allowed shapes. No guard logic changes. - `host-setup/agent-safety/README.md` "Why This Exists" gains one paragraph: a hook implementing these requirements bounds a good-faith agent's mistake rather than an adversary and is not a sandbox. A parse gap reachable only by a command shape no agent plausibly types in a normal session is out of scope, declined rather than fixed, and not filed by the local review of a hook change. A shape is added only when a session produced it or plausibly would, since each hardening change is read again by every later review. It applies `GOVERNANCE.md` "Trust Boundaries and Hardening Effort" and cites Decision (ptr727, 2026-10-23) on #3391, item 1. - `host-setup/agent-safety/claude/gh-write-guard.py` module docstring gains one sentence pointing to that paragraph. - Requirement 6 records that a quoted `-C` value holding a run-time word other than `$HOME`, as in `git -C "$D"`, fails open, unlike the `GIT_DIR`, `GIT_WORK_TREE`, `--git-dir`, and `--work-tree` values (#3382, decided "keep allowed, document"). - Requirement 4's wrapper-body passage records that, in a command holding no `git push`, `xargs -I{} sh -c '{}'` is allowed as an unread script, like `bash script.sh` (#3385, decided "keep allowed, document"). Both verdicts were confirmed against the unchanged guard with `classify` on constructed commands in a throwaway primary repository: `git -C "$D" reset --hard` allow, `git -C $D reset --hard` deny, `GIT_DIR="$D" git reset --hard` deny, `echo 'git reset --hard' | xargs -I{} sh -c '{}'` allow. Closes #3382 Closes #3385 ## Test Command: `python3 host-setup/agent-safety/claude/gh-write-guard.py --selftest`, exit 0. Last line of its output, verbatim: ```text SELFTEST PASS ``` `scripts/prose_lint.py . --diff origin/develop` and the same with `--check sentence-length`: exit 0, no violations. ## Local review Three recorded `local-strict-review` passes. The first raised three introduced findings (the `-C` sentence omitted the `$HOME` exception, "closed" was used in opposite senses across the two files, and the xargs sentence did not name which push it meant) plus one introduced wording item, all fixed in the second commit. Declined as style: line wrapping that differs from the surrounding hard-wrapped text (the file already mixes both), the threat-model paragraph's overlap with the GOVERNANCE rule it cites, and the second pass's note that the `-C` sentence's reason reads close to the previous sentence's. Copilot's one finding, that the `-C` sentence misstated why it fails open, is fixed in ceefd9f, and the third pass found it fixed. Declined as style from that pass: the shortened example `git -C "$D"` carries no subcommand, while the surrounding sentence already names the mutating subcommands requirement 6 denies. No introduced finding remains open. ## Pre-existing findings, not filed None raised. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…em (#3401) ## Summary Changes the review-disposition rule so a `pre-existing` finding is no longer filed as its own issue. - `pr-review-conduct` "Every finding ends in a listed outcome", outcome 4, is rewritten in place. It covers a finding deferred past the pull request or found on text it did not touch, and an `introduced` finding deliberately left as is still takes outcome 3. The first bullet that fits decides: - A `pre-existing` finding on a canonical Markdown unit keeps the per-unit tracker, which already costs one link per unit. - A `pre-existing` correctness defect with a stated failure (it names an input or state and the wrong output or crash) is filed once, labeled `pre-existing`, and its line under `Pre-existing findings, filed` links it. - A `style`, wording, consolidation, or restatement finding on text the change did not touch is dropped: one line under `Dropped findings`, no decline text, no issue, no reply beyond a pointer that resolves the thread. - Any other `pre-existing` finding, local or PR-hosted, is listed under `Pre-existing findings, not filed` with its location and class. The body line is its outcome. - Any other deferral is still filed as an issue. - `pr-review-conduct` "Merge Gate" item 3 names the tracker as outcome 4's first bullet and exempts a line under any heading outcome 4 names from a second answer. "Answering a suppressed finding" gains a `Listed in the body` verdict. - `local-strict-review` "Disposing of Findings" points to outcome 4 instead of saying "filed once". - `repo-config/README.md` no longer says every `style` finding is declined, since one on untouched text is now dropped. - `drive-pr` changes only through its generated include of outcome 4, regenerated by `build_dist.py`, never hand-edited. Why: over 2026-10-16 to 2026-10-23, 108 of 329 non-handoff issues filed across four fleet repositories carried `pre-existing`. Each one costs a lane, a pull request, and a review once worked. Decision (ptr727, 2026-10-23) on #3391, item 2. ## Verification `python3 scripts/build_dist.py --check`, exit 0: ```text Generated skill distributions are current. ``` Prose gate, `python3 scripts/prose_lint.py --diff origin/develop`, exit 0: ```text scope: 13 of 378 file(s) read, 271 changed line(s), diff against 'origin/develop', gate local 5090774 ``` The opt-in `--check sentence-length` run reports hits only on base sentences listed below. A `local-strict-review` pass at the `frontier` tier covers each push. The pass recorded and attested on head 5090774 raised no finding on text this change wrote, and the four it raised on base text are listed below. ## Open introduced findings, edit budget spent The six findings the third local pass left open on the opening push are each fixed, in c05e4d3, b4faf80, and 5090774. Four of them were also raised by Copilot, and those threads carry the fixing SHAs. None remains open. ## Pre-existing findings, not filed - `.agents/skills/pr-review-conduct/SKILL.md:162`, `pre-existing`: the base "A carrying repository routes a finding on a verbatim unit" sentence is 70 words. A reflow moved it onto its own line. - `.agents/skills/local-strict-review/SKILL.md:151`, `pre-existing`: the unchanged "Unless evidence disproves it" sentence is 30 words. - `repo-config/README.md:52`, `pre-existing`: the unchanged first sentence is 34 words. - `repo-config/README.md:52`, `pre-existing`: the unchanged `comments` sentence is 28 words. ## Follow-ups, not edited here - `.agents/skills/drive-pr/SKILL.md` lines 152-231 carry outcome 4 as a generated include, so they change with this PR through the regenerate only. - `.agents/skills/backlog-burndown/SKILL.md` lines 87 and 490 describe "the deferral issues this round's reviews filed" as the next round's ranking input. They do not restate the rule, but with `pre-existing` findings no longer filed, fewer such issues reach the ranking. Whether a burndown round should also read the `Pre-existing findings, not filed` body lists is a decision for the maintainer. - `.agents/skills/unattended-handoff/SKILL.md`: the grep found no restatement. - `GOVERNANCE.md` "Verification Discipline" (a class-sweep sibling in an untouched file "is filed rather than folded in") and "Design Before Code" (sites in untouched files are "filed as one issue naming each") still file siblings. Outcome 4 scopes them out explicitly, since a class-sweep sibling is not a finding a review raised. Whether siblings should also go to the body list is a decision for the maintainer. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Adds `scripts/backlog_metrics.py`, a weekly backlog and review-cost report for the cataloged repositories. It prints markdown or minimal HTML to stdout, reads through `gh` only, and is wired into no workflow, so a server timer can mail it. The test is `tests/test_backlog_metrics.py` (unittest, constructed fixtures, no `gh` call). `tests/test_cli_usage.py` lists the script under `NO_REQUIRED_ARGUMENT`, which that test requires of every tracked entry point. `scripts/README.md` gets a section, since it holds no table of scripts. Review runs match the run `name` field, not `workflowName`: a live read showed `name` carries "Running Copilot Code Review" and `workflowName` reads "Copilot". ## Verification - `uvx ruff@latest format --check scripts tests` -> `57 files already formatted` - `uvx ruff@latest check scripts/backlog_metrics.py tests/test_backlog_metrics.py tests/test_cli_usage.py` -> `All checks passed!` - `uvx mypy@latest` (pyproject.toml configures mypy and pyright, the hub validator runs mypy) -> `Success: no issues found in 65 source files` - `python3 tests/test_backlog_metrics.py` -> `Ran 27 tests ... OK` - `python3 tests/test_cli_usage.py` -> `Ran 16 tests ... OK` - `python3 scripts/prose_lint.py --diff <merge-base>` -> exit 0, no violations - `python3 scripts/repo_gate.py` -> no failing check - `python3 scripts/backlog_metrics.py --bogus` -> `error: unrecognized arguments: --bogus`, exit 2 - Live read-only smoke run against one repository confirmed the table, label line, and billing lines render. Local strict review ran twice at the frontier tier and is recorded against the final content. Round one fixed the review-run field, the missing UTF-8 decode (now reuses `gh_graphql.run_subprocess`), a count in test prose, and README wording. Round two fixed the test gaps. ## Pre-existing findings, not filed - `scripts/README.md:9`: a 43-word sentence in the existing utility list. The opt-in `sentence-length` check reports it because this change added one word to it. ## Decision for the maintainer The window is `>=START` with START = today minus N days, as specified. A weekly run therefore counts the boundary day in two consecutive reports. A bounded `START..yesterday` range would give non-overlapping full days. Not changed here because the brief fixed the `>=DATE` filters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
## Summary The session handoff chain changes from one new issue per session to one standing issue per track, in the rule text, the `session-handoff` skill, and `scripts/handoff.py`. - A track in use holds exactly one open issue carrying the `handoff` label. It is created when the track starts and closed when the track's work is complete. It is never closed and replaced per session. - The issue body is the current handoff, edited in place at each session close. The body's metadata block carries the track and a round number that advances each close. - Before the body is replaced, the outgoing body is appended to the same issue as a comment headed `## Round <n>, closed <YYYY-MM-DD>: <outgoing title>` and ending in `<!-- handoff-round: v1 track=<slug> round=<n> closed=<YYYY-MM-DD> -->`, so the track's history stays on one issue, in order. Why: from 2026-10-16 to 2026-10-23, 151 of 480 issues created across four fleet repositories were handoff links, each one a create, a comment, and a close. Decision (ptr727, 2026-10-23) on #3391, item 5. ## Changes - **`AGENTS.md` "Session Scope"**, the "Hand off in an issue" bullet, is rewritten in place and is shorter (564 words against 667). It keeps the issue-not-scratch-file rule, the track slug, the body carrying the state a resume re-reads, the parked-decision account, and the per-section size rule. The create, forward-link, close ordering is dropped. - **`scripts/handoff.py`** - `new` keeps its name and arguments and is the one entry point. With no open issue on the track it creates one. Where the track was closed before, the new issue continues from the newest closed one through `previous=` at the next round, and nothing is written to the closed issue. With an open issue it archives the outgoing body as a comment, then replaces the title and body and advances the round. Both paths print the issue number. - A rerun after an interrupted `new` finishes it rather than repeating it. If the round is already archived with the same text, only the body is replaced. If the body already holds the new text, nothing is written. If the archived text differs, `new` refuses. - The body is read again immediately before it is replaced, and an edit landing since the archive refuses. The edit is confirmed by reading the body back. - `chain` walks the current body, then the archived rounds newest first, then follows `previous=` into the closed issue the track continues from. `resume` indexes the archived rounds. `current` and `tracks` are unchanged. - A round mark counts only from an `OWNER`, `MEMBER`, or `COLLABORATOR` comment that is not hidden. On a public repository an outsider's comment then can neither plant a round nor block `new`. - New `close` subcommand: it comments the outcome given in `--body-file` on the track's issue, then closes it, confirmed by reading the state back. It is the only way a track ends. A rerun after the comment landed only closes. - Every write keeps `--dry-run`, every comment goes through `--body-file`, and no `gh` output is suppressed. - **`link` is retired**, not reduced. A rerun of `new` repairs a half-applied archive-then-edit by itself, so `link` has nothing left to repair. One consequence: a pre-change chain left half-applied, with two open links on one track, is settled by hand, by closing the one that is not current. Every command already refuses such a track and names both. - **Migration** has no step. The first `new` on a track whose open link predates this change treats that link as the standing issue, and `chain` still reaches the closed links behind it through `previous=`. A test covers this end to end. - **`.agents/skills/session-handoff/SKILL.md`** is updated in "The Chain", "Resuming", "The Attended Session" step 6, "Closing a Session", and "Running the Chain". Step 6 now takes `blocked` off the issue after `new`, since the label no longer leaves with a closed link. Its mirrors are regenerated. - **`scripts/README.md`**, the `handoff.py` contract, is updated to match. - **`.agents/skills/unattended-handoff/SKILL.md`** is edited only where it instructed the old order: - worker step 1, which looked for a handed-back parking comment on a closed link, - the picker's "closed or opened" line, - step 7, whose cross-reference to "The Chain" this change made false, and which now ends a lane with `handoff.py close`. Its mirrors are regenerated and committed with it, since `build_dist.py --check` fails otherwise. This goes beyond the "session-handoff mirrors only" instruction, which did not foresee a second source edit. ## Verification ```text $ uvx ruff@latest format --check scripts/handoff.py tests/test_handoff.py 2 files already formatted exit 0 $ uvx ruff@latest check scripts/handoff.py tests/test_handoff.py All checks passed! exit 0 $ uvx mypy@latest Success: no issues found in 63 source files exit 0 $ python3 -m unittest tests.test_handoff Ran 173 tests OK exit 0 $ uvx coverage@latest run --source=scripts -m unittest tests.test_handoff && uvx coverage@latest report --include=scripts/handoff.py TOTAL 667 10 99% $ python3 scripts/build_dist.py --check Generated skill distributions are current. exit 0 $ python3 scripts/prose_lint.py . --diff origin/develop scope: 12 of 378 file(s) read, 1121 changed line(s), diff against 'origin/develop', gate local d364a95 exit 0 ``` - `mypy` is the repository's configured type checker (`[tool.mypy]` in `pyproject.toml`). - The test file imports `unittest`, so the runner is `unittest`. Every test runs against an in-memory fake `gh` built from constructed fixtures, and none touches live GitHub data. - The pre-commit hook's `repo_gate.py --check eol` passed on every commit. **Dry runs against this repository.** These were dry runs only, with no live `new` or `close`. The track was `engineering`, and the body file held constructed text. ```text $ python3 scripts/handoff.py new --repo ptr727/ProjectTemplate --track engineering --title "Dry run" --body-file <constructed> --dry-run 1. archive round 37 as a comment on #3398 would run: gh issue comment 3398 --repo ptr727/ProjectTemplate --body-file <body-file> 2. write round 38 over the body of #3398 would run: gh issue edit 3398 --repo ptr727/ProjectTemplate --title Session Handoff [engineering]: Dry run --body-file <body-file> #3398 exit 0 $ python3 scripts/handoff.py close --repo ptr727/ProjectTemplate --track engineering --body-file <constructed> --dry-run 1. comment the outcome on #3398 would run: gh issue comment 3398 --repo ptr727/ProjectTemplate --body-file <body-file> 2. close #3398 would run: gh issue close 3398 --repo ptr727/ProjectTemplate #3398 exit 0 ``` Afterwards, #3398 still read `OPEN` with its comment count unchanged. `chain --track engineering --limit 3` exited 0 on the pre-change chain. ## Local review Three `local-strict-review` passes ran at the `frontier` tier and are recorded. Rounds 1 and 2 raised findings that this branch fixes: - comments go through `--body-file`, so a round near the cap fits a Windows command line, - an outsider's round mark is ignored, - each archived round keeps its own title, - text comparisons tolerate line endings, through `carry.normalize_eol` rather than a new helper, - `close` reads its outcome as an outcome and refuses a round mark, - the comment read leaves archived rounds out and shows each comment's author association, - `unattended-handoff` step 7 ends a lane with `close`. Two more passes covered the fix push that answers Copilot's first round. Their findings are fixed in 05982c0 and d364a95: - the comment read in both skills keeps only visible comments from writer accounts and drops a comment only where one of its lines is a whole round mark, so it agrees with `rounds_of`, - `new` refuses where the body moved since the track was listed, or where a round is archived twice, - `close` reuses an outcome comment only from a writer, - the worker's comment rule covers comments on its handoff, not the decision-issue comments its step 3 reads. No `introduced` finding is open. ## Follow-ups: other restatements of the old semantics These still use "link" vocabulary or describe the old per-session issue. None of them instructs the old create, comment, close order, so they are left for a follow-up. - `GOVERNANCE.md` line 22: "hands the link back". Its meaning still agrees with the new step 6. - `.agents/skills/session-handoff/SKILL.md` "The Attended Session" step 1: "Pick the link", plus the other uses of "link" in that step. - `.agents/skills/backlog-burndown/SKILL.md` line 112: "It is a link in the session handoff chain". - `.agents/skills/unattended-handoff/SKILL.md`: - line 281: "starting at its open link and reading every link's body and comments" reads whole comment lists, archived rounds included, - lines 8 and 288: "closes the lane out". - `repo-config/labels.json` line 16: the `handoff` label description, "A link in the session handoff chain". - A `handoff.py` read of a track's non-round comments, so the comment filter in both skills lives in one place with `rounds_of`. ## Pre-existing findings, not filed These are listed under Decision ptr727 2026-10-23, #3391 item 2. - The `--check sentence-length` hits on sentences this change only rewrapped or touched by one word: `AGENTS.md:40` (four sentences), `.agents/skills/session-handoff/SKILL.md` (lines 35, 37, 54, 89, 105, and others in kept text), `.agents/skills/unattended-handoff/SKILL.md` (lines 225, 260, 262), `scripts/README.md` (lines 256, 272, 278), and `scripts/handoff.py` (lines 7, 34, 94, and others). The check is opt-in and not gated. - `scripts/handoff.py` lines 443, 898, and 1322 run over 100 characters, which predates this branch. E501 is not selected. - The old "link" vocabulary sites listed under Follow-ups. - `.agents/skills/unattended-handoff/SKILL.md` worker step 1, "read the answer recorded there and follow it": the answer on a decision issue is read with no writer filter, so an outsider's comment posing as the answer could be followed by an unattended worker. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary Copilot's hosted review runs once per change, at the `develop -> main` promotion pull request, and not on feature pull requests into `develop`. Why: measured on 2026-10-16 to 2026-10-23, the four most active fleet repositories ran 418 Copilot reviews and about 2,200 workflow runs for 382 merged pull requests, and a promotion re-reviews content its feature pull requests already carried. So the hosted review runs once per change, at the promotion, and the feature pull request carries the local pass and CI. Decision (ptr727, 2026-10-23) on #3391, item 4. - `repo-config/develop.json`: the `copilot_code_review` rule is removed. `repo-config/main.json` is unchanged and keeps it. - `scripts/pr_review.py`: `round_before_head` is removed from `holds` and `local_cover`, and the function itself is deleted since nothing else reads it. On a pull request whose base is not the repository's default branch, `wait` requests no Copilot review, and an attested local pass alone satisfies coverage on the head (`review_on_head=local coverage=local`), with the digest saying so. Exceptions kept as they were: a partial Copilot round on record, a review history past the 100-review window, or a request already pending. A pull request into the default branch is unchanged. Every exit code keeps its meaning: `49` is still "no round covers this head, none was requested, and no attestation vouches for it", now reachable on the first head too. The docstring, the `--request` help, the held note, the exit-49 message, and the `COVERAGE IS READ FROM THE LOCAL PASS` digest line are edited in place. - `tests/test_pr_review.py`: constructed fixtures for both base-branch cases. A feature pull request with no Copilot round is never requested (unattested exits `49`, attested exits `0` with `coverage=local`), `status` reads `review_on_head=local` there, a promotion with no round reads `review_on_head=NO` and no local cover, and a promotion is still requested with or without an attestation. The tests that asserted the old first-round rule now assert the new one, and `holds`/`local_cover` are tested directly on both bases. No test calls the live API. - `.agents/skills/drive-pr/SKILL.md` step 3, plus its regenerated mirrors only: request no Copilot round on the feature PR, read the attestation as `coverage=local`, and what clears exit `49`. The promotion steps are unchanged. - In-place sentence edits where a statement became false: `repo-config/README.md` "Rulesets", `scripts/README.md` (the `pr_review.py` review-moment paragraph), `docs/pr-reviewer-reference.md`, `.github/copilot-instructions.md`, and `TODO.md`. ## Applying the Ruleset Change `configure.sh apply` updates an existing ruleset with a `PUT` that replaces the whole document, so removing the rule from `develop.json` removes it from the live `develop` ruleset when apply runs, rather than only no longer asserting it. `configure.sh check` compares the rule-type set in both directions, so until apply runs it reports drift on every release-model repository, and the live `develop` ruleset keeps requesting a Copilot review when a feature pull request opens. Nothing here ran `configure.sh` against any repository. Per `repo-config/README.md`, run it from a hub checkout at `main` once this change is promoted. For one repository: ```sh repo-config/configure.sh apply ptr727/ProjectTemplate release ``` Then `repo-config/configure.sh check ptr727/ProjectTemplate release` confirms it. Each other release-model repository takes the same command with its own name. ## Follow-up: pr-review-conduct Merge Gate text `.agents/skills/pr-review-conduct/SKILL.md` is held by another lane, so this pull request leaves it alone. Until the follow-up lands, it and `GOVERNANCE.md` "PR Review Etiquette" still state the first-round rule this change retires. **Merge Gate item 2.** Replace the sentence that opens "On a pull request into a branch other than the default, a head after Copilot's first round can carry an attested local pass instead" with: > On a pull request into a branch other than the default, every head can carry an attested local pass instead, `coverage=local` in the digest, where the whole review history is in view and no round on record states or appears to state partial coverage. A promotion re-reviews content its feature pull requests already carried, so the hosted review runs once per change, at the promotion. A pull request into the default branch, a promotion among them, always carries a Copilot round on its head. The same follow-up also owes these sentences, which state the same retired rule: - pr-review-conduct "Expected review loop" step 3, the first four sentences and the sentence beginning "`status` and `wait` never read", replaced by: "Request a Copilot round at one defined moment only: the head of a pull request into the default branch, a promotion among them. Auto-trigger is unreliable, so request it explicitly, which step 4's `wait` is what does. On a pull request into any other branch, `wait` requests nothing and reads step 1's attestation as `coverage=local`. Pass `wait --request` where a change deserves a Copilot round anyway." The sentences from "`wait` also skips the request" onward stay as they are. - pr-review-conduct "Which Reviewers a Repository Actually Has", the "Copilot's absence blocks, and is answered elsewhere." bullet: "Merge Gate item 2 requires Copilot's own coverage of the current head, or on a fix push into a branch other than the default an attested local pass," becomes "Merge Gate item 2 requires Copilot's own coverage of the current head, or on a pull request into a branch other than the default an attested local pass,". The rest of that bullet stays as it is. - `GOVERNANCE.md` "PR Review Etiquette", a verbatim-carried section: "Request a review at defined moments rather than on every push: when the pull request opens, and on the head of a pull request into the default branch, a promotion among them." becomes "Request a Copilot review at one defined moment rather than on every push: the head of a pull request into the default branch, a promotion among them." And "On a pull request into any other branch, a fix push after the first round is covered instead by the recorded local pass the push already owes, published to the pull request so the review status can read it." becomes "On a pull request into any other branch, every head is covered instead by the recorded local pass the push already owes, published to the pull request so the review status can read it." ## Verification Run from the worktree with `COVERAGE_FILE`, `MYPY_CACHE_DIR`, `UV_CACHE_DIR`, and `RUFF_CACHE_DIR` under a scratch cache directory, per `OPERATIONS.md`. Results, the full suite rerun at the final head as the second test row shows: | Command | Result | | --- | --- | | `uvx ruff@latest format --check .` | `257 files already formatted`, exit 0 | | `uvx ruff@latest check .` | `All checks passed!`, exit 0 | | `uvx mypy@latest` (the `[tool.mypy]` CI checker in `pyproject.toml`) | `Success: no issues found in 63 source files`, exit 0 | | `python3 -m unittest tests.test_pr_review` | `Ran 958 tests in 23.203s` / `OK` | | `uvx coverage@latest run --source=scripts,spec,host-setup -m unittest discover -s tests` | `Ran 3059 tests in 206.598s` / `OK (skipped=7)`, exit 0 | | `python3 -m unittest discover -s tests`, rerun at the final head `5b5ae9ad` | `Ran 3059 tests in 214.314s` / `OK (skipped=7)` | | `spec/audit.py --selftest` under coverage | `SELFTEST PASS`, exit 0 | | `spec/workflow_reuse.py --selftest` under coverage | `workflow_reuse selftest OK`, exit 0 | | `gh-write-guard.py --selftest` under coverage | `SELFTEST PASS`, exit 0 | | `python3 scripts/build_dist.py --check` | `Generated skill distributions are current.`, exit 0 | | `python3 scripts/canonical_review.py status` | exit 0 | | `python3 scripts/repo_gate.py` | every check `[ok ]`, exit 0 | | `python3 scripts/prose_lint.py . --check charset --check semicolon --check dash --check dupword --check spelling --check comment-wrap --check comment-case --check home-path --check dead-path --check issue-ref` | `scope: 378 file(s) read, whole tree`, exit 0 | | `python3 scripts/prose_lint.py --diff origin/develop` | `scope: 12 of 378 file(s) read, 130 changed line(s)`, exit 0 (same result at the final head) | | `jq empty` over `registry/*.json spec/*.json repo-config/*.json` | no output, exit 0 | | `python3 spec/validate.py` | `Spec validation OK: 22 cataloged repos classify cleanly.`, exit 0 | Not run: `scripts/docker_lint.py`, which needs Docker and repository-exposure approval this seat does not hold, the live-repository `spec/audit.py`, and `repo-config/configure.sh check`, which this change was briefed not to run against any repository. `OPERATIONS.md` names the last two for a change to `repo-config/`, so they are the maintainer's after the apply step above. The opt-in `--check sentence-length` run is listed under the local review below. ## Local Review Five recorded `local-strict-review` passes, at the `frontier` tier, against `develop`: 10 findings, then 4, then 2 before the first push, then 3 after Copilot's round, then 0, then 0 again after merging `develop` to clear a conflict in the generated `drive-pr` digest. Every introduced finding is fixed, so none remains open. One first-round finding is answered here rather than in code: a release-model repository keeps its live Copilot rule on `develop` until `configure.sh apply` runs there, and the spec's `branch.ruleset.develop` check reports drift until then. "Applying the Ruleset Change" above names the command. Copilot's round raised three findings. One, on `docs/pr-reviewer-reference.md`, is fixed. Two, on the drive-pr step and the Copilot instructions, are the known disagreement with `pr-review-conduct` and `GOVERNANCE.md` that the follow-up above carries, and are declined in their threads on that boundary. ## Pre-existing findings, not filed Per Decision (ptr727, 2026-10-23) on #3391, item 2, these are listed rather than filed. Each is a sentence over the opt-in 25-word `sentence-length` cap that this branch did not write and only trimmed, rewrapped, or left beside an edit: - `.github/copilot-instructions.md:31`: six sentences in the "GitHub Copilot Review Runbook" paragraph. - `docs/pr-reviewer-reference.md:27`: the 55-word and 28-word sentences after the edited ones. - `repo-config/README.md:15`: the 43-word opener of the `operational` bullet. - `repo-config/README.md:17`: the 38-word opener of the `main` paragraph. - `scripts/README.md:181`: five sentences in the review-moment paragraph. - `TODO.md:140`: the 42-word Settled bullet. - `scripts/pr_review.py`: the sentences at lines 100, 306 (the 58-word bot-id sentence), 310, and 6067. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Summary Brings the review rule text in line with two changes already on `develop`: Copilot's hosted review runs once per change, at the promotion, and a `pre-existing` finding is listed in the pull request body rather than filed unless it is a correctness defect with a stated failure. Prose only, no code. Decision (ptr727, 2026-10-23) on #3391, items 2 and 4. ### Copilot reviews once per change, at the promotion Applies the replacement text from #3403's "Follow-up: pr-review-conduct Merge Gate text", in place: - `.agents/skills/pr-review-conduct/SKILL.md` "Merge Gate" item 2: every head on a pull request into a branch other than the default can carry an attested local pass (`coverage=local`), and a pull request into the default branch always carries a Copilot round. - Same item 2, promotion evidence path: a constituent feature pull request's full coverage comes from its attested local pass or a Copilot round, and a Copilot table row on the promotion itself counts as per-file evidence. The "lacked that coverage" example reads "no attested local pass and no review round". - "Expected review loop" step 3: one defined moment, the head of a pull request into the default branch. Elsewhere `wait` reads the attestation as `coverage=local` where Merge Gate item 2 allows that reading, and requests a round only where a partial round or a truncated review history is on record (the review found the dictated sentence dropped the exception `pr_review.py` keeps). - "Copilot's absence blocks, and is answered elsewhere": "on a fix push into" becomes "on a pull request into". - `GOVERNANCE.md` "PR Review Etiquette": the two first-round sentences, a sentence naming the review wait's partial-history request, a pointer to the Merge Gate for when the published pass counts as coverage, and the following sentence's "for such a fix push", which referred to the retired case and is recast around "on such a pull request". ### Class-sweep sibling takes the pre-existing outcome - `GOVERNANCE.md` "Verification Discipline": a pre-existing sibling in an untouched file stays out of the diff, and such a sibling takes the outcome a `pre-existing` finding takes under `pr-review-conduct` outcome 4, by pointer. - `pr-review-conduct` outcome 1: "filing the rest" becomes "recording the rest as outcome 4 records a `pre-existing` finding". - `pr-review-conduct` outcome 4: the sentence saying outcome 1 "keeps its own filing rule" for a sweep sibling says instead that the sibling takes those bullets as a `pre-existing` finding does. `GOVERNANCE.md` "Design Before Code" is deliberately unchanged. Its "Sites in files a change does not touch move in a change of their own, filed as one issue naming each" is a consolidation rule rather than the class-sweep sibling rule. Its bold lead says every site moves onto the primitive, and `pr-review-conduct` "Triaging findings" files the other sites as one issue to match. Sending those sites to outcome 4 would drop a consolidation finding and leave the lead false, so that change is left to the maintainer. `agent-conduct` and `drive-pr` change only inside generated include regions, regenerated with `python3 scripts/build_dist.py`, and the `.github/skills/` and `.claude-plugin/` mirrors are regenerated. ## Verification - `python3 scripts/build_dist.py --check`: `Generated skill distributions are current.` (exit 0) - `python3 scripts/prose_lint.py . --diff origin/develop`: exit 0, `scope: 13 of 380 file(s) read, 95 changed line(s)` at 466adc1 ## Local Review Four recorded `local-strict-review` passes at the `frontier` tier, the last over the pushed head with no findings. The two `introduced` findings the third pass left open, the one-moment rule against `wait`'s partial-history request and the implicit antecedent of the Merge Gate pointer, were raised again by Copilot and are fixed in 466adc1. Declined: `sentence-length` reports on edited sentences. The check is opt-in, and most of those sentences are either the dictated replacement text or pre-existing sentences with one clause changed. ## Pre-existing findings, not filed - `pre-existing`, `scripts/pr_review.py` module docstring (`attest`) and `scripts/README.md` `pr_review.py` section: "A promotion reads the comment only in its Merge Gate's per-file fallback" is stale since feature pull requests merge on `coverage=local`, so the promotion case's first bullet also reads the attestation. - `pre-existing`, `.agents/skills/pr-review-conduct/SKILL.md` "Which Reviewers a Repository Actually Has": the bold lead "Copilot's absence blocks, and is answered elsewhere" overstates the case for a pull request into a non-default branch, where an attested head merges with Copilot absent. The dictated replacement left the rest of that bullet as it is. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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. Comment |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved review findings affect backlog label coverage, review-cost scoping, unattested-head reporting, and consistency in the local review guidance.
1 open issue
What changed in this PR
This pull request promotes fleet-wide review-process and review-cost changes from develop to main. It moves hosted Copilot review to promotion pull requests, adds backlog metrics reporting, consolidates handoff tracking, and updates governance, safety, and skill documentation.
Changes:
- Adds
scripts/backlog_metrics.py, CLI registration, tests, and reporting documentation. - Updates review tooling and rulesets for attested local feature-PR coverage and promotion-only Copilot review.
- Revises handoff procedures, finding-disposition rules, write-guard documentation, and generated skill mirrors.
| File | Reviewed changes and final review note |
|---|---|
TODO.md |
Records the settled Copilot ruleset decision. |
tests/test_pr_review.py |
Tests promotion-only Copilot review and local-pass coverage. |
tests/test_cli_usage.py |
Registers the new backlog metrics script. |
tests/test_backlog_metrics.py |
Tests backlog metrics collection, billing, rendering, and failures. |
scripts/README.md |
Documents the metrics script and updated review workflow. |
scripts/pr_review.py |
Implements local coverage for feature pull requests and promotion review; final review found that an unattested head can be labeled as covered. |
scripts/backlog_metrics.py |
Adds backlog and review-cost reporting; final review found incomplete configured-label coverage and no consistently scoped cost-per-merged-PR metric for the selected window. |
repo-config/README.md |
Documents the ruleset split and review model. |
repo-config/develop.json |
Removes Copilot review from the develop ruleset. |
host-setup/agent-safety/README.md |
Documents the write-guard threat model and allowed command shapes. |
host-setup/agent-safety/claude/gh-write-guard.py |
References the write-guard threat-model documentation. |
GOVERNANCE.md |
Aligns review and finding-disposition rules with the new workflow. |
docs/pr-reviewer-reference.md |
Updates manual review-request guidance. |
AGENTS.md |
Updates standing handoff issue behavior. |
.github/skills/unattended-handoff/SKILL.md |
Updates unattended handoff resumption and closure instructions. |
.github/skills/session-handoff/SKILL.md |
Documents standing issues and archived handoff rounds. |
.github/skills/pr-review-conduct/SKILL.md |
Updates coverage and finding-disposition rules. |
.github/skills/local-strict-review/SKILL.md |
Updates pre-existing finding handling. |
.github/skills/drive-pr/SKILL.md |
Uses local coverage on feature pull requests. |
.github/skills/agent-conduct/SKILL.md |
Updates class-sweep guidance. |
.github/copilot-instructions.md |
Aligns Copilot review instructions with promotion-only review. |
.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md |
Regenerated unattended-handoff mirror. |
.claude-plugin/fleet-skills/skills/pr-review-conduct/SKILL.md |
Regenerated review-conduct mirror. |
.claude-plugin/fleet-skills/skills/local-strict-review/SKILL.md |
Regenerated local-review mirror. |
.claude-plugin/fleet-skills/skills/drive-pr/SKILL.md |
Regenerated drive-pr mirror. |
.claude-plugin/fleet-skills/skills/agent-conduct/SKILL.md |
Regenerated agent-conduct mirror. |
.claude-plugin/fleet-skills/.source-digests/unattended-handoff |
Refreshes the unattended-handoff source digest. |
.claude-plugin/fleet-skills/.source-digests/session-handoff |
Refreshes the session-handoff source digest. |
.claude-plugin/fleet-skills/.source-digests/pr-review-conduct |
Refreshes the review-conduct source digest. |
.claude-plugin/fleet-skills/.source-digests/local-strict-review |
Refreshes the local-review source digest. |
.claude-plugin/fleet-skills/.source-digests/drive-pr |
Refreshes the drive-pr source digest. |
.claude-plugin/fleet-skills/.source-digests/agent-conduct |
Refreshes the agent-conduct source digest. |
.agents/skills/unattended-handoff/SKILL.md |
Updates authored unattended-handoff behavior. |
.agents/skills/session-handoff/SKILL.md |
Defines standing handoff issues, archived rounds, and track closure. |
.agents/skills/pr-review-conduct/SKILL.md |
Updates review coverage and finding outcomes; final review found a heading inconsistent with the local-pass exception. |
.agents/skills/local-strict-review/SKILL.md |
Aligns local finding disposition with the updated workflow. |
.agents/skills/drive-pr/SKILL.md |
Updates feature-PR and promotion review steps. |
.agents/skills/agent-conduct/SKILL.md |
Aligns sibling-finding handling with governance. |
Review effort: Lite
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3405 +/- ##
==========================================
+ Coverage 81.33% 81.61% +0.28%
==========================================
Files 18 19 +1
Lines 10049 10235 +186
==========================================
+ Hits 8173 8353 +180
- Misses 1876 1882 +6
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:
|
Answers the Copilot round on the develop -> main promotion #3405, whose findings sit on content merged into develop today. ## Changes - `scripts/pr_review.py`: `wait` on a pull request into a branch other than the default printed "its head is covered by an attested local pass" where no attested local pass covered the head, while the verdict returned `status=AWAITING_LOCAL_PASS`. The note is gated on `local_cover`, the predicate the poll and the verdict read, so a head with no attestation and an attested head Copilot refused each get a note naming what is still owed. Tests cover both cases and the attested case. - `.agents/skills/pr-review-conduct/SKILL.md`: the heading "Copilot's absence blocks, and is answered elsewhere." contradicted the local-pass exception its own bullet states. It reads "Copilot's absence blocks where no local pass stands in, and is answered elsewhere." The two long sentences under it are split. Mirrors regenerated with `build_dist.py`. - `scripts/backlog_metrics.py` and `scripts/README.md`: the README says the report lists open issues by label, while the script counted a fixed subset. The named labels still print first, a zero included, and every other label an open non-handoff issue carries follows them, sorted. The docstring said review cost per merged pull request reads from the report, but Actions minutes and the Copilot gross cover the calendar month while the counts cover the window. The report adds a `Copilot review runs per merged PR (ratio)` column over the window, and the docstring and README state the month scoping. ## Verification - `python3 -m unittest discover -s tests` -> OK - `uvx ruff@latest format --check scripts tests`, `uvx ruff@latest check scripts tests`, `uvx mypy@latest` -> clean - `python3 scripts/build_dist.py --check` -> current - `python3 scripts/prose_lint.py --diff origin/develop` -> no violations, and with `--check sentence-length` -> no violations - The new refused-head test fails with the note gated on `attested()` and passes with `local_cover()`. Three recorded `local-strict-review` passes at the `frontier` tier. The first raised the note's predicate (`attested` rather than `local_cover`), a docstring that said "print", and a 47-word sentence, each fixed in 34e23c1. The second raised the missing refused-head test and a 33-word sentence, fixed in 2e0d435. The third raised one finding with the edit budget spent, listed below. ## Open findings from the local pass - `introduced`: `tests/test_pr_review.py`, `test_an_attested_head_copilot_refused_is_not_called_covered` asserts only a non-zero exit, so a regression from the refusal's exit `41` to `AWAITING_LOCAL_PASS` (`49`) would still pass. **Fixed in b05e99a**, which asserts exit `41` and fails with the note gated on `attested()`. A fourth recorded pass over that push raised nothing. ## Review Copilot reviewed 2e0d435 and raised three findings, each fixed and answered in its thread: the shared wait note read as sending a refused, already-attested head to attest (5a202fd), the non-zero exit assertion (b05e99a), and the README label sentence that did not say handoff issues are left out (5a202fd). A fifth recorded pass over 5a202fd raised nothing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Answers to the findings the Copilot round on d148ffbf states only in its file table notes, beside the one thread it opened. The round collapses no suppressed block, so there is no
|
|
Answer to the headline of the Copilot round on 4a77a1d1, which opens on "Needs a closer look" and counts no finding. The round collapses no suppressed block, so there is no
|

Summary
Promotes these pull requests from develop. Each carries a maintainer decision recorded on #3391.
-Cvalue and anxargsreplace string run as a shell script (item 1).closesubcommand that ends a track (item 5).waitnote for a head no local pass covers, the pr-review-conduct heading, and the backlog report's label line and cost scoping.Closes #3382
Closes #3385
Pre-existing findings, not filed
local_coverinscripts/pr_review.pyrefuses an attested head whose current Copilot round is a refusal, andwaitexits41there. Thewaitentry of thepr_review.pydocstring ("An attested head is covered at once.") and thescripts/README.mdparagraph on the defined review moments ("Where it is attested,waitpolls the head's checks instead.") leave that exception out.pr-review-conductMerge Gate item 2 states it ("A refusal is not that coverage"). Both omissions are onmainalready, so this promotion did not introduce them.🤖 Generated with Claude Code