uttrflow / uttrflow/uttrflow-swift
Nothing in the app ever deletes what AI suggestions learned: Reset, "Forget what it learned here" and turning an app off all leave the typed lines on disk
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
## What happens
AI suggestions stores the lines a person finishes typing in other apps in `predict.v1.sqlite` (`PredictStore`, `Sources/UttrflowPredictStore/PredictStore.swift:28-30`). The store can forget one entry, one app or everything (`PredictStore.swift:295-311`), but nothing in the app calls any of these methods.
- **Reset personalisation** runs `.everything`, whose targets include `.everySuggestion` (`Sources/UttrflowUX/SettingsReset.swift:41`). That target runs `try await suggestions?.forgetEverySuggestion()` (`:220`).
- The settings window builds its store as `FilePersonalisationStore(dictionary: dictionary, history: history, clipboard: clipboard, met: …)` with no `suggestions:` argument (`Sources/Uttrflow/AppDelegate.swift:185-187`). The argument defaults to `nil` (`SettingsReset.swift:169`), and nothing in `Sources/` conforms to `SuggestionCorpus` (`SettingsReset.swift:135`). Only a test fake does (`Tests/UttrflowUXTests/SettingsSuggestionsTests.swift:42`).
- As a result, the optional chain is a silent no-op, and the reset reports success.
- Because the corpus is `nil`, `learnedSuggestions()` is never asked, so every app's learned count is 0 (`SettingsReset.swift:187`). The per-app **Forget what it learned here** row appears only when that count is above 0 (`Sources/UttrflowUX/SettingsPresenter.swift:485`), so it is never shown.
- Turning suggestions off for an app only records `.declined` in the consent file (`Sources/Uttrflow/Suggestion/SuggestionCoordinator.swift:132-139`). Later capture is refused, but nothing already learned is deleted. Turning the whole feature off (`stop()`, `:159`) deletes nothing either.
- `predict-consent.v1.json`, which lists every application the loop has met (`Sources/UttrflowPredictCapture/CapturePreferences.swift:74-75`), is never removed by any reset.
`Docs/predict.md:377` says "Forgetting works at three sizes: one entry, one application, everything". `Docs/predict-context.md:150` says `forget(bundleIdentifier:)` "already removes them".
## Why it matters
The store holds lines typed in every app where suggestions ran: messages, form fields, search queries, commands. A person who resets the app before selling or lending the Mac, or who switches an app off because it was sensitive, is told the data is gone, and it is not. This is the one store of typed text the app keeps, and the only one where deletion does not work at all.
## How to reproduce
1. Turn AI suggestions on and type and commit a few lines in any text field (for example, press Return in a notes app).
2. Settings → Reset personalisation → Reset.
3. `sqlite3 ~/Library/Application\ Support/Uttrflow/predict.v1.sqlite 'select count(*) from entry'` still reports the rows.
Or, without the app: `FilePersonalisationStore` as constructed in `AppDelegate` has no corpus, so `carryOut(.everything)` cannot reach the store.
## Acceptance criteria
- A real `SuggestionCorpus` backed by `PredictStore` is passed to `FilePersonalisationStore`. It must work when suggestions are switched off and the coordinator does not exist (open the store on demand, or delete the files).
- Reset personalisation removes every entry and surface, and the consent file.
- "Forget what it learned here" appears for an app with learned lines and removes only that app's rows.
- Decide, and document in `Docs/predict.md`, whether switching an app off also forgets it (or offers to).
- Tests in `Tests/UttrflowUXTests` or the app-target tests show that a reset through the store the app actually builds leaves `entryCount() == 0`.
- The deleted text does not survive in the `-wal` file (#642).
Contributor guide
Research direction
Start with PredictStore.swift:28-30 and :295-311, then trace the store construction in AppDelegate.swift:185-187 through SettingsReset.swift. Run the existing SettingsSuggestionsTests.swift and inspect SuggestionCoordinator.swift:132-139 and :159, plus the cited prediction docs. Done means the app’s real reset path removes entries, surfaces, consent data, and WAL contents, while per-app forgetting behaves as documented and tests show entryCount() == 0.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, sqlite, swift
- Domain
- database, desktop, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 58/100