Inspiration

Production incidents are where engineering skills are the most important, but practicing them safely is hard. RepoRehearsal was inspired by the idea that developers should be able to rehearse realistic failures without risking an actual repository, deployment, or customer.

The goal is to turn a repository into a focused debugging exercise by allowing the user to inspect evidence, repair an intentionally introduced fault, validate the fix, and receive a clear score and after-action report.

What it does

RepoRehearsal takes a repository, either from our own collection of 110 random GitHub repos or one of your own that you can upload.

It then:

  1. Learns it. Identifies services, routes, migrations, tests, and reliability risk surfaces.
  2. Breaks an isolated copy. After a clean baseline passes, it creates one deterministic, realistic fault at a real code boundary such as but not limited to a missing null check, a container hostname pointing at localhost instead of a Docker Compose service, a required field that a secondary write-path forgot to populate. The actual source repo is never touched an all the editing is done by the site.
  3. Scores the investigation, not just the fix. You get a whole workspace that isn't limited to a single file code editor. The workspace includes a file explorer, code editor, terminal, logs, database inspector, health checks, and a set of investigation tools (inspect logs, compare records, run tests, run build/lint, restart, check health). The final report grades six categories: Diagnosis, Investigation, Fix Quality, Verification, Prevention, Communication. These are graded from what you actually did, not from whether the final diff compiles or passes a couple tests.

Building off the core functionality:

  • Daily Challenge - one common repo with a leaderboard, the same prompt and scoring contract for everyone that day.
  • Repository-derived incidents - point it at a real Go, Python, Java, C#, or Rust service and it analyzes the source to find a genuine "repairable behavior boundary" and injects a fault there. It acts less like a canned problem and more like an actual incident you'd run into in the real world.
  • Team Incident Studio - turn a real pull request that fixed a real bug into a reusable training scenario: the pre-fix diff becomes the fault, the reviewed post-fix lines become the known-good baseline, and a manager-reviewed evidence/validation contract turns "we had an outage" into "now everyone can safely rehearse it."
  • Verified, portable results - a shareable result page and badge markdown, so a strong score means something outside the app, not just inside it.
  • Candidate debugging screens - the same rehearsal engine, repointed at hiring: one link, one isolated incident, every applicant sees the same thing, results land back with the hiring manager.

How we built it

The product runs on a Cloudflare Workers + D1 stack with a TypeScript/React front end, deployed as a static-adjacent app with server-rendered routes for the workspace and report pages (so state like "which file is open" and "what evidence has been gathered" survives properly instead of living only in client memory).

The core engineering problem was the fault injection and scoring engine: for the hand-authored scenarios, each incident is built from an explicit contract so that grading never has to guess whether a fix is "good," it just checks the contract. For the repository-derived incidents, that same contract has to be synthesized on the fly: the system analyzes an arbitrary imported repository, finds a real, "repairable behavior boundary" (a spot where a plausible, safe, reversible fault can be injected without corrupting the rest of the codebase), and builds the same evidence/validation contract around it automatically, reporting a confidence match score so the incident stays honest about how well-grounded the generated fault is.

For the PR-to-incident pipeline in Team Incident Studio, the input is a real diff and the the tool treats the reviewed, merged fix as the known-good state and reconstructs the pre-fix state as a safe, reversible fault, which lets a team turn its own postmortems directly into training material instead of writing scenarios from scratch.

We used Codex as an active build partner throughout including but not limited to implementing features from spec, running the test suite, and shipping to Cloudflare. All this while a separate agent ran continuous, adversarial QA passes against the live site after every round of changes: clicking every link, filling every form, deliberately submitting broken or empty states, and comparing what the UI claimed against what actually happened in the DOM and network tab. That loop caught real problems a changelog alone wouldn't have such as broken filters that looked fine in a demo, "curated repository" cards that silently discarded the user's selection, a scoring report that praised evidence it then scored zero, a genuinely good feature (the public Team Studio demo) that shipped without a single link pointing to it anywhere on the site. The second agent saved the site with the repeat tests to make sure the site did what it claimed to do.

Challenges we ran into

  • Making fault injection deterministic and realistic. A fault that's too synthetic doesn't teach anything; a fault that's too clever isn't safely reversible. Every hand-authored scenario needed a validation contract precise enough to grade fairly without being so rigid it only accepted one exact fix.
  • Scoring fairness at the edges. An early version of the grading logic zeroed every category the moment a rehearsal was submitted without an edit, while the same report's own evidence log praised that investigation. The rule itself (no credit for an untouched repository) was correct, however the presentation contradicting it wasn't, and it took a dedicated audit pass to even notice the report was arguing with itself.
  • Trusting AI-generated content at production quality. The repository-derived incident pipeline is powerful, but it also means every generated scenario needs its own quality bar.
  • Shipping fast without losing the thread. Across several rapid iteration rounds it was easy for genuinely good features to land without the surrounding site catching up. New pages that worked perfectly but weren't linked from anywhere a real visitor would find them, such as a button not being connected. The fix was easy once caught, but it almost left a few key features inaccessible.

What we learned

The hardest part of building a tool that teaches debugging turned out to be debugging the tool itself with the same discipline it asks of its users: don't trust the changelog, reproduce the claim, check the evidence trail, and don't call something done until you've actually seen it work end to end.

Built With

Share this project:

Updates