How we built NOVA for LD Expert, then handed their team the controls.
What it takes to hand a client an agent they can direct themselves, and the testing pipeline that makes that safe.
- July 2026
- every user moved across, the old services cancelled
- 3,300+
- written checks the system runs against itself
- 5 nights
- a week it audits its own code and reports back
- 1 in 3
- changes now written by the agent, approved by a person
- Partner
- LD Expert
- What they do
- Reading intervention and speech and language support for students with learning differences
- Product
- NOVA. Neuroaffirming Operations and Virtual Administration, named by them
- Built
- Talks from 29 October 2025, work from mid-November. In their hands to test April 2026, in use from June, every user migrated July 2026
- Together since
- 2024, starting with their website
Most software a client buys starts ageing the day it ships, because every change after that has to queue behind the people who built it. This is an account of what we did about that at LD Expert: the system first, then the machinery that lets their own team direct the work.
The problem underneath the request
LD Expert provides reading and speech therapy to students with learning differences, in homes and in schools. They asked us for a student login and a few integrations. Before quoting it we asked Chelsea DiMarzio, who runs their operations, to record herself doing her own job, and we worked their systems ourselves using her logins.
The real problem was not the login. Their revenue depended on one person remembering ten different billing rules across two systems that could not see each other: RSM, the reporting system school districts use, and a tutoring platform that held the calendar. Every month somebody read both and typed the result into an invoice. Payroll ran four weeks behind because reconciling them took that long.
The system, and the handover
We started talking on 29 October 2025 and started building in the middle of November. The system went to their team to test in April: schools, therapists, students, service agreements, scheduling, finance and the family portal. They began using it in June and gave feedback as they went. In July they moved every user across and cancelled the services it replaced, and the school portal shipped the same month.
We got the shape wrong once, and they told us so. We had built the school side first, assuming families were the same thing with fewer fields. They are not: schools order fixed hours and pay in arrears, families prepay by the calendar month and need invoices that break cleanly at month end.
The more I am testing things in NOVA, the more I feel like it is not what we need for private families.
So we built the family side properly, and on 1 July the first automated billing run went out. Thirty-five invoices, none assembled by hand.
That was so easy.
Teaching it the business
A system this size changes most weeks, and most of the work in keeping it correct is not clever. It is reading what changed, writing down how it now behaves, and checking nothing else broke. That is the work we hand to AI, and none of it is possible until the machine knows the business.
So the first thing we wrote was not code. It was a file describing how this system works and what is not allowed in it, and then a separate written procedure for each job that recurs: adding a school, correcting a bill, changing a service agreement. Twenty-five of those procedures now.
This is the part teams skip, and it is the part that decides whether any of the rest works. Without it an agent writes plausible code that violates a rule nobody wrote down. With it, the agent argues from the same documents a new employee would be handed.
The testing pipeline
On top of that we built a pipeline that keeps the tests honest without a person driving it. It runs in one direction, and every stage has an output the next stage reads:
- It notices what changed. An audit compares the running system against the written specifications and classifies each difference: new behaviour, changed behaviour, removed behaviour, or no impact.
- It writes down how the feature actually behaves, reading the real implementation rather than the documentation, which is the only way the description cannot quietly drift from the product.
- It turns that into numbered test cases, one row per rule, each traceable back to the specification it came from. Existing rows are never silently rewritten.
- It generates the browser tests from those rows, so each automated test is tied to the written rule it proves.
- It runs them and records the verdict against every row: passed, failed, not run, needs a person, or waiting on a product decision.
The second step has a cost worth naming, because a careful reader will find it anyway. Reading the implementation is what stops the description drifting from the product. It also means these tests prove the code matches itself, not that it matches what anyone asked for. Build the wrong thing and this pipeline will describe the wrong thing accurately, then check it carefully forever. Catching that is still a person’s job, and on this project that person is one of ours.
There are more than 3,300 of those written checks now, because a business with five kinds of login and ten billing rules genuinely has that many rules. Some are recorded as failing on purpose: they describe real defects nobody has fixed yet, and counting them beats hiding them.
Every push to staging triggers the run. The result is posted back onto the card the change belongs to, in the client’s own project board, with the report and any newly written test cases attached. On 11 September it read: passed, 44 tests, 0 failed, 43 new test cases added in this deploy.
One request, start to finish
On 27 August, Chelsea wrote a card on their board. Not a ticket in our system, not an email to a developer. Her own words, on her own board:
Can I have the option to 'select all' when creating therapist bills? Could it automatically add all sessions within the date range selected? Thanks!
Four days later the agent picked it up. It did not start writing code. It restated what it thought was being asked, explained what the screen does today, and then asked three questions, each of which changes what gets built:
- If a therapist already has a bill covering that period, should the bulk run skip them, or create a second bill for an admin to clean up?
- If a therapist has no eligible sessions in the range, create an empty draft bill, or skip them?
- Should “generate for all” replace the single-therapist option, or sit alongside it?
Twenty minutes later it restated the whole plan, and flagged something it had found in the system itself: bills record an exact billing period, and there was no existing check for whether a therapist already had a bill overlapping that range. It proposed treating any overlap as a match, said why, and offered to do it the other way instead.
Then it was corrected, and answered: “Got it, thanks for the correction.” The revised plan dropped the new form entirely in favour of turning the existing dropdown into a checklist, and it closed by pinning down the one decision still open, with the consequence spelled out: checking a single therapist should prompt before creating a duplicate, while a bulk run should skip and report, because one pauses for an answer and the other does not.
It wrote nothing until that was settled. When it did build, it sequenced the work smallest and lowest-risk first, ran the checks, and submitted the change for a person to approve. That approval happened the next morning. On 7 September the change reached LD Expert; on 8 September Chelsea used it.
What it checks while nobody watches
Five nights a week, the same machinery reads the whole codebase against the rules we wrote for it and posts what it found in plain English. The report from 11 September opens by saying the code is in good shape, then lists what is not:
- A feature covering therapist notes had no written test cases at all against roughly two dozen rules in its specification.
- Two fully automated test suites, more than fifty tests between them, had never actually been executed, so they were catching nothing.
- Several other features had far fewer written checks than their specifications call for.
It had already fixed the mechanical findings it could fix safely and submitted them for review, and it said so plainly: nothing is merged until that review happens.
The line that matters most is the last one: decided earlier and not asked again, twelve parked, twenty-three accepted as-is. An earlier version of this audit had no memory. It rescanned everything each night and reported a sample, so it kept raising settled questions and kept missing new ones. It looked productive and was not. Giving it a permanent record of what had already been decided is what turned it from noise into something the team reads.
What it will not do
The agent cannot put anything live. It cannot write to the main or staging branches, and it does not approve its own work. A person does, and today that person is one of ours rather than one of the client’s, which is the honest position rather than the impressive one.
When its own checks are still failing after three repair attempts, it does not quietly submit the work anyway. It puts the failure in the title of the change. Fourteen have shipped carrying that label, visible to everyone, which is the behaviour we want: a gate that gives up loudly is worth more than one that keeps trying quietly.
We have also had it go wrong in the other direction. Changes raised by our own automation were merging without the test suite running at all, and one broke the strictest checks on the main branch before anyone noticed. That was not the AI being wrong about code. It was us not watching the machinery closely enough, which is the standing risk with anything that produces confident output on a schedule.
What changed for the business
Payroll used to run four weeks behind. It is automatic now, calculated from the sessions therapists logged. The monthly invoice run has gone out every month since July without anyone assembling an invoice. Around 85 families log in and see their child’s schedule, notes and invoices instead of emailing to ask. We have not put a figure on the hours saved, because nobody measured the before.
The change we did not plan for is who writes the work now. Close to a third of everything shipped since the end of July started as a request on the client’s own board rather than a specification written by us. In August, Chelsea worked out an entire file format herself, having realised RSM accepts uploads, and posted it on a card. Nobody asked her to.
You're changing our lives and our company, especially for our therapists.
If you want to see whether this fits your business, the call is an hour and it is a working session rather than a pitch. Bring the person everyone asks: what is in their head is the specification, and they will know within the hour whether the machinery could hold it.