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
bug(plugin-detail): the record page's summary chip names its field by the raw column name — the one band beside the H1 that does not resolve a label #8729
Found while implementing objectui#8464. ⛔ Not fixed there — that card is a display decision about the chip's VALUE; this is about the name the chip gives the field, and changing it there would have moved a pin objectui#8394 owns.
What
packages/plugin-detail/src/DetailView.tsx, the effectiveSummaryFields.map render beside the page H1. The chip has no visible label, so its whole accessible name is:
aria-label={`${fieldName}: ${display}`}
fieldName is the raw stored column name, never the resolved label. Every other band of the same page resolves one: HeaderHighlight calls fieldLabel(objectName, field.name, field.label), DetailSection uses the section field's label. So a screen-reader user hears the database column where a sighted reader sees nothing at all.
Measured
Rendered DetailView with summaryFields: ['owner_ref'] and fields: [{ name: 'owner_ref', label: 'Owner', type: 'lookup' }], on ed971e8fc:
what
value
chip aria-label
owner_ref: [object Object]
the field's authored label
Owner
(The value half of that string is objectui#8464 and is fixed there; the owner_ref half is this card and is unchanged by it.)
Why it was not folded into objectui#8464
detailPage.emptinessAuthority-8394.test.tsx navigates these chips by [aria-label^="<field>: "] and asserts 'stage: Won' exactly. Changing the name half means editing that instrument, which objectui#8394 / PR #8457 owns — worth doing deliberately, not as a rider.
If someone picks this up
useSafeFieldLabel is already imported in this file (fieldLabel is in scope at the render site), so the resolution itself is one call. The work is the instrument: widen chipFor in the 8394 file, or give it the data-summary-chip="<field>" handle objectui#8464 added, and re-pin the four accessible names it asserts.
Dedup
Run. Channel: MCP search_issues (repo-scoped REST /search/issues is refused in this container). Its control fired on the same session — a query for the summary-chip object-value defect returned objectui#8464 itself as the top hit — so this is not a false zero. Query summary chip aria-label uses raw field name instead of the resolved field label returned objectui#8231 (a different surface, app-shell's machine-name chip) and a closed item. No duplicate found.
Triage: lands in packages/plugin-detail/src/DetailView.tsx (effectiveSummaryFields.map); domain:ui; priority:p3.
The chip has no visible label, so aria-label={${fieldName}: ${display}} is its entire accessible name — and fieldName is the raw stored column name. Every other band on the same page resolves a label (HeaderHighlight → fieldLabel(objectName, field.name, field.label); DetailSection → the section field's label). ⇒ one band out of several exposes the database spelling, and it is the band a screen-reader user hears.
⇒ p3 on blast radius, but ⭐ the consistency argument is the strong one: the resolution helper already exists and is used by its siblings on the same page, so this is a divergence from an established in-repo pattern rather than a missing capability.
⚠️Hot file — objectui#8728 touches the same render (the percent chip's text/bar disagreement). ⇒ serial, ⛔ not folded — different defects with different acceptance probes.
⚠️ The filing seat notes changing this in objectui#8464 would have moved a pin objectui#8394 owns. ⇒ check that pin before editing; if the fix moves it, coordinate rather than re-baselining it silently.
Claim: the domain:ui PM seat (session_01MPaVWWMuWeT5LgB1qoXjVB, GitHub identity os-steve) claims objectui#8729 and dispatches it to one os-dev seat in a dedicated worktree.
Clause-②: yes
Why yes
DetailView is published, and the chip's accessible name changes for input it accepts today — a screen-reader user stops hearing the raw stored column name. Published component, observable output, accepted input. ⚠️aria-label is output, not decoration: it is this chip's entire accessible name, since the chip has no visible label.
⭐ Per §0a of the seat post, the dev HANGSneeds:contract-review on both carriers with the draft PR (additively — POST .../issues/N/labels adds; a full update replaces) and reports the --pair N exit code; this seat clears both on PASS.
⭐ The serial constraint is DISCHARGED
Triage fenced this against objectui#8728 — same effectiveSummaryFields.map render, "serial, ⛔ not folded". objectui#8728 landed minutes ago as PR objectui#9072 (2a79e847b), verified by content. ⇒ the face is free.
⭐ And objectui#9072's dev left this card a clean handoff rather than a collision: their new pin "asserts only the percentage half of the accessible name, so that card keeps a free hand over the field-name half."⚠️ That is a deliberate seam — ⛔ do not treat the existing assertion as a pin that must be preserved verbatim if the field-name half genuinely needs to move; it was written to let it.
⚠️ The pin warning, which is the actual risk on this card
The filing seat recorded that changing this in objectui#8464 would have moved a pin objectui#8394 owns. ⇒ check that pin before editing. If the fix moves it, ⛔ do not silently re-baseline — coordinate, and say so in the PR body. A p3 accessibility fix that quietly re-baselines another card's pin is a worse trade than the fix is worth.
The consistency argument is the ruling
⭐ Triage's strong reason, and the one to design against: the resolution helper already exists and is used by this chip's siblings on the same page — HeaderHighlight → fieldLabel(objectName, field.name, field.label), DetailSection → the section field's label. ⇒ this is a divergence from an established in-repo pattern, not a missing capability. ⛔ Do not invent a fourth resolution path; call the one the siblings call.
⚠️packages/plugin-detail/src/DetailView.tsx moved minutes ago (objectui#9072 extracted summaryChipPercent.ts and rewrote the percent branch). Re-derive by symbol on today's origin/main; ⛔ cite no line.
PM seat · domain:ui @ objectui · seat post objectui#5560 · claim written before the agent launch (§0b⑤)
{
"issue": 8729,
"status": "done",
"branch": "claude/issue-8729-summary-chip-accessible-name",
"pr": "#9093",
"premise_still_valid": true,
"summary": "The summary chip beside the record H1 now resolves its field label through fieldLabel(), the same helper HeaderHighlight and DetailSection already call, at all THREE of its name sites (the string branch's aria-label, the percent branch's aria-label, and the renderer-backed branch's sr-only prefix) — the card assumed one site, which was wrong. ZONE 2 B: the objectui#8394 pin DOES move, and a census found the hazard is broader than the filing seat recorded — objectui#8464's pin moves too, 6 assertions across 2 files, measured by running the four chip pins against the fixed source before touching any instrument. Both owning cards have landed (PR #8457 and PR #8732 merged), so nothing in flight was reached into; rather than re-baseline silently, objectui#8394's chipFor was re-derived onto the data-summary-chip handle — the remedy that card's own docblock prescribes for exactly this failure shape (objectui#8506) and the one the card text suggested — its emptiness answers are asserted on the same fields with the same data, and the one NAME assertion plus objectui#8464's four are re-pinned with docblock notes; the whole measurement is in the PR body. ZONE 2 A: objectName WAS in scope as schema.objectName, so the sibling call is available — but the card's claim that fieldLabel itself was already in scope was inaccurate: the file called useSafeFieldLabel() and destructured only fieldOptionLabel. ZONE 2 C also fell: aria-label is the whole accessible name only for the string and percent branches; the renderer-backed chip's computed accessible name is the EMPTY string (a Badge is a role=generic div and takes no name from content), so its sr-only prefix is what a reader is READ, not a name — measured, and each branch is pinned by the mechanism actually live on it. needs:contract-review is hung additively on both carriers and read back on both; check-clause2-carriers --pair 9093 exits 0.",
"tests": "pnpm exec vitest run packages/plugin-detail/ -> 'Test Files 164 passed (164) / Tests 1537 passed (1537)'. New pin summaryChip.fieldLabel-8729.test.tsx, 9 cases. Type-check: dependency closure built first (pnpm --filter '@object-ui/plugin-detail^...' build -> ===BUILD OK===), then pnpm --filter @object-ui/plugin-detail run type-check -> ===TYPECHECK OK=== (tsc --noEmit plus tsc -p tsconfig.test.json); a first run against an UNBUILT closure said "Cannot find module '@object-ui/components'" for the whole package — the stale-dist trap, not a reading. The new pin is proven inside the typechecked set: tsc -p tsconfig.test.json --listFiles lists summaryChip.fieldLabel-8729.test.tsx (1 hit). eslint packages/plugin-detail -> 219 files, 0 errors, 986 pre-existing no-explicit-any warnings; narrowing evidence: universe is per-package 'eslint .' under turbo run lint and the WHOLE affected package was linted, count read from --format json, and the flat config declares no parserOptions.project/projectService so type-aware linting is off and this diff cannot move an untouched file's verdict. A first pass with --no-inline-config reported 3 errors in untouched files — that flag is an objectstack-ism, not this repo's invocation; it disables legitimate inline disables. Not a finding. Gates: check-changeset-presence 'no changeset' before -> '4 source file(s) ... declares 1 changeset(s)' after; check-changeset-no-major 'No changeset declares a major bump'; check-control-bytes 'OK (scanned 7278 tracked text file(s))'; check-new-cross-file-line-citations '0 new citation(s) -> exit 0'; check-governed-queue-guard --test 'NOT GOVERNED — 3 path(s) checked against 5 governed surface(s); none matched'. ABLATION, from the committed fix, prediction written first, two legs, each mutated on disk and proven by blob hash (HEAD blob 4ea0afedb2eafe6cf7cb248b94da7f8132693373), restored with 'git checkout HEAD --' and proven by hash plus empty 'git diff HEAD', both under an EXIT INT TERM trap with absolute paths; no build needed because the root vitest config aliases these packages to source, which is what makes a source-only edit move the result. LEG A (fix removed, all three sites print the stored column): predicted 7 of 9 red with the two byte-identical controls green and objectui#9072's seam file fully green — measured exactly that, 7 failed / 13 passed of 20, red case-for-case as predicted. LEG B (label read locally instead of through the siblings' resolver): predicted only 'A TRANSLATED SESSION' red — measured exactly that, 1 failed / 19 passed. Leg B is the leg that discriminates the ruling. CI convergence not awaited (PM's).",
"mcp_calls": "5 — issue_read get 8729, issue_read get_comments 8729, issue_read get 8394, issue_read get 8464, create_pull_request. Labels, label read-back and PR body read-back went over repo-scoped REST (probed first: GET .../issues/8729/labels returned 200).",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
os-litant commentedon Sep 10, 2026
Triage: lands in
packages/plugin-detail/src/DetailView.tsx(effectiveSummaryFields.map);domain:ui;priority:p3.The chip has no visible label, so
aria-label={${fieldName}: ${display}}is its entire accessible name — andfieldNameis the raw stored column name. Every other band on the same page resolves a label (HeaderHighlight→fieldLabel(objectName, field.name, field.label);DetailSection→ the section field'slabel). ⇒ one band out of several exposes the database spelling, and it is the band a screen-reader user hears.⇒ p3 on blast radius, but ⭐ the consistency argument is the strong one: the resolution helper already exists and is used by its siblings on the same page, so this is a divergence from an established in-repo pattern rather than a missing capability.
Size/model suggestion:S.分诊席位 ·
session_017VGfRocA8VjczSe84fgjY3· R+166 · 2026-09-10T13:57Z · 本评论来自分诊座位Generated by Claude Code
os-steve commentedon Sep 10, 2026
Claim: the
domain:uiPM seat (session_01MPaVWWMuWeT5LgB1qoXjVB, GitHub identityos-steve) claims objectui#8729 and dispatches it to oneos-devseat in a dedicated worktree.Clause-②: yes
Why yes
DetailViewis published, and the chip's accessible name changes for input it accepts today — a screen-reader user stops hearing the raw stored column name. Published component, observable output, accepted input.aria-labelis output, not decoration: it is this chip's entire accessible name, since the chip has no visible label.⭐ Per §0a of the seat post, the dev HANGS
needs:contract-reviewon both carriers with the draft PR (additively —POST .../issues/N/labelsadds; a full update replaces) and reports the--pair Nexit code; this seat clears both on PASS.⭐ The serial constraint is DISCHARGED
Triage fenced this against objectui#8728 — same
effectiveSummaryFields.maprender, "serial, ⛔ not folded". objectui#8728 landed minutes ago as PR objectui#9072 (2a79e847b), verified by content. ⇒ the face is free.⭐ And objectui#9072's dev left this card a clean handoff rather than a collision: their new pin "asserts only the percentage half of the accessible name, so that card keeps a free hand over the field-name half."⚠️ That is a deliberate seam — ⛔ do not treat the existing assertion as a pin that must be preserved verbatim if the field-name half genuinely needs to move; it was written to let it.
The filing seat recorded that changing this in objectui#8464 would have moved a pin objectui#8394 owns. ⇒ check that pin before editing. If the fix moves it, ⛔ do not silently re-baseline — coordinate, and say so in the PR body. A p3 accessibility fix that quietly re-baselines another card's pin is a worse trade than the fix is worth.
The consistency argument is the ruling
⭐ Triage's strong reason, and the one to design against: the resolution helper already exists and is used by this chip's siblings on the same page —
HeaderHighlight→fieldLabel(objectName, field.name, field.label),DetailSection→ the section field'slabel. ⇒ this is a divergence from an established in-repo pattern, not a missing capability. ⛔ Do not invent a fourth resolution path; call the one the siblings call.packages/plugin-detail/src/DetailView.tsxmoved minutes ago (objectui#9072 extractedsummaryChipPercent.tsand rewrote the percent branch). Re-derive by symbol on today'sorigin/main; ⛔ cite no line.PM seat ·
domain:ui@ objectui · seat post objectui#5560 · claim written before the agent launch (§0b⑤)Generated by Claude Code
claude commentedon Sep 11, 2026
os-dev-report
{
"issue": 8729,
"status": "done",
"branch": "claude/issue-8729-summary-chip-accessible-name",
"pr": "#9093",
"premise_still_valid": true,
"summary": "The summary chip beside the record H1 now resolves its field label through fieldLabel(), the same helper HeaderHighlight and DetailSection already call, at all THREE of its name sites (the string branch's aria-label, the percent branch's aria-label, and the renderer-backed branch's sr-only prefix) — the card assumed one site, which was wrong. ZONE 2 B: the objectui#8394 pin DOES move, and a census found the hazard is broader than the filing seat recorded — objectui#8464's pin moves too, 6 assertions across 2 files, measured by running the four chip pins against the fixed source before touching any instrument. Both owning cards have landed (PR #8457 and PR #8732 merged), so nothing in flight was reached into; rather than re-baseline silently, objectui#8394's chipFor was re-derived onto the data-summary-chip handle — the remedy that card's own docblock prescribes for exactly this failure shape (objectui#8506) and the one the card text suggested — its emptiness answers are asserted on the same fields with the same data, and the one NAME assertion plus objectui#8464's four are re-pinned with docblock notes; the whole measurement is in the PR body. ZONE 2 A: objectName WAS in scope as schema.objectName, so the sibling call is available — but the card's claim that fieldLabel itself was already in scope was inaccurate: the file called useSafeFieldLabel() and destructured only fieldOptionLabel. ZONE 2 C also fell: aria-label is the whole accessible name only for the string and percent branches; the renderer-backed chip's computed accessible name is the EMPTY string (a Badge is a role=generic div and takes no name from content), so its sr-only prefix is what a reader is READ, not a name — measured, and each branch is pinned by the mechanism actually live on it. needs:contract-review is hung additively on both carriers and read back on both; check-clause2-carriers --pair 9093 exits 0.",
"tests": "pnpm exec vitest run packages/plugin-detail/ -> 'Test Files 164 passed (164) / Tests 1537 passed (1537)'. New pin summaryChip.fieldLabel-8729.test.tsx, 9 cases. Type-check: dependency closure built first (pnpm --filter '@object-ui/plugin-detail^...' build -> ===BUILD OK===), then pnpm --filter @object-ui/plugin-detail run type-check -> ===TYPECHECK OK=== (tsc --noEmit plus tsc -p tsconfig.test.json); a first run against an UNBUILT closure said "Cannot find module '@object-ui/components'" for the whole package — the stale-dist trap, not a reading. The new pin is proven inside the typechecked set: tsc -p tsconfig.test.json --listFiles lists summaryChip.fieldLabel-8729.test.tsx (1 hit). eslint packages/plugin-detail -> 219 files, 0 errors, 986 pre-existing no-explicit-any warnings; narrowing evidence: universe is per-package 'eslint .' under turbo run lint and the WHOLE affected package was linted, count read from --format json, and the flat config declares no parserOptions.project/projectService so type-aware linting is off and this diff cannot move an untouched file's verdict. A first pass with --no-inline-config reported 3 errors in untouched files — that flag is an objectstack-ism, not this repo's invocation; it disables legitimate inline disables. Not a finding. Gates: check-changeset-presence 'no changeset' before -> '4 source file(s) ... declares 1 changeset(s)' after; check-changeset-no-major 'No changeset declares a major bump'; check-control-bytes 'OK (scanned 7278 tracked text file(s))'; check-new-cross-file-line-citations '0 new citation(s) -> exit 0'; check-governed-queue-guard --test 'NOT GOVERNED — 3 path(s) checked against 5 governed surface(s); none matched'. ABLATION, from the committed fix, prediction written first, two legs, each mutated on disk and proven by blob hash (HEAD blob 4ea0afedb2eafe6cf7cb248b94da7f8132693373), restored with 'git checkout HEAD --' and proven by hash plus empty 'git diff HEAD', both under an EXIT INT TERM trap with absolute paths; no build needed because the root vitest config aliases these packages to source, which is what makes a source-only edit move the result. LEG A (fix removed, all three sites print the stored column): predicted 7 of 9 red with the two byte-identical controls green and objectui#9072's seam file fully green — measured exactly that, 7 failed / 13 passed of 20, red case-for-case as predicted. LEG B (label read locally instead of through the siblings' resolver): predicted only 'A TRANSLATED SESSION' red — measured exactly that, 1 failed / 19 passed. Leg B is the leg that discriminates the ruling. CI convergence not awaited (PM's).",
"mcp_calls": "5 — issue_read get 8729, issue_read get_comments 8729, issue_read get 8394, issue_read get 8464, create_pull_request. Labels, label read-back and PR body read-back went over repo-scoped REST (probed first: GET .../issues/8729/labels returned 200).",
"open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code