Skip to content

Guard against correctable misspellings in completions (upstream #814 + SwiftLint fix) - #5

Closed
akramj13 wants to merge 6 commits into
mainfrom
claude/pr-814-swift-lint-fixes-6d5c1f
Closed

akramj13 wants to merge 6 commits into
mainfrom
claude/pr-814-swift-lint-fixes-6d5c1f

Conversation

@akramj13

@akramj13 akramj13 commented Sep 4, 2026

Copy link
Copy Markdown
Owner

Summary

Mirror of upstream FuJacob#814 by @BaptisteGarcin plus the fix for the strict SwiftLint gate that was failing there. The guard hides ghost text whose first generated word the native spell checker flags as a correctable typo, and the streaming path holds that word back until its boundary arrives so the spell lookup runs once per generation. The lint fix moves the nested gate switch out of applyStreamedPartial into passesStreamedLeadingWordGate (complexity 11 is over the cap of 10), mirroring the existing handleTypoGate precedent, with no behavior change; four tests pin down the boundary semantics that were easy to misread. Opened on the fork so CI can validate the combined branch; the two fix commits alone live on claude/pr-814-fix-only for pushing to the contributor's branch.

Validation

swiftlint --strict --quiet            # SwiftLint 0.65.0, same as CI
# exit 0

xcodebuild test -project Cotabby.xcodeproj -scheme Cotabby -destination 'platform=macOS' \
  -skip-testing:CotabbyTests/FoundationModelDriftEvalTests CODE_SIGNING_ALLOWED=NO \
  -derivedDataPath build/DerivedData
# ** TEST SUCCEEDED **  1785 tests, 0 failures, 6 skipped (same skips as CI)
  • Llama eval harness (RUN_LLAMA_EVAL, Qwen3.5-0.8B-Base, 117 cases): 11 seam-guard suppressions, all attributable to the pre-existing mid-word rule; the new leading-word rule fired 0 times, so eval scores are unchanged by this branch.
  • Live in Cotabby Dev against a local OpenAI-compatible stub streaming canned text: ecrir plus vite was suppressed with leadingWordMisspelling(word: "ecrir") in 5 of 5 generations; with hello there friend the streamed session became acceptable only once the second chunk completed the word "hello", and Tab pressed mid-stream accepted it (Tab-accepted-chunk). Also exercised with the real llama model in TextEdit: suggestion shown, typed through, and accepted.

Linked issues

Refs FuJacob#814, Refs FuJacob#811 (upstream context).

Risk / rollout notes

  • The streaming path now performs one NSSpellChecker lookup per generation on the main actor: about 0.1 ms when the first word is known, about 9 ms when it is not (the guesses call), and the final apply repeats it with no shared memo.
  • The first render of a lowercase first word is deferred until its boundary token arrives; a completion that is a single lowercase word never streams and only shows as the final result.
  • "Has a correction" is a weaker typo signal than it sounds. On a stock en_CA automatic checker, lowercase changelog, webhook, hotfix, iterable, hashable, swiftlint, swiftui, openai, gguf, and cotabby are all correctable and would be suppressed as a first generated word; capitalized forms are exempt. Worth watching the leadingWordMisspelling suppression metric after rollout.

🤖 Generated with Claude Code

BaptisteGarcin and others added 6 commits August 17, 2026 19:47
The nested leading-word gate switch pushed applyStreamedPartial to a
cyclomatic complexity of 11, failing the strict lint gate. Move the gate
into passesStreamedLeadingWordGate, mirroring how handleTypoGate keeps
generateFromCurrentFocus within budget. Behavior is unchanged: a pending
gate consults the seam guard once, a settled gate answers without another
spell lookup.

Also fix the CompletionSeamGuard header, which still said "Both rules"
after the leading-word rule made three.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Cover the cases that were easy to misread while reviewing the guard: the
final verdict suppresses a correctable last word with no trailing boundary
(only the streamed verdict waits for one), a connector continuing the
caret word stays in the mid-word rule, hyphenated tokens are assessed
whole, and words under four letters skip the lookup entirely.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@akramj13 akramj13 self-assigned this Sep 4, 2026
@akramj13
akramj13 marked this pull request as ready for review September 4, 2026 01:58
@akramj13 akramj13 closed this Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants