uttrflow / uttrflow/uttrflow-swift
A snippet is skipped whenever its expansion appears inside any word of the dictation: "Ops" is switched off by "stopsign"
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
## What happens
`SnippetExpander.expand` skips a snippet when the dictation already "quotes" its expansion (`Sources/UttrflowAI/SnippetExpander.swift:26-27`):
```swift
let spoken = TextTidy.collapseWhitespace(transcript).lowercased()
let eligible = candidates.filter { !spoken.contains($0.quoted) }
```
`contains` is a plain substring test, so an expansion found inside any other word switches the snippet off for that whole dictation. The trigger matching next to it is careful about word boundaries (`fits`, `:66-92`); this check is not.
Measured with a throwaway test in `UttrflowAITests`:
| Snippet | Dictation | Expected | Actual |
|---|---|---|---|
| `my team` → `Ops` | `Ask my team about the rollout.` | `Ask Ops about the rollout.` | `Ask Ops about the rollout.` |
| `my team` → `Ops` | `Ask my team about the stopsign rollout.` | `Ask Ops about the stopsign rollout.` | unchanged (`stopsign` contains `ops`) |
| `sig` → `Best` | `That is the bestseller, sig` | `That is the bestseller, Best` | unchanged (`bestseller` contains `best`) |
## Why it matters
Short expansions (a team handle, initials, a short code) are common, and they are the ones most likely to sit inside an ordinary word. The snippet then fails without any sign, in some dictations and not others, which is hard for anyone to work out.
## How to reproduce
Add to `Tests/UttrflowAITests/SnippetExpanderTests.swift`:
```swift
let expander = SnippetExpander(snippets: [makeSnippet(trigger: "my team", expansion: "Ops")])
#expect(expander.expand("Ask my team about the stopsign rollout.").text
== "Ask Ops about the stopsign rollout.")
```
## Acceptance criteria
- The quoting check matches the expansion only on word boundaries (letters or digits must not continue it on either side), so it still holds back `My address is , as you know.` and the case- and spacing-insensitive cases in `quotingIsRecognisedLoosely`.
- The two rows above expand; the existing quoting tests still pass.
## Where to start
- `Sources/UttrflowAI/SnippetExpander.swift:20-56`; `Surroundings.repeats` in `Sources/UttrflowContext/Surroundings.swift` already has a whole-word substring check that shows the shape.
- Tests: `Tests/UttrflowAITests/SnippetExpanderTests.swift` (the "Never expanding what the user is quoting" section).
- Run `make verify` (export `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer` first) and read CONTRIBUTING.md.
**Size:** S, about an hour.
Contributor guide
Research direction
Start in Sources/UttrflowAI/SnippetExpander.swift:20-56, comparing the quoting check with Surroundings.repeats in Sources/UttrflowContext/Surroundings.swift. Add the regression to Tests/UttrflowAITests/SnippetExpanderTests.swift and run make verify after setting DEVELOPER_DIR. Done means expansions inside larger words no longer suppress snippets, while existing quoting tests still pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, swift
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- Under an hour
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 92/100