Repository navigation
Add AI skills: analyze-debug-files, find-related-github-issues, trace-code-introduction #2584
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
David Paulson (dpaulson45)
wants to merge
7
commits into
main
Choose a base branch
from
dpaul-AISkill
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
58303d9
Add release-tag lookup skill with regression coverage
dpaulson45 db7f53e
Add related GitHub issue lookup skill with regression coverage
dpaulson45 41eccad
Add shared filesystem-safety helpers for repository skills
dpaulson45 44ae891
Add code-introduction tracing skill with provenance coverage
dpaulson45 8dd4e8a
Add release-pinned debug-analysis skill and regression coverage
dpaulson45 4ad3b22
Integrate skill tests with repository tooling
dpaulson45 a30d468
Restore Git command state after skill helper tests
dpaulson45 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| Describe 'Pester runner branch selection' { | ||
| BeforeAll { | ||
| $Script:runnerPath = Join-Path -Path $PSScriptRoot -ChildPath '..\Pester.ps1' | ||
|
|
||
| if (-not ('PesterRunnerTestJob' -as [type])) { | ||
| Add-Type -TypeDefinition @' | ||
| using System.Management.Automation; | ||
| public sealed class PesterRunnerTestJob : Job { | ||
| public PesterRunnerTestJob(string name) : base("fixture", name) { | ||
| SetJobState(JobState.Running); | ||
| SetJobState(JobState.Completed); | ||
| } | ||
| public override string Location { get { return ""; } } | ||
| public override string StatusMessage { get { return ""; } } | ||
| public override bool HasMoreData { get { return false; } } | ||
| public override void StopJob() { } | ||
| } | ||
| '@ | ||
| } | ||
|
|
||
| function git { | ||
| throw 'Unexpected git invocation without a mock.' | ||
| } | ||
|
|
||
| function Invoke-TestRunner { | ||
| & $Script:runnerPath -NoProgress -Branch main *> $null | ||
| } | ||
| } | ||
|
|
||
| BeforeEach { | ||
| $Script:runnerState = @{ | ||
| ChangedFile = '.github/skills/analyze-debug-files/SKILL.md' | ||
| SelectedPaths = [System.Collections.Generic.List[string]]::new() | ||
| } | ||
| $state = $Script:runnerState | ||
| Mock -CommandName git -MockWith ({ | ||
| switch ($args[0]) { | ||
| 'log' { return '1111111111111111111111111111111111111111 Wed, 28 Oct 2026 07:46:41 -0500' } | ||
| 'diff-tree' { return $state.ChangedFile } | ||
| 'status' { return } | ||
| } | ||
| throw "Unexpected git arguments: $($args -join ' ')" | ||
| }.GetNewClosure()) | ||
| Mock -CommandName Start-Job -MockWith ({ | ||
| param($ArgumentList, $Name) | ||
| $state.SelectedPaths.Add([string]@($ArgumentList)[0]) | ||
| return [PesterRunnerTestJob]::new($Name) | ||
| }.GetNewClosure()) | ||
| Mock -CommandName Receive-Job -MockWith { | ||
| return [PSCustomObject]@{ | ||
| Result = 'Passed' | ||
| Duration = [TimeSpan]::FromMilliseconds(1) | ||
| } | ||
| } | ||
| Mock -CommandName Remove-Job -MockWith {} | ||
| } | ||
|
|
||
| It 'skips documentation-only changes for <ChangedFile>, matching main' -ForEach @( | ||
| @{ ChangedFile = '.github/skills/analyze-debug-files/SKILL.md' } | ||
| @{ ChangedFile = '.github/skill-lib/README.md' } | ||
| @{ ChangedFile = 'README.md' } | ||
| ) { | ||
|
dpaulson45 marked this conversation as resolved.
Resolved
|
||
| $Script:runnerState.ChangedFile = $ChangedFile | ||
| Invoke-TestRunner | ||
|
|
||
| $Script:runnerState.SelectedPaths.Count | Should -Be 0 | ||
| } | ||
|
|
||
| It 'retains all test areas when <ChangedFile> changes' -ForEach @( | ||
| @{ ChangedFile = '.build/Pester.ps1' } | ||
| @{ ChangedFile = '.github/skills/analyze-debug-files/Get-DebugFileMetadata.ps1' } | ||
| ) { | ||
| $Script:runnerState.ChangedFile = $ChangedFile | ||
| Invoke-TestRunner | ||
|
|
||
| @($Script:runnerState.SelectedPaths | Where-Object { | ||
| $_ -notmatch '[\\/]\.github[\\/]' | ||
| }).Count | Should -BeGreaterThan 0 | ||
| @($Script:runnerState.SelectedPaths | Where-Object { | ||
| (Split-Path -Path $_ -Leaf) -eq 'SkillDocContract.Tests.ps1' | ||
| }).Count | Should -Be 1 | ||
| @($Script:runnerState.SelectedPaths | Where-Object { | ||
| $_ -match '[\\/]\.github[\\/]examples[\\/]' | ||
| }).Count | Should -Be 0 | ||
| } | ||
|
|
||
| It 'retains all test areas without a branch filter even for documentation-only changes' { | ||
| & $Script:runnerPath -NoProgress *> $null | ||
|
|
||
| @($Script:runnerState.SelectedPaths | Where-Object { | ||
| $_ -notmatch '[\\/]\.github[\\/]' | ||
| }).Count | Should -BeGreaterThan 0 | ||
| @($Script:runnerState.SelectedPaths | Where-Object { | ||
| (Split-Path -Path $_ -Leaf) -eq 'SkillDocContract.Tests.ps1' | ||
| }).Count | Should -Be 1 | ||
| @($Script:runnerState.SelectedPaths | Where-Object { | ||
| $_ -match '[\\/]\.github[\\/]examples[\\/]' | ||
| }).Count | Should -Be 0 | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # skill-lib | ||
|
|
||
| Shared filesystem-safety helpers dot-sourced by skills under `.github/skills/`. | ||
|
|
||
| This directory sits **beside** `.github/skills/`, not inside it, so the skill | ||
| loader does not attempt to discover a `SKILL.md` here. Each helper is a | ||
| single-purpose `.ps1` file with a documented contract at the top; skills | ||
| dot-source only the helpers they need. | ||
|
|
||
| ## When to add a helper here | ||
|
|
||
| Extract a helper into this directory only when it is: | ||
|
|
||
| - **Byte-for-byte reusable** across two or more skills. If two callers need | ||
| different behavior, keep the helpers inline in each skill — divergent | ||
| copies with the same name are worse than duplication because they silently | ||
| break the "same call, same behavior" contract downstream. | ||
| - **Purely defensive filesystem plumbing** (path validation, reparse-point | ||
| detection, DOS-device probes, handle equality checks). Domain logic, | ||
| reporting helpers, and one-of-a-kind orchestration stay in the calling | ||
| skill. | ||
|
|
||
| ## Consuming a helper | ||
|
|
||
| Skills dot-source with a `$PSScriptRoot`-relative path that walks up out of | ||
| `.github/skills/<skill-name>/` and back down into `.github/skill-lib/`: | ||
|
|
||
| ```powershell | ||
| . $PSScriptRoot\..\..\skill-lib\Resolve-SkillLocalPath.ps1 | ||
| ``` | ||
|
|
||
| The `analyze-debug-files` helpers — `Get-DebugFileMetadata.ps1`, | ||
| `Assert-BaselineTrusted.ps1`, `Get-BaselineDependencyGraph.ps1`, and | ||
| `Write-DebugAnalysisReport.ps1` — all use this same `$PSScriptRoot`-relative | ||
| form, because each is a real `.ps1` file where the variable is well-defined. | ||
|
|
||
| `Resolve-SkillLocalPath` owns the shared path policy and loads the two defensive | ||
| primitives itself. It returns a validated absolute path, or `$null` on refusal. | ||
| Callers must use that returned path rather than normalize the input again. | ||
| Relative paths resolve against PowerShell's current location. `-PathType Leaf` | ||
| requires an existing file; the default requires a directory. `-AllowMissing` | ||
| performs the same locality checks without requiring existence or an item type, | ||
| for paths that the caller will create. | ||
|
|
||
| Each helper's `.DESCRIPTION` carries a `Consumed by:` list. That list is not | ||
| decorative — `Tests/SkillLibContract.Tests.ps1` derives the real consumer set | ||
| from both the skills and this library, and fails when either the list or the "Skills that depend | ||
| on this directory" section below falls out of sync. | ||
|
|
||
| ## Repository-only: these skills are not independently distributable | ||
|
|
||
| Because the helpers live **outside** each skill's own directory, the | ||
| `.github/skills/<skill-name>/` folders are **not** self-contained. The Agent | ||
| Skills loader discovers and bundles only the files inside a skill's directory, | ||
| so copying one of these skill folders on its own — or installing it with | ||
| `gh skill install` — produces a skill that fails at dot-source time. | ||
|
|
||
| Skills that depend on this directory: | ||
|
|
||
| - `.github/skills/analyze-debug-files/` | ||
| - `.github/skills/trace-code-introduction/` | ||
|
|
||
| These are **repository-scoped skills**, intended to run from a | ||
| `microsoft/CSS-Exchange` clone. That is a deliberate trade: a single canonical | ||
| copy of each safety helper is worth more than independent distributability, | ||
| because divergent copies of a path-validation routine fail silently and | ||
| dangerously. If a skill here ever needs to be distributed standalone, vendor the | ||
| helpers into its own directory at that point rather than loosening this rule. | ||
|
|
||
| `find-release-tag-for-script-version` intentionally carries equivalent inline | ||
| filesystem checks to remain self-contained. It is not a consumer of this | ||
| directory. When changing the canonical policy or its primitives, review that | ||
| standalone copy for the same edge case; do not silently make it depend on this | ||
| library. | ||
|
|
||
| ## Add-Type namespace convention | ||
|
|
||
| Helpers that use `Add-Type` for P/Invoke declare types under the | ||
| `SkillLib.*` namespace and guard the declaration with an `-as [type]` | ||
| check so re-sourcing is a no-op: | ||
|
|
||
| ```powershell | ||
| if (-not ('SkillLib.DosDeviceHelper' -as [type])) { | ||
| Add-Type -Namespace 'SkillLib' -Name 'DosDeviceHelper' -MemberDefinition ... | ||
| } | ||
| ``` | ||
|
|
||
| A single shared namespace means the P/Invoke types load once per PowerShell | ||
| session even when multiple skills consume the same helper. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.