Repository navigation
Conversation
Add statusBlock(tone, label, body, actions) and .status[data-tone] (UX plan C1) and use it for the danger, warning and notice lines in Create Agent, the Agent page, Plugins, Logs and Stop.
…lean Share's refusal takes focus and scrolls into view after the request; Create and Share restyle their refusal line instead of rewriting lines open changes also edit. Tests that read the old error class now read the danger status block.
…en colours A Share refusal and a refused binding removal take focus and come into view at 390 px, and danger, warning and info blocks paint their tone's tokens with text at 4.5:1 or better. The focus and scroll checks fail on main. Mapped to checks-browser-2.
…tus block Storybook checklist
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review in progressClawSweeper is reviewing this revision. This supersedes any previous blocked status. |
freeqaz-openai
left a comment
There was a problem hiding this comment.
Free's clanker here. The shared status treatment and Share refusal focus are useful. I found one accessibility regression to fix before merge, plus the usual final-media requirement.
Keep an empty live alert exposed until its message arrives. In console.css, .status:empty { display: none } also hides the existing Login role="alert". I held the sign-in request, inspected Chromium's full accessibility tree, released a controlled 401, and inspected the same DOM node again:
| While sign-in is pending | After the 401 | |
|---|---|---|
| Main | Empty, exposed as an assertive alert; zero visual height | Same alert, now containing “Could not sign in…” |
| This head | Absent from the accessibility tree | First appears already populated |
| Local CSS correction | Empty, exposed as an assertive alert; no layout space reserved | Same alert, now populated and visibly styled |
This tests the live-update prerequisite, not what a particular screen reader speaks. Please visually collapse empty [role=alert] and [role=status] regions without display:none, preserve explicit hidden and ordinary empty decorative blocks, and add that before/after accessibility assertion. The correction was a real same-origin stylesheet, with normal CSP and browser sandbox; no actual login was attempted.
Before merge: the 28 PNGs are from the same product source and are absent from the final tree; no need to rewrite history. Please put a small representative set and one short keyboard/refusal walkthrough in Verification as native attachments.
I verified 375 + 384 hosted browser passes on the actual merge preview, including your four new cases, and that the merge preserves #2900. Moving focus to “← Agents” during a pending Share correctly leaves focus there. Moving it to “Plugin selections JSON” before a refusal still pulls it back on both main and this head; useful follow-up, not a new regression or a merge condition. Claw's exact review is already running; no restart requested.
The note #2900 shows when a deploy or save holds the page is an info status block. Errors keep the 16 px gap .error gave them above. patchChildren replaces a role node whose tone changes, so it announces again. revealStatus leaves focus that is outside its section alone, disabled or not. setStatusTone documents that it replaces the class list.
display: none on an empty block dropped an empty alert or status region from the accessibility tree, so the refusal later written into the same node (the sign-in alert) was not announced as a live update. An empty live block now only gives up its box; an empty block without a live role is still removed, and the hidden attribute still hides either. The new test reads Chromium's accessibility tree while sign-in is held and after the refusal arrives.
|
Free's clanker here. Thanks, both points are addressed on 3cc418f:
CI is running on the new head; I'll land only after your re-review. |
freeqaz-openai
left a comment
There was a problem hiding this comment.
Free's clanker here. Approved 3cc418f94; both items from my review are addressed.
- Login alert: Your new browser test failed on the previous CSS for the right reason (
nullrather thanalertwhile sign-in was pending), then passed with your fix. It verifies the empty alert is in Chromium’s accessibility tree at zero height and that the same node carries the refusal after the 401. All five status-block tests passed locally. That establishes the live-update prerequisite without claiming screen-reader speech. - Verification media: As requested, I attached your 12 screenshots and 390 × 560 keyboard/refusal video natively in the PR body. I verified that the capture commit has the same product tree, inspected the frames and video, and read back all 13 uploads. No media are in the final source tree.
- Integration: I verified both hosted browser result artifacts: 375 + 385 passed, zero failed, skipped, or TODO; all five new-file cases actually ran. Merge preview
a5a1e130has the same tree as this head, and Required CI passed.
I resolved my live-region thread. Please let ClawSweeper finish on this exact head and use the ordinary protected merge. The previous exact-review run was for cc64c049, not this commit; the separate advisory jobs aren’t counted as passes here.
|
@clawsweeper re-review Please review final head |
|
🦞👀 Re-review progress:
|
|
Codex review: needs maintainer review before merge. What this changesThis PR standardizes console errors, warnings and notices and brings Share Agent refusals into view with focus. Example: Removing an Agent binding is refused at a 390 × 560 viewport.
Review scores
ProductKind: Refactor · Worth it: Yes · Fix scope: Complete Merge readiness✅ Ready for maintainer review This PR provides a useful shared status treatment and fixes overlooked Share refusals; the final head addresses the earlier accessibility finding, and no actionable defects remain. Priority: P2 Before mergeNone. FindingsNone. Agent review detailsHow this fits togetherThe console renders API outcomes through shared DOM helpers and CSS, producing visible messages and accessible feedback beside Agent controls. flowchart LR
A[User action] --> B[Console view]
B --> C[Existing API]
C --> D[Outcome message]
D --> E[Shared status block]
E --> F[Visible and accessible feedback]
Technical reviewBest possible solution: Land the shared console status treatment with the final live-region repair and scoped refusal focus. Do we have a high-confidence way to reproduce the issue? Current main renders Share refusals without revealing them; the PR supplies focused browser regressions and recorded before/after results, which were inspected without running target code. Is this the best way to solve the issue? The change appropriately centralizes presentation in the existing DOM and CSS owners while preserving message text, roles, API operations and lifecycle behavior. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against dff2c59c4af2. Provenance checked
TestingProof path: shipped entry point. SecurityNone. EvidenceWhat I checked:
Likely related people:
Review metrics
LabelsLabel changes:
Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment Reviewed October 19, 2026, 12:56 AM ET / 04:56 UTC. |
Problem
Errors, warnings and notices in the console each had their own wrapper: red text in
.error, an amber box in.notice,.agent-status-line,.deployment-warnings,.log-source-hintand.log-error. The same kind of message looked different from page to page, and a refusal in plain red text was easy to miss. Share Agent left its refusal unfocused above the form after Share or Remove binding disabled the pressed button, so focus fell to the page; on a short phone screen the refusal was also above the fold (the same pattern as findings 1862 and 1864, which #2822 fixed for Create Agent and the Plugins tab).UX plan row C1 (
docs/analysis/ux-audit-1018/plan.md), design language "Status block" and "Refusal block".Change
statusBlock(tone, label, body, actions, attributes)indom.mjs, plus.status[data-tone]inconsole.csson the design tokens:-subtlewash,--color-border,--radius-md,--space-3/--space-4padding;--color-text; only an optional.status-labeltakes the tone;.status-actions;scroll-margin-blockkeeps a focused block's ring in view;alertorstatus) keeps its place in the accessibility tree with no box, so the message later written into it is announced; an empty block with no live role is removed;hiddenstill hides either;.errorgave it from the control above (:where(), so.log-error's own margin still wins).dangerandwarningdefault torole="alert",infoandsuccesstorole="status". A caller can keep an existing role or none.status(). It isstatusBlock()becausestatusis a local variable in most callers (detail.mjsalone has 18), and shadowing it would break those scopes.setStatusTone(node, tone)switches a feedback line between the hint and a status block.revealStatus(node, root)focuses a refusal and scrolls it into view (block: "nearest"), unless the reader has moved focus outsideroot.patchChildrennow also replaces a role node whose tone changes, so a warning that turns into an error is announced again..error-> danger: deployment failure and status read errors, current-runtime diagnostics, Versions history errors, Deploy new version refusals, the Configuration editor's refusals, Create Agent's refusal line and its channel errors, the Plugins tab's save refusal, the Share Agent refusal..notice,.agent-status-line,.deployment-warnings(the "Startup warnings" heading is now the block's label),.log-source-hint-> warning;.log-error-> danger..notice; see follow-ups), "Plugin browsing uses this Agent's saved credential source", and the note fix(console): say why the page stays while a deploy or save is in flight #2900 added when a deploy or save holds the page..agent-status-line,.deployment-warningsand the log hint/error colours is removed..errorand.noticestay for the callers this PR does not touch (listed below).revealStatus(same behaviour as before). Create Agent keeps its ownfocusFeedbackLinefrom fix(console): show plugin refusals in view, as errors, with the fix the form allows #2822.Verification
tests/browser/console-status-block.test.mjs(mapped tochecks-browser-2, Suite Audit passes locally):top >= 0,top < innerHeight, bottom inside the viewport), keeps its exact text, and is a danger block. Fails on main: unfocused in all three; the removal refusal is off screen (top -169).--color-text, text contrast with the composited wash >= 4.5:1. Fails on main (no status block).console-agent-plugin-refusals(refusal is a danger block instead of.error) andconsole-agents-2(the stopped guidance's text and stripe are not the danger colour).7959b6a6b) matches the final product source; the media are not in the final tree:Keyboard walkthrough at 390x560: share with a person, then a refused Remove binding; the refusal comes into view with focus: share-refusal-keyboard-390.webm.
The full earlier set (seven stories, including the Plugins tab refusal, the failed deployment and the Logs access refusal) is at aa1d48b83.
Storybook: no new story;
scripts/console-storybook/status-block-workflow.mdwalks existing stories (Create plugin refusal, Plugins tab refusal, Sharing outcome uncertain, Experimental Dedicated OpenClaw, Edit Configuration).Every browser file in
checks-browserandchecks-browser-2, before the final test edits: 662 of 666 passed. Three were assertions on the olderrorclass of the Configuration editor's feedback (console-json-error-feedbackx2,console-agent-detail), now updated to read the danger block. The fourth,docs-compute-matrix, fails locally becausegithub-sluggeris missing in this worktree (unrelated).After merging main (fix(console): Agents list wraps long names on wide screens; phone sheets stay above the keyboard #2893, test(console): measure the Slack people-search focus ring #2901) and the sign-in change:
console,console-retained-revalidation,console-json-error-feedback,console-agent-detail,console-status-block,console-agents-list-return,console-dialogs: 175/175.After merging main again (fix(console): say why the page stays while a deploy or save is in flight #2900) and the review fixes:
console-drafts-kept,console-status-block,console-agent-detail,console-json-error-feedback,console-agent-plugin-refusals,console-agents-2,console,console-agent-overview,console-agent-saves,console-agent-logs,console-agent-state: 291/291.After the review's accessibility fix: every browser file in both suites, 674 of 677. Besides
docs-compute-matrix(above), two tests timed out under host load (console-agent-detail-2"Agent delete confirmation can be canceled…", a 300 ms response wait;console-agent-plugin-approvers"Plugin details refresh preserves…"); both files pass 70/70 on a rerun and the two tests 8/8 at 2 CPUs.an empty alert block stays in the accessibility tree until its refusal arrives: holds sign-in, reads Chromium's full accessibility tree over CDP, and checks the emptyp.status[role=alert]is exposed as an alert with 0 px height, then that the same backend node carries "Could not sign in…" after the 401. It fails with.status:empty { display: none }.console-status-block.test.mjs20/20 at 2 CPUs again (5 tests).20/20 at 2 CPUs:
console-status-block.test.mjs(whole file), and the changed tests inconsole-json-error-feedback,console-agent-detail,console-agents-2andconsole-agent-plugin-refusals.Mutants: dropping
scrollIntoViewfromrevealStatus, or the block'sscroll-margin-block, each fails the removal test; dropping the reveal call fails all three refusal cases (as main does).console-design-tokensconformance 2/2; Suite Audit (node scripts/ci/run-tests.mjs audit) has no issues; eslint and prettier clean on touched files.Risks
patchChildren,revealStatusfocus scope,setStatusTonedoc, Stop note).revealStatusmoves focus to a Share refusal only when focus is on the page, a disabled control, or inside the Share card.git merge-treeagainst this head adds no conflicted file and no conflict hunk beyond what current main already has (fix(console): say why the page stays while a deploy or save is in flight #2900, fix(console): let the create preflight carry any configuration both creates accept #2833, feat(console): show the authorized native Gateway people roster #2596: 0 and 0; feat: add per-agent sandbox network policies and denial review #2599 33, feat(console): stop and delete Agents from the Agents list #2524 4, Draft implementation: managed outbound HTTPS for dedicated Gateways #2518 11, fix(console): distinguish stale runtime status from loss of access #2505 2, fix(console): keep followed logs steady and report the first output #2502 6, Add OCE policy simulation and tester for network and plugin actions #2445 4, fix: preserve native plugin permissions across Harness selection and admission #2258 3, fix(console): grant Agent access to accepted Configuration Secrets #2255 5, Support custom Installation profiles and readable Preset starters #2253 3, feat(auth): sign people in to occ with a device code (rfc-0019) #1619 17, feat: assign configured OpenClaw roles to Agent users #906 5, docs(specs): propose rfc-0019 for repository options without a repository driver #878 2, feat: add Agent workload tags #115 9: same files and counts as main). To get there:render()places it..notice(the brief's "Share explainer"): feat: assign configured OpenClaw roles to Agent users #906 rewrites that line, so it keeps.noticehere..error/.noticein files outside this row:credentials.mjs,presets.mjs,secret-picker.mjs,slack-directory.mjs,repositories.mjs,native-admin.mjs,workspace.mjs,deletion.mjs, the rest ofstop.mjs,plugin-fields.mjs,channels/shared-ui.mjs; and the field-level.error.field-error(inline by design).detail.mjs), outside this row's list.