Build note 01

A Feature Is Not Shipped Until It Works

Four failures in Aria's voice input taught me why a green build and a working development demo are not enough.

I thought voice input for Aria was finished. The backend accepted audio, the transcription service ran, and the browser test worked. The feature was wired from one end to the other.

Then I tried it in the actual desktop app.

It failed in four different places. None of those failures were visible in the test that had convinced me the work was done.

A successful response that changed nothing

The first problem was configuration. I had added the voice settings to the central registry, and the API accepted an update request. It even returned a successful response.

The values did not change.

The API’s update model did not include the new fields, so it silently discarded them. The write looked successful, but reading the settings back returned the old values.

That is a particularly bad kind of bug because it creates false confidence. The request did not crash. The response did not contain an error. A shallow test would mark it green.

The useful test was a round trip:

  1. Read the current value.
  2. Write a different value.
  3. Read it again.
  4. Confirm that the stored value changed.
  5. Restore the original value.

An API response only proves that the API produced a response. It does not prove that the requested state exists.

Configurable in code is not configurable for the user

The second failure was less technical and more honest. I described the voice settings as tunable, but there were no controls for them in the app.

They could be changed through environment variables, followed by a restart. That is useful for development, but it is not a real settings experience. It is hidden, easy to forget, and unavailable to someone using the application normally.

If a feature is meant to be adjusted while the app is running, its controls belong where the user will look for them. In this case, that meant the existing configuration screen, backed by the same registry as the API.

I now treat configuration as having three parts:

  • a durable source of truth;
  • a working read and write path;
  • a visible control for settings the user is expected to change.

Leaving out any one of those turns a setting into an implementation detail.

The development browser was not the product

The third failure came from testing in the wrong environment.

Voice capture worked in a normal browser on localhost. Aria’s desktop app uses an embedded web view, and that environment did not expose the same microphone API. The operating system also needed the correct permission description before it would grant access.

The page was the same. The runtime was not.

Desktop wrappers make it easy to think of the bundled app as a browser with a frame around it. It is safer to treat it as a separate platform. It has its own permissions, capabilities, lifecycle, networking behavior, and failure modes.

A localhost demo can prove that the frontend and backend agree. It cannot prove that the distributed application works.

The model existed, but the service was incomplete

The fourth failure waited until the first real transcription.

The speech model’s weights and configuration were present, so the service appeared ready. The first request crashed because the local model snapshot did not include the matching processor and tokenizer files.

This is common with systems that load expensive resources lazily. Startup proves that the process can start. It does not prove that the first job can finish.

After adding the missing files, I tested the full request with a small non-speech recording. The result did not need to be meaningful. The point was to make the complete pipeline load, process input, and return a valid response.

The test that matters

These were four separate bugs, but they came from one mistaken definition of done. I had tested the parts I had just built instead of the experience I was claiming to ship.

My checklist is now more demanding:

  • Does a setting survive a write and read round trip?
  • Can the user find and change it without editing a file?
  • Does the feature work inside the packaged application?
  • Have I tested the operating system permission path?
  • Has every lazy-loaded dependency handled its first real request?
  • Have I restarted from a clean state and tried again?

Build success matters. Unit tests matter. Development smoke tests matter. They are evidence along the way, not the finish line.

A feature is shipped when it works in the place where the user will use it, through the controls they actually have, after a clean start. Everything before that is progress.

~/

↑↓ move enter run help commands ⌘K toggle