uttrflow / uttrflow/uttrflow-swift

Expired pipeline stages are recorded as successful because timeout validation happens outside measurement

Open
#782 0 comments 0 reactions 0 assignees View on GitHub
area:dictation bug P2
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## Problem

The pipeline measures a call to `withStageTimeout`, then checks the returned optional outside the measurement closure. A timeout returns `nil` without throwing, so `MetricsRecording.measuring` records `succeeded: true`. The subsequent guard reports a stage failure, but its measurement already claims success. `StageLatency.failures` consequently excludes these timeouts.

This is an observability defect, not evidence that a timeout fails to stop the pipeline. It makes failure counts unreliable for the hung stages those counts need to distinguish.

## Reproduction

Using the unchanged `StageTally`, `ManualClock` and timeout helper in an isolated Swift test:

1. Measure `.transcription` with a closure calling `withStageTimeout(.seconds(120))`.
2. Park the work behind an explicit continuation and advance the clock once a sleeper is installed.
3. Await the returned value, then release the parked work so the test leaks no continuation.

Observed: returned value `nil`, measurement `succeeded == true`, `StageLatency.summarise(...).failures == 0`. This reproduces the exact nesting used by `DictationPipeline.transcribe`. Its nil guard throws after measurement, and the failure path reports the tally to the external recorder. Transformation and insertion also use this nesting.

## Acceptance criteria

- Validate timeout outcomes inside the measured stage, or record an explicit timeout outcome that failure summaries count correctly.
- Cover transcription and insertion timeouts and the transformation fallback: a stage that expired must not be recorded as having completed successfully even when dictation can continue with raw text.
- Keep ordinary successful, thrown-error and multi-piece aggregate counts correct. Use a manual clock and bounded test synchronization.

## Existing work checked

#732 asks for insertion timeout behavior and transcript recovery coverage; it does not address measurement success flags. #344 concerns drain duration accounting. This issue concerns the failure outcome attached to a measurement, rather than its duration.

## Source

Reviewed main at `8d93f5b8574f3c7b8c30086d9c817bf7f5d4827d`.

- [Sources/UttrflowCore/Support/Metrics.swift:63](https://github.com/uttrflow/uttrflow-swift/blob/8d93f5b8574f3c7b8c30086d9c817bf7f5d4827d/Sources/UttrflowCore/Support/Metrics.swift#L63)
- [Sources/UttrflowPipeline/DictationPipeline.swift:581](https://github.com/uttrflow/uttrflow-swift/blob/8d93f5b8574f3c7b8c30086d9c817bf7f5d4827d/Sources/UttrflowPipeline/DictationPipeline.swift#L581)
- [Sources/UttrflowPipeline/DictationPipeline.swift:597](https://github.com/uttrflow/uttrflow-swift/blob/8d93f5b8574f3c7b8c30086d9c817bf7f5d4827d/Sources/UttrflowPipeline/DictationPipeline.swift#L597)
- [Sources/UttrflowPipeline/DictationPipeline.swift:507](https://github.com/uttrflow/uttrflow-swift/blob/8d93f5b8574f3c7b8c30086d9c817bf7f5d4827d/Sources/UttrflowPipeline/DictationPipeline.swift#L507)
- [Sources/UttrflowCore/Support/Metrics.swift:148](https://github.com/uttrflow/uttrflow-swift/blob/8d93f5b8574f3c7b8c30086d9c817bf7f5d4827d/Sources/UttrflowCore/Support/Metrics.swift#L148)

Contributor guide

Open the contributing guide

Research direction

Start with Metrics.swift at lines 63 and 148, then trace the measurement nesting in DictationPipeline.swift at lines 507, 581, and 597. Use the stated StageTally, ManualClock, timeout helper, and bounded synchronization to cover transcription, insertion, and transformation fallback. Done means timeout measurements are failures while ordinary successes, thrown errors, and multi-piece aggregates remain correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
observability, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
64/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.