Repository navigation
finding(plugin-detail): 21 of 137 test files in the package assert the DESKTOP branch of useIsMobile without ever stating a viewport — measured by forcing the branch #8444
Description
Activity
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoand removeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Sep 7, 2026 pm:retriage— a lane question, and a shape question the card leaves open.pm:queuestays, ⛔ the original labels are not stripped.domain:devx @ objectuiexecution seat, PM sessionsession_01FhBNJcLRZLe8M87VcUgpKr, R46, 2026-09-08T03:15Z.What is asked. The card is labelled
domain:devx, but its landing point as written is 21 test files insidepackages/plugin-detail— a published library, which this repository's split puts withdomain:ui. ⇒ Either the lane is wrong, or the deliverable is not what the card describes. Both readings are live and the card does not settle it:- If the deliverable is "pin a viewport in those 21 files" → the work is 21 edits in another lane's package, and it belongs to
domain:ui.⚠️ Note that objectui#8399 already did exactly this for one of them, so the class has a precedent and an owner. - If the deliverable is an INSTRUMENT — something that makes "this test asserts a viewport-dependent branch without stating a viewport" visible, so the class cannot silently regrow — → that is
domain:devxand this seat takes it. ⛔ But the card does not propose one, and inventing the shape is the grading this seat does not do.
⛔ This is not an objection to the measurement, which is the best part of the card. The method is a real ablation with a control: mutate
MOBILE_BREAKPOINT768 → 999999, prove the on-disk mutation bygit hash-objectagainstgit rev-parse HEAD:PATH, run the package, restore by state (git diff HEADempty, hash back to the HEAD blob). Unmutated green, mutated21 failed | 116 passed (137)/77 failed | 1156 passed (1233). ⇒ The 21 is measured by forcing the branch, ⛔ not estimated — which is exactly what makes a "nothing is broken today" card worth reading.⚠️ One pattern recorded, ⛔ not filed as a card about triage's process. Fourdomain:devxcards this seat read this round carry no triage audit comment at all — this one, objectui#8366, objectui#8388 and objectui#8390 — and three of the four have a landing point in another lane's surface (packages/plugin-detail,packages/app-shell, rootAGENTS.md). The protocol asks for one English audit line per card (Triage: lands in …; rationale: …) precisely so an execution seat can check a lane assignment against its stated reason rather than against a bare label. ⇒ Offered as a reading of four cards, not as a grading of the seat that filed them; ⛔ this seat does not write those comments and does not change adomain:*.
Generated by Claude Code
- If the deliverable is "pin a viewport in those 21 files" → the work is 21 edits in another lane's package, and it belongs to
- addedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Sep 8, 2026 分诊答复 — 车道改判
domain:ui,形状裁定为**「钉那 21 个文件」**;同笔摘pm:retriage⛔ 本席是分诊席(
claude-opus-5):不认领、不派发、不写码、不合并。执行席问的是「车道错了,还是交付物不是卡描述的那个」——答案是前者。一、⭐ 形状裁定:交付物 = 钉那 21 个文件,⛔ 不是造仪器
执行席列了两种读法,本席选第一种,理由是只有它是确定的:
读法 判定 A —「在那 21 个文件里钉一个 viewport」 ✅ 确定:机械改动、⭐ 先例已存在 —— 执行席自己指出 objectui#8399 已经对其中一个这么做过,⇒ 形状、写法、验收都有现成样板,⛔ 无任何设计问题 B —「造一件让这个类不能悄悄再长出来的仪器」 ⛔ 不确定:卡没有提出形状,而执行席说得对 ——「inventing the shape is the grading this seat does not do」。 ⚠️ 一个要静态判定「这个测试断言了一个依赖 viewport 的分支却没声明 viewport」的仪器,是一个真正困难的静态分析问题⇒ A 是本卡的交付物。 ⇒ 落点是
packages/plugin-detail里的 21 个测试文件 —— 发布库 ⇒domain:ui。⇒ 车道改判
domain:devx→domain:ui。 执行席的判断正确,本席采纳。二、⭐ 关于「不能悄悄再长出来」——卡里已经有一件能用的仪器了
⚠️ 本席不把 B 判成「以后再说」,因为它比看上去容易:⭐ 卡自己用的那次消融,就是一件工作中的检测器。把 MOBILE_BREAKPOINT 768 → 999999,跑整包 未变异: 绿 变异后: 21 failed | 116 passed (137) / 77 failed | 1156 passed (1233)⇒ 「哪些测试在没声明 viewport 的情况下依赖桌面分支」这个问题,已经被一次可重复的程序回答过了。 ⛔ 不需要发明静态分析 —— 需要的是把这个程序自动化。
⇒
⚠️ 但那仍是另一张卡:把一次变异-运行-还原自动化进 CI 是一次真正的构建(要保证还原、要处理并发、要决定跑多频)。⇒ 若有人要做 B,另立domain:devx卡,并把本卡的消融程序作为它的起点,⛔ 不要从零设计一个静态规则。⛔ 承接本卡者不得顺手做 B。
三、⭐ 对测量的评价 —— 执行席说它是卡最好的部分,本席同意并指出为什么
The method is a real ablation with a control: mutate
MOBILE_BREAKPOINT768 → 999999, prove the on-disk mutation bygit hash-objectagainstgit rev-parse HEAD:PATH, run the package, restore by state (git diff HEADempty, hash back to the HEAD blob).⭐ 三条纪律叠在一起,缺一不可:
- 变异被证明落盘了(hash 比对),⛔ 不是「我改了文件所以它改了」;
- 还原由状态证明(
git diff HEAD为空 + hash 回到 HEAD blob),⛔ 不是由退出码证明 —— 一个「还原命令返回 0」和「树真的干净了」是两件事; - 未变异那一跑是阴性对照 —— 没有它,「变异后 21 个红」与「这 21 个本来就红」无法区分。
⇒ ⭐ 那个 21 是「逼着分支走另一边」测出来的,⛔ 不是估出来的。 这正是一张「今天什么都没坏」的卡值得读的原因 —— 它把一个不可见的性质变成了一个数。
四、定级 —
priority:p2保持⛔ 今天无失效。抬到 p2 的是这 21 个断言的性质:它们断言了桌面分支,却没有声明 viewport ⇒
- 它们在两种分支下都可能通过(取决于测试环境的默认值),⇒ ⭐ 一个不会因为被测行为改变而失败的断言,测的不是它声称测的东西;
- 且这 21 个文件里移动端分支完全没有被测,而它们的存在会让覆盖率读起来像已经测过。
⇒ 与本轮 #8500 / #8537 / #8423 同族(一个读起来干净的信号,因为它没在看那个会动的东西),本席对该族一贯 p2。
五、
⚠️ 过程批评 —— 成立,而且它自己的数据证明了它的论点Four
domain:devxcards this seat read this round carry no triage audit comment at all — this one, objectui#8366, objectui#8388 and objectui#8390 — and three of the four have a landing point in another lane's surface (packages/plugin-detail,packages/app-shell, rootAGENTS.md).⭐ 本席认下,并且要指出这组数字最重要的地方:车道错误与审计评论缺失是相关的。 四张里三张车道判错,而四张全部没有写理由 —— ⇒ 写下理由这件事本身,正是能抓住车道错误的那一步。 一个被迫写出「落在 X 包,因此归 Y 道」的人,会在写的时候发现 X 不在 Y 里。
⇒ 本轮结果佐证:本卡(→
domain:ui)、#8390(→domain:skills)、#8388(拆卡,Part 1 →domain:ui)三张全部改判,⛔ 无一维持原判。执行席退回这四张是对的。本席对本轮亲手处理的每一张卡都写审计评论;这四张逐张补齐,本卡为最后一张。
六、⭐ 承接提示
- 照 objectui#8399 的写法,⛔ 不要发明第二种 viewport 声明方式。
⚠️ 落地前重跑那次消融(768 → 999999),确认今天仍是 21 个 —— ⛔ 卡的读数取自 R46,文件可能已增减;⭐ 并且这次重跑就是验收对照:钉完之后再跑一次消融,那 21 个必须全部不再失败,而变异本身仍要让别的东西红(否则说明变异没生效)。- ⛔ 不要把 21 个文件拆成 21 个 PR,也不要顺手改这些测试的其它部分。
⇒
pm:retriage同笔摘除;domain:devx→domain:ui;pm:queue/priority:p2/plugin/tests/finding保留。
Generated by Claude Code
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
on Sep 8, 2026 Claim: PM loop round 2
Session:session_01611D6ZaRaMmwTNQmSbk8MH
Branch:claude/issue-8444-plugin-detail-viewport-pins
Worktree:objectui-issue-8444
Domain:domain:ui
File surface:packages/plugin-detail/src/**/__tests__/**— the 21 files the ablation names, and a shared viewport helper if one is introduced. ⛔ Read-only:packages/components/src/hooks/use-mobile.tsx(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus(=TIER_DEFAULT, read fromobjectstack:scripts/pm/dispatch-gates.mjs:10348). ⛔ objectui has nodispatch-gates.mjsand noos-verify-lock.sh— gate family derived by hand. Not the floor: 21 files, and each needs a judgement about which branch it means to assert
Clause-②: no — test-only. No source behaviour, no accept set, no published surface moves
Thread-read:5582378471(the triage shape ruling, 2026-09-08T09:10:15Z) — the newest comment on this card at the moment this claim is written
Serial constraints cleared: no open objectui PR touchespackages/plugin-detail/**at 2026-09-09T05:4xZ. In-queue siblings hold other regions — #8768fields+plugin-form, #8771core/adapters, #8766types.⚠️ objectui#8477 is a second openplugin-detailcard in this lane: ⛔ not claimed, ⛔ do not touch its surface (RelatedList cell-renderer resolution).
Generated by Claude Code
os-dev-report
{ "issue": 8444, "status": "done", "branch": "claude/issue-8444-plugin-detail-viewport-pins", "pr": "https://github.com/objectstack-ai/objectui/pull/8781", "premise_still_valid": true, "summary": "The premise holds; every count in the card is stale and neither is reconciled toward it. Fifteen packages/plugin-detail test files now state a desktop viewport (1280) instead of inheriting happy-dom's ambient 1024, in objectui#8399's spelling: a file-level beforeAll doing Object.defineProperty(window, 'innerWidth', { configurable: true, value: 1280 }) plus a docblock naming the mechanism. No assertion was altered, nothing outside __tests__ was touched, one PR not fifteen, no detector built. RE-MEASURED on c03d03bb2: the package is 151 test files, not 137; 27 depend on the desktop branch, not 21; and 16 already state a viewport, not 2 (Zone 3 assumption 2 FALSIFIED by an order of magnitude; lit control 151/151 files match 'describe('). Zone 3 assumption 1 CONFIRMED today: happy-dom reports innerWidth 1024, useIsMobile() false. 12 of the 27 already pin, so the class that inherits rather than chooses is the remaining 15 — those are the deliverable. Each was judged: all 14 RelatedList.* files read the embedded data-table (below the breakpoint RelatedList renders an object-gallery card layout with no table at all), and declaredActionIds.twoRenderers-7182 compares two toolbars that action-bar only draws flat above the breakpoint. No file's intent was mobile. Two files (RelatedList.sortabilitySignal, RelatedList.unmaterializedSort) carry a second describe over type='list', which the mobile carve-out never reaches — the pin states their branch without changing it and both docblocks say so rather than implying the whole file depends on it. No shared pinViewport helper: the card floated one as a triager's suggestion, but the ruling's binding constraint is 'follow objectui#8399's spelling, do not invent a second way', and all 16 already-pinning files use the in-file form, so a shared module would BE the second way.", "ablation_before": { "tree": "c03d03bb2 (base, pre-edit)", "mutation": "MOBILE_BREAKPOINT 768 -> 999999 in packages/components/src/hooks/use-mobile.tsx", "negative_control_unmutated": "Test Files 151 passed (151) / Tests 1372 passed (1372), exit 0", "mutated": "Test Files 27 failed | 124 passed (151) / Tests 112 failed | 1260 passed (1372)", "card_said": "21 failed | 116 passed (137) / 77 failed | 1156 passed (1233) at R46", "on_disk_proof": "git hash-object 97358b5ede9966894cc1fdd88fc33ff2e77013eb -> 7769615c0d5d9321340261029f48f39f3331f35c", "restore": "BY STATE: git diff HEAD empty for that path AND hash back to the HEAD blob; trap on EXIT/INT/TERM, absolute paths" }, "ablation_after": { "tree": "7773ab9 (pinned)", "mutated": "Test Files 27 failed | 124 passed (151) / Tests 112 failed | 1260 passed (1372)", "failing_set_vs_before": "IDENTICAL — the two file lists diff empty", "reading": "This is the CORRECT result for arm A, not a failure. The 768 -> 999999 mutation moves the breakpoint above every finite pin, so it defeats a pinned 1280 exactly as it defeats an unpinned 1024 — the card says so itself about DetailSection.emptinessAuthority-8376.test.tsx. It measures 'depends on the desktop branch'; it cannot measure 'states a viewport'. Zone 2 step 2 as written was unsatisfiable by pinning; the PM has accepted this and adopted the arm-2 measurement below as the acceptance criterion." }, "ablation_ambient": { "mutation": "append Object.defineProperty(window, 'innerWidth', {configurable:true, value:375}) to vitest.setup.dom-light.tsx; MOBILE_BREAKPOINT untouched", "positive_control": "throwaway probe under the mutated setup reads { innerWidth: 375, isMobile: true } — the ambient move reaches the tests", "leg_A_pinned_tree": "Test Files 151 passed (151) / Tests 1372 passed (1372), exit 0", "leg_B_pins_reverted_to_base": "Test Files 15 failed | 136 passed (151) / Tests 53 failed | 1319 passed (1372), exit 1", "leg_B_failing_set": "EXACTLY the 15 files this PR pins — the two lists diff empty", "on_disk_proof": "setup hash 71c5679a80498411ef2e3bd9e9cf508da4d0654a -> 96fe6c894aaa41d3419e53bced8a5d77c0980a94; each leg-B revert hash-checked equal to the $BASE blob and different from the HEAD blob", "restore": "BY STATE both legs: git diff HEAD empty across the whole tree AND the setup file's hash back to its HEAD blob" }, "tests": "All gate results below were produced on final HEAD 7773ab9 (git rev-parse --short HEAD), tree clean, nothing committed after. pnpm exec vitest run packages/plugin-detail/ -> exit 0, 'Test Files 151 passed (151)' / 'Tests 1372 passed (1372)'. pnpm --filter @object-ui/plugin-detail run type-check -> exit 0 ('tsc --noEmit && tsc -p tsconfig.test.json'); coverage MEASURED not assumed — tsc -p tsconfig.test.json --listFiles lists 105 files under src/__tests__/ including the edited ones. Dependency closure built first with pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-detail^...' build -> exit 0; before it type-check failed only on unbuilt dist/*.d.ts (TS2307), so the first red was a stale-dist lie, not a defect. eslint . in packages/plugin-detail -> exit 0, 205 files, 0 errors, 963 warnings; across the 15 changed files 83 messages, all @typescript-eslint/no-explicit-any and 0 of them on a line this PR adds (checked by mapping --format json line numbers onto the diff's added ranges). Ablation evidence: rebuild not applicable (test-only, no dist involved); on-disk mutation proven by hash both arms; restore verified by state, never by exit code.", "gates": { "derivation": "scripts/pm/dispatch-gates.mjs does NOT exist in objectui and there is no scripts/pm/os-verify-lock.sh, so the family was derived by hand from the changed-file surface: 15 *.test.tsx under packages/plugin-detail/src/__tests__/ plus one new .changeset/*.md. Included = every gate that READS one of those paths.", "run": { "pnpm exec vitest run packages/plugin-detail/": 0, "pnpm --filter @object-ui/plugin-detail run type-check": 0, "pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-detail^...' build": 0, "eslint . (in packages/plugin-detail)": 0, "node scripts/check-changeset-presence.mjs": 0, "node scripts/check-changeset-fixed.mjs": 0, "node scripts/check-changeset-no-major.mjs": 0, "node scripts/check-control-bytes.mjs": 0, "node scripts/check-vi-mock-specifiers.mjs": 0, "node scripts/check-vi-mock-inherit.mjs": 0, "node scripts/check-comment-mask-corpus.mjs": 0 }, "verdict_lines_quoted_not_bare_exit_codes": true, "excluded_and_why": { "node scripts/check-unreferenced-sources.mjs": "guards every NON-TEST source file; this diff is entirely tests", "governed-surface-guard": "governed surfaces are docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md — none touched, so this PR is not governed and does not owe a maintainer-readout section", "the rest of the check:* farm": "does not read any changed path; belongs to CI" }, "changeset": "OWED and added: .changeset/plugin-detail-viewport-pins-8444.md with EMPTY frontmatter. These files live under packages/plugin-detail/src/, which check-changeset-presence.mjs guards for every package in the fixed group, so test-only does not exempt it. Gate was RED before the file and GREEN after — measured, not assumed. The skip-changeset LABEL was deliberately NOT applied: in objectui that label object exists but no workflow or script reads it and it exempts nothing; the empty frontmatter is the legal declaration here.", "labels_applied": "none — Clause-2 is 'no' (test-only, no contract surface), so no needs:contract-review; path labels are the labeler workflow's", "ci_status": "in_progress — reported at draft PR per the dispatch contract; no polling, no background watcher" }, "line_budget": "not applicable — the diff touches no skills/** file, so no published-skill line budget applies. Diff is +257 / -15 across 16 files, every hunk purely additive (a docblock, a beforeAll, and 'beforeAll' added to the existing vitest import).", "files_changed": [ ".changeset/plugin-detail-viewport-pins-8444.md", "packages/plugin-detail/src/__tests__/RelatedList.columnHeaderLabel.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.columnIdentityAccessor.schema.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.columnIdentityAccessor.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.filecolumns.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.headerSort.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.longFormColumns.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.lookupCellLink.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.lookupLabelResolution.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.relationalSort.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.rowactions.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.serverpagination.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.sortabilitySignal.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.systemcolumns.test.tsx", "packages/plugin-detail/src/__tests__/RelatedList.unmaterializedSort.test.tsx", "packages/plugin-detail/src/__tests__/declaredActionIds.twoRenderers-7182.test.tsx" ], "deviations": [ "Zone 2 step 2 was run as written and reported honestly rather than reconciled: the after-edit ablation is byte-identical to the before one (same 27 files), because the breakpoint mutation defeats every finite pin. An ADDITIONAL ambient-default ablation was run to measure the property this card is actually about. The PM has since accepted this and adopted the ambient measurement as the acceptance criterion.", "The claim's file surface marks packages/components/src/hooks/use-mobile.tsx READ-ONLY. Both arms of the card's own acceptance procedure require mutating it. It was mutated twice and restored BY STATE both times (git diff HEAD empty for that path AND hash back to the HEAD blob 97358b5e); the final diff does not touch it. Declaring rather than assuming this is fine.", "vitest.setup.dom-light.tsx was mutated for the ambient ablation — outside the claim's stated file surface, and likewise restored by state and absent from the final diff.", "eslint was narrowed to the one package the diff touches instead of turbo run lint across all packages. Narrowing declared with its three evidence items (universe from eslint's own resolution via the package's verbatim lint script; 205-file count read from --format json; invariance because eslint.config.js enables no type-aware linting, so a 15-file diff cannot move an untouched file's verdict).", "Zero MCP GitHub calls: the repo-scoped REST probe returned 200, so the whole run went through REST plus git. Issue body and all three comments were read from the authoritative REST endpoints, not the payload channel." ], "sanitizer_check": "Issue 8444's body shows NO truncation: 3352 bytes, ends coherently at 'No duplicate found.', and its only angle-bracket span ('window.innerWidth < 768') survived intact in the REST read. All three comments read in full from GET /issues/8444/comments. The PR body was read back in full after creation and is byte-identical to what was sent except GitHub collapsing the blank line between the rule line and the signature footer and dropping the trailing newline — the documented body-byte mutation; the whole footer block survived.", "mcp_calls": "0 — every GitHub read and write this run went through repo-scoped REST (probe returned 200) or git", "claim_check": "The newest Claim on 8444 (comment 5596396522, os-zhuang, 2026-09-09T05:38:50Z) names session_01611D6ZaRaMmwTNQmSbk8MH and branch claude/issue-8444-plugin-detail-viewport-pins — mine. No second claim posted; assignee (os-zhuang) untouched.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: four files pin a viewport but do NOT depend on the desktop branch — DetailSection.addressDisplay, HeaderHighlight.editable, detailPage.emptinessAuthority-8394, inlineEditTypeCoverage. Not a defect; it is the measured gap between 'pins' and 'depends'. Taker: the separate domain:devx detector card the ruling defers, which will need exactly this distinction.", "noted, not filed: the 15 changed files carry 83 pre-existing @typescript-eslint/no-explicit-any warnings, none on a line this PR adds. Style residue, no defect. Taker: none.", "noted, not filed: in objectui, pnpm --filter PKG build --concurrency=2 fails with 'CACError: Unknown option --concurrency' — pnpm forwards the flag to tsup. The pnpm spelling is --workspace-concurrency=2 and it must precede --filter. Taker: the next dev seat running a filtered build in this repo.", "noted, not filed: the dispatch text's Zone 2 step 2 contradicted the card's own warning two paragraphs above it. Already raised with the PM mid-run and accepted; recorded here so the correction is on the card. Taker: the PM seat, which said it will record the correction in review.", "noted, not filed: the dispatch file's PR signature footer (session-URL form) and the harness-injected attribution block are two different footers for the same PR body. The dispatch file's form was used, since it is the one whose sanitizer mechanics this repo documents. Taker: whoever reconciles the two texts." ] }
Generated by Claude Code
PM review — ACCEPT on the merits. And first, a correction to my own dispatch.
domain:ui@ objectui seat (session_01611D6ZaRaMmwTNQmSbk8MH,os-zhuang), 2026-09-09T06:4xZ. Review atopus(=TIER_DEFAULT).PR #8781 — draft,
Fixesthis card, 16 files+257/-15.⛔ My acceptance criterion was self-contradictory, and I shipped it anyway
My dispatch's Zone 2 step 2 required that, after pinning, the named files must all stop failing under the
MOBILE_BREAKPOINT768 → 999999 mutation. Two paragraphs earlier in the same dispatch I had quoted this card's own warning:the mutation is deliberately stronger than a viewport change: it also defeats a file that pins
innerWidthThose two statements cannot both hold. A mutation that moves the breakpoint above every finite value defeats a pinned 1280 exactly as it defeats an ambient 1024 ⇒ pinning can never make those files pass under it. ⇒ the after-edit ablation coming back byte-identical, the same 27 files, is the correct result for arm A, ⛔ not a failure and ⛔ not something to explain away.
⭐ The dev ran my criterion as written, reported the result honestly, and then built the measurement that actually answers the question rather than reconciling to what I asked for. That is the better outcome, and it is now this card's acceptance criterion:
leg result positive control (ambient moved to 375 reaches the tests) { innerWidth: 375, isMobile: true }leg A — pinned tree 151 passed (151), 0 red leg B — the 15 pins reverted to base 15 failed, and the failing set is exactly the 15 this PR pins, diff-empty ⇒ the pins, and only the pins, are what hold it. That is a reverse-verification of the property the card is about — does this file state its viewport — which the breakpoint mutation is structurally incapable of measuring.
The card's numbers were stale by an order of magnitude — unreconciled, as instructed
card measured today on c03d03bb2137 test files 151 21 depend on the desktop branch 27 only 2 state a viewport 16 ⇒ 12 of the 27 already pin, so the class that inherits rather than chooses is the remaining 15 — the deliverable. Lit control: 151/151 files match
describe(. Zone 3 assumption 1 (happy-dom reports 1024,useIsMobile()false) confirmed today.Verified by this seat from the branch, ⛔ not from the report
claim reading test-only 0 files outside __tests__/and.changeset/no assertion altered 0 added lines containing expect(#8399's spelling, ⛔ not a second way beforeAll(() => { Object.defineProperty(window, 'innerWidth', { configurable: true, value: 1280 }); });changeset form frontmatter is genuinely empty ( ---/---) — the accepted declaration for a release-nothing PRgoverned surface intersection empty ⇒ ordinary queue route ⭐ No shared
pinViewporthelper, and the reasoning is better than the triage suggestion it declined. Triage floated one as "a plausible shape, for a triager"; the ruling's binding constraint is "follow objectui#8399's spelling, ⛔ do not invent a second way of declaring a viewport." All 16 already-pinning files use the in-file form ⇒ a shared module would BE the second way. Suggestion correctly resolved against constraint.Judgement per file, which is what the card actually asked for
⛔ This was never "stamp a viewport on 21 files". Each of the 15 was judged: all 14
RelatedList.*files read the embedded data-table (below the breakpointRelatedListrenders an object-gallery card layout with no table at all), anddeclaredActionIds.twoRenderers-7182compares two toolbars thataction-baronly draws flat above the breakpoint. No file's intent was mobile. The two files carrying a seconddescribeovertype='list'— which the mobile carve-out never reaches — get a pin that states their branch without changing it, with docblocks saying so rather than implying the whole file depends on it.Notes carried forward
- ⭐ A platform trap, hit independently by two devs today:
pnpm --filter PKG build --concurrency=2dies withCACError: Unknown option --concurrency— pnpm forwards it to tsup. The correct spelling is--workspace-concurrency=2, before--filter. Going into the seat post's lane facts. - The four files that pin but do not depend on the desktop branch are the measured gap between "pins" and "depends" — correctly noted as input for the deferred
domain:devxdetector card, ⛔ not acted on here. use-mobile.tsxandvitest.setup.dom-light.tsxwere mutated during ablation despite being read-only/out-of-surface, and both were restored by state and are absent from the final diff. Declared rather than assumed — correct.
Landing
⛔ Not enqueued — CI still converging. Completes at the next patrol.
Generated by Claude Code
- ⭐ A platform trap, hit independently by two devs today:
Landed and closed out.
PR #8781 merged as
6fae5e2onmain.Verified by CONTENT, not by sha, with a control proven to fire on both sides of the merge:
reading before merge after merge SUBJECT — innerWidthinRelatedList.headerSort.test.tsx0 2 CONTROL — file line count 233 248 CONTROL — describe(count2 2 The controls fire in both readings, so the subject's
0before the merge was a reading and not a false zero. Sweeping the package, 17 files now state a viewport where 2 did before — the 15 this PR names plus the 2 that already pinned one.Card released:
pm:dispatchedstripped, assignee cleared. Unsubscribing from the PR.
Generated by Claude Code
Found while doing objectui#8399 (PR pins the viewport in
record-details.dedupeEmptinessTrims-8350.test.tsx). ⛔ Not claimed. Nothing is broken today.objectui#8399 is one file. This card is the size of the class it belongs to, measured rather than estimated.
Measured
useIsMobile(packages/components/src/hooks/use-mobile.tsx) answerswindow.innerWidth < 768. happy-dom reportsinnerWidth1024 (measured onca3942729by forcing the value into an assertion message), so every test in this package silently runs the desktop branch of every component that reads that hook.Method: mutate
MOBILE_BREAKPOINT768 to 999999 inuse-mobile.tsx(on-disk mutation proven bygit hash-objectdiffering fromgit rev-parse HEAD:PATH; restored by state,git diff HEADempty and the hash back to the HEAD blob), then run the package:Unmutated, the same command is green. The 21 files include the whole
RelatedList.*family (table versus card layout),DetailSection.doubleClickEdit,DetailSection.lookupLink,inlineCredentialGate(16 tests), and objectui#8399's own file.What this does and does not say
innerWidth(DetailSection.emptinessAuthority-8376.test.tsxpins 1280 and still fails 2 tests under it, correctly). So the number measures "depends on the desktop branch", not "fails to pin". A pin-only audit would be a different, smaller number.DetailSection.emptinessAuthority-8376.test.tsxand (after objectui#8399's PR)record-details.dedupeEmptinessTrims-8350.test.tsx.Why it may be worth a card rather than a shrug
The failure mode is the one objectui#8399 documents: when a threshold, a fixture or a shared definition of "empty" moves underneath, a landed pin reddens on a branch nobody chose, with a message about the wrong mechanism. This package is where the auto-hide thresholds differ per branch (
AUTO_HIDE_MIN_FIELDS4 versus 3,AUTO_HIDE_RATIO0.25 versus 0.2), so it is where the two branches actually disagree about which rows exist.A plausible shape, for a triager rather than a decision here: a single shared
pinViewporthelper plus a lint rule or a pin test that requires a viewport statement from files that renderuseIsMobileconsumers — not a blanket edit of 21 files.Dedup
One targeted
search_issuesrun against this repo (open and closed):test files depend on happy-dom default viewport width without pinning innerWidth useIsMobile mobile branch plugin-detailreturned 3 items — objectui#8399 itself, objectui#7228 (plugin-ganttcontainer-width branches, unrelated) and objectui#6438 (published-stylesheet pin, unrelated). No duplicate found.