Skip to content

[Bug]: Non-Latin feature descriptions produce a nameless branch/directory (001-, 004-, ...) #4574

Closed

Description

@weizeng-alt

What happened

A feature description written entirely in a non-Latin script produces a branch and directory with no name at all — just the number and a trailing dash. Every such feature looks identical apart from its number.

specify init demo --integration claude

./.specify/scripts/powershell/create-new-feature.ps1 -Json "给倒推引擎加正推能力"
# {"BRANCH_NAME":"001-", ... "specs\\001-\\spec.md"}

./.specify/scripts/powershell/create-new-feature.ps1 -Json "客户邮件审核队列"
# {"BRANCH_NAME":"004-", ... "specs\\004-\\spec.md"}

Resulting tree — two unrelated features, indistinguishable:

specs/
├── 001-/
├── 004-/
└── 005-mail-review-queue/   # same description, but with -ShortName

For comparison, on the same install:

Description BRANCH_NAME
给倒推引擎加正推能力 001-
add forward scheduling engine 002-forward-scheduling-engine
forward 正推 engine 003-forward-engine (Latin words kept, rest dropped)

Why this is not the already-known crash

Get-BranchName in create-new-feature.ps1 already carries a comment describing this path — a previous fix stopped it throwing ArgumentNullException and made it return an empty suffix instead, matching the bash and Python twins. That fix is correct as far as it goes: the script no longer dies.

But the outcome it settles on is a directory name that carries no information. The empty suffix is a reasonable internal result; it just isn't a usable name. For a team working in Chinese, Japanese, Korean, Arabic, Hebrew, Thai, Greek, or Cyrillic, this is the default path, not an edge case — every feature they create lands in NNN-.

The root cause is the character class, in two places:

# line 89
$Name.ToLower() -replace '[^a-z0-9]', '-' ...
# line 136
$Description.ToLower() -replace '[^a-z0-9\s]', ' '

Both drop every non-ASCII character, so a CJK description reduces to the empty string before stop-word filtering ever runs.

Suggested directions

Listed roughly by cost; any one of them removes the nameless directory.

  1. Warn and point at the escape hatch. -ShortName already works (005-mail-review-queue above). When the computed suffix is empty, print a line saying the description produced no usable branch name and that -ShortName <name> sets one. Cheapest fix, and it turns a silent surprise into a choice.
  2. Fall back to something stable instead of nothing. A short hash or timestamp of the description — 001-f3a9c2, 001-20260914 — is still opaque, but at least distinct per feature.
  3. Widen the character class. Keep Unicode letters and digits (\p{L}\p{N}) and percent-encode or transliterate what git cannot take. Git branch names do accept UTF-8, so 001-客户邮件审核队列 is a legal ref; whether it is desirable is a separate call, and tooling downstream may not all agree.

(1) alone would have saved the confusion here. (3) is the real fix but needs a decision about non-ASCII refs that is yours to make, not mine.

Environment

  • specify-cli 1.0.7.dev0 (git d848fb4), installed via uv tool install
  • Windows 11, PowerShell 5.1, Python 3.13.7, git 2.49.0.windows.1
  • --script auto-selected powershell

Not PowerShell-specific — reproduced on both script backends:

specify init demo-sh --integration claude --script sh
bash .specify/scripts/bash/create-new-feature.sh --json "给倒推引擎加正推能力"
# {"BRANCH_NAME":"001-", ... "specs/001-/spec.md"}

Activity

  1. github-actions commented on Sep 15, 2026

    @github-actions
    Contributor

    Bug assessment — non-latin-feature-names: Valid · severity low


    Bug Assessment: Non-Latin feature descriptions produce nameless branches and directories

    Report (summarized)

    The reporter observes that descriptions written entirely in non-Latin scripts, such as 给倒推引擎加正推能力 and 客户邮件审核队列, produce 001-/004- branch names and specs/001-//specs/004-/ directories. Latin descriptions retain a useful suffix, while mixed descriptions retain only their Latin words. The behavior is reported for both the PowerShell and Bash script backends on Windows 11 and is distinguished from an earlier PowerShell crash fix: the scripts now complete, but the resulting name is not useful.

    No additional comments were present on the issue.

    Symptom

    The feature-number prefix is created successfully, but the generated suffix is empty when the description contains no ASCII letters or digits, so unrelated features can receive indistinguishable names apart from their numeric prefix. The expected behavior is either a usable, stable identifier or an explicit warning/required choice rather than a silent nameless suffix.

    Reproduction

    1. Initialize a project with the Claude integration and run the PowerShell workflow with a non-Latin-only description, for example create-new-feature.ps1 -Json "给倒推引擎加正推能力".
    2. Observe BRANCH_NAME equal to 001- and the corresponding specs/001-/spec.md path.
    3. Run the Bash equivalent with create-new-feature.sh --json "给倒推引擎加正推能力".
    4. Observe the same empty suffix (001-).

    The issue report states that the behavior is also present for other non-Latin scripts, including Japanese, Korean, Arabic, Hebrew, Thai, Greek, and Cyrillic; those additional scripts were not independently exercised here.

    Suspected Code Paths

    • scripts/powershell/create-new-feature.ps1:86-89 — ConvertTo-CleanBranchName lowercases the value and replaces every character outside [a-z0-9] with -, so a non-Latin-only value cleans to an empty string after separator trimming.
    • scripts/powershell/create-new-feature.ps1:123-136 — Get-BranchName extracts words using [^a-z0-9\s]; descriptions without ASCII words therefore reach the empty fallback.
    • scripts/powershell/create-new-feature.ps1:285-290 — the computed suffix is concatenated into ${featureNum}-${branchSuffix}, producing the trailing-dash name that is then used for featureDir.
    • scripts/bash/create-new-feature.sh:156-159 — clean_branch_name has the equivalent ASCII-only filtering.
    • scripts/bash/create-new-feature.sh:206-217 — generate_branch_name removes non-ASCII characters before word selection and falls back to the empty cleaned value.
    • scripts/bash/create-new-feature.sh:365-366 — the suffix is concatenated into the final branch name and feature directory path.
    • scripts/python/create_new_feature.py:168-175 — the Python twin uses the same ASCII-only regular expressions. Existing parity coverage in tests/test_create_new_feature_python_parity.py:1218-1240 explicitly treats an empty suffix (001-) as the cross-variant behavior, so changing the policy requires updating that contract test.
    • tests/test_create_new_feature_python_parity.py:1218-1240 — verifies that punctuation-only and non-Latin descriptions do not crash and currently expects 001-; it does not assert that the result is a useful identifier.

    Root Cause Hypothesis

    Confidence: high. All three core implementations intentionally restrict automatic slug generation to ASCII letters and digits. When stop-word filtering finds no usable ASCII words, the fallback applies the same restriction, leaving an empty suffix; the final naming code unconditionally inserts the numeric prefix and separator. The earlier PowerShell fix removed the exception but preserved the empty-name outcome for parity.

    Proposed Remediation

    Preferred: Define and enforce a non-empty fallback policy in the shared behavior of all three core script variants. The least disruptive option is to detect an empty generated suffix and fail with a clear message directing the user to --short-name/-ShortName; this prevents creation of ambiguous directories and avoids silently changing branch naming policy. The detection should happen before final directory creation and should have equivalent JSON/error behavior across Bash, PowerShell, and Python.

    If the project wants fully automatic support, a second preferred-policy decision is needed: either preserve Unicode letters/digits in branch names or generate a deterministic ASCII fallback (for example, a short hash). Unicode preservation is more descriptive but has compatibility implications for downstream tooling; a hash is portable but opaque. Whichever policy is selected must be implemented identically across the three script variants.

    Alternatives:

    • Emit a warning and continue with NNN-; this preserves compatibility but does not prevent collisions or confusing directories, so it only improves observability.
    • Add deterministic transliteration for supported scripts; this improves readability but introduces locale/library dependencies and transliteration collisions.

    Files likely to change:

    • scripts/bash/create-new-feature.sh
    • scripts/powershell/create-new-feature.ps1
    • scripts/python/create_new_feature.py
    • tests/test_create_new_feature_python_parity.py
    • Potentially tests/test_timestamp_branches.py and Git extension parity tests if the chosen validation policy is shared with the extension scripts.

    Tests to add or update:

    • Cover Chinese/Japanese/Cyrillic/Arabic-only descriptions and assert the selected fallback or explicit error in Bash, PowerShell, and Python.
    • Cover punctuation-only descriptions separately, since they exercise the same empty-suffix path without involving Unicode letters.
    • Assert that a successful automatic name is non-empty and does not end in a bare separator.
    • Preserve parity assertions across all available script backends and update the current 001- expectation to the chosen contract.
    • If Unicode names are accepted, test filesystem output and branch-name length/encoding handling; if hashes are used, assert determinism and distinct outputs for distinct descriptions.

    Risks & Considerations

    • Changing the output for existing descriptions can affect scripts, automation, and users who rely on exact branch/directory names; retain --short-name behavior and document the new fallback/error.
    • Unicode branch names are valid in Git but may be inconvenient or unsupported by external tools; ASCII fallback avoids that risk at the cost of readability.
    • A non-deterministic timestamp fallback can still make repeated dry runs differ and should not be preferred for ordinary sequential numbering.
    • The three script variants currently have an explicit parity contract, so changing only one backend would create platform-specific behavior.

    Open Questions

    • [NEEDS CLARIFICATION: Should automatic names preserve Unicode characters, generate deterministic ASCII identifiers, or require --short-name when no ASCII slug can be derived?]
    • [NEEDS CLARIFICATION: Should the same policy be applied to the optional extensions/git branch-creation scripts, which contain parallel slug-generation logic?]

    Generated by 🐛 Assess Bug from Labeled Issue for #4574 · copilot · gpt52codex · 2.68 AIC · ⌖ 6.42 AIC · ⊞ 25.5K · ◷

  2. added
    bug-fixTrigger the bug-fix agentic workflow
    on Sep 17, 2026
  3. github-actions commented on Sep 17, 2026

    @github-actions
    Contributor

    The bug assessment for non-latin-feature-names is Likely valid, needs reproduction, but the proposed fix is blocked by unresolved policy questions:

    • Should automatic names preserve Unicode characters, generate deterministic ASCII identifiers, or require --short-name when no ASCII slug can be derived?
    • Should the same policy also apply to the optional extensions/git branch-creation scripts?

    No code change or pull request was made because implementing the fix without those decisions would be guesswork. Please resolve the questions and re-run the assessment/fix stages. The repository does not have a needs-reproduction label, so no status label was added.

    Generated by 🛠️ Fix Bug from Labeled Issue for #4574 · copilot · gpt52codex · 1.29 AIC · ⌖ 7.55 AIC · ⊞ 26.9K · ◷

  4. added
    bug-fixTrigger the bug-fix agentic workflow
    and removed
    bug-fixTrigger the bug-fix agentic workflow
    on Sep 28, 2026
  5. mnriem commented on Sep 28, 2026

    @mnriem
    Collaborator

    Filenames should use UTF-8

  6. github-actions commented on Sep 28, 2026

    @github-actions
    Contributor

    Pull request created: #4780

    Generated by Fix Bug from Labeled Issue · copilot · gpt52codex · 3.45 AIC · ⌖ 7.44 AIC · ⊞ 17K

  7. github-actions commented on Sep 28, 2026

    @github-actions
    Contributor

    Draft PR: main...fix/4574-non-latin-feature-names

    non-latin-feature-names: preserve UTF-8 letters and digits in generated branch and feature directory names across Bash, PowerShell, and Python. Please review the draft PR, then validate the fix through the configured stage-3 bug-test workflow.

    Generated by 🛠️ Fix Bug from Labeled Issue for #4574 · copilot · gpt52codex · 3.45 AIC · ⌖ 7.44 AIC · ⊞ 17K · ◷

  8. github-actions commented on Sep 28, 2026

    @github-actions
    Contributor

    Bug test — non-latin-feature-names: ❌ failing · 5 passed, 2 failed, 0 skipped · fix from PR #4780 (eb4c9dc)


    Bug Test Report: Non-Latin feature descriptions produce nameless branches/directories

    Summary

    The proposed Unicode-preserving behavior passes the newly added cross-backend Unicode tests and the focused PowerShell checks, but the focused subset has two failures in the locale-collation cases. Those failures are caused by assertions expecting the unrelated French word réservation for Spanish and German descriptions; the implementation instead preserves each input description's Unicode words. The complete parity file also fails 21 tests because existing expectations still require the old ASCII-only output.

    Test Results

    Metric Count
    Passed 5
    Failed 2
    Skipped 0
    Errored 0
    Duration 3.04s focused subset; 44.04s full parity file

    Failures (if any)

    • test_bash_branch_name_ignores_locale_collation[spanish] — expected réservation in the branch, received 001-añadir-autenticación-usuario.
    • test_bash_branch_name_ignores_locale_collation[german] — expected réservation in the branch, received 001-prüfung-für-benutzer-anlegen.

    The full parity file run (100 collected) reported 79 passed and 21 failed. Besides the two focused failures, 19 failures retain pre-fix expectations of 001- or ASCII-only sanitization, including test_empty_feature_name_warning and test_all_variants_keep_acronym_next_to_non_ascii.

    Verification vs. Historical Fix

    Not applicable (no historical fix referenced). The issue and proposed PR describe the current fix; no merged historical fix or commit was identified for comparison.

    Notes & Caveats

    • Tests ran in an isolated worktree at the proposed PR head, not the base checkout.
    • The focused subset selected the three tests named by the proposed fix plus their parametrized cases: 7 cases total, 5 passed and 2 failed.
    • Bash, Python, and PowerShell Unicode-only parity cases passed where their required runtimes were available. The full-file failures indicate the test suite has not been fully updated to the new Unicode-preserving contract.
    • No repository source files were modified.

    Generated by 🧪 Test a Bug Fix from a Labeled Issue for #4574 · copilot · gpt52codex · 2.49 AIC · ⌖ 6.69 AIC · ⊞ 17K · ◷

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions