What changed
v0.0.2 — 2026-09-10
The decision path is domain code (ADR 0008). dialogue.py, brain.py,
briefs.py, gate.py and demo_loads.py moved under app/domain/calling/,
where the import-linter purity contract forbids I/O. The live bot no longer
imports a benchmark script at start-up. The router and brain tests run in the
main suite with no skip.
One venv. [dependency-groups] voice records the Pipecat install that was
never written down. uv sync --group dev --group voice; 1,289 tests in one
interpreter.
Ending the call: one mechanism. CallEnd arms on any hang-up decision,
ends only on audio that started after arming plus a playout grace, and has a
watchdog. Every path — model goodbye, canned goodbye, give-up, abuse — arms
the same object. The session record carries ended_by (ori · watchdog ·
browser · idle) and the disposition.
A cut-off figure is held. "तो मेरा rate लगभग" is held 1.5 s and merged with its continuation before anything is decided.
The router is a table. Rules in precedence order, each returning its
name; the page and the record show which rule fired. normalise() splits what
the recogniser joined; every list is matched folded (nukta-insensitive) and
word-bounded; verb forms come from one paradigm; unmistakable recordings
precede the callback rule; abuse warns once and ends on the second strike.
Both scripts in every list, because Flux writes "number" and "switch off" in
Latin inside Hindi.
The brain has phases. Seven of them replace nine booleans. An out-of-range quote is questioned before the ladder closes; a good quote is squeezed once before the ladder takes it; the deferral is terminal; a particle during the probe gets one more ask; accepting the counter settles at the concession, never the ceiling. The wind-down line is canned and every brief forbids the model from saying it. The prompt carries the last three exchanges with her figures stripped.
Transliteration. Unknown words stay in Latin; the rule speller that produced दिसतनके for "distance" is gone. The model's 196-word vocabulary is a fixture and every word must have a pronunciation.
Comments. Every file on the decision path and in the ASR layer says why in
one or two lines; the stories are in the incident ledgers. The code AST of each
trimmed file is unchanged (scripts/comments_only.py). Emoji markers in
source: 0 on the decision path.
Deleted. The push-to-talk glass box (app/api/ori.py, live.py, two
pages, 17 tests), the CLI scaffold (poc/pc-tele, bot.py, Dockerfile,
pcc-deploy), the stale poc/pipecat shadow package, a two-week-old handoff
note.
Tests. tests/domain/calling/test_phases.py (17), test_call_end.py
(16), test_normalise.py, test_router_stability.py (the perturbation
ceilings), test_brain_abuse.py; scripts/mutate.py and make mutate;
poc/e2e.py with seven audio scenarios; a CI workflow.
Measured.
| what | v0.0.1 | v0.0.2 |
|---|---|---|
| routings moved by joining the first two words (133 rows) | 29, 18 money-critical | 1, 1 |
live calls replayed where counter_once was reached (22) |
3 | 5 |
| calls the brain decided to end (22) | 10 | 13 |
| model turns handed a vague brief while a probe was open | 7 | 1 |
| end-to-end scenarios ending by Ori's decision | 0 of 1 (the goodbye was clipped) | 7 of 7 |
| decision-path files with emoji markers | 14 | 0 |
| test suite | 1,209 + 254 in two venvs | 1,289 in one |
Tooling. poc/converse_bakeoff.py (12 models, three passes, two judges),
poc/judge_resume.py, poc/analysis/ (mine_calls, mine_words, replay_calls,
perturb, probe_models), docs/site/build.py and deploy/docs.sh for this
site.
Still open. The bake-off verdict; real call recordings; telephony; the semantic fallback under the router; the venv swap on the machine that runs the live bot.
v0.0.1 — 2026-09-10 (morning)
The first build confirmed end to end by Mehul: a call placed, negotiated,
ended by the agent, and feedback saved against it with audio and a transcript.
Defined once in version.py and stamped by the server into the page and every
session record.