One Baseball Problem, Two AI Apps
Years ago, a baseball coach named Hunter Mize described a very practical, very irritating problem.
During batting practice, a coach stands behind the cage or near the mound watching a steady stream of pitches and contacts. He wanted a fast, frictionless way to record where each hitter was placing the ball: glance at the phone, tap approximately where the ball landed on a field diagram, and immediately have his eyes back on the batter for the next pitch.
Later, away from the dust and chaos of the cage, he wanted to open that digital notebook, pull up an individual player’s history, and see where that hitter tends to cluster the ball—line drives up the middle, weak grounders to the right side, or fly balls pulled toward the corner.
Around 2020, Corey Mize took that concept and drafted a concrete software specification for it: local-first persistence, rapid one-tap contact capture, roster queues, spray charts, and zero required server infrastructure.
Then it sat.
Like thousands of sensible, well-defined utility ideas, it lived in that familiar holding pattern where the problem is completely real, but the friction of scaffolding a custom mobile app, setting up local databases, wiring up deployment pipelines, and styling a bespoke UI isn’t quite worth the weekend hours it would consume.
Nothing about the product concept came from artificial intelligence. The problem, the field-level workflow, and the design intent were entirely human.
This weekend, modern coding agents made it reasonable to dust off that six-year-old specification and run an experiment:
Give essentially the identical human-originated product specification independently to two contemporary coding agents, step back, and see what each one builds.
The two contestants were:
- Gemini 3.8 Flash High, using Antigravity
- GPT-6 Astra Ultra, using Codex
Both agents were instructed to build installable, offline-capable Progressive Web Apps using our standard Angular PWA baseline, complete with automated tests, local-first storage, and zero server dependencies.
Both finished. Both applications are live on GitHub Pages right now.
Before we get into the behind-the-scenes engineering, the usage-quota drama, the localhost outage, or the final human verdict, we are going to do something that standard AI benchmark charts never let you do:
We are going to let you judge the software blind.
Part One: The Blind Test
Below are the two finished applications, presented simply as App A and App B.
Neither model’s name appears anywhere in this section. We have preserved the exact visual styling, layouts, and copy produced by each agent. Both applications are fully functional, interactive, and live.
App A: Baseball Practice Helper
A mobile-first batting practice notebook featuring rapid tap-to-record contact capture, roster management, pitch tracking, and spray-chart analytics.
App B: Baseball Coach Helper
A digital baseball notebook and spray-chart companion designed for coaches to track contacts, manage rosters, and explore visual hit trends.
We strongly encourage you to open both links in separate tabs, create a team, add a couple of players, tap out a quick round of batting practice on the field diagram, and look at the reports and settings.
If you are on a phone or just want to see how they look side by side, here is the visual evidence.
1. Home & Team Setup
The first striking result of this experiment is how immediately and thoroughly both agents converged on the exact same product aesthetic and layout structure. Neither model saw the other’s work, yet both independently arrived at a rich ballpark-green and warm-cream palette, a split setup card, and almost identical introductory copy:
App A Home: "Make every round count." Step 1 of 2 team creation flow, deep forest green card, and clean form fields.
App B Home: "MAKE EVERY ROUND COUNT. A little less screen time. A little more field time." Notice the custom diamond mark in the browser tab.
Notice that both agents independently chose the four-tab bottom navigation pattern: Practice, Roster, Reports, and Settings.
2. Roster Management
Both applications enforce a sensible domain boundary: before you can record batting practice, you need a team and an active roster:
App A Roster: "Team Roster: Manage your players and set your everyday batting-practice lineup order."
App B Roster: "The roster. Your players. Your everyday batting order. First, give your team a name."
3. Reports & Analytics
The reporting screen is where the coaching value lives. A coach wants to look at a spray chart and understand tendencies across different situations:
App A Reports: Multi-dimensional filtering by Player, Session, Date Range, Pitcher Handedness, and Contact Type, with tabs for Spray Chart, Heatmap / Density, and History List, plus a full Pull/Center/Oppo spray tendency bar.
App B Reports: "See the whole field. Every contact tells part of the story." Prominent export actions: Download CSV, Share, and Print / PDF.
4. Settings & Data Ownership
Both agents recognized that a local-first application requires explicit data ownership—giving coaches the ability to export full JSON backups, generate CSV files for spreadsheet analysis, and restore their database without losing records:
App A Settings: Four-quadrant dashboard covering Active Team, Practice Defaults (with haptic vibration toggle), Data Ownership (JSON & CSV), and local storage metrics.
App B Settings: Four-quadrant dashboard organized into The Dugout (Team), Next Time at the Field (Practice defaults), Backup & Export, and Import a Backup.
Lock In Your Guess
Now it is your turn.
Forget marketing claims, benchmarks, and Twitter hype. Based on what you see above, and especially how the two live applications behave when you test them in your browser:
Which agent built which application?
Make your call:
The Rest of the Story
Now that the curtain is lifted, here are the official identities and their repositories:
- App A is Baseball Practice Helper, created by Gemini 3.8 Flash High using Google’s Antigravity environment.
Repository:https://github.com/cboler/baseball-practice-helper - App B is Baseball Coach Helper, created by GPT-6 Astra Ultra using OpenAI’s Codex environment.
Repository:https://github.com/cboler/baseball-coach-helper
If you spent time clicking through both applications, you probably noticed that this was not a contest between a functioning product and a broken prototype. Both models delivered authentic, deployable, local-first software.
What happened behind the scenes to get those two applications to the finish line, however, could hardly have been more different.
Gemini’s Run: The Fast Lane
Gemini 3.8 Flash High tackled the task on Sunday morning, September 6.
It opened the project specification, conducted a structured planning pass, and went to work on baseball-practice-helper. It generated an Angular 22 mobile PWA with native IndexedDB storage, atomic multi-store transactions, interactive field SVG tap handling, roster queues, and comprehensive reporting.
It even added a hands-free feature not explicitly mandated in the brief: voice-assisted player selection using the browser’s native SpeechRecognition API. If a coach is holding a bat or standing on the field, speaking a player’s jersey number or name automatically switches the active batter in the queue without touching the screen.
When its implementation pass completed, Gemini ran local validations:
- Zero lint errors.
- Prettier style conformance.
- 37 unit tests passing across domain math, coordinate translation, transfer parsing, and repository transactions.
- All 4 Playwright viewports (
phone-portrait,phone-landscape,tablet-portrait,desktop) passing cleanly in 29.5 seconds. - GitHub Actions workflow run 34041085290 succeeded on the first attempt with an HTTP 200 response on GitHub Pages.
Shortly after finishing, a snapshot of the Antigravity IDE revealed this:
Gemini’s completion snapshot: the full application was built, verified across four viewports, and deployed to GitHub Pages with roughly 79% of its 5-hour model quota still intact.
A quick word of caution about that screenshot: do not read a 79% remaining quota meter as proof that one model is universally four times faster than another.
Quota meters reflect tokens, tool calls, and API credits measured against a specific tier’s rolling window on a specific run. They are not stopwatch benchmarks.
What it does illustrate, however, is that for this specific task, Gemini took a very direct, economical path from specification to working production code without spinning its wheels.
There was one small experimental asymmetry worth noting in the interest of full disclosure: during Gemini’s initial planning pass, it flagged a slight naming ambiguity between “Coach” and “Practice” in the starter notes. The human responded with a quick one-sentence clarification before Gemini proceeded. Astra did not receive that exact prompt exchange. While unlikely to explain the divergence in workflow, it is part of the honest experimental record.
Astra’s Run: The Quota Odyssey
Where Gemini’s run was a tidy morning sprint, GPT-6 Astra Ultra’s run in Codex was an all-day endurance marathon.
Astra began building baseball-coach-helper with immense ambition. It wrote extensive domain models, interactive SVG field layouts, and rich settings dashboards. But it also dove deeply into edge cases: building custom concurrency protections so that multiple browser tabs editing the same practice wouldn’t clobber each other’s queue state, writing robust backup merge algorithms, and constructing multi-viewport end-to-end tests.
That thoroughness had a steep cost. At 2:22 PM, right in the middle of implementation, Astra hit the wall:
Astra’s first quota wall: 0% of its 5-hour allowance remaining at 2:22 PM while implementation was still actively underway.
Like the Moss & Ember run yesterday, the quota meter had treated the job like an all-out sprint and exhausted its entire 5-hour allowance.
Hours later, the window refreshed and Astra resumed:
Astra resuming later in the evening, working on browser tests, concurrent-tab writes, and backup merges, burning its allowance down to 3% at 10:40 PM.
As Astra noted in its progress log:
“The unit suite is passing, and lint is clean. Browser testing is now covering the full coach workflow and file restore. I also strengthened concurrent-tab writes and backup merges so an older queue state cannot silently overwrite a newer practice.”
At 10:41 PM, a fresh 5-hour allocation kicked in:
10:41 PM: A fresh continuation opens with 100% of the 5-hour allocation available.
Astra immediately sprinted into final test execution. In less than an hour, it burned through almost that entire fresh allowance—dropping from 100% down to 6%:
In under an hour, Astra completed its test passes, dropping its quota meter down to 6%, and pushed commit 94a367c to GitHub.
By the time it pushed commit 94a367c5b11ebf3121005490ab0509ea47c013c9 (“Build Baseball Coach Helper local-first coaching app”), Astra’s local verification was formidable:
- 54 unit tests passing.
- 49 Playwright browser checks passing across five viewports.
- 1 production offline/PWA test passing.
- Clean formatting, linting, and production builds.
Locally, Astra had built a rock-solid piece of software.
Then it met GitHub Actions.
The Pipeline Failure
What happened next is one of the most delightfully relatable moments in software engineering.
Astra pushed its code to GitHub, expecting the CI pipeline and GitHub Pages workflow to build, verify, and publish the app automatically.
Instead, red crosses lit up across the repository:
Commit 94a367c pushed to GitHub: 2 failing checks, 1 successful, and 1 skipped.
Both the Deploy to GitHub Pages workflow and the CI / Lint, Test & Smoke Validation workflow failed.
Looking at the Actions log revealed that this was not a syntax error, a broken TypeScript type, or a failed unit test:
The Pages workflow failure: Playwright timed out waiting 120,000ms for config.webServer.
The CI validation workflow failed at the exact same step: config.webServer timeout after two minutes.
Every earlier step in the pipeline had flown through:
- Node.js setup: 0s
- Install dependencies: 11s
- Check code formatting: 2s
- Run linter: 3s
- Run unit tests: 5s
- Configure Pages base path: 1s
- Build production application: 6s
- Generate SPA 404 fallback: 0s
- Install Playwright browsers: 20s
Then the pipeline reached Run coach workflows across five viewports. Playwright started the local Angular development server to run headless browser checks, waited two full minutes for it to respond, received nothing, and threw:
Error: Timed out waiting 120000ms from config.webServer.
Because the test step failed, the workflow exited, the deployment artifact was never uploaded, and GitHub Pages never published.
And Astra had just spent 94% of its remaining quota allowance pushing that commit. It had no meaningful runway left to troubleshoot the failure.
It would be tempting to frame this as “Astra failed to build the app.” But that would be inaccurate. Astra had built the app. The code was completely functional. It had simply tripped over the final, invisible wire of remote CI networking.
Gemini’s One-Line Rescue
At this juncture, we made a deliberate human decision: be sportsmanlike.
Declaring Astra’s application non-existent because an Ubuntu GitHub runner had a networking hiccup with a local dev server would ruin an otherwise fascinating comparison. Astra had done the hard work of implementing the entire coaching notebook.
So we invited Gemini 3.8 Flash back into the ring for a strictly bounded rescue mission:
Do not touch Astra’s application code. Do not redesign the UI or refactor its logic. Inspect the CI failure, find the smallest possible correction to get Astra’s existing application through GitHub Actions and onto GitHub Pages, and preserve clean attribution.
Gemini opened baseball-coach-helper, inspected the GitHub Actions logs, and looked at playwright.config.ts and package.json.
The diagnosis took less than two minutes:
- Playwright was configured to poll
http://127.0.0.1:4200to verify that the dev server was ready before launching browser tests. - Astra’s
package.jsonstarted the dev server using the default Angular command:"start": "ng serve". - On modern Linux GitHub Actions runners,
ng servebinds tolocalhost, which frequently resolves to IPv6::1rather than IPv4127.0.0.1. - While the server was happily listening on IPv6, Playwright’s polling against
127.0.0.1received continuousECONNREFUSEDerrors until the 120-second timeout expired.
Gemini changed exactly one line in Astra’s package.json:
"scripts": {
"ng": "ng",
- "start": "ng serve",
+ "start": "ng serve --host 127.0.0.1",
"build": "ng build",
That was it. No component changes, no CSS tweaks, no domain modifications.
Gemini committed the fix under commit 7fe64a62d8aa52fdc42307ec6df927c2ee0cc13b with explicit attribution:
commit 7fe64a62d8aa52fdc42307ec6df927c2ee0cc13b
Author: Chris <christopher.boler@gmail.com>
Date: Sun Sep 6 23:31:24 2026 -0500
fix: repair CI and Pages deployment for Astra implementation
The result?
- CI passed completely.
- 54 unit tests passed.
- 49 cross-viewport browser checks passed.
- The production PWA offline check passed.
- GitHub Pages deployed immediately.
Gemini then verified the live deployed Astra application in a real browser—confirming team creation, field taps, roster editing, reload persistence, and console health.
The clean attribution of this experiment is: Astra built Baseball Coach Helper. Gemini fixed one line of its deployment harness so the world could actually use it.
Head-to-Head: What the Agents Actually Built
When you set aside the quotas and the pipeline rescue, what did these two independent agents actually produce from the same product idea?
The most remarkable finding is how much the two implementations resemble each other. Without any shared communication, both models independently converged on:
- A local-first client architecture using native browser
IndexedDB. - An installable, offline-first Progressive Web App.
- A dark green and warm cream ballpark color scheme.
- A four-tab bottom navigation bar (
Practice,Roster,Reports,Settings). - Rapid coordinate capture by tapping an SVG baseball field.
- Roster management requiring team initialization before batting practice.
- Multi-team support and customizable practice defaults (pitcher handedness, rotation modes).
- Full JSON backup and CSV export capabilities.
Yet each model demonstrated genuine, distinct strengths that reflect different engineering personalities.
Where Astra Won Points
- Favicon and PWA Icon Polish:
If you looked closely at the browser tabs in the earlier screenshots, you might have noticed something interesting: Astra’s app had a custom baseball-diamond icon in the tab, while Gemini’s app was still displaying the default Angular red shield.
How did Astra pull that off? Inscripts/generate-icons.mjs, Astra wrote a standalone Node script that booted headless Playwright, rendered its custommark.svgacross eight standard PWA dimensions (from 72x72 to 512x512), and programmatically assembled a genuine binarypublic/favicon.icocomplete with icon directory headers. Gemini drew a nice SVG mark, but left the starter template’s defaultfavicon.icountouched. Astra took the extra step to make the browser tab look like a finished brand. - Multi-Tab Concurrency Hardening:
Insrc/app/data/repository.ts, Astra added ametadatastore with revision UUIDs. Before applying any atomic transaction, it compares revisions to ensure that if a coach has two tabs open on a phone or laptop, a stale tab cannot silently overwrite newer batting practice data. - Exhaustive Automated Testing:
Astra produced 54 unit tests and 49 Playwright end-to-end assertions spanning five separate viewports, plus a dedicated offline PWA test (e2e-pwa/offline.spec.ts) that verifies the production bundle functions with the network disabled.
Where Gemini Won Points
- The Reports Experience:
Gemini’s reports suite feels like software built for a baseball coach. In addition to a clean spray chart, it provides a togglable Density Heatmap showing where balls are concentrating, an automated Spray Tendency calculation (Pull %, Center %, Oppo %), pitcher handedness breakdowns (vs RHP / vs LHP), and contact quality distributions (Dribbler, Ground Ball, Line Drive, Pop Up). Astra gave coaches a solid spray chart and CSV export, but Gemini gave them analytical insight directly inside the app. - Voice-Assisted Player Selection:
Gemini anticipated the physical reality of batting practice: a coach often has one hand on a fungo bat or a bucket of balls. By integrating the Web Speech API directly into the field header, a coach can speak a player’s name or number to immediately change the batter without tapping the roster list. - Onboarding and Product Narrative:
Gemini’s copy and UI state management feel slightly more cohesive. The transition from naming a team to setting up a lineup and stepping onto the field has an intuitive, guided flow that explains the value of the notebook at every step.
The Human Verdict
After spending the evening testing both applications on desktop and mobile, entering practice rounds, and reviewing the codebases, the verdict is:
Gemini 3.8 Flash won this experiment.
It is not a blowout. Astra built a completely legitimate, contender-grade application with superior icon generation, great concurrency guards, and an enormous test suite.
But Gemini built the better baseball app.
Gemini’s implementation feels richer, more polished, and more closely attuned to how a coach actually thinks at the field. The heatmap analytics, the situational splits, the voice input, and the clean execution give it that extra layer of product maturity that turns a functional prototype into something you would happily hand to a high school or travel-ball coach tomorrow.
A fair summary of the contest is:
Astra built a formidable contender. Gemini built the app you’d actually keep on your home screen.
What This Really Means
It is easy to turn an experiment like this into a trivial contest of model superiority. That misses the real story.
Consider the history of this project:
- A youth baseball coach identified a real-world workflow problem during batting practice.
- A software developer cared enough to turn it into a clear, detailed specification in 2020.
- That specification sat completely dormant in a drawer for six years because building bespoke mobile utilities is tedious, time-consuming, and expensive.
- On a single Sunday in September 2026, the cost and friction of building software dropped so dramatically that a single person could feed that same old specification to two different AI coding agents and receive two fully functional, tested, installable, production-ready applications before the weekend ended.
Both applications exist. Both are hosted for free on GitHub Pages. Both store data privately on your device. You can open either one right now, add your kid’s team, and track their batting practice tomorrow afternoon.
That is the true shift. It isn’t that one model scored a few percentage points higher on a synthetic benchmark. It is that the distance between a good human idea and functioning, deployable software has collapsed to near zero.
Article Provenance
In the spirit of honest technical documentation, here is how this article was produced:
- Human (Chris Boler): Provided the original baseball specification, designed the experiment, conducted the runs, performed the one-line deployment intervention, tested both live applications, and rendered the final product judgment.
- GPT-5.6 Sol: Analyzed the raw session evidence, reconstructed the timeline from timestamps and commit logs, evaluated the experimental methodology, and synthesized the editorial brief.
- Gemini 3.8 Flash (High): Authored the final Jekyll article, implemented the interactive blind reveal component, organized the screenshot evidence, and verified the site build.
If you have an old product specification sitting in a text file somewhere, maybe it’s time to dust it off.