At the end of part 1, I had a specification, prototype tickets, and rules for how an agent should work through them. There was no application or controller yet. The next step was to try those rules against something that could actually fail.

The dot-finance prototypes gave me a desktop application to use, encrypted storage and backup experiments, and a small controller to manage the agent’s work and stop it when it reached the agreed limits. They also gave me a test that passed for the wrong reason, an interface that needed several rounds of correction, and a build pipeline that ran out of artifact storage.

By the end of this stage, I had a good base for production development to start. Getting there involved looking quite closely at what the passing checks established, and what they hadn’t tested at all.

The interruption test hadn’t interrupted anything

The persistence prototype could save and reopen synthetic data, restore backups, and reject the wrong-password and damaged-file cases covered by the tests. Independent agent review then found a gap in the interruption coverage.

Asking an operation to cancel gives it an opportunity to clean up. Killing the process during a backup doesn’t. I needed to know what happened in that second condition.

The agent added a harness that launched a child process and attempted to kill it at a controlled checkpoint. Initially, the harness accepted any unsuccessful exit as evidence that the interruption had happened. Unfortunately, the process-kill call itself threw an exception.

The test appeared to pass because something had failed. It hadn’t reached the failure I wanted to test.

The missing partial backup file helped expose the mistake. Fixing the kill call dealt with that immediate problem, but a further review required an explicit marker showing that the process had reached the intended checkpoint. The checks then had to establish that recovery worked and the previous completed backup was unchanged.

This was a useful example of why independent review in the loop is so important. The code and its test could agree with each other while missing the requirement. A reviewer asking what had actually happened exposed a much weaker check than the result suggested. The same reason I’d ask a colleague for a second pair of eyes when I’ve been deep in the weeds.

The corrected test still had a specific scope. It demonstrated recovery from interruption at a controlled checkpoint, not at every possible instant during a write. Separate agent review wasn’t a specialist security audit either. That gave me more confidence in the backup handling, but there was still plenty it hadn’t tested.

The move from mock-up to actual app was rough

I’d chosen a specific UI direction from the mockups, but the first workbench implementation had strayed significantly from it. It’ll be interesting to investigate this more in the future, as I think this may be something more common to less used frameworks like Avalonia over say HTML or Typescript. Either way, this needed to be addressed.

The first workbench implementation, with a permanent password field in the header, small text and transaction content intruding into neighbouring columns.

The first workbench implementation I sent back with feedback. The data is fictional.

The feedback was ordinary desktop application feedback. Text was too small, icons were ambiguous or missing, columns didn’t line up properly, and the scrollbar obscured the amount column. The password field had become a permanent fixture in the header, when it belonged with saving and reopening the data.

I also needed category totals visible while reviewing transactions. A final confirmation screen wouldn’t do the same job. If I’m changing an allocation, I need to see its effect alongside the transaction I’m changing. That became an explicit specification and acceptance requirement.

The corrections brought in recognisable outline icons, larger text, clearer column boundaries, and password prompts attached to the operations that needed them.

The later prototype showing a populated transaction ledger, selected transaction editor and the visible upper portion of running totals.

The later prototype after feedback and correction. The window size and fictional examples differ from the earlier capture.

There were several rounds of this. At smaller window sizes, the transaction list could paint over the right-hand panel. Contained horizontal scrolling and truncation within columns addressed that, but I later caught overlapping balance labels and overflowing rule controls as well.

A compact balance panel with labels colliding with the input fields.

One of the compact-layout problems I caught while trying the prototype.

A successful build and a screenshot capture could coexist with something I could immediately see was awkward. For the repeatable problems, the agent added compact-window captures and geometry assertions for the ledger, inspector, balance panel, and rule controls. Those gave later changes something concrete to fail against. Deciding whether the result was clear and comfortable to use still needed me to use it.

Review also found behavioural gaps. Unresolved items weren’t always blocking acknowledgement, changed transactions could be silently skipped on re-import, and foreign-currency rows didn’t require an actual GBP amount. Those went into a separate repair issue before the production decision.

Accepting the interface direction hadn’t meant accepting every behaviour in the prototype. Keeping those decisions separate let me retain the layout and address the omissions.

These corrections were also giving me clearer UI requirements and checks to carry into production development.

Corrections needed to survive the next session

Some other feedback also changed the rules for subsequent work.

During the early hosted builds, I caught a GitHub Actions runtime deprecation warning. The Node version selected for the project was separate from the runtime used internally by an action. Updating the project’s version hadn’t addressed the warning.

That led to an explicit repository requirement for supported packages, actions, and images. The storage work also moved from the original SQLCipher bundle, recorded as deprecated during the project, to SQLite3MC. An authenticated snapshot experiment was feasible, but would have introduced a bespoke format and whole-file writes where an embedded database already suited the work.

Live totals went into the specification. Compact-layout defects became regression checks. Supported tooling became a repository rule. These were decisions a fresh session could find without me repeating the conversation.

But the budget rule from part 1 hadn’t been demonstrated in the early persistence work. Correction counts were recorded after the fact, and CI repairs continued beyond the recorded count without a clear budget-renewal checkpoint. Writing down three attempts or 90 minutes hadn’t made the limit enforce itself. The controller still needed its own experiment.

Retaining evidence filled the storage allowance

GitHub Actions artifact storage was a real pain, and a time sink I hadn’t wanted from this experiment. It also showed how AI can still make some baffling decisions, like uploading hundreds of megabytes on every run without checking whether any of it needed keeping.

The workflow uploaded application output and validation evidence from each platform. When I asked what it was keeping, the investigation estimated roughly 680 MB of compressed output across three large uploads per run. My allowance was 500 MB. Most of the output was native binaries and debugging symbols, rather than the much smaller screenshots and diagrams.

Uploads were failing because the quota had been reached. Application checks could pass, then the workflow would fail during upload and block the dependent cross-platform backup cycle. I had to distinguish the checks that had passed from the validation that couldn’t run.

The first reduction removed the large bundles and rebuilt from the tested commit in each job, keeping only the small encrypted backups needed between platforms. I then made the policy explicit. Actions artifact storage was for release-ready application binaries and, where useful, their debugging symbols. Test data, traces, screenshots, and intermediate output didn’t belong there.

The final prototype workflow uploaded no artifacts. It passed the small synthetic encrypted backup through job outputs so the cross-platform restore exercise could continue. The resulting hosted run passed all seven jobs and reported zero artifacts. That transfer was specific to the small fixture, not a general mechanism for moving application databases.

This changed the earlier plan to retain generated architecture output as an artifact too. LikeC4 still ran during validation; generating its output didn’t require uploading it on every run.

Asking the agent to retain evidence had produced a workflow whose storage needs hadn’t been checked against the available allowance. Reviewing the pipeline needed to include what it kept and why. Otherwise the process intended to validate the application could prevent that validation from finishing.

The proposed permissions boundary had another route around it

For a live tracker-recovery trial, the agent proposed narrowly scoped credentials. I questioned whether that would provide the intended restriction. I’d already needed broader permissions for legitimate project work, and the existing authenticated GitHub CLI session was still available.

GitHub would enforce the permissions of the credential used for a request. Giving the controller a narrow credential wouldn’t isolate an agent that could also use the broader session.

I kept the trial focused on whether the controller could recover after a GitHub update. The manual tracker adapter was fixed to one sandbox issue, one project, one marked comment, and two status transitions. It exercised losing the response after GitHub had accepted a write, then recovering without duplicating the comment or repeating an already completed mutation. The broader operator permissions were recorded explicitly.

That let me investigate recovery under supervision. It didn’t establish a security boundary for unattended execution, which remained unapproved. That would need an isolated environment with only the intended credentials available.

The controller’s process-recovery tests had a separate problem on Windows. A supervisor intended to survive the controller’s termination wasn’t producing its recovery receipt. This time the run reached its correction limit and stopped. I explicitly authorised another attempt. Detaching the supervisor resolved the tested failure, and the hosted checks subsequently passed across all three operating systems.

That was a concrete improvement over the early budget bookkeeping. The run stopped with an unresolved problem, and continuing required a decision from me.

This is definitely one I want to return to, as ideally agents should only be running with the exact access they need. For this supervised trial on a personal project, I deemed the risk acceptable with the controls I’d put in place.

What I’d accepted

After working through the prototypes, I was happy to move forward with Avalonia and .NET, SQLite3MC, the guided reconciliation approach, and the small controller I’d been testing under supervision. The workflow checks had passed on macOS, Windows, and Linux, and a backup had been restored through all three platforms.

The disposable shell still needed production boundaries, importer contracts, accessibility acceptance, security decisions, and packaging work. Passing the prototypes hadn’t turned it into a finished financial application.

I also asked for an isolated trial with my real data and actual flow once the complete workflow was available, before release packaging. Synthetic fixtures meant development and validation could happen without exposing financial records. The later trial would check whether the application fitted the job I needed it for, with me operating it privately and keeping the records out of the agents, repository, and CI. I still wanted to try it with my own data before considering it ready for release.