Skip to content

fix(agent-context): skip non-file plan candidates in PowerShell fallback - #5283

Open
sx4im wants to merge 8 commits into
github:mainfrom
sx4im:fix/5282-powershell-plan-candidate-parity
Open

sx4im wants to merge 8 commits into
github:mainfrom
sx4im:fix/5282-powershell-plan-candidate-parity

Conversation

@sx4im

@sx4im sx4im commented Nov 6, 2026

Copy link
Copy Markdown

Fixes #5282

PR #5222 fixed plan-candidate discovery in the bash and Python implementations of the agent-context extension, but the PowerShell twin was left behind. This ports that fix to update-agent-context.ps1.

What broke: the mtime fallback picked the newest specs/**/plan.md with no check on what the candidate actually is. A dangling plan.md symlink, or one pointing through a non-directory, was selected and written into the context file as the current plan.

What changed: link candidates are now probed by opening them, so only links whose target is a readable regular file are kept. Sorting uses the target mtime, like p.stat().st_mtime in the twins. Extension version bumped 1.0.3 to 1.0.4 with the catalog kept in sync.

How verified: new regression test test_powershell_mtime_fallback_selects_only_in_project_files covers regular files, directories, dangling links, non-directory links, directory links, and file links. It fails on main (4 cases) and passes with this change (12/12). Full parity files pass (148 passed, 5 skipped), agent config consistency passes, ruff clean, and the extension version guard passes. The test runs under PowerShell 7.5 on Linux here; Windows PowerShell 5.1 validation is left to CI, since no Windows host is available in this environment.

Two known limits, both from Windows PowerShell 5.1 having no link-target resolution API: a file link is reported at its in-project link path rather than the resolved target path the twins emit, and the escaping-link containment skip from #5222 could not be ported, so that case stays covered by the bash/python test only.

Port the bash/python mtime-fallback fix from github#5222 to the PowerShell
twin: probe each symlinked candidate by opening it, so dangling links,
links to directories, and links through non-directories are skipped,
and sort by the target mtime. Bump agent-context 1.0.3 to 1.0.4.

Fixes github#5282
@sx4im
sx4im requested a review from mnriem as a code owner November 6, 2026 01:43
Copilot AI auto review requested due to automatic review settings November 6, 2026 01:43

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.

🟡 Changes recommended

Plan discovery accepts links outside the project root, allowing the generated agent context to direct agents to files beyond the checkout.

5 open issues
What changed in this PR

Adds link validation to the agent-context extension’s PowerShell plan-discovery fallback, following the Bash/Python fix in #5222 and addressing #5282.

Changes:

  • Probe linked plan.md candidates before selection and update the timestamp sort key.
  • Add 12 regression cases covering regular files, directories, and several link types.
  • Bump the extension and catalog versions from 1.0.3 to 1.0.4.

The PR’s reported regression evidence was reviewed; PowerShell tests were not rerun during this review.

File Description
tests/​extensions/​test_update_agent_context_python_parity.py Adds PowerShell fallback regression cases.
extensions/​catalog.json Updates the catalog version to 1.0.4.
extensions/​agent-context/​scripts/​powershell/​update-agent-context.ps1 Adds link probes and updates fallback sorting.
extensions/​agent-context/​extension.yml Bumps the extension version to 1.0.4.

Review effort: Max (auto)

…owerShell fallback

Address the Copilot review on github#5283: the mtime fallback now resolves the complete link chain via Resolve-ContextPath, skips candidates that resolve outside the project and reports the resolved project-relative path, rejects special files from target metadata instead of opening links (a named pipe with no writer hung the update), sorts by the resolved target's mtime, and propagates unrelated I/O failures instead of silently reporting an older plan. The mtime fallback tests now run under WINDOWS_POWERSHELL so the 5.1-specific path is exercised on Windows.
Copilot AI auto review requested due to automatic review settings November 6, 2026 03:10

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.

… fallback

Resolve-ContextPath collapsed '..' in link targets before resolving their symlinked parents, used case-insensitive -eq for the resolution loop, and accepted candidates when the loop exhausted without stabilizing. Walk link targets segment by segment, compare with the platform-aware comparison, and reject candidates whose chain never stabilizes.
Copilot AI auto review requested due to automatic review settings November 6, 2026 04:00

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.

🟡 Changes recommended

Critical symlink-resolution flaws can select incorrect plans, bypass containment checks to modify external files, and cause exponential processing that stalls the updater.

2 open issues
2 previously missed issues

In code that hasn't changed since last review

High severity Reject parent traversal through non-directory components

extensions/​agent-context/​scripts/​powershell/​update-agent-context.ps1:140

A link target such as ../../plans/not-a-directory/../current.md, where not-a-directory is a regular file, is reduced to plans/current.md even though filesystem lookup should fail. If that file exists, the fallback selects it as the plan instead of rejecting the invalid link. Validate intermediate components before consuming .., skip invalid candidates without discarding valid ones, and add this case to the non-directory-link regressions.

High severity Reject unresolved link chains before processing parent segments

extensions/​agent-context/​scripts/​powershell/​update-agent-context.ps1:143

If a directory-link chain exceeds $Depth before a .. segment, this removes an unresolved component and can select the wrong file. For example, twelve links ending at plans/archive/nested make plans/alias01/../current.md resolve to plans/current.md; the outer loop then stabilizes on that incorrect path. Propagate incomplete resolution and reject it before consuming further segments, with a regression for a link chain followed by ...

3 resolved since last review

Review effort: Balanced (auto)

Copilot AI auto review requested due to automatic review settings November 6, 2026 05:10

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.

🟡 Changes recommended

Unix backslash paths can cause containment validation to inspect a different target from the one written, while a shared link-follow budget can suppress later valid plans.

3 open issues
2 resolved since last review

Review effort: Max (auto)

Copilot AI auto review requested due to automatic review settings November 6, 2026 06:24

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.

🔵 Needs a closer look

Human assessment is needed because subtle link-resolution edge cases can allow writes outside the project and select incorrect plan files.

No open issues 🎉

3 resolved since last review

Review effort: Balanced (auto)

@mnriem mnriem added the triage-must-have Verdict: high-value, important work for Spec Kit — do first label Nov 6, 2026
@mnriem
mnriem requested an auto review from Copilot November 6, 2026 13:59

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.

🟡 Changes recommended

Link resolution mishandles whitespace-only path components and accepts partially resolved paths at its depth limit, allowing containment checks to pass before context files are written outside the project.

5 open issues

Review effort: Balanced (auto)

@mnriem

mnriem commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback and fix test & lint errors

@mnriem mnriem added the author-awaiting Waiting on author response label Nov 6, 2026
…t -f

The mtime fallback rejected named-pipe link targets through the
UnixMode property, which proved insufficient on macOS: the fifo-link
tests failed on macOS CI while passing on Linux. test -f stats the
resolved target and is true only for a regular file, never opens it,
and is POSIX-identical on Linux and macOS, matching the bash twin.
UnixMode remains as the fallback when test is unavailable.
Copilot AI auto review requested due to automatic review settings November 6, 2026 15:22

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.

🔵 Needs a closer look

The context-file containment check can accept long symlink chains that escape the project, allowing subsequent writes to overwrite a file outside the project.

4 open issues
1 resolved since last review

Review effort: Balanced (auto)

… in PowerShell fallback

Copilot round 6 on github#5283: the recursive link-target walk discarded
whitespace-only components (valid Unix directory names) and collapsed
'..' past missing or non-directory ancestors, letting validation accept
an in-project path while the later write follows the link outside the
project. The context-file caller also checked a partially resolved
path only once, so a chain past the depth limit passed containment.
And a link to the filesystem root aborted the resolver with a binding
error on the empty relative path.

Resolve-ContextPath now preserves whitespace-only components, requires
the preceding component to be an existing directory before applying
'..', and accepts an empty relative path as the base directory. The
context-file check re-runs resolution until it stabilizes, like the
mtime fallback, and rejects chains that never stabilize. The FIFO
finding is already covered by the test -f fix on the current head.

Five new PowerShell regression tests, red on the old code and green
on the new: root link target, whitespace directory, '..' after a
missing ancestor, '..' after a non-directory ancestor, and an
unresolved 100-link context-file chain to an outside directory.
Copilot AI auto review requested due to automatic review settings November 6, 2026 15:55

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.

🟡 Changes recommended

The resolver mishandles .. after exhausting its link-recursion limit, allowing an incorrect path to appear in-project and context-file writes to modify files outside the project.

1 open issue
4 resolved since last review

Review effort: Balanced (auto)

@mnriem

mnriem commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

Please address Copilot feedback. If not applicable, please explain why

Copilot AI auto review requested due to automatic review settings November 6, 2026 16:34

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.

🔵 Needs a closer look

Human assessment is needed because path-resolution edge cases in symlinked checkouts and malformed link targets can reject valid links or select broken ones.

No open issues 🎉

1 resolved since last review

Review effort: Balanced (auto)

@sx4im

sx4im commented Nov 6, 2026

Copy link
Copy Markdown
Author

Addressed. The latest Copilot finding (depth-limit handling of .. in link resolution) is fixed in a44fd01, with a regression test covering depth exhaustion followed by ... The earlier rounds are fixed in the previous pushes as well.

This branch has not been deployed

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

Labels

author-awaiting Waiting on author response triage-must-have Verdict: high-value, important work for Spec Kit — do first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

agent-context: PowerShell implementation not updated for the #5222 plan-candidate fix (bash/python changed, PS 5.1 parity diverges)

3 participants