Ctrl K
ComunidadGuías…

CHANGELOG.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Changelog

All notable changes to computah are recorded here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
[semantic versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- Syl voice dispatcher policy (#49): Syl's persistent-bridge prompt keeps quick
  conversation inline and instructs Syl to send explicit handoffs, tool use, and
  multi-step work to an ephemeral background subagent after any required spoken
  confirmation. Syl gives a short acknowledgment so the listening loop can resume,
  accepts corrections while the subagent runs, and speaks each saved result once in
  bounded later voice replies without adding an unsolicited bridge reply or changing
  later text-channel behavior.
- Capture-device suitability warning (#34): `capture_quality.py` judges whether a
  mic can carry continuous speech, and the live loop says so at startup instead of
  letting it surface as a garbled transcript. A Bluetooth hands-free (HFP) mic on
  Windows downsamples to narrowband and drops frames, so faster-whisper returns
  garbled text while wake detection keeps firing at 0.998 -- the loop looks
  healthy right up to the transcript. Two property signals are a hands-free
  marker in the device name and, on WASAPI only, a default rate below the
  pipeline's 16 kHz. Other host APIs expose a preferred default rather than a
  bandwidth limit. `audio.py --list` tags unsuitable inputs, and `--test-mic`
  also flags the 4 kHz cliff left by an upsampled narrowband stream. It exits 3
  for a flagged device and 4 when the audio is unanalyzable or the narrowband
  cliff is absent, since that check cannot rule out wideband HFP recompression
  and frame drops. The module is hardware-free so `test_capture_quality.py` runs
  with no PortAudio.
- `prep_wake_samples.py --clean` (#8): removes leftover clips of a take the run
  just re-recorded (a `<stem>_NNN.wav` clip whose stem this run wrote) from
  `--output`, so re-recording with fewer utterances no longer strands orphaned
  higher-numbered clips that training and eval would still read. Off by default
  (deletion is opt-in). The source manifest below broadens cleanup to the
  prep-owned clips of an intentionally omitted take while still sparing source
  recordings and hand-curated audio. With no manifest, the narrow same-stem rule
  remains as a warned legacy fallback; any present-but-unusable record fails
  closed until removed. Without `--clean` the run still warns and names the
  leftover count. `test_prep_wake_samples.py` covers the
  re-run-with-fewer-clips case with and without `--clean`, and that source-aware
  `--clean` spares files prep did not record.
- `prep_wake_samples.py` output manifest (#84): prep records each resolved source
  path and the clips it owns in `.prep-manifest.json` in the output dir.
  `--clean` uses that provenance to remove orphans the stem match cannot reach --
  clips from an input dropped between runs, and clips under a disambiguated stem
  (`take-1_000.wav`) that a later run no longer produces. Before a destructive
  run, prep names every omitted source and how many of its clips `--clean` will
  remove. A run must share an exact recorded source path before it may write to
  that dataset, so a different dataset with the same label and generic basename
  cannot overwrite or clean it.
  Malformed ownership maps, including clip names that are paths instead of safe
  output filenames or clips claimed by multiple sources, are refused before any
  audio is decoded or written. Manifests are read and written explicitly as
  UTF-8 so non-ASCII recording paths round-trip across supported platforms.
  Manifested stems remain reserved for their source while new output names are
  assigned, so a new same-basename recording cannot overwrite the only good
  clips from a source whose rerun is silent. A source this run attempted but got
  no clips from retains those prior clips. With a readable source map,
  hand-curated audio stays outside it and is never deleted. A non-clean legacy
  refresh that leaves ambiguous same-stem files does not write a manifest; the
  next `--clean` remains on the documented filename fallback instead of turning
  a guess into durable provenance. A no-output run cannot claim an unrecorded
  directory, and a first-time source that writes no clips cannot gain cleanup
  authority over an existing dataset. Manifest writes use atomic replacement.
  Only an absent manifest degrades `--clean` to the narrow stem match with an
  explicit warning; that fallback cannot distinguish a prep leftover from a
  hand-added `<same-stem>_NNN.wav`. An unreadable, malformed, or non-v2 manifest
  fails closed until the user removes it to bootstrap ownership explicitly.
  Existing pre-manifest directories must bootstrap with the complete source set;
  clips under stems omitted from a partial first run remain deliberately unowned.
- Configurable request endpointing (#15): the trailing-silence window that ends a
  captured request and the max-request cap that bounds a runaway are now config keys
  (`endpoint_silence_ms`, `max_request_ms`, milliseconds) instead of fixed constants,
  so the live loop is tunable without a code change. `run_turn` and the `live_driver`
  loop thread the config through `capture_request`; both keys default to the built-in
  values (800 ms endpoint, 8000 ms cap), so the shipped config leaves capture behavior
  unchanged. `test_endpoint_config.py` covers the conversion, the no-drift default
  invariant, the tuned endpoint and cap, and the `run_turn` wiring, model-free.
- Mishear confidence guard: both live paths (`pipeline.run_turn` and the
  `live_driver` hardware loop) now gate the transcript on faster-whisper confidence
  before dispatching to the brain, through a shared `guard_transcript`, so a garbled
  command cannot trigger an action on either path. `avg_logprob` is the gate;
  following faster-whisper's own no-speech rule, a high `no_speech_prob` only marks a
  reject as silence when the decode is also unconfident, so a clear command is never
  dropped for it alone. A rejected turn speaks a short re-prompt instead of calling
  the brain. New config keys `stt_confidence_guard`, `stt_min_avg_logprob`, and
  `stt_max_no_speech_prob` (defaults mirror faster-whisper's own thresholds).
  `transcribe_detailed` returns the new `Transcript` (text plus the two signals);
  `transcribe` still returns text.
- `test_confidence_guard.py`: fast, no-model coverage of the gate decision, segment
  aggregation, and the shared `guard_transcript`. `test_live_driver.py`: fast,
  no-model proof the hardware path honors the guard. Two model-tier checks in
  `test_stream_turn.py` prove a low-confidence transcript skips the brain and a
  confident one passes through.
- Config-selectable brain backend: the `brain_backend` key chooses `cli` (the
  `claude -p` fallback, default) or `bridge` (a persistent assistant session), so the
  bridge is reachable from a real run, not only from tests.
- `config.local.json` overlay (gitignored) for deployment-specific bridge settings —
  persona, transport, ssh host, reply path — overriding the committed `config.json`.
  `config.local.example.json` is a template.
- `test_brain_dispatch.py`: proves config alone selects the backend and that
  persisting the wake word does not leak local config into `config.json`.

### Changed
- `brain()` now dispatches on `brain_backend`; the `claude` CLI path moved to
  `_brain_cli`. `load_config()` merges `config.local.json` over `config.json`.

### Fixed
- `set_wake_word()` wrote the merged config (defaults plus the local overlay) back to
  `config.json`. It now round-trips only the committed base, so the gitignored bridge
  settings can no longer leak into the tracked file.

## [0.1.0] - 2026-06-21

First working core. The full voice chain runs mic-free, driven by audio files.

### Added
- Four-stage pipeline (`pipeline.py`): openWakeWord wake detection, faster-whisper
  speech-to-text (int8, no PyTorch), the brain stage, and Piper text-to-speech, plus
  an end-to-end chain and a CLI.
- Changeable wake word from `config.json`, with `--list-wake-words` and
  `--set-wake-word`.
- Brain bridge (`brain_bridge.py`): routes the transcript to a persistent assistant
  session over a file-based message-passing contract, with injected transports
  (local CLI, ssh, and a test stand-in).
- Simulated persona (`sim_persona.py`) for exercising the brain loop with no live
  session and no microphone.
- Tests: bridge round-trip (`test_brain_bridge.py`), full chain with the bridge
  brain (`test_pipeline_bridge.py`), and full chain with the fallback CLI brain
  (`test_pipeline.py`).
- Pinned dependencies (`requirements.txt`), CPU-only, no PyTorch.

[Unreleased]: https://github.com/jamditis/computah/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/jamditis/computah/releases/tag/v0.1.0