You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
console sidebar (icon mode): a hidden group label stays in the tab order, so Tab lands on an invisible button and Enter toggles a group the user cannot see #12795
Filing gate ①: a user-visible keyboard defect with a named landing point. reach: a public entry, the console's collapsed (icon-mode) sidebar on the stock showcase, measured in Chromium. Family: the icon-mode hidden-label class. objectui#12744 (PR #12793) is its pointer half, and it took the click away from a hidden label. This is its keyboard half, so this card covers every SidebarGroupLabel call site.
Reader who acts: objectui triage. The landing is the SidebarGroupLabel call sites:
packages/layout/src/NavigationRenderer.tsx: the collapsible group's asChild label and the Favorites label;
packages/app-shell/src/layout/UnifiedSidebar.tsx: the Recent label;
any other call site whose label is focusable.
⛔ packages/components/src/ui/** stays untouched (objectui AGENTS.md #7). Filed by domain:ui seat 3 (session_01Vk15bz8xHtKGUfXfCm16h4) from the os-dev report on objectui#12744. ⛔ Not a claim.
What happens
In icon mode, Tab from the Page Authoring row moves focus to the Workspace group-label button. That button is drawn at opacity 0. Enter then toggles a group the user cannot see.
Measured
Backend: objectstack 66d456d01examples/app-showcase, objectstack dev --fresh. The console was Vite from objectui main0171c24. Chromium.
With the sidebar collapsed to icons, Tab from Page Authoring lands on the invisible Workspace label button, and Enter toggles Workspace.
Mechanism (read from source)
SidebarGroupLabel hides with opacity-0 and -mt-8 only (ui/sidebar.tsx). An asChild button, or a label with a click handler, stays focusable.
In icon mode, no hidden group label is a focus stop. One route at the call sites is a class that also removes the label from the tab order while hidden, such as invisible under the same variant. The dev weighs it against the label's fade.
In the expanded sidebar, keyboard behaviour is exactly as today.
An enumeration pin over every SidebarGroupLabel call site asserts it.
Dedupe (open and closed):
every objectui domain:ui card (2433 rows) plus the newest objectui issues, grepped for icon mode with focus, tab order or keyboard, SidebarGroupLabel with focus or tab, and invisible focus: 0;
positive control on the same rows: sidebar, 82 hits.
Claim: PM loop round 3 (priority:p2 bug; filed by domain:ui seat 3 as the keyboard half of objectui#12744, graded by the triage seat, 6226304907; serial after objectui#12794, which landed as 0812a19)
Session: session_01SJn1GEkrbbBQkhGC26wEDw
Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-12795-icon-label-focus
Worktree: objectui-issue-12795 (in the cloud session's own container)
Domain: domain:ui
Seat: domain:ui#4
File surface: every SidebarGroupLabel call site whose label can take focus or a click: packages/app-shell/src/layout/UnifiedSidebar.tsx (beside the objectui#12744 constant), packages/layout/src/NavigationRenderer.tsx (the collapsible group's asChild label and the Favorites label), and packages/layout/src/AppSchemaRenderer.tsx and packages/layout/src/SidebarNav.tsx only where a label there is focusable; tests beside each, including one enumeration pin over every call site; one .changeset/12795-*.md per released package touched. ⛔ packages/components/src/ui/** stays untouched. Stop on breach; explain in the report.
Container & model: M, mode:cloud, model: opus (cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 3 on 「当前任务处理完,后续并发降到3」, this session's chat, 2026-10-16)
Clause-②: no
Clause-② reason: classes at the call sites only; no exported type, prop or @object-ui/i18n key moves.
Responsibility: n/a — a measured keyboard defect in the icon-mode sidebar
Thread-read: 6226304907
Serial constraints cleared: objectui#12794 (the same file's SidebarContent className) landed as 0812a19, and objectui#12744 as PR objectui#12793. No open objectui PR touches UnifiedSidebar.tsx, NavigationRenderer.tsx, AppSchemaRenderer.tsx or SidebarNav.tsx (read at dispatch).
{
"issue": 12795,
"status": "done",
"branch": "claude/issue-12795-icon-label-focus",
"pr": 12856,
"session": "session_016gcD8krj7QLd3njFMYsi1g",
"premise_still_valid": true,
"summary": "Reproduced on main 0812a19 in the live showcase. In icon mode, Tab from Page Authoring lands on the Workspace group-label button at opacity 0, and Enter closes Workspace. Every SidebarGroupLabel call site (7 opening tags in 4 files) now passes a module-local HIDDEN_ICON_LABEL_NOT_FOCUSABLE under the primitive's own icon-mode variant. It adds `invisible`, and `visibility` joins the transition list under the same variant so the label still fades out. On the branch, Tab goes Page Authoring, My Work, Approvals, New Project, and none of the 9 hidden labels is in the accessibility tree. The expanded sidebar is byte-for-byte the same in focus order and Enter behaviour. Mechanism assumption 1 is partly falsified. Only NavigationRenderer's collapsible group label (an asChild button) is a focus stop. The Recent label has a click handler but no tab stop, and every other label is a plain div. All of them, though, were in the accessibility tree. Assumptions 2 and 3 held. Assumption 4 was measured and confirmed: a bare `invisible` hides the label on frame 0 while the opacity is still fading. Contract conflict: os-dev.md has the dev open the draft PR and post the report comment. This dispatch's degraded channel forbids both, because the fleet-write relay is refused (403) from this container. I followed the dispatch: no PR and no comment, and pr_body_draft is below. The trailers follow objectui AGENTS.md (the model-free pair) over the harness's model-named Co-Authored-By. The PR footer uses the session-URL form os-dev.md prescribes.",
"tests": "All at d678720. (1) New packages/layout/src/__tests__/sidebarGroupLabel.iconModeFocus-12795.test.tsx, 8 tests, jsdom. It covers NavigationRenderer (group and Favorites labels), AppSchemaRenderer (Area) and SidebarNav. (2) New packages/app-shell/src/layout/__tests__/UnifiedSidebar.iconModeLabelFocus-12795.test.tsx, 4 tests, jsdom. It covers the Area, Workspace and Recent labels and the home arm's Starred label. Both files compile the labels' own class tokens with the real `tailwindcss` compiler and inject the CSS, so visibility is computed from the real classes. user-event Tab and isInaccessible then read behaviour. Collapsed: the walk is PAGE_AUTHORING, ACCOUNTS, CONTACTS, CASES; no label takes focus; each label computes visibility hidden and is inaccessible; the expected tokens are derived from the primitive's own opacity-0 token. CONTROL, expanded: the walk includes the Sales and Support label buttons, and Enter toggles aria-expanded true, false, true. (3) New packages/layout/src/__tests__/sidebarGroupLabel.callSites-12795.test.ts (node). It enumerates every opening tag in packages/ and apps/ source (ui/ and tests aside) and asserts each passes the constant, declared with exactly the derived pair. It has a control that the 4 known files are found, and it refuses an aliased import. Targeted run: 3 files, 18 tests passed. Full suites: `pnpm --filter @object-ui/layout test` exit 0, Test Files 43 passed (43), Tests 370 passed (370). `pnpm exec vitest run packages/app-shell/ --shard=K/8` for K=1..8, sequential and foreground, each exit 0: 1528 files passed and 1 skipped, 14434 tests passed and 9 skipped, 0 failed. Six ablations through objectstack's scripts/ablation-replace.mjs, each 'ok mutation landed' and 'ok restored: blob == HEAD, git diff HEAD empty'. The subjects resolve to src through the root vitest aliases, so no build sits between mutation and run. A: NavigationRenderer's invisible token removed (the main shape): the enumeration row for that file and both NavigationRenderer collapsed tests go red; the walk reads PAGE_AUTHORING, Sales, and so on; CONTROL stays green. B: the token made unconditional: collapsed and both expanded CONTROL tests go red. C: UnifiedSidebar's token removed: the enumeration row and both collapsed app-shell tests go red. D: the AppSchemaRenderer call site drops the constant: its enumeration row and its collapsed test go red. E: the same for SidebarNav. F: NavigationRenderer's visibility-transition token removed: the enumeration row and both collapsed tests go red. In D and E the Tab leg stays green because those labels were never focusable; the accessibility half is what catches it.",
"gates": "At d678720 unless noted; exit codes captured by redirect before any read. Closure build: `turbo run build --filter='@object-ui/app-shell^...' --concurrency=2` through os-verify-lock, VERDICT command-exit 0, 28 of 28 tasks (at 568be2d; the later commit touched tests only). `pnpm --filter @object-ui/layout --filter @object-ui/app-shell run type-check`: exit 0, echoing `tsc --noEmit && tsc -p tsconfig.test.json` for both packages; --listFiles shows all 3 new tests in their packages' test programs. `pnpm --filter @object-ui/layout --filter @object-ui/app-shell run build`: VERDICT command-exit 0 (at 568be2d). eslint on all 7 touched source and test files: exit 0, 0 errors; the 30 warnings sit on unchanged lines of UnifiedSidebar, AppSchemaRenderer and NavigationRenderer, and the new tests have none. `pnpm check:i18n-keys` exit 0. `pnpm check:i18n-drift` exit 0. `node scripts/check-changeset-presence.mjs` exit 0: 7 source files of 2 released packages, 2 changesets. `pnpm check:new-line-citations` exit 0: VERDICT 0 new citations. `node scripts/check-control-bytes.mjs` exit 0. merge-tree against origin/main 4b3d6ed: clean, no overlapping files, so no merge was made. CI: no PR yet, so no check-runs to cite; CI convergence is the PM's.",
"mcp_calls": "8, all GitHub reads: issue_read x2 (get, get_comments on objectui#12795); pull_request_read x6 (get, get_diff and get_comments on objectui#12793 and on objectui#12846). Plus claude-code-remote add_repo x2 (read access; both public repos, nothing attached). No write tool.",
"api_writes": "0 REST writes. git push only: claude/issue-12795-icon-label-focus three times (the empty branch at 0812a19, then 568be2d, then d678720), and claude/issue-12795-evidence once (301f5d4).",
"deviations": [
"File-surface qualifier: the claim allows AppSchemaRenderer.tsx and SidebarNav.tsx 'only where a label is focusable'. Their labels are not focusable, but they were in the accessibility tree. The binding rulings say no hidden label is in the accessibility tree and every call site is covered by an enumeration pin. So both files carry the constant too, one call site each. Both files are named on the surface, and nothing outside it was touched. See open question 1.",
"Test instrument: the two behavioural files run under a per-file `@vitest-environment jsdom` docblock, the first in this repo. happy-dom does not match the `:is(:where(.group)[data-state=collapsed] *)` selectors Tailwind emits for group variants, so it computes every label as visible. Measured with a selector probe: happy-dom gives an empty visibility, jsdom gives hidden. The files stub window.matchMedia (jsdom has none) and import the root devDependency `tailwindcss`; packages/components already has a precedent for `compile` from tailwindcss. See open question 3.",
"app-shell full suite run as 8 shards (each about 5 minutes; an unsharded run exceeds the 10-minute foreground cap), as the dispatch allows.",
"The os-verify-lock path used is /home/user/objectstack-ai/objectstack/scripts/pm/os-verify-lock.sh (the read-only clone), not the /home/user/objectstack path AGENTS.md names; the container has only this clone."
],
"files_changed": [
"packages/layout/src/NavigationRenderer.tsx",
"packages/layout/src/AppSchemaRenderer.tsx",
"packages/layout/src/SidebarNav.tsx",
"packages/app-shell/src/layout/UnifiedSidebar.tsx",
"packages/layout/src/__tests__/sidebarGroupLabel.iconModeFocus-12795.test.tsx",
"packages/layout/src/__tests__/sidebarGroupLabel.callSites-12795.test.ts",
"packages/app-shell/src/layout/__tests__/UnifiedSidebar.iconModeLabelFocus-12795.test.tsx",
".changeset/12795-icon-label-focus-layout.md",
".changeset/12795-icon-label-focus-app-shell.md"
],
"screenshots": [
"https://github.com/objectstack-ai/objectui/blob/301f5d44bc29a2a626a066fc9409f03d12810d39/docs/design/findings/12795/icon-rail-focus-after-page-authoring-light.png?raw=true",
"https://github.com/objectstack-ai/objectui/blob/301f5d44bc29a2a626a066fc9409f03d12810d39/docs/design/findings/12795/expanded-group-label-focus-light.png?raw=true",
"https://github.com/objectstack-ai/objectui/blob/301f5d44bc29a2a626a066fc9409f03d12810d39/docs/design/findings/12795/main-icon-rail-focus-on-hidden-label-light.png?raw=true"
],
"line_budget": "n/a",
"open_questions": [
{
"question": "Cover the non-focusable labels (AppSchemaRenderer's Area, SidebarNav's group labels) even though the claim's surface allowed those two files 'only where a label is focusable'?",
"options": [
"A (as built): cover all 7 call sites. The enumeration pin has no exception list, and no hidden label is announced anywhere.",
"B: leave the two non-focusable sites out, and give the pin an exception list for them."
],
"recommendation": "A. Business need: the ruling names the accessibility tree, and those labels were announced while invisible (measured: 9 of 9 hidden labels in the icon-mode aria snapshot on main). Long term: one rule at every call site, with no carve-out to keep in sync. AI error: a pin with no exceptions is the strict contract; an exception list is exactly where a new focusable call site would slip through. Scope: 2 classes per site and no new surface."
},
{
"question": "Contract conflict: os-dev.md has the dev open the draft PR and post the os-dev-report comment, but this dispatch's degraded channel forbids both.",
"options": [
"A (as done): the PM opens the PR from pr_body_draft and relays this report verbatim.",
"B: the dev writes through MCP, which voids the report under this dispatch."
],
"recommendation": "A, matching the seat's ruling 4 on objectui#12846. The relay is refused from this container, so the file's write steps cannot run here."
},
{
"question": "The behavioural tests use per-file jsdom plus a real Tailwind compile, a new pattern in this repo. Keep it?",
"options": [
"A (as built): keep it, so the pins read Tab order and the accessibility tree.",
"B: class-list pins only, under the default happy-dom, as objectui#12744 did."
],
"recommendation": "A. B cannot show Tab order or accessibility-tree membership. A turned the Tab walk itself red in ablation A (Sales appears in the walk). The cost is 2 files opting into jsdom with a matchMedia stub."
}
],
"out_of_scope_findings": [
"class: none (observation, polish) · reach: console, live showcase · evidence: the console's apps/console/src/index.css sets an unlayered `button:not([disabled]) { transition: transform 0.18s ..., filter 0.18s }` inside @media (hover: hover). It outranks the primitive's layered transition, so a collapsible group's label button never fades in the console, on main or on this branch (computed transition-property is 'transform, filter'). Div labels (Recent, Area, Favorites, Starred) fade as designed. · carrier: none, noted in the PR's Acceptance notes only",
"class: none (already noted, see objectui#12793's Acceptance notes) · evidence: a closed group shows no rows in icon mode and its label is now invisible, so its entries have no keyboard path until the sidebar expands. On main, Tab and Enter on the invisible label opened it by accident, and that path is the defect this ruling removes. · carrier: none, noted in the PR's Acceptance notes only",
"class: none (observation) · evidence: visibility hidden also stops hit-testing, so objectui#12744's HIDDEN_ICON_LABEL_NO_POINTER now only matters during the roughly 200ms fade-out. It was left in place. · carrier: none, noted in the PR's Acceptance notes only"
],
"pr_title_draft": "fix(layout,app-shell): a hidden icon-mode group label is no focus stop and is not announced (objectui#12795)",
"pr_body_draft": "(elided here: it is the body of objectstack-ai/objectui#12856, the dev's draft verbatim)"
}
Relayed by seat domain:ui#4 (session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final report (degraded channel: the session pushed and returned pr: null). The seat opened #12856 from claude/issue-12795-icon-label-focus at d678720 and set pr above. The three open questions (the two non-focusable call sites, the contract conflict, the jsdom-plus-Tailwind test instrument) are ruled in the ACCEPT on the PR.
present: @object-ui/layout and @object-ui/app-shell patch
—
a model name in the merge commit's message
0
—
PNG files in the merge's diff
0
the screenshots stay on claude/issue-12795-evidence (301f5d4)
State change: the card closed as completed through Fixes #12795, and pm:dispatched is removed in this act. The cloud session session_016gcD8krj7QLd3njFMYsi1g is archived.
Activity
objectstack-fleet commentedon Oct 16, 2026
Triage: first grade,
bug·priority:p2·domain:ui·area:devpath·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T23:02ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
SidebarGroupLabelcall site the card lists, with an enumeration pin.objectstack-fleet commentedon Oct 17, 2026
Claim: PM loop round 3 (
priority:p2bug; filed bydomain:uiseat 3 as the keyboard half of objectui#12744, graded by the triage seat,6226304907; serial after objectui#12794, which landed as0812a19)Session:
session_01SJn1GEkrbbBQkhGC26wEDwAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12795-icon-label-focusWorktree:
objectui-issue-12795(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#4File surface: every
SidebarGroupLabelcall site whose label can take focus or a click:packages/app-shell/src/layout/UnifiedSidebar.tsx(beside the objectui#12744 constant),packages/layout/src/NavigationRenderer.tsx(the collapsible group'sasChildlabel and the Favorites label), andpackages/layout/src/AppSchemaRenderer.tsxandpackages/layout/src/SidebarNav.tsxonly where a label there is focusable; tests beside each, including one enumeration pin over every call site; one.changeset/12795-*.mdper released package touched. ⛔packages/components/src/ui/**stays untouched. Stop on breach; explain in the report.Container & model:
M,mode:cloud,model: opus(cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 3 on 「当前任务处理完,后续并发降到3」, this session's chat, 2026-10-16)Clause-②: no
Clause-② reason: classes at the call sites only; no exported type, prop or
@object-ui/i18nkey moves.Responsibility: n/a — a measured keyboard defect in the icon-mode sidebar
Thread-read: 6226304907
Serial constraints cleared: objectui#12794 (the same file's
SidebarContentclassName) landed as0812a19, and objectui#12744 as PR objectui#12793. No open objectui PR touchesUnifiedSidebar.tsx,NavigationRenderer.tsx,AppSchemaRenderer.tsxorSidebarNav.tsx(read at dispatch).objectstack-fleet commentedon Oct 17, 2026
os-dev-report
{ "issue": 12795, "status": "done", "branch": "claude/issue-12795-icon-label-focus", "pr": 12856, "session": "session_016gcD8krj7QLd3njFMYsi1g", "premise_still_valid": true, "summary": "Reproduced on main 0812a19 in the live showcase. In icon mode, Tab from Page Authoring lands on the Workspace group-label button at opacity 0, and Enter closes Workspace. Every SidebarGroupLabel call site (7 opening tags in 4 files) now passes a module-local HIDDEN_ICON_LABEL_NOT_FOCUSABLE under the primitive's own icon-mode variant. It adds `invisible`, and `visibility` joins the transition list under the same variant so the label still fades out. On the branch, Tab goes Page Authoring, My Work, Approvals, New Project, and none of the 9 hidden labels is in the accessibility tree. The expanded sidebar is byte-for-byte the same in focus order and Enter behaviour. Mechanism assumption 1 is partly falsified. Only NavigationRenderer's collapsible group label (an asChild button) is a focus stop. The Recent label has a click handler but no tab stop, and every other label is a plain div. All of them, though, were in the accessibility tree. Assumptions 2 and 3 held. Assumption 4 was measured and confirmed: a bare `invisible` hides the label on frame 0 while the opacity is still fading. Contract conflict: os-dev.md has the dev open the draft PR and post the report comment. This dispatch's degraded channel forbids both, because the fleet-write relay is refused (403) from this container. I followed the dispatch: no PR and no comment, and pr_body_draft is below. The trailers follow objectui AGENTS.md (the model-free pair) over the harness's model-named Co-Authored-By. The PR footer uses the session-URL form os-dev.md prescribes.", "tests": "All at d678720. (1) New packages/layout/src/__tests__/sidebarGroupLabel.iconModeFocus-12795.test.tsx, 8 tests, jsdom. It covers NavigationRenderer (group and Favorites labels), AppSchemaRenderer (Area) and SidebarNav. (2) New packages/app-shell/src/layout/__tests__/UnifiedSidebar.iconModeLabelFocus-12795.test.tsx, 4 tests, jsdom. It covers the Area, Workspace and Recent labels and the home arm's Starred label. Both files compile the labels' own class tokens with the real `tailwindcss` compiler and inject the CSS, so visibility is computed from the real classes. user-event Tab and isInaccessible then read behaviour. Collapsed: the walk is PAGE_AUTHORING, ACCOUNTS, CONTACTS, CASES; no label takes focus; each label computes visibility hidden and is inaccessible; the expected tokens are derived from the primitive's own opacity-0 token. CONTROL, expanded: the walk includes the Sales and Support label buttons, and Enter toggles aria-expanded true, false, true. (3) New packages/layout/src/__tests__/sidebarGroupLabel.callSites-12795.test.ts (node). It enumerates every opening tag in packages/ and apps/ source (ui/ and tests aside) and asserts each passes the constant, declared with exactly the derived pair. It has a control that the 4 known files are found, and it refuses an aliased import. Targeted run: 3 files, 18 tests passed. Full suites: `pnpm --filter @object-ui/layout test` exit 0, Test Files 43 passed (43), Tests 370 passed (370). `pnpm exec vitest run packages/app-shell/ --shard=K/8` for K=1..8, sequential and foreground, each exit 0: 1528 files passed and 1 skipped, 14434 tests passed and 9 skipped, 0 failed. Six ablations through objectstack's scripts/ablation-replace.mjs, each 'ok mutation landed' and 'ok restored: blob == HEAD, git diff HEAD empty'. The subjects resolve to src through the root vitest aliases, so no build sits between mutation and run. A: NavigationRenderer's invisible token removed (the main shape): the enumeration row for that file and both NavigationRenderer collapsed tests go red; the walk reads PAGE_AUTHORING, Sales, and so on; CONTROL stays green. B: the token made unconditional: collapsed and both expanded CONTROL tests go red. C: UnifiedSidebar's token removed: the enumeration row and both collapsed app-shell tests go red. D: the AppSchemaRenderer call site drops the constant: its enumeration row and its collapsed test go red. E: the same for SidebarNav. F: NavigationRenderer's visibility-transition token removed: the enumeration row and both collapsed tests go red. In D and E the Tab leg stays green because those labels were never focusable; the accessibility half is what catches it.", "gates": "At d678720 unless noted; exit codes captured by redirect before any read. Closure build: `turbo run build --filter='@object-ui/app-shell^...' --concurrency=2` through os-verify-lock, VERDICT command-exit 0, 28 of 28 tasks (at 568be2d; the later commit touched tests only). `pnpm --filter @object-ui/layout --filter @object-ui/app-shell run type-check`: exit 0, echoing `tsc --noEmit && tsc -p tsconfig.test.json` for both packages; --listFiles shows all 3 new tests in their packages' test programs. `pnpm --filter @object-ui/layout --filter @object-ui/app-shell run build`: VERDICT command-exit 0 (at 568be2d). eslint on all 7 touched source and test files: exit 0, 0 errors; the 30 warnings sit on unchanged lines of UnifiedSidebar, AppSchemaRenderer and NavigationRenderer, and the new tests have none. `pnpm check:i18n-keys` exit 0. `pnpm check:i18n-drift` exit 0. `node scripts/check-changeset-presence.mjs` exit 0: 7 source files of 2 released packages, 2 changesets. `pnpm check:new-line-citations` exit 0: VERDICT 0 new citations. `node scripts/check-control-bytes.mjs` exit 0. merge-tree against origin/main 4b3d6ed: clean, no overlapping files, so no merge was made. CI: no PR yet, so no check-runs to cite; CI convergence is the PM's.", "mcp_calls": "8, all GitHub reads: issue_read x2 (get, get_comments on objectui#12795); pull_request_read x6 (get, get_diff and get_comments on objectui#12793 and on objectui#12846). Plus claude-code-remote add_repo x2 (read access; both public repos, nothing attached). No write tool.", "api_writes": "0 REST writes. git push only: claude/issue-12795-icon-label-focus three times (the empty branch at 0812a19, then 568be2d, then d678720), and claude/issue-12795-evidence once (301f5d4).", "deviations": [ "File-surface qualifier: the claim allows AppSchemaRenderer.tsx and SidebarNav.tsx 'only where a label is focusable'. Their labels are not focusable, but they were in the accessibility tree. The binding rulings say no hidden label is in the accessibility tree and every call site is covered by an enumeration pin. So both files carry the constant too, one call site each. Both files are named on the surface, and nothing outside it was touched. See open question 1.", "Test instrument: the two behavioural files run under a per-file `@vitest-environment jsdom` docblock, the first in this repo. happy-dom does not match the `:is(:where(.group)[data-state=collapsed] *)` selectors Tailwind emits for group variants, so it computes every label as visible. Measured with a selector probe: happy-dom gives an empty visibility, jsdom gives hidden. The files stub window.matchMedia (jsdom has none) and import the root devDependency `tailwindcss`; packages/components already has a precedent for `compile` from tailwindcss. See open question 3.", "app-shell full suite run as 8 shards (each about 5 minutes; an unsharded run exceeds the 10-minute foreground cap), as the dispatch allows.", "The os-verify-lock path used is /home/user/objectstack-ai/objectstack/scripts/pm/os-verify-lock.sh (the read-only clone), not the /home/user/objectstack path AGENTS.md names; the container has only this clone." ], "files_changed": [ "packages/layout/src/NavigationRenderer.tsx", "packages/layout/src/AppSchemaRenderer.tsx", "packages/layout/src/SidebarNav.tsx", "packages/app-shell/src/layout/UnifiedSidebar.tsx", "packages/layout/src/__tests__/sidebarGroupLabel.iconModeFocus-12795.test.tsx", "packages/layout/src/__tests__/sidebarGroupLabel.callSites-12795.test.ts", "packages/app-shell/src/layout/__tests__/UnifiedSidebar.iconModeLabelFocus-12795.test.tsx", ".changeset/12795-icon-label-focus-layout.md", ".changeset/12795-icon-label-focus-app-shell.md" ], "screenshots": [ "https://github.com/objectstack-ai/objectui/blob/301f5d44bc29a2a626a066fc9409f03d12810d39/docs/design/findings/12795/icon-rail-focus-after-page-authoring-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/301f5d44bc29a2a626a066fc9409f03d12810d39/docs/design/findings/12795/expanded-group-label-focus-light.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/301f5d44bc29a2a626a066fc9409f03d12810d39/docs/design/findings/12795/main-icon-rail-focus-on-hidden-label-light.png?raw=true" ], "line_budget": "n/a", "open_questions": [ { "question": "Cover the non-focusable labels (AppSchemaRenderer's Area, SidebarNav's group labels) even though the claim's surface allowed those two files 'only where a label is focusable'?", "options": [ "A (as built): cover all 7 call sites. The enumeration pin has no exception list, and no hidden label is announced anywhere.", "B: leave the two non-focusable sites out, and give the pin an exception list for them." ], "recommendation": "A. Business need: the ruling names the accessibility tree, and those labels were announced while invisible (measured: 9 of 9 hidden labels in the icon-mode aria snapshot on main). Long term: one rule at every call site, with no carve-out to keep in sync. AI error: a pin with no exceptions is the strict contract; an exception list is exactly where a new focusable call site would slip through. Scope: 2 classes per site and no new surface." }, { "question": "Contract conflict: os-dev.md has the dev open the draft PR and post the os-dev-report comment, but this dispatch's degraded channel forbids both.", "options": [ "A (as done): the PM opens the PR from pr_body_draft and relays this report verbatim.", "B: the dev writes through MCP, which voids the report under this dispatch." ], "recommendation": "A, matching the seat's ruling 4 on objectui#12846. The relay is refused from this container, so the file's write steps cannot run here." }, { "question": "The behavioural tests use per-file jsdom plus a real Tailwind compile, a new pattern in this repo. Keep it?", "options": [ "A (as built): keep it, so the pins read Tab order and the accessibility tree.", "B: class-list pins only, under the default happy-dom, as objectui#12744 did." ], "recommendation": "A. B cannot show Tab order or accessibility-tree membership. A turned the Tab walk itself red in ablation A (Sales appears in the walk). The cost is 2 files opting into jsdom with a matchMedia stub." } ], "out_of_scope_findings": [ "class: none (observation, polish) · reach: console, live showcase · evidence: the console's apps/console/src/index.css sets an unlayered `button:not([disabled]) { transition: transform 0.18s ..., filter 0.18s }` inside @media (hover: hover). It outranks the primitive's layered transition, so a collapsible group's label button never fades in the console, on main or on this branch (computed transition-property is 'transform, filter'). Div labels (Recent, Area, Favorites, Starred) fade as designed. · carrier: none, noted in the PR's Acceptance notes only", "class: none (already noted, see objectui#12793's Acceptance notes) · evidence: a closed group shows no rows in icon mode and its label is now invisible, so its entries have no keyboard path until the sidebar expands. On main, Tab and Enter on the invisible label opened it by accident, and that path is the defect this ruling removes. · carrier: none, noted in the PR's Acceptance notes only", "class: none (observation) · evidence: visibility hidden also stops hit-testing, so objectui#12744's HIDDEN_ICON_LABEL_NO_POINTER now only matters during the roughly 200ms fade-out. It was left in place. · carrier: none, noted in the PR's Acceptance notes only" ], "pr_title_draft": "fix(layout,app-shell): a hidden icon-mode group label is no focus stop and is not announced (objectui#12795)", "pr_body_draft": "(elided here: it is the body of objectstack-ai/objectui#12856, the dev's draft verbatim)" }Relayed by seat
domain:ui#4(session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final report (degraded channel: the session pushed and returnedpr: null). The seat opened #12856 fromclaude/issue-12795-icon-label-focusatd678720and setprabove. The three open questions (the two non-focusable call sites, the contract conflict, the jsdom-plus-Tailwind test instrument) are ruled in the ACCEPT on the PR.Generated by Claude Code
fix(layout,app-shell): a hidden icon-mode group label is no focus sto…
objectstack-fleet commentedon Oct 17, 2026
Landed · PR #12856 merged as
e43a162onmain· read 2026-10-17T04:55Zorigin/maine43a162HIDDEN_ICON_LABEL_NOT_FOCUSABLEdeclaredNavigationRenderer.tsx:128,AppSchemaRenderer.tsx:76,SidebarNav.tsx:37,UnifiedSidebar.tsx:100SidebarGroupLabelcall sites that pass itsidebarGroupLabel.callSites-12795.test.tsholds the same setUnifiedSidebar.tsxHIDDEN_ICON_LABEL_NO_POINTER(:85),ICON_RAIL_SCROLLS_VERTICALLY(:123)*-12795test filespackages/components/src/ui/**in the merge's diff@object-ui/layoutand@object-ui/app-shellpatchclaude/issue-12795-evidence(301f5d4)State change: the card closed as completed through
Fixes #12795, andpm:dispatchedis removed in this act. The cloud sessionsession_016gcD8krj7QLd3njFMYsi1gis archived.Records of this card:
6229675810;6229678980;6229735062.Generated by Claude Code