Skip to content

docs(skills): maintainer-driven tool actions and duplicate-cluster resolution - #970

Merged
castrojo merged 6 commits into
mainfrom
pr-review-cluster-doctrine
Sep 23, 2026
Merged

castrojo merged 6 commits into
mainfrom
pr-review-cluster-doctrine

Conversation

@castrojo

@castrojo castrojo commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

Why

Downstream in projectbluefin/review, the maintainer's PR-walk tool (bluefin-review queue) detects duplicate clusters but could not act on them: a local test banned pr merge outright — stricter than the doctrine it implements. The ambiguity sat here: human-gates said "agents never self-merge" without distinguishing a tool executing the maintainer's explicit keypress, and pr-review had competing-pair detection with no cluster resolution verb.

What changes

  • human-gates.md (1.0 → 1.2): the Merge Gate now distinguishes agent self-merge (never) from a tool executing the maintainer's explicit per-item keypress with rulesets still enforced (the documented human-decides loop). The carve-out is bounded: it covers keypress-confirmed closes as well as merges, and auto-merge is in scope only when pinned with --match-head-commit to the head SHA captured alongside the diff the human reviewed. --admin, submitting reviews, and non-interactive batch mutation stay forbidden for any tool.
  • pr-review/SKILL.md (3.5 → 3.6): new "Duplicate-cluster resolution" pointer; the procedure itself lives in pr-review/references/duplicate-cluster.md (new, 83 lines) rather than inline, which keeps SKILL.md at 186 lines, well under the 500-line hard cap. The procedure: a human confirms the duplicate and names the survivor from diff evidence (complementary diffs stay as separate PRs), arm the survivor first pinned to the reviewed head, comment before close, one explicit keypress per mutation, never --reason "not planned", linked-issue re-check, halt on first failure.

Design memo driving this: projectbluefin/review session artifact, org review walk design (§0, §4, §9).

Validation

check-skill-frontmatter.sh, check-skill-index.sh, and check-doc-links.sh all exit 0 (frontmatter warnings pre-existing); index regenerated with generate_skill_index.py --write.

Assisted-by: Claude Opus 4.8 via GitHub Copilot
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

@castrojo
castrojo requested review from a team and repires as code owners August 8, 2026 22:48
@castrojo
castrojo enabled auto-merge August 8, 2026 22:55

@hanthor hanthor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. The carve-out is correctly bounded and the duplicate-cluster procedure is careful in the places that matter.

On the human-gates amendment. The distinction it draws is the right one — the concern behind "agents never self-merge" is unreviewed change reaching a protected branch, not the mechanical identity of the process invoking the API. A per-item maintainer decision with rulesets still enforced server-side doesn't create that risk. Retaining the three hard prohibitions is what makes it safe to state:

  • no --admin (the only one that actually bypasses protection)
  • no submitting an approving review (an agent must never manufacture the approval it then acts on — this is the load-bearing one)
  • no non-interactive batch mutation (preserves per-item intent)

--match-head-commit <sha> with the SHA read live is the best detail in here. Converting "the branch moved under us" from a race into a server-side refusal is exactly right, and it's the kind of thing that's easy to omit and impossible to notice until it bites.

Also correct: --body-file rather than --body with prose through a shell, and "a still-open issue with no remaining open PR is a finding to report, not something to silently fix." The latter keeps the agent from quietly papering over a state the human should see.


One gap I'd like addressed in the text: --auto is a deferred action, and the amendment's justification doesn't cover it.

The new human-gates paragraph rests on "the maintainer's explicit per-item keypress." But step (2) arms gh pr merge <S> --squash --auto, which lands the merge at some later point once checks pass — possibly minutes or hours after the keypress, unattended. That's still legitimate, but it isn't the same thing as the human pressing a key and the merge happening; it's the human pre-authorizing a conditional future merge.

--match-head-commit covers the obvious drift (a new push to the head), but not everything that can change between authorization and landing — the base branch advancing, a required check being reconfigured, or the superseded PRs in the cluster being reopened. Worth saying explicitly in human-gates.md that deferred/auto-merge is in scope for this carve-out and why the head-SHA pin is considered sufficient. Right now a reader could reasonably conclude auto-merge falls under "non-interactive batch mutation" and is forbidden, which contradicts the procedure in pr-review/SKILL.md. Since these two files are meant to be read together, that ambiguity is worth closing.

Minor: the ordering in the cluster procedure — arm survivor (2), then close superseded (3–4) — is the safe direction, since a failure mid-sequence leaves duplicates open rather than everything closed with nothing landing. Worth stating that rationale inline; "halting on the first failure" says what but not why this order, and the next editor might reasonably swap them to "clean up first."

Housekeeping: currently DIRTY against main — needs a rebase. Since index.json / index.md are generated by scripts/generate_skill_index.py, regenerate rather than hand-resolve those two if the conflict lands there.

@hanthor hanthor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically the cleanest PR in this queue — but the human-gates.md paragraph is a policy change, not a docs change

Verified against current main:

  • merges clean, validate green
  • python3 scripts/generate_skill_index.py --check → docs/skills/index.json and index.md are up to date (40 skills) — the index is properly regenerated here (2026-08-18 → 2026-09-06, moving forward, 40 skills preserved, with the matching version/last_updated bumps for human-gates and pr-review). Several other open docs PRs in this queue regress that file backwards; this one is the correct pattern.
  • python3 scripts/check-doc-links.sh → exit 0, so the new references/duplicate-cluster.md link from pr-review/SKILL.md resolves
  • bash scripts/check-skill-frontmatter.sh → only the pre-existing brew-lifecycle/SKILL.md is 208 lines (soft max 200) warning, unchanged from main
  • python3 -m pytest tests/test_skill_docs.py → 10 passed
  • nothing under system_files/, so no bluefin / bluefin-lts / dakota blast radius

The duplicate-cluster half is uncontroversial and, judging by this queue, needed — #942 is superseded by merged #1020, #1018 duplicates a bluespeed recipe already on main, and #1080/#1073 are a dependent pair. "Arm the survivor before closing the rest" is exactly the right ordering.

The part that deserves a deliberate yes, not a skim

The human-gates.md addition materially loosens the Merge gate:

This gate binds agents, not the maintainer's own hands. A review tool that executes a merge or close only on the maintainer's explicit per-item keypress — with rulesets and branch protection still enforced by GitHub — is the human acting at the gate, not an agent self-merging.

Read narrowly this is obviously true: a maintainer pressing a key per item is a human decision. But it is being written into the document that defines what agents may not do, and the load-bearing words are all in the carve-out — "explicit", "per-item", "keypress". Two questions worth answering in the thread before this merges, because after it merges this paragraph is what future agents will cite:

  1. What enforces "per-item"? The prohibition list that follows forbids "non-interactive batch mutation", but nothing here distinguishes fifteen individually-confirmed keypresses from a fifteen-item confirm-all prompt that is technically per-item. If pr-review's card loop is the intended vehicle, saying so by name would bound this to the reviewed implementation rather than to any tool that claims a keypress.
  2. Does "close" carry the same weight as "merge"? Merge is gated by branch protection and rulesets, as the paragraph notes. Close is not — GitHub enforces nothing, so a mis-keyed close is unprotected by anything except the human's attention. The roadmap in #1073 separately proposes auto-closing superseded agent PRs, which is the same authority with the keypress removed. Worth being explicit that the carve-out covers keypress-confirmed close only, so #1073's item 5 cannot lean on this paragraph.

Neither is a defect in the diff; both are about how narrowly this reads in six months. If the answers are "the pr-review card loop, one keypress per card, close included and auto-close excluded", then saying that in the text makes this a clean merge from my side.


Generated by Claude Code

castrojo pushed a commit that referenced this pull request Sep 12, 2026
Address hanthor's review on #970 in the text of human-gates.md:

- Name the reviewed vehicle: the pr-review card loop, one keypress per
  card, never a confirm-all prompt spanning items.
- State that close carries the same weight as merge: the carve-out covers
  keypress-confirmed closes only, so an auto-close without a per-item
  keypress (e.g. the obsolescence remedy proposed in #1073) cannot lean
  on this paragraph.
- State that arming auto-merge on the keypress is the same decision
  deferred until checks pass, in scope only with --match-head-commit
  pinning the reviewed head so drift fails server-side.

human-gates 1.1 -> 1.2; index.json/index.md regenerated with
scripts/generate_skill_index.py --write. check-skill-frontmatter.sh,
generate_skill_index.py --check, check-doc-links.sh, and
tests/test_skill_docs.py (10 passed) all green.

Assisted-by: Kimi K3 via GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
castrojo pushed a commit that referenced this pull request Sep 12, 2026
Address hanthor's review on #1073: Phase 0 item 5 read as adopted
intent to auto-close agent PRs, an agent mutation of human-visible
state that conflicts with docs/skills/human-gates.md. Rephrase to
detect-and-flag: detection is automated, the close itself requires a
per-item human keypress, matching the carve-out #970 negotiates.

The proposal content (adopt the remedy at all) remains a maintainer
decision; this change only removes the doctrine conflict from the text.

Assisted-by: Kimi K3 via GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@castrojo
castrojo disabled auto-merge September 12, 2026 12:34
@castrojo
castrojo enabled auto-merge September 12, 2026 12:35
@castrojo
castrojo requested a review from ahmedadan September 12, 2026 12:37
@castrojo

Copy link
Copy Markdown
Contributor Author

K3 final batch audit (970/1000/1073/1080 cohort) — 970 verified and armed for landing.

Verified against current main (56d81ef):

State: hanthor's approval stands (1 of 2 required by the main — merge queue ruleset). This PR is castrojo-authored, so the batch reviewer's castrojo-token approval cannot count here — a second human maintainer approval is needed (ahmedadan / repires requested). Auto-merge is armed; it enters the squash merge queue automatically once the second approval lands.

@castrojo castrojo added the lgtm This PR has been approved by a maintainer label Sep 12, 2026

@Danathar Danathar 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.

Approving as the second reviewer. Two things in here:

  1. A written procedure for resolving duplicate PRs (pick the survivor, arm it, close the rest) — hanthor called this uncontroversial and needed, and today's cleanup across the org bore that out.
  2. A clarification to the Merge gate in human-gates.md: a maintainer pressing a key per PR in the review tool is the human acting, not an agent self-merging.

hanthor's 09-12 comment asked for two things before he'd call it clean: name the pr-review card loop as the only vehicle (one keypress per card, no confirm-all), and say explicitly that keypress-confirmed close is covered but auto-close is not. The current text says both, nearly word for word. Nothing under system_files/, so no image change; index regenerated correctly; validate green.

@hivecommons-hive hivecommons-hive Bot 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.

Correctness review (head f831267):

  1. duplicate-cluster.md:29-31 — the SHA pin protects the wrong window. Step 2 says "Read the head SHA live and pin the merge to it" (sha=$(gh pr view <S> --json headRefOid ...) at merge time). Pinning to a SHA read at keypress time only guards the read→merge window; a push landing between the human's diff review (step 1) and the keypress merges unreviewed code with the pin satisfied. This contradicts the guarantee claimed in human-gates.md:99-101 ("drift between keypress and landing fails server-side instead of merging unreviewed code" — true, but the reviewed-vs-keypress drift is the unguarded gap). Pin to the head SHA captured when the diff evidence was presented, not a fresh read.

  2. Body/diff gap: version numbers. The body says human-gates goes to "1.1"; the diff sets version: "1.2" (human-gates.md:3, mirrored in index.json:383). Diff is internally consistent; body is stale.

  3. Body/diff gap: 500-line cap claim. The body says SKILL.md was "Compressed to fit the 500-line hard cap (exactly 500; one stray blank line reclaimed)." At head, pr-review/SKILL.md is 186 lines and human-gates.md is 147; the SKILL.md diff is +3/−2 with both deletions being frontmatter — no blank line was reclaimed. The claim appears to belong to a different revision.

  4. duplicate-cluster.md:59 — nonexistent flag. "Never --reason \"not planned\"" appears under step 4 (closing PRs), but gh pr close has no --reason flag; it exists only on gh issue close. If the intent is to guard linked-issue closes, say so; as written it prohibits an impossible command.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78

@hivecommons-hive hivecommons-hive Bot 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.

security
references/duplicate-cluster.md:30-33 reads the survivor's head SHA live at arm time (sha=$(gh pr view <S> --json headRefOid ...)) and pins the merge to it. That guarantees keypress→landing integrity, but human-gates.md:104 says the merge is "pinned to the reviewed head" — a push landing between the step-1 gh pr diff evidence and the keypress is silently blessed, because the live read picks up the new head. Low risk in a tight card loop, but capturing the SHA alongside the step-1 diff (or re-diffing at keypress) would make the snippet match the doctrine it cites.

intent-alignment
PR body vs head mismatch: body says human-gates bumps to "1.1" but the diff goes 1.0→1.2 (docs/skills/human-gates.md:3), and body claims SKILL.md was "compressed to fit the 500-line hard cap (exactly 500)" — at head f831267 docs/skills/pr-review/SKILL.md is 186 lines. Looks like the body describes an earlier single-file revision before the split into references/duplicate-cluster.md. Harmless, but worth correcting the body so the audit trail matches what landed.

No findings from: style, docs-currency.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78

@hivecommons-hive hivecommons-hive Bot added agent/scanner Filed or owned by the scanner agent. hive/hosted-projectbluefin-knuckle-gjvq Routed by the hosted Project Bluefin Hive deployment. labels Sep 20, 2026

@hivecommons-hive hivecommons-hive Bot 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.

docs-currency

  • docs/skills/pr-review/SKILL.md — the References table (the "| File | Contents |" block near the end of the file) lists all seven other files in references/, but the new references/duplicate-cluster.md is not added to it. The inline bullet at line 84 links it, but the table is now an incomplete inventory of the references directory.

correctness

  • docs/skills/pr-review/references/duplicate-cluster.md:74 — "Never --reason "not planned"" appears under step 4 (closing superseded PRs), but gh pr close has no --reason flag; only gh issue close does. PRs cannot be closed with a state reason. If the rule is aimed at the linked issues from step 5, say so there; as written it prohibits a flag that doesn't exist on the command in question. (Low.)

No findings from: security, intent-alignment, style.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78

@hivecommons-hive hivecommons-hive Bot 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.

correctness

  • docs/skills/pr-review/references/duplicate-cluster.md:38 — step 2's gh pr merge --squash --auto --match-head-commit "$sha_S" fails when the survivor's checks have already passed: gh pr merge --auto errors on a PR in clean status ("Pull request is in clean status"). Since the procedure says "halting on the first failure" (line 9), the most common case — a green survivor — halts the whole resolution. Worth a sentence covering the fallback (direct gh pr merge --match-head-commit "$sha_S" on the same keypress, which preserves the pin).

style

  • duplicate-cluster.md:22-23 capture sha_A/sha_B, but the step-2 snippet uses $sha_S, which is never defined. Readable in context, but it's an executable snippet — a copy-paste with the literal variable silently expands to empty, and --match-head-commit ""'s behavior is not what anyone tested. Either define sha_S explicitly or note the substitution.

No findings from: security, intent-alignment, docs-currency.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78

@hivecommons-hive hivecommons-hive Bot 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.

Reviewed — no findings from correctness, security, intent-alignment, style, docs-currency.

— hive: agent=reviewer backend=copilot model=claude-fable-5 copilot=1.0.78

@Danathar Danathar 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.

Read the full diff at 3237e48 (human-gates.md v1.2, pr-review/SKILL.md v3.6, new references/duplicate-cluster.md, regenerated index). The human-gates amendment is scoped correctly: it distinguishes agent self-merge (still forbidden) from a tool executing the maintainer's own per-item keypress with rulesets enforced server-side, and the auto-merge carve-out is pinned to --match-head-commit against the SHA the human actually reviewed. The new duplicate-cluster procedure requires human confirmation of the survivor before acting and never infers it from a shared issue alone. Front matter versions/dates in index.json and index.md line up with the SKILL.md changes. This is my second approval; common requires 2 and hanthor already approved.

castrojo and others added 5 commits September 22, 2026 21:48
…solution

human-gates: the Merge Gate binds agents, not the maintainer's own hands.
A review tool that executes a merge or close only on the maintainer's
explicit per-item keypress, with rulesets still enforced by GitHub, is the
human acting at the gate; --admin overrides, submitting reviews, and
non-interactive batch mutation remain forbidden for any tool. This
ambiguity had already produced a walker stricter than the doctrine it
implements.

pr-review: competing-pair detection could find a duplicate cluster but had
no verb for resolving it. Add the ordered procedure: survivor from diff
evidence, arm the survivor first with --match-head-commit, comment before
close, never 'not planned', then the linked-issue re-check — halting on
the first failure.

Assisted-by: Claude Opus 4.8 via GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Require human confirmation that a cluster is truly duplicate, preserve complementary PRs, and gate each merge, comment, and close action individually. Forbid batch closure so the documented maintainer tool cannot infer or automate destructive actions.

Assisted-by: GPT-5.6 Luna via GitHub Copilot

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address hanthor's review on #970 in the text of human-gates.md:

- Name the reviewed vehicle: the pr-review card loop, one keypress per
  card, never a confirm-all prompt spanning items.
- State that close carries the same weight as merge: the carve-out covers
  keypress-confirmed closes only, so an auto-close without a per-item
  keypress (e.g. the obsolescence remedy proposed in #1073) cannot lean
  on this paragraph.
- State that arming auto-merge on the keypress is the same decision
  deferred until checks pass, in scope only with --match-head-commit
  pinning the reviewed head so drift fails server-side.

human-gates 1.1 -> 1.2; index.json/index.md regenerated with
scripts/generate_skill_index.py --write. check-skill-frontmatter.sh,
generate_skill_index.py --check, check-doc-links.sh, and
tests/test_skill_docs.py (10 passed) all green.

Assisted-by: Kimi K3 via GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Step 2 of the duplicate-cluster procedure read the survivor head SHA at
keypress time, so a push landing between the step-1 diff evidence and the
keypress became the pinned head and merged unreviewed. Capture the SHA with
the diff in step 1, pin to that, and treat a --match-head-commit refusal as a
signal to re-present the diff and retake the keypress rather than an error to
retry around.

Tighten the matching human-gates claim so it describes the head SHA captured
alongside the reviewed diff instead of "the reviewed head" generally.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
gh pr close has no --reason flag, so move the "not planned" prohibition to
the linked-issue re-check where gh issue close --reason applies. Add the new
duplicate-cluster.md row to the pr-review References table.

Assisted-by: Claude Opus 5 via GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Step 2 of the duplicate-cluster procedure used an undefined `$sha_S`, which
expands to an empty `--match-head-commit ""` when copy-pasted. Name it as the
survivor's SHA from step 1.

`gh pr merge --auto` is also rejected with "Pull request is in clean status"
when the survivor is already green and the repo has no merge queue. Because
the procedure halts on the first failure, that common case stopped the whole
cluster resolution. Document the direct-merge fallback with the same
`--match-head-commit` pin, and scope which form applies where.

Assisted-by: Claude Opus 5 via GitHub Copilot
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@castrojo
castrojo force-pushed the pr-review-cluster-doctrine branch from 3237e48 to 5a7dce5 Compare September 23, 2026 01:48
@castrojo
castrojo merged commit 8f3ff2e into main Sep 23, 2026
1 check passed
@castrojo
castrojo deleted the pr-review-cluster-doctrine branch September 23, 2026 01:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent/scanner Filed or owned by the scanner agent. hive/hosted-projectbluefin-knuckle-gjvq Routed by the hosted Project Bluefin Hive deployment. lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants