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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Studio Validations editor on a read-only package: ~20 disabled controls give no reason (no tooltip, no aria-describedby, no keyboard path) #12691
Filing gate ①: a user-visible product defect with a named landing and a reproduction. Reach: Studio on a read-only (code) package, reproduced 2/2 after a screenshot confirmed the render.
Reader who acts: the objectui Studio lane seat owning the Validations editor in the Data pillar. Apply the same read-only-reason treatment objectui#12303 gave the Field-properties inspector.
What
On a read-only package, the Studio Validations editor renders about 20 disabled controls with no stated reason:
no tooltip on hover;
no title or aria-describedby;
no keyboard path (Tab never focuses them).
The Publish button and the Enabled toggle on the same page do carry the reason: "Read-only package — switch to or create a writable package to edit."
As admin, open /_console/studio/com.example.showcase/data?surface=object%3Ashowcase_task.
Click Validations. The rule "Task Status Flow" opens.
Hover the Severity combobox ("error (rejects the save)") for 1.5 s. No [role=tooltip] appears, and no title / aria-describedby / tabindex is set on it or its ancestors.
Tab through the page: no form control receives focus.
Expected: hover and keyboard reach the read-only reason, as Publish and Enabled do.
Dedupe
MCP search_issues on objectstack-ai/objectui, closed included → 11 hits, none matching (by the cloud runner). objectui#12303 names only the Field-properties inspector.
Claim: PM loop round 7 (priority:p3; triage grade 6218493223)
Session: session_011K9g23W67dy2zwnyzaoB6o
Account: os-tesla
Branch: claude/issue-12691-validations-readonly-reason
Worktree: objectui-issue-12691 (in the cloud session's own container)
Domain: domain:ui
Seat: domain:ui#1
File surface: the Studio Data pillar's Validations editor on a read-only package.
packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx (ObjectValidationsPanel, which takes disabled from its mount): on a read-only package the editor states the existing reason (engine.studio.pkg.readonlyHint, "Read-only package — switch to or create a writable package to edit.") so hover and keyboard reach it, by the treatment objectui#12303 gave the Field-properties inspector and Publish / Enabled already wear (a tooltip wrapper and an aria-describedby reason);
its mount in StudioDesignSurface.tsx (viewMode === 'rules', near :6152 at main33ee9de) only if the reason must be passed down;
tests beside them;
one .changeset/12691-*.md for @object-ui/app-shell.
Outside the surface: the other Data pillar panels (Settings, Hooks, Actions), which take the same disabled; the read-only state itself (triage: "The read-only state itself is right"); and any new language-pack or dictionary key (the reason string exists).
A route outside the surface stops and reports (stop on breach; explain in the report).
Container & model: S, mode:cloud, model: opus (default tier; no path-derived mandate)
Clause-②: no
Clause-② reason: a disabled editor gains a stated reason through an existing string. No prop, export or key changes. If the reason must reach the panel as a new prop, the prop is module-internal to app-shell (the panel is not exported); if it turns out exported, line 2 becomes Clause-②: yes and the body says so.
Responsibility: the Studio Data pillar's Validations editor (@object-ui/app-shellObjectValidationsPanel) | objectui#12303 gave the Field-properties inspector the read-only-reason treatment; Publish and the Enabled toggle on the same page already carry it | every admin who opens a code package's object rules in Studio
Thread-read: 6218493223
Serial constraints cleared: read at objectui main33ee9de. No open PR names ObjectValidationsPanel.tsx or StudioDesignSurface.tsx (every open PR's file list was read: #12818, #12822, #12823, #12824, #12825, #12826, #12827). The in-flight area:studio cards are disjoint: this seat's objectui#12780 (flow-node-config and its tests) and objectui#12690 (ResourceEditPage.tsx, metadata-admin/i18n.ts), and seat-held objectui#12768 (the metadata directory page).
{
"issue": 12691,
"status": "done",
"branch": "claude/issue-12691-validations-readonly-reason",
"pr": "https://github.com/objectstack-ai/objectui/pull/12833",
"session": "session_01KRbDaSjHueddhNPJ9LH6Pd",
"premise_still_valid": true,
"summary": "On a read-only package, the body of the Validations rule editor now gets the read-only-reason treatment that objectui#12303 gave the Field properties rail. The body is a focusable group named by the panel title. It is described by an sr-only copy of engine.studio.pkg.readonlyHint, and it opens a tooltip with that reason on hover or focus. The controls stay disabled, and a writable package renders exactly as before. The change is in ObjectValidationsPanel.tsx only: the panel already has the locale and the disabled flag, so the StudioDesignSurface mount is unchanged. No new key, prop or export. H1 confirmed: at 33ee9de the editor controls carry no title, aria-describedby or tab stop; live Tab lands on BODY and hover shows no tooltip. H2 measured: #12303 used ONE wrapper for a panel with many controls (the rail body: role=group, tabIndex 0, aria-describedby pointing at an sr-only span, TooltipTrigger asChild), not one per control, so this reuses that shape. H3 confirmed: the en and zh rows exist and are reused.",
"tests": "New file ObjectValidationsPanel.readOnlyReason-12691.test.tsx: `pnpm exec vitest run packages/app-shell/src/views/studio-design/ObjectValidationsPanel.readOnlyReason-12691.test.tsx` gives 'Tests 7 passed (7)', VERDICT command-exit 0, at 158ee06. Covered: in en-US and zh-CN, the body is described by the reason and named by the panel title, and holds at least 6 disabled controls; hovering the disabled Severity picker opens a tooltip with the reason; Tab from the rule list lands on the described body and the tooltip opens; CONTROL on a writable package: no data-disabled-reason, no aria-describedby, reason text absent, controls enabled. Ablation: the panel was replaced with its 33ee9de blob (data-disabled-reason count 0, readonlyHint count 0, with a trap to restore) and the run gave 'Tests 6 failed | 1 passed (7)', VERDICT command-exit 1. Only the CONTROL stayed green, as expected. Restored with `git checkout HEAD --`: hash-object 4722e2f4c80e equals the HEAD blob 4722e2f4c80e, and `git diff HEAD` is empty. The test imports the panel through a relative src path, so no dist step applies. Families: every test under packages/, apps/ and scripts/__tests__ that names ObjectValidationsPanel, readonlyHint, ReadOnlyReason or StudioDesignSurface (182 files) gives 'Test Files 182 passed (182) / Tests 1518 passed (1518)', VERDICT command-exit 0, on head 700571b after the merge. Live reading (e2e/live/ci/start-backend.sh on :4612 with published @objectstack/cli@18.0.0-next.2 showcase@e5136ff10f1a, console vite on :5612, page /studio/com.example.showcase/data?surface=object%3Ashowcase_task, Validations tab): BEFORE (33ee9de blob swapped in, then restored with hash equal to HEAD): hover tooltip [], Tab focus BODY. AFTER: hover tooltip ['Read-only package — switch to or create a writable package to edit.'], Tab focus DIV role=group, described by the same reason, tooltip open. PNGs are on claude/issue-12691-evidence@f19092a under evidence/12691/ (before-hover, before-tab, after-hover, after-tab); the probe logs were gitignored and are quoted here.",
"gates": "Every exit code was captured before any pipe. On head 700571b: `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build && pnpm --filter @object-ui/app-shell type-check`, VERDICT command-exit 0 (the type-check script name was echoed). Whether type-check includes the test files was not counted with --listFiles; vitest ran them. check:i18n-keys 0, check:i18n-dead-keys 0, check:changeset-claims 0 ('No pending changeset names a file this change touches'), changeset:check 0, check:test-path-roots 0, check:spec-symbols 0, check:new-line-citations 0 ('0 new citation(s)'), `node scripts/check-changeset-presence.mjs` 0 ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'). eslint on the 2 changed files: exit 0, 0 errors, 1 warning (react-hooks/set-state-in-effect in pre-existing panel code, not in this diff). The gate list was derived by hand from package.json and ci.yml (objectui has no dispatch-gates.mjs). CI check-runs: NOT MEASURED, reason: no PR yet; the seat opens it.",
"mcp_calls": "3 — mcp__github__issue_read (get, get_comments) on #12691, plus ToolSearch to load it. All reads, no write tool.",
"api_writes": "0 REST writes. git pushes: claude/issue-12691-validations-readonly-reason (new branch, 700571b) and claude/issue-12691-evidence (new branch, f19092a, one commit on top of 700571b).",
"open_questions": [
{
"question": "Tooltip placement: side=left, align=start copies the #12303 rail. In this two-pane layout the tooltip sits over the top of the rule list (the panel header) while it is open. Keep it, or use side=top?",
"options": [
"A keep side=left (one pattern, matches #12303)",
"B side=top for this panel only"
],
"recommendation": "A, because the brief bars a second pattern and the overlap only lasts while the tooltip is open. after-hover.png shows it."
}
],
"out_of_scope_findings": [
"class: a (suspected, not reproduced) · reach: none measured: Settings, Hooks and Actions get the same `disabled={readOnly}` at their StudioDesignSurface mounts, and the claim lists them as outside the surface. Whether their disabled controls give a reason was not read live · evidence: the mount props ObjectSettingsPanel / ObjectHooksPanel / ObjectActionsPanel disabled={readOnly} next to the rules mount · dedupe words: read-only reason, Settings panel, Hooks panel, Actions panel, disabled controls · carrier: none, noted only",
"carrier: none · noted, not filed: the eslint react-hooks/set-state-in-effect warning in ObjectValidationsPanel.tsx predates this diff"
]
}
Posted by the domain:ui seat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filled pr with the draft PR it opened, #12833.
The Settings / Hooks / Actions finding is recorded, not filed: suspected from the mount props, not read live. The seat is signing off at the maintainer's word and does not claim new work; it names this in the seat's sign-off ledger so the next seat or triage can measure it.
Verified by content: the merge commit's own diff equals the PR's diff from its merge-base 4839f5c to the reviewed head 700571b, changed line for changed line in each of the 3 files (+187/−4). Positive control at the merge commit: ObjectValidationsPanel.tsx declares const readOnlyReasonId = React.useId();.
Card: closed completed by Fixes #12691. This note precedes the strip of pm:dispatched, and the cloud session is archived.
Next, outside this card: none filed. Whether the Settings, Hooks and Actions panels state their read-only reason stays unmeasured, as recorded in the acceptance; objectui#12718 (StudioDesignSurface.tsx) no longer waits on this card's surface.
Activity
objectstack-fleet commentedon Oct 16, 2026
Triage: first grade,
bug·priority:p3·domain:ui·area:studio·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T15:10ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
domain:ui. Apply objectui#12303's read-only-reason treatment to the Validations editor.objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop round 7 (
priority:p3; triage grade6218493223)Session:
session_011K9g23W67dy2zwnyzaoB6oAccount:
os-teslaBranch:
claude/issue-12691-validations-readonly-reasonWorktree:
objectui-issue-12691(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#1File surface: the Studio Data pillar's Validations editor on a read-only package.
packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx(ObjectValidationsPanel, which takesdisabledfrom its mount): on a read-only package the editor states the existing reason (engine.studio.pkg.readonlyHint, "Read-only package — switch to or create a writable package to edit.") so hover and keyboard reach it, by the treatment objectui#12303 gave the Field-properties inspector and Publish / Enabled already wear (a tooltip wrapper and anaria-describedbyreason);StudioDesignSurface.tsx(viewMode === 'rules', near:6152atmain33ee9de) only if the reason must be passed down;.changeset/12691-*.mdfor@object-ui/app-shell.Outside the surface: the other Data pillar panels (Settings, Hooks, Actions), which take the same
disabled; the read-only state itself (triage: "The read-only state itself is right"); and any new language-pack or dictionary key (the reason string exists).A route outside the surface stops and reports (stop on breach; explain in the report).
Container & model:
S,mode:cloud,model: opus(default tier; no path-derived mandate)Clause-②: no
Clause-② reason: a disabled editor gains a stated reason through an existing string. No prop, export or key changes. If the reason must reach the panel as a new prop, the prop is module-internal to app-shell (the panel is not exported); if it turns out exported, line 2 becomes
Clause-②: yesand the body says so.Responsibility: the Studio Data pillar's Validations editor (
@object-ui/app-shellObjectValidationsPanel) | objectui#12303 gave the Field-properties inspector the read-only-reason treatment; Publish and the Enabled toggle on the same page already carry it | every admin who opens a code package's object rules in StudioThread-read: 6218493223
Serial constraints cleared: read at objectui
main33ee9de. No open PR namesObjectValidationsPanel.tsxorStudioDesignSurface.tsx(every open PR's file list was read: #12818, #12822, #12823, #12824, #12825, #12826, #12827). The in-flightarea:studiocards are disjoint: this seat's objectui#12780 (flow-node-configand its tests) and objectui#12690 (ResourceEditPage.tsx,metadata-admin/i18n.ts), and seat-held objectui#12768 (the metadata directory page).Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
os-dev-report
{ "issue": 12691, "status": "done", "branch": "claude/issue-12691-validations-readonly-reason", "pr": "https://github.com/objectstack-ai/objectui/pull/12833", "session": "session_01KRbDaSjHueddhNPJ9LH6Pd", "premise_still_valid": true, "summary": "On a read-only package, the body of the Validations rule editor now gets the read-only-reason treatment that objectui#12303 gave the Field properties rail. The body is a focusable group named by the panel title. It is described by an sr-only copy of engine.studio.pkg.readonlyHint, and it opens a tooltip with that reason on hover or focus. The controls stay disabled, and a writable package renders exactly as before. The change is in ObjectValidationsPanel.tsx only: the panel already has the locale and the disabled flag, so the StudioDesignSurface mount is unchanged. No new key, prop or export. H1 confirmed: at 33ee9de the editor controls carry no title, aria-describedby or tab stop; live Tab lands on BODY and hover shows no tooltip. H2 measured: #12303 used ONE wrapper for a panel with many controls (the rail body: role=group, tabIndex 0, aria-describedby pointing at an sr-only span, TooltipTrigger asChild), not one per control, so this reuses that shape. H3 confirmed: the en and zh rows exist and are reused.", "tests": "New file ObjectValidationsPanel.readOnlyReason-12691.test.tsx: `pnpm exec vitest run packages/app-shell/src/views/studio-design/ObjectValidationsPanel.readOnlyReason-12691.test.tsx` gives 'Tests 7 passed (7)', VERDICT command-exit 0, at 158ee06. Covered: in en-US and zh-CN, the body is described by the reason and named by the panel title, and holds at least 6 disabled controls; hovering the disabled Severity picker opens a tooltip with the reason; Tab from the rule list lands on the described body and the tooltip opens; CONTROL on a writable package: no data-disabled-reason, no aria-describedby, reason text absent, controls enabled. Ablation: the panel was replaced with its 33ee9de blob (data-disabled-reason count 0, readonlyHint count 0, with a trap to restore) and the run gave 'Tests 6 failed | 1 passed (7)', VERDICT command-exit 1. Only the CONTROL stayed green, as expected. Restored with `git checkout HEAD --`: hash-object 4722e2f4c80e equals the HEAD blob 4722e2f4c80e, and `git diff HEAD` is empty. The test imports the panel through a relative src path, so no dist step applies. Families: every test under packages/, apps/ and scripts/__tests__ that names ObjectValidationsPanel, readonlyHint, ReadOnlyReason or StudioDesignSurface (182 files) gives 'Test Files 182 passed (182) / Tests 1518 passed (1518)', VERDICT command-exit 0, on head 700571b after the merge. Live reading (e2e/live/ci/start-backend.sh on :4612 with published @objectstack/cli@18.0.0-next.2 showcase@e5136ff10f1a, console vite on :5612, page /studio/com.example.showcase/data?surface=object%3Ashowcase_task, Validations tab): BEFORE (33ee9de blob swapped in, then restored with hash equal to HEAD): hover tooltip [], Tab focus BODY. AFTER: hover tooltip ['Read-only package — switch to or create a writable package to edit.'], Tab focus DIV role=group, described by the same reason, tooltip open. PNGs are on claude/issue-12691-evidence@f19092a under evidence/12691/ (before-hover, before-tab, after-hover, after-tab); the probe logs were gitignored and are quoted here.", "gates": "Every exit code was captured before any pipe. On head 700571b: `pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build && pnpm --filter @object-ui/app-shell type-check`, VERDICT command-exit 0 (the type-check script name was echoed). Whether type-check includes the test files was not counted with --listFiles; vitest ran them. check:i18n-keys 0, check:i18n-dead-keys 0, check:changeset-claims 0 ('No pending changeset names a file this change touches'), changeset:check 0, check:test-path-roots 0, check:spec-symbols 0, check:new-line-citations 0 ('0 new citation(s)'), `node scripts/check-changeset-presence.mjs` 0 ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'). eslint on the 2 changed files: exit 0, 0 errors, 1 warning (react-hooks/set-state-in-effect in pre-existing panel code, not in this diff). The gate list was derived by hand from package.json and ci.yml (objectui has no dispatch-gates.mjs). CI check-runs: NOT MEASURED, reason: no PR yet; the seat opens it.", "mcp_calls": "3 — mcp__github__issue_read (get, get_comments) on #12691, plus ToolSearch to load it. All reads, no write tool.", "api_writes": "0 REST writes. git pushes: claude/issue-12691-validations-readonly-reason (new branch, 700571b) and claude/issue-12691-evidence (new branch, f19092a, one commit on top of 700571b).", "open_questions": [ { "question": "Tooltip placement: side=left, align=start copies the #12303 rail. In this two-pane layout the tooltip sits over the top of the rule list (the panel header) while it is open. Keep it, or use side=top?", "options": [ "A keep side=left (one pattern, matches #12303)", "B side=top for this panel only" ], "recommendation": "A, because the brief bars a second pattern and the overlap only lasts while the tooltip is open. after-hover.png shows it." } ], "out_of_scope_findings": [ "class: a (suspected, not reproduced) · reach: none measured: Settings, Hooks and Actions get the same `disabled={readOnly}` at their StudioDesignSurface mounts, and the claim lists them as outside the surface. Whether their disabled controls give a reason was not read live · evidence: the mount props ObjectSettingsPanel / ObjectHooksPanel / ObjectActionsPanel disabled={readOnly} next to the rules mount · dedupe words: read-only reason, Settings panel, Hooks panel, Actions panel, disabled controls · carrier: none, noted only", "carrier: none · noted, not filed: the eslint react-hooks/set-state-in-effect warning in ObjectValidationsPanel.tsx predates this diff" ] }Posted by the
domain:uiseat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filledprwith the draft PR it opened, #12833.The seat's answers:
side="left". One pattern with the console UX conventions (family card): inline-edit Save All and Studio Discard draft give no feedback, and Studio's read-only Field properties controls are disabled with no reason and no keyboard path to one #12303 rail; the overlap lasts only while the tooltip is open.700571b: 3 files, +187/−4,ObjectValidationsPanel.tsxonly in source. On a read-only package the editor body becomes onerole="group"tab stop witharia-describedbyon ansr-onlycopy ofengine.studio.pkg.readonlyHintand the tooltip trigger, exactly the console UX conventions (family card): inline-edit Save All and Studio Discard draft give no feedback, and Studio's read-only Field properties controls are disabled with no reason and no keyboard path to one #12303 shape; a writable package takes the unchangeddiv. No key, prop or export:Clause-②: nostands.700571b, then the ACCEPT.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Landed ·
domain:uiseat 1 ·session_011K9g23W67dy2zwnyzaoB6o· 2026-10-17T00:56Zmaind0a00d7950, with one parent,2ff84f8. It is an ancestor oforigin/main.4839f5cto the reviewed head700571b, changed line for changed line in each of the 3 files (+187/−4). Positive control at the merge commit:ObjectValidationsPanel.tsxdeclaresconst readOnlyReasonId = React.useId();.completedbyFixes #12691. This note precedes the strip ofpm:dispatched, and the cloud session is archived.StudioDesignSurface.tsx) no longer waits on this card's surface.Generated by Claude Code
fix(app-shell): the Studio Validations editor says why it is read-onl…