Working PeachJam proof
These recordings exercise the actual PeachJam composer and browser MediaRecorder. Chromium’s virtual microphone played a public 3.4-second speech WAV; the transcript came from the approved live OpenRouter gateway. The surrounding project data is a deterministic UI fixture, not a production project.
The complete Lovable state graph
Captured against authenticated Lovable on both /dashboard and project chat. “Apply” means use the transcript as draft text; it does not submit the prompt.
Normal composer
Editor, model control, microphone, and send control are visible.
Await permission
Draft remains visible. Normal trailing controls are replaced immediately by Discard and Apply.
Honest waveform
The editor is replaced by analyser-driven bars. Attach/actions remain. Discard and Apply stay visible.
Stop capture
MediaRecorder finalizes the blob. Tracks and AudioContext are released.
Draft restored
Inline “Transcribing...” appears. Discard and Apply are visible but disabled.
Append result
Empty draft becomes transcript. Existing draft gets two newlines, then transcript.
No speech
An empty {text:""} response restores idle without changing the draft or showing an error.
Retryable
Draft remains. Inline failure appears. Controls become Discard recording and Retry transcription.
Return to idle
Helpful GUI message: “Failed to access microphone. Please check permissions.”
Local only
Stops capture, preserves the draft, and sends no transcription request.
Ready to apply
PeachJam stops capture, freezes the waveform, and asks the user to Apply or Discard.
Editable draft
The transcript is still only draft text. Sending remains a separate explicit action.
| Surface | Shared behavior | Measured difference | PeachJam translation |
|---|---|---|---|
| Dashboard | Permission swap, waveform, Discard/Apply, STT response shape | Wider waveform (128 bars at 638 px); 32 px recording controls | Same shared component; bar count comes from measured width |
| Project chat | Same interaction states and exact audio request field | 82 bars at 408 px; 28 px desktop controls | Same state machine; project layout owns the available width |
| Dark theme | Same state transitions | Lighter waveform; light Apply control on dark composer | Named light/dark voice tokens, no blanket primitive restyle |
| Mobile | Same shared state graph | Composer stays bottom-aligned; controls remain touch-sized | Verified with installed iPhone 17 Pro profile |
Implementation boundary
This is deliberately not a general component migration and not a builder-provider payload change.
POST /v1/user/speech-to-text/audio/transcriptionsBrowser → PeachJam
- Authenticated multipart request with one field:
audio. - WebM/Ogg/MP4/MP3/WAV, maximum 4 MiB.
- Audio exists in memory for the request only; PeachJam does not persist it.
- Browser receives only
{text:string}.
PeachJam → provider
- Existing OpenRouter API key and Cloudflare AI Gateway token.
- Multipart fields:
file,model,response_format=json. - Provider errors are typed and upstream bodies are not exposed to users.
- Request outcome, latency, audio seconds, and USD cost are emitted as low-cardinality telemetry.
Limits, credits, and cost
| Concern | Policy | Reason |
|---|---|---|
| Recording duration | 60 seconds client-side | Bounds wait time and cost while covering ordinary prompt dictation. |
| Payload | 4 MiB server-side | Much tighter than OpenRouter’s documented 25 MB maximum. |
| Concurrency | One active transcription per actor | Prevents accidental double-apply and duplicated spend. |
| Rate | 10/minute and 100/rolling 24 hours per actor | Abuse guard without turning ordinary iteration into friction. |
| Build credits | No debit for voice transcription | Voice is an input method. Normal Build credits apply only after explicit prompt submission. |
| Provider billing | Platform operating cost, measured from provider response | The live 3.4-second sample was billed at the provider’s 10-second minimum: $0.000111. |
Known scaling constraint: per-actor rate state is process-local in this first slice. It is correct for the current single API instance; it must move to a shared durable limiter before horizontal API scaling.
Provider references: OpenRouter speech-to-text guide and Groq speech-to-text pricing/limits. The measured 10-second billable duration matches Groq’s documented minimum.
Direct Lovable evidence
No prompt-text assertions: screenshots, DOM/computed-style inspection, live MediaRecorder behavior, request/response bodies, and an intentionally aborted request were used to map observable behavior.






Verification
Passed
- Frontend TypeScript + Vite production build.
- OpenAPI generation into the frontend contract.
- Provider multipart/header/usage/error unit tests.
- Service concurrency and minute/daily limit tests.
- Authenticated HTTP alias, missing audio, and oversize tests.
- Desktop and iPhone 17 Pro browser transitions.
- Live gateway smoke with the same approved model.
Evidence boundary
- The videos use an honest virtual microphone and live transcription, not a hardcoded transcript.
- The demo’s surrounding project/chat API data is a deterministic fixture.
- The direct gateway smoke and backend contract are separately verified.
- No production deployment is claimed by this report until the change lands on
origin/main.