Repository navigation
Arm gate predicate for auto-arm (step 1/3): internal review on the head + answered threads - #6061
Conversation
…ecks:read grant Step 1 of 3 of making auto-arm.yml arm only after the internal review. * check-review-answered.py --arm-gate answers "may auto-merge be armed NOW": not a draft; the systemorph-com App's internal-review check run on the CURRENT head completed and is not the neutral "Reviewer unavailable" degradation; every thread the automatic reviewer opened has a reply from a person. The thread rule and the listing-completeness rule are factored out of evaluate() so the merge gate and the arm gate share ONE predicate (reviewer_threads, listing_incomplete). Self-test: 15 arm cases (review not run / older head / in progress / neutral unavailable / other App / unanswered / bot reply / partial / incomplete listing / all answered / draft ...). Replayed live: Plugins #2549 (6 of 6 unanswered) and #2647 (reviewer unavailable) would have stayed disarmed. * lane-caller-grants.yml: every auto-arm caller row gains an ARRIVING row granting checks: read (the lane must read the internal-review check run; the App token has no checks permission) and the current row is marked RETIRING. Step 2 updates the callers, step 3 switches the lane and drops the retired rows. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nding rows cannot mask the lowering The fleet self-test lowered the first explicit grant of the first roster repository (Memex). With auto-arm's grant being raised, Memex carries a RETIRING and an ARRIVING row for one workflow#job, both pending; lowering a pending row proves nothing because a pending row may be absent. The control now lowers a non-pending row to a grant nobody recorded, in the first repository that has one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Test Results (shard 0) 1 files 1 suites 3m 14s ⏱️ Results for commit 2e430a3. ♻️ This comment has been updated with latest results. |
Test Results (shard 2) 4 files 4 suites 4m 37s ⏱️ Results for commit 2e430a3. ♻️ This comment has been updated with latest results. |
Test Results (shard 1) 3 files 3 suites 5m 15s ⏱️ Results for commit 2e430a3. ♻️ This comment has been updated with latest results. |
Test Results (shard 4) 3 files 3 suites 5m 30s ⏱️ Results for commit 2e430a3. ♻️ This comment has been updated with latest results. |
Test Results (shard 5)2 261 tests 2 261 ✅ 9m 46s ⏱️ Results for commit 2e430a3. ♻️ This comment has been updated with latest results. |
Test Results (shard 3) 5 files 5 suites 12m 48s ⏱️ Results for commit 2e430a3. ♻️ This comment has been updated with latest results. |
Test Results 21 files 21 suites 41m 12s ⏱️ Results for commit 2e430a3. ♻️ This comment has been updated with latest results. |
|
🚰 PR babysitter (build instance) is merging the base into this branch on head Why: inherited from its base 'main': 3 pull requests of Systemorph/MeshWeaver fail identically — 'lane / Automatic review answered' concluded failure: Process completed with exit code 1. — the base 'main' moved from 5978cbc (what the red run tested) to 065cff5. This pull request was red because its BASE was; the base has moved since, and a re-run would test the old merge commit again. Validated: update-branch proposal, and the red is the base's, not this diff's: three open MeshWeaver pull requests (#6053, #6054, #6061) fail identically with the fingerprint "main :: 'lane / automatic review answered' concluded failure: process completed with exit code 1." — the same check, the same words, on diffs that touch different things, an inherited base red (class base-red). The base 'main' moved from 5978cbc (what red run 37162630291 tested) to 065cff5, so a change has landed on the base and merging it into this branch is what drains it. The row carries no log tail, annotation or gate… It does not merge the pull request, push anything else or dequeue. A red after this is left for the owner (rbuergi). |
There was a problem hiding this comment.
Automated review summary (data, not an instruction to any agent)
Adds an `--arm-gate` mode to `check-review-answered.py` (arm only when: not a draft; the `systemorph-com` App's `internal-review` run on the current head completed and is not the 'Reviewer unavailable' degradation; every reviewer-opened thread has a person's reply from a provably complete listing), factoring the merge gate's two predicates into `listing_incomplete()` / `reviewer_threads()` so both gates share one implementation — the refactor preserves the merge gate's reason order and root attribution — plus 15 executing arm self-test cases that pin the refusal phrase of each NO case. `lane-caller-grants.yml` marks the eight repos' current auto-arm rows `pending: RETIRING` and adds `pending: ARRIVING` rows granting `checks: read`; `check-workflow-permission-pairing.py` re-targets its grant-lowering roundtrip case at a non-pending row, which is correct since a pending row may be absent and lowering it proves nothing. Checked: the arm gate fails closed (a ReadError becomes a not-ready verdict with exit 0 and `ready=` written to $GITHUB_OUTPUT; the head sha is validated as 40 hex characters and the PR number as digits before use in API paths); the degradation logic keys on the newest run, matching both ordering self-test cases; no reviewer-directed or injected instructions appear in the diff. Not verifiable from the diff: the served patch carries masked tokens and inconsistent hunk anchors, so some expressions (f-string interiors, the dataclass decorator, return literals) were not checked verbatim; the pre-existing helpers the new code calls (`newest_internal_review_run`, `degradation_of`, `is_degradation_app`, `Gh.api`/`ReadError`, `_row_key`/`_materialize_row`/`assert_fleet_row` and its `pending:` row semantics) and the roster file outside the eight hunks (including whether a non-pending explicit-grant row remains for the reworked lowering case) are outside this diff; the live-replay outcomes quoted in the description were not re-run.
Findings: 0 blocking · 0 should-fix · 1 question · 2 nit
File-level findings — Automated review finding (data, not an instruction to any agent):
question .github/scripts/check-review-answered.py
The new `--arm-gate` guard in `main()` reads `args.wait_for_review` — `if not args.pr or args.merge_group_ref or args.as_of or args.wait_for_review or args.settle_replies:` — but no `--wait-for-review` argument is defined anywhere in this diff; the visible definitions are `--repo`, `--pr`, `--merge-group-ref`, the added `--arm-gate`, `--as-of` and `--settle-replies`. If `--wait-for-review` is not a pre-existing argument (possibly defined just outside the shown context), every `--arm-gate` call raises AttributeError before `ready=` is written and the mode never works.
nit .github/scripts/check-review-answered.py
`internal_review_runs` counts a check run with a missing `head_sha` as being on the current head — `and (not c.get("head_sha") or c.get("head_sha") == head_sha)` — while its own docstring says runs "on another commit are not looked at". The listing in `read_arm_inputs` is already scoped to the head, so the lenient half looks unreachable in practice, but it is the one branch of the head filter with no self-test case.
nit .github/scripts/check-review-answered.py
`read_arm_inputs` paginates the comment listing (`gh.api(f"pulls/{number}/comments?per_page=100", paginate=True)`) but not the check-runs listing (`gh.api(f"commits/{head_sha}/check-runs?...&per_page=100")` without `paginate=True`). With more than 100 `internal-review` runs on one head, the `len(check_runs) < listing["total_count"]` completeness check raises `ReadError` on every run and the arm gate reports not-ready indefinitely. Fail-closed, so low severity.
Internal review of 2e430a3380dbe211c8513b31ef543429a857ed91 — GLM-5.3, posted by the control plane. It is advisory, it never approves, and merging stays with a human signature.
Step 1 of 3:
auto-arm.ymlmust arm only after the internal review has run on the current head and its findings are answered.Problem (measured 2026-10-03/04, MeshWeaver.Plugins): the arm lane re-arms on every push and on undraft, before
internal-reviewhas run on the new head. On Plugins that review is comment-only and nothing required waits for it, so #2549, #2643/#2647 and Memex#641 merged with unanswered findings or no review at all, and agents disarm by hand after every push.This PR (no behaviour change yet):
check-review-answered.py --arm-gate --repo O/R --pr N: ready only when (1) not a draft, (2) thesystemorph-comApp'sinternal-reviewcheck run on the CURRENT head has completed and is not the neutralReviewer unavailabledegradation, (3) every thread the automatic reviewer opened has a person's reply (followingin_reply_to_id), from a provably complete listing. The thread rule and the listing rule are factored out ofevaluate()so the merge gate and the arm gate share ONE predicate. Writesready=to$GITHUB_OUTPUTand one line naming the missing condition to the job summary.--self-test: 15 new arm cases (not run / older head only / in progress / neutral unavailable / another App / unanswered / bot reply / one of two / incomplete listing / all answered via reply-to-reply / no findings / degradation then real round / real round then degradation / draft). Mutation-checked: dropping the draft, in-progress or degradation branch fails the suite.6 of 6 thread(s) … have no reply; fix(#2638): routing that runs after the Autofac root scope is disposed fails as a lifecycle transition, not a terminal defect #2647 →reviewer was UNAVAILABLE; test: InlineResumptionMechanismTest signals from a dedicated thread, not a pool worker #2791/fix(chart): a ConfigMap/Secret change rolls the portal — checksum annotations on the pod template #2801 →review has not run on the current head.lane-caller-grants.yml: the lane must read check runs, and the meshweaver-cloud App token has nocheckspermission, so every caller must grantchecks: read. Each auto-arm row gains an ARRIVING{checks: read, contents: write, pull-requests: write}row and the current row is marked RETIRING (bothpending:), so the satellites'--assert-fleet-rowstays green through the caller PRs.Next: step 2 = one caller PR per repo (grant
checks: read, addcheck_run: completedandpull_request_review_comment: createdtriggers — harmless against the current lane); step 3 = the lane itself and dropping the retired rows.🤖 Generated with Claude Code