Testero
Evidence-backed origination orchestrationHome equity origination scatters the facts of a case across documents, policy versions, vendor work and the people chasing all three. Testero keeps one canonical case state, traces every material fact to the page it came from, and derives readiness with deterministic rules instead of asserting it.
- Sole builder and technical decision-maker
- Deployed demo, fully synthetic case
- TypeScript · Next.js · Zustand · Zod · Vitest
- 40 rule and invariant tests

Engineering brief
- Architecture
- A plain TypeScript domain layer with no React, Next or network imports, holding the case model, ten effective-dated rules, the readiness projection and the action planner. Next.js and Zustand render a projection of that state; Zod guards the one API boundary.
- The hard part
- Refusing to resolve things the evidence does not resolve. Missing facts stay UNKNOWN, disagreeing sources stay contradicted with both sides retained, and an unsettled policy stays CONFLICT, so the system never asserts a readiness nobody decided.
- Testing
- 40 rule and invariant tests over the domain core, plus 6 metrics tests. They run without a renderer because the domain imports nothing, which is the practical payoff of keeping the layer framework-independent.
- Known limitation
- One synthetic case, fixtured extraction, and no persistence or authentication. The rules and transitions are real; the volume, the document pipeline and the multi-user concerns are not.
Readiness gets asserted, not derived
A home equity investment file is ready when a specific set of conditions hold. In practice nobody can say which ones, because the facts live in six places: the application, the recorded deed, a mortgage statement, a credit response, vendor orders and whatever someone typed into a note.
So readiness becomes a judgement someone makes and then defends. When the file stalls, the question is not just what is missing. It is which source was believed, which rule version applied on the day, and who decided. Correctness matters here in a specific way: a system that is confidently wrong about ownership is worse than one that says it does not know.
One canonical state, projected into everything else
There is one case state. Readiness, the blocker list, the action queue and the event timeline are all projections over it rather than separate stores that have to be kept in step. Nothing writes a readiness label, so nothing can write the wrong one.
That decision is what makes the demo behave correctly under change. Verifying a trust certification does not set the file to ready; it adds an assertion, and readiness is recomputed from the rule set at version time. The screen is downstream of the rules, always.
Every material fact knows where it came from
An assertion is not a value. It carries the text as written and a normalized value for comparison, the document, page and block it was taken from, the extractor that produced it, a confidence, a verification status and whether the fact is material or merely supporting. Block coordinates are percentages of the page box, so a highlight lands correctly at any size.
Material facts are the ones that gate decisions, and below a confidence threshold they require human verification before a rule will lean on them. Superseded assertions are retained and pointed at their replacement rather than deleted, so the history of what was believed survives.
Where two sources disagree on a material field, the case records a contradiction and keeps both sides. Testero never silently picks a winner.
In the demo case the application reports individual ownership and the recorded deed vests title in a revocable trust. That is not a data-quality nuisance to be cleaned up. It is the finding, and the rule that depends on it stays unresolved until a person names the authoritative record.
Ten rules, seven verdicts, no booleans
Each rule is effective-dated and evaluates against the case state at version time. A rule may return exactly one of seven verdicts, and the absence of a boolean is the point: missing evidence is UNKNOWN rather than a quiet failure, and an unsettled internal policy is CONFLICT rather than a guess.
Rule identifiers are not decoration. A blocker on screen names the rule that produced it, and every next action declares the rule IDs it is expected to move off the blocking list. The queue then ranks actions by how many current blockers each one actually clears, rather than by age, so the top of the list is the thing most worth doing.
The calls that shaped it
The domain layer imports nothing
No React, no Next, no fetch. The rules, the case-state projection and the action planner are plain TypeScript, which is why 40 tests can exercise them without a renderer or a network. A domain that can only be tested through a component eventually stops being tested.
Readiness is derived, never stored
There is no `isReady` column to fall out of date. Readiness is a projection over the current assertions and the rule set at version time, so clearing a blocker re-derives the answer instead of editing it. The screen cannot disagree with the rules because it is computed from them.
Seven verdicts, because a boolean lies
A rule returns PASS, FAIL, UNKNOWN, WARNING, MANUAL_REVIEW, CONFLICT or NOT_APPLICABLE. Missing evidence is UNKNOWN, not a quiet FAIL, and a policy the firm has not settled is CONFLICT. Collapsing those into pass or fail is how a system starts asserting things nobody decided.
Verdict and treatment are separate concerns
The same FAIL can be a submission blocker or a tracked trailing dependency, depending on whether a covering vendor order is already in flight and expected before the gate date. Keeping the verdict and its queue treatment as different fields is what lets the queue stay useful without weakening the rule.
Every material fact carries its provenance
An assertion records the value as written, a normalized value for comparison, the source document, the page, the block, the extractor, a confidence and a verification status. Block geometry is stored as percentages of the page box, so a highlight resolves at any rendering size.
Contradictions keep both sides
When two sources disagree on a material field, the case holds a contradiction with both sides retained rather than resolving to whichever document loaded last. The field stays contradicted until a person names the authoritative record. That is a deliberate refusal to guess.
Actions are ranked by what they unblock
Each action declares the rule IDs it is expected to move off the blocking list, and the planner ranks by how many current blockers it actually clears. Ownership is explicit too: an action waiting on a vendor, a policy owner or the homeowner is a different queue state from one waiting on the processor.
The API cannot be talked into a case the engine did not build
The client posts a demo step and a small set of operator overrides, validated with Zod, not a case object. The server rebuilds the state from the same domain code before anything reads it, so a crafted request cannot smuggle in a case state that never passed the rule engine.
What this does not establish
One case, fully synthetic
Six intake documents and one borrower. The rules are real and the state transitions are real; the volume that would expose performance and concurrency questions is not there.
Extraction is fixtured, not learned
Assertions arrive with confidences and page coordinates already attached. A production system would need a document pipeline, and the interesting failure mode would move to extraction quality rather than rule evaluation.
No persistence and no authorization
State lives in the browser for the length of a session. Roles are modeled in the domain as owners of actions, but there is no authentication, no audit storage and no multi-user concurrency.
Policy versioning is demonstrated, not administered
Rules are effective-dated and one rule deliberately runs under a conflicted policy, but there is no interface for a policy owner to author or retire a version.
What a real deployment would change
Ordered by what would hurt first. The domain core is the part designed to survive all of it.
- 01
Persistence and an event log
The case state is already a projection, so the change is to persist the assertions and decisions as an append-only log and rebuild from it. The projection code does not move.
- 02
Document extraction as a real boundary
An extraction service producing the same assertion shape, with confidence thresholds routing low-confidence material facts to human verification rather than into the rules.
- 03
Authorization on the decision, not the screen
Approving an exception or naming an authoritative record is where permission matters. Those are already discrete domain operations, which is the right place to enforce it.
- 04
Policy administration and history
Effective-dated rules need an editor, a review path and the ability to answer what the rule set said on the day a decision was made.