Testing¶
Voice is tested at four levels, each proving more with more running, and sbt test runs the first
two in a few minutes with Docker. The live-model suites and the tier against the real reasoning
service are run on purpose.
The domain and each component¶
sbt domain/test
sbt 'service/testOnly voice.unit.*'
The domain module depends on ankka-core only, so it cannot name a component and its suites run in
milliseconds: a sealed value round-trips through the platform's serializer and prints as its subject;
every event and state type is listed and the suite fails on a text field with no classification; every
refusal name in the contract exists exactly once and vice versa; the state machines of contribution,
evidence, action and notification refuse the transitions they should; a receipt's types hold no sealed
value or free text. The unit suites run each entity and workflow with the platform's test kits, and a
scripted model provider in place of the agents.
The living features¶
sbt 'service/testOnly voice.features.*'
The platform's AnkkaTestKit boots the whole service against a throwaway Postgres, with a recorded
model provider answering from modules/service/src/test/resources/model/, an in-suite ES256 issuer
minting staff tokens, and a stub reasoning service answering the record routes from the seed pack.
The seven feature files under features/ run as one suite per file, driving the service through its
three endpoints:
| Feature | Proves |
|---|---|
participation/private-conversation.feature |
a session with no identity, a turn, a proposal, confirmation, recovery across a restart; nothing public |
disclosure/exact-approval.feature |
four modes, exact text, review, rejection with reason, enhanced review, association, withdrawal; no public route returns a private field |
evidence/source-backed.feature |
a claim's explanation from records, the contradiction, the abstention, search creating no interest, corrections and review prompts |
deliberation/opinions-not-evidence.feature |
opinions never in claims, aggregates labelled, small cells suppressed, the dashboard's labels |
action/human-authority.feature |
suggested stays suggested, only a representative records, dates refused, the chronology's labels |
feedback/one-truthful-update.feature |
one update per follower per development, through a redelivered event and a restart |
erasure/field-erasure.feature |
after everything else for two participants, erase one: replay, restart, a view rebuild and a database dump find no plaintext; the other participant and the issue are intact; dormancy |
Suites share one service, so a scenario asserts on text of its own, never on text another scenario may have published. A log-hygiene suite runs the whole set with a capturing appender and fails on any of the seed's personal text in a log line or a trace name.
Against the real reasoning service¶
just up
just tier3
just tier3 runs the one suite tagged Reasoning against the reasoning service just up started:
the seed pack loads through the real service and again without change, every reference the issue
links resolves by id, and the contradiction and the abstention come from records alone. With
VOICE_GRAPH=1 and just up-graph, a fourth test reads the graph tier. The build excludes the
Live and Reasoning tags from sbt test; a recipe lifts one with VOICE_INCLUDE_TAGS.
The live model¶
ANTHROPIC_API_KEY=… just live
The live suites run the seed conversations against the model, checking the shape of every reply
and that a proposal's passages fall inside the participant's messages, and an extraction evaluation
over a labelled set in modules/service/src/test/resources/evaluation/. They spend tokens, so no
other recipe runs them. VOICE_MODEL_RECORD=1 re-records the fixtures the feature suites answer
from, which is needed when a prompt changes.
The interface¶
cd web && npm run typecheck && npm test && npm run build
The features, the glossary and the specifications¶
just check
The checker reads every feature, the glossary and the specifications that name scenarios, and
reports a step that uses an undefined word, a refused synonym, two scenarios that contradict, or a
specification naming a scenario that does not exist. A clean run says 0 findings.
Features and the glossary says how to keep it so.
Continuous integration¶
Every push and pull request runs the format check, the domain, service and seed suites, the interface's type check, tests and build, and the checker. The documentation build runs on a pull request that touches it. Nothing is deployed or published except on a version tag.