Skip to content

fix: stop check-prerequisites --paths-only from writing feature.json (#3025)#3190

Open
Noor-ul-ain001 wants to merge 3 commits into
github:mainfrom
Noor-ul-ain001:fix/paths-only-no-persist-feature-json
Open

fix: stop check-prerequisites --paths-only from writing feature.json (#3025)#3190
Noor-ul-ain001 wants to merge 3 commits into
github:mainfrom
Noor-ul-ain001:fix/paths-only-no-persist-feature-json

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown

What

check-prerequisites --paths-only (and PowerShell -PathsOnly) is documented as pure, read-only path resolution. But when SPECIFY_FEATURE_DIRECTORY is set, get_feature_paths / Get-FeaturePathsEnv called the persist routine and rewrote .specify/feature.json — dirtying the working tree and overwriting a pinned feature directory during what should be a no-op.

Fixes #3025.

How

Opt out of the write at the resolver boundary with an explicit flag, rather than a global env back-channel (per maintainer feedback on #3053):

  • bash: get_feature_paths accepts a leading --no-persist flag that skips _persist_feature_json; check-prerequisites.sh passes it in --paths-only mode.
  • PowerShell: Get-FeaturePathsEnv gains a -NoPersist switch that skips Save-FeatureJson; check-prerequisites.ps1 passes it in -PathsOnly mode.

Normal (non-paths-only) invocations are unchanged and still persist the override, so future sessions without the env var keep working.

Tests

Added regression tests (bash + PowerShell):

  • --paths-only / -PathsOnly leaves a pinned feature.json untouched even when SPECIFY_FEATURE_DIRECTORY differs from the pinned value, while still honoring the override in the output.
  • Normal mode still persists the override (guards against regressing write behavior).

Notes

This is an alternative to #3053, which originally used a SPECIFY_NO_PERSIST_FEATURE_JSON env var; that approach was flagged in review as a leaky global back-channel. This PR uses explicit local flags/parameters at the call site instead.

…ithub#3025)

check-prerequisites --paths-only / -PathsOnly is documented as pure,
read-only path resolution, but when SPECIFY_FEATURE_DIRECTORY was set it
called the persist routine and rewrote .specify/feature.json. That dirtied
the working tree and overwrote a pinned feature directory during what should
be a no-op.

Add an explicit opt-out at the resolver boundary instead of a global env
back-channel:

- bash: get_feature_paths accepts a leading --no-persist flag that skips
  _persist_feature_json; check-prerequisites.sh passes it in --paths-only mode.
- PowerShell: Get-FeaturePathsEnv gains a -NoPersist switch that skips
  Save-FeatureJson; check-prerequisites.ps1 passes it in -PathsOnly mode.

Normal (non-paths-only) invocations are unchanged and still persist the
override, so future sessions without the env var keep working.

Add regression tests asserting --paths-only/-PathsOnly leaves a pinned
feature.json untouched even when the env override differs, plus a guard that
normal mode still persists.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes unintended side effects during “read-only” path resolution: check-prerequisites --paths-only / -PathsOnly now resolves feature paths without persisting SPECIFY_FEATURE_DIRECTORY into .specify/feature.json, preventing working tree dirtiness and accidental overwrites of pinned feature directories (issue #3025).

Changes:

  • Bash: add get_feature_paths --no-persist opt-out and use it from check-prerequisites.sh --paths-only.
  • PowerShell: add Get-FeaturePathsEnv -NoPersist opt-out and use it from check-prerequisites.ps1 -PathsOnly.
  • Add regression tests ensuring paths-only honors the override in output but does not rewrite .specify/feature.json (bash + PowerShell), and that bash normal mode still persists.
Show a summary per file
File Description
tests/test_check_prerequisites_paths_only.py Adds regression coverage for “paths-only does not write feature.json”, plus a bash “normal mode still persists” guard.
scripts/powershell/common.ps1 Adds -NoPersist switch to skip feature.json persistence for read-only callers.
scripts/powershell/check-prerequisites.ps1 Passes -NoPersist to Get-FeaturePathsEnv when -PathsOnly is used.
scripts/bash/common.sh Adds --no-persist flag handling to get_feature_paths to skip _persist_feature_json.
scripts/bash/check-prerequisites.sh Uses get_feature_paths --no-persist in --paths-only mode.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Low

Comment on lines +167 to +171
# Persist to feature.json so future sessions without the env var still
# work — unless the caller opted out for read-only resolution (#3025).
if (-not $NoPersist) {
Save-FeatureJson -RepoRoot $repoRoot -FeatureDirectory $env:SPECIFY_FEATURE_DIRECTORY
}
The em-dash in the persist comment introduced non-ASCII bytes, failing
test_ps1_file_is_ascii_only which enforces ASCII-only PowerShell sources
for Windows PowerShell 5.1 compatibility.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Low

Comment on lines +348 to +352
@pytest.mark.skipif(not (HAS_PWSH or _WINDOWS_POWERSHELL), reason="no PowerShell available")
def test_ps_paths_only_does_not_persist_feature_json(prereq_repo: Path) -> None:
"""-PathsOnly must not rewrite feature.json even when the env override
differs from the pinned value (#3025)."""
pinned = "specs/001-my-feature"

@mnriem mnriem left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address Copilot feedback

@Noor-ul-ain001 Noor-ul-ain001 requested a review from mnriem June 29, 2026 15:56

@mnriem mnriem left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address Copilot feedback and add the requested test

Addresses Copilot review feedback on github#3190: the bash side had a
`test_normal_mode_still_persists_feature_json` guard, but there was no
symmetric PowerShell test asserting that running check-prerequisites.ps1
*without* -PathsOnly still persists the SPECIFY_FEATURE_DIRECTORY override
into .specify/feature.json.

Add test_ps_normal_mode_still_persists_feature_json, which guards against
accidentally passing -NoPersist unconditionally (or flipping the default)
in a future refactor. Verified it fails when -NoPersist is passed in the
non -PathsOnly branch and passes with the current conditional.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Noor-ul-ain001

Copy link
Copy Markdown
Author

@mnriem All feedback has been incorporated. Commit 2e7e49c adds the
requested test_ps_normal_mode_still_persists_feature_json test to
achieve feature parity with bash coverage. All 4 regression tests are
now in place and comprehensive. Please re-review when available.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Low

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: get_feature_paths persists .specify/feature.json during read-only path resolution (check-prerequisites.sh --paths-only)

3 participants