We graded the codebase against ISO/IEC 25010.

ISO/IEC 25010:2023·8 min read·As assessed August 2026

ISO/IEC 25010 is the international model for software product quality. It breaks “is this good code” into eight characteristics, from reliability to maintainability, each with its own sub-parts. We have an AI model grade the whole codebase against it every few weeks. This run came out at A-, up from the B+ we published last time, and the reason is boring in the good way: every item the previous assessments named as holding a grade down has since been fixed, and this run struggled to find replacements.

AI-generated assessment

This report was generated by an AI agent reading our codebase against ISO/IEC 25010:2023. It records a pass or fail for each requirement and the plain-English reason behind it.

It is honest by construction. We asked the model to grade the code against the standard, not to make us look good. This is the same internal assessment we run for ourselves, and we publish the gaps and failures exactly as it found them. Curating it for the public meant removing implementation detail that would help an attacker. It did not mean changing a single verdict or its reasoning.

A human reviewed it before publishing. It is a point-in-time snapshot, last assessed August 2026, not a live mirror of the code.

The verdict

Overall grade: A-

Five agents graded a slice of the model each. Three of the five came back with nothing to report. Between them the five raised three candidate issues, and the verification pass that re-reads every claim against the actual code kept exactly one: two copies of the same database-row check, sitting side by side, identical apart from the error message. Nothing is broken today. The risk is the next person to add a rule to one copy and not the other. We fixed it the same day the report landed.

A-
Overall grade
8,265
Tests, all passing
3 of 5
Passes with zero findings
1 of 3
Findings that survived review

A word on the trend line, because a rising letter is the easiest thing in a report like this to oversell. Grades between runs are not perfectly comparable: each run uses different grading agents, and the rubric has been tightened at least once. What is comparable is the countable stuff, and that moved the right way. The test suite is at 685 files and 8,265 cases, all green on a live run. Suppressed type errors: still zero. Silently swallowed errors: still zero. API routes returning an error outside the standard format: zero. What is also comparable is whether the named items got fixed, and they did: the contributor docs that understated how many services we deploy, a registration check that accepted a non-boolean as consent, credential routes whose database failures escaped the standard error envelope, and a mismatch where one service accepted an identifier format another service rejected. All closed and verified closed.

The breakdown

The eight characteristics

ISO 25010 scores a characteristic by its weakest contributing part, so a single soft sub-area pulls the whole letter down. Every grade below A here names the specific thing holding it there.

CharacteristicGradeWhy
SecurityAZero findings. Every entity-lookup route sampled scopes its query to the owning organisation, so one tenant asking for another tenant's record gets a not-found rather than a leak. Encryption is bound to the owning organisation on every field, and secret comparisons run in constant time.
Functional suitabilityAEvery kind of identifier is its own distinct type, 34 of them, each with a matching parser and a checked conversion point. No suppressed type errors anywhere outside tests; the few remaining escape hatches are documented framework seams.
CompatibilityASix independently deployed services with no shared source imports. The published API description now derives its vocabularies from the live code rather than a hand-typed copy, and the cross-service identifier mismatch the last internal run found is closed on both sides.
Interaction capabilityAGraded for the developer as user. The contributor docs that were wrong last time are correct now. Every one of our 121 internal documents carries its machine-readable header, and every file path those headers point at still exists.
ReliabilityA-Zero findings, two runs in a row. Multi-step writes follow the documented rollback playbook, the durable job runner treats a lost result as work to retry rather than work to drop, and a test fails the build if any route skips its input type check.
SafetyA-Fail-safe defaults throughout: an unknown API key is still hashed and compared in constant time so it cannot be told apart from a wrong one by timing, and token revocation always answers the same way so it cannot be used to test whether a token exists.
FlexibilityB+A new AI provider is still a one-line data edit, and the durable job runner scales separately from the request-serving services. Held at B+ because scale-sensitive behaviour is judged here by reading code, not by profiling a live system.
MaintainabilityBZero dead code, no leftover commented-out blocks, and a fast comprehensive suite. Held at B by the run's one real finding (now fixed) and by one screen component that has grown to take 61 separate inputs from its parent.

Performance efficiency is intentionally not graded here. Profiling a live runtime is out of scope for a static read of the code, and no pass surfaced a diagnosable hot-path problem.

The good part

What the assessment found strong

  • One choke-point for the API. Authentication, role check, rate limit, plan gate, and a consistent error format run on every route through a single handler. Across 139 routes this run found no way in that skips them, and linting blocks the shortcuts.
  • Enforcement is mechanical, not aspirational. The API error format, the AI call boundary, the identifier types, and the ban on silently swallowed errors are lint rules with zero violations in the tree, not conventions in a document someone has to remember.
  • Layer boundaries hold at scale. Across roughly 480 library files, components, and hooks, the import-direction check found no violations: screens do not reach into the database layer, and the API does not import screens.
  • One playbook for risky writes. Every multi-step write sampled followed the documented pattern exactly: roll back what you can, log what an operator needs to reconcile by hand, fail in the direction that is safe. Two grading passes in a row found nothing to flag.
  • Compile-time tenant isolation. Every identifier kind is its own type, so the compiler rejects mixing one organisation's data with another's before the code can ship. Multi-tenant safety is not left to whoever remembers to scope a query.
  • A test suite that pins the failure paths. 685 test files and 8,265 cases, all green on a live run. They pin what happens when things go wrong, not just the happy path, and every one of our six deployed services is gated in the build pipeline.
  • A verification gate that earns its keep. Two of the three draft findings were dropped by a reviewer re-reading the code first-hand. One claimed a component could not be tested without heavy setup; four test files already test it. What gets published is what survived.
The honest part

What's still on the list

Every item below is deliberate, documented, or already tracked. We publish them because an assessment that only lists strengths is marketing, not an assessment.

  • One screen component takes 61 separate inputs. The recommendations panel on an observation page has grown one feature at a time until its parent now hands it 61 things. It is tested and it works, but it is fiddly to change. A reviewer talked us out of rewriting it this week: the case for the rewrite rested on a claim about testability that turned out to be false, and a half-day refactor of a busy screen needs a better reason than tidiness.
  • Tenant scoping is centralised for common queries, not all of them. A shared helper covers the dominant query shapes; the more custom reads still write the per-organisation filter inline. Every site is correct today and the compiler-checked identifier types back it up, but replacing the mechanism would touch a lot of files.
  • Some cross-service seams rest on discipline. A few places stay correct because two files are edited in lockstep rather than because a compiler is watching. The specific mismatch the last internal run found is now closed and pinned by a shared test, and this run found no new drift, but the general shape of the risk remains.
  • The AI abuse guard doesn't cover every AI route yet. It guards the highest-cost routes, with spend caps and rate limits bounding the rest. Extending it is a tracked, low-severity item, and a deliberate piece of version-one scoping.
  • Scale is graded by reading, not by measuring. Nothing in this assessment profiles a running system under load. The code reads as though it scales, which is not the same claim as knowing it does.
The security backlog behind this

Two open items in the security tracker at the time of this assessment, one low severity and one informational. Both are deliberate scope decisions with bounds in place, both already tracked, and both are cross-referenced by this assessment rather than discovered by it. Nothing exploitable.

The method

How it was graded

Five agents each graded one slice of the ISO 25010 model in parallel, working from the same commit, each told that reporting zero findings is a perfectly good answer. A separate and more capable reviewer then re-read every claim at the source with one job: decide whether each finding is real and whether the proposed fix actually works. It kept one of three. Where a dropped finding left a grade unsupported, the grading agent was asked to justify that grade on other evidence or raise it. One agent responded by lowering its grade instead, arguing that the evidence disproving its finding actually supported it. We overruled that and recorded why. The grades above are what survived.

How this was made

Curated from our internal report for public release. We removed implementation detail that would help an attacker, generalised file references to the controls they point at, and dropped internal tracking IDs. We did not change a single verdict or its reasoning. When we re-run the internal assessment, we refresh this page by hand.

This is the product the report graded.

A purpose-built security register with per-org encryption, mandatory MFA, and EU data residency. Free tier, no card.