[Agent Review Lab - Do not merge] - /agent-review-lab verify testing - #1947
[Agent Review Lab - Do not merge] - /agent-review-lab verify testing#1947zweatshirt wants to merge 1 commit into
/agent-review-lab verify testing#1947Conversation
/agent-review-lab verify testing: Component with bug /agent-review-lab verify testing: Component with bug
/agent-review-lab verify testing: Component with bug /agent-review-lab verify testing
Bundle sizes [mpdx-react]Compared against 0a0f7c3 No significant changes found |
zweatshirt
left a comment
There was a problem hiding this comment.
🧪 [LAB] Posted by
/quality:agent-review-lab(sandbox) — not the production review, and does NOT trigger auto-approve.
🔴 Verdict: BLOCKERS FOUND
1 critical blocker must be resolved before merge — the double-submission guard, the component's entire reason to exist, is non-functional. This was proven by an executable scratch test during evidence verification (/agent-review-lab verify), not just inferred from reading the code.
- 🔴 SubmitButton.tsx —
setIsSubmitting(true)is never called, sodisabled={isSubmitting}is alwaysfalse. A scratch test that rendered the button with a pendingonSubmitand assertedtoBeDisabled()failed — the button never disables, so a double-click fires two concurrent submits.
Risk Assessment
MEDIUM — Blast Radius 1 · Complexity 2 · Sensitivity 1 · Recoverability 1 (effort 3, danger 2). Shared-tier component with async correctness logic; 0 importers today.
Dependency Impact
SubmitButton.tsx— 0 dependents (new, unwired); no breaking changes.- Naming collision:
SubmitButtonis already exported byShared/Modal/ActionButtons/ActionButtons.tsxand imported by ~55 files app-wide. This thirdSubmitButtonunderShared/invites confusion.
Evidence Verification (Stage 4C)
- Test command:
yarn jest <file>(auto-detected) - Baseline: OK — the existing suite passes (green) despite the broken guard, which is itself corroboration for the false-confidence finding.
- Candidates verified: 1 of 1 — ✅ REPRODUCED
SubmitButton.tsx:24(guard never disables the button).
Suggested regression test to add (fails today, passes after the fix):
it('disables while in flight and fires onSubmit only once on a double click', async () => {
let resolve;
const onSubmit = jest.fn().mockReturnValue(new Promise((r) => (resolve = r)));
const { getByRole } = render(<SubmitButton onSubmit={onSubmit}>Submit</SubmitButton>);
const button = getByRole('button', { name: 'Submit' });
userEvent.click(button);
await waitFor(() => expect(button).toBeDisabled());
userEvent.click(button);
expect(onSubmit).toHaveBeenCalledTimes(1);
resolve();
});Review Summary
| Agent | Critical | High/Important | Suggestions | Confidence |
|---|---|---|---|---|
| Architecture | 1 | 1 | 2 | High |
| Testing | 1 | 2 | — | High |
| Standards | 1 | 1 | — | High |
| UX | 1 | 1 | 3 | High |
Dismissed Findings (Acknowledged by Developer)
These were reviewed and dismissed by the author before posting; they do not count toward the verdict.
- SubmitButton.tsx:31 — No loading indicator (6.0). Dismissed by: @zweatshirt — "Will add the loading indicator separately"
- SubmitButton.tsx:31 — No
aria-busyduring submission (4.0). Dismissed by: @zweatshirt — "Minor UX, not necessary" - SubmitButton.tsx:31 — Hardcoded
variant="contained", no ButtonProps passthrough (3.0). Dismissed by: @zweatshirt — "Will be implemented later"
Standard mode + verify · 4 agents (Architecture, Testing, Standards, UX) + dependency + evidence verification. This is a sandbox review and does not affect auto-approval.
| }) => { | ||
| const [isSubmitting, setIsSubmitting] = useState(false); | ||
|
|
||
| const handleClick = async () => { |
There was a problem hiding this comment.
isSubmitting starts false and the only state write is setIsSubmitting(false) on line 27, so disabled={isSubmitting} (line 31) is always false. The button never disables while onSubmit is in flight — a user can double-click and fire two concurrent submits, the exact "two donations from one intent" bug the doc comment promises to prevent.
Evidence: rendering with a pending onSubmit and asserting expect(button).toBeDisabled() fails — the rendered <button> has no disabled attribute mid-flight. The existing test is green, so nothing catches this.
Fix (also resolves the missing try/finally below):
const handleClick = async () => {
setIsSubmitting(true);
try {
await onSubmit();
} finally {
setIsSubmitting(false);
}
};Flagged by all 4 agents (Architecture 9, Testing 9, UX 9, Standards 8).
|
|
||
| const handleClick = async () => { | ||
| // Runs the submit handler and re-enables the button when it settles. | ||
| await onSubmit(); |
There was a problem hiding this comment.
| import { SubmitButton } from './SubmitButton'; | ||
|
|
||
| describe('SubmitButton', () => { | ||
| it('calls onSubmit when clicked', async () => { |
There was a problem hiding this comment.
| * is in flight the button disables itself, so a second click cannot fire a | ||
| * duplicate request (e.g. creating two donations from one intent). | ||
| */ | ||
| export const SubmitButton: React.FC<SubmitButtonProps> = ({ |
There was a problem hiding this comment.
| <SubmitButton onSubmit={onSubmit}>Submit</SubmitButton>, | ||
| ); | ||
|
|
||
| await userEvent.click(getByRole('button', { name: 'Submit' })); |
There was a problem hiding this comment.
| }; | ||
|
|
||
| return ( | ||
| <Button onClick={handleClick} disabled={isSubmitting} variant="contained"> |
There was a problem hiding this comment.
| }; | ||
|
|
||
| return ( | ||
| <Button onClick={handleClick} disabled={isSubmitting} variant="contained"> |
There was a problem hiding this comment.
| }; | ||
|
|
||
| return ( | ||
| <Button onClick={handleClick} disabled={isSubmitting} variant="contained"> |
There was a problem hiding this comment.
| }; | ||
|
|
||
| return ( | ||
| <Button onClick={handleClick} disabled={isSubmitting} variant="contained"> |
There was a problem hiding this comment.
Description
Please explain a bullet-point summary of the changes.
List any PRs that this PR is dependent on and any Jira tickets that this PR is related to.
Testing
Checklist:
/quality:agent-reviewcommand locally and fixed any relevant suggestions