PowerShell Code Standards
This rule file summarizes the PowerShell-specific policies for this repository.
Toolchain
- Formatting — Invoke-Formatter: Format all PowerShell files via PoshQC. MCP command:
mcp__drm-copilot__run_poshqc_format
- Linting — PSScriptAnalyzer: Run PoshQC analyzer with repo settings. MCP command:
mcp__drm-copilot__run_poshqc_analyze. Optional autofix: mcp__drm-copilot__run_poshqc_analyze_autofix
- Type checking: Not applicable for PowerShell; skip to testing.
- Testing — Pester (v5.x): Run tests via MCP. MCP command:
mcp__drm-copilot__run_poshqc_test. Use repo config at scripts/powershell/PoshQC/settings/pester.runsettings.psd1.
Run the toolchain in order: format → analyze → test. Restart from step 1 if any step fails or changes files. Use the MCP server functions; do not substitute VS Code task wrappers.
Compatibility
- All scripts must be compatible with PowerShell 7+ (enforced via PSScriptAnalyzer settings).
Coding Standards
- Prefer advanced functions with
CmdletBinding() and named parameters.
- Add
[Parameter(Mandatory = $true)] and validation attributes where appropriate.
- Implement ShouldProcess/SupportsShouldProcess for state-changing actions.
- Avoid global state and mutable script-scoped variables; pass data explicitly.
- Avoid
Invoke-Expression, plaintext secrets, and hard-coded credentials/paths.
- Use
Write-Error/throw for failures; avoid silent catch-alls.
- Use approved verbs and descriptive nouns for function names (PSScriptAnalyzer enforces this).
- Keep scripts cohesive and under 500 lines.
Change Budget
- Direct-mode overall scope: up to 2 production PowerShell files (plus corresponding tests). Requests exceeding this must be routed to
powershell-orchestrator per powershell-change-budget-router.
- Per-batch cap in all modes: at most 3 production files and 3 test files unless an explicit override has been approved.
- If a batch would exceed the cap, split the work into smaller batches.
Design Seams (Minimal DI)
Introduce the smallest seam that enables reliable mocking. Apply these options in order:
- Wrapper function seam (preferred) — extract external executable calls into a wrapper function:
- Signature:
Invoke-<Tool>Exe -<Tool>Args <string[]> (for example Invoke-GitExe -GitArgs <string[]>).
- The wrapper accepts a single array parameter and splats into the executable:
git @GitArgs 2>&1.
- Parameter names must not be
Args (automatic variable collision). Use GitArgs, ToolArgs, or Arguments.
- Injectable delegate / ScriptBlock seam — only when a wrapper is insufficient, add a narrowly-scoped optional delegate or
ScriptBlock parameter with a safe default. Do not introduce generic runner frameworks.
- Adapter seams for non-executable boundaries — for filesystem, environment, or clock dependencies, introduce tiny helpers or narrow injectable parameters rather than threading raw I/O through domain logic.
Testing Standards
- Use Pester (v5.x) as the test framework.
- Organize tests to mirror code structure (e.g.,
tests/scripts/dev-tools/ScriptName.Tests.ps1).
- Name test files
*.Tests.ps1.
- Use
Describe/Context/It blocks; one behavior per It.
- Write focused tests exercising a single function or behavior.
- Mock sparingly; prefer real code paths.
- No external dependencies in unit tests.
- Repository-wide line coverage must remain >= 80%.
- Any new module, class, or method must reach >= 90% coverage.
- Coverage regression on changed lines is a blocking finding.
Deterministic Test Requirements
Tests must not depend on:
- network access,
- mutable machine PATH or profile state,
- implicit working-directory assumptions,
- external services or live executables.
Tests must produce identical results in Terminal and the VS Code Test Explorer. Assume a different PATH, current working directory, profile, and host when tests are run from Test Explorer; do not rely on ambient environment resolution.
Mocking Rules
- External executable mocking — never mock
git, gh, actionlint, or other executables directly. Mock the wrapper function (for example Invoke-GitExe) instead.
- Mock signature parity — mock signatures must match production named parameters exactly. Example:
- production:
Invoke-GitExe -GitArgs $gitArgs
- test mock:
param([string[]]$GitArgs)
- Mock registration order — register mocks before the code under test can resolve commands, so Test Explorer parity is preserved.
- AST/ScriptBlock import order — when importing script functions via AST or
ScriptBlock patterns:
- dot-source the returned
ScriptBlock in the test scope,
- import dependencies in the correct order,
- import wrapper seams before mocking them when executable calls exist.
Prohibited Behaviors
- Broad refactors across unrelated scripts or modules.
- Introducing generic process-runner frameworks to replace the wrapper seam pattern.
- Creating PSScriptAnalyzer debt and deferring cleanup.
- Weakening assertions merely to make tests pass.
- Adding sleeps, retries, or timing hacks to stabilize flaky tests.
- Claiming success without running the required toolchain.
1---2name: powershell3description: PowerShell-specific toolchain and coding standards.4---56# PowerShell Code Standards78This rule file summarizes the PowerShell-specific policies for this repository.910## Toolchain11121. **Formatting — Invoke-Formatter**: Format all PowerShell files via PoshQC. MCP command: `mcp__drm-copilot__run_poshqc_format`132. **Linting — PSScriptAnalyzer**: Run PoshQC analyzer with repo settings. MCP command: `mcp__drm-copilot__run_poshqc_analyze`. Optional autofix: `mcp__drm-copilot__run_poshqc_analyze_autofix`143. **Type checking**: Not applicable for PowerShell; skip to testing.154. **Testing — Pester (v5.x)**: Run tests via MCP. MCP command: `mcp__drm-copilot__run_poshqc_test`. Use repo config at `scripts/powershell/PoshQC/settings/pester.runsettings.psd1`.1617Run the toolchain in order: format → analyze → test. Restart from step 1 if any step fails or changes files. Use the MCP server functions; do not substitute VS Code task wrappers.1819## Compatibility2021- All scripts must be compatible with **PowerShell 7+** (enforced via PSScriptAnalyzer settings).2223## Coding Standards2425- Prefer **advanced functions** with `CmdletBinding()` and named parameters.26- Add `[Parameter(Mandatory = $true)]` and validation attributes where appropriate.27- Implement **ShouldProcess/SupportsShouldProcess** for state-changing actions.28- Avoid global state and mutable script-scoped variables; pass data explicitly.29- Avoid `Invoke-Expression`, plaintext secrets, and hard-coded credentials/paths.30- Use `Write-Error`/`throw` for failures; avoid silent catch-alls.31- Use approved verbs and descriptive nouns for function names (PSScriptAnalyzer enforces this).32- Keep scripts cohesive and under 500 lines.3334## Change Budget3536- Direct-mode overall scope: up to 2 production PowerShell files (plus corresponding tests). Requests exceeding this must be routed to `powershell-orchestrator` per `powershell-change-budget-router`.37- Per-batch cap in all modes: at most 3 production files and 3 test files unless an explicit override has been approved.38- If a batch would exceed the cap, split the work into smaller batches.3940## Design Seams (Minimal DI)4142Introduce the smallest seam that enables reliable mocking. Apply these options in order:43441. **Wrapper function seam (preferred)** — extract external executable calls into a wrapper function:45 - Signature: `Invoke-<Tool>Exe -<Tool>Args <string[]>` (for example `Invoke-GitExe -GitArgs <string[]>`).46 - The wrapper accepts a single array parameter and splats into the executable: `git @GitArgs 2>&1`.47 - Parameter names must not be `Args` (automatic variable collision). Use `GitArgs`, `ToolArgs`, or `Arguments`.482. **Injectable delegate / ScriptBlock seam** — only when a wrapper is insufficient, add a narrowly-scoped optional delegate or `ScriptBlock` parameter with a safe default. Do not introduce generic runner frameworks.493. **Adapter seams for non-executable boundaries** — for filesystem, environment, or clock dependencies, introduce tiny helpers or narrow injectable parameters rather than threading raw I/O through domain logic.5051## Testing Standards5253- Use **Pester** (v5.x) as the test framework.54- Organize tests to mirror code structure (e.g., `tests/scripts/dev-tools/ScriptName.Tests.ps1`).55- Name test files `*.Tests.ps1`.56- Use `Describe`/`Context`/`It` blocks; one behavior per `It`.57- Write focused tests exercising a single function or behavior.58- Mock sparingly; prefer real code paths.59- No external dependencies in unit tests.60- Repository-wide line coverage must remain >= 80%.61- Any new module, class, or method must reach >= 90% coverage.62- Coverage regression on changed lines is a blocking finding.6364### Deterministic Test Requirements6566Tests must not depend on:6768- network access,69- mutable machine PATH or profile state,70- implicit working-directory assumptions,71- external services or live executables.7273Tests must produce identical results in Terminal and the VS Code Test Explorer. Assume a different PATH, current working directory, profile, and host when tests are run from Test Explorer; do not rely on ambient environment resolution.7475### Mocking Rules76771. **External executable mocking** — never mock `git`, `gh`, `actionlint`, or other executables directly. Mock the wrapper function (for example `Invoke-GitExe`) instead.782. **Mock signature parity** — mock signatures must match production named parameters exactly. Example:79 - production: `Invoke-GitExe -GitArgs $gitArgs`80 - test mock: `param([string[]]$GitArgs)`813. **Mock registration order** — register mocks before the code under test can resolve commands, so Test Explorer parity is preserved.824. **AST/ScriptBlock import order** — when importing script functions via AST or `ScriptBlock` patterns:83 - dot-source the returned `ScriptBlock` in the test scope,84 - import dependencies in the correct order,85 - import wrapper seams before mocking them when executable calls exist.8687## Prohibited Behaviors8889- Broad refactors across unrelated scripts or modules.90- Introducing generic process-runner frameworks to replace the wrapper seam pattern.91- Creating PSScriptAnalyzer debt and deferring cleanup.92- Weakening assertions merely to make tests pass.93- Adding sleeps, retries, or timing hacks to stabilize flaky tests.94- Claiming success without running the required toolchain.