Skip to content

Chore/production hardening - #1

Open
avase33 wants to merge 3 commits into
mainfrom
chore/production-hardening
Open

Chore/production hardening#1
avase33 wants to merge 3 commits into
mainfrom
chore/production-hardening

Conversation

@avase33

@avase33 avase33 commented Jul 28, 2026

Copy link
Copy Markdown
Owner

No description provided.

Akhil Vase and others added 3 commits July 27, 2026 08:01
… green

`ruff check` was failing on 49 errors even though nothing in the repo had
changed. The cause was configuration, not code: the dev extra asked for
`ruff>=0.5` with no upper bound, and ruff widened its *default* rule set from
~60 to ~400 rules in 0.16, so CI installed a linter that enforced far more than
the one this code was written against.

Two changes make the check mean the same thing tomorrow as today:

* `[tool.ruff.lint].select` now names the rule families explicitly instead of
  inheriting ruff's default, and the `dev` extra bounds ruff (plus pytest,
  pytest-asyncio and mypy) so a release can't silently change what CI enforces.
* the 49 findings are fixed rather than suppressed: `Optional[X]` -> `X | None`,
  `typing.AsyncIterator`/`Callable` -> `collections.abc`, `Union[...]` -> `|`,
  `%`-formatting -> f-strings, `re.I` -> `re.IGNORECASE`, sorted `__all__` and
  import blocks, `int(round(...))` -> `round(...)`, and every line brought under
  the 100-column limit the config already declared but never enforced.

The one suppression is a `noqa: BLE001` on the tool dispatcher's catch-all,
which is deliberate: a failing tool has to come back as an error the model can
talk about, never as an exception that drops a live call. The pylint refactor
family (PL*) is left unselected because PLR0911/PLR0912 fire on the dialog state
machine's branch-per-slot design and PLR2004 on the codec constants; both are
intentional, so the family stays off rather than being papered over per line.

Also hoists the per-call `import sys` in the PCM codec to module scope and
resolves the byte-order test once at import instead of per frame, chains the
`ImportError` behind `vox serve`'s missing-extra message, and extends lint
coverage to `scripts/` and `examples/`. CI gains `permissions: contents: read`,
`fail-fast: false` and per-ref concurrency cancellation.

Verified: `ruff check vox_agent tests scripts examples` exits 0, `pytest -q`
25 passed, `python scripts/verify_full.py` 19 passed / 0 failed on Python 3.10,
3.11 and 3.12. Audio output is byte-identical to before the change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011mYwvHvELPE8nvgjP3AMg8
…e diary keys

`_looks_iso` accepted `2026-7-9` via `strptime` and then passed the string
through untouched, while every date the system generates itself comes from
`date.isoformat()` and is zero-padded. Two spellings of the same day therefore
produced two different `day` values, and since double-booking is prevented by
`UNIQUE(day, time)` on that column, a partly padded date could book a slot that
was already taken.

`_as_iso_date` replaces it: one strict regex, explicit construction, and a
canonical `YYYY-MM-DD` string out. `_resolve_day` folds the
"ISO date or weekday name" decision that both `check_availability` and `book`
were duplicating into one place. Parsing stays explicit rather than delegating to
`date.fromisoformat`, which from 3.11 also accepts `20260709` and ISO week dates
— behaviour that would differ across the supported Python range.

Also makes "today" explicitly local (`datetime.now().astimezone().date()`
instead of a naive `date.today()`): same result, no implicit assumption, and it
satisfies the DTZ rules now that they are enforced.

Verified: `2026-07-09` then `2026-7-9` at the same time is now correctly rejected
as `slot_taken`; every other input in a 15-case table resolves exactly as before.
`pytest -q` 25 passed, `python scripts/verify_full.py` 19 passed / 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011mYwvHvELPE8nvgjP3AMg8
Removals:

* `docs/architecture.md` — a 30-line generated template ("Repository pattern for
  data access layer", for a project with no repository pattern) sitting next to
  the real `docs/ARCHITECTURE.md`. Two paths differing only in case cannot both
  be checked out on a default macOS or Windows filesystem, so this pair broke
  clone for a large share of readers.
* `docs/dev-log-2026-07-{17,20,21,22}.md` — four byte-identical generated files
  claiming "Refactored core modules for better maintainability" on days when no
  code changed.
* `CHANGELOG.md` is rewritten in Keep-a-Changelog form. What was there described
  a session id (`## [20260722212147]`) and invented work; what is there now is
  0.1.0 as it actually shipped, plus this branch's changes.

README corrections, all measured on this machine rather than asserted:

* The pasted `vox demo` transcript was stale — it showed two tool calls and a
  date-based slot list, where a real run makes three calls (the second checks the
  specific requested time) and offers weekday-relative slots. Replaced with
  verbatim output, and the two lines that legitimately vary between runs (the
  confirmation date, the latency line) are called out as such.
* The latency block contained literal `...` where the numbers should be. It now
  carries real figures from `vox demo` and `vox bench -n 20`, the commands and
  runtimes to reproduce them, and the machine they came from.
* "speaks back in well under half a second" was true of time-to-first-byte only;
  `total_p50_ms` is ~2.5s. A new "Latency, precisely" section defines all four
  metrics, states that any sub-500ms figure in this project refers to `ttfb_ms`
  and nothing else, and explains why `total_ms` is seconds: it includes streaming
  every audio frame of the reply, and measures 0.54-0.55x the emitted audio
  duration, so it tracks how long the sentence is rather than any compute cost.
* Three claims the code does not support are corrected: barge-in credited
  `audio/vad.py`, but the interrupt flag lives in `pipeline.py` and the browser
  demo's signal comes from the browser's own `onspeechstart`; `audio/` claimed
  "resampling" where only decimation exists; the metrics row implied p50/p95 for
  all four timings where `summary()` aggregates TTFB and total.
* A new "Limitations" section records what is honestly unfinished: `VOX_STATE=redis`
  persists only the dialog stage, the paid-provider adapters are untested code
  paths, the server drops raw mic audio unless a real STT is configured, the
  calendar is in-memory by default, and the dialog policy repeats itself when a
  requested slot is already gone. The existing "How offline works honestly"
  section is kept as-is.
* `RedisStore`'s docstring claimed history was serialised as JSON. It isn't —
  only `stage` is written. Docstring now says so.

Verified: every number and transcript above came from running `vox demo`,
`vox bench -n 20`, `vox bench -n 2` and `scripts/verify_full.py` on the tree at
this commit; timings are wall-clock measurements on the machine named in the
README.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011mYwvHvELPE8nvgjP3AMg8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant