uttrflow / uttrflow/uttrflow-swift
Whitespace before an alias slash bypasses duplicate-name validation
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 3h 32m
- Merged PRs (30d)
- 277
Description
## Problem
`PanelAlias.handle` removes leading slashes before removing whitespace. With a space before the slash, `" /PG Prod"` becomes `"/pgprod"`, whereas normalizing that result a second time yields `"pgprod"`. The normalization is not idempotent.
`propose` compares the newly corrected string with normalized existing aliases. An existing `pgprod` therefore does not conflict with a new ` /PG Prod`, even though search later normalizes both to the same exact alias.
## Verified reproduction
On unmodified main `8d93f5b8574f3c7b8c30086d9c817bf7f5d4827d`:
1. Have one clip with alias `pgprod` and a second unnamed clip.
2. Open the second clip's naming sheet and enter ` /PG Prod` (one space before the slash).
3. `PanelAlias.propose` returns corrected `/pgprod`, no holder, and a usable proposal. Applying `.alias`, `.draft`, `.return` produces `.setAlias` instead of retaining the conflict sheet.
4. Pass that exact change to the production `ClipboardStore.setAlias`. The store returns persisted aliases `["/pgprod", "pgprod"]`.
5. Search for `pgprod` through `PanelSnapshot.results`: both clips have `isExactAlias == true`.
The store probe used a temporary folder with the real store and panel reducer; it did not mutate user data or automate the UI. Five direct assertions failed (normal form, conflict, blocked commit, unique exact match, idempotence), and a separate store-backed assertion failed with two exact matches. All 73 selected existing naming/sheet/keyboard/selection tests passed.
## Impact
A name intended to identify one clip can identify two. Return then chooses according to normal ranking/copy order, rather than the unique alias the naming sheet promises. This is ordinary typed or pasted whitespace, not a malformed persisted file.
## Code and acceptance checks
- `Sources/UttrflowUX/PanelAlias.swift:29-45`: strip whitespace and leading slash conventions in an order that produces a stable handle, and compare the same stable form on both sides of conflict validation.
- `Sources/UttrflowUX/PanelChange.swift`: naming-sheet commit uses the proposal.
- `Sources/UttrflowUX/PanelResults.swift`: `isAlias` normalizes again during lookup.
- `Sources/Uttrflow/AppDelegate.swift:886-887`: applies the alias change through the store; the store does not independently enforce normalized uniqueness.
Add cases combining leading spaces/tabs with slashes, a normalization-idempotence check, and a store-backed round trip proving that a conflicting name cannot create two exact alias matches. Keep existing slash-only and whitespace-only spelling controls passing.
#725 is about incomplete slash-prefixed searches; #711 is about Unicode search/folding disagreement. Neither covers this duplicate alias created by normalization order.
Contributor guide
Research direction
Start with Sources/UttrflowUX/PanelAlias.swift:29-45, then trace the proposal through PanelChange.swift, PanelResults.swift, and AppDelegate.swift:886-887. Run the existing naming, sheet, keyboard, and selection tests, then add the whitespace/slash, idempotence, and store-backed round-trip cases described in the issue. Done means conflicting normalized aliases are blocked, exact matches remain unique, and existing slash-only and whitespace-only controls still pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100