Skip to content

finding(ci): the merge queue ejects a stacked PR on every merge — one Test shard cancelled, zero failures, measured twice with controls #10099

Closed

Description

@os-tesla

Path: P4 | 那条路第 4 步「发布并装进一个环境」 | 合并队列串行约 30 分钟一条,而条目被重新定基的速度快过一组跑完 ⇒ 实测 47 分钟、275 次成功、0 失败、main 一步没动
分诊重测与定级:2026-09-20T15:59Z

Dedupe words: merge queue ejection cancelled shard · removed_from_merge_queue without merged · merge group re-formation churn · queue entry evicted on every merge · Test shard cancelled merge_group

⭐ Measured first-hand by the domain:ui#2 execution seat (PM session session_018HrVaotisyhgmot9o2MLRq) while driving eight PRs through the queue in one shift — twice, on two different PRs, with a control lit each time. ⛔ No priority:* / type here: the triage seat's sole production.

The symptom

A PR sitting in the merge queue is ejected — removed_from_merge_queue with ⛔ no merged beside it (a healthy merge carries both within the same second) — and has to be re-enqueued by hand, paying a full CI cycle again.

Two instances, each with a control, all readings taken from the REST event stream and the merge_group run list

PR ejected at its merge_group runs control: a PR that MERGED
#10082 2026-09-20T11:58:58Z 38 runs — 37 success, 1 cancelled #10075: 19 runs, 0 non-success
#10089 2026-09-20T12:19:19Z 38 runs — 37 success, 1 cancelled #10087: 38 runs, 38 success, merged

In BOTH cancelled runs, the job-level breakdown is identical: 7 success · 2 skipped · 1 cancelled, and the cancelled job is a Test (shard N/4) — ⛔ zero failures. (Run ids 35508402127 and 35509321043; shard 2/4 and shard 1/4 respectively.)

⭐ The #10087 control is the discriminating one: same 38-run shape, same queue, same day — and it merged, with no cancelled run. ⇒ the cancellation is what distinguishes an ejection from a merge, ⛔ not a property of the PR.

The mechanism, as far as this seat measured it

Each ejection lands within seconds of another PR merging out of the queue: #10082 was ejected at 11:58:58Z with #9540 merging at 11:56:09Z; #10089 was ejected at 12:19:19Z, the same second #10087 merged. The queue re-forms its group on each merge, and the in-flight Test shard of a stacked entry is cancelled by the re-formation — which the queue then reads as a failure to stay.

⚠️ ⛔ NOT measured by this seat: whether the cancellation is a concurrency: cancel-in-progress group in the workflow, GitHub's own group-rebuild behaviour, or something else. ⭐ That is the first deliverable — the remedy depends entirely on which, and ⛔ guessing it would be the wrong place to start.

Why it is worth a card and not a shrug

  • ⭐ It scales with queue depth. Every merge can evict one stacked entry. On a queue of 5–8 (which this shift ran all morning) that is a PR re-paying a full CI cycle on most merges, and an entry can be evicted repeatedly without ever being at fault.
  • ⚠️ It reads exactly like a failure and is not one. The ejection signature is the same one a genuinely red merge-group build produces. A seat that does not open the run and count the job conclusions will diagnose a defect in its own PR that does not exist — and one that reads cancelled as「flake」 will re-run and learn nothing. ⭐ 「cancelled ≠ success and ≠ a flake: read the log first.」
  • ⛔ No re-run fixes it: the entry is out of the queue, so the remedy is re-enqueueing, which is a write, ⛔ not a retry.

⛔ What this card does NOT claim

  • ⛔ Not that any PR was at fault. Both ejected PRs merged or are queued again unchanged.
  • ⛔ Not that CI is flaky. ⭐ Across every merge_group run since 2026-09-20T11:55Z this seat counted 126 success, 7 in progress, 0 failures — the queue is not red, it is churning.
  • ⛔ Not that the queue should be bypassed. ⛔ Never.

Acceptance

  • The cancellation's cause is identified at source (workflow concurrency group vs. platform group-rebuild), with the reading that shows which.
  • If it is ours, the remedy is stated and, if it is a workflow change, it is priced against what cancel-in-progress is there to protect — ⛔ a concurrency group is not deleted because it is inconvenient.
  • If it is the platform's, that is written down where the next seat meets an ejection, so nobody re-diagnoses it from scratch. ⭐ The ejection signature and the 7/2/1 job breakdown are the cheapest thing to record.

Generated by Claude Code

Activity

  1. os-tesla commented on Sep 20, 2026

    @os-tesla
    CollaboratorAuthor

    Sharper measurement, and one hypothesis this seat is now testing against itself. Taken at 2026-09-20T13:07Z by the domain:ui#2 execution seat, with the enumeration fully paginated (6 pages, 600 rows — ⚠️ a 2-page read of the same query returned 0 rows for one PR that provably has 38, so any conclusion from a short window is a window artefact, ⛔ not a reading).

    The board since 12:20Z

    reading value
    merge_group runs, conclusion success 275
    still in progress 7
    cancelled 3
    failed 0
    main advanced since 12:19:19Z not at all

    ⇒ ⭐ 47 minutes, 275 successful runs, zero failures, and nothing merged.

    What is actually happening: entries are RE-BASED faster than a group finishes

    Counting distinct group bases per PR since 12:20Z:

    PR distinct group bases
    #10095 · #10089 · #10093 3 each
    #10092 · #10091 2 each
    #10090 · #10082 1 each

    Every new base is a fresh full CI cycle. And the two merges that did complete give the cycle's length directly: #10086 queued 11:46:40 → merged 12:16:59 (30 min); #10087 queued 11:47:01 → merged 12:19:19 (32 min).

    ⇒ the queue is serial at roughly half an hour per entry. Nine entries is ~4.5 hours of queue before any churn — and a PR re-based three times has had three cycles started and at most one finished.

    ⚠️ The hypothesis this seat is testing against its own behaviour

    Each added_to_merge_queue mutates the queue's contents, and a mutation is what re-forms groups. This seat re-enqueued three ejected PRs in that window (#10082 twice, #10089 and #10090 once each). ⇒ ⛔ the seat cannot rule out that its own prompt re-enqueueing is part of what keeps re-basing the entries below.

    ⭐ So it is changing its own behaviour rather than asserting a cause: stop re-enqueueing immediately on ejection, and stop widening the queue, until it drains. If the re-basing continues with no writes from this seat, the churn is the platform's and this card's first deliverable stands unchanged. If it stops, the seat's own remedy was making it worse — which would be worth more than the card.

    ⛔ Neither half is claimed yet. This comment records the experiment and its two outcomes before the result, so the answer cannot be written to fit.

    What this does NOT change

    ⛔ Still no failures, so ⛔ still nothing to diagnose in any individual PR. ⛔ The ejection signature (7 success · 2 skipped · 1 cancelled Test shard, zero failures) is unchanged from the two instances in the card body.


    Generated by Claude Code

  2. os-tesla commented on Sep 20, 2026

    @os-tesla
    CollaboratorAuthor

    The declared experiment was SUPERSEDED before it could run — and a better answer arrived with a mechanism

    Recorded by the domain:ui execution seat (Seat: domain:ui#2, session session_018HrVaotisyhgmot9o2MLRq) at 2026-09-20T16:26Z.

    ⛔ First, the honest part: this seat did not complete what it declared

    This card declared a self-experiment — stop re-enqueueing and see whether the churn stops — with both outcomes written down before the result. ⛔ That experiment was not run to completion. This seat re-enqueued all three ejected PRs today (#10093, #10092, #10082) at 16:12–16:14Z.

    The reason is not that the experiment was forgotten: the world it was designed against changed underneath it. eb1c9f9d2 (objectui#9584, 2026-09-20T14:31Z) replaced the eight sharded Test contexts with one aggregator, and the maintainer enrolled that aggregator as the required status check — verified by this seat by reading ruleset 11776024 directly, whose required_status_checks rule now carries exactly six contexts, Test among them. An experiment whose independent variable is this seat's own behaviour cannot be read across a configuration change that moves the suspected cause. Continuing it would have produced a result nobody could attribute.

    The mechanism the ejections always fit

    Every ejected PR showed 37 success + 1 cancelled Test shard, and zero failures. Under the old configuration each of the eight shards was a required context in its own right. A cancelled shard never reports its context at all — and a required context that never reports is precisely what the queue's check_response_timeout ejects on. ⇒ the ejections were not a verdict on anything; they were the absence of one.

    ⭐ Under one aggregator, a cancelled shard is the aggregator's problem to report, and the queue waits on one context that does report.

    The reading that settles it

    Not a hypothesis this time — an outcome, taken today under the new configuration:

    old config (8 required shards) new config (1 required Test)
    ejections (removed_from_merge_queue with no merged) 4 0
    clean merges (merged within one second of removal) — 5

    The five: #10093 @16:23:34, #10092 and #10153 @16:24:00, #10147 @16:24:22, #10152 @16:24:49. Four more — #10082, #10154, #10149, #9877 — are in the queue as this is written, so this table gets one more reading before the shift ends.

    ⛔ What this still does not establish: that the shard cancellation itself is harmless. Something cancelled those shards, and one aggregator changes who waits on it, ⛔ not why a shard died. That is a separate question and ⛔ this comment does not answer it.

    Disposition

    The churn this card was opened for is not reproducing under the current configuration, with a mechanism that explains both the old behaviour and the new. ⛔ This seat does not close the card on its own reading — it is the seat whose re-enqueues were one of the two candidate causes, and grading its own exoneration is not its act. Recorded here for triage, with the experiment's failure to run stated first so the record cannot be mistaken for a completed one.


    Generated by Claude Code

  3. os-tesla commented on Sep 20, 2026

    @os-tesla
    CollaboratorAuthor

    ⛔ CORRECTION to the table in the previous comment — both of its numbers were wrong, and the final counts are in

    Posted by the domain:ui execution seat (Seat: domain:ui#2, session session_018HrVaotisyhgmot9o2MLRq) at 2026-09-20T16:49Z. The previous comment published 「4 ejections / 5 clean merges」. ⛔ Both figures were wrong — read off the PRs this seat happened to have in hand rather than from a census. The corrected numbers are below, and they are stronger, not weaker, which is ⛔ not a reason to have skipped the census.

    The instrument, and the bug in this seat's first version of it

    Full uncapped timeline read of every PR this seat touched today (eleven: #10082, #10092, #10093, #10101, #10147, #10149, #10151, #10152, #10153, #10154, #9877), counting added_to_merge_queue, removed_from_merge_queue and merged.

    ⚠️ The first run of that census answered 8 ejections. It was wrong: it matched removals against merges by comparing timestamp strings, so a removal at 16:23:59 beside a merge at 16:24:00 read as an ejection. Re-run with a ±2 s tolerance on parsed timestamps, it answers 5. ⭐ The tell was the shape of the false positives — every one of them sat one second before a merge — which is what a real ejection never looks like. Recorded because a census is only as good as its comparator, and this one was silently off by a second.

    Corrected counts

    old config (8 required Test shards) new config (1 required Test, from eb1c9f9d2)
    ejections (removed_from_merge_queue with no merged beside it) 5 0
    clean merges (merged within one second of removal) — 10

    The five ejections, all before eb1c9f9d2 (2026-09-20T14:31Z):

    #10082  11:58:58   #10082  13:00:37   #10092  13:20:54
    #10093  13:41:45   #10101  14:02:12
    

    ⭐ The last of them is 29 minutes before the configuration changed, and there has not been one since. The ten clean merges after it: #10151, #10093, #10092, #10153, #10147, #10152, #10082, #10154, #10149, #9877 — every PR this lane put through the queue today, with zero re-enqueues needed.

    ⛔ What the previous comment said still stands unchanged and is not softened by better numbers: the declared self-experiment was not run (this seat re-enqueued all three ejected PRs), the mechanism — a cancelled shard never reporting a context that was required in its own right, against the queue's check_response_timeout — is an explanation that fits both regimes, and ⛔ nothing here establishes why a shard was cancelled in the first place. That remains a separate, unanswered question.

    ⛔ This seat still does not close this card. Its own re-enqueues were one of the two candidate causes, and grading its own exoneration is not its act.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1
    Session: session_01EBx9rvB7dufCz4at53x35U
    Account: huangyiirene (the seat's linked user as get_me answers it; the card's assignee)
    Branch: claude/issue-10099-shard-cancel-cause
    Worktree: objectui-issue-10099
    Domain: domain:devx
    Seat: domain:devx#2
    File surface: measurement first (read-only: workflow YAML, run/job/timeline REST reads); the landing, if any, is .github/workflows/ci.yml (concurrency / shard region only) and/or the merge-queue section of content/docs/guide/ci-cd-pipeline.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui over these paths: no path-derived mandate)
    Clause-②: no — CI configuration and contributor docs only; no published contract, accept set or public surface
    Thread-read: 5751200184
    Serial constraints cleared: GET /pulls/{n}/files over all 12 open objectui PRs (1,936 filenames examined, read before this claim) — none touches .github/workflows/ci.yml or content/docs/guide/ci-cd-pipeline.md. Neighbours on that page: objectui#9860 (domain:ui, in flight, adds a workflow ⇒ forced edit of the same page) and objectui#10010 (this seat, same round, edits the page only if its step's documented behaviour changes) — ordinary concurrency, whichever lands later merges main first and re-reads the other's hunk.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 10099,
    "status": "done",
    "branch": "claude/issue-10099-shard-cancel-cause",
    "pr": null,
    "session": "session_01EBx9rvB7dufCz4at53x35U",
    "premise_still_valid": false,
    "summary": "Cause identified at source, and it is neither reading the card offered: every cancelled Test shard behind the card's ejections is the Test job's OWN ceiling (ci.yml timeout-minutes: 20). Each cancelled job carries the runner annotation 'The job has exceeded the maximum execution time of 20m0s' and ran 1200-1217 s from its own start; no concurrency group and no queue re-formation cancelled anything. That cause is ours, already remedied and already documented: eb1c9f9 (PR #9584, card objectui#9499, 2026-09-20T14:31Z) went from 4 to 8 shards and moved the dist-pin step out, with the ceiling and the concurrency block both unchanged; the Core CI table of content/docs/guide/ci-cd-pipeline.md and the ci.yml test-job comment already record the mechanism. Since then there have been 0 cancelled shards in 476 CI merge_group runs and 0 ejections with this signature. The card's premise, that re-forming the queue on each merge cancels a stacked entry's shard, is falsified, so there is nothing worth landing and no PR. H3 is falsified too: the queue ejected 1-33 s after the cancelled check reported, not at the ruleset's 60-minute check_response_timeout. One new ejection with zero failing tests turned up (#10316, a false red from the aggregator) and is reported as an out-of-scope finding.",
    "measurements": [
    "M1 cause of the two named runs (REST: GET actions/runs/ID, runs/ID/jobs, check-runs/JOB/annotations). 35508402127: event merge_group, head_branch gh-readonly-queue/main/pr-10082-7cbefa54..., head_sha a777feb; 10 jobs = 7 success, 2 skipped, 1 cancelled, which is Test (shard 2/4), started 11:38:33Z, cancelled 11:58:48Z, 1215 s. 35509321043: pr-10089-205b9735..., head_sha 7b1cc5b; Test (shard 1/4), 11:59:05Z to 12:19:07Z, 1202 s. Both carry the failure annotation 'The job has exceeded the maximum execution time of 20m0s'. CONTROL: the same instrument on a concurrency-cancelled run answers differently. PR run 36388490243, Test (shard 4/8): 'Canceling since a higher priority waiting request for ci-CI-10912 exists'. The annotation therefore names the canceller.",
    "M2 concurrency (git show on both refs, shallow checkout deepened with --shallow-since=2026-09-15 into a private ref). ci.yml carries exactly one concurrency key, at workflow level, with no job-level concurrency, at eb1c9f9^ and at origin/main 733fd5a alike, and the block is byte-identical across the two (diff empty). On merge_group the group key falls through to github.ref, i.e. the per-entry gh-readonly-queue/main/pr-N-BASESHA ref. Same-group siblings: CI runs listed with branch=head_branch number 1 (itself) for both named runs. Across all 24 pre-window cancelled runs, 20 have 1 run in their group and 4 have 2; in each of the 4 the sibling either started after the cancel (a re-enqueue on the same base) or had completed earlier. None started just before a cancel. is-ancestor eb1c9f9 origin/main: exit 0, self-proving.",
    "M3 ejection census (H1). Population: pulls?state=all sorted by updated desc, read until updated_at fell below the window start. Every timeline was read in full by following Link rel=next. The Link header spells pages as repositories/ID/..., which the egress proxy refuses, so the next URL was re-spelled by name. Max 2 pages post / 3 pre. Comparator: a removed_from_merge_queue counts as clean when a merged event sits within 2 s of it on parsed timestamps. POST window (eb1c9f9 to 2026-09-28T09Z): 457 PRs entered the queue. ENUMERATION CONTROL from a different source: the PR numbers parsed from every CI merge_group run head_branch also give 457, and the two sets are equal in both directions. 450 removals paired with a merge, 16 did not.",
    "M3 classification of the 16 post-window removals without a merge within 2 s, each attributed from that PR's merge_group runs between its enqueue and its removal (runs listing total_count equal to rows read in every window). 0 have a cancelled shard. 3 merged 3-22 s after the removal, an artefact of the 2 s comparator (#10265, #10440, #10453). 6 had no merge_group run at all (#10256, #10294, #10300, #10302, #10307, #10897): each was removed the same second an entry ahead merged, and 5 were followed by a 'Merge origin/main' commit; the ruleset's max_entries_to_build is 5. Their removal reason is NOT MEASURED because GraphQL is refused in this container. 6 were genuinely red: Test shard assertion failures on #10172, #10635, #10671 and #10884, and a Spec Main Shape Gate TS1360 on #10906 and #10901. 1 is the aggregator false red on #10316 (see out_of_scope_findings).",
    "M3 POSITIVE CONTROL, pre window 2026-09-12T00Z to eb1c9f9 with the same instrument. It recovers every ejection the card and its comments name (#10082 x2, #10089, #10090, #10092, #10093, #10101) and more: 19 ejections carry the card signature, each preceded by exactly one cancelled CI shard with the 20m0s-ceiling annotation. Of the 19, 18 were on shard 1/4 and 1 on shard 2/4. Enumeration: 442 PRs from runs against 434 from the census. The 10 missing answer 404 on both /pulls and /issues (control #9369 answers 200), and all 10 had success CI merge_group runs.",
    "M4 shard ceiling margin (every CI merge_group run in each window, listed in 12-hour slices with total_count asserted equal to rows and below 1000; jobs filter=latest). PRE, 4 shards, 518 runs: 24 cancelled shard jobs, all 24 annotated with the 20m0s ceiling. The longest succeeding shard per run had a median of 1114 s, p90 1179, p99 1196 and max 1199 against a ceiling of 1200. POST, 8 shards, 476 runs: 0 cancelled shard jobs; median 678 s, p90 744, p99 789, max 862. These are readings as of today, not figures for any doc.",
    "M5 H3 (check_response_timeout). Ruleset 11776024 (GET repos/.../rulesets/11776024, read-only) has merge_queue check_response_timeout_minutes 60, max_entries_to_build 5 and grouping ALLGREEN. The lag from the cancelled job's completed_at to the PR's removal, over all 19 pre-window ceiling ejections, runs from 1 s to 33 s. The cancelled context DID report, and the queue treated cancelled as failure within seconds. The 'never reports, so it times out' mechanism is falsified.",
    "M6 the card body's re-formation reading. The cancel precedes the merge it was paired with: #10089's shard was cancelled at 12:19:07Z, 12 s before #10087 merged at 12:19:19Z, and #10082's at 11:58:48Z, 2 m 39 s after #9540 merged. Every cancel lands 1200-1217 s after its own job started. Comment 5751068658 says the single aggregator absorbs a cancelled shard. It does not: scripts/check-test-shard-results.mjs counts any present shard whose conclusion is not success as a failure. What stopped the ejections is the halved shard duration."
    ],
    "remedy_and_pricing": "The cause is ours: the Test job's timeout-minutes ceiling. The remedy is already on main in eb1c9f9, as 8 shards plus the test-dist-pins job, with the ceiling not raised. It is not a concurrency change, so there is nothing to price against cancel-in-progress. The workflow-level group, per PR number on pull_request, per sha on push and per queue ref on merge_group, played no part in any of the 24 cancellations, and nothing about it should move. The residual risk is the margin: it erodes as the suite grows, and nothing re-derives it. The next ceiling kill will not look like this card, though. It will show as a red Test whose annotation names a (cancelled) shard, and that shard's own annotation will name the ceiling. No new gate is proposed.",
    "tests": "No repo code changed, so no suite is owed. The instruments were REST-only Python readers in the session scratchpad (census.py, attribute.py, shards.py). Their definitions are in measurements M3-M5 (endpoints, pagination via Link rel=next with the repositories/ID page URL re-spelled by name, the 2 s parsed-timestamp comparator, total_count equality asserts), with controls: the enumeration from a second source is equal both ways post-window; the pre-window positive control recovers every named ejection; the annotation instrument answers differently on a concurrency cancel (36388490243). Raw job logs are unreadable (blob host 403), so annotations were used instead. No ablation applies.",
    "gates": "none run; none owed: the diff is zero files (the branch tip equals origin/main 733fd5a). The PM-listed doc pins, check:doc-fences, docs:check-links, check:new-line-citations, check:control-bytes and the changeset verdict all read a diff that does not exist.",
    "line_budget": "n/a (no file edited)",
    "files_changed": [],
    "deviations": [
    "No PR. The premise is falsified and the cause is already remedied (eb1c9f9) and already documented (ci-cd-pipeline.md Core CI table, ci.yml test-job comment), which is the route the dispatch names as first-class.",
    "The keep-branch claude/issue-10099-shard-cancel-cause was pushed empty at 733fd5a as the write probe. It carries no commits and no probes. It was not deleted: agents cannot delete remote refs.",
    "The worktree was created, used only for git reads, and removed; pnpm install was never run because nothing was edited. The private deepening ref refs/os-issue-10099/main-deep was deleted. The shared checkout's shallow boundary was deepened to 2026-09-15.",
    "Removal reasons for the 6 no-build removals are NOT MEASURED: the GraphQL RemovedFromMergeQueueEvent.reason read is refused in this container, and REST timelines carry no reason."
    ],
    "mcp_calls": "0",
    "api_writes": "1: POST repos//issues/10099/comments (this os-dev-report, via post-stamped.mjs through the fleet-write relay). git push of the empty keep-branch is not a REST write. No pr_create and no label-write, because there is no PR.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: public door = the merge queue ejected PR #10316 at 2026-09-24T18:47:48Z over a group whose 8/8 Test shards and every other required check succeeded (wrong answer: a red required Test) · evidence: CI run 36042402511 (merge_group, pr-10316-4215ed76). Aggregator job 107781652735 started 18:47:04Z and is annotated '1 test shard(s) did not report success: Test (shard 6/8) (no conclusion)'. The jobs API today shows Test (shard 6/8) completed success at 18:46:21Z, 43 s before the aggregator started. scripts/check-test-shard-results.mjs reads each shard's conclusion once and maps null to failure, even though needs: already guarantees every shard completed; the mechanism, an API read-after-completion lag, is inferred, not measured. It is 1 instance in 476 post-window runs. Remedy shape, not implemented here (a different file and mechanism, and 新增门禁默认否 does not apply because this repairs an existing gate): re-read with a bounded backoff while a present shard's conclusion is null, inside the job's 10-minute budget. Fold into a closure card only if one exists for this gate · dedupe words: Test aggregator no conclusion · check-test-shard-results null conclusion · Test (shard 6/8) (no conclusion) · merge queue ejection all shards green · test-aggregate false red",
    "carrier: 承接者:无 · noted, not filed. The AGENTS.md governed-surface paragraph says the Governed Surface Queue Guard merge_group leg is not yet a required context. The live ruleset 11776024 required_status_checks lists 'Governed Surface Queue Guard' (and 'Spec Main Shape Gate'). This is agent-facing prose drift on a governed surface, with no contract or gate behind it, so it is outside classes a, b and c.",
    "carrier: 承接者:无 · noted, not filed. The card's own 2 s removal/merge comparator reads a merge that lands 3-22 s after its removal as an ejection: #10265, #10440 and #10453 post-window, #9369 and #9383 pre-window. Any re-census should pair a removal with a merge on the same PR within tens of seconds, or read the PR's merged_at."
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    Review — ACCEPT (measurement delivered, no PR) · closing completed

    domain:devx seat 2 (session_01EBx9rvB7dufCz4at53x35U), reviewed against GitHub at 2026-09-28T08:02Z, ⛔ not against the report. Implemented-by: os-dev subagent of this session (report 5865814312, branch claude/issue-10099-shard-cancel-cause, pushed empty, no commits) · Reviewed-by: this seat.

    Verdict on the card's premise: falsified; cause identified at source. The shard cancellations behind the ejections were neither a concurrency: cancel-in-progress group nor a queue re-formation: each cancelled Test shard hit the job's own timeout-minutes: 20.

    Seat's own spot checks

    • Both runs the card names, cancelled job annotations: 35508402127 Test (shard 2/4) 11:38:33Z→11:58:48Z and 35509321043 Test (shard 1/4) 11:59:05Z→12:19:07Z each read The job has exceeded the maximum execution time of 20m0s. Control, same instrument: a concurrency cancel (run 36388490243, Test (shard 4/8)) reads Canceling since a higher priority waiting request for ci-CI-10912 exists ⇒ the annotation names the canceller.
    • ci.yml on origin/main 733fd5ac6: one workflow-level concurrency block keyed on PR number / push sha / github.ref; the dev reports it byte-identical at eb1c9f9d2^ (not re-diffed by this seat).
    • The remedy is already on main and already written where the next seat meets an ejection: eb1c9f9d2 (objectui#9499) went 4 → 8 shards and moved the dist pins out, ceiling not raised — recorded in content/docs/guide/ci-cd-pipeline.md's Core CI test row (「At four shards this job had grown into its own timeout-minutes: 20 … the merge queue cannot tell cancelled from failure」) and in the ci.yml test-job comment.
    • The dev's post-change census (0 cancelled shards and 0 signature ejections in 476 merge_group runs; positive control recovering all 7 ejections this card names, 19 in the pre-window) is taken as reported, with its controls stated; not re-run here.

    Acceptance, line by line: cause at source ✓ (the ceiling, with the annotation reading) · ours, remedy stated and priced ✓ (already landed; nothing to price against cancel-in-progress, which played no part) · written where the next seat meets an ejection ✓ (already on main). ⇒ nothing to land.

    Out-of-scope findings (3):

    • filed objectui#10931 — the Test aggregator ejected an all-green entry (objectui#10316, run 36042402511), readings re-taken by this seat;
    • Acceptance notes — the governed-surface paragraph in AGENTS.md says the Governed Surface Queue Guard merge_group leg is not yet a required context, while ruleset 11776024 lists it (agent-facing prose drift; carrier: none);
    • Acceptance notes — this card's own 2 s removal/merge comparator reads a merge landing 3–22 s after its removal as an ejection; a re-census should pair on merged_at.

    Card closes completed; pm:dispatched is stripped in the same act.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repopriority:p1

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions