An AI agent's report always sounds confident. Most of our harness is about making sure each claim is backed by evidence, and that anything without evidence is labelled.
The honest label
The developer asked whether the app was ready for an upcoming iOS SDK. The agent researched the platform docs, built the app against the new SDK, and reported: "build green, runtime launch unverified."
A week later, the app crashed on launch on a device running the new OS. The label had pointed straight at the gap.
Since then, every agent report and pull request description ends with two lists:
- Checked: what the agent actually ran or observed.
- Not checked: what it couldn't verify, such as anything that needs the VPN, a physical device, a real login or a production account.
A reviewer reads "Not checked" first.
Tests first, with proof they fail
Need Help Implementing This?
Our team can help you put these ideas into action. Get in touch for a free consultation.
- Baseline first. The agent runs the full suite before touching anything, and names any failures that already exist so they aren't blamed on the change.
- Show the red. It writes the failing test, shows it failing ("All 14 new tests fail as expected"), and only then implements the fix.
- The volume. In one month on the consumer app the agent ran tests about 700 times, type-checked 240 times and linted about 130 times. Edits to test files (255) nearly matched edits to source files (314).
- The trend. On the portal, sessions that wrote the test before the source rose from 8 in 19 to 14 in 17 over three weeks.
Some tests guard native configuration and security properties instead of features. They fail if the scene lifecycle declaration, the network trust configuration or the readiness of over-the-air updates changes by accident. A refactor can't quietly undo a fix that took a day to find.
Read the output, not the exit code
Green and red are both claims, and both can be wrong:
- Known false failures. The portal's verify script reports about 41 failures that don't matter. The instruction file says to read the output, not the exit code.
- The wrong command. One type-check mode reported "clean" five times while a file-name clash sat in the code. The file now names the right command.
- Suites that are always red. End-to-end suites that ran against live infrastructure were "perpetually red locally", so in June we deleted them. They were replaced by component tests with a mocked network (about 280 files) plus deliberate, recorded live probes. A suite that is always red verifies nothing.
Probe reality, then write down what you saw
Many "front-end bugs" turned out to be backend contract drift: the API behaved differently from what it had promised. So the agent checks the real test backend before building. In one month, 75 of 94 portal sessions did.
Probing became a skill only after it had worked once by hand. The developer supplied a disposable email inbox, and the agent created a throwaway account end to end: sign-up, admin approval, then login with two-factor authentication. The developer said "turn this into a local skill." It was used 36 times in the next two weeks.
The skill's safety rules all came from working on a shared backend:
- Writes from a probe touch shared data, so restore anything you change afterwards.
- "A GET can write."
- "A missing ID can widen a write."
- Never print tokens. Credentials live in a gitignored file, and if one is missing, the human adds it in their editor, not in chat.
- Open two-factor sessions only when needed, and revoke them afterwards.
- Record each finding in the module's API spec, with the date and exactly what was verified live. Sixty-seven commits did nothing but that.
Claims need sources
A lot of the developer's corrections were short questions about sources:
- "Is this endpoint in the API collection? Where did you get it?" The agent admitted it had found the URL in code and logs, then checked the collection.
- An API rule stated as "seen". It came from probes that couldn't tell the two cases apart, and the agent retracted it from the docs and the pull request.
- A count mismatch blamed on the app. The developer asked what the device actually sends. A live probe showed the backend honoured only one of the two parameters.
- "Did you start correctly?", with a screenshot attached. The agent ran the real data transformer against live responses to prove the break was genuine.
- "Check again, I just pulled it a few minutes ago." The agent had been reporting from a stale copy of another repository.
Bugs that only exist in the agent's shell
Some failures had nothing to do with the product. They came from the agent's own environment:
- Colour codes. The shell exported
FORCE_COLOR=3, and the colour codes made a build script's output look like a valid file path. - A `$` in a password. Loading an env file in zsh expanded part of a password as a variable, leaving 6 characters instead of 12. The agent concluded the test account didn't exist, until the developer asked: "6 chars? It should be 12."
- Word splitting. zsh doesn't split a variable into words the way bash does, so a list of IDs arrived as one argument.
- A hidden folder. A file watcher hid a nested worktree's dependencies from the JavaScript bundler.
- The wrong source. Symlinking dependencies into a worktree made it silently build and test the main checkout's code.
Each of these is now one line in an instruction file or memory note, so it costs nothing the next time.
What to copy
- End every report with Checked and Not checked.
- Run the baseline first, prove the new test fails, then implement.
- Delete tests that are always red, and replace them with ones you trust.
- Probe the real backend safely, and write down what you saw with a date.
- Ask "where did you get that?" until the agent asks it of itself.
- Record environment bugs as carefully as product bugs.