Skip to content

ci: restore one recorded merge path and refuse merges with uncovered local skips #2940

Closed

Description

@schlessera

Part of #2934 (Phase A, task 4).

Context

Policy makes bun scripts/integrate.ts confirm and merge the mandatory path for ordinary candidates (docs/decisions/ci-utility.md:1237-1258; .agents/skills/work-issue/SKILL.md:272-279). Its merge path already refuses a candidate whose canonical exact-head CI is missing selected jobs or has mismatched checkouts (docs/decisions/ci-utility.md:1248-1258). The policy records that direct merges can bypass it (docs/decisions/ci-utility.md:1260-1262).

In practice, refs/heads/brain-integration-reservation records 45 acquisitions between 2026-10-19 and 2026-10-23 12:43 UTC+2, and none since, while about 100 squashes landed on main. scripts/integrate.ts did not change in that window. The subsequent cohort's median ready → merge is 3 seconds. Every throughput and incident measurement under #2934 assumes one known merge path; currently it is not known which path ran.

A red-main fix was recently merged by bypassing every check, because it was queued behind unrelated PRs for local proof resources; there was no expedited path to use instead.

Agents also skip long local checks that time out (see #2934). scripts/check-pr.ts reports its own skips (scripts/check-pr.ts:148-149), but nothing carries a skipped or timed-out check into the PR or the merge decision.

Scope

  1. Establish why ordinary merges stopped calling integrate.ts after 2026-10-23: which skill, orchestrator or manual path merged them, using PR timelines and merge actors. Record the finding on this issue.
  2. Make the path in use the recorded one: either restore integrate.ts in the skills and orchestration, or, if the maintainer rules for a replacement, implement that ruling.
  3. Make check:pr emit a machine-readable receipt listing every selected check with its outcome, including skipped, timed-out and preempted (a run cancelled by admission, which must be rerun and never counts as checked or as a failure), and have the PR template carry it.
  4. If the Phase A task 2 ruling accepts a red-main fix lane, add an expedited mode to the merge path (for example integrate.ts merge <pr> --fixes-main-run <run-id>) that checks the ruled expedited proof, records the failing run, the fix's evidence and the actor, writes and later clears the repository-level red-main record if one is ruled in, and queues the backstop check on the next main-push run. A forced bypass then has a recorded form instead of none.
  5. Have the merge path refuse a candidate whose recorded local skips are not covered by an exact-head hosted category, and print which ones are missing.

Out of scope

  • Changing what hosted proof selects.
  • Branch protection or permission changes, which policy excludes.
  • The lane rulings themselves (Phase A task 2); this task implements only what they accept.

Acceptance criteria

  • The finding for 1 names the actual merge path or paths used since 2026-10-23, with evidence.

  • After the change, a merge through the documented path appears in the reservation ref history, and scripts/ci-timings.ts reports it.

  • A check:pr run with a check forced to time out produces a receipt recording timed-out for it, proven by a test that fails before the change.

  • integrate.ts merge refuses a candidate whose receipt records a skipped or preempted category absent from its exact-head hosted proof, proven by a test that fails before the change and by a restored mutation.

  • If the expedited mode is ruled in: it refuses a fix whose failing category was not shown red on the base and green on the head, and it records an event that scripts/ci-timings.ts reports; both proven by tests that fail before the change.

Verification

bun run test tests/integration-command.test.ts tests/integration-reservation.test.ts and the check:pr tests touched, plus the mutation receipts in the PR.

Contract impact

If the receipt is a new --json shape of a brain command, it is a contract addition; if it stays a repository script output, none.

Activity

  1. added
    type: choreTooling, CI, release plumbing, dependencies.
    area: ciCI workflows, the gates they run, release scripts, packaging.
    agent-readyContext and acceptance criteria are complete enough for an agent to take this unattended.
    on Oct 25, 2026
  2. added this to the 0.45.0 milestone on Oct 25, 2026
  3. self-assigned this
    on Nov 2, 2026
  4. schlessera commented on Nov 2, 2026

    @schlessera
    OwnerAuthor

    Claimed as part of working epic #2934 end to end (claim token wi-20261102-fd2d2f21). Order chosen for earliest queue-velocity benefit: #2938+#2939 rulings first (they unlock hosted draft feedback), then the red-main/merge-path chain (#2942, #2940, #2944); #2943, #2941 and #2937 run in parallel since they touch disjoint code. Intended branch: feat/2940-recorded-merge-path (after #2942's record schema lands, since the expedited mode writes that record).

  5. schlessera commented on Nov 2, 2026

    @schlessera
    OwnerAuthor

    Finding for scope item 1: which merge path ran after 2026-10-23

    Window and sources. Every merged PR into main from 2026-10-21T17:19:18Z (the #2934 subsequent-cohort start) to 2026-11-02 09:30Z: 249 PRs, read with gh pr list --state merged --search "merged:>=2026-10-19". Each was matched by exact PR number and head SHA against every lease recorded in refs/heads/brain-integration-reservation (the active and last.previous of every commit, read with git show <commit>:reservation.json). Ready→merge times come from each PR's issue timeline (the last ready_for_review and merged events).

    Cohort PRs Exact-head lease Ready→merge median / p90 Ready→merge ≤ 10 s
    No matching lease 157 0 3 s / 5 s 138 (6 without a ready event)
    Exact-head lease 92 92 1,248 s / 2,291 s 1

    The merge path actually used. The 157 unleased merges ran from #2543 (2026-10-22T08:06:03Z) through #3029 (2026-10-26T19:17:06Z). They were made through the shared maintainer account as a direct ready_for_review followed 2–5 seconds later by a squash. No reservation was taken, and no candidate-confirmation run could have completed on the merged head before the squash. Examples: #2672, ready 21:57:26 → merged 21:57:29; #2861, 22:57:46 → 22:57:48; #2947, 21:03:07 → 21:03:10; #3022 and #3029, the same pattern. scripts/integrate.ts performs the same ready transition but then waits for the run and verifies it, which takes minutes, not seconds. The merge actor is the same login for every PR in both cohorts, so the actor alone cannot tell the paths apart. The lease record and the ready→merge interval can.

    Restoration. From #3031 (2026-10-26T23:44:30Z) onward, all 85 later merges, and 92 in the window overall, have an exact-head lease. Their ready→merge median is about 21 minutes, which matches a waited-for confirmation; #3265, for example, was marked ready at 08:40:54 and merged at 09:02:40. Daily acquisitions resumed on 2026-10-26: 3 that day, then 14, 18, 29, 31, 11, 12 and 36. The skill text that mandates integrate.ts confirm was in place throughout, from #2197 on 2026-10-20, and did not change in the window. The repository therefore does not record what made agents bypass it and later return to it; the evidence above is what it does record.

    Consequences for the remaining scope. Item 2 is satisfied in practice: the documented path is the one in use, and every merge since 2026-10-26T23:44Z appears in the reservation history. That alone does not stop a bypass from recurring, because the path is cooperative. #2942's landed-while-red detection reports bypasses only while main is red. Items 3–5 (receipts, uncovered-skip refusal, expedited mode) remain the implementation.

  6. schlessera commented on Nov 2, 2026

    @schlessera
    OwnerAuthor

    Implementation for scope items 3–5 is on feat/2940-recorded-merge-path (commit 07fd0ec, built on feat/2942-red-main-controller @ b75fc09). Item 2 is satisfied in practice per the investigation: every merge since 2026-10-26T23:44Z used an exact-head lease; scripts/ci-timings.ts now reports each merged PR's merge path (recorded / expedited / unrecorded / unknown).

    What it does:

    • check:pr writes tmp/check-pr-receipt.json and prints a PR-body block (template markers added): every selected check with passed / failed / skipped / timed-out / preempted (exit 75 = host admission), plus --check-timeout=<s> and --skip <name>.
    • integrate.ts merge refuses a missing receipt (confirm refuses before acquiring), and refuses skipped/timed-out/preempted checks whose hosted categories did not run successfully in the exact-head proof. Each such check is named.
    • integrate.ts confirm|merge <pr> --fixes-main-run <run>: open-record run match, declare-fix, red-main-probe.yml purpose fix at the exact base (must fail) and the exact head (must pass), with a structured probe receipt line. It also requires the exact-head verify fast invariants, then squashes under the reservation. Category-level failures are refused. Per the 2026-11-02 recovery ruling, a targeted revert is accepted on the same evidence; a failing test file may be absent at the head only if the fix deletes it. Afterwards it records an expedited entry on the red-main record and an expedited-fix ci-timings event. The coordinator ignores fix probes.

    Proof: check:pr --base origin/feat/2942-red-main-controller passed (1132 tests). Each acceptance criterion fails first against the pre-change scripts, and six restored mutations each fail on the named assertion.

    Waiting, not yet a PR: #3279 is still an open draft, so I have not opened this against main. Confirmation is also gated by the proof-system stability window. Latest proof-system squash 2efe3fa1c has its own run green plus one of the two following main runs; #3279's merge will open a new window. Next step: once #3279 merges, rebase onto origin/main, open the PR and wait for the window. Then run collisions and integrate.ts confirm <pr> --issues schlessera/brain-kit#2940.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

agent-readyContext and acceptance criteria are complete enough for an agent to take this unattended.area: ciCI workflows, the gates they run, release scripts, packaging.priority: p1Scheduled into the current or next milestone.type: choreTooling, CI, release plumbing, dependencies.

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions