Skip to content

[Bug] Mid-word completion inserts an extra space (master tracking issue) #623

@FuJacob

Description

@FuJacob

Summary

Multiple bug reports describe the same defect: when a user starts typing a word and accepts the inline suggestion with Tab, Cotabby inserts the completion with an extra space in the middle of the word (e.g. typing after and accepting afternoon yields after noon). The ghost text renders correctly, but the inserted text does not match what was shown.

What occurred

The model's first token is the boundary signal: it emits a leading space when it intends a new word, and emits none when it intends to continue the current word. Real generations in llm-io.jsonl confirm the model gets this right consistently (e.g. prompt ending ...its hrd to kn produces raw w wht to say..., correctly continuing knknw). The overlay also renders this correctly, so the ghost text reads afternoon.

The defect is at accept time. SuggestionSessionReconciler.insertionChunk Rule 2 (Cotabby/Support/SuggestionSessionReconciler.swift:451) unconditionally inserts a space whenever the live preceding character is a word character and the accepted chunk's first character is a word character:

guard let firstChunkChar = chunk.first, firstChunkChar.isAcceptanceWordCharacter,
      let lastPrecedingChar = precedingText.last, lastPrecedingChar.isAcceptanceWordCharacter
else { return chunk }
return " " + chunk

Its own doc comment admits the gap: "we don't try to distinguish a fresh new word from a partial-word completion." This single accept-time heuristic overrules the model's correct boundary decision and breaks the WYSIWYG invariant (ghost shows afternoon, Tab inserts after noon).

Cause

Cotabby was originally designed to only trigger after the user typed a space, so every completion was treated as a fresh word and accept-time space injection was safe. Users have come to rely on mid-word completions, but the accept-time space-injection rule was never updated. The model's leading-space signal is correct and is preserved through normalization; it is only at the final insertion step that the boundary information is discarded.

Fix

PR #622 makes insertion render-faithful: the model's leading-space signal is treated as part of the first chunk and accept-time space injection is removed, so Tab inserts exactly the ghost text. New-word boundaries (e.g. I went to the | store) remain correct because the model emits the leading space itself, which is now preserved end-to-end.

Fixed by #622.

Related issues

Bug reports:

Feature requests describing the same underlying defect:

Note

Some of the issues linked above (#559, #557, #553, #491, #395) were accidentally closed by me in a triage sweep with a comment claiming they were addressed in 0.5.0-beta. They are not yet fixed in any released build. Those issues have been reopened and the misleading comments removed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions