Version. 0.2 (corrects v0.1's scope — see below) Date. 2026-07-05 Status. Scoped, ready for build brief. Not built. Repos. loomworks-engine, loomworks.
v0.1 assumed this was a metadata-wiring task — attach source_mode/source_file_id to the existing live-dictation assertion. Step-0 found this is wrong on two counts: (1) the browser's Web Speech API (used for live dictation) exposes no raw audio at all — a second, parallel recording mechanism (getUserMedia + MediaRecorder) is required alongside it, which is new capture machinery, not a wiring task; (2) live-dictation and file-upload are two separate code paths that each create their own assertion independently — there is no existing way to attach metadata to an assertion after creation. Confirmed decision: build a store-only upload variant (persists audio, does not transcribe or create its own assertion) and thread its reference through the classifier into the live-dictation assertion-creation call, so one assertion is created with the audio metadata from the start. Rejected alternative: uploading the recording separately after the fact, which would create a second assertion via a redundant Whisper transcription — reintroducing the duplicate-assertion pattern this session's CR-2026-136/141/145 work already eliminated.
Two voice-capture paths exist today, behaving differently. The file-upload path (uploaded audio, transcribed) retains the original audio permanently, viewable via the existing "View source" mechanism. The live-dictation path (browser mic → live transcription → sent as text) keeps only the transcript — no audio, nothing to verify against if the transcription is wrong.
MediaRecorder alongside the existing Web Speech API during live dictation, capturing a real audio Blob for the same session.put_blob + an upload event), does not run transcription, does not create its own assertion._route_add_knowledge), so the one assertion is created carrying source_mode: "voice" and source_file_id from the start — no second assertion, no redundant Whisper call.source_mode: "voice" — confirmed at Step-0 this needs no new UI component: the existing View-source control (opens the source-file URL in a new tab) already produces a native browser audio player for audio content. Only a label change ("Replay" instead of "View source" when source_mode === "voice").The source-file serving route already serves audio correctly for the file-upload path — nothing to change there regardless of this build.
No explicit seed commitment on audio retention. Specification-level. Consistent in spirit with "corrections preserved, not smoothed" — a transcription is an interpretation of the original; without the original, an error in that interpretation can never be verified or corrected against source.
Unifying the two voice-capture mechanisms into one (considered, rejected — nothing about the current two-path split is broken, only incomplete on the live-dictation side). Any change to the file-upload voice path, which already works correctly.