Skip to content

fix(pr-pipeline): route the issue lane's non-owner stops away from a person - #10978

Merged
kyle-sexton merged 29 commits into
mainfrom
fix/stop-routes-owner-rule
Oct 30, 2026
Merged

kyle-sexton merged 29 commits into
mainfrom
fix/stop-routes-owner-rule

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

No related issue: verified audit findings, .work/gh-monitor/audit-2026-10-29/route-automation-lanes.md

Summary

The issue lane's route table (.github/scripts/work-resolve-issue/stop-routes.json) sent stops to a person that name none of the owner's reasons for one, against its own header (stop-routes.mjs: "Only an intent, design, security or cost reason routes here"). An uncoded stopped, split-required, a wait on an unmerged pull request, an issue whose work was already on main and a read-only report all ended at needs-human. A wait on a pull request also stayed parked after that pull request merged, because nothing cleared it.

Fix

  • Hold rows carry a class. Each hold row names its class: intent-change, design-change, security-risk or cost-risk. A test fails any hold row with another class. pushback is intent-change. The four trust gates (scan-refused-output, collect-refused, issue-edited, patch-invalid) are security-risk. research-first and probe-first are design-change.
  • Uncoded stopped: it retries once (the row's retries: 1) and then fails, never reaching a person. A reason the table does not list now fails instead of holding.
  • blocked-by-pr → new wait route. GitHub's Issue.blockedBy is an IssueConnection (GraphQL introspection), so a pull request cannot be a blocked_by edge. Instead, the issue keeps agent-ready with an outcome=wait pr=<n> marker. work-unblock's sweep restarts it once that pull request merges or closes, and counts its waits against limits.stop-retries separately from retries. If the pull request named is not open, or none is named, the stop retries instead.
  • already-done / report-delivered → new close route. The issue is closed as completed:
    • already-done closes only after the lane confirms the cited merged pull request, or the cited commit, is on the default branch.
    • report-delivered closes only a work-class: read-only issue the run committed nothing for, and posts the run's summary as the report.
    • Otherwise either one retries, with a line saying why.
  • split-required → new intake route. It removes agent-ready, status: ready and admission-deferred. The triage sweep now counts outcome=intake as a hand-back, so it sends the issue back through intake, whose split files the sub-issues (owner Q93). The route allows one pass (retries: 1): a second one since a listed human added agent-ready fails, so a split child that keeps Size Large cannot loop.
  • The lanes App's already-done close counts as a trusted close (owner Q9, 2026-10-29). isTrustedClose in .github/actions/check-trusted-trigger/check-trusted-trigger.mjs takes an isApp predicate. A close by the lanes App counts only when the App's last close comment names already-done and the new .github/scripts/lib/done-evidence.mjs re-reads that the cited pull request or commit is on the default branch with a message that closes the issue. A report-delivered close, or any failed read, counts for nothing. Its callers pass the predicate: intake-triage admit.mjs (a blocker the App closed as done admits its dependents) and work-unblock label-unblocked.mjs closedByHumanOrMerge (it unblocks dependents and can close split parents). done-evidence.mjs is on the hold floor as trust, and sync-hold-floor.py regenerated the copies.
  • More security words hold. SECURITY_WORD in stop-routes.mjs is wider, and a security word after a close, host-run or attended code now holds as security-risk. This holds more stops for a person, never fewer.
  • Stop-reason marker. A new shared module, .github/scripts/lib/stop-reason.mjs, writes and validates <!-- stop-reason lane=<lane> reason=<code> --> and a visible line, Reason: `<code>` . The code is one of intent, design, security, cost or none, and the module refuses none on a comment that reaches a person.
    • Every issue-lane comment that reaches a person carries both the marker and the line.
    • collect-base-activity copies .github/scripts/lib/ next to a script's base copy, so its ../lib/ import resolves.
    • The merge hold floor lists the new module as enforcement, and sync-hold-floor.py regenerated the copies.
  • /work-items:work documents the three new codes and names the four that reach a person.

Verification

  • node --test passes in .github/scripts/lib (4), work-resolve-issue (388), intake-triage (633), work-unblock (224), maintenance-audit-lane-runs (81) and pr-merge (645).
  • New tests cover:
    • the class of every hold row;
    • an uncoded stop retrying once, then failing;
    • wait on an open, merged or closed pull request, plus the wait cap;
    • closing on already-done evidence, and retrying without it;
    • closing on a delivered report;
    • the intake route and its loop cap;
    • the triage-sweep hand-back from outcome=intake;
    • every hold row's comment carrying the stop-reason marker and line;
    • report-outcome loading from its base copy next to the copied lib.
  • The new work-unblock wait test fails when the sweep's wait branch is disabled.
  • Babysit scripts' pytest suite passed: 3509 passed, 14 skipped. sync-hold-floor.py --check is clean.
  • scripts/check-affected.sh passes on the branch.

Related

  • The audit records and the verifier's corrections are in .work/gh-monitor/audit-2026-10-29/route-automation-lanes.md (local).
  • This partly covers #10517, the issue-lane rows (split-required). It does not settle that issue.
  • Not done here, because the verifier narrowed the finding to the issue lane: the refinement-schema part of the wait-on-PR finding (refine.mjs).
  • A follow-up moves intake-triage admit.mjs, apply-verdict.mjs and refine.mjs, intake-reenter reenter.mjs, work-unblock label-unblocked.mjs and triage-sweep.mjs onto stop-reason.mjs after fix(pr-pipeline): keep the issue body untouched when intake splits off person-only done-when items #10951 merges. This PR changes label-unblocked.mjs and triage-sweep.mjs only for the wait restart, the intake hand-back and the App done-close predicate.

🤖 Generated with Claude Code

kyle-sexton and others added 4 commits October 29, 2026 11:49
…person

stop-routes.mjs says only an intent, design, security or cost reason
holds for a person, yet the table held an uncoded stop, a split and a
wait on an unmerged pull request.

- Every hold row names its class; a test fails any hold row whose
  class is not intent-change, design-change, security-risk or
  cost-risk.
- An uncoded stop retries once (the row's own retries), then fails.
- split-required takes a new intake route: agent-ready, status: ready
  and admission-deferred come off, and the triage sweep, which now
  counts outcome=intake as a hand-back, sends the issue to intake,
  whose split files its sub-issues (owner Q93).
- blocked-by-pr takes a new wait route: agent-ready stays with an
  outcome=wait pr=<n> marker, and work-unblock restarts the issue once
  that pull request merges or closes, its waits counted apart from
  retries under limits.stop-retries. GitHub's blockedBy is an
  IssueConnection, so a pull request cannot be a blocked_by edge.
- already-done and report-delivered take a new close route: the issue
  closes as completed, already-done only once the cited merged pull
  request or commit is on the default branch, report-delivered only
  on a work-class: read-only issue with no commit. Either retries
  otherwise.
- /work-items:work teaches the three new codes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A shared module, .github/scripts/lib/stop-reason.mjs, writes and
  validates the stop-reason marker
  `<!-- stop-reason lane=<lane> reason=<code> -->` and the visible
  line "Reason: `<code>`", the code one of intent, design, security,
  cost or none; it refuses none on a comment that reaches a person.
- The issue lane's hand-back and dimension-skip comments carry both,
  the code taken from the hold row's class. A test checks every hold
  row's comment. A reason the route table does not list now fails
  instead of holding.
- collect-base-activity copies the base .github/scripts/lib/ beside a
  script's base copy for its ../lib/ imports; the hold floor lists the
  new module as enforcement, and sync-hold-floor regenerated its copies.
- The intake route is capped by its row's retries (1): a split child
  that keeps Size Large past admission fails on its second intake
  instead of looping through triage.
- A wait on a pull request that is not open, and an already-done stop
  with no evidence on the default branch, say why they retry;
  already-done tries up to three SHA-looking words.
- /work-items:work names the four codes that reach a person.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 29, 2026 16:26
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-29T16:29:56.923674Z fe3f660 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe3f660ac1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions github-actions 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.

claude-security-review: 1 inline finding(s) on fe3f660ac142e638d812b5d016da6df0240436aa; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

claude-security-review reviewed feb8a1c7a4c2bfe2620328e67046398cb06d11fa: 0 finding(s), 0 as inline comments.

critical-findings: 0

Security review of #10978 at feb8a1c. I read the whole diff (32 files) and the PR context, and found no security issues. I could not run tests. I read the code only.

Trust-control widening: the lanes App's already-done close now counts as a trusted close (check-trusted-trigger.mjs isTrustedClose/appDoneClose, new lib/done-evidence.mjs). This lets more through, so I checked it as a widening.

  • Who can reach it: only the lanes App, matched by account id. isApp(closer) must be true on the issue's closed_by. The close comment is also filtered by isApp(comment.user), so a forged comment from another account cannot supply the marker.
  • What counts: closeStop must parse the App's last close comment, and its stop line must be already-done. The comment has to start with the exact close marker followed by the stop line.
  • What stops it: doneEvidence re-reads GitHub at decision time.
    • The cited PR must be merged into the default branch, or the cited SHA must be contained in it.
    • The merge or commit must postdate both the issue's creation and its last reopened event.
    • The merge commit message must contain a closing keyword for this issue. A "not" prefix, a revert, a cross-repo reference such as o/r#77, and #770 do not count.
    • A failed read, an events listing past 10 pages, or a failed dynamic import all return false. That fails closed.
  • Conclusion: the evidence is already-merged default-branch content that was reviewed under the repo's rulesets. The existing GraphQL-closer path already trusts the same kind of merge. I found no attacker-controlled input that makes the check true, so this is not a finding.
  • Not widened: report-delivered closes count for nothing.
  • Callers: both pass an id-based predicate. In admit.mjs it is actor.id === appId, and it is false when appId is undefined. In label-unblocked.mjs it is actor.login === bot.

Other trust-adjacent changes I read and found tighter or neutral

  • triage-sweep.mjs handedInComments now counts a hand-back only from the lanes App's account id, and counts none when appId is null. The old check accepted any Bot.
  • The wait route in report-outcome.mjs requires the cited PR to be open and opened by the lanes App or a listed human (trustedAuthor). If not, it retries. work-unblock only reads wait markers from the App's own comments, and waits are capped by limits.stop-retries.
  • collect-base-activity copies the base-branch .github/scripts/lib/, never the PR head's, so a PR cannot swap the shared modules the base copy imports. Both new lib modules are added to the hold floor (merge-holds.mjs, babysit_risk.py, pr-require-checks.yml, both review workflows' hold-path lists) as trust and enforcement.
  • runCode widens SECURITY_WORD, NFKC-normalizes the text, and strips format characters. A security word after a close, host-run or attended code now holds as security-risk. This holds more stops for a person, not fewer.

Owner threat-model line (throughput phase): an uncoded stopped, split-required, blocked-by-pr, already-done and report-delivered no longer end at needs-human. This removes person-approval friction holds the skill exempts, so I hold nothing for it.

manifest: this diff has no plugin.json or marketplace.json change, so there is no manifest <field> line.

Spend: no change to turn limits, schedules or paid resources, and no charge-bearing change. There is no cost hold.

@github-actions github-actions 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.

claude-review: 2 inline finding(s) on fe3f660ac142e638d812b5d016da6df0240436aa; the summary is in this lane's pull request comment.

claude-lane: claude-review

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

claude-review reviewed feb8a1c7a4c2bfe2620328e67046398cb06d11fa: 0 finding(s), 0 as inline comments.

Code review: no findings

I read all 32 files of the diff and the PR context. I did not run any tests, because this session has no shell. The test results in the PR description are the author's claims, and I did not check them.

Closing issue: none. The PR context says "No related issue", so there are no acceptance criteria to check.

Manifests: the diff changes no plugin.json or marketplace.json, so there are no manifest <field> lines. Two changelog fragments look low for what they describe, but the lane's bump rule only applies when a manifest changes. .changes/work-items/…9c4d7e1f.md is patch although it adds three new accepted stop codes (a minor-sized capability). .changes/source-control/…3e8a0d6b.md is patch for two hold-floor entries. If the repo judges fragments independently of manifests, the person merging may want to confirm both levels.

What I checked, by reading the code:

  • Route table and cap logic (stop-routes.json, stop-routes.mjs, report-outcome.mjs):
    • The load-time checks reject any hold row without an owner class and any class on a non-hold row.
    • retry-spent stays a fail route.
    • The counted routes (retry, wait, intake) are capped consistently in routeStop, capRetries and finishStop.
    • The wait-to-retry fallbacks (a pull request that is not open, none named, or not opened by the lanes App or a listed human) and the already-done-without-evidence fallback both re-enter the cap.
    • The pr= marker field is parsed by the same parseOutcomeMarker that label-unblocked.mjs uses, so the sweep's wait branch reads it.
  • Trusted close for the lanes App's already-done close (check-trusted-trigger.mjs, done-evidence.mjs):
    • It counts only when the App's last close comment names already-done and the cited pull request or commit is merged into the default branch after the issue opened and after its last reopen.
    • That commit's message must also close the issue.
    • Any failed read, including the dynamic import of done-evidence.mjs, returns false, so it fails closed.
    • Both callers (admit.mjs, label-unblocked.mjs) pass an isApp predicate matching how they identify the App (id and login respectively).
  • Triage sweep (triage-sweep.mjs): the hand-back search now counts only the lanes App's account, with databaseId added to the GraphQL query, and outcome=intake is recognised as a hand-back.
  • Hold floor: merge-holds.mjs, babysit_risk.py, the three generated workflow copies and the test counts agree on the two new paths. They are 18→19 trust, 40→41 enforcement, 106→108 total, and 66→67 for the high floor.

Minor observations, not counted as findings:

  • finishStop on a close route comments and removes agent-ready before the PATCH that closes the issue. If the PATCH fails, the issue is left open and unlabeled, with a comment saying it closes. The retry path is idempotent per run, but this one has no equivalent check.
  • The stopped row's retries: 1 counts every retry since the last agent-ready, whatever stop wrote it. The PR documents this, and it is intended.

Spend: the new wait, intake and one-shot stopped retries can cause extra lane runs. They draw on prepaid credit or subscription usage only and are bounded by limits.stop-retries, so they are not a hold. No billed resource or plan changes.

kyle-sexton and others added 2 commits October 29, 2026 12:47
…the issue

doneEvidence took any merged pull request or any commit on the default
branch as proof, so run 40844966342 closed issue #10858 on release commit
abb359b, which never touched it, and the close admitted its dependents.

A cited merged pull request or default-branch commit now counts only when
its title, body or message cites #<issue> as a whole token, or it changes a
path the issue body names. Any failed read still proves nothing, and the
stop retries instead of closing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@github-actions github-actions 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.

claude-security-review: 1 inline finding(s) on 04223e8bd49cca0f13262c0aaef037ddee71fe96; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

@github-actions github-actions 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.

claude-review: 1 inline finding(s) on 04223e8bd49cca0f13262c0aaef037ddee71fe96; the summary is in this lane's pull request comment.

claude-lane: claude-review

kyle-sexton and others added 3 commits October 29, 2026 13:08
Security review on #10978:

- runCode reads a stop code in any case, past emphasis, backticks and a
  Reason: label, with a space or hyphen between its words; a reason with
  no code that names security, intent, design or cost as a word takes
  that hold row, so a misformatted owner code reaches a person instead of
  retrying and failing.
- doneEvidence counts a citation only as a closing keyword before
  #<issue>, takes a pull request only when merged into the default branch,
  takes evidence only from after the issue opened, and matches only a
  named path that holds a directory.
- A blocked-by-pr wait counts only a pull request the lanes App or a
  listed human opened, by the same author check closed-by-open-pr uses.
- stop-routes.json does not load when a hold row's class is not an owner
  reason.
- The triage sweep's hand-off search counts a hand-back only from the
  lanes App's account, as readState does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
runCode's backstop held an uncoded stop that named intent, design or
cost as a word, so plain reasons such as "the test design needs X" or
"the cost of retrying" reached a person, against the owner's rule that
only real owner reasons do. Only a whole-word `security` or `vulnerab*`
now routes an uncoded stop to the security-risk hold; the tolerant code
parsing stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@github-actions github-actions 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.

claude-security-review: 1 inline finding(s) on 8327c667c7639cad4fbce4e5f512bb8a201e7d52; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

@github-actions github-actions 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.

claude-review: 2 inline finding(s) on 8327c667c7639cad4fbce4e5f512bb8a201e7d52; the summary is in this lane's pull request comment.

claude-lane: claude-review

kyle-sexton and others added 3 commits October 29, 2026 13:21
Re-review of 603166e on #10978:

- runCode reads the reason NFKC-normalized, takes the security code with
  a hyphen, underscore, space or nothing between its words, and holds an
  uncoded reason that contains `security` or `vulnerab` anywhere, so
  SECURITY_RISK, SecurityRisk and full-width forms reach a person.
- Every other code needs its hyphenated form followed by a colon, a
  backtick, closing emphasis, a space or the end, so "Design change in X"
  no longer holds for the owner.
- doneEvidence takes only a closing keyword, from the merge commit of a
  cited pull request or from a cited commit; the issue-body path fallback
  and bodyPaths are gone, and an edited pull request body proves nothing.
- stop-routes.json does not load without a security-risk hold row of
  class security-risk, or with a class on a row that does not hold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hidden security words

A hyphenated code now ends at any non-word character, so design-change. and design-change, hold again; format and combining characters are stripped and vuln counts, so secu<ZWSP>rity and vuln: hold as security; a closing keyword needs #<issue> followed by no word character.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@github-actions github-actions 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.

claude-review: 1 inline finding(s) on f492613e78b11b020b73334166158f78d060474a; the summary is in this lane's pull request comment.

claude-lane: claude-review

@github-actions github-actions 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.

claude-security-review: 1 inline finding(s) on f492613e78b11b020b73334166158f78d060474a; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

@github-actions github-actions 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.

claude-security-review: 1 inline finding(s) on 53be940aab2b2934609de8daaf235e089c0098db; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

kyle-sexton and others added 2 commits October 29, 2026 14:02
…ate the shared retry cap

Review threads on #10978:
- doneEvidence tries the first three cited #<n> other than the issue, so
  "duplicate of #50, fixed by #60" reads #60's merge commit instead of
  retrying on #50's 404.
- A stop row's `retries` caps the issue's shared count of retry markers
  since a listed human last added agent-ready, whatever stop wrote them;
  the stopped and retry-spent whys, the route header, the convention, the
  work skill and the fragments now say so.
- pr-run-activity says a reason the table does not list fails, as
  stopRoute does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@github-actions github-actions 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.

claude-review: 1 inline finding(s) on ade86e237dcbf71a99e9e55ad40b48143b86e4e4; the summary is in this lane's pull request comment.

claude-lane: claude-review

@github-actions github-actions 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.

claude-review: 1 inline finding(s) on ac7c1ce68ec42ac27dab59623e8565e2258f95ae; the summary is in this lane's pull request comment.

claude-lane: claude-review

A report-delivered stop on an issue that is not work-class: read-only, or
whose run left a branch, retried with only the close wording. Pass a why
line, as the already-done retry does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

The pr-verify verifier failed head 951f8941ab6015148b5875bfa8612f0d70a8dae5. What it wrote, as data:

What it wrote (35 lines)
Summary: PR #10978 links no issue, so its own title and body are the spec. The diff delivers what
  the body describes. Hold rows now carry a class, and uncoded `stopped` retries once and then
  fails. It adds the `blocked-by-pr` wait route with the work-unblock restart, the
  already-done/report-delivered close route, and the split-required intake route with its
  triage-sweep hand-back. It adds the stop-reason marker module, copies lib/ in
  collect-base-activity, and syncs the hold floor, all with tests. It fails because it also loosens
  `isTrustedClose` in `.github/actions/check-trusted-trigger/` (a protected takeover-set file). The
  lanes App's own already-done close now counts as a trusted close for dependents and split parents
  in admit.mjs and label-unblocked.mjs. The body does not ask for this anywhere; it even says "No
  `admit.mjs` change". The only basis is an owner decision ("Q9") quoted in the PR author's review
  replies, which are context, not spec. A takeover-set check weakened beyond the spec is a blocking
  takeover risk.
- .github/actions/check-trusted-trigger/check-trusted-trigger.mjs:378 `isTrustedClose` gains an
  `isApp` parameter and `appDoneClose`, so the lanes App's already-done close of an issue now counts
  as trusted. That loosens a takeover-set trust gate, and the PR body (the spec) does not ask for
  it. Either remove this change, along with the `isApp` pass-through in
  `.github/scripts/intake-triage/admit.mjs:252,263` and
  `.github/scripts/work-unblock/label-unblocked.mjs:2158`, or put it in the PR body: name the
  trust-gate change and the owner decision it rests on (Q9, 2026-10-29), so the spec covers it.
- .github/scripts/intake-triage/admit.mjs: the PR body says "No `admit.mjs` change", but the diff
  changes `closedByTrusted` and `admissionFacts`. Fix the body so it matches the diff.
- .github/scripts/work-resolve-issue/stop-routes.mjs:1828 the wider `SECURITY_WORD` backstop
  (security words after a close/host-run/attended code, and in uncoded reasons) is in the changelog
  but not in the PR body. It tightens the route rather than loosening it, but put it in the body so
  the spec covers it.
- .github/scripts/maintenance-audit-lane-runs/triage-sweep.mjs:616 `handedInComments` now counts a
  hand-back only from the lanes App's databaseId, and none at all when no appId is given. This
  tightening is not in the body; put it in the body.
- .github/scripts/work-unblock/label-unblocked.mjs:2135 the wait branch's `GET /pulls/<n>` has no
  local error handling. Confirm a failed read there cannot abort the whole sweep, or catch it and
  skip that issue.
- .github/scripts/lib/done-evidence.mjs `doneEvidence` accepts any merged default-branch PR whose
  merge commit says `Closes #N`, whoever wrote it. That is acceptable because a merge already needs
  trust, but it is now a trust input (correctly classed `trust` in the hold floor), so a person
  should review it.

This pull request leaves the merge queue, and ci-status holds it out while it carries pr-verify-failed. A pr-verify pass at a new commit removes the label.

@github-actions github-actions Bot added the pr-verify-failed pr-verify failed this head; a pass at a new commit removes it. label Oct 29, 2026
@melodic-automation-lanes

melodic-automation-lanes Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

The pr-unblock lane stopped resolve-conflicts on this pull request: the merge stages the pull request's own .github/workflows/ changes together with the base's, which the lane token cannot push, so a session merges main by hand. The lane sets no label: the run ends in a failing pr-unblock/conflict status on the head the lane gated.

When a retry on this head can change the outcome, the lane runs one on its own, up to its per-head cap, and edits this comment if it stops again; a run that does not stop clears the status. When no retry can (a review thread the lane does not take or settle, or a failing check after the retries are spent), a person resolves the threads or gets the checks green, then dispatches the workflow below: that run finds the cause gone and clears the status. On a pull request the lanes App opened, the dispatchers start that run once per stop; on any other, a person does. A new commit to the branch starts clean.

To run it again on this head now, dispatch the pr-unblock workflow:

gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=10978 -f activity=resolve-conflicts

@github-actions github-actions 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.

claude-security-review: 2 inline finding(s) on 25d0d754bd095074ce208f4fa0356cd3a542291b; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

Comment thread .github/scripts/lib/done-evidence.mjs Resolved
kyle-sexton and others added 4 commits October 29, 2026 19:47
…d more security words

doneEvidence now takes only work merged after the issue was last reopened,
reading the issue's events and failing closed when they do not read whole,
so the lanes App's already-done close no longer counts as trusted past a
person's reopen. SECURITY_WORD adds password, API key, private key,
backdoor, exploit, whole-word XSS/RCE/CVE and "ignore ... instructions".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@github-actions github-actions 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.

claude-security-review: 2 inline finding(s) on ea29316858acbfca730f046ddf3256c8eec0ce58; the summary is in this lane's pull request comment.

claude-lane: claude-security-review

Comment thread .github/scripts/lib/done-evidence.mjs Resolved
@kyle-sexton kyle-sexton removed the pr-verify-failed pr-verify failed this head; a pass at a new commit removes it. label Oct 30, 2026
@kyle-sexton
kyle-sexton enabled auto-merge October 30, 2026 02:29
kyle-sexton and others added 4 commits October 29, 2026 22:51
…everted closes

An uncoded stop naming branch protection now holds as security-risk, and
the docs and changelog list every security word the code matches. A
"does not fix #N" line or a revert commit no longer counts as already-done
evidence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-rule

# Conflicts:
#	.github/scripts/intake-triage/admit.test.mjs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant