Skip to content

Gitmoji subject split mid-emoji, with a second type injected into the gap #7

Description

@kud

Generating a refactor commit in gitmoji style produced a subject with the emoji split in half and a second type wedged into the gap.

What it generated

♻ chore: ️ refactor(claude-code): use shui for hook adoption prompts

Codepoints, in order:

U+267B ♻ RECYCLING SYMBOL — the base codepoint, alone
chore: an injected type that was never asked for
U+FE0F the orphaned variation selector, now attached to nothing
refactor(claude-code): … the real type and summary

So ♻️ (U+267B U+FE0F) was emitted as two pieces with chore: inserted between them.

Why it is worse than a cosmetic glitch

The subject now contains two conventional-commit types. Any downstream tooling that reads the type — a changelog generator, a semver bump, a lint rule, or a glyph-mapping pass — reads chore and acts on it, while a human reads refactor.

In my setup a wrapper asserts a closed type→gitmoji mapping after each commit. It parsed chore, decided the glyph was wrong, and "corrected" it:

🧹 chore: ️ refactor(claude-code): use shui for hook adoption prompts

Which is worse than what it started with, because it now looks deliberate. A visibly wrong glyph gets amended; a plausible wrong glyph never gets looked at again.

Reproduction

Not reliably reproducible on demand — it has happened once, on a staged diff of ~33 insertions across two files, with --style gitmoji. Recorded here because the reflog preserves the pre-amend subject as direct evidence:

HEAD@{1} commit: ♻ chore: ️ refactor(claude-code): use shui for hook adoption prompts

The chore: prefix appearing at all is the second half of the bug — nothing in the diff suggested a chore, and the model clearly also produced refactor(claude-code), so something concatenated two candidate subjects rather than choosing one.

Suggested fix

Validate the generated subject before returning it. It should match ^<single-emoji> <type>(<scope>)?: <summary>$ with exactly one type, and a U+FE0F anywhere past the first grapheme is a reliable tell that an emoji was split. Regenerate or fail loudly rather than emitting it — a malformed commit message is permanent in a way a failed generation is not.

Emoji should also be handled as graphemes rather than codepoints wherever the subject is assembled; splitting on codepoints is what allows an insertion to land between a base character and its variation selector.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions