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 into
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. |
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.
| } | ||
|
|
||
| if ($numberInUse) { | ||
| Write-Warning "-Number $Number conflicts with existing branch/spec ($manualNumPadded-*). Auto-detecting next available number." |
There was a problem hiding this comment.
New collision-warning message lacks the [specify] prefix used by other warnings in this script (e.g., -Number ignored with -Timestamp, branch-name truncation). For consistent output and easier grepping, consider including [specify] Warning: here too.
| Write-Warning "-Number $Number conflicts with existing branch/spec ($manualNumPadded-*). Auto-detecting next available number." | |
| Write-Warning "[specify] Warning: -Number $Number conflicts with existing branch/spec ($manualNumPadded-*). Auto-detecting next available number." |
mnriem
left a comment
There was a problem hiding this comment.
Please resolve conflicts
|
This pull request has been automatically marked as stale because it has not had any activity for 150 days. It will be closed in 30 days if no further activity occurs. |
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