EngineeringThe Blog
Measure What You Actually Built
A passing test suite can prove exactly what it tested. The dangerous part is everything you quietly assumed it covered.
Contents9 sections
- A test count is not a quality score
- Different failures require different witnesses
- The bug outside the measurement still exists
- A green pipeline is permission to look further
- Measurement can create its own blindness
- Tests are strongest when they preserve embarrassment
- What I call a test should correspond to a claim
- More tests can increase uncertainty
- Build evidence, not decoration
From the WALDHORN.AI Build Archive
Build date: May 31, 2026
By this afternoon, WALDHORN.AI had 178 automated tests passing.
That is a satisfying number to look at. It is also surprisingly easy to misunderstand.
A test suite tells me something valuable: the behaviors represented by those tests produced the expected results under the conditions in which they ran. It does not tell me that the whole application works. It does not tell me that I tested the right things. It does not tell me that a browser can render what the test runner never sees, that a production build can compile what TypeScript accepted, or that a multi-step workflow survives contact with the services around it.
Today I added a continuous integration pipeline that runs several different checks every time the code changes. The interesting part is not automation itself. The interesting part is admitting that no single green number deserves to stand in for the product.
A test count is not a quality score
I like tests because they turn assumptions into repeatable questions. If a piece of software should reject an invalid state, preserve a value, parse a response, enforce a boundary, or calculate something exactly, I would rather encode that expectation than rely on remembering to check it manually.
The danger starts when the number of tests becomes a proxy for how trustworthy the application is.
One hundred tests can be excellent or nearly meaningless. A thousand tests can exercise a broad system or repeat variations of the same narrow behavior. Coverage can increase because important logic is being examined, or because easy code is being measured more aggressively. Every metric has a subject, even when the dashboard displaying it makes that subject disappear.
The question is not simply how many tests pass.
The question is what claim those tests allow me to make.
That is harder to put on a badge.
Different failures require different witnesses
Over the last several days I have been repeatedly running the test suite and type checker after changes. By May 31, the suite had grown from the first service-layer tests into a broader collection covering product logic, parsing, validation, security-sensitive boundaries, display helpers, configuration, and other deterministic behavior.
But the application is not only TypeScript functions.
A type checker can tell me that certain relationships in the program are structurally valid. It cannot tell me whether a stylesheet contains something the production compiler rejects. A unit test can prove that a helper behaves correctly while the page that uses it is broken. A build can prove that the application compiles while saying very little about whether a user can successfully finish a real contract review.
These checks overlap, but they are not substitutes for one another.
That is why the pipeline I added today runs type checking, automated tests, and the actual production build as separate gates. A change has to survive all three.
This is not sophisticated engineering. It is closer to refusing to let three different questions share one answer.
Does the program satisfy its type constraints?
Do the behaviors I chose to test still behave as expected?
Can the application actually be assembled the way production expects?
Green on one line does not answer the other two.
The bug outside the measurement still exists
This matters because some of the most annoying defects I have been fixing recently were not failures of the underlying business logic.
A mobile panel could render outside the viewport. A keyboard focus state could disappear. A browser-native control could look wrong against the interface. A valid contract could be rejected because a quality check interpreted legitimate language too narrowly.
The code can be working according to one definition while the product is failing according to another.
That is the uncomfortable thing about software quality. There is no neutral place from which to measure all of it.
Every automated test begins by choosing what matters enough to observe. Anything outside that observation can still be broken.
The answer cannot be to automate nothing. That would replace incomplete evidence with memory and optimism.
The answer is to be precise about what each form of evidence actually proves.
A green pipeline is permission to look further
Later today I refactored a large part of the royalty-audit flow. The goal was structural: move a large page into smaller components while preserving behavior.
The type checker passed.
All 178 tests passed.
The production build passed.
I still left myself a note to run one real audit before relying on the refactor.
That may look inconsistent. If all the automated checks are green, why perform a manual smoke test?
Because the checks answer different questions from the one I still care about.
The automated suite can verify a great deal of the logic around the flow. The build can verify that the application compiles. Neither automatically proves that a real file can travel through authentication, upload, processing, streaming, persistence, and final rendering exactly as a user experiences it.
I could write increasingly elaborate automated integration tests for that path, and some of that may be worth doing. Even then, the question remains the same: what environment did I actually test?
A green pipeline is evidence.
It is not absolution.
Measurement can create its own blindness
There is a psychological problem with measurable engineering work.
Once something has a number, it starts attracting attention.
Test count is visible. Coverage is visible. Build status is visible. Execution time is visible. A subtle misunderstanding in a real contract workflow may not be visible until somebody encounters it.
That creates an incentive to improve what can be counted.
I do not think this is unique to software. Any metric can start replacing the thing it was designed to approximate.
If I begin optimizing WALDHORN.AI for test count, I can make the number move without necessarily making the product safer. If I optimize only for coverage, I can cover code without testing the assumptions that matter. If I optimize for zero build failures, I can produce software that compiles beautifully and behaves badly.
The metric is useful only while I remember what it is measuring.
The moment I start treating the measurement as the underlying reality, it becomes dangerous.
Tests are strongest when they preserve embarrassment
The best tests I have written so far tend to come from something that already went wrong or something I can imagine being embarrassed by later.
A valid input was rejected.
A state could drift.
A parser accepted something it should not.
A mobile interaction failed at a real viewport.
A security boundary depended on an assumption that had not been enforced.
Once the failure is understood, a test can preserve the lesson. The code may change completely six months from now, but the embarrassing behavior should not quietly return.
That is more interesting to me than accumulating tests for their own sake.
A test is useful when it makes forgetting expensive.
It turns an unpleasant discovery into a permanent question the code has to keep answering.
This is also why a smaller number of adversarial tests can sometimes teach me more than a large number of comfortable ones. A test designed around the happy path confirms that the system behaves the way I expected. A test built around a previous failure challenges whether my expectation was complete.
Both have value.
They measure different things.
What I call a test should correspond to a claim
I am starting to think the language around engineering metrics should be stricter.
If I say WALDHORN.AI has 178 tests, that statement should mean 178 tests actually executed in the suite I am referring to. If I say the build passes, it should mean the production build was actually run. If I say a workflow is verified, I should know whether I mean its pure logic was unit-tested, its route was exercised, or a real end-to-end action succeeded.
Those are different claims.
Combining them into a general word like tested makes communication easier and reality blurrier.
The same problem appears when evaluating AI systems. A benchmark result can look wonderfully objective until you ask what documents were included, what was excluded, what counted as success, and whether the evaluation resembles the environment the product will actually encounter.
I am not solving that larger problem today.
I can already see the shape of it.
Measurement is not just about collecting numbers. It is about defining the thing the number is allowed to represent.
More tests can increase uncertainty
This sounds contradictory, but sometimes a growing test suite makes me more aware of how much remains untested.
The first few tests create confidence because obvious behavior becomes repeatable. As the suite grows, boundaries appear. This function is covered, but the service using it depends on something external. This route is tested, but not under a real browser session. This component renders, but the complete workflow has another state the test never enters.
That is not a reason to stop testing.
It is one of the reasons testing becomes useful.
A good measurement system does not only increase confidence. It reveals the shape of the uncertainty around that confidence.
I would rather know that a particular claim is unproven than let a large green number imply that everything around it is safe.
Build evidence, not decoration
There is a version of engineering where tests appear near the end.
The feature works, the interface looks good, and then tests are added because mature software is supposed to have tests.
I am trying to move in the opposite direction.
When a behavior matters, its verification should become part of the behavior's existence. When a bug teaches me something, the lesson should survive the fix. When a production build can fail in a way the earlier checks cannot see, the production build belongs in the routine check.
The goal is not to make WALDHORN.AI look heavily tested.
The goal is to accumulate evidence about increasingly specific claims.
That evidence will always be incomplete. Some failures will appear outside the current measurement. Some workflows will still need to be exercised in the real environment. Some assumptions will remain invisible until reality finds them.
The useful response is not to pretend the uncertainty disappeared because the pipeline turned green.
It is to keep making the boundary between proven and assumed harder to ignore.
Today the product has 178 passing tests, a type check, and a production build running automatically against changes.
That is more evidence than I had yesterday.
It is not a score for how correct WALDHORN.AI is.
It is a clearer record of what I have actually checked.