Implements the full M1 milestone. Two clients authenticate over TLS 1.3 (guest + Argon2id password) and exchange channel + private text messages through a real server. All five ctest --preset m1-dev tests pass in ~1 s. Key components added: - vcpkg baseline + m1-dev preset (protobuf/mbedTLS/libsodium/asio/sqlite3) - FrameCodec feed+emit, encode/decode_envelope, protobuf codegen - TcpServerConn with blocking TLS handshake thread + tls_read_loop - TlsContext (mbedTLS 1.3, ECDSA-P256 self-signed cert, TOFU on client) - WorkerPool (3 threads, used for Argon2id) - Database: SQLite + libsodium Argon2id, account lifecycle, bootstrap admin - ServerIdentityManager: Ed25519 key + cert generate/persist/fingerprint - ConnSession state machine: WaitingHello -> WaitingAuth -> Authenticated - SessionRegistry: channel tree, user map, text routing, broadcast - vc_client full M1 C ABI: connect/TLS/handshake/auth/text/disconnect - voicecat-admin CLI: account add/reset/del/list - test_m1_integration: M1 exit criterion, verified green Bug fixed: double-framing in ConnSession::send_envelope -- encode_envelope was adding the [4-byte len] prefix, then TcpServerConn::send_frame added a second one, causing the client to parse [len][proto] as protobuf (silent failure). Fixed by serializing raw protobuf bytes in send_envelope and letting send_frame apply the single length prefix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
86 lines
4.2 KiB
Markdown
86 lines
4.2 KiB
Markdown
# PROGRESS — VoiceCat
|
|
|
|
Living status. **Update this file in the same commit as your work** so the next agent picks
|
|
up instantly. Newest status at the top.
|
|
|
|
- **Date convention:** ISO (YYYY-MM-DD).
|
|
- Statuses: `[ ]` not started · `[~]` in progress · `[x]` done.
|
|
|
|
---
|
|
|
|
## ▶ Where we left off / next action
|
|
|
|
- **Done:** **M1 — control plane** ✓ complete (2026-06-15).
|
|
`ctest --preset m1-dev` — all 5 tests green (smoke, frame_codec, envelope, tls_loopback,
|
|
m1_integration). Two clients authenticate over TLS 1.3 and exchange channel + private text.
|
|
- **Next:** **M2 — voice, single stream**. First task: Opus encode/decode stub → real
|
|
implementation; UDP socket + ChaCha20-Poly1305 AEAD media frame; jitter buffer.
|
|
See `docs/voice.md` and `docs/roadmap.md §M2`.
|
|
|
|
---
|
|
|
|
## Milestones (see [docs/roadmap.md](docs/roadmap.md) for full detail)
|
|
|
|
- [x] **M0 — Scaffolding** ✓ complete
|
|
- [x] **M1 — Control plane** ✓ complete (2026-06-15)
|
|
- [~] **M2 — Voice, single stream** (UDP, Opus, jitter buffer, APM send-side, VAD/PTT) ← current
|
|
- [ ] **M3 — Multi-stream & per-channel tuning** (screen audio, listener-side per-user NR)
|
|
- [ ] **M4 — Native clients** (Windows C#, macOS/iOS Swift)
|
|
- [ ] **M5 — Moderation, polish, beyond** (perms, bans, DRED; then file transfer, E2EE, …)
|
|
|
|
---
|
|
|
|
## M0 — Scaffolding ✓ (completed)
|
|
|
|
- [x] Repo layout (`core/ server/ tools/ clients/ tests/`), CMake + presets, vcpkg manifest.
|
|
- [x] C ABI header `core/include/voicecat.h` (full surface, stubbed).
|
|
- [x] Protocol source-of-truth `core/proto/voicecat.proto` (matches docs/protocol.md).
|
|
- [x] Core stubs for all six subsystems (net/crypto/codec/protocol/session/audio) + `vc_client`.
|
|
- [x] `voicecat-server` (arg parsing, config, stub run) and `vccli` (drives the C ABI).
|
|
- [x] CTest **smoke test** asserting the C ABI contract (not just "it compiles").
|
|
- [x] `.gitattributes` (LF), `.gitignore`, `.clang-format`, onboarding docs.
|
|
- **Verified:** `cmake --preset dev && cmake --build --preset dev && ctest --preset dev` → green.
|
|
|
|
---
|
|
|
|
## M1 — Control plane ✓ (completed 2026-06-15)
|
|
|
|
**Exit criterion:** ✓ `test_m1_integration` — two clients authenticate over TLS 1.3 (guest
|
|
+ Argon2id password), exchange channel and private text messages. Passes in ~1 s.
|
|
|
|
- [x] vcpkg baseline + `m1-dev` preset; `find_package` for protobuf/mbedTLS/libsodium/asio/sqlite3.
|
|
- [x] `FrameCodec` feed + emit; `encode_envelope` / `decode_envelope`.
|
|
- [x] Asio TCP acceptor + `TcpServerConn` (TLS path: blocking handshake thread + `tls_read_loop`).
|
|
- [x] `TlsContext` (mbedTLS 1.3, server cert/identity, ECDSA-P256 self-signed, TOFU on client).
|
|
- [x] `WorkerPool` (3 threads, used for Argon2id).
|
|
- [x] `Database` — SQLite, Argon2id via libsodium, `create_account` / `authenticate` / bootstrap admin.
|
|
- [x] `voicecat-admin` — account add/reset/del/list against live DB file.
|
|
- [x] `ServerIdentityManager` — generate/persist Ed25519 key + cert; fingerprint display.
|
|
- [x] `ConnSession` — WaitingHello → WaitingAuth → Authenticated state machine; full protocol relay.
|
|
- [x] `SessionRegistry` — channel tree, user map, broadcast, text routing.
|
|
- [x] `vc_client` (`client.cpp`) — full M1 C ABI: connect/TLS/ClientHello/AuthRequest/text/disconnect.
|
|
- [x] `Server::run()` — io_context, acceptor, worker pool, signal handling, `on_ready` callback.
|
|
- [x] `test_m1_integration` — M1 exit criterion. Verified green 2026-06-15.
|
|
|
|
**Key bug fixed:** double-framing in `ConnSession::send_envelope` — `encode_envelope` was
|
|
pre-framing the protobuf, then `TcpServerConn::send_frame` re-framed it. Fixed by serializing
|
|
raw protobuf bytes directly and letting `send_frame` add the single `[4-byte len]` prefix.
|
|
|
|
---
|
|
|
|
## Decisions log
|
|
|
|
All architecture/scope decisions are settled and recorded in
|
|
[docs/roadmap.md §2 "Resolved decisions"](docs/roadmap.md) and reflected across `docs/`.
|
|
If you make a *new* decision, record it there and link it here.
|
|
|
|
---
|
|
|
|
## How to update this file
|
|
|
|
1. Check off tasks as you complete them; flip a milestone to `[x]` only when its **exit
|
|
criterion test** passes.
|
|
2. Keep the **"Where we left off / next action"** block at the top accurate — it's the first
|
|
thing the next agent reads.
|
|
3. When you start a milestone, copy its task list from `docs/roadmap.md` into a section here.
|