From 5f5062cca628831bc4f3de8864c84bb2759ed6f7 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 4 Nov 2026 13:24:32 +0100 Subject: [PATCH 1/6] Give module bootstrap direct initial-release steps --- docs/content/get-started/module-bootstrap.md | 38 +++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/docs/content/get-started/module-bootstrap.md b/docs/content/get-started/module-bootstrap.md index 3508aaf0..b7f4b6d4 100644 --- a/docs/content/get-started/module-bootstrap.md +++ b/docs/content/get-started/module-bootstrap.md @@ -1,31 +1,35 @@ --- title: Module bootstrap -description: How to get a brand-new module to its first release using a single integration branch for the load-bearing core. +description: Release a module's load-bearing core through one integration branch. --- # Module bootstrap -A brand-new module usually has a small **load-bearing core**: the piece(s) every other function will depend on, without which nothing else in the module can work at all. A single feature PR cannot carry that much scope and still be small and focused, so bootstrap uses one integration branch instead. +A module's **load-bearing core** contains the components that all other module functions require. The module cannot work without these components. + +If the core exceeds one focused feature pull request, use one integration branch for bootstrap. ## Identify the load-bearing core first -What counts as "load-bearing" follows the module's archetype from [Module types](../reference/module-types.md): +Identify the core from the module's archetype in [Module types](../reference/module-types.md): -- **Data modules** — the conversion pivot: `ConvertFrom-` / `ConvertTo-` (and whatever parser/serializer they wrap). Every other function (`Import-`, `Export-`, `Format-`, `Merge-`, ...) is built on top of this pivot and is meaningless without it. -- **Integration (API) modules** — a [`Context`](https://github.com/PSModule/Context)-backed credential/config store, the client setup that uses it, and at least one API function that consumes the context end-to-end. Every other API function needs the same context and client to do anything. +- **Data modules** - The core is the conversion pivot: `ConvertFrom-` / `ConvertTo-` and any parser or serializer they use. Other functions (`Import-`, `Export-`, `Format-`, `Merge-`, ...) depend on this pivot. +- **Integration (API) modules** - The core contains a [`Context`](https://github.com/PSModule/Context)-backed credential and configuration store, its client setup, and at least one API function. That API function uses the context end-to-end. Other API functions depend on the same context and client. -Scope the integration branch to exactly that core, not to everything planned for v1. Keeping it to the minimum that "everyone needs" gets a usable release out faster, and lets independent follow-up functions be developed in parallel — by different people or agents — as soon as the core is stable enough to build against, even before it merges. +Limit the integration branch to this core, not all features planned for v1. Contributors or agents can develop independent follow-up functions in parallel before the core merges. Start this work only when the core supports those functions. ## Pattern -1. Cut one long-lived branch from the default branch for the initial release, named for the outcome, e.g. `build-thing-module`. -2. Open one pull request per function (or small group of related functions) targeting that branch instead of `main`. These PRs can land in parallel — there is no strict order between them, unlike a [stacked pull request](https://msx.no/docs/Ways-of-Working/Branching-and-Merging/#stacked-pull-requests). -3. Once the load-bearing core is coherent and complete, open the pull request that merges the integration branch into `main`. Its resulting important push becomes the module's first real release (`v1.0.0`). -4. Smaller follow-up features (one more function, a formatter, an alias) can keep targeting the integration branch before it lands, the same way they targeted it during bootstrap. +1. Create one long-lived branch from the default branch for the initial release. Name it for the outcome, for example, `build-thing-module`. +2. Open one pull request per function or small group of related functions. Target the integration branch instead of `main`. Independent pull requests can merge in any order, unlike a [stacked pull request](https://msx.no/docs/Ways-of-Working/Branching-and-Merging/#stacked-pull-requests). +3. When the core is complete and consistent, open the pull request from the integration branch to `main`. The resulting important push produces the module's first release (`v1.0.0`). +4. To include smaller follow-up features before integration, target the same integration branch. Examples include another function, a formatter, or an alias. ## After the core lands -Once the core has merged as `v1.0.0`, ordinary [SemVer](../reference/versioning.md) applies: a new function built on the stable core is a **minor** bump, a fix is a **patch** bump, and only a change to the core's own contract (signature, exported class shape, behavior) is a **major** bump. No special versioning exception is needed once the core is in place — the bootstrap phase exists only to get that core to a first release quickly. +After the core merges as `v1.0.0`, ordinary [SemVer](../reference/versioning.md) applies. A new function on the stable core is a **minor** bump. A fix is a **patch** bump. Only a change to the core's own contract (signature, exported class shape, behavior) is a **major** bump. + +Bootstrap has no versioning exception after the core's first release. The bootstrap phase provides the core's initial usable release. ```mermaid gitGraph @@ -46,20 +50,20 @@ gitGraph merge build-thing-module id: "v1.0.0" ``` -`function-a` and `function-b` are independent — both cut from `build-thing-module` and merged back in any order, unlike a stacked pull request where each layer depends on the one before it. +`function-a` and `function-b` are independent. Both start from `build-thing-module` and can merge into it in any order. In a stacked pull request, each layer depends on the preceding layer. ## Example -A module bootstrapped this way: +The example uses one bootstrap integration branch: | PR | Targets | Contents | | --- | --- | --- | -| #1 | `main` | `build-thing-module` branch, the load-bearing core (e.g. conversion pivot, or context + client + first API function) | -| #2 | `build-thing-module` | a follow-up function built on the core, added before the integration branch merged | +| #1 | `main` | `build-thing-module` branch with the load-bearing core, such as a conversion pivot or context, client, and first API function | +| #2 | `build-thing-module` | A follow-up function on the core, added before the integration branch merges | ## When to use this -- The module has no usable release yet, and the load-bearing core hasn't landed. -- Use this only for the initial bootstrap. Once `main` has a first release, ongoing feature work targets `main` directly with ordinary topic branches, or uses a [stacked pull request](https://msx.no/docs/Ways-of-Working/Branching-and-Merging/#stacked-pull-requests) when changes genuinely depend on each other. +- Use bootstrap only when the module has no usable release and the load-bearing core has not merged. +- After `main` has a first release, target `main` with ordinary topic branches. Use a [stacked pull request](https://msx.no/docs/Ways-of-Working/Branching-and-Merging/#stacked-pull-requests) only for dependent changes. For the general branching and merge model, see [MSX Branching and Merging](https://msx.no/docs/Ways-of-Working/Branching-and-Merging/). From a3510327fed0a46db51f32720f0ea96321d6e051 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 4 Nov 2026 13:29:51 +0100 Subject: [PATCH 2/6] State supported module test and skip procedures directly --- .../guides/skipping-framework-tests.md | 42 ++++----- docs/content/guides/writing-module-tests.md | 93 ++++++++++--------- 2 files changed, 70 insertions(+), 65 deletions(-) diff --git a/docs/content/guides/skipping-framework-tests.md b/docs/content/guides/skipping-framework-tests.md index a69a1265..c879675f 100644 --- a/docs/content/guides/skipping-framework-tests.md +++ b/docs/content/guides/skipping-framework-tests.md @@ -1,36 +1,36 @@ --- title: Skipping framework tests -description: How to skip individual PSModule framework tests on a per-file basis, the available test IDs, and the broader configuration alternatives. +description: Skip an individual framework test for one file and record the reason for the exception. --- # Skipping individual framework tests -The PSModule framework tests run automatically as part of the `Test-Module` and `Test-SourceCode` jobs. While you can skip entire test categories using the configuration settings (e.g., `Test.PSModule.Skip`), you can also skip individual framework tests on a per-file basis when needed. +The PSModule framework runs tests in the `Test-Module` and `Test-SourceCode` jobs. Configuration settings, such as `Test.PSModule.Skip`, skip entire test categories. A skip comment exempts an individual test for one file. -## How to Skip Tests +## How to skip tests -To skip an individual framework test for a specific file, add a special comment at the top of that file: +To skip an individual framework test, add this comment at the top of the file: ```powershell #SkipTest:: ``` -- ``: The unique identifier of the test to skip (see list below) -- ``: A brief explanation of why the test is being skipped +- ``: The unique identifier of the test to skip +- ``: A brief explanation of why the file needs the exception -The skip comment will cause the framework to skip that specific test for that file only, and will log a warning in the build output with the reason provided. +The framework skips only the identified test for that file. It writes the supplied reason as a warning in the build output. ## Available framework tests -Every source-code test ID, its meaning, and an example skip comment are listed in -[Framework test IDs](../reference/framework-test-ids.md#source-code-tests). +The [Framework test IDs](../reference/framework-test-ids.md#source-code-tests) reference lists every source-code test ID, +its meaning, and an example skip comment. [Module tests](../reference/framework-test-ids.md#module-tests) run against the compiled module in the -`.PSModule/module` directory and typically don't need to be skipped, as they validate the final built module. +`.PSModule/module` directory. These tests validate the final built module. -## Example Usage +## Example usage -Here's an example of a function file that skips the `FunctionCount` test because it includes helper functions: +This function file skips `FunctionCount` because it contains helper functions: ```powershell #SkipTest:FunctionCount:This file contains helper functions for the main function @@ -163,24 +163,24 @@ function Format-ComplexData { } ``` -Replace `` with the HTTPS host that publishes the module documentation and `` with the module's published name. If the public function belongs to a group, insert `/` between `Functions/` and `Get-ComplexData`. +Replace `` with the HTTPS host that publishes the module documentation. Replace `` with the module's published name. If the public function belongs to a group, insert `/` between `Functions/` and `Get-ComplexData`. -The skip exempts only `FunctionCount`. Every function in the file must still follow the [PowerShell function standard](https://msx.no/docs/Coding-Standards/PowerShell/Functions/), including complete comment-based help, matching `[OutputType()]` and `.OUTPUTS` metadata, typed parameters, and implicit output. +The skip exempts only `FunctionCount`. Every function in the file must follow the [PowerShell function standard](https://msx.no/docs/Coding-Standards/PowerShell/Functions/). This includes complete comment-based help, matching `[OutputType()]` and `.OUTPUTS` metadata, typed parameters, and implicit output. -## Best Practices +## Best practices -- **Use skip comments sparingly**: Framework tests exist to maintain code quality and consistency. Only skip tests when absolutely necessary. -- **Provide clear reasons**: Always include a meaningful explanation in the skip comment to help reviewers understand why the test is being skipped. -- **Consider alternatives**: Before skipping a test, consider whether refactoring the code to comply with the test would be better for long-term maintainability. -- **Document exceptions**: If you skip a test, document the reason in your PR description or code comments. +- **Use skip comments sparingly**: Use a skip comment only when a necessary exception prevents compliance with the test. +- **Provide clear reasons**: Include a reason that identifies the exception and explains why the file needs it. +- **Consider alternatives**: Before you skip a test, consider whether code refactoring improves long-term maintainability and satisfies the test. +- **Document exceptions**: Record the reason in the PR description or code comments. -## Related Configuration +## Related configuration For broader test control, use the configuration file settings: - Skip all framework tests: `Test.PSModule.Skip: true` - Skip only source code tests: `Test.SourceCode.Skip: true` -- Skip framework tests on specific OS: `Test.PSModule.Windows.Skip: true` +- Skip framework tests on Windows: `Test.PSModule.Windows.Skip: true` See [Settings](../reference/settings.md) for the full list and [Configuring the pipeline](configuring-the-pipeline.md) for worked examples. diff --git a/docs/content/guides/writing-module-tests.md b/docs/content/guides/writing-module-tests.md index cba3709b..db8208d8 100644 --- a/docs/content/guides/writing-module-tests.md +++ b/docs/content/guides/writing-module-tests.md @@ -1,51 +1,56 @@ --- title: Writing module tests -description: How Process-PSModule discovers module-local Pester tests, the setup and teardown phases, and how to share test infrastructure across the platform matrix. +description: Discover module-local Pester tests and share test infrastructure across the platform matrix. --- # Writing module tests -Module-local tests are the Pester tests you write for your own module, as opposed to the framework tests that -Process-PSModule enforces on every module. They run in parallel across Windows, Linux, and macOS after the module has -been built and imported. +Module-local Pester tests verify the module's own behavior. They are separate from the framework tests that +Process-PSModule enforces on every module. The workflow builds and imports the module before it runs module-local tests. +The tests run in parallel across Windows, Linux, and macOS. ## Pester version -Module test files declare a Pester **6.1.x** requirement at the top of each `*.Tests.ps1`: +At the top of each `*.Tests.ps1`, declare a Pester **6.1.x** requirement: ```powershell #Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.1.0'; MaximumVersion = '6.*' } ``` -This is a convention module authors add. Process-PSModule pins its reusable +This declaration is a module-author convention. Process-PSModule pins its reusable [Invoke-Pester](https://github.com/PSModule/Invoke-Pester) action runs to the -`[6.1.0,7.0.0)` range, so patch updates flow in automatically while a new -major stays a deliberate, reviewed change. +`[6.1.0,7.0.0)` range. Patch updates install automatically. A major-version +change requires explicit review. -Pester 6.1 adds opt-in controls for shuffled and parallel file execution +Pester 6.1 provides opt-in controls for shuffled and parallel file execution (`Run.Shuffle`, `Run.ShuffleSeed`, `Run.Parallel`, and `Run.ParallelThrottleLimit`) and diagnostic start markers -(`Debug.ShowStartMarkers`). These controls are available when invoking Pester -directly with `New-PesterConfiguration`. Process-PSModule's reusable action will -expose them after the coordinated `PSModule/Invoke-Pester` action adds matching -inputs; the current v5.1.0 action contract does not accept them. +(`Debug.ShowStartMarkers`). Direct Pester invocations with +`New-PesterConfiguration` support these controls. The pinned +`PSModule/Invoke-Pester` v5.1.1 +[action contract](https://github.com/PSModule/Invoke-Pester/blob/c5494aba3c07d7bfd81bdbbc9f301e8fa4a729fb/action.yml) +does not accept these controls. Process-PSModule does not expose them through +its reusable workflow. ## Test discovery Simple, Standard, and Advanced are [documentation profiles](https://msx.no/docs/Coding-Standards/PowerShell/Testing/#module-test-profiles), not selectable workflow modes. The same discovery engine handles every profile. `.github/PSModule.yml` has no test-layout -or suite-matrix setting; `Settings.Test.Module.Suites` is computed internally from the repository files. +or suite-matrix setting. Process-PSModule calculates `Settings.Test.Module.Suites` from the repository files. -Process-PSModule inspects `tests/` recursively. Within each directory it uses the first matching form: +Process-PSModule inspects `tests/` recursively. In each directory, it selects the first matching form: -1. Exactly one `*.Configuration.ps1`. Discovery fails when a directory contains more than one. When selected, sibling `*.Container.ps1` and `*.Tests.ps1` files are not independently selected. -2. Otherwise, one or more `*.Container.ps1`. When selected, sibling `*.Tests.ps1` files are not independently selected. +1. Exactly one `*.Configuration.ps1`. If a directory contains more than one, discovery fails. Discovery does not independently select sibling `*.Container.ps1` or `*.Tests.ps1` files. +2. Otherwise, one or more `*.Container.ps1`. Discovery does not independently select sibling `*.Tests.ps1` files. 3. Otherwise, all `*.Tests.ps1`. -The selected form takes precedence only in that directory. Child directories are still inspected independently, so a repository may mix configurations, containers, and ordinary test files across different directories. +Precedence applies separately to each directory. Discovery also inspects child directories. +A repository can mix configurations, containers, and ordinary test files across different directories. -Every discovered artifact needs a unique prefix before its first dot because that prefix becomes `TestName`. For example, `Users.Unit.Tests.ps1` and `Users.Integration.Tests.ps1` both become `Users`; use distinct prefixes such as `UsersUnit` and `UsersIntegration`. +Each discovered artifact needs a unique filename prefix before its first dot. Discovery uses that prefix as `TestName`. +For example, `Users.Unit.Tests.ps1` and `Users.Integration.Tests.ps1` both produce `Users`. +Use distinct prefixes such as `UsersUnit` and `UsersIntegration`. Discovery does not affect which changes trigger a release. A test-only change does not enter the build, test, and publish path unless `^tests/` is added to @@ -53,20 +58,20 @@ publish path unless `^tests/` is added to ## Setup and teardown scripts -The workflow supports automatic execution of setup and teardown scripts for module tests: +The workflow runs setup and teardown scripts for module tests: - `tests/BeforeAll.ps1` and `tests/AfterAll.ps1` are special workflow phase files, not ordinary recursively discovered test entries. -- Each phase is enabled only when its exact file exists at the root of `tests/`. -- If either file is absent, the workflow skips that phase and continues normally. +- The workflow enables each phase only when its exact file exists at the root of `tests/`. +- If either file is absent, the workflow skips that phase and continues without it. - Phase detection is **not** recursive. Nested files named `BeforeAll.ps1` or `AfterAll.ps1` do not create workflow phases. -- Both scripts run with the same environment variables as the tests, including anything passed through +- Both scripts receive the same caller-provided environment variables as the tests through [`TestData`](calling-the-workflow.md#passing-test-data). ### Setup - `BeforeAll.ps1` -- Place at the exact repository-root path `tests/BeforeAll.ps1`. -- Runs once before all test matrix jobs to prepare the test environment. -- Deploy test infrastructure, download test data, initialize databases, or configure services. +- Place the script at the exact repository-root path `tests/BeforeAll.ps1`. +- The workflow runs this script once before all test matrix jobs to prepare the test environment. +- Use it to deploy test infrastructure, download test data, initialize databases, or configure services. ```powershell Write-Host "Setting up test environment..." @@ -78,9 +83,9 @@ Write-Host "Test environment ready!" ### Teardown - `AfterAll.ps1` -- Place at the exact repository-root path `tests/AfterAll.ps1`. -- Runs once after all test matrix jobs complete to clean up the test environment. -- Remove test resources, clean up databases, stop services, or upload artifacts. +- Place the script at the exact repository-root path `tests/AfterAll.ps1`. +- The workflow runs this script once after all test matrix jobs complete to clean up the test environment. +- Use it to remove test resources, clean up databases, stop services, or upload artifacts. ```powershell Write-Host "Cleaning up test environment..." @@ -92,14 +97,14 @@ Write-Host "Cleanup completed!" ## Sharing test infrastructure -Tests run in parallel across multiple OS runners. To avoid rate limits or conflicts from excessive resource creation, -provision shared infrastructure once in `BeforeAll.ps1` and tear it down in `AfterAll.ps1`. Individual test files -should consume the shared infrastructure instead of creating their own. +Tests run in parallel across multiple OS runners. To limit resource creation and avoid rate limits or conflicts, +provision shared infrastructure once in `BeforeAll.ps1`. Remove it in `AfterAll.ps1`. +Individual test files should use the shared infrastructure instead of creating their own. ### Use deterministic naming with `$env:GITHUB_RUN_ID` -Use `$env:GITHUB_RUN_ID` (stable per workflow run, shared across OS runners) to build deterministic resource names. -This lets test files reference shared resources by name without passing state between jobs. +Use `$env:GITHUB_RUN_ID` to build deterministic resource names. The value is stable per workflow run and shared across OS runners. +Test files can then reference shared resources by name without state transfer between jobs. ```powershell # BeforeAll.ps1 @@ -108,13 +113,13 @@ $id = $env:GITHUB_RUN_ID $resourceName = "Test-$os-$id" ``` -Do **not** use `[guid]::NewGuid()` or `Get-Random` for shared resource names — these produce different values on -each runner and cannot be referenced by other jobs. +Do **not** use `[guid]::NewGuid()` or `Get-Random` for shared resource names. +These produce different values on each runner. Other jobs cannot derive those values. ### Clean up stale resources from previous failed runs -If a previous workflow run failed before teardown completed, stale resources may remain. Start `BeforeAll.ps1` by -removing any resources matching your naming prefix before creating new ones: +After a failed workflow run, stale resources can remain if teardown does not complete. +At the start of `BeforeAll.ps1`, remove resources with the naming prefix before you create others: ```powershell # Remove stale resources from previous failed runs @@ -126,7 +131,7 @@ New-Resource -Name "Test-$os-$id" ### Tests reference shared resources — they do not create them -Test files should fetch the shared resource by its deterministic name, not create new resources: +Test files should get the shared resource by its deterministic name, not create another resource: ```powershell # Inside a test file @@ -137,12 +142,12 @@ BeforeAll { } ``` -Test-specific ephemeral resources (for example, secrets, variables, or temporary items) can still be created and -cleaned up within each test file. Only long-lived or expensive resources should be shared. +Test files can create and remove test-specific resources, such as secrets, variables, or temporary items. +Test files should share only long-lived or expensive resources. ### Naming conventions -Use a consistent naming scheme so that resources are easy to identify and clean up. A recommended pattern: +Use a consistent naming scheme to identify and remove resources. The following table gives recommended patterns: | Resource | Pattern | Example | |-------------------|---------------------------------------|----------------------------| @@ -151,8 +156,8 @@ Use a consistent naming scheme so that resources are easy to identify and clean | Secret / variable | `{TestName}_{OS}_{RunID}` | `Secrets_Linux_1234` | | Environment | `{TestName}-{OS}-{RunID}` | `Secrets-Linux-1234` | -When tests use multiple authentication contexts that share the same runner, include a token or context identifier in -the name to avoid collisions (for example, `Test-{OS}-{ContextID}-{RunID}`). +If multiple authentication contexts share a runner, include a token or context identifier in each resource name to prevent collisions. +For example, use `Test-{OS}-{ContextID}-{RunID}`. ## Related From 6744ca27f2b69c47a0a1d1d2d95a972611347fc0 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 4 Nov 2026 13:34:49 +0100 Subject: [PATCH 3/6] Give module coordination and review explicit author actions --- .../module-development-orchestration.md | 108 +++++++++--------- .../guides/validating-before-review.md | 63 +++++----- 2 files changed, 86 insertions(+), 85 deletions(-) diff --git a/docs/content/guides/module-development-orchestration.md b/docs/content/guides/module-development-orchestration.md index cdb029c1..fcef0d4c 100644 --- a/docs/content/guides/module-development-orchestration.md +++ b/docs/content/guides/module-development-orchestration.md @@ -1,18 +1,17 @@ --- title: Module development orchestration -description: Coordinate substantial module work across an orchestrator session and narrowly scoped child sessions, then integrate it safely for release. +description: Coordinate scoped module changes through an orchestrator, child sessions, and verified integration. --- # Module development orchestration -Substantial module work is easier to review and integrate when it is split into -small, independently verifiable changes. Use one parent (orchestrator) session -to own the plan and integration, and use narrowly scoped child sessions for the -work that can proceed independently. +Coordinate module work as small, independently verifiable changes. Use one +parent (orchestrator) session for the plan and integration. Assign independent +work to narrowly scoped child sessions. -This complements [Module bootstrap](../get-started/module-bootstrap.md). During -bootstrap, the shared branch is an **integration branch** for the load-bearing -core. For an existing module, follow the repository's +During [Module bootstrap](../get-started/module-bootstrap.md), the shared +**integration branch** holds the load-bearing core. For an existing module, +follow the repository's [trunk-based development](../specification/principles-and-practices.md#trunk-based-development) default: child pull requests use short-lived branches and target `main`. Use a stacked pull request only when a dependency requires it. @@ -27,36 +26,34 @@ The orchestrator: - creates the bootstrap integration branch and its draft pull request to `main` when the module needs one - gives each child one reviewable unit of work and the branch it must target -- keeps shared design decisions, naming, and cross-cutting changes coherent +- keeps shared design decisions, naming, and cross-cutting changes consistent - reviews each child pull request, runs the relevant validation, and integrates it into the shared branch - owns release readiness for the coordinated change set -The orchestrator coordinates the work; it does not become a second place where -the implementation is silently changed. Changes outside a child's scope should -become a new child task or an explicitly recorded decision. +The orchestrator does not change a child's implementation without a recorded +scope decision. For changes outside a child's scope, the orchestrator should +create a separate child task or record an explicit decision. ### Child session -A child session owns one cohesive change, such as one public function and its -tests, one documentation page, or one focused fix. A child should be able to -describe its change without referring to unrelated planned work. +A child session owns one cohesive change. Examples include one public function +with tests, one documentation page, or one focused fix. A child should be able +to describe its change without references to unrelated planned work. -Each child: +For each assigned change: -1. starts from `main`, or from the bootstrap integration branch when one is - required -2. opens a **draft pull request** targeting `main`, or the bootstrap integration - branch when one is required -3. implements and validates only its assigned scope -4. updates the documentation and tests required by that scope -5. reports the result to the orchestrator before asking for integration +1. Start from `main` or the required bootstrap integration branch. +2. Open a **draft pull request** that targets the same branch. +3. Implement only the assigned scope. Validate the assigned change. +4. Update the documentation and tests required by that scope. +5. Before you request integration, report the result to the orchestrator. -Use the repository's normal [branching and merging +Follow the repository's [branching and merging practice](https://msx.no/docs/Ways-of-Working/Branching-and-Merging/) and the -shared [workflow](https://msx.no/docs/Ways-of-Working/Workflow/) for the -ordinary branch, draft PR, implementation, test, and review loop. This page -only describes how to coordinate several such changes. +shared [workflow](https://msx.no/docs/Ways-of-Working/Workflow/) for branches, +draft PRs, implementation, tests, and review. This page describes how to +coordinate those changes. ## Coordination protocol @@ -73,9 +70,9 @@ The orchestrator's handoff should include: - the validation expected before the child reports completion - the orchestrator session's identifier or communication channel -If the child discovers a missing prerequisite or a conflicting design choice, -it should stop at that boundary and report it rather than expanding its scope -silently. +If a prerequisite is missing or a design decision conflicts, the child should +stop at that boundary. The child should report the problem instead of +expanding its scope without a record. ### Require a useful completion report @@ -88,50 +85,53 @@ The child reports: - decisions or risks the orchestrator must review - follow-up issues for work that does not belong in the child pull request -The orchestrator treats this as input to review, not as a substitute for -review. Read the diff, verify the acceptance criteria, and run the smallest -relevant checks before merging. Use +The completion report does not replace review. Before you merge, read the +diff. Make sure that it satisfies the acceptance criteria. Run the smallest +relevant checks. Use [Validating before review](validating-before-review.md) for the PSModule -specific validation pass. +validation pass. ### Integrate deliberately -Merge children only after their checks and review are complete. Merge -independent children into `main` in any order. For dependent work, either wait -for the prerequisite to merge or make the dependency explicit in a stacked -branch arrangement; do not make a child appear independent by copying -unreviewed changes. During bootstrap, merge children into the integration -branch, then merge that branch to `main` when the load-bearing core is ready. +After checks and review are complete, merge independent child pull requests +into `main` in any order. For dependent work, wait for the prerequisite to +merge or use an explicit stacked branch arrangement. Do not copy unreviewed +changes to make a child appear independent. -Keep `main` or the bootstrap integration branch buildable. Resolve conflicts in -the orchestrator's context, rerun affected checks after integration, and record -any cross-cutting decision in the relevant pull request or issue. +During bootstrap, merge child pull requests into the integration branch. +When the load-bearing core is ready, merge that branch to `main`. + +Keep `main` or the bootstrap integration branch buildable. Resolve conflicts +in the orchestrator's context. After integration, rerun the affected checks. +Record cross-cutting decisions in the relevant pull request or issue. ## Release readiness -Release readiness is a property of the integrated change, not a reason to keep -a long-lived release branch. Before marking a bootstrap integration pull -request ready, or reporting a coordinated trunk-based change complete, confirm: +Release readiness applies to the integrated change. It does not justify a +long-lived release branch. Before you mark a bootstrap integration pull +request ready, examine the integrated change against these conditions. +Apply the same conditions before you report a coordinated trunk-based change +complete: - every child pull request is merged, closed with a documented reason, or explicitly deferred with a follow-up issue - the integrated branch passes the applicable build, test, lint, and documentation checks -- the final tree still follows +- the final tree follows [Structuring your module](structuring-your-module.md), the module [repository standard](../reference/repository-standard.md), and the [test specification](../reference/test-specification.md) - user-facing documentation, examples, and generated-help inputs describe the integrated behavior -- the parent or coordinating pull request records the outcome, links the child - pull requests when one exists, and identifies related issues without claiming +- if a parent or coordinating pull request exists, it records the outcome, + links the child pull requests, and identifies related issues without claiming unrelated work - the version and prerelease intent match [Versioning and releases](versioning-and-releases.md) -If the change is not ready, keep the relevant pull request in draft and create -another focused child task or follow-up issue. Once it is ready, follow [Your -first release](../get-started/your-first-release.md) and the canonical MSX +If the change is not ready, keep the relevant pull request in draft. +Create a focused child task or follow-up issue for the remaining work. +When the change is ready, follow [Your first release](../get-started/your-first-release.md) and the canonical MSX [definition of ready for review](https://msx.no/docs/Ways-of-Working/Definition-of-Ready-and-Done/#definition-of-ready-for-review). ## Relationship to other work @@ -140,6 +140,6 @@ first release](../get-started/your-first-release.md) and the canonical MSX needs a load-bearing core before its first release. - For an existing module, use short-lived topic branches targeting `main`, as described in [Principles and practices](../specification/principles-and-practices.md). -- Use a stacked pull request only when the changes genuinely depend on one - another; see [MSX branching and +- Use a stacked pull request only when one change depends on another. + See [MSX branching and merging](https://msx.no/docs/Ways-of-Working/Branching-and-Merging/). diff --git a/docs/content/guides/validating-before-review.md b/docs/content/guides/validating-before-review.md index 4be25bfd..ad4cec6e 100644 --- a/docs/content/guides/validating-before-review.md +++ b/docs/content/guides/validating-before-review.md @@ -1,88 +1,89 @@ --- title: Validating before review -description: PSModule-specific validation checks that extend the shared MSXOrg Build/Implement workflow step before a draft pull request is marked ready. +description: Validate a module change against design, documentation, and PowerShell requirements before independent review. --- # Validating before review -Use this page after scaffolding a module change or implementing a function and before you finish self-review or mark a draft pull request ready. It extends the shared MSXOrg [Workflow Build step](https://msx.no/docs/Ways-of-Working/Workflow/#build) and [Implement guidance](https://msx.no/docs/Ways-of-Working/Workflow-Stages/Implement/) with the PSModule-specific validation checks that module repositories must pass. +Use this sequence after you scaffold a module change or implement a function. Run it before you complete self-review or mark a draft pull request ready. It extends the shared MSXOrg [Workflow Build step](https://msx.no/docs/Ways-of-Working/Workflow/#build) and [Implement guidance](https://msx.no/docs/Ways-of-Working/Workflow-Stages/Implement/). Module repositories must satisfy these PSModule-specific validation requirements. -Do not repeat the shared workflow here. Follow the shared branch → draft PR → implement → test → self-review loop first, then run this PSModule pass to confirm the change still fits the module's design, documentation, and PowerShell standards. +Follow the shared branch → draft PR → implement → test → self-review loop first. Then run this author-side validation sequence for module design, documentation, and PowerShell standards. ## Validation sequence 1. **Module design alignment** - Confirm that the change fits the module's archetype and the module-specific design rules before reviewing individual files. + Before you review individual files, make sure that the change fits the module's archetype and design rules. - Check: + Make sure that: - - the module still follows the right archetype from [Module types](../reference/module-types.md) - - the change respects the layout, private-helper boundaries, context rules, and SOLID guidance in [PowerShell module standard](../reference/powershell-module-standard.md) + - the module follows the applicable archetype from [Module types](../reference/module-types.md) + - the change follows the layout, private-helper boundaries, context rules, and SOLID guidance in [PowerShell module standard](../reference/powershell-module-standard.md) - the function belongs in this module instead of a different module, a shared helper, or a follow-up issue - A human contributor or agent should be able to explain why this change belongs in this module, in this shape, without inventing new local rules. + A contributor or agent should be able to explain why this change and its design belong in this module. The explanation should not introduce local rules. 2. **Module documentation** - Confirm that the repository-level and group-level documentation still matches the delivered behavior. + Make sure that the repository-level and group-level documentation describes the delivered behavior. - Check: + Make sure that: - - `README.md` still answers the start-page questions and reflects any user-visible behavior, prerequisites, or setup changes from [Repository Standard](../reference/repository-standard.md#readme-default) - - the relevant public command-group overview page (`src/functions/public//.md`) exists or is updated when the change affects that group's purpose or usage, per [PowerShell module standard](../reference/powershell-module-standard.md#repository-layout) - - any module-level documentation under `docs/` or other published surfaces is updated when the change adds or changes guidance that should not live only in comment-based help + - `README.md` answers the start-page questions and reflects user-visible behavior, prerequisites, or setup changes from [Repository Standard](../reference/repository-standard.md#readme-default) + - the relevant public command-group overview page (`src/functions/public//.md`) exists or reflects changes to that group's purpose or usage, as required by [PowerShell module standard](../reference/powershell-module-standard.md#repository-layout) + - module-level documentation under `docs/` or other published surfaces includes guidance that should not appear only in comment-based help - If the change teaches the user something new, confirm that the user can discover it from the published documentation surfaces, not only from the diff. + If the change affects user guidance, make sure that users can find it in published documentation, not only the diff. 3. **Function structure** - Confirm that each changed function still follows the expected repository anatomy. + Make sure that each changed function follows the repository layout. - Check: + Make sure that: - public functions live under `src/functions/public//` and private helpers live under `src/functions/private//` - file placement, grouping, and exported surface match [Structuring your module](structuring-your-module.md) and the layout rules in [PowerShell module standard](../reference/powershell-module-standard.md#repository-layout) - there are no nested helper functions, multi-function files, or naming shortcuts that break the "one declaration per file" rule - This step is about shape, not behavior: the goal is that a reader or tool can find the module surface and its helpers exactly where PSModule expects them. + This step concerns file layout, not function behavior. The layout lets readers and tools locate the module's public functions and private helpers. 4. **Function documentation** - Confirm that every changed function carries complete comment-based help and that the help matches the implementation contract. + Make sure that every changed function has complete comment-based help that matches the implementation contract. - Check: + Make sure that: - comment-based help is present for every changed function, including private helpers - help sections, examples, `.INPUTS`, `.OUTPUTS`, and parameter documentation match the function contract from [MSX PowerShell Functions](https://msx.no/docs/Coding-Standards/PowerShell/Functions/) - every public function has a first `.LINK` entry using an absolute HTTPS URL whose path matches the generated command documentation path - - public-function links and usage examples are current enough that generated documentation will stay accurate + - public-function links resolve and usage examples match the implemented parameters and outputs - Do not treat help as optional cleanup. In PSModule repositories, the function help is part of the delivered behavior. + Function help is part of the delivered behavior in PSModule repositories. Do not defer help as optional cleanup. 5. **PowerShell best practices** - Confirm that the implementation still reads like idiomatic PowerShell after the mechanical checks pass. + After the mechanical checks pass, review the implementation against the PowerShell standards. - Check: + Make sure that: - advanced-function structure, parameter typing and validation, `ShouldProcess`, output behavior, and error handling align with [MSX PowerShell](https://msx.no/docs/Coding-Standards/PowerShell/) and [MSX PowerShell Functions](https://msx.no/docs/Coding-Standards/PowerShell/Functions/) - - the code also satisfies the PSModule-specific conventions in [PowerShell module standard](../reference/powershell-module-standard.md), especially around private helpers, context handling, and repository layout - - PSScriptAnalyzer warnings are addressed or intentionally justified, but review does not stop there; also look for awkward parameter design, leaky transport details, non-idiomatic output, or code that technically passes lint but is not good PowerShell + - the code satisfies the PSModule-specific conventions in [PowerShell module standard](../reference/powershell-module-standard.md), including private helpers, context handling, and repository layout + - PSScriptAnalyzer warnings have fixes or intentional justifications - PSScriptAnalyzer is part of the validation loop, not the whole loop. + Do not limit the review to PSScriptAnalyzer. Also examine parameter design, exposed transport details, output behavior, and deviations from PowerShell conventions, even when lint passes. 6. **Coding standards alignment** - Run one final cross-check against the shared MSX coding standards before leaving self-review. + Before you complete self-review, compare the change with the shared MSX coding standards. - Check: + Make sure that: - naming, documentation, error handling, testing expectations, and security posture align with the relevant pages under [MSX Coding Standards](https://msx.no/docs/Coding-Standards/) - - the change follows the shared "written once, referenced everywhere" rule by linking canonical guidance instead of copying it into local docs or code comments, as described in [Agentic Development](https://msx.no/docs/Capabilities/agentic-development/) - - the draft PR description, issue progress, and any follow-up issues reflect what actually shipped and what still belongs out of scope + - the change follows the shared "written once, referenced everywhere" rule from [Agentic Development](https://msx.no/docs/Capabilities/agentic-development/) + - local documentation and code comments link to canonical guidance instead of copying it + - the draft PR description, issue progress, and follow-up issues describe the delivered change and its exclusions - This is the last author-side gate before a PSModule draft PR is ready for independent review. + This completes the author-side validation before independent review of a PSModule draft PR. ## Where this connects From 561da8677670e7fee725c9ca7097050c09718665 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 4 Nov 2026 13:38:22 +0100 Subject: [PATCH 4/6] Give plugin skill authors direct scoped instructions --- docs/content/guides/writing-plugin-skills.md | 75 ++++++++++---------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/docs/content/guides/writing-plugin-skills.md b/docs/content/guides/writing-plugin-skills.md index cbc5a9c1..7d82c026 100644 --- a/docs/content/guides/writing-plugin-skills.md +++ b/docs/content/guides/writing-plugin-skills.md @@ -1,27 +1,26 @@ --- title: Writing plugin skills -description: Design, author, validate, and maintain thin PSModule plugin skills that point to shared documentation. +description: Create and maintain plugin skills with agent-specific instructions and links to shared guidance. --- # Writing plugin skills -Use this guide when creating or changing a skill in the PSModule plugin. A -skill is an operational entry point for an agent; shared process and policy -belongs in the documentation structure so people and agents can use the same -source of truth. +Use this guide to create or change a skill in the PSModule plugin. +A skill is an agent's entry point. Shared process and policy belong in the +documentation, where people and agents use the same source. ## Keep skills thin -Put common explanations, repository policy, standards, and user-facing +Put shared explanations, repository policy, standards, and user-facing procedures in the appropriate `docs/content/` page. Keep `SKILL.md` focused on the agent-specific information needed to apply that guidance: -- when the skill should be used and when it should not; -- the agent's operating sequence and required handoffs; -- explicit stop conditions and escalation boundaries; +- when the skill should be used and when it should not. +- the agent's operating sequence and required handoffs. +- explicit stop conditions and escalation boundaries. - the repository-specific validation and report-back contract. -The skill should link to the shared guide near its beginning. Do not copy +The skill should link to the shared guide near its start. Do not copy organization-wide MSX rules, module standards, or long tutorials into the skill. Link to the canonical source instead. @@ -36,54 +35,56 @@ Create one directory per skill: Use lowercase, descriptive, hyphen-separated identifiers. Start `SKILL.md` with front matter containing the matching `name` and a concise `description`. -The description should make the skill discoverable without embedding the full -procedure. +The description should identify when to use the skill without the full procedure. After the front matter, include: -1. a short purpose statement and the link to the shared documentation; -2. agent-specific operating instructions; -3. explicit stop conditions; -4. references to related repository and canonical MSX guidance. +1. State the purpose. Link to the shared documentation. +2. Add agent-specific operating instructions. +3. State explicit stop conditions. +4. Link to related repository and canonical MSX guidance. -Prefer short imperative instructions, checklists, and handoff fields over -background material. Do not include stale vendor-specific model recommendations -or obsolete tool instructions. If a procedure changes for both users and -agents, update the documentation guide first and reduce the skill to a pointer -plus the remaining agent contract. +Prefer short imperative instructions, checklists, and handoff fields to +background explanations. Do not include model recommendations or tool +instructions that no longer apply. If a procedure changes for both users and +agents, update the documentation guide first. Then reduce the skill to a link +and the remaining agent-specific instructions. ## Plugin integration -Inspect the existing plugin before editing. Preserve its `plugin.json` -metadata and directory conventions. Add the new skill to the plugin README's +Before you edit, examine the existing plugin. Preserve its `plugin.json` +metadata and directory conventions. Add the skill to the plugin README's discoverability list with a repository-relative link. Do not add a second manifest or duplicate marketplace registration for an individual skill. Keep the skill's scope explicit. If it coordinates child sessions or other -agents, define the parent owner, child boundary, expected handoff, validation, -report-back, and stop conditions. Do not silently broaden a skill into -unrelated repository work. +agents, define the parent owner and each child's scope. +Specify handoffs, validation, completion reports, and stop conditions. +Do not broaden a skill into unrelated repository work without an explicit scope decision. ## Validation Run the smallest existing checks that cover the changed surfaces: -- `git diff --check`; -- repository Markdown and natural-language lint when available; -- plugin and marketplace metadata parsing; +- `git diff --check`. +- repository Markdown and natural-language lint when available. +- plugin and marketplace metadata parsing. - `zensical build --clean` when documentation or navigation changes. -Review every relative link from the skill and guide, the final plugin README -entry, and the diff for duplicated policy, stale instructions, accidental -generated files, or unrelated changes. Report the draft PR URL, files changed, -validation outcomes, policy decisions, and blockers to the owning session. +Review every relative link from the skill and guide. Make sure that the plugin +README entry identifies the skill and links to it. +Examine the diff for duplicate policy, outdated instructions, generated files, +or unrelated changes. +Report the draft PR URL, changed files, validation results, policy decisions, +and blockers to the owning session. ## Maintenance rule -When shared process changes, update the documentation page and its navigation, -then make each dependent skill point to the revised source. When only an -agent-specific trigger, handoff, stop condition, or tool boundary changes, -update the skill without duplicating the common documentation. +When shared process changes, update the documentation page and its navigation. +Then make each dependent skill link to the revised source. +When only the agent contract changes, update the skill. Agent-specific changes +include triggers, handoffs, stop conditions, and tool boundaries. +Do not duplicate shared documentation. ## References From 8fda4a814064dd64aa28a97631a226a4708e6f37 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 4 Nov 2026 13:44:52 +0100 Subject: [PATCH 5/6] Keep guide conditions short and Pester range wording exact --- docs/content/guides/module-development-orchestration.md | 4 ++-- docs/content/guides/writing-module-tests.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/content/guides/module-development-orchestration.md b/docs/content/guides/module-development-orchestration.md index fcef0d4c..426613a4 100644 --- a/docs/content/guides/module-development-orchestration.md +++ b/docs/content/guides/module-development-orchestration.md @@ -123,8 +123,8 @@ complete: [test specification](../reference/test-specification.md) - user-facing documentation, examples, and generated-help inputs describe the integrated behavior -- if a parent or coordinating pull request exists, it records the outcome, - links the child pull requests, and identifies related issues without claiming +- if a parent or coordinating pull request exists, it records the outcome and + links the child pull requests. It identifies related issues without claiming unrelated work - the version and prerelease intent match [Versioning and releases](versioning-and-releases.md) diff --git a/docs/content/guides/writing-module-tests.md b/docs/content/guides/writing-module-tests.md index db8208d8..4d481a74 100644 --- a/docs/content/guides/writing-module-tests.md +++ b/docs/content/guides/writing-module-tests.md @@ -11,7 +11,7 @@ The tests run in parallel across Windows, Linux, and macOS. ## Pester version -At the top of each `*.Tests.ps1`, declare a Pester **6.1.x** requirement: +At the top of each `*.Tests.ps1`, declare this Pester requirement: ```powershell #Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.1.0'; MaximumVersion = '6.*' } From d33a7e1773f9bde2527ae94fea7a8ed2c22a4acf Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Wed, 4 Nov 2026 13:47:35 +0100 Subject: [PATCH 6/6] Give plugin authoring steps an imperative lead --- docs/content/guides/writing-plugin-skills.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/guides/writing-plugin-skills.md b/docs/content/guides/writing-plugin-skills.md index 7d82c026..252df445 100644 --- a/docs/content/guides/writing-plugin-skills.md +++ b/docs/content/guides/writing-plugin-skills.md @@ -37,7 +37,7 @@ Use lowercase, descriptive, hyphen-separated identifiers. Start `SKILL.md` with front matter containing the matching `name` and a concise `description`. The description should identify when to use the skill without the full procedure. -After the front matter, include: +After the front matter, follow these steps: 1. State the purpose. Link to the shared documentation. 2. Add agent-specific operating instructions.