The 32-hour spoon
Band-Aider passes her capstone, and Wall Street is having a meltdown.
Band-Aider passed her capstone. The Nasdaq fell 4.5% in the same week. That's a 100% coincidence rate, based on one observation. I'm leaving the causality question to the financial analysts, who have considerably larger computers.
Band-Aider has been in release candidate for longer than I'd care to admit. It's a local-first coding harness built around a thesis I've been testing for a while: much of what we call AI intelligence might be probabilistic generation coupled with graph traversal. We tend to ask the model to figure out where to go, do the work when it gets there, and somehow remember what happened along the way.
Band-Aider splits that job. Software plans the traversal and tracks progress; Gemma handles local code changes. Failed attempts can be rejected and revisited without requiring the model to remember the whole journey. I wanted to know whether that arrangement could carry a relatively small local model through a problem that would ordinarily take substantial help from a stronger hosted model.
The elephant
The capstone was a partially completed refactor of Band-Aider's Memento system, which preserves file state during an attempted edit. A failed candidate needs to restore the right baseline. With several files in the same attempt, a partial commit can leave the repository in a state nobody intended.
I handed Band-Aider a 1,816-word prompt that insisted on finishing the work as one story. The changes were mutually dependent. Finishing one class or making a few tests green wasn't completion. The assignment, in brief:
Complete the existing Memento lifecycle refactor without replacing the framework. Make file snapshots scope-managed and single-use. Update the existing callers, and ensure that multi-file changes are either accepted together or restored together. Continue from the partial implementation already in the repository.
The main change was in who owns an edit's lifetime. ClassMeta would return an inactive Memento descriptor; the caller would manage it within a context, committing or rolling back once. Leaving the scope would clean up the snapshot. Existing callers, including CachedFilePatcher, DirectCodeEditor, and AlphaLoop, needed to follow that lifetime. A multi-file attempt had to validate every member before committing any of them.
The resulting diff touched 20 Python files, with 941 insertions and 689 deletions: six production files and fourteen test files. Some test changes were mechanical. The production work changed when edits become accepted and how failed attempts restore previous state.
The room it had to navigate
For scale, Band-Aider is larger and more internally coupled than the four other agent projects I measured. I compared it against Aider, SWE-agent, mini-SWE-agent, and smolagents using the same analyzer and production-Python scope, counting tests separately. Band-Aider was measured at commit aee90b7; peer revisions are pinned in the separate methodology.
| Metric | Band-Aider | Aider | SWE-agent | mini-SWE-agent | smolagents |
|---|---|---|---|---|---|
| Production SLOC | 48,466 | 14,961 | 7,962 | 4,018 | 8,463 |
| Test SLOC | 52,286 | 8,393 | 1,715 | 6,785 | 9,865 |
| Cyclomatic complexity, mean / P95 | 4.81 / 16 | 5.42 / 17 | 3.05 / 9 | 2.88 / 8 | 4.45 / 15 |
| Maximum cyclomatic complexity | 89 | 161 | 29 | 26 | 58 |
| Mean afferent / efferent coupling | 4.90 / 4.90 | 2.68 / 2.68 | 2.87 / 2.87 | 2.14 / 2.14 | 3.28 / 3.28 |
| Mean module instability | 0.491 | 0.491 | 0.471 | 0.609 | 0.450 |
| Mean LCOM4 | 1.54 | 1.95 | 1.28 | 1.19 | 1.26 |
| Eligible classes with LCOM4 > 1 | 33.5% | 31.6% | 26.2% | 19.2% | 21.7% |
| Mean file maintainability index | 56.8 | 66.8 | 50.5 | 57.0 | 35.6 |
| Halstead volume, summed by file | 167,740 | 51,366 | 21,198 | 6,334 | 23,353 |
The dependency figures need some explanation. Afferent coupling counts incoming module dependencies; efferent coupling counts outgoing ones. Module instability is Ce / (Ca + Ce), averaged here across modules. It describes dependency direction, not crash probability. The scan found 50 modules in structural dependency cycles, dropping to zero when typing-only and deferred function-body imports were excluded. So the first number doesn't demonstrate 50 startup import failures.
LCOM4 of 1 describes a class whose methods form one connected group. 54 of 161 eligible Band-Aider classes (33.5%) scored above 1. They're worth inspecting, though stateless adapters can score poorly while having a perfectly coherent job. Complexity is concentrated too: 238 functions exceed cyclomatic complexity 10, and 68 exceed 20. The largest hotspots are source-call discovery (89), two dependency-graph maintenance functions (80 each), and failure-report parsing (79).
Mean file Halstead difficulty was 4.29, with theoretical effort of 1.75 million units. Those aren't measured development hours. Summed Halstead volume also grows with codebase size, so it's hardly a league table of software quality. The point of the comparison is more modest: the capstone took place in a fairly large, connected repository with real stateful behavior. It wasn't a five-file toy example.
Measurement note: Same analyzer and production-Python scope across all five projects; test SLOC reported separately. Band-Aider measured at aee90b7. Full methodology, peer commit pins, hotspot list, and reproducible analyzer are in the separate comparison report (link to be added).
What runs the search
Band-Aider uses a collection of established techniques rather than one enormous prompt. A source inspection at revision 0fed864 identified these broad categories in the production implementation. Not every one necessarily ran during this capstone.
| Technique | What it contributes |
|---|---|
| Graph traversal and dependency ordering | Locate related work and decide what can be examined next. |
| Static code analysis | Discover source relationships and possible call paths. |
| Lexical and semantic retrieval | Find relevant code without loading every file in full. |
| Progressive context selection | Supply more source context as a repair needs it. |
| Compilation and targeted tests | Check candidate edits before they're accepted. |
| File snapshots and rollback | Restore rejected work without losing an accepted baseline. |
| Caching and retry management | Reuse suitable prior work and continue after unsuccessful attempts. |
One spoon at a time
The run lasted 31 hours, 38 minutes, 1 second. It made 3,430 LLM calls, with 27 hours and 30 minutes spent waiting for the model. The reported average was 9 hours and 48 minutes per COT task. Speed was not among the achievements.
A manager once asked me how to eat an elephant.
One spoon at a time, apparently for 32 hours.
My Roomba analogy has become difficult to escape. A robot vacuum can traverse a room within virtual fencing without understanding the room. The useful part of the fence is that a bad turn doesn't have to become a disaster. Gemma made plenty of turns over those 32 hours; I didn't have to handhold every patch.
That leaves an interesting question: how much expensive model capability is doing the local repair, and how much is spent keeping a long process coherent? I moved more of the latter into software, at the cost of a rather long wait.
Independent review
I asked Sol and Astra to audit the result in a disposable copy. Sol opened its review with a line that sounded almost surprised:
The target's test-suite success is real.
Not quite a standing ovation, but I'll take it. The independent checks found 2,595 passing tests, including integration tests, and zero Pyright diagnostics across all 20 changed Python files. The original acceptance rollback defect was fixed. A separate two-file rejection probe confirmed that rejecting the second member committed neither file and restored both.
The review also exercised three cases outside the current tests. Two occur after commit. DirectCodeEditor can encounter a cleanup error and report no changed files even though the edit remains; in that path it can also obscure the original exception. AlphaLoop can raise when refreshing metadata after a successful commit. Keeping the edit in both cases is consistent with the transaction contract: commit means commit. The remaining question is whether the caller reports the distinction between an accepted edit and a later failure clearly enough.
The third finding is about acceptance evidence. The new diff helper doesn't describe the creation or deletion of an empty file, although file existence has changed. That's a narrower issue than a broken rollback. The review confirmed the core transaction behavior and identified where post-commit reporting and evidence handling may need attention. Neither repository was modified during the audit.
The successful endpoint tells me the arrangement can work. It doesn't establish whether those 3,430 calls represented steady convergence or a lengthy series of detours. The final answer is visible; the shape of the search is a separate question.
What comes next
Band-Aider should have another release soon. Unfortunately, I have a day job, so availability and the appropriate reward function will determine the schedule.
After that I want shortcuts for transitive inspection, so related code can be reached with less unnecessary traversal, and broader support for HTML, JavaScript, FastAPI, and Django. Language-specific implementations are already isolated, so Liskov shouldn't be disappointed.
The elephant has been eaten. I would have preferred a smaller elephant, but that wasn't part of the acceptance criteria.
Fine print: Causation between Band-Aider's capstone and the Nasdaq's weekly performance is neither suggested nor denied. The claimed 100% correlation is based on one observation. The p-value is left as an exercise for the statistically ambitious.
If you need a competent data scientist, there's ChatGPT. But if you need a human interlocutor, I know people. ;)