What to build
在 PhemeMurmurCore 中建立 RecordingCoordinator — 從 AppDelegate 抽取錄音→轉錄→貼上的狀態機邏輯,放到一個 deep module 中,擁有小 interface、大 implementation。
需要定義的型別和 protocol:
值型別(Core):
RecordingState enum:.idle、.recording、.transcribing
AudioStopResult enum:.success(URL)、.noAudio、.tooShort(Double)、.tooQuiet(Double)
SkipReason enum:對應 noAudio、tooShort、tooQuiet 的原因
Seam protocol(Core):
AudioRecording: Sendable — startRecording() throws、stopRecording() -> AudioStopResult、var isRecording: Bool { get }
TextPasting: Sendable — pasteText(_ text: String)
RecordingCoordinatorDelegate: AnyObject — coordinatorDidChangeState(_:)、coordinatorDidProduceText(_:)、coordinatorDidFail(_: Error, context: String)、coordinatorDidSkipSilence()、coordinatorDidSkipRecording(_: SkipReason)
RecordingCoordinator class(Core):
init(recorder: AudioRecording, paster: TextPasting, delegate: RecordingCoordinatorDelegate?)
- 可變屬性:
provider: TranscriptionProvider?、promptTemplate: PromptTemplate?、voiceCommandsEnabled: Bool、prefix: String?
- 操作:
toggle()、cancel()
- 唯讀:
private(set) var state: RecordingState
Coordinator 擁有的邏輯(從 AppDelegate 移植):
toggle() 根據 state 分派 start / stop
cancel() 停止錄音、清理暫存檔、回到 idle
- 停止後驅動 provider.transcribe()、VoiceCommandProcessor、prefix 拼接、TextPasting
__SILENCE__ 偵測
ErrorLog.append 記錄錯誤
- 暫存檔清理
測試(用 mock):
- MockAudioRecording、MockTextPasting、MockTranscriptionProvider、MockRecordingCoordinatorDelegate
- 驗證完整狀態機:idle→recording→transcribing→idle
- 驗證取消流程:recording→idle
- 驗證跳過情境:tooShort、tooQuiet、noAudio
- 驗證 silence 偵測(
__SILENCE__)
- 驗證 VoiceCommandProcessor 整合
- 驗證 prefix 拼接
- 驗證 provider 失敗時的 delegate 通知
- 驗證 transcribing 狀態下 toggle 被忽略
Acceptance criteria
Blocked by
None - can start immediately
What to build
在
PhemeMurmurCore中建立RecordingCoordinator— 從 AppDelegate 抽取錄音→轉錄→貼上的狀態機邏輯,放到一個 deep module 中,擁有小 interface、大 implementation。需要定義的型別和 protocol:
值型別(Core):
RecordingStateenum:.idle、.recording、.transcribingAudioStopResultenum:.success(URL)、.noAudio、.tooShort(Double)、.tooQuiet(Double)SkipReasonenum:對應noAudio、tooShort、tooQuiet的原因Seam protocol(Core):
AudioRecording: Sendable—startRecording() throws、stopRecording() -> AudioStopResult、var isRecording: Bool { get }TextPasting: Sendable—pasteText(_ text: String)RecordingCoordinatorDelegate: AnyObject—coordinatorDidChangeState(_:)、coordinatorDidProduceText(_:)、coordinatorDidFail(_: Error, context: String)、coordinatorDidSkipSilence()、coordinatorDidSkipRecording(_: SkipReason)RecordingCoordinator class(Core):
init(recorder: AudioRecording, paster: TextPasting, delegate: RecordingCoordinatorDelegate?)provider: TranscriptionProvider?、promptTemplate: PromptTemplate?、voiceCommandsEnabled: Bool、prefix: String?toggle()、cancel()private(set) var state: RecordingStateCoordinator 擁有的邏輯(從 AppDelegate 移植):
toggle()根據 state 分派 start / stopcancel()停止錄音、清理暫存檔、回到 idle__SILENCE__偵測ErrorLog.append記錄錯誤測試(用 mock):
__SILENCE__)Acceptance criteria
RecordingCoordinator和所有相關型別定義在PhemeMurmurCoretargetAudioRecording、TextPastingprotocol 各有明確的 seam,為後續 adapter 做準備RecordingCoordinatorDelegate涵蓋所有 UI 需要回應的事件swift test通過Blocked by
None - can start immediately