fix(scripts): validate --number flag against existing branches/specs#2036
fix(scripts): validate --number flag against existing branches/specs#2036fsilvaortiz wants to merge 9 commits intogithub:mainfrom
Conversation
When an AI assistant ignores the prompt instruction to omit --number and passes a conflicting value (e.g. --number 1), the script now detects the collision and auto-detects the next available number instead of silently reusing it. This prevents branch numbering from resetting to 001 — the root cause of github#1744. - Check specs directories and git branches (after fetch) for collisions - Warn on stderr and fall back to auto-detection on conflict - Skip validation when --allow-existing-branch is set (intentional reuse) - Applied symmetrically to both Bash and PowerShell scripts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds defense-in-depth in the feature-creation scripts to prevent branch/spec number collisions when callers manually pass a number, addressing intermittent “reset to 001” behavior when AI assistants ignore guidance and supply --number.
Changes:
- Bash: when
--numberis provided (and--allow-existing-branchis not), detect collisions against existing spec directories and git branches (after fetch) and auto-select the next available number. - PowerShell: implement the same collision validation + auto-detect behavior for
-Number, with-AllowExistingBranchbypass. - Tests: update the existing “no allow-existing” test to assert the new auto-detect-on-collision behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
scripts/bash/create-new-feature.sh |
Validates manually provided --number against existing spec dirs/branches; auto-detects next number on collision. |
scripts/powershell/create-new-feature.ps1 |
Mirrors the same manual number collision validation and auto-detect logic for PowerShell users. |
tests/test_timestamp_branches.py |
Updates the relevant regression test to reflect the new collision-handling behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback. If not applicable, please explain why
Addresses Copilot review comment — verifies the PowerShell script contains the collision detection logic (manualNumPadded, git fetch, warning message, AllowExistingBranch bypass). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Addressed Copilot suggestion in e602275. Added a static guard test ( |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…rtion - Bash: reject non-numeric --number with clear error before arithmetic - PowerShell: reject negative -Number values (< 1) with clear error - Test: use regex for elseif assertion to tolerate whitespace changes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Bash: reject non-numeric and zero --number before if/elif (fixes crash with --allow-existing-branch + non-numeric --number) - PowerShell: reject negative -Number before if/elseif (same issue) - Ensures consistent behavior: 0 is rejected in Bash (PS already treats 0 as auto-detect) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reject --number 0, non-numeric, and negative values - Detect collision via specs directory (not just branches) - Accept unused --number as-is - Static guard: PS script rejects negative -Number Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mnriem
left a comment
There was a problem hiding this comment.
One more small thing according to Copilot
…ault
Addresses Copilot review — previously -Number 0 silently fell through
to auto-detect. Now uses $PSBoundParameters.ContainsKey('Number') to
reject explicitly passed values < 1, matching Bash behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@fsilvaortiz So more Copilot feedback to address |
Avoids double fetch when collision is detected — check_existing_branches already fetches internally during auto-detect fallback. Matches the PowerShell script change from previous commit. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Addressed the double-fetch comments in 135163b (bash) and a8e710e (PowerShell): removed |
Matches bash change from 135163b — the collision check now uses git branch -a with available refs. If a collision triggers auto-detect, Get-NextBranchNumber fetches internally. Updates static guard to match. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- grep -Eq instead of grep -q with non-POSIX \+ (portability fix) - Restore git fetch before collision check in both scripts: correctness over performance — without fetch, remote-only branches are invisible and collisions go undetected Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if [ "$NUMBER_IN_USE" = true ]; then | ||
| >&2 echo "Warning: --number $BRANCH_NUMBER conflicts with existing branch/spec (${MANUAL_NUM_PADDED}-*). Auto-detecting next available number." | ||
| if [ "$HAS_GIT" = true ]; then | ||
| BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR") |
There was a problem hiding this comment.
When a collision is detected, this branch re-calls check_existing_branches, which itself runs git fetch --all --prune. Since the collision check above already fetched and scanned git branch -a, this can cause a redundant second fetch (extra latency / potential network hang) in the exact failure mode this PR is trying to harden. Consider refactoring so the conflict path reuses the already-fetched branch/spec info (or add a way for check_existing_branches to skip fetching when the caller already fetched).
| if [ "$NUMBER_IN_USE" = true ]; then | |
| >&2 echo "Warning: --number $BRANCH_NUMBER conflicts with existing branch/spec (${MANUAL_NUM_PADDED}-*). Auto-detecting next available number." | |
| if [ "$HAS_GIT" = true ]; then | |
| BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR") | |
| compute_next_branch_number_from_cache() { | |
| # Compute the next available branch number using existing specs and an | |
| # already-fetched list of git branches (to avoid a redundant git fetch). | |
| local specs_dir="$1" | |
| local branches_input="$2" | |
| local highest max_num | |
| # Start from the highest number found in the specs directory. | |
| highest=$(get_highest_from_specs "$specs_dir") | |
| max_num="$highest" | |
| # If we have a cached branch list, incorporate it to find the true max. | |
| if [ -n "$branches_input" ]; then | |
| while IFS= read -r branch; do | |
| # Normalize branch name: strip leading markers and remote prefix. | |
| local clean_branch | |
| clean_branch=$(echo "$branch" | sed 's/^[* ]*//; s|^remotes/[^/]*/||') | |
| # Extract numeric prefix (e.g., "012" from "012-something"). | |
| local num_part | |
| num_part=${clean_branch%%-*} | |
| # Ensure prefix is numeric before comparing. | |
| if echo "$num_part" | grep -Eq '^[0-9]+$'; then | |
| local num_value | |
| num_value=$((10#$num_part)) | |
| if [ "$num_value" -gt "$max_num" ]; then | |
| max_num="$num_value" | |
| fi | |
| fi | |
| done <<< "$branches_input" | |
| fi | |
| echo $((max_num + 1)) | |
| } | |
| if [ "$NUMBER_IN_USE" = true ]; then | |
| >&2 echo "Warning: --number $BRANCH_NUMBER conflicts with existing branch/spec (${MANUAL_NUM_PADDED}-*). Auto-detecting next available number." | |
| if [ "$HAS_GIT" = true ]; then | |
| if [ -n "${branches:-}" ]; then | |
| # Reuse the already-fetched branch list to avoid a redundant git fetch. | |
| BRANCH_NUMBER=$(compute_next_branch_number_from_cache "$SPECS_DIR" "$branches") | |
| else | |
| # No cached branches available; fall back to the existing behavior. | |
| BRANCH_NUMBER=$(check_existing_branches "$SPECS_DIR") | |
| fi |
| if ($numberInUse) { | ||
| Write-Warning "-Number $Number conflicts with existing branch/spec ($manualNumPadded-*). Auto-detecting next available number." | ||
| if ($hasGit) { | ||
| $Number = Get-NextBranchNumber -SpecsDir $specsDir | ||
| } else { | ||
| $Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1 |
There was a problem hiding this comment.
In the collision path, the script has already executed git fetch --all --prune (above) to validate $Number, but then calls Get-NextBranchNumber, which performs another git fetch --all --prune. This duplicates network work and can add noticeable latency/hangs when the user hits a collision (the scenario this validation is targeting). Consider reusing the already-fetched branch/spec scan results or adding a -SkipFetch option to Get-NextBranchNumber for callers that already fetched.
|
Re: double fetch optimization suggestions (comments on bash line 308 and PS line 260): Acknowledged — the collision-then-auto-detect path does fetch twice. This is intentional and accepted as a trade-off:
The first comment (PS missing fetch) was already addressed in 29302c2. |
Summary
Fixes the intermittent branch numbering reset reported in #1744 (see comment by @echarrod).
PR #1757 fixed the
specify.mdprompt to tell the AI not to pass--number, but AI assistants intermittently ignore that instruction, causing new features to get001instead of the next available number.This PR adds script-level validation as defense in depth:
--numberis passed, the script checks specs directories and git branches (after fetch) for collisions--allow-existing-branchis set (intentional reuse)Test plan
test_without_flag_still_errors→test_without_flag_auto_detects_on_collisionto reflect new behavior--allow-existing-branchbypasses validation correctly🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com