Skip to content

Branch-name unsafe-character handling silently skips merge checks (e.g. '+' in title) #3483

@mabry1985

Description

@mabry1985

Observed (in protoagent app, 2026-04-19)

A seed script generated a feature with a + character in its title, which produced the branch name feature/skill-index-+-retrieval-injection. The git workflow then emitted "Branch name contains unsafe characters" warnings and silently skipped the external merge checks — a quiet correctness bug, not just cosmetic.

Recovery: rename the branch to feature/skill-index-retrieval-injection (drop the +).

Why this is severity-worthy

Skipping merge checks because a branch has unsafe characters is exactly backwards. The right responses, in order of preference:

  1. Refuse to create the branch in the first place (slugification should strip + and other unsafe chars at name-generation time)
  2. Hard-fail the merge gate when an unsafe-char branch reaches the check, not silently skip — silent skip means the operator never knows their PR went out unchecked

Today neither happens: the slug carries + through, and the gate is bypassed.

Suggested fix

  1. Slugification at branch generation: in whatever produces branch names from feature titles (generateBranchName() or equivalent), strip +, &, #, ?, :, and any other character outside [a-z0-9./-] at slug time. Don't rely on downstream consumers to handle it. (Related: feature 4buhlnzsp on this app's board — branch names also leak prompt fragments. Probably the same code path needs hardening end-to-end.)
  2. Gate behavior: in the unsafe-char detection path, change "warn and skip" to "fail loudly and refuse the merge gate." Better to block a PR than to merge it unverified.

Files to investigate

  • libs/git-utils/src/ — branch name generation (probably generateBranchName())
  • Whatever git workflow service emits the "Branch name contains unsafe characters" warning
  • The merge-check pipeline that consumes that warning and decides to skip

Source

Operator note 2026-04-19, protoagent — seed script title skill index + retrieval injection produced the broken branch. Renamed manually to recover.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions