An empty dashboard ended the clean streak with a missing heading
/dashboard-emptyCaptured at a 375px viewport. Long pages scroll inside the frame.
The screenshots stay in Japanese. Every round is a real screen for a real Japanese industry, so an English re-render would no longer be the screen the agent actually produced.
Write-up
An empty dashboard ended the clean streak with a missing heading
Build log series: I hand a real screen to an AI that has never seen Gunjo (
@gunjo/ui) and let it build. This round covered an empty dashboard for a first-time user.
The agent saw the same limited inputs: the shipped package and docs, not the source. The /dashboard-empty assignment called for a welcome banner, Statistic components with zero values, charts with no data, an onboarding checklist with Progress, an empty activity area with EmptyState, and a full-page StatusScreen.
Rounds #18 and #19 had produced no new class of problem twice in a row. This was the third attempt, meant to determine whether the library had really stopped turning up anything new.
Result: 4.5/5, but the clean streak ended
tsc and build passed, the console stayed clear, the server and browser output matched with no hydration errors, and nothing overflowed at 375px. The functionality was solid. But the screen exposed one new class of accessibility failure.
The best result: charts handled empty data safely
The central question for a first-run dashboard was whether the charts would break with no data. The real-browser results were strong:
- There was no
NaNanywhere in the DOM. When every value was zero,BarChartgave each barheight:0%and kept the axes as the intended empty display. - With every value at zero,
DonutChartreached an explicitif(every value<=0) return fallbackguard incircular-chart-utils.ts. The component deliberately prevents a divide-by-zero crash. - With
data={[]},SparklineChartrendered an empty line and noNaN. It usesspan = max-min || 1.
Charts often fail on empty data. Gunjo guards this case explicitly, which earned substantial credit.
Why the streak ended: a new accessibility failure
The titles in EmptyState and StatusScreen were not headings. The source showed:
EmptyState.tsx:32:<p className="text-sm font-semibold">{title}</p>StatusScreen.tsx:129:<p className="text-2xl font-semibold">{resolvedTitle}</p>
A full-page StatusScreen such as "No projects yet" therefore had no <h1> at all. A screen-reader user navigating by heading would find no structure on a screen with meaningful content, violating WCAG 2.4.6 and 1.3.1. The API offered no escape hatch such as headingLevel or as. I logged issue #104.
This was the sixth distinct accessibility failure, following issues #57, #71, #83, #87, and #93. Empty-state components are the focus of a first-run screen, but they were secondary on the profile and settings screens in #18 and #19. This assignment was the first to expose the missing structure.
Other minor findings: Progress had no divide-by-zero guard when max=0 (issue #105); Badge had no success tone even though Statistic did (issue #106); and several docs pages had the wrong import path (issue #50).
What I took away: do not declare the work finished too early
I nearly treated the two clean rounds, #18 and #19, as proof that nothing new remained. Round #20 disproved that conclusion. The same thing had happened when #8 looked like the home stretch and #9 found another failure.
Functionality: no new failures, with no crashes, NaN, or type mismatches and robust empty chart data
Accessibility: still producing a new case when the screen type changes, now for the sixth time
Docs: still behind, with incorrect imports and no empty-data examples
Functionally, the components had stopped producing new problems. Accessibility coverage had not. Each new kind of screen brought a different component to the foreground and exposed another missing accessibility behavior. That meant the series needed to continue. I recorded the sixth failure plainly and fixed it.
Every defect I fixed stayed fixed in the next round, but each new kind of screen still revealed a different gap. That was proof that the work was not finished.
I added headings in issue #104 and the Progress guard in issue #105, shipping both in PR #108. A real-browser check confirmed <h2> in every EmptyState demo and <h1> in all six StatusScreen variants. In parallel, the Slider fix from issue #100 shipped in PR #107.
Next up: build log #21
- A blog post, docs article, or landing page, continuing the accessibility coverage with another kind of screen.
The run
- gunjo.jp / npm
@gunjo/ui/ GitHub - Earlier rounds: #1 through #19
- Overview: Gunjo (
@gunjo/ui) / Why it exists: Design systems in the age of AI - GunjoUI by UIXHERO
Gunjo was still in early alpha at the time; issues are welcome.
This series is co-created with AI (Claude and Codex). A human designs the experiments, makes the calls, and fact-checks before publishing; the AI does the hands-on work and drafting.
Components from @gunjo/ui
The components this screen's source imports directly.
The code the agent actually wrote
Click a file to expand its source.