Historical upstream plan. Work took place in an isolated worktree, keeping
mainandfeat/v3-parakeetuntouched. Changes were incremental, with structural and behavioral commits separated following Tidy First. Sources are listed below.
The architecture already has the right overall shape: one-way SSE, child-process supervision, shared types, and Python ports/adapters. For a solo founder launching soon, the main risk is an ambitious rewrite. The plan instead uses Strangler Fig and Sprout/Wrap techniques with characterization tests, preserving the working pipeline.
Two areas merit reliability work before launch: bounded backpressure and process supervision. An orphaned FFmpeg process holding the microphone can make a real-time transcription app appear broken.
server.ts: 2,197 lines, combining more than eight domains: routing, FFmpeg, Ollama, SSE, recording state, configuration, sessions, setup, and recovery.- Global mutable state in
server.ts: 14 variables around lines 1108–1391, changed by multiple asynchronous handlers, creating races such as stopping during an in-flight live chunk. - 29
catch {}blocks silently swallowing errors, including corrupt configuration becoming an empty object. useRecording.ts: 390 lines, coupling the API, three EventSource instances, animation, and Zustand.transcription_server.py: 1,741 lines, combining HTTP, models, diarization, SSE, and voices.- Live state spread across seven variables and two functions, without an explicit lifecycle.
Other high-priority findings: incompatible append/replace/upsert store patterns; an implicit SSE contract without discriminated unions; no error recovery in _stream_dual; duplicate loadConfig() implementations; no recording state machine; no structured logging; and approximately 0.4% test coverage across two files.
- Vercel Web Interface Guidelines: https://vercel.com/design/guidelines and the MIT-licensed
vercel-labs/web-interface-guidelinesrepository. - Vercel AI SDK: streaming, error handling, backpressure, and stopping streams at https://ai-sdk.dev. The plan does not adopt the SDK; it adopts distinctions such as partial/final results, in-band errors, and abort versus finish.
- John Ousterhout, A Philosophy of Software Design: deep modules, information hiding, and defining errors out of existence.
- Martin Fowler, Refactoring, second edition; Strangler Fig; SelfTestingCode: small steps rather than a large rewrite.
- Michael Feathers, Working Effectively with Legacy Code: seams and characterization tests for code without a safety net.
- Kent Beck, Tidy First?: separate structural changes from behavioral changes.
- Eric Normand, Grokking Simplicity: functional core and imperative shell; distinguish actions, calculations, and data.
- Alistair Cockburn, hexagonal architecture; Scott Wlaschin, Domain Modeling Made Functional; Jimmy Bogard, vertical slices: explicit boundaries and capabilities rather than universal layers.
- The Grug Brained Developer, Dan Abramov, and Sandi Metz: avoid premature abstraction; duplication can be cheaper than a wrong abstraction.
- React 19 documentation, TkDodo on Zustand/React Query, react-error-boundary, Total TypeScript, dependency-cruiser, and Bun workspaces.
- RF-1 — contracts: discriminated unions in
sharedfor SSE events and recording states, plusassertNever. Contract errors should fail compilation. - RF-2 — structural: consolidate configuration into one module and add structured logging.
- RF-3 — structural extraction: extract behavior-preserving
sse.ts,process-supervisor.ts,ollama.ts, andtranscription-client.tsmodules fromserver.ts. - RF-4 — reliability behavior: graceful shutdown reaps FFmpeg and system capture on SIGTERM/SIGINT; add readiness checks, in-band SSE errors, and heartbeats.
- RF-5 — client: normalize transcript state with
segmentsByIdandsegmentIds, use atomic selectors, keep audio levels outside global state, and add a discriminated state machine. - RF-6 — client: place an error boundary around the transcript while keeping recording controls outside it; add
onUncaughtErrortocreateRoot. - RF-7 — safety net: characterize pure TypeScript/Python functions and enforce no cycles plus shared-leaf boundaries with dependency-cruiser.
A large rewrite of either main file; universal hexagonal layers; XState; full event sourcing/CQRS; a generic supervision framework; adopting the Vercel AI SDK; TanStack Query for SSE; React Actions/useOptimistic/use; ts-rest; Zod-to-Valibot migration; Turborepo/Nx; Zod-to-Pydantic code generation; URL-as-state/i18n; universal branded types; RSC/Next caching.
Use bunx tsc --noEmit for client/server, bun test for pure TypeScript logic, Python self-tests, doctor.py, alternate-port boot smoke tests, and bunx depcruise. Junior validates live capture and stopping with the physical microphone.