Skip to content

How this was built

In short

The code, tests and most documents were written by an AI coding agent, Claude Code, working in the maintainer's repository: it proposed options and a recommendation at each decision point, the maintainer chose, and the maintainer merged every pull request.

Tools and models

Claude Code (Anthropic's command-line coding agent), running in the VS Code extension, with the model Claude Sonnet 5.5 (claude-sonnet-5-5). Every agent commit carries Co-Authored-By: Claude Sonnet 5.5. PX4 SITL with Gazebo for simulation, MAVSDK for vehicle control, FastAPI for the backend, React, TypeScript and MapLibre for the console, GitHub Actions for CI. ROS 2 was in the original spec and is not used.

Who did what

Maintainer Agent
Direction Every product and technical decision (below); scope and ethics guardrails; what to build next Options with evidence and a recommendation each time
Code and tests Read, reviewed and merged the pull requests Wrote all of it
Simulation and measurement Ran the machine and fixed the environment (Docker memory and disk) Ran the experiments and wrote the harness; reported numbers from the data
Product docs Owns them First drafts, at the maintainer's request
Usability sessions Plans and runs them Wrote the kit and the extractor
Weekly status, risk log Owns them Drafts

Facts from git (snapshot of 2026-10-10)

Repository history 8 to 10 October 2026 (the planning before it is not in the repository)
Non-merge commits on main 27, all authored by the agent
Merge commits on main 18, all by the maintainer
Pull requests 17 merged, 2 open when this was written
Issues 14 closed, 5 open
Python / TypeScript / YAML / Markdown lines about 6,900 / 1,700 / 160 / 1,200 (before these docs; excludes dependencies)
Tests 269 Python, 23 console; CI runs lint, types and tests with no simulator
Recordings 32 simulated runs with ground truth, with a results table CI regenerates
Architecture decision records 3, each recorded on the maintainer's instruction

Reproduce: git log --no-merges --format=%an | sort | uniq -c, gh pr list --state all.

The decisions, and who made them

At each point below the agent laid out options. The maintainer decided.

What went wrong, and how it was found

A public list. Each row is a mistake in the agent's work, found by the method in the third column.

# What went wrong How it was found Where fixed
1 Issue 5 was written from PX4's main documentation, which does not match the pinned v1.17.0: GPS failure injection for Gazebo did not exist there The injection command timed out PR 22 pinned a main commit
2 Two wrong diagnoses of a silent failure injector (a shared UDP port, then a silent loop) before the real one: it crashed on the timeout Reading the full output PR 22
3 The escalation timer counted the 2 s recovery hold as outage time, so a 4 s outage went RED A test I wrote passed by 0.02 s, which looked wrong PR 27
4 Assumed a vehicle with a frozen GPS position stalls in place, and recommended HOLD Ground truth showed it flies away at up to 36 m/s PR 32, ADR 0003
5 Told the maintainer a faulted vehicle was "in HOLD", which was true of its mode but not shown to have stopped it Same experiment PR 32
6 The first HOLD and RTL experiment was unfair: the injector cleared the fault whenever the believed position left the zone Reading the trace PR 32 (redone with a latched fault)
7 A check I added to stop a hang crashed the recorder when PX4 landed a vehicle by design, and aborted the whole batch The first long-outage run PR 33
8 A bare off in YAML is read as False A test PR 33
9 Matching ground truth to the nearest sample added up to 5 m of false error at 10 m/s The nominal runs showed an error floor PR 33 (interpolation)
10 Briefly took a recording still being written for a failed run Checking the batch log not committed
11 "Closes #X and #Y" closes only the first issue; five finished issues stayed open Reading the issue list closed by hand
12 An unanswered recommendation was never marked expired in a live session, so ADR 0003's re-issue never happened; my earlier test hid it by calling GET /state Running the usability flow end to end PR 34
13 The console clock read T+NaN:NaN at the start of every session Same PR 34
14 The console's map worker failed to load, its container collapsed to zero height, and the server had no WebSocket library Looking at screenshots PR 31
15 The held-out report quoted the development set's flight hours Re-reading the totals before opening the PR PR 35
16 The displayed position bound (about 0.15 m) was the estimator's own figure and held in 30.8% of reports; spec requirement NT-03 was not met. I had called it "not validated" earlier but still displayed it Measuring it against ground truth PR 37
17 Wrote that the 3 m nominal error was "roughly 0.3 s of lag"; a time-shift analysis refuted it Checking before building a confidence on it PR 37
18 4,073 files of console/node_modules committed by git add -A on a branch with an old .gitignore; CI passed regardless Counting lines in the repository PR 38 (untracked; still in history)

The pattern: the agent's own checks (tests, the type checker, CI) passed in most of these. What found the problems was running the system, measuring it against ground truth, and reading the numbers back.

Luckily the agent collected and archived the errors and will use it as context to avoid them in the future

What the agent could not do or did not verify

  • It cannot tell how closely each pull request was read; that is the maintainer's to state.
  • Everything was measured in simulation. No real receiver, no real interference, no operator under stress. The usability sessions have not happened.
  • Several results rest on few runs (2 to 4 per scenario, one run per action in ADR 0003).
  • The held-out set is no longer held out for this version of the engine.