uttrflow / uttrflow/uttrflow-swift

A snippet is skipped whenever its expansion appears inside any word of the dictation: "Ops" is switched off by "stopsign"

Open Beginner friendly
#716 0 comments 0 reactions 0 assignees View on GitHub
area:dictation bug good first issue P2
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.