Repository navigation
Conversation
…e Kit's autoMode Entries (#3704) ## Why Agents driving work under `drive-pr`, `backlog-burndown`, and `unattended-handoff` reach a feature pull request whose gate is met. Then Claude Code's auto-mode classifier denies the hand-typed `gh pr merge --squash` as "Merge Without Review". This happens most often inside a subagent, which sees neither the review nor the maintainer's go-ahead. The agent then hands the maintainer a command, sometimes while a prompt is open and the command cannot run. `pr_review.py cleanup` already shows the fix pattern. It runs its checks in code under the installer's `pr_review.py` allow rule, and auto mode completes it. This change gives the develop merge the same shape. Authorization to merge stays with the skills. The code guarantees that the merge is into `develop`, at the gated head, inside the registry scope, and with the Merge Gate's mechanically readable items met. A develop -> main promotion merge is unchanged and stays the maintainer's. ## What Changes - **`pr_review.py merge NUMBER --repo OWNER/NAME [--cleanup --checkout DIR]`** (new `scripts/pr_merge.py`) merges only when all of these hold: - `wait`'s gate exits 0, with no review request. - A fresh read of the digest's field tuples shows coverage, zero open threads, every no-thread count zero, and `mergeStateStatus` CLEAN. A missing or unreadable count fails closed. - The base is `develop`, the head is neither a fork nor a permanent or protected branch, and the target is inside the registry scope. - The merge is pinned with `--match-head-commit` and confirmed by reading it back. A refused merge (exit 1) is told apart from an unconfirmed one (exit 2). - It shares the target query and reader with `pr_cleanup.py`. - **Skills.** - `drive-pr` step 4, `backlog-burndown`, and `unattended-handoff` route develop merges through `merge`. - Clearable refusals go back to the review loop. - `MERGE_NOT_CONFIRMED` is read back before anything is reported. - A harness refusal of the call itself follows the refused-write rule. - **GOVERNANCE "Repository Boundaries and Write Safety".** The refused-write rule now names a gate-checked subcommand the maintainer's installer allows as a route sanctioned in advance. It is never reached for after a hand-typed form of the same write was refused. - **Host-safety installer (Claude Code).** - The kit now owns tagged (`[agent-safety] `) entries in `settings.json` `autoMode`. - It never removes, reorders, or rewrites an untagged entry, so each host's own rules survive. - It keeps `$defaults` in any list it creates, and its entries join the stamp digest so `--report` shows them stale. - Until now `autoMode` was unmanaged. Claude Code reads it only from user or managed settings, so one repository's content had drifted in host-wide. ## Local Review Findings and Their Outcomes Each push carried a recorded local strict pass, with up to two edit rounds per push. Every finding those passes raised was either fixed in a later commit on this branch or has one of the outcomes below. - **Deferred to #3724** (`merge` prints its own next step, so the skills stop listing status lines): a `CLOSED` read-back route, a merge landing during the gate's own read, step 3 against step 4 on reporting a peer merge, and the `BEHIND`/`DIRTY`/`UNKNOWN` clearing routes. - **Deferred to #3718** (an acknowledgment record): `merge` stays strict on answered earlier-round findings and noted output, per the maintainer's decision. - **Deferred, design reuse:** `ready()` repeats `cleanup_check`'s refusal list. `auto_mode_misshape` and `report()`'s autoMode walk could share `main()`'s shape table and `tagged_auto_mode`. `read_settings` sits beside `registration_problems`. The `--repo` parse is a third copy, and the other two copies predate this branch. - **Declined:** a `__main__` guard in `pr_merge.py`, since `test_cli_usage` then requires a full entry point and the module is reached only through `pr_review.py merge`. The existing allow rule approving `merge` before the installer re-runs, since the maintainer installed it, merging is the maintainer's act, and `--report` reads stale until the re-run. The non-string guard in `tagged()`, which an earlier round asked for. The attested pass's own finding count, which is a PR-body finding the driver already disposes of. - **Open premise, settled by this PR's own merge:** whether auto mode keeps the `Bash(uv run --no-project --script scripts/pr_review.py:*)` allow rule. This pull request is merged with `pr_review.py merge`, which is the live test. ## Verification - `tests/`: `test_pr_merge test_pr_review test_pr_review_size test_pr_cleanup test_cli_usage test_build_dist` pass, 790 tests. - `host-setup/agent-safety/claude/test_install.py` passes, 182 tests. - ruff 0.17.3 format and check, mypy, `build_dist.py --check`, and the prose gate (`--allow-comments`, the `comments` label) all pass. - Not exercised live yet: `merge` against a real pull request, and a classifier run with the new `autoMode` entries. Both follow the release and the installer run. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…3735) ## Why An unattended run often ended saying it needed the maintainer when nothing did. The picker had a single reply, `NONE`, for every kind of skip, and the run's final message routed that to the attended session as if a decision were waiting. Its exclusions stacked on each other: attended tracks, issues any handoff names, burndown claims, and an all-or-nothing "outcome determined" test. It also ran one worker per round. `backlog-burndown`, which works parallel file-claimed groups, proved more effective at running unattended. ## What - **`backlog-burndown` gains an away mode.** - It keeps the same rounds and the same file claims. - A lean orchestrator holds only what a planner subagent and the workers return. - A group meeting a question parks behind a `decision` issue instead of asking. The park is recorded in its claim comment, and the decision is named on every pull request it blocks. - Merges go only as far as the `develop`, `main` or `release` scope named at invocation. - The end report names every held-back issue under the reason that actually holds it back, and counts only real questions as needing the maintainer. - It brings over the parts of the retired loop it still needs: the transient dispatch retry, the one-run-per-repository rule, the write-access comment filter, the blocked-promotion hold and the standing promotion grant. - Ranking now also holds back an issue already fixed on develop until a promotion closes it. This applies to attended runs as well. - **New `decision-triage` skill (attended).** - Classifiers sort the open issues into fixable alone, question, split, or held for another reason. - Researchers return a recommended answer per question, and each question is filed as a `decision` issue. - The whole queue is then put to the maintainer at once, and the answers are applied. - It owns the "Needs the Maintainer" test, which `backlog-burndown` carries as a generated include. It carries `GOVERNANCE.md` "Communicating with the User" as an include rather than paraphrasing it. - **`unattended-handoff` is retired.** References in `AGENTS.md`, `session-handoff`, `merge-and-release`, `pr-review-conduct`, `local-strict-review` and `repo-config/README.md` are swept. Open `auto-*` lanes an earlier loop left are picked up by the away mode. Closes on promotion: #3375 ## Local review All `local-strict-review` passes ran at the `frontier` tier, over the whole branch diff each time. - Before the first push, three passes raised 15, then 3, then 1 introduced findings. The first two rounds fixed theirs in 62e8ce6 and cb52db2. - The 1 left open at the first push was the promotion hold keyed on any claim release. It is fixed in 0990687. - The follow-up passes raised two more on that fix: a no-merge answer holding the promotion forever, and a dropped answer leaving its issue re-ranked. They are fixed in 706460d and 24603cc. - The pass on 24603cc raised nothing. - Copilot's round on cb52db2 opened 3 threads. One was already fixed. Two were real: outsider issue text steering an away run, and operational-model direct pushes missing from the fixed set. They are fixed in af29ce3. - Passes on that fix raised 4, then 1. They are fixed in 6f0dac6 and c42e20e. The pass on c42e20e raised nothing. ### Open introduced findings None. ## Related open issues the retirement may overtake None is closed here, since closing on judgment is the maintainer's call. Each targets the retired skill: - #1853 is partly covered by "Trusting a Comment". - #2342 is covered by the away-mode review-handback step. - #2378: the picker it names no longer exists. - #2183: lessons are filed as `decision` issues. - #2433: the agent-safety rule is now in "Needs the Maintainer". 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3736 +/- ##
==========================================
+ Coverage 82.02% 82.31% +0.28%
==========================================
Files 27 28 +1
Lines 9275 9438 +163
==========================================
+ Hits 7608 7769 +161
- Misses 1667 1669 +2
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:
|
There was a problem hiding this comment.
🟡 Changes recommended
Approval is blocked by an unresolved critical race that can merge into the wrong base branch, plus a read-back handling issue that misclassifies definitively refused merges.
2 open issues
What changed in this PR
This promotion moves changes from develop toward main, adding gate-checked feature merging, host-safety autoMode ownership, and backlog-burndown away mode with attended decision triage while retiring unattended-handoff.
Changes:
- Adds
pr_review.py mergeandpr_merge.pywith gate validation, pinned squash merges, confirmation, cleanup integration, documentation, and tests. - Adds host-safety ownership, preservation, validation, and reporting for tagged Claude Code
autoModeentries. - Replaces
unattended-handoffwithbacklog-burndownaway mode anddecision-triageacross canonical and generated skill distributions.
Review findings:
scripts/pr_merge.py:90— [P1] critical, 1 vote: the final merge-target payload is not revalidated, allowing a retargeted pull request to merge intomain.scripts/pr_merge.py:167— [P1] moderate, 1 vote: requested cleanup is skipped when the pull request was already merged by a peer.scripts/pr_merge.py:217— [P2] moderate, 2 votes: a closed read-back after a failed merge is reported ambiguously instead of as a definitive refusal.
This pull request requires changes.
| File | Summary |
|---|---|
tests/test_pr_review.py |
Tests merge command parsing, gate polling, and non-requesting wait behavior. |
tests/test_pr_review_size.py |
Adds the size ceiling for pr_merge.py. |
scripts/README.md |
Documents the merge command and its contract. |
scripts/pr_review.py |
Adds merge forwarding, merge flags, and non-requesting gate waits. |
scripts/pr_review_digest.py |
Exposes digest fields and standardized count labels for merge validation. |
scripts/pr_merge.py |
Implements gate-checked squash merging, read-back confirmation, and optional cleanup. |
scripts/pr_cleanup.py |
Shares pull request target reads and permanent-branch checks. |
repo-config/README.md |
Updates parked-handoff terminology for away mode. |
host-setup/agent-safety/claude/test_install.py |
Tests tagged autoMode installation, reporting, preservation, and malformed settings. |
host-setup/agent-safety/claude/README.md |
Documents managed permissions and autoMode behavior. |
host-setup/agent-safety/claude/install.py |
Manages tagged autoMode entries and includes them in digests. |
GOVERNANCE.md |
Defines the sanctioned gate-checked merge command shape. |
AGENTS.md |
Routes unattended backlog work through away mode and decision triage. |
.github/skills/session-handoff/SKILL.md |
Replaces retired unattended-handoff handling with away-mode behavior. |
.github/skills/pr-review-conduct/SKILL.md |
Documents merge forwarding and away-mode promotion evidence. |
.github/skills/merge-and-release/SKILL.md |
Recognizes away-mode promotion grants. |
.github/skills/local-strict-review/SKILL.md |
Removes retired unattended-handoff references. |
.github/skills/drive-pr/SKILL.md |
Routes feature merges through pr_review.py merge. |
.github/skills/decision-triage/SKILL.md |
Adds the attended decision-triage procedure. |
.github/skills/backlog-burndown/SKILL.md |
Adds away-mode rounds, parking, promotion, and reporting rules. |
.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md |
Generated Claude Skill copy of the session-handoff updates. |
.claude-plugin/fleet-skills/skills/pr-review-conduct/SKILL.md |
Generated Claude Skill copy of the review-conduct updates. |
.claude-plugin/fleet-skills/skills/merge-and-release/SKILL.md |
Generated Claude Skill copy of the release updates. |
.claude-plugin/fleet-skills/skills/local-strict-review/SKILL.md |
Generated Claude Skill copy of the review updates. |
.claude-plugin/fleet-skills/skills/drive-pr/SKILL.md |
Generated Claude Skill copy of the merge-routing updates. |
.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md |
Generated Claude Skill copy of the new triage skill. |
.claude-plugin/fleet-skills/.source-digests/unattended-handoff |
Removes the retired skill digest. |
.claude-plugin/fleet-skills/.source-digests/session-handoff |
Updates the generated session-handoff digest. |
.claude-plugin/fleet-skills/.source-digests/pr-review-conduct |
Updates the generated review-conduct digest. |
.claude-plugin/fleet-skills/.source-digests/merge-and-release |
Updates the generated release digest. |
.claude-plugin/fleet-skills/.source-digests/local-strict-review |
Updates the generated review digest. |
.claude-plugin/fleet-skills/.source-digests/drive-pr |
Updates the generated drive-pr digest. |
.claude-plugin/fleet-skills/.source-digests/decision-triage |
Adds the new triage digest. |
.claude-plugin/fleet-skills/.source-digests/backlog-burndown |
Updates the generated backlog digest. |
.claude-plugin/fleet-skills/.claude-plugin/plugin.json |
Registers decision-triage and removes unattended-handoff. |
.agents/skills/session-handoff/SKILL.md |
Updates the canonical session-handoff skill. |
.agents/skills/pr-review-conduct/SKILL.md |
Updates the canonical review-conduct skill. |
.agents/skills/merge-and-release/SKILL.md |
Updates the canonical release skill. |
.agents/skills/local-strict-review/SKILL.md |
Removes the retired unattended-handoff reference. |
.agents/skills/drive-pr/SKILL.md |
Routes feature merges through the gate-checked command. |
.agents/skills/decision-triage/SKILL.md |
Adds the canonical decision-triage skill. |
.agents/skills/backlog-burndown/SKILL.md |
Adds canonical away-mode procedures. |
Review effort: Lite
## Why Copilot's round on promotion #3736 found that `pr_review.py merge` reports a pull request read back `CLOSED` after the merge call as `MERGE_NOT_CONFIRMED`, exit `2`, "may still land on the server". A closed pull request cannot merge later, so a driver following `drive-pr` step 4 was sent to read back a merge that cannot have happened. ## What - A read-back of `CLOSED` is `status=REFUSED`, exit `1`, nothing merged, whatever `gh` answered. The `scripts/README.md` contract says so. - It shares the branch an `OPEN` refusal already takes, so `pr_merge.py` stays under its size ceiling. The first push's separate branch tripped `test_pr_review_size.py` in CI. The line now names the state it read and what `gh` answered, or `nothing` where the call never finished. - A test covers `gh` exit `0`, exit `1`, and a call that never finished. It fails on the previous code, which returned exit `2` for each. The same round's other two findings are answered on #3736 rather than changed here: - **Retargeted base:** `ready()` already re-checks the base on the read after the gate, at `scripts/pr_merge.py` in `merge()`. - **Cleanup skipped on `PEER_MERGED`:** `scripts/README.md` "`pr_merge.py`" and `drive-pr` step 4 state this as the contract. ## Local review Two `local-strict-review` passes ran at the `frontier` tier. - The first raised 3 findings. A redundant base check I had added was dropped, together with its README claim. The closed read-back test's subtests now read only their own output. - The second raised nothing. - After the CI ceiling failure, the third raised 1: the shared branch named a `gh` refusal that had not happened. The fourth raised nothing. - The full suite of 3249 tests passes locally. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Answering the round on 06e45c4's findings list item with no thread (the round lists 3 findings, 2 with threads, both answered there).
No change needed. This is the documented contract. |
There was a problem hiding this comment.
🔵 Needs a closer look
The change introduces autonomous GitHub merges and host-wide Claude Code autoMode behavior, but the supplied tests do not verify live classifier, merge, or recovery operations, leaving critical production boundaries for maintainer validation.
No open issues 🎉
2 resolved since last review
Review effort: Lite
|
Answering the round on 4b7c352, whose verdict is
No change needed here, and the live validation it names is on record or tracked.
Merge Gate item 2, promotion case. |
…Fetch Before Its History Check (#3762) Promotes the changes merged into `develop` since promotion #3736 to `main`. - [#3760](#3760) improves `decision-triage` from its first full run: - Researchers take topic clusters, and step 3 states the researcher count and a token estimate before dispatching. - The researcher brief reads every comment newest last, says its output is posted publicly, and bounds writes to a scratch directory of its own. - The classifier can return `OVERTAKEN` after a cheap history check, and a new step offers to close overtaken issues. - Coupled questions are asked in one prompt. - A new `deferred` label marks a "not yet" answer, which the classifier and `backlog-burndown` skip and report by count. - A recorded maintainer approval lets an attended run implement an agent-safety edit, with the merge still waiting on a per-PR go-ahead. - [#3763](#3763) has the triaging session fetch `main` and `develop` once before dispatching the history check and the researchers, and stop if the fetch fails. The subagents read the full remote-tracking refs and fetch nothing. It answers this promotion's first review round. After the release, the maintainer runs `repo-config/configure.sh apply ptr727/ProjectTemplate` to create the `deferred` label, then labels #781, #1464 and #2174 `deferred`, per #3760's "After Merge". Deferred review findings: #3761 (an attended `backlog-burndown` run applies no agent-safety hold to an unapproved issue). Fixes #3759 🤖 Generated with [Claude Code](https://claude.com/claude-code)


Promotes the changes merged into
developsince promotion #3715 tomain.#3704: squash-merges a gate-met feature pull request through
pr_review.py merge, and the host-safety kit now owns itsautoModeentries.#3735 adds an away mode to
backlog-burndown:decisionissue instead of asking.develop,mainorreleasescope named at invocation.It also adds the attended
decision-triageskill, which researches and asks every open question at once, and retiresunattended-handoff.#3737 reads a pull request that reads back closed after
pr_review.py merge's merge call as a refusal that merged nothing, rather than as an unconfirmed merge. It answers this promotion's first review round.After the release, the host-safety installer re-run that #3704 needs is still the maintainer's, per its handoff #3734. That handoff's step 3 names an
unattended-handoffworker. That skill is retired here, so the verification runs from abacklog-burndownworker instead.Fixes #3375
🤖 Generated with Claude Code