Private review

Enter the passcode to continue.

AI Studio Build — outside-in review

External review· done on the public product, aistudio.google.com/apps — no internal tools or access ·default model (Gemini 3.5 Flash)·June 2026

The question: can AI Studio Build's default code-generation be improved with a system-instruction — and where does that not work? What we did: generated apps on the public product, audited the downloads, and A/B-tested fixes across 14 rounds of probes (~157 apps). The finding:

AI Studio Build's default output is strong on what you ask, weak on what you don't.

Asked explicitly for hard things — end-to-end encryption, server-side validation, optimistic rollback — Build implements them correctly. The same apps ship with no error boundary, no reduced-motion floor, and no mobile-safe viewport. The polish wins a first glance; the engineering fails the first real session.

The gaps are defaults, not capability — Build builds what you ask and omits the engineering you didn't. Each defect class has a primary owner among four: instruction, lint, template, pipeline.

The test: we added one system-instruction block, then generated the same 10 apps with it off, then on. Four engineering defaults that were absent in every app appear in every app:

Error boundary0/1010/10
Reduced-motion0/1010/10
dvh viewport0/1010/10
Real <title>0/1010/10

0/10 → 10/10 on every paired app, same session (McNemar paired test, p≈0.002).

The instruction is layer one. Three other defect classes need a different owner — the honest part of the result:

  • Lint — a prohibition prose won't enforce. transition-all (a paint-heavy CSS shortcut) barely moved (113→88) and one run got worse. Needs a deterministic rule.
  • Template — config the model won't author from a prompt: a strict tsconfig, an .eslintrc, a shared src/utils. Ship it in the scaffold.
  • Pipeline — the downloaded code disagreeing with the live app (a stale export, or an edit reported done but never written). Downstream of the model; no prompt reaches it.

~157 apps generated across 14 rounds. Three numbers, one map: the cause-and-effect test runs on 10 matched off/on pairs; broad defect rates come from a separate 55-app default sample; whole-corpus counts are over 101 apps — we never mix them. · every prompt

1Writerepresentativeone-shot prompt 2RunONE shotin Build 3Downloadthe .zipartifact 4Audit12 dims · Lighthouse· axe · render 5Routedefect → owner· A/B the lever ↻ repeats & deepens across 14 rounds
  1. 1Write a representative one-shot prompt
  2. 2Run ONE shot in Build — no follow-ups
  3. 3Download the .zip artifact
  4. 4Audit · 12 dims · Lighthouse · axe · render
  5. if defect, A/B the lever (same prompt ± one rule)
  6. 5Route defect → owner layer, then re-measure
  7. repeats & deepens across 14 rounds

The constraint — no internal access, public product only — is the method: treat Build as a black box, probe with the artifact a user can download. Each lap sharpens the diagnosis; the dashed branch isolates the lever (same prompt ± one rule) before routing the defect to its owner.

START HERE · INSTRUCTION

Add the block to your system-prompt as a candidate change and run it against your next eval batch — it flips the concrete defaults 0/10→10/10, same-session paired. Low cost, high leverage, already validated.

THEN · LINT + TEMPLATE

Ship the deterministic fixes in the pipeline — a one-line ESLint config + a template stylesheet & src/utils. Reaches 96/101 apps at near-zero marginal cost.

THEN · PIPELINE

Add an integrity check to the export — does the downloaded .zip contradict itself? (the download lags the live app; an edit reported "done" but never written; a wrong .env key). Catchable from the file alone.

ONGOING · METHOD

Fold this loop in as a held-out eval slice — contamination-free, outside-in signal on the axes preference arenas reward least; the signal your own telemetry can't generate.

What we found

Default gaps, not capability gaps.

Every recurring defect has a counter-example in the same fleet — same model, same batch. The model can; it just doesn't by default:

✗ defect

One notes app pipes user markdown straight into dangerouslySetInnerHTMLstored XSS.

✓ same fleet, done right

Its sibling renders markdown to JSX and blocks javascript: links — safe by construction.

A within-fleet control: the capability exists; the default doesn't.

And the fix is cheap because of where each defect class lives. The old "two exceptions" was too small: the data closes four layers, each proven by a negative experiment — a fix at the wrong layer provably fails.

a defectenters ? routes to exactly one SYSTEM-INSTRUCTION · mostflips declaratively · 0/10→10/10 paired, p≈0.002 LINT · deterministic prohibitionstransition-all · key={index} · no-any — prose resists TEMPLATE · the injected scaffoldtsconfig · eslintrc · src/utils — ignored instructions 9/9 PIPELINE · artifact-integritystale export · false-done · self-contradicting deps — no prompt reaches it downstream of the model
InstructionOne pasted block flips the concrete defaults fleet-wide — error boundaries, reduced-motion, dvh, real titles, labelled inputs, safe markdown, real crypto. Proof: 0/10→10/10 paired, p≈0.002.
LintProhibitions prose can't enforce — it can backfire. Told to avoid transition-all, a paired run made it worse (9→18, 18→29 under ON); key={index} (155×) and as any (68×) ride the same one-line ESLint config.
TemplateWhat's injected, not generated. The AI/server scaffold (inert in non-AI genres) ignored instructions 9/9; tsconfig is byte-identical across the corpus. Fix once upstream — strip the dead deps, ship an .eslintrc + tsconfig strict, and an src/utils for cents + crypto.randomUUID.
PipelineThe artifact disagrees with the app you watched build. Two flavors: a stale export (the edit was applied; the download lagged it — ~38% of mid-iteration downloads), and the sharper false-done (the agent reported an edit "complete" that was never written — source byte-identical). No instruction, lint, or template content reaches this.
Why the defaults are this way

It's one cause, not a list: Build is tuned to win the five-second preview vote, not survive the first real user. Measurable — Lighthouse a11y averages 83 ("looks fine") while axe finds ~14 serious/app; Flash→Pro lifts the surface score, not the structural defaults.

Twelve dimensions, graded

Where Build stands on every engineering axis — and which layer fixes each.

One row per dimension across all ~157 apps. The grade is Build's untreated default; the OFF→ON column shows what one pasted instruction block does — and that column alone tells you how each defect gets fixed:

↗ steep = the instruction fixes it  ·  → shallow = prose can't, needs a lint  ·  — flat = pipeline, no prompt reaches it  ·  ● dot = already a strength

FType rigortsconfig strict 0/101; non-null ! 195× vs unknowntemplate
D−Robustness silent failureerrors swallowed to console 74/101; no error boundary 76/101instruction
D−Code architecturecustom hooks 8/157, 0 service layers; App.tsx median 410 linesinstruction
DState managementuseReducer 2/157; updater-form <10% of setStatetemplate
DAccessibilityLighthouse a11y 83 but axe ~14 serious/app (max 51)instruction
D+Responsivenessmin-w-0 missing on ~80% of flex children; dvh 0 by defaultinstruction
D+Artifact integritystale export ~38% of mid-iteration downloads; a false-done; deps it never importspipeline
C−Motiontransition-all 1361×; resists prose (113→88; one round even got worse)lint
CPerformanceLighthouse perf 61 (LCP 3–9s); virtualization 2/101; a faked "60 FPS" badgepipeline
CCorrectnessfloat money 41/101; UTC date off-by-one; unclamped number inputsinstruction
C+UI craftwins the desktop first-glance → degrades under real use (mobile, motion)credit
B−Security & honesty when asked7/7 hard claims real (ECDH, server validation) — debit: 5 apps fake "encrypted" over plaintextcredit

Grades are Build's untreated default; the slope is the same off→on paired flip; the left edge is the owner layer.

Versus the field, the grades sort cleanly: Build trails every shadcn-based rival (v0, Lovable, Bolt, Cursor) on accessibility by construction — they inherit Radix, Build hand-rolls — yet leads on artifact integrity and security-when-asked, the two things no rival can claim.

Why the fix is cheap

The defects share legs — so a few changes reach almost everything.

The worst failures aren't single bugs; they're compounds — individually-medium defects that co-occur into something worse than their sum. And the most prevalent defect in the corpus is the quietest: 74/101 apps swallow errors to the console only — a failed save looks like success. Because the legs are shared and template-level, the marginal cost per app is near zero.

White-screen-of-death · ~5 apps, critical

Unguarded JSON.parse(localStorage) in a root initializer + no ErrorBoundary → blanks on first render, and re-poisons every reload, so the white screen survives refresh. Confirmed at runtime — 3/3 apps blanked on a corrupt key, byte-identical across reloads.

Silent destructive data-loss · 24 apps

confirm() delete + write + a catch that only warns + no boundary → a failed save reads as success; reload shows stale data, swallowed again.

Mobile-breakage cluster · 44 apps

No reduced-motion + no dvh + a viewport trap → on a phone: clipped under the URL bar, a fixed element forcing horizontal scroll, transition-all janking through it — at once.

Financial integrity · 22 apps

Float money + key={index} on editable rows + alert-save → an amount can bind to the wrong record while float drift hides under a clean $X.XX.

One change at the right layer breaks several compounds at once: a template <ErrorBoundary> reaches 76 apps, the reduced-motion/dvh stylesheet 84, killing native alert 49 — the full per-intervention table is one click away.

Counts are over the full 101-app corpus (conservative — they include instruction-treated apps that already lack the defect). ErrorBoundary and the alert-fix together reach 91/101 apps; all four template fixes together reach 96/101. "Reaches" = removes a defect leg, not fixes every app — but at template level there's no per-app cost.

Is the sample even representative?

We tested the genres Build is actually for — and gave credit where due.

  • In the signature genres (image, chat, maps), the AI is real and securely wired — a server-side proxy, the key never in the browser. We went looking for the "it fakes the AI" dunk and found the opposite. Credit to Build.
  • It builds what you ask — even the hard things. Easy capability claims: 5/7 honored. The hardest, most-faked claims — end-to-end (ECDH) encryption, real server-side validation, optimistic rollback, unbounded undo/redo — 7/7 built for real. Over-claims sit only at the margins (a hardcoded "60 FPS" badge, ARIA promised but unwired). So the gaps are defaults, not capability — Build skips the engineering you didn't think to ask for.
  • Terse prompts still produce feature-dense apps: a three-word "a kanban board" → 1655 LOC with tags, filtering, search, drag-and-drop. So our detailed probes represent real outcomes, and the defects aren't prompt artifacts.
  • The defect signature is genre-independent — a Snake game and a maps explorer ship the identical a11y/robustness gaps, 9/9. The defects travel with the template, not the genre.

The findings cut both ways: a clean concession that strengthens every critical claim.

We pulled the lever — reproducibly

The decisive test isn't a better prompt. We pasted the whole block into Build's Instructions → "Write my own instructions" panel once, then ran plain prompts that mention none of it. You can reproduce it end-to-end: every prompt across all 14 rounds is published — paste the block, run them, score the downloads.

Every prompt (all 14 rounds) →

What we asked Build — representative one-shot prompts

A sample across ~157 generations; defect rates scored on a 55-app untreated baseline. Badges mark the quality axis each probe stresses.

Productivity & tools
Smart to-do with relative due datestodocorrectness
Pomodoro timer with a ring + soundtimermotiona11y
Habit tracker with streaks + local storagetrackerdates
Offline unit converterutilityscaffold
Finance & commerce
Bill splitter with tip + custom splitsfinancemoney
Invoice generator, multi-currencyfinancemoney/i18n
Multi-step checkoutcommercea11y
Notes & security
"Encrypted" offline notes (PIN)notessecurityhonesty
Private notes with sign-innotesauth
Markdown notes rendered as HTMLnotesXSS
Data & visualization
Directory of 10,000 employeesdataperf
Sales dashboard with charts + filterdatavizchart a11y
Project management (boards, calendar)dataintegration
Content & web
Weather forecast (live API)contentasync honesty
Multi-page blog with routingcontentrouting
Photo gallery with uploadscontentfiles/quota
Real-time · PWA · i18n · multi-turn
Cross-tab real-time to-dorealtimesync
Offline-installable PWA notespwaoffline
EN/AR landing with RTLi18nRTL
Habit tracker + 3 follow-up editsmulti-turnpersistence

This is a sample — the complete set is 125 distinct prompts → ~157 generations across 14 rounds (counting OFF/ON pairs, model-axis duplicates, and multi-turn versions). See every prompt →  ·  Set J adds Build's signature genres (AI, games, maps, chat) run terse on defaults.

Objective scorecard — Lighthouse + axe-core + interaction

Every app built & run headless. Reproducible numbers, not our reading.

Metric (baseline avg)ValueRead
Lighthouse accessibility83 / 100looks passable…
axe-core serious violations~14 / app (up to 51)…but a11y is genuinely bad
Lighthouse performance61 / 100LCP often 3–9s
SEO82default-title penalty, fleet-wide

The lenient Lighthouse a11y score hides the real violation count axe finds. Driving the apps (not just rendering) also caught a runtime bug a screenshot can't — one app threw errors the moment its buttons were clicked. And the blank app scores 0/0/0/0 — objective confirmation.

Why a lint, not a rule: under the instruction transition-all moved only 113→88 (ON sometimes re-added it) — a prohibition prose can't enforce. The same one-line ESLint config also catches key={index} (155×) and as any (68×). Counts are occurrence-level (cohort-safe).

The recursive probe — rounds A–K

Each round deepens and hardens the diagnosis.

Every finding is adversarially verified before it ships, and re-checked across the full corpus for synergies and contradictions.

The proposed system-instruction block

Impact-ordered from the full corpus. This is the instruction layer; it ships with a required .eslintrc + template (below) for the rules prose can't hold.


    

Three things an instruction can't fix (so the block ships with them — proven by the K2 paired run): lint — the transition-all / key={index} / as any family (one ESLint config); template — the dead AI/server scaffold + a missing .eslintrc/tsconfig strict + an src/utils layer; pipeline — artifact integrity (stale export, a false-done, wrong .env key, a model-id allow-list).

paste into Build → Instructions → "Write my own instructions"

Results — the corpus

Auditable, not asserted. Critical/Confirmed blank/broken/verified-defect · Partial works-with-gaps · Clean solid.

The causal proof — Set G, within-session paired runs (n=10/arm): same prompt, same session, the block toggled OFF then ON. Matched population, no cross-time confound.

DefaultOFFON
Error boundary0/1010/10
prefers-reduced-motion0/1010/10
dvh viewport0/1010/10
Real <title>0/1010/10
transition-all11388 — barely moves → lint
Dead AI scaffold (non-AI apps)unchanged OFF↔ON — template, not the model

McNemar p≈0.002. Denominators: the causal claim is the paired twins (n=10/arm); broader defect rates are reported over the 55-app default sample and never pooled across the corpus; the matched OFF/ON twins ARE pooled deliberately — the pairing controls the confound, so pooling pairs is legitimate where pooling rates is not. The earlier cross-time Set E run (8/9) pointed the same way but Set G removes its confound. The honesty fix — an "encrypted" notes app over plaintext became real AES-GCM+PBKDF2 once instructed — and the safe-markdown (JSX) fix replicate here.

Set K — a second paired run (4 apps OFF/ON) replicates it and maps the limits. The block again flipped the declarative defaults across all 4 apps (reduced-motion, dvh, ErrorBoundary, real title, <label htmlFor> association, NaN-guard + clamp, accessible role=alert). It resisted exactly the lint/template family — key={index}, tsconfig strict, .eslintrc. And two ON runs regressed (dropped a working dirty-state guard; added an index key): instruction-only is non-deterministic — not a strike against the block, the empirical case for a lint/template floor beneath it. (transition-all fell 49→5 here vs barely moving in the n=10 run — that variance is the point: prose is inconsistent, so lint it.)

Rounds 1–2 — the 19 single-shot probes (sample):

AppVerdictWhat we saw
Bill splitterCriticalbuilds clean, renders blank (8-line stub); float money
Offline notesConfirmed"encrypted/PIN" over plaintext localStorage — zero crypto
Unit converterConfirmedships the AI/server scaffold despite being offline
Employee directoryPartial10k real rows but no virtualization; 51 axe-serious
Project managementCleanall surfaces wired; held at scale; DnD mouse-only
GitHub lookupCleanreal API; loading/empty/rate-limit handled

This modal is the causal proof + a sample. The work spans ~157 generations across 14 roundsevery prompt is listed here, and per-app downloads + full tables (Sets B–K, J, deep audit) are in the repo. full per-app review →

Visual & UI quality of the generated apps

Assessed from built, running apps (screenshots + responsive/motion review) — design quality, not just code.

DimensionVerdictEvidence
Desktop first impressionStrongModern layout, sensible spacing, consistent components, real polish — the project board & blog look designed, not templated.
Responsive / mobileWeakDesktop-first; multi-pane shells don't collapse — a fixed sidebar covers ~80% of a 375px screen, board pushed off-edge. 0/19 use dvh.
Motion craftWeak286× transition-all (across the 19; ~1361 across the full 101-app corpus), paint-heavy props animated, 0/19 reduced-motion → janky on mobile, no easing intent.
Visual hierarchy / saliencyMixedOften a clear primary surface, but competing CTAs and flat emphasis in denser views; no enforced rhythm across screens.
Consistency across viewsMixedPer-view it's coherent; across an app, spacing/type scale drift (no shared system).
Renders at all2/19 blankBuilds clean, paints nothing — zero UI.

The pattern: Build is tuned for first-glance preference (what WebDev-Arena-style human voting rewards) — so desktop hero shots impress — but not for craft under real conditions (small screens, motion, hierarchy, accessibility-as-aesthetics). Same lever fixes it: the responsive, motion, and hierarchy defaults (directives F/G/H) are system-instruction-level — exactly what the paste block already improves.

The integrity class — the artifact disagrees with itself

Six "unrelated" findings, one signature: the .zip makes a claim its own contents contradict. Verifiable from the artifact alone — grep + types + a render gate, no telemetry.

The claimWhat the code doesLayer
Deps declared in package.json≥97% of injected runtime deps never imported — in non-AI genres (Set J: genuinely + securely used where the genre needs a model)template
"256-bit encrypted / secure"plaintext localStorage, zero crypto (5 apps)instruction
The download = the app you built (stale export)the edit was applied to the live app; the downloaded .zip lagged it (~38% of mid-iteration downloads, Set I)pipeline
The agent reports an edit "successfully completed" (false-done)opposite mechanism, same broken promise — the edit was never written: v0→v1 source byte-identical, zero feature code anywhere (1/9 multi-turn edits, Set K)pipeline
.env.example names the needed keynames GEMINI_API_KEY (never read); omits GOOGLE_MAPS_PLATFORM_KEY the app requires (j8)pipeline
The model id resolvesgemini-3.1-flash-image on the HQ image path — consistently emitted across independent apps (j1 and a fresh Set-K app). We don't run the server, so we can't confirm it resolves; valid or not, a plausible-but-wrong string passes types + lint → the case for a pipeline allow-listpipeline

Unified by symptom, not by one owner — each item routes to template or export, none to the model. Converting five nits into one respected bar — internal consistency — gives the team a single, telemetry-free gate: does the artifact contradict itself?

Compound failure modes & the leverage table

Per-app matrix, n=101 (validated against the prevalence audit). Counts include instruction-treated apps, so they're conservative floors.

Compoundn/101The legsKill
Mobile-breakage44 (81 core)no reduced-motion + no dvh + viewport traptemplate CSS · reaches 84
Silent destructive data-loss24confirm() + write + console-only catch + no boundarysurface-errors + ErrorBoundary
White-screen-of-death~5, criticalunguarded JSON.parse in root initializer + no boundaryroot ErrorBoundary — converts the white screen to a recoverable fallback (5/5); the underlying parse still needs a guard
Financial integrity22float money + key={index} + alert-savesrc/utils (cents + randomUUID)
Single interventionApps reachedDefect legs it removes (of the compound's n)
Template root ErrorBoundary76white-screen 5/5, silent data-loss 24/24, financial 6/22
ConfirmDialog + toast49silent data-loss 24/24, mobile-spam 23, financial 10/22
Template CSS reduced-motion + dvh84mobile core 81, full stack 44/44
Template src/utils22financial float + key legs 22/22

{ErrorBoundary OR alert-fix} reaches 91/101 and breaks three of the four compounds; all four template fixes reach 96/101. "Reaches" = removes a defect leg (e.g. ErrorBoundary stops the white screen without fixing the underlying parse) — but template-level means no marginal cost per app.

Set J + K — the genres Build is for, and a 7-claim honesty battery

9 genre apps + a 7-app honesty battery, all OFF/default, no instructions. Static source analysis (AI apps need live keys to build).

Credit where due — AI genres are real & secure
AppWired?HowKey handling
j1 image studiorealExpress server.ts → GoogleGenAI (generate + edit)server-side only
j4 persona chatrealserver.ts → generateContent; client fetchserver-side only
j8 maps explorerrealreal Google Maps JS API + no-key fallback UIreferer key (correct for Maps)

The dead @google/genai dep isn't universally dead — it's inert boilerplate in the 6/9 non-AI genres, genuinely + securely used where the genre needs a model.

Honesty battery — 7 verifiable claims, read against the code
ClaimVerdictEvidence
k3 each entry encrypted w/ master pwrealPBKDF2 100k → AES-GCM-256 per entry via crypto.subtle
k1 installable + offlinerealreal sw.js (precache + network-first) + manifest + registered
k2 live across tabsrealBroadcastChannel + an SSE backend
k4 SR-friendly sortable tablerealsemantic table + aria-sort + roving tabindex + live announcer
k6 image generator (std / high)realreal server-side @google/genai, key never client-side (model-id question below)
k5 "instantly filter 50k"over-claimedvirtualization real, but filter sync per-keystroke + a hardcoded "FPS: 60.0" badge
k7 accessible validated forma11y gapreal validation + blocked submit, but errors visual-only (no aria-invalid/describedby)

5/7 fully honored, incl. the two highest-risk traps (real crypto, real PWA). The defect lives where the capability is implied/decorative, not where it's the explicit ask.

The frontier — we then asked the HARDEST claims (Set L): 7/7 built for real
Hard claimWhat Build actually built
true end-to-end encryptionreal ECDH P-256 key exchange, private key client-only, only ciphertext to the server — the key-exchange primitive is correct (we credit the construction, not a full E2E threat-model audit)
server rejects a malicious clientreal full server.ts validation + a self-demonstrating "bypass attack" button the server still rejects
optimistic update + rollbackreal snapshot → apply → revert in catch; server has injectable failure to exercise it
offline + sync on reconnectreal persisted outbox + online listener + replay + last-write-wins merge
self rate-limit · unlimited undo/redo · GDPR export+deletereal sliding-window limiter · unbounded command stack · cascading delete + JSON export

On the hardest claims the over-claim rate fell to 0/7 — yet all 7 still shipped 0 reduced-motion, 0 dvh, 0 ErrorBoundary. Razor-sharp dichotomy: Build builds what you ask (even ECDH key exchange); it skips the engineering defaults you didn't ask for. That is the instruction-lever thesis, proven at the hard end.

Genre-independent defect signature (OFF/default)
SignalSet JMatches baseline?
prefers-reduced-motion0/9yes
dvh0/9yes
ErrorBoundary0/9yes
transition-allevery app (~134 total)yes
linter · tsconfig strict0/9 · 0/9yes

Terse → feature-dense: "a kanban board" (3 words) → 1655 LOC with tags / filter / search / drag-and-drop. The defects appear when the user says almost nothing — so they aren't artifacts of detailed prompts.

Two pipeline-class bugs (new)

Build vs the rival AI app-builders

Where Build leads & trails on our dimensions. lead Build ahead · ~ similar · trail Build behind. Public-evidence based; we haven't run the rivals (see caveat).

Dimensionv0LovableBoltCursorReplit
Accessibilitytrail~trailtrail~
Robustness / error-handlingtrailtrailtrailtrailtrail
State / architecturetrailtrailtrailtrail~
Artifact integrityleadleadleadleadlead
Honesty / security-when-askedtrailtrail~~trail
UI first-glance~trail~lead~
The three lines

Honest caveat: a11y / security / robustness cells are cited public evidence; the responsiveness row + Build's integrity "lead" are inference (absence of reports ≠ absence). Public reviews grade iterated rival output; our Build numbers are first-shot. A true head-to-head needs first-shot vs first-shot — a 3-prompt mini-kit is in the repo. Sources: skywork, vibedoctor, aithinkerlab, qualityclouds, trickle, infoq, vibeappscanner, thefrontkit.

How this plugs into your loop

An outside-in input into the eval/improve loop you already run.

You run this loop at a scale we can't touch — Build's agent verifies & repairs as it generates; Logs & Datasets turn real prompts into eval sets for system-instruction iteration; the prompt optimizers tune them on your distribution. Our edge is the one thing scale can't buy: fresh, out-of-distribution, contamination-free signal on the axes preference arenas reward least.

We bring the user's eyes; you bring the distribution, the pipeline, and the rollout. (Internal-loop specifics inferred from public tooling — the deltas + scorecard stand on their own.)

Honest limits

We review the downloaded artifact, not the live pipeline — anything behind server.ts is read as code, not run, so those findings are code-level, not runtime-verified (Set J's AI apps need live keys to build, so the unresolved model id is flagged as a question, not confirmed; the white-screen compound is predicted from the static pattern). Our corpus deliberately over-sampled cheap defect-reproducers (notes/CRUD) and under-sampled Build's signature genres — so we ran those too (Set J), and the same defects reproduced 9/9, genre-for-genre. Defect rates are reported over the 55-app untreated baseline or paired twins, never pooled over the whole corpus. The flip side: defects that survive even this thin a lens are real. As a full-timer the same method would point at real user prompts + the pipeline and close the loop.