Skip to content

ci(ui-merge): every merge-queue entry runs all four ui lanes because the ui filter output falls back to 'true' on merge_group — decide the ui lanes from the diff against merge_group.base_sha, as Test Core already does (parent #25677) #25867

Closed

Description

@objectstack-fleet

Filing gate ③ (maintainer-directed) + ④: aftercare of the ui/ merge (#25752), part of #25677. Touches .github/workflows/ci.yml = Tier H: GOVERNED_APPROVERS review, the PR stops at draft.

Maintainer, 2026-10-26 01:45Z, in the project thread that measured post-merge CI speed: 「创建issue」 (asked after reading the ranked fix list; this is item 1).

谁付代价(业务筛): every PR that lands goes through the merge queue. Since the merge, a queue entry that changes only docs, scripts or a core package still runs Test UI (16 shards), Type Check UI, Build & E2E UI and Lint UI. Small entries used to finish in 4–10 min; now their floor is ~16–18 min, and each entry pays ~220 extra runner-minutes. With up to 8 card threads landing in parallel, this is the main post-merge slowdown the fleet feels.

Measured

  • Pre-merge merge_group CI runs (2026-10-25, list of 40): small entries 4.0–9.8 min (e.g. 40181079769 4.0, 40195098891 4.9, 40198037200 5.1), core entries 26–30 min.
  • Post-merge queue build 40251505048 (fix(ui-merge): two tests that #25745 broke on main read the merged tree — the Changesets config through changesetConfigPath(), the SDUI html tier by its tags (#25711) #25852): Test UI shards 8.4–17.7 min, Type Check UI 15.5 min, Build & E2E UI 5.0, Lint UI 4.5 — all scheduled although the job's queue base was only one commit behind.
  • Cause, ci.yml filter job: dorny/paths-filter runs only on pull_request / push (if: github.event_name == 'pull_request' || github.event_name == 'push'), and the outputs ui / ui_consumers fall back to 'true' (ui: ${{ steps.changes.outputs.ui || 'true' }}). Test Core does not have this problem: scripts/ci/select-shard-packages.sh already scopes merge_group runs with turbo ls --affected against merge_group.base_sha.

Wanted

  1. On merge_group, compute the ui and ui_consumers outputs from git diff --name-only <merge_group.base_sha>...HEAD, using the same globs the pull_request filter uses. Fail open: if the base cannot be fetched or the diff fails, the output stays 'true'.
  2. push / schedule / workflow_dispatch keep the full battery (maintainer ruling 2026-10-25 Q6-b: push-to-main runs stay).
  3. The workflow's gate rosters follow (check-ci-filter-parity, check-expected-skips, check-step-collectors); each --self-test exits 0.

Acceptance

  • A queue entry that changes no ui/** file and no ui_consumers path shows the four ui lanes as skipped, and the required contexts (Lint UI, Build & E2E UI, and later Type Check UI) still report success. Skipped counts as passing for a required check, so name the run that shows this.
  • A queue entry touching ui/** still runs all four lanes.
  • On the card: queue CI wall time for one small entry before and after.

Expected saving: ~220 runner-min per non-ui queue entry; small entries back to 5–10 min. Size: S. Clause-②: no. Metadata-protocol: none.

Dedupe

search_issues 2026-10-26 01:50Z 「merge_group merge queue runs all ui jobs paths filter ui output true」: 5 hits, all closed and unrelated (#19036, #16574, #11621, #9283, #4897). New.

Measurement report: /mnt/project-files/d1-merge/out/ci-speed/post-merge-pr-ci-speed.md (project thread "Keep PR CI fast after the merge").

Activity

  1. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: epic #25677 round 8 (post-cutover CI speed cards; Tesla 2026-10-26 01:45Z 「创建issue」) 2026-10-26T01:55Z
    Session: session_01RSDL3SFtJaKzcymvCD8RsU
    Account: os-tesla
    Branch: claude/project-thread-8dceid (the card thread's designated branch in objectstack-ai/objectstack — the thread can push only this branch, a measured platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-25867
    Domain: domain:devx
    Seat: epic:#25677
    Scope: the whole card — ci.yml filter job computes ui / ui_consumers on merge_group from git diff --name-only <merge_group.base_sha>...HEAD with the pull_request globs, fail-open to 'true'; push/schedule/workflow_dispatch keep the full battery (Q6-b); the gate rosters follow with --self-test 0; Tier H (draft, os-zhuang + hotlong), skip-changeset
    Why now: every queue entry pays ~220 runner-min and a 16–18 min floor for four ui lanes it does not need; with 6 card threads landing tonight this is the queue's pace
    Container & model: S, mode:thread (thread session session_01Suqt7vsGh5kE2NhDZyqeh6; order: this card's body, FRAME.md applies), model: opus, effort: xhigh
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — epic step
    Thread-read: none
    Serial constraints cleared: #25868 edits only the test-ui job of the same file (branch claude/project-thread-n0iri6); the #25853 seat's Type Check UI row PR edits scripts/check-required-contexts.mjs and the two statesTheSet surfaces, not ci.yml; #25869 is held until this and #25868 land. Rebase over whichever lands first; ⛔ do not change any lane's if: beyond the filter outputs this card names

  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 25867,
     "status": "done",
     "branch": "claude/project-thread-8dceid",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/25881",
     "session": "session_01Suqt7vsGh5kE2NhDZyqeh6",
     "premise_still_valid": true,
     "summary": "ci.yml filter job: the dorny/paths-filter step's allow-list gains merge_group (the pinned v4.0.3 reads merge_group.base_sha/head_sha from the payload and diffs base..head), continue-on-error on that event so a failed diff fails open to 'true'. ui and ui_consumers read the queue diff; docs/core/crosspkg are guarded with github.event_name != 'merge_group' and stay 'true' on queue builds; schedule/dispatch unchanged. check-expected-skips header + ui roster reasons and the dispatch-gates marker census (133 -> 137) follow.",
     "tests": "Replayed the pinned action dist/index.js with synthetic merge_group payloads and this branch's filter block: non-ui entry abebc4e1 -> ui=false ui_consumers=false; spec+lint b00fc55c -> ui=false ui_consumers=true; ui/ entry 12105449 -> ui=true; 3-commit group 3fca5996..c475b45b -> ui=true; depth-1 checkout with base absent -> action fetched base by sha and diffed; unfetchable base -> action exit 1 with no outputs (fail-open via continue-on-error). Live queue evidence owed after landing (this PR's own entry changes ci.yml, which is in the ui filter, so it runs all four ui lanes).",
     "gates": "be2cff5e: dispatch-gates --commands derives 67; all 67 exit 0 (incl. check:pm-dispatch-gates fast tier 1917/1917, check-ci-filter-parity + --self-test, check:pm-expected-skips, check-step-collectors + --self-test, check:type-check-debt); --ran: 67 derived, 67 run, 0 NOT-MEASURED (derived zero). Earlier head 5aa9fcb3: check:pm-dispatch-gates 1 of 1917 red (marker census pinned check-expected-skips.mjs:133), fixed in be2cff5e. PR check-runs: in_progress at report time.",
     "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
     "files_changed": [
      ".github/workflows/ci.yml",
      "scripts/pm/check-expected-skips.mjs",
      "scripts/pm/dispatch-gates.self-test.mjs"
     ],
     "line_budget": "+70 / -37",
     "deviations": [
      "Route: the card says git diff --name-only with the pull_request globs; the step runs dorny/paths-filter itself on merge_group instead, so the globs are the same block by construction and check-ci-filter-parity's one-step rule holds.",
      "Third file outside the card's named rosters: dispatch-gates.self-test.mjs marker-census row moved 133 -> 137 because the check-expected-skips header grew four lines."
     ],
     "mcp_calls": "4 — issue_read get, issue_read get_comments, list_pull_requests, pull_request_read get (all reads, no write tool)",
     "api_writes": "2 — relay pr_create (fleet-write run 40259928648; relay's governed-review follow-up requested os-zhuang + hotlong), this report comment via post-stamped",
     "open_questions": [],
     "out_of_scope_findings": [
      "carrier: none · noted, not filed — docs/core/crosspkg could read the queue diff the same way (Build Core / Build Docs would skip on queue entries outside their paths); left at 'true' per the filter's 'queue build is the last validation before main' reasoning"
     ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Live queue evidence for #25881 (merged 03:27Z), read 2026-10-26T05:25Z.

    Non-ui entry: #25929 (fix(service-automation), 3 files: packages/services/service-automation/src/** + a changeset). Merge-group run 40271496679, base dd5e3554f0:

    job conclusion window
    filter success 04:55:07–04:55:34
    Test UI (pre-expansion name, all 16 shards) skipped 04:55:34
    Type Check UI skipped 04:55:34
    Build & E2E UI skipped 04:55:34
    Lint UI skipped 04:55:34
    Build Core / Build Docs success until 05:01:26 / 05:00:41
    Test Core (8 shards + aggregate) success until 05:15:39 (long pole: 4/8, 19.5 min)

    The entry landed on main as de2b7e02 with Lint UI and Build & E2E UI (required) reported as skipped, so the queue accepted skipped as passing.

    Spec entry: #25830 (spec,plugin-auth,runtime,cli). Run 40264874688 took the ui_consumers path, as designed:

    • Test UI and Lint UI were skipped.
    • Type Check UI (03:36:39–03:48:37) and Build & E2E UI (03:36:39–03:43:43) ran.
    • The run concluded success and landed as f00e8d5c.

    Before vs after (ui lanes per queue entry):

    Wall clock: 40271496679 ran 20.6 min (04:55:05 to 05:15:39). For an entry that touches a core package, Test Core 4/8 is the critical path either way, so the ui skip does not shorten it; the saving there is runner-minutes and slots.

    Pending: a docs- or scripts-only entry, where the ui lanes used to set the ~16–18 min floor, has not entered the queue since the merge. When one does, its wall clock is the remaining before/after number on this card.


    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

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:devxpm:epicpriority:p2Medium: important, M3tooling

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions