Raychis

Field notes: Part 5 of 10

The Two Weeks I Stopped Building

Within a few days of coming back, the collectors were running. The pipeline ran end to end. The fire that had nearly killed the project in November was out.

I sat down to write more code. But, I didn’t know what to write next.

The harder problem

The audit at the start of the year after I got back from my break had found a specific bug, five collectors that weren’t being invoked at runtime. Finding the bug took less than a week. Fixing it, just a day. But the bug wasn’t really the problem. The problem was that I had never written down what the system was supposed to do. There was no specification. There was no contract between what I was building and what it was being built for. The collectors had stopped running silently in November, and I hadn’t noticed for nearly two months, because there was no document anywhere that said this should be running, and this is what it should produce.

I’d been working for nearly half a year without a written description of what success looked like. The bug was a symptom. The lack of clarity and direction was the real problem.

In 2025 I would have called that bureaucracy. Specifications were what enterprise teams wrote because they had to coordinate with each other; a solo engineer could hold the spec in their head. Except the spec hadn’t been in my head. It had been in fragments across half a year of decisions, none of them written down, all of them subject to drift as I change my mind. The codebase had grown beyond what I could hold; the spec had grown beyond what I could remember; and the gap between them was what had let the project nearly die.

I opened a fresh document, not the code.

The mobile spec was first.

The first thing I wrote wasn’t an ML specification. It was a mobile app specification. What the app needed to do for the user. What it needed to look like. What constraints it had to live inside: model size, inference latency, battery cost, privacy, offline behaviour. What a “scan” was, end to end, from the user opening the camera to the result appearing on the screen.

In 2025 I had built the model and assumed the app would figure out how to use it. Now I did the opposite. I wrote what the app needed before I wrote what the model would do. The constraints came first. The engineering came second. That order had been wrong for a year.

The ML side then had to answer the mobile side’s questions. What was the maximum acceptable inference latency? Could the model run quantised without losing accuracy? What confidence labels would the UI display, and how were they calibrated? When the model wasn’t sure, what did it return? The mobile spec asked these questions; the ML spec had to answer them. Where the answers conflicted, I went back and forth between the two documents until they were consistent.

For the first time, the system had defined edges. Before that, it had just been code.

Most of the back-and-forth surfaced things I hadn’t realised I was assuming. The mobile side wanted four confidence tiers; the ML side had been computing scalar probabilities with no calibration. The mobile side wanted a 100ms p95 inference target; the ML side had been training a model that ran at 280ms on the development machine. The two documents didn’t agree because the work hadn’t been designed for them to agree. Each iteration narrowed the gap. By the second week the documents could be read in sequence and made sense.

The Plan. Illustration generated with AI.

Reading help

I gave both documents to ChatGPT and to Claude, and asked them what they were missing.

This was the first time I had asked an AI to do anything on this project. The rule I had for myself; don’t use the agents, build it alone, hadn’t been replaced with a new rule when it broke. It had just stopped being absolute. I wasn’t ready to hand the work over. But I was ready to have it read.

They asked the kinds of questions a careful reviewer would ask. What happens when the model is wrong, and how do you know? What’s the contingency if the accuracy target isn’t reached? How do you handle a user whose phone can’t run the model at the latency budget? What does the system do at the edges, the species you’ve never seen, the photo of nothing, the hand half-blocking the leaf? Most of the questions were ones I would have got to eventually. Some of them I would not have. The contingency question was one I had not written down anywhere. When the reviewers asked, I did.

The collaboration was modest. I wrote the documents. They read them. The thinking was still mine. But the documents were stronger for the reading, and that was the first useful thing AI tools had done on the project, and it was enough to break the habit of refusing them entirely.

Four roadmaps in one day

With the specifications in shape, I wrote a roadmap.

Then I wrote it again.

Then I wrote it again.

Then I wrote it again.

Each round reviewed with ChatGPT and Claude before the next.

By the end of January 25th, version 1.3.0 of the Project Roadmap included a Resource Requirements section, a Visual Timeline rendered as an ASCII Gantt chart, a Version Control Strategy with branching conventions, Project Success Metrics across technical and process dimensions, a Data Backup & Disaster Recovery procedure, a Security Audit, and Phase Testing Gates with detailed exit criteria for Weeks 4, 8, and 12.

There was no team. There were no stakeholders. There was one engineer writing documents to an empty room.

I knew, while I was doing it, that this level of detail was not what a solo project required. I wrote it anyway. In 2025 I would have called it bureaucratic overhead. In January 2026 I was writing it because more than one person’s needs was the wrong measure. More than I’d had before was the right one.

The Task structure

The roadmap was followed by a formal task breakdown. Task 1.1, Task 1.2, Task 1.3. Sequential, numbered, each with acceptance criteria, each with inputs from prior tasks. There were thirteen tasks in the first phase, and I knew what each of them was, and I knew the order they came in, and I knew what done meant for each. None of that had been true for any week of 2025.

The tasks were not exciting. They were boring. Environment Configuration, PostgreSQL Database Setup, API Key Configuration, Monitoring Infrastructure. The kind of work I would have skipped over in 2025 to get to the more interesting parts, and which I would later have paid for skipping. I did them in order this time, in the order the roadmap said, and I closed each one when its acceptance criteria were met.

The kill switches

Among the rules I wrote during those two weeks, several were designed to tell me when to stop. The crash rate was one. If the application crashed more than 2% of the time for seven consecutive days, I would halt feature work and fix stability. The retention rate was another. If day-7 retention fell below 25% by Month 2 of operation, I would stop adding features and investigate why people weren’t coming back. There were others.

One of them was the species accuracy stage gate. Written in formal language in the spec, it had six pass criteria: accuracy thresholds, model size budgets, mobile hardware targets, ANN search latency, ONNX quantisation requirements, hardware acceleration coverage. In my head, it was simpler. If the model didn’t reach 75% species accuracy on five thousand species by a specific date, I would stop pushing for the ML model and pivot the app to something else.

It would also be the hypothesis failing. The architectural bet that composed AI components, on device, not cloud. That would have lost the test I’d set for it.

I didn’t tell anyone about the rule. I didn’t put it anywhere outside the spec it lived in, which nobody else was reading. The other rules were for the project. This one was for me.

The project would live or die depending on if it made that stage gate.

The other rules were checks against external failures. A crash rate too high, a retention rate too low, an accuracy too poor for the product to be honest. The stage gate was a check against an internal one. I knew myself. I knew that without a rule I had committed to in writing, I would push through a failure I should have stopped at, and I would pay for it later. I knew myself well enough to know I wouldn’t stop on my own. The rule was the thing that would stop me.

I wrote it. I dated it. I moved on.

The work begins

Task 1.1 landed on the evening of January 25th. Task 1.2 the next day. Task 1.3 a few days later.

I had a plan now. I had a contract with the work. I had a way to know if I was failing. None of those things had been true a month earlier, and all of them were true now, and they were true because I had spent two weeks doing the kind of work I had previously thought of as not-the-real-work and discovered it was the real work all along.

I did not know whether the plan was right. I knew I had one. For the first few weeks back from my Christmas holidays, that was enough.

To be continued.

All field notes