Field report · published 2026-08-26
112 days late
I spent 22 days building a macOS app to manage Claude Code sessions. Anthropic had shipped most of it 112 days before I wrote my first line — and I never checked. This is the full record, with dates, commit counts, and the audit that found out.
01The number that reframes everything
The story I told myself for three weeks was the familiar one: I was building something, and the platform vendor shipped it out from under me. It is a comfortable story. It casts you as unlucky rather than careless.
Then I actually checked the dates.
days between Anthropic shipping the thing and me starting to build it.
| Event | Date | Δ from their launch |
|---|---|---|
| Anthropic ships the Claude Code desktop redesign — multi-session sidebar, per-session git worktrees, integrated terminal and file editor, split panes, preview pane. Routines ship the same day. | 2026-04-14 | day 0 |
| Mobile push notifications land in v2.1.110 — including "push when actions required," for permission prompts | 2026-04-16 | +2 |
I create the first file in my project (a UI mockup, 19:56 local time) | 2026-08-04 | +112 |
| I run my one and only competitive check before this audit | 2026-08-08 | +116 |
First git commit, 00:00:16 | 2026-08-09 | +117 |
| I finally do a line-by-line audit and find out | 2026-08-24 | +132 |
The actual failure
Nobody overtook me. I started building a product that substantially existed, and I shipped 215 commits before anyone checked whether it did. That is not bad luck. That is a missing step in how I start projects — and it is a step that would have cost about forty minutes.
I am writing this down because the forty-minute version of this check is easy to describe and easy to reuse, and because the 22 days were not wasted — just not in the way I planned. Both halves are below, with the data.
02What I actually built
A native macOS menu-bar app. Three things it does: watch every Claude Code session on the machine, collect risky operations into one approval console, and host sessions directly in an embedded terminal.
Twelve delivery stages, all with written acceptance contracts. Here is the shipping record — dates are the day each stage was accepted, not the day work began.
| Stage | What shipped | Accepted | PR |
|---|---|---|---|
| 2 | UI design frozen — 9-page information architecture, 5 visual mockups | 2026-08-04 | — |
| 1 | Technical spike — proved the two risky assumptions (three-channel external monitoring; SwiftTerm can host the Claude TUI, detection→UI measured at 14ms) | 2026-08-05 | — |
| 3 | Monitoring MVP — menu-bar icon, quick panel. New sessions appear in 2.0s (target was 10s) | 2026-08-05 | — |
| 4 | Main control center, read-only | 2026-08-05 | — |
| 5 | Embedded terminal host — PTY, tabs, split panes, birth registry, three injection automations | 2026-08-06 | — |
| 6 | Approval center + notifications — 10 risk predicates, decisions written into the hook response body | 2026-08-08 | — |
| 7 | Task triage and dispatch — headless CLI triage (25.8s: 3 tasks → 4 sessions), git worktree isolation | 2026-08-09 | — |
| 8 | Animated mascot — 7 states; plus the binary fingerprint gate that caught a real "you didn't swap the binary" on its first day | 2026-08-11 | — |
| 9 | Topic tracking — 8/8 criteria green, 3 runs at 100/100/100% precision, 89/94/94% recall | 2026-08-19 | #4 |
| 10 | Projects / History / browser pane / settings — 8 criteria, started and accepted the same day | 2026-08-19 | #5 |
| X | Multi-source progress tracking — 7 criteria | 2026-08-20 | #6 |
| 11 | Multi-agent abstraction — zero brand literals left in the core layer | 2026-08-21 | #7 |
| 12a | Codex CLI read-only support — second agent provider, shipped same day it started | 2026-08-21 | #9 |
| Y1 | Background execution base — 6 criteria, full regression 103 ✅ / 0 ❌ | 2026-08-21 | #10 |
| N | Panel noise filtering + a reusable evidence-gate protocol | 2026-08-23 | #12 |
| Y2a | Execution-target advisor | 2026-08-24 | #12 |
Size, measured not estimated
| Metric | Value | How it was counted |
|---|---|---|
| Calendar days from first artifact to the audit | 20 | 2026-08-04 → 2026-08-24 |
| Git commits | 215 | git rev-list --count HEAD, all in August 2026 |
| Busiest single day | 61 commits | 2026-08-21 (stages 11, 12a and Y1 all landed) |
| Second busiest | 43 commits | 2026-08-23 |
| Swift source | 76 files / 25,284 lines | Core 10,957 · UI 9,435 · Providers 2,109 · Terminal 1,488 |
| Design and process docs | 6,202 lines | 20 markdown files under docs/ |
| Regression scripts | 12 | one per stage, each chaining all earlier ones |
| Evidence artifacts on disk | 530 files | logs, screenshots, JSON snapshots under spike/out/ |
| Pull requests | 12 (10 merged) | #1 through #12; #11 and #12 still open |
I mention the size not to impress anyone. I mention it because the point of this article is that all of it happened after the thing already existed, and volume of work is exactly what makes that failure invisible from the inside. Every one of those 22 days felt productive. Most of them were, locally. None of them were, strategically.
03The audit: 48 features, line by line
On 2026-08-24 I stopped building and did the check I should have done on day zero. I took the 48 features from my own internal feature matrix — the authoritative one, so I could not cherry-pick — and went through Anthropic's current documentation feature by feature.
Evidence rules, in order of weight: official documentation text first; release notes and reporting only to establish when something shipped; public issue-tracker status only to establish that something does not yet exist, which is stronger evidence than documentation silence.
What the desktop redesign took
These are the ones that hurt, because they were my stages 5, 7 and 10 — the load-bearing ones:
- Per-session git worktree isolation. Mine was stage 7. Theirs defaults to
<project-root>/.claude/worktrees/, has a configurable location and branch prefix, a.worktreeincludefile for pulling gitignored files like.envinto the worktree, and auto-archives when the PR merges. Theirs is more complete than mine. - Integrated terminal, file editor, split panes, drag-and-drop layout. My stage 5.
- App preview pane and external site browsing. My stage 10, which I had not even started.
- An execution-target picker. Local / Cloud / SSH / WSL, chosen when you start a session. I had decomposed this into five stages (Y1–Y5) and finished two of them. It is a dropdown they shipped in April.
- A usage ring showing per-session context consumption and plan usage for the period. My context meter, plus a layer I did not have.
- Session sidebar with filtering by status, project, and environment, and grouping by project.
What Remote Control took
Remote Control connects a local CLI session to claude.ai/code and the mobile apps.
Two lines from the official documentation:
/configoffers "Push when actions required" — for "permission prompts and questions."- "Claude Code keeps permission prompts and
AskUserQuestionquestions open until you answer them."
So approving a permission from your phone, and answering a multiple-choice prompt from your phone, are both free and official. Worth noting: I had explicitly declared remote answering of multiple-choice prompts a red line we will never cross. Anthropic just shipped it. On that specific point they were more aggressive than I was willing to be, which is its own kind of feedback about my product instincts.
What survived, and why
| Survivor | Why it survived | Durability |
|---|---|---|
| Cross-vendor abstraction — a core layer that knows no agent brand; Claude Code, Codex and opencode are all just providers | Anthropic will never build an abstraction whose purpose is to also manage Codex | Structural. Not a roadmap gap — a thing they cannot want |
| Seeing sessions started in a plain terminal | Official docs are explicit: the desktop app sees only sessions it runs itself — not ones you started from the terminal CLI or the VS Code extension, "even in worktrees of the same project." There is an open feature request for it | Time-limited. The day they unify the session store, this is gone |
| The approval console — one inbox across sessions, three risk tiers with impact text, an append-only decision log, per-event-type notification switches | Official permission modes grade autonomy (Manual / Accept edits / Plan / Auto / Bypass), not the risk of one request. And on notifications the docs say plainly: "Beyond the two on/off toggles below, there is no per-event configuration" | Structural-ish. Their Auto mode is explicitly designed to reduce permission prompts. We are pointed in opposite directions |
The distinction that took me three weeks to see
"Can you approve remotely?" — yes, officially, free, since April.
"Can you see all pending approvals in one place, ranked by risk, with a record of what you approved?" — not in any documentation I can find.
I had been selling the first sentence. Only the second one was ever true.
04How I missed it for 132 days
Here is the part I find genuinely useful, because the failure is specific and repeatable rather than "I should have researched more."
I did research. On 2026-08-08 — day 5 of the project — I ran a competitive check that was, by its own standards, rigorous. I pulled the official documentation rather than trusting secondhand write-ups. I found two research summaries that contradicted each other about whether you could approve permissions from a phone, went to the source, and established that you could — and that the summary claiming otherwise was stale. I enumerated eight hard limits of Remote Control. I deleted two of my own selling points on the spot because the evidence killed them.
The method was fine. The scope was drawn wrong.
The scoping error, stated precisely
The question I asked was: "Can Anthropic's mobile offering replace my mobile offering?"
So I checked Remote Control, Dispatch, Channels, scheduled tasks — everything on the phone line. Thoroughly.
The desktop redesign was not in that question's blast radius, because it is not a mobile feature.
It had shipped 116 days earlier and it was the single biggest hit to my core product.
I checked the line I was anxious about instead of the line they were shipping on.
The reusable form of the lesson:
- Scope a competitive check by the opponent's product lines, not by the line you are worried about. Anxiety is a terrible index. Read their whole changelog, not the part that maps onto your fear.
- Do it before the first commit, then on a schedule. Mine happened on day 5 and then never again for 16 days — during which I shipped nine stages. A recurring calendar entry would have caught it.
- Write the result into the repo, not into a chat log. My August 8 findings did land in a spec file, which is why I could reconstruct exactly what I checked and what I did not. That part worked. Had it been a conversation, this article would have no evidence in it.
There is a smaller, more embarrassing corollary. Four months of platform releases changed the nature of at least 18 features in my product, and my project documentation contains no trace of any of it. I have 6,202 lines of design docs and a defect genealogy going back to day one, and not one line saying "the platform shipped X, here is what it means for us." I instrumented my code exhaustively and my market not at all.
05What the 22 days actually bought
Not a product. What I got instead was a set of engineering results with numbers attached, and those numbers turned out to be more transferable than the code.
The review economics
For stages 4 through 8 I ran multi-agent code review rounds — fan out reviewers across dimensions, then adversarially verify each finding. I kept the receipts.
| Stage | Review scale | Confirmed findings | Hit rate |
|---|---|---|---|
| 4 | 18 agents (4 dimensions → adversarial verify) | 8 | — |
| 5 · round 1 | 38 agents (4 dimensions) | 29 | — |
| 5 · round 2 | 33 agents (reviewing round 1's fixes) | 20 | — |
| 6 · round 1 | 10 agents (5 dimensions) | 47 | — |
| 6 · round 2 | 7 agents | 12 | — |
| 7 · three rounds | 37 + 20 + 13 = 70 agents | 28+ | — |
| 8 · round 1 | 6 dimensions + per-finding adversarial verify | 14 (from 42 raised) | 33% |
| 8 · round 2 | reviewing round 1's fixes | 6 | — |
| Total | ~190 agents | ~170 | — |
Three findings fell out of that table that I did not expect:
1. Two thirds of what review agents raise is not real
Stage 8, round one: 42 findings raised, 14 survived adversarial verification. A 33% hit rate. Two thirds of the spend went into refuting problems that did not exist. The 28 that got knocked down were almost entirely pure code-reading inferences — "this looks like it would break."
2. The findings that mattered came from running, not reading
Both CRITICALs in that same stage came from execution, not analysis:
- One had an actual crash report on disk —
AgentCompanion-2026-08-10-131832.ips. Anullinside a tool's input JSON reacheddataWithJSONObjectand aborted the process. - One was measured with
ps: 20.3% CPU still burning after the panel was closed, against 0.5% with animation off. Nobody reads their way to that number.
Later I ran two entire stages — X and 11 — with zero review agents, and they still surfaced real crashes and real latent defects, because the work involved actually running the thing. By my count this pattern has now held five separate times in one project.
3. Reviewing the fix code always found a critical. Five stages, no exceptions
| Stage | Worst thing found in round 1's own fixes |
|---|---|
| 5 | The injection gate was reading the scrollback buffer instead of the live viewport bottom — fail-open. A keystroke delayed by 0.25s never re-checked the gate |
| 6 | Two sides of resolveExternally used different keys, so "answer it in the terminal → the card disappears" was a dead path end to end |
| 7 | Multiple confirmed, three of them majors introduced by round 1's own fixes |
| 8 | A negative argument to a debug endpoint aborted the process; and the 20.3% idle CPU above |
If you take one operational thing from this article, take this: a fix is not a smaller change than the thing it fixes. Review it like new code.
4. One module produced most of the criticals — and the root cause was undecidable
The injection gate — the component that decides whether it is safe to send a keystroke into a live terminal — produced more criticals than anything else in the project. Two in stage 5, two more in stage 5's second round (oscillating between fail-open and fail-closed), and in stage 7's third round it locked itself: the app blocked its own Enter key, permanently stalling three automation chains, with no dialog visible on screen to explain why.
The root cause is written into my own notes and it is not a bug: the gate is a lexical predicate. It matches strings to decide "is there a prompt on screen right now." That question is not decidable by string matching, so no number of review rounds fixes it — each round just pushes you to the next counterexample. Some defects are not defects. They are the shape of the design.
06Six incidents, dated
These are the ones I would tell a friend about. Each is in the project's defect genealogy with a date, because writing them down was a rule.
2026-08-20 — a symlink ate 823MB and 15 transcripts, permanently
A frozen test corpus, 823MB, gitignored, therefore not checked out into git worktrees.
The fix was to symlink it from the main tree. The fix became the bomb: a .gitignore pattern
written with a trailing slash matches directories and does not match symlinks, so the symlink got
committed. After merging, a checkout in the main tree dropped a self-pointing symlink at that path
and cleared the real corpus — git treats ignored files as expendable. 15 transcripts gone for good.
The tell was that the failure did not look like a missing fixture. It looked like a broken product:
"181 work threads (ground truth 178) / 0 continuation chains / ai-title coverage 0 of 181."
Absurd but specific numbers. The .gitignore now carries both the slashed and unslashed pattern,
and the repair command is guarded by [ -e … ] || so it is a no-op in the main tree.
2026-08-20 — macOS quietly mangles non-ASCII environment variables
When the app relaunches itself from its bundle via NSWorkspace, non-ASCII environment variable
values get reinterpreted as Latin-1. My project path contains Chinese characters, so
学习 arrived as å¦ä¹. The isolation override silently failed and fell back to the real
directory — while an ASCII-valued variable in the same launch worked perfectly.
Test fixtures now live at ASCII-only paths, and the criterion asserts the override actually took effect.
2026-08-11 — the binary fingerprint gate caught a real one on day one
Every regression run starts by asking the running app for its binary fingerprint and refusing to continue if it does not match the build on disk. It caught a genuine "you did not actually swap the binary" the first time it ran. The failure mode it prevents is the nastiest kind: every subsequent test passes, against the old code, with no errors anywhere. The cause turned out to be mundane — an open terminal pane triggers a quit-confirmation dialog that silently blocks the kill, so the restart looks successful.
Amusingly, the first version of the fingerprint criterion was itself wrong: it ignored that
codesign --force rewrites the binary in place, so the two sides were permanently 480 bytes apart.
2026-08-21 — another session swapped the binary mid-regression
One machine, one app instance, one port. Two Claude Code sessions working in parallel on the same repo, each with its own build. Whoever launches the app wins, and the other side's evidence is all invalid. Cost: a full regression run discarded halfway. The rule that came out of it is deliberately strict — handoffs count only on an explicit ping at both start and end. Reachability, uptime, fingerprints, "they've been quiet a while" — none of those count as a handoff.
Undated but recurring — I misjudged a running process as my own test fixture
I once identified a process as a leftover regression harness and killed it. It was the user's live work. The rule now: never kill, restart, or replace any running process without asking first, and by default assume every running process on the machine belongs to someone else.
2026-08-19 — the criterion that "passed" because it had no data
A screenshot criterion used screencapture without screen-recording permission.
It captured nothing. The criterion counted "no data" as "no change" and printed a green check.
This sits in a whole family I ended up cataloguing as fake evidence: verification paths that route around
the mechanism they claim to test. An offscreen redraw that reported "correct" while the real render function
was never called. An animation test where the window was occluded, the gate correctly closed,
all 16 frames came out identical — and the criterion nearly filed correct behaviour as a fault.
07The rules I'm keeping
Seven things earned their place. I state them the way they are written in the repo, because the wording is load-bearing.
- Every new criterion must be made to fail on purpose first. Break the thing it tests, watch it go red, then fix it. An assertion never observed failing is not an assertion. This project logs its red proofs — stage N had 56 of them, stage Y2a had 54, all hitting.
- Static checks are not behavioural evidence. Learned expensively: a gate-detection layer in this codebase matched nothing at all for two entire stages while its static check stayed green. Every lexical predicate must be paired with a runtime case.
- When a test goes red, first decide: product defect or rotten fixture?
Fixture rot is the normal case, not the exception — hardcoded search terms that expired,
a regex where
All|Bulkmatched the "All" inside "Allow for This Session", a test binary path pointing into a directory that gets cleaned. - One idempotent, sub-second evidence command per acceptance criterion, written when the stage starts. Retrofitted evidence is not evidence — you write it to pass.
- Resolve spec ambiguity at kickoff, in writing, in a comment at the top of the code, pinned by a test case. Not in a chat message. Chat messages do not survive.
- Overwrite the status document; never append. One file, under 80 lines, describing only right now: current stage, what was finished, what is next, what is unresolved. History goes to an archive and is never rewritten.
- Acceptance criteria are a contract. No measurable evidence means not done. No checking boxes you cannot prove. When something is missing, write down what is missing.
And the one I'd add after this article
Rule 8: date the platform. Before the first commit, write down what the platform vendor shipped in the last 6 months and what it means for each thing you plan to build. Then repeat it on a fixed schedule — not when you get nervous. Keep it in the repo next to the acceptance contracts, because it is an acceptance contract: it is the one that decides whether the rest are worth passing.
08What I'm doing with it
Not shutting it down. Repointing it.
The audit says the honest position is not "a control panel for Claude Code" — that is a race against a vendor who is inside the process, has all the information, and moves faster. It is "one approval console for every coding agent." That target sits in their structural blind spot: they will not manage Codex, ever.
The useful thing about that repositioning is that it needs no new features. The cross-vendor line was already underway — stage 11 emptied the core layer of brand literals, stage 12a added Codex as the second provider, stage 13 targets a third. What it needs is stopping four other things: the browser pane, the diff and task tabs for my own sessions, the mobile terminal mirror, and most of the execution-target work.
There is also a competitive fact I did not have before the audit: the cross-vendor menu-bar niche is no longer empty. There are several tools tracking Claude Code and Codex sessions from the menu bar now, one of which explicitly claims to cover CLI, Xcode, desktop app and Codex, and one of which is already charging for it. Every one of them stops at usage metering. Not one touches permission requests — because that requires hooking the permission channel, building a risk model, and handling timeout policy. The unoccupied square is the intersection, not either axis.
And a small one that matters more than it should: my dispatch feature has the same name as an official Anthropic feature that does an adjacent thing. That needs to change.
09Where this article is soft
An audit that does not say where it is weak is marketing.
- "Not in the documentation" is not "does not exist." Most of the 15 survivors are judged on documentation silence. Vendors ship faster than they document. The approval-console claims are the most exposed to this.
- I did not install the official desktop app and click through it. Every judgement about their capabilities comes from documentation text. The gap between "documented" and "actually good" is unmeasured in both directions.
- The 18/15/15 split is mine. I chose the granularity of the 48 features and I drew the line between "partial overlap" and "replaced." Someone else would get different numbers. Treat it as an order of magnitude.
- The review-economics numbers come from my own delivery notes, written at the time but by the person being measured. Stage 8's two rounds did not record per-round agent counts, which is why the total is "about 190."
- The competitor claims are unverified. I read their marketing; I did not install them. If the one claiming to see CLI sessions actually does, the second-ranked moat is weaker than I said.
- One thing I did not check at all: whether anybody wants any of this. Twenty-two days, zero users. The audit measures uniqueness, not demand — and 15 unique features that nobody has asked for is not obviously better than 18 replaced ones.
10Data appendix
Everything numeric in this article, with how it was obtained. All timestamps are local time, UTC+08:00.
Publication record
| Artifact | Committed | Commit | Deployment |
|---|---|---|---|
| The full feature-by-feature audit (Chinese) | 2026-08-24T21:58:29+08:00 | b84233d | Cloudflare Workers, version 3bf5f25d-5312-497c-bd46-6edc1cd8af03; 1 new asset uploaded, 360 unchanged; live checks returned 200 for both the article shell and the direct file; Supabase index gained 1 row |
| This article | 2026-08-26T12:19:54+08:00 | 820c887 | Same pipeline: build → Cloudflare Workers → Supabase sync → push to prod |
Project timeline, exact
| Timestamp | Event | Source |
|---|---|---|
| 2026-04-14 | Claude Code desktop redesign ships; Routines enter research preview | Anthropic announcement + press coverage |
| 2026-04-16 | Mobile push notifications ship in v2.1.110 | release notes |
| 2026-08-04 19:56 | First file in my project — docs/ui-mockups/vA.html | filesystem mtime |
| 2026-08-04 20:07 | UI design spec written | filesystem mtime |
| 2026-08-08 | My one pre-audit competitive check | dated section in the launch spec |
| 2026-08-09 00:00:16 | First git commit — "Initial commit: Agent Companion for macOS" | git log --reverse |
| 2026-08-10 13:18:32 | Crash: null in tool input reaches dataWithJSONObject | AgentCompanion-2026-08-10-131832.ips, cited in the project retrospective |
| 2026-08-17 | First pull request opened and merged (#1) | GitHub |
| 2026-08-20 | 823MB frozen corpus destroyed; 15 transcripts lost | defect genealogy §2.5 |
| 2026-08-21 | Peak day — 61 commits; stages 11, 12a and Y1 all land (PRs #7, #9, #10) | git log + GitHub |
| 2026-08-24 17:36 | Last engineering commit before the audit | git log |
| 2026-08-24 21:58 | Audit published | site repo |
Commits per day
| Date | Commits | What was going on |
|---|---|---|
| 2026-08-09 | 2 | repo initialised at midnight |
| 2026-08-10 | 4 | stage 7 post-review fixes |
| 2026-08-11 | 14 | stage 8 accepted |
| 2026-08-12 | 9 | stage 9 deviations logged |
| 2026-08-14 | 5 | — |
| 2026-08-17 | 1 | PR #1 |
| 2026-08-18 | 10 | stage X registered |
| 2026-08-19 | 28 | stages 9 and 10 both accepted, same day |
| 2026-08-20 | 13 | stage X accepted; corpus incident |
| 2026-08-21 | 61 | stages 11, 12a, Y1 |
| 2026-08-22 | 5 | stage N queue-jumped in |
| 2026-08-23 | 43 | stage N accepted; evidence-gate protocol built |
| 2026-08-24 | 20 | stage Y2a accepted; then the audit |
| Total | 215 | 13 working days across a 16-day span |
Verification volume
| Measure | Value |
|---|---|
| Regression scripts (each chains all earlier stages) | 12 |
| Evidence artifacts on disk | 530 files |
| Stage 9 acceptance | 8/8 criteria; 3 runs at 100/100/100% precision, 89/94/94% recall; regression 17 ✅ / 0 ❌ / 1 honestly skipped |
| Stage Y1 acceptance | 6 criteria; regression across 6 layers, 103 ✅ / 0 ❌ / 0 skipped |
| Stage N evidence gate | 7 evidence packs, 5 stamped, 56 red-proofs all hitting; 2 packs honestly left unstamped |
| Stage Y2a | 4 criteria stamped, 54 red-proofs |
| Regression state at time of writing | 21 pass / 2 fail on one chain, 7 pass / 1 fail on the other — both failures attributed, neither a product defect |
Two of those rows are deliberately unflattering. A stage that reports "all green" while quietly skipping things is worth less than one that reports 5 of 7 and says which 2 and why. That was the rule, so the numbers here follow it too.
11Sources
Official documentation — the basis for every capability judgement
- Desktop application — the session sidebar and its filters, per-session worktrees, split panes, usage ring, permission-mode table, tasks pane, cross-session messaging, cloud and SSH environments; and the passage stating that Claude does not see sessions started from the terminal CLI or the VS Code extension
- Remote Control — answering permission prompts from a phone, the
Push when actions requiredtoggle, "there is no per-event configuration," where transcripts are stored, and the conditions that disable Remote Control entirely - Worktrees · Permission modes · Desktop scheduled tasks
Release dating
- Anthropic Rebuilds Claude Code Desktop App Around Parallel Sessions — 2026-04-14
- Claude Code Desktop Redesign: Multi-Sessions + Routines
- Push notifications in v2.1.110 — 2026-04-16
Public issue tracker — used only to establish absence
Companion piece
- The full feature-by-feature audit (Chinese) — all 48 rows, the evidence for each judgement, and the roadmap consequences. This article is the story; that one is the worksheet.
Capability judgements reflect documentation publicly available on 2026-08-24. Anything shipped after that date is outside this article's scope. Project figures come from the repository itself — git history, file counts, and the delivery notes written at the time.