Repository navigation
ci: a diff confined to a package ui tests import (packages/lint, spec, client, core, formula, sdui-parser, types) skips the Test UI shards on the PR and in the queue #28220
Description
domain:ui#3 · os-tesla · session_01L9qibz8HEj53Wx2uphTo2o
Ruled: 6545651687 · letter A · 2026-10-31T15:55Z
Ruling-ref: 6545651687
Filing gate: ① a named, reproduced defect (a CI gap that let a red reach main). Root-cause card for the p0 anchor #28219.
Business reason
Who: every lane, through the merge queue. What happens: a diff confined to packages/lint/** (or another ui_consumers package) lands without the Test UI shards ever running, though ui tests import that package; the red then surfaces on the next unrelated PR that does start the shards, which is ejected for a change it never made. If not done: the same thing recurs for every lint/spec/client/core/formula/sdui-parser/types change that moves a value a ui test pins; today it cost #28197 a queue round and opened #28219.
Mechanism
- .github/workflows/ci.yml, the changes filters (≈L522–570): ui (which starts Lint UI and the Test UI (n/16) shards) lists ui/** and shared roots; ui_consumers lists packages/spec/**, client, core, formula, lint, sdui-parser, types, and starts Type Check UI and Build & E2E UI only.
- fix(lint): a flow node config-value finding carries the slot's key path, so Studio's Problems row selects the node #28192 (3efccfd, packages/lint/** + packages/metadata-protocol/**): its queue CI run 41091107812 shows Test UI (n/16) and Lint UI skipped, Type Check UI / Build & E2E UI / Live E2E UI success. Merged 16:55:58Z.
- ui/packages/app-shell/src/views/studio-design/AutomationsPillar.problemsAgree-27799.test.tsx imports validateStackExpressions from @objectstack/lint; the next queue build that ran the shards (41095303977, fix(ui): Setup metadata lists take their title from the sidebar and lead with the label #28197) failed it.
Fix direction (owner decides the shape)
Start the Test UI shards when ui_consumers matches, or narrow it by measurement (which ui_consumers packages ui test files import) and add those to the condition that starts the shards. Cost to weigh: shard runner-minutes on spec/lint-only diffs (#25869 / #25881 measured the ui lanes' cost).
Acceptance
- A diff confined to packages/lint/** starts the Test UI shards on the PR and in the queue (filter self-test or a measured run).
- The CI filter parity / self-tests that pin these lists are updated in the same PR.
Reader and dedupe
- Who acts: domain:devx (CI filters; ci(ui-merge): every merge-queue entry runs all four ui lanes because the
uifilter output falls back to 'true' on merge_group — decide the ui lanes from the diff againstmerge_group.base_sha, as Test Core already does (parent #25677) #25867 / ci(ui-merge): queue builds decide the four ui lanes from the merged diff against merge_group.base_sha #25881 / ci: schedule the ui jobs, Build Docs and Test Core for the root inputs they read (package.json, five ui test inputs) #28089 were this lane's). - Dedupe: ci: schedule the ui jobs, Build Docs and Test Core for the root inputs they read (package.json, five ui test inputs) #28089 (package.json in ui/docs filters, ui test inputs in core:) and ci(ui-merge): every merge-queue entry runs all four ui lanes because the
uifilter output falls back to 'true' on merge_group — decide the ui lanes from the diff againstmerge_group.base_sha, as Test Core already does (parent #25677) #25867 (queue ui lanes from the diff) are related, closed, and do not cover ui_consumers → Test UI. Open issues since 16:50Z: none.
Activity
objectstack-fleet commentedon Oct 30, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p1 ·
domain:devx·pm:queue· agreed · 2026-10-30T18:01Z⛔ Not a claim.
sys_metadata_activationin the disabled-action sentence that #27842 rewrote #28082 (dogfood), Test UI red on main: flow-value-envelope.test.ts pins the flow expression ledger at 18 value entries, and #28150 added a 19th (connector_action input.*) #28185 (flow-value-envelope) and Test UI red on main: AutomationsPillar.problemsAgree-27799 still expects the node config finding's where prose, and #28192 now gives it a key path #28219 (problemsAgree-27799). In each, a spec or lint change moved a value that a test pins, and the suite holding that pin did not run for the change's own diff. A bystander PR was then ejected for it.ui_consumerspackages that ui test files actually import. The PR states the runner-minute cost against ci(ui-merge): twenty ui jobs each rebuild the same seven @objectstack packages (1.6–2.5 min apiece, mostly turbo cache misses on PRs) — build them once per run and hand the dists to the ui lanes (parent #25677) #25869 and ci(ui-merge): queue builds decide the four ui lanes from the merged diff against merge_group.base_sha #25881.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:devx#2 · os-justin · session_01QSeKYmTYfaPbLQD4BJfomW
决策请求:#28220 要改
ci.yml,需维护者裁决 · 2026-10-30T18:04Z⛔ 不是认领。分诊审计 6529894991 已同意本卡:p1,
domain:devx。本卡的修复只能落在根.github/workflows/ci.yml。维护者有常设约束:改ci.yml先裁决(#25913 的授权只覆盖那一步)。所以本卡转needs-user-decision,裁后由席位派发;PR 属 Tier H,另需契约复审 PASS 和你的批准。一句话问题:只改了 lint、spec 等「ui 依赖的平台包」的 PR,合并前从不跑 ui 的单元测试;坏了要等下一个无关 PR 被踢出合并队列才暴露。今天三个 p0 都是这个形状:#28082、#28185、#28219。
背景与实测(origin/main
3739d8d6c6):Test UI (n/16)和Lint UI的if:(ci.yml:3733、:3976)只看ui输出。Type Check UI、Build & E2E UI、Build UI Deps同时看ui和ui_consumers(:3321等)。ui/scripts/select-affected-tests.mjs的outsideTreeReasons已经规定:ui 依赖的外部包(从依赖图推出,objectstack 上即ui_consumers那 7 个)一变,就判mode=full,跑全部测试。脚本的结论是对的,缺的只是 job 根本没启动。ui/、但碰这 7 个包的有 57 个,只碰那 5 个被 import 包的有 48 个。Governing text:分诊引维护者原话「平台测试清单反复变红,肯定要修啊」;「新增门禁默认否」不触发,因为分片已存在且是必查项,本卡只是让它在输入变化时启动。先例:#27283 裁 A(把 ui 根构建输入并入
core:过滤器),#27709(ci(filter),ci.yml+27/−4)。选项
Test UI分片(和Lint UI,若实测它读这些包)的if:加上|| ui_consumers != 'false',和其他 ui job 同形;改哪些测试、跑全量还是部分,仍由现有选测脚本决定ci.yml两行if:,加check-expected-skips的推导/自测;先例 #27709 量级业务含义:A = 谁改了上游零件,谁就在出厂前跑一遍下游的质检;B = 同上,但只对「已知会用到」的零件,名单靠人维护;C = 精确到只检测用到这个零件的那几道工序;D = 继续等巡检车发现。
四轴
os-decision-facets
① 长远:A 复用选测脚本的唯一依赖图答案,零新增特例;B 加第二份手写清单,C 留作后续优化
② 拉动:今日 3 个 p0(#28082 #28185 #28219),24h 内 57 个合并属此类,实测
③ 防错:A 让上游改动在自己的 PR 上响亮变红;B 的清单漂移与 D 都是静默放行
④ 不扩散:A 只改启动条件,不新增门禁或清单;B 和 C 扩大长期维护面
Prior rulings read: "ci.yml" "ui_consumers" "Test UI" → #27283 A, #27709, #28089, #25867 (closed); ADR none; thread: 6529894991
推荐:A
只看①选 A;②③④ 是否翻转:否(④反而加强 A)。
置信缺口:
Lint UI是否需要一起加,取决于 ui 的 eslint 是否读这些包,由 dev 实测,不读就不加。B 不取:多一份要人维护的清单。C 不取:现在做是过早优化,成本真成问题再单独立卡。D 不取:问题会继续发生。
裁后执行:选 A 后,席位认领并派 Opus dev:
packages/lint/**的 diff,跑过滤自测,读到 Test UI 被跳过。ci.yml两处if:,同步check-expected-skips的推导和自测、CI filter parity。选 B 或 C,按所选派发。
Generated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
director#2 · os-tesla · session_01L9qibxdiybU8ehPKBroYE3
Brief-claimed-by: session_01L9qibxdiybU8ehPKBroYE3 · batch #433 · 2026-10-31T15:18Z
Director seat (the maintainer's decisions thread, 2026-10-31). This card is presented to the maintainer in batch #433 (five cards: #27884, #27401, #27949, #28117, #28220 — the in-flight-blocked ones first) with the latest four-facet letter on this card as the seat's reading; the seat's increment and the maintainer's letter follow in the ruling comment.
objectstack-fleet commentedon Oct 31, 2026
director#2 · os-tesla · session_01L9qibxdiybU8ehPKBroYE3
Ruling: batch #433 item 5 · letter A · maintainer 「同意」 2026-10-31T15:50Z
Director seat (the maintainer's decisions thread). Presented in batch #433 (five in-flight-blocked cards, detailed letters in the project's decision doc; brief-claimed on this card at 15:16Z–15:18Z). The maintainer answered the whole batch at 2026-10-31T15:47Z, verbatim: 「同意」 = every item at the seat's recommendation.
What the ruling binds (letter A): the
Test UI (n/16)shards (andLint UI, if the dev measures that ui's eslint reads these packages) start when theui_consumersfilter matches, the same shape the other ui jobs already use — twoif:lines in the rootci.yml, with thecheck-expected-skipsderivation / self-test and the CI filter parity updated in the same PR. Which tests run stays the select-affected script's decision. The maintainer's standing "ci.yml edits need a ruling" constraint is satisfied by this record. Not taken: B (a hand-kept list of the five imported packages — a second drift source), C (import-precise selection — a later optimisation card if the cost bites), D (leave it).Workload of the letter:
domain:devx· 1 PR · precedent #27709 (ci.yml +27 −4) · Tier H (root workflow): contract review PASS at the named tier, then the maintainer's approval, then the seat lands · the PR body states the runner-minute cost against #25869 / #25881.Execution: the
domain:devxseat claims and dispatches as its letter 6529967823 lays out (reproduce the skip first);needs-user-decision→pm:queue/pm:dispatchedis that seat's stroke, withRuling-ref:naming this comment.objectstack-fleet commentedon Nov 1, 2026
domain:devx#1 · os-zhuang · session_01QUs3BvP5Aq9USg5GtmgAAR
Ruled →
pm:queue· 2026-11-01T02:08Z — taking the stroke the ruling names as the devx seat's (seat 2 has signed off and handed the lane to seat 1, brief 6540114700). ⛔ Not a claim; the claim follows once the card thread's branch is known.Ruling-ref: 6545651687
Test UI (n/16)(andLint UIonly if measured to read these packages) start whenui_consumersmatches;check-expected-skipsderivation / self-test and CI filter parity in the same PR; runner-minute cost stated against ci(ui-merge): twenty ui jobs each rebuild the same seven @objectstack packages (1.6–2.5 min apiece, mostly turbo cache misses on PRs) — build them once per run and hand the dists to the ui lanes (parent #25677) #25869 / ci(ui-merge): queue builds decide the four ui lanes from the merged diff against merge_group.base_sha #25881.ci.yml, governed): contract review PASS at the named tier, then the maintainer's approval, then the seat lands. The seat does not approve or merge it.ActionSchema.overrides, ui pin never run). Its stop-bleed is onmain; this card is the root fix.State change:
needs-user-decisionremoved,pm:queueadded in this stroke.objectstack-fleet commentedon Nov 1, 2026
domain:devx#1 · os-zhuang · session_01QUs3BvP5Aq9USg5GtmgAAR
Claim: PM loop round 3
Session:
session_01QUs3BvP5Aq9USg5GtmgAARAccount:
os-zhuangBranch:
claude/project-thread-cbuqpy(the card thread's platform-assigned push branch, the measured platform exception to the protocol branch shape)Worktree:
objectstack-issue-28220Domain:
domain:devxSeat:
domain:devx#1File surface:
.github/workflows/ci.yml(twoif:lines),scripts/pm/check-expected-skips.mjsand its self-test, the CI filter parity check and its fixtures (stop on breach; explain in the report)Container & model:
M,mode:thread,model: default (governed root workflow; judgment on Lint UI),effort: high (p1, Tier H)Clause-②: no
Metadata-protocol: none
Responsibility:
the Test UI shard start condition (ci.yml) | Test UI (n/16) on a ui_consumers-only diff | every PR and queue build; no product changeThread-read: 6552157492
Premise: holds (ruling 6545651687 letter A; p0 #28491 is the fourth recurrence on
main, triage 00:53Z: PR #28467's spec-only diff skippedTest UI)Serial constraints cleared: no in-flight devx card names ci.yml (#26993's PRs #27005 / #27329 are closed); none
Tier H: contract review PASS at the named tier, then the maintainer's approval, then the seat lands.
check-governed-merges.mjs --test .github/workflows/ci.yml→ governed.objectstack-fleet commentedon Nov 1, 2026
domain:devx#1 · os-zhuang · session_01QUs3BvP5Aq9USg5GtmgAAR
os-dev-report
{ "issue": 28220, "status": "done", "branch": "claude/project-thread-cbuqpy", "pr": "https://github.com/objectstack-ai/objectstack/pull/28501", "session": "session_01QUs3BsPpUdAGmm7wLdoKaK", "premise_still_valid": true, "summary": "Test UI (n/16) now starts on `ui || ui_consumers`, the shape ui-deps / type-check-ui / build-e2e-ui use; the selector already answers mode=full for any of the seven packages, so which tests run is unchanged. test-ui-gate (the required Test UI context) now explains a skip only when filter succeeded and ui_tree=false or ui=false AND ui_consumers=false, so an if: regression reds on the first ui_consumers-only diff. Lint UI not added: ui's eslint is not type-aware and its local rules read no file. check-expected-skips and check-ci-filter-parity needed no edit (the roster derives from the if: and the Test UI row moved to `filter ui_tree + filter ui|ui_consumers` by itself; parity has no ui subject). Final diff: .github/workflows/ci.yml alone (+36/-14).", "tests": "Reproduction on origin/main ea74ebf93: queue run 41091107812 (#28192, lint + metadata-protocol) has `Test UI (${{ matrix.shard }}/16)` skipped, Lint UI skipped, Type Check UI / Build & E2E UI / Live E2E UI success; a one-off picomatch 4.0.7 evaluation of the live filter block + each ui job's if: on packages/lint/src/index.ts gives ui=false ui_consumers=true, Test UI SKIPPED before and STARTS on this head (spec file same; ui/ file starts all both sides; scripts/ file starts none both sides). test-ui-gate run block executed for 6 input sets: skipped+ui_consumers=true now exit 1 (was 0), the other 5 unchanged. ui tests reading root ci.yml (select-affected-tests, select-affected-tests-wiring, turbo-cache-save-bound, check-action-forward-parity, lint-workflow): 5 files, 148 tests pass. check-expected-skips --self-test 206 cases pass. No ablation: workflow-only diff.", "gates": "node scripts/pm/dispatch-gates.mjs --commands at head 33b9f44f31 (1 path vs merge base ea74ebf93): 53 derived, 53 run, 53 exit 0 (each recorded `cmd :: exit N`, captured before any pipe); --ran: `53 derived, 53 run, 0 NOT-MEASURED, 0 UNRUN`. Full pnpm build under os-verify-lock first (VERDICT command-exit 0, 13m42s) for dts-closure / dual-build-cjs-loads / lean-entry-closure / sourcemap-no-sources-content; check:pm-dispatch-gates fast tier 1937 cases pass; check:type-check-debt exit 0. PR check-runs at report time on 33b9f44f31: 21 success, 12 skipped (expected roster: opt-ins, full-battery-only, PR-automation event skips), 25 in_progress, 0 failure — in_progress is the honest value. Contract review at CONTRACT_REVIEW_TIER by an isolated subagent: PASS, record on PR comment 6552512600 (Served-tier CONTRACT_REVIEW_TIER, Head-sha 33b9f44f31db4e1f915867a39e13875a555d0258).", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "1 — mcp__claude-code-remote__subscribe_pr_activity (PR #28501); no GitHub MCP tool called", "api_writes": "3 relay writes — fleet-write pr_create (run 41266210181, read-back identical, labels skip-changeset, no assignees); post-stamped comment on PR #28501 (contract-review record 6552512600, run 41266639701, read-back identical); this os-dev-report comment on #28220. Plus git push (not a REST write).", "open_questions": [], "out_of_scope_findings": [ "carrier: domain:devx seat · noted, not filed (not reproduced as a red; the ruling scoped Lint UI to eslint) — Lint UI's spec check:liveness step (ci.yml Lint UI) and its skill-example / doc-snippet / doc-example / readme-export type checks compile against @object-ui closures that include the @objectstack dists, so a ui_consumers-only diff can still red Lint UI first on a bystander ui PR · dedupe words: Lint UI ui_consumers skipped spec liveness doc-snippets", "carrier: domain:devx seat · noted, not filed (outside the ruling; no red measured) — the selector turns mode=full for every non-documentation workspace-root file and patches/** (select-affected-tests.mjs outsideTreeReasons), but several of the 21 tracked ones (.npmrc, eslint.config.mjs, vitest.preset.mts, paseo.json, .gitattributes) and patches/** are in no list the Test UI shards start on · dedupe words: ui filter patches npmrc Test UI skipped root file", "carrier: domain:devx seat · PR body correction owed (dev writes the body once): the contract review's should-fix — the per-merge runner-minute floor omits the push-to-main full battery, so it is ~564 runner-min (PR head + queue + push), not ~376, and the daily lower bound ~12,400 to ~17,500 runner-min" ] }Deviations: one, from the claim's file surface: a ui/scripts/tests pin (select-affected-tests.test.ts plus a helper in helpers/root-ci.ts) reconciling the ui_consumers list against the selector's package graph was committed in the first commit and reverted in the second, because it was the second reconciling check the ruling declined with option B; the net diff is ci.yml alone. The PR carries no assignees, per the dispatch contract.
objectstack-fleet commentedon Nov 1, 2026
domain:devx#1 · os-zhuang · session_01QUs3BvP5Aq9USg5GtmgAAR
Landed · 2026-11-01T04:06Z — PR #28501 merged by the maintainer as
23d1303d1f(Tier H, human merge).merged=true.github/workflows/ci.yml— blob sha1 identical to the reviewed head33b9f44f31test-uistarts onuiORui_consumers; the aggregate explains a skip only when both are'false'Carried forward, not filed (seat ACCEPT on PR #28501):
Lint UI's non-eslint steps read the seven packages; root non-doc files andpatches/**turn the selector full but start no shards.State change: card closed
completedbyFixes;pm:dispatchedremoved in this stroke.