Business Viability
A real product with real users — sign-up, analysis, and feedback all in production — and open books: costs are pulled nightly from billing APIs by the same system that runs the app.
4thCoach is a real business run by one person — which is only possible because AI does the operating: analyzing every clip, routing every model call, keeping the books. This page documents that machinery, with numbers. It's the evidence file for theBuild With Gemini XPRIZE.
A real product with real users — sign-up, analysis, and feedback all in production — and open books: costs are pulled nightly from billing APIs by the same system that runs the app.
AI isn't a feature here; it's the staff. Models make production decisions on every clip — classification, routing, quality scoring — scheduled jobs do the back office, and a fleet of scheduled AI agents reviews the business itself: costs, security, release state, business trends, and Android parity, each posting its findings to public GitHub issues.
Education & Human Potential: 4thCoach turns the clips already on a phone into patient, repeatable coaching for anyone working at a physical skill — a swing, a sprint, a lift, at any age — closing a feedback loop most people never get, on video handled the way children's video should be.
The three judging criteria, equally weighted. Ties break on Business Viability first. — geminixprize.com/rules
Everything that makes this a business was built inside the contest window: 3,409 of 3,540 commits (96%), ~655K lines, the entire production backend, and every loop below. Full disclosure, because the rules ask for it: the first commit is 05/13 — an iOS spike, one of many personal AI explorations over the past ~24 months — and I found out about the Build With Gemini XPRIZE on 05/26, after the window had already opened.
First commit: an iOS spike — one of many personal AI explorations over the past ~24 months. 131 commits of prototype existed on day one.
96% of all commits (3,409 of 3,540) and ~655K net lines land after this date.
Learned about the Build With Gemini XPRIZE two days after the real backend went live on Cloud Functions + Firebase, with Gemini on Vertex AI as the production brain — and decided to build a submission around what was already running.
Prod data protection (PITR, backups, delete-protection), separate staging/prod projects, gated deploys.
TestFlight + Firebase App Distribution rings; features soak on staging before a human cuts the prod tag.
Moment feedback shipped, live scoreboard on the site, this proof page — the business starts marketing itself.
Vertex-only inference, a 180-day media expiry that keeps the coaching and drops the footage, audited admin access, and an adult-account gate at signup — the safety half of a product built on children's video, shipped before the submission rather than promised in it.
1:00pm PT. The window closes.
● = Google stack · Gemini API powers every analysis in production
From upload to coaching, the pipeline runs itself. The cyan stages are decisions AI makes in production on every single clip — which sport this is, which model to use when capacity shifts mid-request, and whether each finding is actually backed by what's in the video.
Anyone can post a video to an API. The distance between that and a product a parent trusts is all in the layer around the call — how the video is sampled and delivered, what happens when the model is uncertain or at capacity, what happens when it returns something half-broken, and how a prompt change is allowed to reach a real kid's clip. Prompt v3.26, 2 models, every call on Vertex.
Gemini samples video at roughly 1 fps by default. A swing or a pitch is about one second long, so the default can miss the entire event — early clips came back described as unanalyzable still images. Every analyze call sets the sampling rate on the clip part itself, which is why athletic motion registers at all.
Clips under 14 MiB are sent inline. Anything larger is handed to Vertex by storage URI instead, so the bytes are never downloaded into the function at all — the difference between a request that works at 40 MiB and one that dies trying to base64 it.
Flash handles the normal case. A low-confidence read escalates to Pro; a capacity error walks to the next entry rather than failing the user. The whole chain runs against a time budget that reserves room for the validation, judging, and writes that happen after the model returns.
Responses are validated against a schema before anything reaches a user. A response that is partly malformed doesn't fail whole — the valid findings are salvaged and the bad paths dropped, because one broken field shouldn't cost a parent the other four things the model got right.
Analyze results are keyed by a content hash of the clip and the assembled prompt. A re-analysis that would produce an identical call skips the model entirely and serves the cached result — the cheapest inference is the one never issued.
The analyze prompt is at v3.26 — the minor is a real count of shipped iterations of the v3 line, each one gated by the eval harness before it could ship. Prompt changes are reviewed, versioned, and regression-tested, not edited live.
Every prompt change is gated by the harness inevidence it works ↑ · the Vertex pin and why it exists is in handling minors' video ↓
Every change to the coaching brain runs a gauntlet first: a golden set of real clips with hand-authored ground truth, 12 deterministic scorers, and an LLM judge grading every finding on 5 axes — specificity, actionability, correctness, tone fit, grounding. A replay harness re-runs the real production corpus to catch regressions before they reach a single kid's clip.

That is a responsibility before it is a product decision, so the guardrails were built into the pipeline rather than bolted on for a submission — 5 of them run in production today, and each one is a line of code a judge can go read.
None of them ask how old you are. The same rules govern every clip and every account: an adult working on a squat gets the video handling, the retention limits, and the coaching boundaries a nine-year-old's swing gets. Minors set where the bar sits — everyone gets the bar.
Athlete video is frequently of minors, so no clip ever touches the consumer AI Studio surface, whose terms historically may use submitted content for training and human review. Vertex AI's enterprise terms do neither. buildProductionChain() rewrites any @aistudio entry back to @vertex, so even an environment-variable override can't reintroduce it.
since 2026-06-16A daily sweep deletes source video and audio 180 days after upload and flips the clip to an expired state, with a storage lifecycle rule as backstop. Findings, trends, and the poster frame persist — the value outlives the liability. Users are told the window up front, so expiry is never a surprise.
since 2026-07-23Admin access to any clip writes a durable record — who, which clip, when. It's a top-level collection on purpose: a record nested under the session would die with the session, which is exactly when a retroactive question would need it.
since 2026-07-14Storage rules scope every read and write to the owning account, cap uploads, and deny client-side update and delete outright — deletes go through a function so media and metadata can never drift apart. A scheduled job re-checks the deployed rules against the repo daily and fails loudly on drift.
since 2026-07-07Point-in-time recovery over a rolling 7-day window, automated daily snapshots, and delete protection on the production database — so no API call or console mis-click can take it out.
since 2026-05-30The whole minor-data posture rests on the account holder being an adult, with any child in a clip a subject whose guardian consented. A neutral date-of-birth screen now blocks account creation for a self-identified minor, and the server refuses to analyze for an account with no adult attestation. Deliberately stores the verdict, never the birth date. Server enforcement is staged behind a flag until the build carrying it is in users' hands.
since 2026-07-25Coach chat is the one surface where a user types freely, and the subject is a child's body. A scope block now bounds it: no medical or injury judgment, nothing evaluative about anyone's body in EITHER direction — praise about a kid's build teaches the same lesson criticism does — and any sign of real distress routes to a trusted adult instead of a drill. Asserted by tests so a prompt refactor can't quietly drop it.
since 2026-07-25Every model call now pins its own harm-category thresholds instead of taking whatever the SDK default happened to be — a default that can change under you with no record that it did. Strictest on sexual content; deliberately moderate on 'dangerous', because youth sports is full of imagery a naive classifier reads as violent and blocking a bat swing protects nobody. A withheld response is handled as a content outcome, not an outage, so the block rate stays visible.
since 2026-07-25One tap on a finding or a coach reply files a report — no explanation required, because friction in front of a harm report is friction that loses reports. Reports land in their own collection, never the general feedback queue: sharing a queue would mean a report about a child gets ranked against feature requests. The daily ops job trips on any unread report older than 24 hours, with no volume floor. Owner and response times are written down, including that the backup is currently nobody.
since 2026-07-25The COPPA / minor-data position is written up and pending counsel review — listed as pending rather than claimed, same as everything else on this page.
40 dashboard views over pre-aggregated rollups — growth, quality, cost, and ops — built for a staff of one. Spend is pulled nightly from three billing APIs. Model toggles take effect in seconds and every flip is audit-logged. Nothing here requires a data team; the data team is a cron schedule.

The submission requires revenue by month, total costs, marketing spend, and related-party revenue reported separately. Here they are — kept honest automatically, because costs are recorded nightly by the same billing syncs that run the business. Revenue is the youngest number on this page: both rails are wired end-to-end, and neither has recorded a sale yet.
The rules ask for "evidence that playbooks are running in production continuously." This is the playbook roster — every scheduled and event-triggered job, and the human work it replaces.
10 Event-triggered · 19 Scheduled syncs & rollups · 12 AI agents · 1 Maintenance routine
| Job | Runs | What it does for the business |
|---|---|---|
| Event-triggered · 10fire on product and crash events | ||
| onClipFinalized | on every upload | Runs the full AI analysis the moment a clip lands in Storage — classify, analyze, judge, validate, persist. |
| onPosterFinalized | on every upload | Classifies the sport off the poster frame, minting a new activity into the catalog if it's one the catalog has never seen. |
| onSignupCreated | on every signup | Sends the welcome email without a human touching the list. |
| onGoogleRtdnMessage | on Play Store event | Ingests Google Play real-time developer notifications so Android subscription state stays server-authoritative. |
| onPlayerCreated | on every player added | Enforces the plan's player cap at write time. |
| onSessionDeleted | on delete | Cleans up analysis subcollections and media when a user deletes a session. |
| onSessionScopeChanged | on player/sport/skill edit | Reconciles the issue ledger when a session's scope changes so a pattern never tracks against the wrong athlete or skill. |
| onCrashlyticsFatalIssue | on Crashlytics alert | Pushes a fatal iOS crash into the same ops feed that watches the backend — Crashlytics has no poll API, so this is event-driven, not a cron. |
| onCrashlyticsRegression | on Crashlytics alert | Flags a previously-resolved crash that came back. |
| onCrashlyticsVelocity | on Crashlytics alert | Flags a crash spiking in frequency before it becomes a fatal-issue alert. |
| Scheduled syncs & rollups · 19keep the books, metrics, and hygiene current on a cron | ||
| bizopsRollupSync | daily | Rebuilds the business-cockpit rollups, timed after the billing syncs so same-day cost data is folded in. |
| userBlockersRollupSync | daily | Rebuilds the fleet-level view of which users are stuck and where. |
| ledgerBackfillSync | daily | Self-heals any issue-ledger key that a prior backfill missed. |
| sessionsRollupSync | hourly | Aggregates usage events into the KPI rollups the dashboard reads. |
| dailyRollupSync | hourly | Builds 90 days of per-day metrics: sessions, failures, active users, activity heatmaps. |
| funnelRollupSync | daily | Recomputes the sign-up → import → first-analysis → feed funnel. |
| gatesRollupSync | daily | Recomputes the gate metrics the roadmap is judged against, including paying subscribers. |
| billingSync | daily | Pulls Google Cloud spend from the BigQuery billing export; flags cost spikes. |
| anthropicBillingSync | daily | Pulls LLM-judge spend from the Anthropic cost report. |
| githubBillingSync | daily | Pulls CI/build spend from GitHub billing. |
| pricingSync | daily | Discovers current per-model pricing from the Cloud Billing SKU catalog. |
| modelsSync | daily | Discovers available models and probes each for callability. |
| mediaExpirySweep | daily | Deletes expired source video while preserving the session and its findings, so coaching outlives the file. |
| compExpiryReminderSync | daily | Warns time-boxed comped users before their access lapses — no silent expiry. |
| sportTaxonomySync | on change + daily | Promotes provisional activities to permanent once enough distinct users hit them, and merges duplicates. |
| coachReviewBatchSync | weekly | Composes an uncertainty-weighted clip batch for the human coach panel to label. |
| progressRecapSync | weekly | Sends each family a recap of what changed in their athlete's patterns. |
| winBackSync | weekly | Reaches out to families who stopped uploading, referencing their own players. |
| triggerStatus | every run | Every job above logs its own completion, latency, and errors for ops visibility. |
| AI agents · 12read production and post their findings to GitHub | ||
| agent-ops-digest | daily | An AI agent reads production health end-to-end — failure rates, costs, crashes, feedback, ledger freshness — and posts a dated digest, filing and now also closing its own issues as conditions clear. |
| agent-bizops | daily | An AI business analyst re-evaluates every open observation against fresh data, writes new schema-validated ones through a deterministic I/O harness, and files roadmap issues for the ones that demand action. |
| agent-release-train | daily | Reports what is merged but undeployed per release channel and composes the exact tag command a human would push — the AI decides what should ship; a human pushes the button. |
| agent-chief-of-staff | daily | An AI chief of staff reads the rest of the fleet's findings plus the triage and PR queues and posts one ranked 'top 3 today' brief — a synthesizer bound by an anti-noise contract: it files no issues and holds no credential at all. |
| agent-usage-report | weekly | Writes the per-user prod usage narrative: who used the product, what failed for whom, and whether features are used as intended. |
| agent-authz-sweep | weekly | Security review of route auth, Firestore/Storage rules permissiveness, credential hygiene, and the agent fleet’s own privileges. |
| agent-gtm-funnel | weekly | Drafts the go-to-market funnel report from prod signup and funnel rollups. |
| agent-growth | weekly | Drafts up to three send-ready growth assets — outreach, listing copy, testimonial requests with an explicit consent ask — grounded only in shipped features and public pages. Drafts only: the founder sends; the agent never publishes or emails. |
| agent-cost-guardian | weekly | Owns week-over-week cost trends across GCP, GitHub, and Anthropic spend, plus CI run-shape anomalies. |
| agent-parity-ledger | weekly | Diffs two weeks of shipped iOS changes against the Android port and maintains the public parity ledger: ported, n/a, or gap. |
| agent-architecture-review | monthly | Judgment-level architecture review, capped at five findings so every one is worth reading. |
| agent-doc-truth | monthly | Verifies checkable claims in the ops docs against the code and opens a correction PR when reality drifted. |
| Maintenance routines · 1change code, but only as draft PRs a human reviews | ||
| routine-dead-code | weekly | Finds dead code, verifies the build stays green without it, and opens a draft deletion PR for human review. |
Every loop below is a signal, a decision, and an action. Closed means the whole cycle runs without a human. Closing means the work is underway. Open means a human is still the middleware — listed anyway, because a trajectory you can audit beats a claim you can't.
a closed ring runs itself · a spinning ring is being closed · the dot in the broken ring is a human, still doing that step
The clearest way to see the difference between AI that advises and AI that runs things is to follow a single loop all the way through. Think of the "coaching recipe" as the instructions the AI follows when it looks at a swing and decides what to say.
AI changed what the product says to real families, and held the power to stop a release until it was satisfied. A human still pushes the production release button — that gate is deliberate, and it is the only step in this loop a person performs.
This page is maintained by an agent skill — proof-sync — that re-inventories the codebase, refreshes every number above, diffs the claims against reality, and opens a pull request the founder reviews. The roadmap that schedules that work is itself groomed by agents in GitHub issues. Product strategy lives in a separate knowledge base with one standing rule: when a document disagrees with shipped code, the code wins and the document gets fixed.
Watching the race? The live scoreboardtracks clips, total users, and revenue against the deadline — and thefounder letter explains why this exists at all.