docs: add errors-use-error-notice frontend review rule - #8303
Conversation
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
UX Review (Fable 5) — ✅ PASSUX-level review of UX-Verdict: PASS Docs-and-review-rule-only change — no rendered UI, strings, or flows are touched; nothing a user experiences differs. [UX-REVIEWED] 2d5d586 |
Design Review (Fable 5) — ✅ PASSDesign-level review of Design-Verdict: PASS Codifies an already-proven pattern; every referenced artifact (component, prop default, comment convention, exemplar sites) exists and matches the rule's claims. Suggestions
[DESIGN-REVIEWED] 2d5d586 |
Opus 4.8 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
ac6ffbb to
db62519
Compare
|
Status note — the remaining red is infrastructure, not this diff.
I will re-run the audit job once the registry recovers (another PR's audit going green is the signal) rather than retrying every few minutes. |
Every error surfaced to the user renders through ErrorNotice, and turns on its askAgent hand-off wherever the hand-off cannot destroy unsaved state. A hand-written red div throws away the structured context (endpoint, status, backend code) the component recovers from the error journal and leaves the user at a dead end in an agent app. The hand-off navigates away and unmounts the tree that rendered the banner, so next to an unsaved draft askAgent must stay off, and the omission must carry a "No hand-off" comment naming the draft it protects, so a reviewer can tell a protected draft from a forgotten prop. Applies to what a diff adds or touches; the pre-existing hand-written sites are grandfathered until edited. Enforced by the GPT and Opus review lanes through website/AUTOSDE.yaml, with a pointer in website/AGENTS.md.
db62519 to
2d5d586
Compare
bolichen97
left a comment
There was a problem hiding this comment.
Approving — docs + AI-reviewer config only, no runtime impact.
Scope check: website/AGENTS.md prose plus one appended entry in AUTOSDE.yaml custom-rules. 99 additions, 0 deletions. No workflow, CODEOWNERS, or branch-protection change, and no existing rule blocking flag, file-patterns, or text is modified — this only adds strictness for the AutoSDE reviewer, it relaxes nothing.
Verified the rule matches the code it governs: src/components/ErrorNotice.tsx exposes variant and askAgent (defaulting false, with the data-loss rationale the rule quotes).
Follow-up nit (not blocking): the onHandoff bullet reads as an ErrorNotice prop, but ErrorNotice has no onHandoff — it is an AskAgentButton prop. Worth one clarifying clause in a later pass.
Verdict: MERGE_WITH_FOLLOWUP.
Problem / Motivation
The dashboard has one shared error surface,
ErrorNotice, that renders an error and offers to hand it to the agent with the full structured context (route, failed endpoint, HTTP status, backendcode). Nothing requires anyone to use it. Roughly 100 sites still render an error as a hand-written<div className="text-danger">{err}</div>, and new ones keep landing, because no review rule names the component or theaskAgentdecision.Why it matters
This is an AI agent app: an error the user cannot fix themselves is usually one the agent can, so every hand-written red div is a dead end that throws away the context the agent would need. It also re-implements the visual (icon,
role="alert", tokens, dismiss) slightly differently each time. The hand-off is also destructive (it navigates away and unmounts the tree, destroying unsaved local state), so theaskAgentchoice has to be made deliberately per surface — and today a reviewer cannot tell "protected a draft" from "forgot the prop".What changed (motivation → approach → change)
Goal: make "render errors through
ErrorNotice, decideaskAgentexplicitly" a review-enforced rule rather than tribal knowledge.Approach: a
blocking: truerule inwebsite/AUTOSDE.yaml, which is what the GPT and Opus review lanes load from the base ref, plus a one-bullet pointer inwebsite/AGENTS.md's "Rules that must not wait for a pointer" list so agents see it before writing code. No CI script — the error-vs-validation split and the "does this subtree hold a draft" question are semantic, so this belongs to the AI lanes, not a grep gate.The rule (
errors-use-error-notice):useQuery/useMutationerror, a backend{ error, code }body, a job'slast_error, a boundary fallback) renders throughErrorNotice; classification is by where the value comes from, not how it is rendered. Validation hints, empty states and warnings are out of scope.askAgenton where nothing unsaved can be lost, and must leave it off next to an unsaved draft with a{/* No hand-off: … */}comment naming the draft (the form already used inRemoteCrewPanel.tsx).onHandofflets a dialog close itself but does not make the navigation safe.ErrorNoticewith neitheraskAgentnor aNo hand-offcomment) — never on the direction of the decision, since whether a subtree holds unsaved state is not visible in a hunk and a wrong demand would cause exactly the data loss the prop's default prevents.max-two-buttons-per-row's growth-only grandfather because the migration is one line and growth-only would leave the backlog a dead end forever.ErrorBoundary/MessageErrorBoundaryfallbacks (they mountAskAgentButtondirectly), chat-transcriptErrorCardrows (the agent is already in that conversation), oruseNotify(..., { type: 'error' })toasts — but a toast as the only report of a failure that leaves the user in a failed state is a violation, because the app-sdk seam carries only message + type and cannot host the hand-off.Local adversarial review (GPT and Opus lanes mirrored locally, then one verifier): 0 blocking, 5 advisory findings, all fixed in this commit — the reviewer bright line moved to "missing decision", the
onHandoffclause no longer counts as enabled over a draft, the toast exception was corrected against the realuseNotifysignature, the stricter grandfather is stated with its reason, and error classification is anchored on the value's source.Tests
N/A — the diff is a review rule (YAML) and a doc bullet (markdown); no runtime code path. The YAML was parsed (
custom-rulesstill loads, 14 rules, the new oneblocking: trueonsrc/**/*.tsx), and the diff-scoped gates (check_brand_name.py,docs-lint.sh,scrub-lint.sh,check_focus_cue.py,check_harness_parity.py,check_changelog_history.py) exit 0.Manual verification
Every factual claim the rule makes about the codebase was checked against the source:
ErrorNotice.askAgentdefaults tofalse;RemoteCrewPanel.tsxcarries theNo hand-offcomment form;App.tsxmountsAskAgentButtonwithonHandoff; chatrole: 'error'rows render throughErrorCard;useNotifytakes(message, { type })only.Related Issues
no linked issue: the rule was requested directly, not tracked in an issue.
Checklist
feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)