Repository navigation
[Decision] Test UI is not a required context, so the merge queue lands a PR whose Test UI shard is red (#26419 → #26421): enrol a Test UI aggregate as required, keep it advisory with a seat read, or keep it as is #26460
Description
Ruled: 6435318516 · letter A (staged) · 2026-10-27T06:31Z
Filing gate ②: a maintainer-only decision. Enrolling a required context is a new gate (「新增门禁默认否」), and it revisits ruling 30 = B on #25752 (test shards read afterwards on main). Maintainer, 2026-10-27, verbatim: 「立决策卡」, on the triage seat's R697 report. Filed by the triage seat (session_01AavokzJ5DndAwitDXvKy4U, seat post #6015). ⛔ Not a claim.
维护者速读
合并队列只认 8 个必过检查。Test Core 有一个汇总任务(Test Core)是必过的,但 Test UI 的 16 个分片没有汇总,都不是必过。所以 Test UI 红了,队列照样合入。今天凌晨 #26419 就是这样:它的席位 03:24Z 发现会红,撤回草稿,但已经入队,03:20Z 先合了。现在 main 上 Test UI(8/16)是确定性的红,修复在 #26421。10-26 下午的 corpus guard 红(#26222/#26223/#26234)也是同一个口子。请裁:A 仿照 Test Core 加一个 Test UI 汇总任务,列入必过——新增门禁;B 不加必过,让席位放行前必须读队列构建里的 Test UI 结果,红了就不放行;C 维持现状,红了合入后再修。选 A / B / C?
Premises (measured 2026-10-27, on origin/main)
- P1.
scripts/check-required-contexts.mjsREQUIRED_CONTEXTSlists 8:Lint & Repo Gates,TypeScript Type Check,Test Core,Build Core,Governed Surface Queue Guard,Lint UI,Build & E2E UIandType Check UI.Test UIis absent. cutover(ui-merge): the switch itself — freeze both repos,git subtree addobjectui asui/with its adaptation commit, land 4a / PR B / 4b PR 2 in order, migrate open objectui branches and cards, archive the objectui repo (parent #25677, 5/6) #25752 step 6: "Test UIstays advisory under ruling 30 = B". - P2.
Test Coreis enrolled through a 1-minute aggregate job over its 8 shards.Test UIhas 16 shards, 7–12 min each on the 00:11Z schedule run, and no aggregate. - P3. ci: one setup-workspace composite action replaces the setup steps copied into 38 jobs, and pull requests stop saving the pnpm store #26419 (
d15f99d72f) merged at 03:20Z withTest UI(8/16) red in its queue build (40443632873). fix(plugin-detail): reveal the inline-edit pencil on keyboard focus #26325 and refactor(app-shell): move ObjectView's view tab strip, plugin schema and header chrome into sibling hooks (slice 9) #26412, stacked behind it, also merged (Queue-flake anchor: scripts/__tests__/doc-version-claims.test.ts #26422). Its seat's draft conversion at 03:24Z came too late. - P4. The same class on 2026-10-26: feat(spec,plugin-security,lint): sharing.controlledByParent.ownerMayEdit — a detail row's owner updates it with read on the master #26005 merged, and the app-shell corpus guards turned
Test UI6/16 and 12/16 red until PR test(app-shell): re-point the ObjectSchema corpus guards to 48 after sharing was adopted #26231 (4-hourly full run: red on main (CI) #26234). - P5. Unmeasured: Test UI's own flake rate. If it flakes, A turns each flake into an ejection. The dev measures the last N queue builds before enrolment.
Options
| Option | What | Consequence | Workload |
|---|---|---|---|
| A | A Test UI aggregate job (as Test Core has), enrolled in REQUIRED_CONTEXTS and in the ruleset. |
The queue refuses a red Test UI, and main stops taking ui test reds. A flaky shard ejects queue entries; the flake-anchor workflow already reports those. No extra runtime: the shards already run in the queue. | devx · 1 PR, Tier H (.github/workflows/**) · the maintainer flips the ruleset entry in the same sitting (precedent: Lint UI and Build & E2E UI, enrolled 2026-10-26T00:25Z) |
| B | No gate. At ACCEPT the seat reads the queue build's (or the PR head's) Test UI and does not land it on red. |
No CI change, but P3 is exactly the case where the seat read it and still could not stop a queued PR. It does not close the gap. | skills · 1 line in the review checklist |
| C | Keep it as is. | Each such red is fixed after it lands. Twice in two days so far. | none |
Recommendation
A, after the dev measures P5 on the last 50 queue builds. The shards already run in every queue build, so A adds no runtime, only the refusal. B relies on a seat act that P3 shows cannot stop a PR already in the queue. If P5 shows Test UI flaking above Test Core's rate, fix the flakes first ("a failing test is never an infra flake") and then enrol.
os-decision-facets
① 项目长远合理性:A 让 ui 测试和 core 测试同等对待(Test Core 早已必过),消除并仓后留下的不对称;不新增测试,只新增拒绝。
② 实际业务拉动:两天内两次 main 变红(#26234、#26421),一次已经影响发版前的全量检查。
③ 防 AI 犯错:A 是合并前响亮拒绝;B 靠席位记得读,而 P3 证明入队之后席位已经拦不住。
④ 创业阶段不扩散:A 是新门禁(默认否),但不多跑任何东西;如果分片不稳,先修不稳再列入。
Prior rulings read: required contexts · Test UI advisory · ruling 30 → #25752 ruling 30 (B, for the cutover sitting), step 6 enrolment of Lint UI and Build & E2E UI; 「新增门禁默认否」; 「平台测试清单反复变红,肯定要修啊」; ADR none; thread: #26422, #26421
After the ruling
A: domain:devx dispatches the aggregate job (Tier H), and the maintainer enrols the context in Settings → Rulesets in the same sitting as the merge (#9325's two-halves rule). B: domain:skills widens the ACCEPT check.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 27, 2026
Brief-claimed-by: session_01KrKXQVvgYk2AJ4VkqMobyb · batch #408 · 2026-10-27T04:44Z
Director seat, summon #51 continuation (ledger objectstack#12708). Presented to the maintainer in batch #408 as item 1 of 5 (five devx cards: two new gates asked, two governed slices awaiting a review spend, one CI wall-clock follow-up). Seat increment (re-read on
origin/main26e7c75e9a; the card is not restated):REQUIRED_CONTEXTShas 8 entries,Test UIabsent;Test Coreis enrolled through thetest-gateaggregate (ci.yml:1702–1706:name:andif: always()both load-bearing) — the shape A copies.Test UIalone (and merged, since nothing required it); of the 100 newest redmainruns (10-22 → 10-27), 27 carry a redTest UIshard — mostly repeats of the same deterministic red across consecutive pushes (two distinct causes carded in two days: 4-hourly full run: red on main (CI) #26234, ui/scripts:doc-version-claimsanchors the docs' Node version on literalnode-version:lines in .github/workflows, so #26419 (Node read from.nvmrc) turns it red #26421). FourQueue-flake anchorcards in two days name ui test files (Queue-flake anchor: packages/app-shell/src/services/MetadataService.specKeyObjectPayload.test.ts #26222, Queue-flake anchor: packages/app-shell/src/services/MetadataService.retiredObjectEnabled.test.ts #26223, Queue-flake anchor: src/controlled-by-parent-owner-may-edit.test.ts #26247, Queue-flake anchor: scripts/__tests__/doc-version-claims.test.ts #26422). So A would turn both the deterministic reds and the flakes into ejections; the flake share of the 27 is not separable from here.needs-user-decisionandpm:awaiting-maintainertogether; the second leaves in the ruling's stroke.Prior rulings read: required contexts · Test UI advisory → cutover(ui-merge): the switch itself — freeze both repos,
git subtree addobjectui asui/with its adaptation commit, land 4a / PR B / 4b PR 2 in order, migrate open objectui branches and cards, archive the objectui repo (parent #25677, 5/6) #25752 ruling 30 (B), step 6 enrolments; 「新增门禁默认否」; thread: Queue-flake anchor: scripts/__tests__/doc-version-claims.test.ts #26422, ui/scripts:doc-version-claimsanchors the docs' Node version on literalnode-version:lines in .github/workflows, so #26419 (Node read from.nvmrc) turns it red #26421.objectstack-fleet commentedon Oct 27, 2026
Ruling: batch #408 item 1 · letter A (staged) · maintainer 「批 #408 同意」 2026-10-27T06:24Z
Recorded by the director seat (summon #51 continuation,
session_01KrKXQVvgYk2AJ4VkqMobyb, ledger objectstack#12708). The maintainer answered batch #408 with 「批 #408 同意」 — every seat letter. Brief 6433960457. Letter A, staged as the card and the brief say, and the maintainer's yes is the explicit flip of 「新增门禁默认否」 for this one context: aTest UIaggregate job over the 16 shards (thetest-gateshape,ci.yml:1702–1706:name:literal andif: always()both load-bearing), enrolled inREQUIRED_CONTEXTSand in the ruleset by the maintainer in the same sitting as the merge (#9325's two halves; precedentLint UI/Build & E2E UIon 10-26). Order: first the ui lane measures the ui flake rate on the last 50 queue builds and fixes the flakes the four anchors name (#26222, #26223, #26247, #26422 — "a failing test is never an infra flake"); the aggregate lands after that reading is on this card. Not B (cannot stop a queued PR, P3) and not C.Seat measurement on the card: 27 of the 100 newest failed queue builds failed on
Test UIalone and merged; 27 of the 100 newest redmainruns carry aTest UIshard red. Workload: devx · 1 Tier H PR (.github/workflows/ci.yml, lands by the maintainer's approval) · XS, after the ui lane's flake fixes (S, their own cards or one PR).Execution:
needs-user-decision→pm:queuein this act (domain:devx, p1,area:devpath);pm:awaiting-maintainerremoved in the same stroke.Ruling-ref:names this comment.Clause-②: no,Metadata-protocol: none.2 remaining items
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26460, "status": "done", "branch": "claude/project-thread-2ddfc7", "pr": null, "session": "session_01ADHkmRBcYqig1yVS7FYsGL", "premise_still_valid": true, "summary": "ui step 1 of ruling 6435318516 (claim 6436277065). Measured Test UI over merge_group CI builds (Actions API, workflow 224644133, filter=all), classified every red shard from its check-run annotations, and posted the reading as comment 6436579765. Main reading, the newest 50 queue builds that ran Test UI (10-26 23:32Z to 10-27 07:10Z, 800 shards): 4 red, all (a) doc-version-claims from #26419, fixed by PR #26432 (6746140361). (b) = 0, (c) = 0, flake rate 0/50. The literal newest 50 builds of any kind: 18 ran Test UI, 0 red. Over a 24h extension (395 builds, 165 ran Test UI): 2 flake files, SettingsView.shellLeave-13231 (3 hits, seat 2, fixed by PR #26212 f42b55f2f3) and buildIdentity-12970 (1 hit, fixed by PR #26197 f143cd8809), plus 7 (a) corpus-guard builds (PR #26231 a1477dec8a) and one (c) group (#26056's own Build Core isNew redeclare, corrected before it merged). All four anchors are verified: the fix commits a1477dec8a, 733b3c849a and 6746140361 are ancestors of origin/main f48aa4510, and no named file has gone red in the queue since its fix. No flake is live, so step 2 had nothing to fix and no PR was opened. Seat 1 approved posting the reading before it went up.", "tests": "No code change and no tests run. The reading is API data: run lists from /actions/workflows/224644133/runs?event=merge_group (4 pages, 400 runs, 395 completed), jobs from /actions/runs/ID/jobs?filter=all, failure lines from /check-runs/ID/annotations. Job log downloads were refused by the container proxy (CONNECT 403), so annotations were the evidence. Ancestry: git merge-base --is-ancestor gave exit 0 for a1477dec8a, 733b3c849a, 6746140361, f42b55f2f3 and f143cd8809 against origin/main f48aa4510.", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack exited 2 with 'this branch changes nothing against origin/main (merge base f486e9c1b) — nothing to derive'. Empty diff, so there is no local gate subset and no PR check-runs.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (no PR)", "mcp_calls": "0 — no MCP GitHub calls; reads went through the container proxy's REST", "api_writes": "2 — post-stamped via relay: POST /repos/objectstack-ai/objectstack/issues/26460/comments for the reading (6436579765) and this os-dev-report. No git push, no pr_create.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: merge-group Test UI runs only the affected selection, so a flake in a file no queued diff selects is outside this reading. The scheduled full battery on main is the backstop. Stated as a caveat in 6436579765." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 11 · 2026-10-27T07:54Z
Session:
session_01Q4MDXRbEJCNdPAP4SiXwp9(devx seat 2) · card threadcmsg_01FdL1XeUyvVNxLreh3F4Qi9C2Dy8KN4fv23aea1JR1i9TAccount:
os-steveBranch:
claude/project-thread-nsgh5p(the harness-pinned branch of the card thread; it names no issue, so this claim is the identity record; amended on spawn)Worktree:
objectstack-issue-26460Domain:
domain:devxSeat:
domain:devx#2(seat post #20163)File surface:
.github/workflows/ci.yml, one new aggregate job named exactlyTest UIover the 16test-uishards, in thetest-gateshape (name:literal andif: always()both load-bearing, a needs-result check that reds on any non-success shard), placed next totest-ui;scripts/check-required-contexts.mjsoneREQUIRED_CONTEXTSrow (workflow: 'ci.yml',jobthe new job id,context: 'Test UI',authorizednaming ruling 6435318516) plus its self-test cases and any doc the registry derives. Any gate that countsci.ymljobs or required contexts and reds on the new one, only as far as the new row needs. ⛔ No otherci.ymljob; no shard, timeout or filter change. The ruleset entry is the maintainer's, in the same sitting as the merge. The PR is Tier H (.github/workflows/**): draft until a GOVERNED_APPROVERS approvalContainer & model: S,
mode:thread,model: default tier (TIER_DEFAULT, from dispatch-gates --tier: no path-derived mandate),effort: mediumClause-②: no
Metadata-protocol: none
Ruling-ref: 6435318516
Responsibility: n/a — maintainer-only decision card (「立决策卡」); ruled A (staged) at 6435318516; the ui step's reading (flake rate 0/50) is 6436579765
Thread-read: 6436579765
Premise: on
origin/main,REQUIRED_CONTEXTShas 8 rows and noTest UI;ci.ymljobtest-uiis namedTest UI (${{ matrix.shard }}/16)and has no aggregate (the dev re-reads both before editing)Serial constraints cleared: #25870 (this seat, claim 6436188889) also edits
ci.yml, but only the Test Core "Declarations skipped" / closure steps; this claim touches no Test Core line.ci.ymlis not a single-claim path. Whichever lands second mergesorigin/mainfirstGenerated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26460, "status": "done", "branch": "claude/project-thread-nsgh5p", "pr": "https://github.com/objectstack-ai/objectstack/pull/26569", "session": "session_01ADHkmNhqdySz5JeM3ARKGW", "premise_still_valid": true, "summary": "devx step of ruling 6435318516 (letter A, staged; claim 6436627175), after the ui step's flake reading 0/50 (6436579765). Premise re-read on origin/main f48aa4510: REQUIRED_CONTEXTS had 8 rows and no Test UI; test-ui is a 16-leg matrix named 'Test UI (${{ matrix.shard }}/16)' with no aggregate. Added ci.yml job test-ui-gate, name: Test UI, needs [test-ui, filter], if: always(), roster declaration (members test-ui, non-member filter), one step: rollup success passes, skipped passes only when filter succeeded and ui_tree or ui is 'false' (#4928), everything else red. Registered the context in REQUIRED_CONTEXTS and the REQUIRED_AGGREGATORS floor, with self-test cases in both; the two statesTheSet surfaces (AGENTS.md merge-queue rule, pm-dispatch platform-readings.md) go eight to nine, as #25857/#25878 did. Draft PR #26569, Tier H: waits on a GOVERNED_APPROVERS approval (os-zhuang, hotlong); the ruleset entry is the maintainer's in the same sitting as the merge.", "tests": "head 853ddedb4: node scripts/check-required-contexts.mjs exit 0 (9 pinned, ci.yml:test-ui-gate -> 'Test UI'); --self-test exit 0, 179 assertions (new: rename of the bare Test UI name red; Test UI shard-name collision red + coexistence control). node scripts/check-aggregator-roster.mjs exit 0 (5 aggregators, all 5 required declared); --self-test exit 0, 63 assertions (new: dropped-member and phantom-needs controls for test-ui-gate). pnpm --dir ui exec vitest run scripts/__tests__ under os-verify-lock: VERDICT command-exit 0, Test Files 178 passed | 2 skipped (180), Tests 5097 passed (the ui pins that read ci.yml as text). No ablation: the diff changes a workflow, gate scripts and prose, not tested runtime behaviour.", "gates": "head 853ddedb4: dispatch-gates --commands derived 80 families; all run, each exit captured before any pipe; --ran reconciliation exit 0: 80 derived, 80 run, 0 NOT-MEASURED (derived zero). Five first exited 3 (PREREQUISITE NOT MET, no built dist): check:doc-formula-expressions, check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content; re-run exit 0 after turbo run build --filter='./packages/**' (lock VERDICT command-exit 0). check:pm-dispatch-gates exit 0 (1935 fast-tier cases). PR check-runs: in_progress at report time.", "line_budget": "+119 / -14 across 5 files (133 changed lines, under the 3000 human-merge threshold)", "files_changed": [".github/workflows/ci.yml", "scripts/check-required-contexts.mjs", "scripts/check-aggregator-roster.mjs", "AGENTS.md", ".claude/skills/pm-dispatch/references/platform-readings.md"], "deviations": [ "AGENTS.md and .claude/skills/pm-dispatch/references/platform-readings.md are governed surfaces the increment does not name. They were edited (one list line each, eight to nine) because check:required-contexts reds otherwise: both are statesTheSet surfaces whose mustName must equal the registry exactly. Read as the claim's 'any doc the registry derives' / 'only as far as the new row needs', following #25857 and #25878, which edited the same two lines in the registry PR. The PR is Tier H either way.", "scripts/check-aggregator-roster.mjs is not named in the claim's file surface: REQUIRED_AGGREGATORS gained the test-ui-gate row because its header keeps it in step with REQUIRED_CONTEXTS (the required names that aggregate), so the new aggregate cannot silently lose its roster declaration.", "The PR was not subscribed for activity: the dispatch contract owns CI convergence; patch rounds come through the seat." ], "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "4 — issue_read x3 (get, get_comments x2), pull_request_read x1 (get, PR read-back); no MCP write", "api_writes": "3 — git push of claude/project-thread-nsgh5p; relay pr_create (PR #26569, draft, assignee os-steve, label skip-changeset); this os-dev-report comment via post-stamped", "open_questions": [], "out_of_scope_findings": [ "carrier: ui lane (seat 1) · noted, not filed: ui/scripts/check-test-shard-results.mjs (objectui's per-shard `Test` aggregate reader, row 7 of #25697, 'dropped until cutover') hardcodes `Test (shard N/M)`, so it cannot read `Test UI (k/16)`. If the ui lane wants per-shard conclusions instead of the rollup word, its port re-derives the spelling from the root job and test-ui-gate's step can call it.", "carrier: none · noted, not filed: 'cancelled' reads red, so a superseded PR push paints the old sha's Test UI red; no required check reads an old sha." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Release:
session_01Q4MDXRbEJCNdPAP4SiXwp9(devx seat 2) · seat signs off on the maintainer's word 「devx 车道当前任务处理完就下班」 (2026-10-27 08:42Z) · next: a GOVERNED_APPROVERS approval of PR #26569, then merge, then the maintainer addsTest UIto themainruleset in the same sittingPR #26569 (head
853ddedb) carries a Contract review PASS (6437562805) and the seat ACCEPT (6437580781); CI was green except two jobs still running at review time. It is Tier H (.github/workflows/ci.yml,AGENTS.md) and stays a draft. ⛔ Merge first, ruleset second: listingTest UIin the ruleset before the job exists onmainleaves every PR and queue entry pending (the #3622 deadlock). The card closes onFixeswhen it merges.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
devx seat 2 · half-state corrected · 2026-10-27T23:03Z
This card is closed but still carried
pm:awaiting-maintainer. Closing stripspm:*status labels in the same stroke, so the label is removed now. Nothing else changed.Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Triage: the ruleset half is done —
Test UIis a required context onmain· 2026-10-28T07:20Z⛔ Not a claim.
GET /repos/objectstack-ai/objectstack/rules/branches/main, at 2026-10-28T07:20Z):TypeScript Type Check | Test Core | Build Core | Lint & Repo Gates | Governed Surface Queue Guard | Lint UI | Build & E2E UI | Type Check UI | Test UI. That is nine contexts, and it now equalsREQUIRED_CONTEXTSinscripts/check-required-contexts.mjs(PR ci(test-ui): add theTest UIaggregate job and register it as a required context #26569, merged 2026-10-27T10:04Z). The maintainer added it on 2026-10-28.Test UIas advisory. fix(app-shell): list a package's draft objects in the Access matrix, badged as drafts #27064 landed at 05:33Z although its only queue build (40637014766, the same sha) was red onTest UI (3/16), and main went red (Queue-flake anchor: packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.objectGrantInherited-27010.test.tsx #27097 / Queue-flake anchor: packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.packageDoorDraftBase-26837.test.tsx #27104). Queue-flake anchor: packages/app-shell/src/views/__tests__/AppReportIndex.navGates-26892.test.tsx #27116's non-deterministic test also reached main this way.Test UIejects the PR from the queue instead of landing it. Measured on six green queue builds, there is no new compute (the queue already ranTest UI, and it skips in under 1 min on non-ui groups), and it adds up to about 3 min of wait whenTest UIis the slowest job. The new cost is ejections from flaky UI tests, so those stay p0 (Queue-flake anchor: packages/app-shell/src/views/__tests__/AppReportIndex.navGates-26892.test.tsx #27116 is in flight).Generated by Claude Code