From c7a78650ed3da60d542875e068ae8d34d49152ea Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 1 Nov 2026 14:06:36 +0100 Subject: [PATCH 1/7] Guard the canonical release settings filename --- tests/PR-Format.Tests.ps1 | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/tests/PR-Format.Tests.ps1 b/tests/PR-Format.Tests.ps1 index ccff1a2..691dd26 100644 --- a/tests/PR-Format.Tests.ps1 +++ b/tests/PR-Format.Tests.ps1 @@ -67,6 +67,87 @@ Describe 'PR Format authoring contract' { } } +Describe 'Canonical release-settings authoring contract' { + BeforeAll { + $ErrorActionPreference = 'Stop' + $script:repositoryRoot = Split-Path -Path $PSScriptRoot -Parent + $script:documentationRoot = [IO.Path]::Combine($repositoryRoot, 'src', 'docs') + $releaseRoot = [IO.Path]::Combine($documentationRoot, 'Capabilities', 'release-management') + $script:releaseDesign = [IO.File]::ReadAllText([IO.Path]::Combine($releaseRoot, 'design.md')) + $script:releaseSpec = [IO.File]::ReadAllText([IO.Path]::Combine($releaseRoot, 'spec.md')) + } + + It 'uses only the canonical release.settings.yml filename in /' -ForEach @( + @{ Directory = @('Ways-of-Working'); File = 'PR-Format.md' } + @{ Directory = @('Ways-of-Working'); File = 'Automation-Labels.md' } + @{ Directory = @('Capabilities', 'release-management'); File = 'spec.md' } + @{ Directory = @('Capabilities', 'release-management'); File = 'design.md' } + @{ Directory = @('Capabilities', 'vscode-extension-framework'); File = 'design.md' } + ) { + $segments = [string[]] (@($documentationRoot) + $Directory + @($File)) + $guidance = [IO.File]::ReadAllText([IO.Path]::Combine($segments)) + + ($guidance -cmatch '\.github/release\.settings\.yml') | Should -BeTrue + ($guidance -cmatch 'release\.config\.yml') | Should -BeFalse + } + + It 'preserves the branch, bump, and path-filter settings in the examples' { + $releaseDesign | Should -Match ( + 'release-branches:\s+- branch: main\s+release-type: stable\s+' + + '- branch: dev\s+release-type: prerelease' + ) + $releaseDesign | Should -Match '(?m)^DefaultBump: minor\r?$' + $releaseDesign | Should -Match '(?m)^release-paths:\r?$' + $releaseDesign | Should -Match 'ordered\s+include/exclude globs \(excludes win\)' + } + + It 'preserves defaults, caller precedence, omission, and invalid-setting validation' { + $releaseDesign | Should -Match '`DefaultBump` accepts exactly `patch`, `minor`, or `major`' + $releaseDesign | Should -Match ( + 'default is `patch`; omitting the configuration file or field inherits that value' + ) + $releaseDesign | Should -Match ( + '(?s)shared defaults are overridden by repository settings in the optional\s+' + + '`[^`]+`, then by explicitly supplied supported caller\s+inputs for that invocation' + ) + $releaseDesign | Should -Match ( + 'Omitted caller inputs preserve repository settings;\s+' + + 'they do not overwrite them with an input''s default' + ) + $releaseDesign | Should -Match ( + 'Unknown setting names,\s+null or empty values, and values outside the documented set fail validation,\s+' + + 'even when a narrower override or bump label exists' + ) + } + + It 'keeps the optional file separate from target-route applicability' { + $releaseSpec | Should -Match ( + 'does not create a release pipeline, and its absence\s+does not opt a managed route out' + ) + $releaseDesign | Should -Match ( + 'A site deployment without a versioned artifact is\s+not by itself a release-managed route' + ) + $releaseSpec | Should -Match ( + 'A route without versioned release behavior MUST NOT require, apply, or report the ' + + '`Release decisions` block or any `release:\*` label' + ) + } + + It 'preserves required decision checks for managed routes without the optional file' { + $releaseSpec | Should -Match ( + 'Every PR targeting an invoked release route MUST receive a named release-decision CI check ' + + 'required by the branch ruleset or protection' + ) + $releaseSpec | Should -Match 'MUST block both manual and automated merge' + $releaseDesign | Should -Match ( + 'native producer routes, changes that will not publish, and repositories without\s+' + + 'a release configuration file' + ) + $releaseDesign | Should -Match 'path filters do not skip the validator' + $releaseDesign | Should -Match 'failure, pending execution, and\s+absence block merge' + } +} + Describe 'Repository PR-template-file policy' { BeforeAll { $ErrorActionPreference = 'Stop' From e65b9e0125d418852a993282e2b4cd5125f16d3a Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 1 Nov 2026 14:08:06 +0100 Subject: [PATCH 2/7] Use release.settings.yml in canonical guidance --- .../Capabilities/release-management/design.md | 18 +++++++++--------- .../Capabilities/release-management/spec.md | 6 +++--- .../vscode-extension-framework/design.md | 4 ++-- src/docs/Ways-of-Working/Automation-Labels.md | 2 +- src/docs/Ways-of-Working/PR-Format.md | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index 1466cc6..cd0b33b 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -8,7 +8,7 @@ description: How release management is built — effective defaults, owned overr The behavior in the [spec](spec.md) is delivered by shared release mechanics, through a reusable workflow or a native producer pipeline. A repository's effective release pipeline establishes which target routes are managed. The -optional `.github/release.config.yml` file refines those settings; it does not +optional `.github/release.settings.yml` file refines those settings; it does not create a release pipeline, and its absence does not opt a managed route out. Documented defaults make a managed route usable without per-PR bump labels; repository settings, supported caller inputs, and owned labels provide overrides. @@ -21,7 +21,7 @@ immutable output that another system consumes by version. - When a shared workflow or native producer pipeline delivers that release behavior, evaluate its release decision and require the pre-merge check. This - remains true when `.github/release.config.yml` is absent or the route does not + remains true when `.github/release.settings.yml` is absent or the route does not call a named shared workflow. - When the route has no versioned release behavior, Release Management does not apply. Omit the `Release decisions` block and every `release:*` label, @@ -57,7 +57,7 @@ A **release branch** is any branch configured as a release target, each with a a release branch produces **exactly one** release for all bundled changes. ```yaml -# .github/release.config.yml +# .github/release.settings.yml release-branches: - branch: main release-type: stable @@ -107,7 +107,7 @@ that supplied each decision before Build. Follow [Smart defaults, local overrides](../../Ways-of-Working/Principles/Software-Design.md#smart-defaults-local-overrides): shared defaults are overridden by repository settings in the optional -`.github/release.config.yml`, then by explicitly supplied supported caller +`.github/release.settings.yml`, then by explicitly supplied supported caller inputs for that invocation. Omitted caller inputs preserve repository settings; they do not overwrite them with an input's default. The implementing workflow or action documents its exact supported caller surface and validates it through @@ -121,13 +121,13 @@ even when a narrower override or bump label exists. | Setting | Shared default | Repository override | Supported caller override | | --- | --- | --- | --- | -| `DefaultBump` | `patch` | `DefaultBump` in `.github/release.config.yml` | Explicitly supplied caller override supported and documented by the invoked producer for this setting. | +| `DefaultBump` | `patch` | `DefaultBump` in `.github/release.settings.yml` | Explicitly supplied caller override supported and documented by the invoked producer for this setting. | For example, a repository can select minor as its normal level without requiring a minor label on every publishing PR: ```yaml -# .github/release.config.yml +# .github/release.settings.yml DefaultBump: minor ``` @@ -256,7 +256,7 @@ either: rerun the existing release with the same artifact and version under the ## Path filtering -When present, `.github/release.config.yml` declares `release-paths` as ordered +When present, `.github/release.settings.yml` declares `release-paths` as ordered include/exclude globs (excludes win). On an invoked route, the workflow **always runs** so validation executes on every merge; only the release step is skipped when no artifact-affecting path changed. @@ -494,12 +494,12 @@ release, and its runs are serialised like any other. | Surface | Where | | --- | --- | | Release Management applicability | effective target-route pipeline, including shared workflows and native producers | -| Release branches + type | optional `.github/release.config.yml`; the default branch is stable when omitted | +| Release branches + type | optional `.github/release.settings.yml`; the default branch is stable when omitted | | Default bump and overrides | documented shared `DefaultBump: patch`, repository settings, then supported caller inputs | | Explicit bump / prerelease / skip | `release:` PR label on an invoked route | | Pre-merge decision validation | named PR check required by the branch ruleset or protection | | Optional ad hoc release | `workflow_dispatch` inputs | -| Path filter | `.github/release.config.yml` | +| Path filter | `.github/release.settings.yml` | | Prerelease cleanup toggle | release config / workflow input | | Publishing targets | reusable-workflow input + GitHub environment; see [Publishing Targets](design-publishing-targets.md) | diff --git a/src/docs/Capabilities/release-management/spec.md b/src/docs/Capabilities/release-management/spec.md index 5ef9a80..38c470e 100644 --- a/src/docs/Capabilities/release-management/spec.md +++ b/src/docs/Capabilities/release-management/spec.md @@ -16,7 +16,7 @@ release CLI, a hand-edited version file, or a tagging convention. A target route participates when its effective pipeline produces a versioned, immutable output consumed by version. This includes a shared Release Management workflow and a native producer pipeline; the contract is not conditional on one -implementation's name. The optional `.github/release.config.yml` file refines a +implementation's name. The optional `.github/release.settings.yml` file refines a managed route's settings but does not create a release pipeline, and its absence does not opt a managed route out. @@ -41,7 +41,7 @@ If no, there is nothing to release and the pull request carries neither the ## Requirements - **Semantic versioning.** Versions follow [SemVer 2.0.0](https://semver.org/) (`vMAJOR.MINOR.PATCH`), derived automatically — never written by hand. -- **Release behavior determines applicability.** Release Management MUST evaluate every pull request targeting a managed release route, including native producer routes and routes without `.github/release.config.yml`. A route without versioned release behavior MUST NOT require, apply, or report the `Release decisions` block or any `release:*` label. +- **Release behavior determines applicability.** Release Management MUST evaluate every pull request targeting a managed release route, including native producer routes and routes without `.github/release.settings.yml`. A route without versioned release behavior MUST NOT require, apply, or report the `Release decisions` block or any `release:*` label. - **Producer compatibility is verified, not inferred.** Authors MUST verify the effective producer revision's settings and owned-label mapping. A differing released interface MUST have a verified adapter or producer/configuration migration before the canonical signals are used. Unsupported signals MUST block finalization and required decision validation, not become ignored skip requests or an excuse to classify a managed route as unmanaged. The producer's PR/release record owns its exact adoption actions. - **Settings have documented defaults and supported overrides.** Release automation MUST document its setting names, accepted values, shared defaults, and supported caller overrides. Repository settings MUST override shared defaults; explicitly supplied supported caller inputs MUST override repository settings for that invocation. Unknown settings and invalid supplied values MUST fail even when a narrower override or explicit bump label exists. Omission MUST inherit a documented default rather than require configuration to become usable. - **A resolved PR release decision.** `DefaultBump` accepts exactly `patch`, `minor`, or `major` and has the shared default `patch`. Multiple owned bump labels, or `release:skip` combined with another owned release label, MUST fail. A valid `release:skip` MUST select no release without resolving a bump. For publishing decisions, one owned `release:patch`, `release:minor`, or `release:major` label MUST take precedence over the valid effective default; without a bump label, that default MUST supply the level without requiring a per-PR bump label. If neither source resolves a valid level, automation MUST fail with an actionable decision error; it MUST NOT recover from invalid input by selecting patch. `release:prerelease` MAY use either the explicit or default bump; the mode alone does not supply a level. Bare or unrelated labels MUST be ignored. Conventional commit messages are **not** required. @@ -88,7 +88,7 @@ Because versions are semantic, immutable, and published once, a consumer can ado ## Success criteria - Merging an eligible PR with an explicit or configured bump produces a GitHub Release, a git tag, and (where one exists) a published artifact, with no manual step. -- A pull request targeting a managed release route, including a native producer route, is evaluated even when `.github/release.config.yml` is absent; an unmanaged route carries no release decision block, label, or check. +- A pull request targeting a managed release route, including a native producer route, is evaluated even when `.github/release.settings.yml` is absent; an unmanaged route carries no release decision block, label, or check. - With no repository setting, caller override, or bump label, a publishing PR resolves the documented patch default. A repository default and supported caller override resolve in that order, and an explicit owned bump label overrides the valid effective default. - The resolver records the effective value and its source. Invalid supplied settings and conflicting owned labels block merge even when another input would supply a valid level; no success-shaped fallback occurs. - Removing a bump override re-evaluates the PR check against the effective default; changing source, settings, or route inputs also re-evaluates it. A prior result does not validate different inputs. diff --git a/src/docs/Capabilities/vscode-extension-framework/design.md b/src/docs/Capabilities/vscode-extension-framework/design.md index ab8e226..b1f9a7e 100644 --- a/src/docs/Capabilities/vscode-extension-framework/design.md +++ b/src/docs/Capabilities/vscode-extension-framework/design.md @@ -204,7 +204,7 @@ Every external Action is pinned to a commit SHA; organization- or initiative-own | Explicit bump / prerelease / skip | owned pull-request label | | Default bump and overrides | shared `DefaultBump: patch`, repository settings, and supported caller inputs | | Pre-merge decision validation | version check required by the branch ruleset or protection | -| Release branches + path filter | `.github/release.config.yml` ([Release Management](../release-management/design.md)) | +| Release branches + path filter | `.github/release.settings.yml` ([Release Management](../release-management/design.md)) | | Marketplace publish tokens | a GitHub environment's secrets | | Extension manifest (`engines.vscode`, `contributes`, activation) | `package.json` | @@ -218,7 +218,7 @@ The template repository lays down the whole shape, mirroring `contributes`, `activationEvents`, and `main` pointing at the bundle. - the bundler config, `tsconfig.json`, and `.vscodeignore`. - `install/` — the hosted one-liner install scripts. -- `.github/` — the caller workflow, `vscode-extension.yml`, `release.config.yml`, +- `.github/` — the caller workflow, `vscode-extension.yml`, `release.settings.yml`, and `dependabot.yml`. ## Where this connects diff --git a/src/docs/Ways-of-Working/Automation-Labels.md b/src/docs/Ways-of-Working/Automation-Labels.md index fd3b443..64f4b63 100644 --- a/src/docs/Ways-of-Working/Automation-Labels.md +++ b/src/docs/Ways-of-Working/Automation-Labels.md @@ -60,7 +60,7 @@ This set applies only when the pull request's target route invokes Release Management, including through a native producer pipeline. An unmanaged route does not apply or report any `release:*` label, including `release:skip`. The optional -`.github/release.config.yml` file refines an invocation; its absence alone does +`.github/release.settings.yml` file refines an invocation; its absence alone does not determine whether the route invokes the capability. These labels are read by diff --git a/src/docs/Ways-of-Working/PR-Format.md b/src/docs/Ways-of-Working/PR-Format.md index 556dd40..c741204 100644 --- a/src/docs/Ways-of-Working/PR-Format.md +++ b/src/docs/Ways-of-Working/PR-Format.md @@ -167,7 +167,7 @@ target route. Inspect the effective pipeline and its inputs, including native producer pipelines that publish versioned artifacts without calling a named shared workflow. The [applicability contract](../Capabilities/release-management/design.md#applicability) is about the route's release behavior, not one implementation. The optional -`.github/release.config.yml` file refines the route's settings; its absence alone +`.github/release.settings.yml` file refines the route's settings; its absence alone does not prove that release management is absent. Verify the immutable producer revision's supported settings and owned-label @@ -411,7 +411,7 @@ from the actual base. When the target route does not invoke Release Management, omit this block and all `release:*` labels. Do not add `release:skip` merely because the repository -has no `.github/release.config.yml`. +has no `.github/release.settings.yml`. ### Assemble the body From 04998646b94859463ef37730f6c5b197a27efceb Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 1 Nov 2026 22:55:19 +0100 Subject: [PATCH 3/7] Guard solution settings naming and module compatibility --- tests/PR-Format.Tests.ps1 | 103 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/tests/PR-Format.Tests.ps1 b/tests/PR-Format.Tests.ps1 index 691dd26..c788be4 100644 --- a/tests/PR-Format.Tests.ps1 +++ b/tests/PR-Format.Tests.ps1 @@ -148,6 +148,109 @@ Describe 'Canonical release-settings authoring contract' { } } +Describe 'Solution-owned settings naming contract' { + BeforeAll { + $ErrorActionPreference = 'Stop' + $repositoryRoot = Split-Path -Path $PSScriptRoot -Parent + $script:documentationRoot = [IO.Path]::Combine($repositoryRoot, 'src', 'docs') + $script:namingPath = [IO.Path]::Combine($documentationRoot, 'Coding-Standards', 'Naming.md') + $script:naming = [IO.File]::ReadAllText($namingPath) + $script:settingsRule = [regex]::Match( + $naming, + '(?s)## Solution settings files\r?\n(?.*?)(?:\r?\n## |\z)' + ) + $script:moduleSettings = [IO.File]::ReadAllText( + [IO.Path]::Combine($documentationRoot, 'Initiatives', 'PSModule.md') + ) + } + + It 'defines the conventional settings filename once in the Naming standard' { + $settingsRule.Success | Should -BeTrue + $settingsRule.Groups['body'].Value | Should -Match ( + 'Solution-owned settings MUST use `\.settings\.yml` as their conventional filename' + ) + $owners = @( + [IO.Directory]::EnumerateFiles($documentationRoot, '*.md', [IO.SearchOption]::AllDirectories) | + Where-Object { [IO.File]::ReadAllText($_).Contains('`.settings.yml`') } + ) + + $owners.Count | Should -Be 1 + $owners[0] | Should -BeExactly $namingPath + } + + It 'excludes tool-owned filenames and YAML that is not solution settings' { + $settingsRule.Groups['body'].Value | Should -Match ( + 'Tool-mandated manifests, lockfiles, workflow filenames' + ) + $settingsRule.Groups['body'].Value | Should -Match ( + 'YAML files that are not solution-owned settings' + ) + } + + It 'leaves the settings directory with the owning solution' { + $settingsRule.Groups['body'].Value | Should -Match ( + 'Each solution documents its settings location' + ) + $settingsRule.Groups['body'].Value | Should -Match 'does not impose a shared directory' + } + + It 'preserves supported explicit custom paths instead of imposing a runtime restriction' { + $settingsRule.Groups['body'].Value | Should -Match 'documented explicit path override' + $settingsRule.Groups['body'].Value | Should -Match ( + 'does not remove that input or restrict otherwise supported custom paths' + ) + } + + It 'links / to the one naming rule' -ForEach @( + @{ Directory = @('Coding-Standards'); File = 'YAML.md' } + @{ Directory = @('Ways-of-Working'); File = 'Repository-Standard.md' } + @{ Directory = @('Capabilities', 'release-management'); File = 'design.md' } + @{ Directory = @('Initiatives'); File = 'PSModule.md' } + ) { + $segments = [string[]] (@($documentationRoot) + $Directory + @($File)) + $guidance = [IO.File]::ReadAllText([IO.Path]::Combine($segments)) + + $guidance | Should -Match 'Naming\.md#solution-settings-files' + $guidance | Should -Not -Match ([regex]::Escape('`.settings.yml`')) + } + + It 'retains PSModule.yml through SettingsPath for module release settings' { + $moduleSettings | Should -Match ( + 'supported settings default is `\.github/PSModule\.yml`, through `SettingsPath`' + ) + $moduleSettings | Should -Match 'including module release settings' + $moduleSettings | Should -Match ( + 'do not need a separate `\.github/release\.settings\.yml` file' + ) + $moduleSettings | Should -Not -Match '(?i)psmodule\.settings\.yml' + } + + It 'links the module compatibility boundary from /' -ForEach @( + @{ Directory = @('Ways-of-Working'); File = 'Repository-Standard.md' } + @{ Directory = @('Capabilities', 'release-management'); File = 'design.md' } + ) { + $segments = [string[]] (@($documentationRoot) + $Directory + @($File)) + $guidance = [IO.File]::ReadAllText([IO.Path]::Combine($segments)) + + $guidance | Should -Match 'Initiatives/PSModule\.md#module-settings' + } + + It 'distinguishes the release conventional filename from an implemented reader or renamed input' { + $path = [IO.Path]::Combine($documentationRoot, 'Capabilities', 'release-management', 'design.md') + $guidance = [IO.File]::ReadAllText($path) + + $guidance | Should -Match '`ConfigurationFile`' + $guidance | Should -Match 'does not implement a reader or rename its public input' + $guidance | Should -Match 'supported explicit custom paths' + $guidance | Should -Not -Match 'auto-release\.yml|release\.config\.yml' + } + + It 'points module settings to the verified canonical framework references' { + $moduleSettings | Should -Match 'https://psmodule\.io/Process-PSModule/reference/workflow-inputs/' + $moduleSettings | Should -Match 'https://psmodule\.io/Process-PSModule/reference/settings/' + } +} + Describe 'Repository PR-template-file policy' { BeforeAll { $ErrorActionPreference = 'Stop' From f0214185c21726f2637206ca202138489a156fb3 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 1 Nov 2026 22:56:50 +0100 Subject: [PATCH 4/7] Define canonical solution settings filenames and module exception --- src/docs/Capabilities/release-management/design.md | 8 +++++++- src/docs/Capabilities/release-management/spec.md | 2 +- src/docs/Coding-Standards/Naming.md | 12 ++++++++++++ src/docs/Coding-Standards/YAML.md | 2 ++ src/docs/Initiatives/PSModule.md | 8 +++++++- src/docs/Ways-of-Working/Repository-Standard.md | 4 +++- 6 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/docs/Capabilities/release-management/design.md b/src/docs/Capabilities/release-management/design.md index cd0b33b..76b3857 100644 --- a/src/docs/Capabilities/release-management/design.md +++ b/src/docs/Capabilities/release-management/design.md @@ -8,7 +8,7 @@ description: How release management is built — effective defaults, owned overr The behavior in the [spec](spec.md) is delivered by shared release mechanics, through a reusable workflow or a native producer pipeline. A repository's effective release pipeline establishes which target routes are managed. The -optional `.github/release.settings.yml` file refines those settings; it does not +release solution's optional `.github/release.settings.yml` file refines those settings; it does not create a release pipeline, and its absence does not opt a managed route out. Documented defaults make a managed route usable without per-PR bump labels; repository settings, supported caller inputs, and owned labels provide overrides. @@ -105,6 +105,12 @@ that supplied each decision before Build. ### Settings and caller overrides +The release solution uses `.github/release.settings.yml` under the [Naming standard](../../Coding-Standards/Naming.md#solution-settings-files). + +A filename convention does not implement a reader or rename its public input. Verify the immutable producer revision's declared settings input and default before adoption. `ConfigurationFile`, where exposed, remains the settings-path input; supported explicit custom paths follow that producer's contract. + +[Module settings](../../Initiatives/PSModule.md#module-settings) retain their supported initiative interface; the release-solution filename does not replace it. + Follow [Smart defaults, local overrides](../../Ways-of-Working/Principles/Software-Design.md#smart-defaults-local-overrides): shared defaults are overridden by repository settings in the optional `.github/release.settings.yml`, then by explicitly supplied supported caller diff --git a/src/docs/Capabilities/release-management/spec.md b/src/docs/Capabilities/release-management/spec.md index 38c470e..1dcba21 100644 --- a/src/docs/Capabilities/release-management/spec.md +++ b/src/docs/Capabilities/release-management/spec.md @@ -16,7 +16,7 @@ release CLI, a hand-edited version file, or a tagging convention. A target route participates when its effective pipeline produces a versioned, immutable output consumed by version. This includes a shared Release Management workflow and a native producer pipeline; the contract is not conditional on one -implementation's name. The optional `.github/release.settings.yml` file refines a +implementation's name. The release solution's optional `.github/release.settings.yml` file refines a managed route's settings but does not create a release pipeline, and its absence does not opt a managed route out. diff --git a/src/docs/Coding-Standards/Naming.md b/src/docs/Coding-Standards/Naming.md index 9a3db9e..126e788 100644 --- a/src/docs/Coding-Standards/Naming.md +++ b/src/docs/Coding-Standards/Naming.md @@ -34,6 +34,18 @@ Follow the **idiom of the language**, and be consistent within a codebase: - Never fight the language's conventions to impose a personal preference. The least-surprising name is the right name. - Files and folders follow the repository's established pattern. When starting fresh, prefer `kebab-case` for cross-platform safety (no case-sensitivity surprises between Windows, macOS, and Linux). +## Solution settings files + +Solution-owned settings MUST use `.settings.yml` as their conventional filename, where `` identifies the owning solution. One naming shape makes both the owner and the file's purpose discoverable. + +Each solution documents its settings location. This standard does not impose a shared directory or change settings schemas, defaults, or precedence. + +Tool-mandated manifests, lockfiles, workflow filenames, and YAML files that are not solution-owned settings follow their tool's contract, not this settings-filename convention. + +A reader MAY expose a documented explicit path override. This convention does not remove that input or restrict otherwise supported custom paths. + +A supported naming exception MUST be documented by the owning solution. Verify the reader before changing a released conventional filename, and keep exact migration actions in its [release record](../Capabilities/release-management/design.md#release-notes). Review verifies adoption against the reader contract; documentation-contract tests guard this rule and its linked guidance. + ## Scope and length Name length should track scope. A loop index living for three lines can be `i`. A module-level export read across the codebase earns a full, descriptive name. The wider the reach, the more the name has to carry on its own. diff --git a/src/docs/Coding-Standards/YAML.md b/src/docs/Coding-Standards/YAML.md index e0228b1..42091d5 100644 --- a/src/docs/Coding-Standards/YAML.md +++ b/src/docs/Coding-Standards/YAML.md @@ -27,6 +27,8 @@ One exception exists, and only because the tool allows no alternative: `.pre-commit-config.yaml`. Where a tool hard-codes the long form, follow the tool and note it; otherwise, `.yml`. +Solution-owned settings filenames follow the [Naming standard](Naming.md#solution-settings-files). + ## Lint every file `yamllint` MUST run against every YAML file in the repository — locally through diff --git a/src/docs/Initiatives/PSModule.md b/src/docs/Initiatives/PSModule.md index 1a237a4..b762be3 100644 --- a/src/docs/Initiatives/PSModule.md +++ b/src/docs/Initiatives/PSModule.md @@ -12,7 +12,7 @@ It is two things at once: - **A module-building workflow** — GitHub Actions and reusable workflows that automate the whole PowerShell delivery lifecycle: build, test, version, and publish. - **The modules themselves** — a growing collection of reusable PowerShell modules built with that workflow. -PSModule inherits the [Coding Standards](../Coding-Standards/index.md) and [Ways of Working](../Ways-of-Working/index.md) from this site and adds only what is specific to the framework. The end-to-end workflow that ships every module — [Process-PSModule](https://psmodule.io/docs/Modules/Process-PSModule/) — is documented at its canonical site. +PSModule inherits the [Coding Standards](../Coding-Standards/index.md) and [Ways of Working](../Ways-of-Working/index.md) from this site and adds only what is specific to the framework. The end-to-end workflow that ships every module — [Process-PSModule](https://psmodule.io/Process-PSModule/) — is documented at its canonical site. ## Target audience @@ -23,6 +23,12 @@ PSModule inherits the [Coding Standards](../Coding-Standards/index.md) and [Ways In both cases, users are also integrators: these are roles of the same audience, not separate classes of customer. Repository READMEs [declare their audience](../Ways-of-Working/Readme-Driven-Context.md#target-audience) by adopting this definition or stating their specialization. +## Module settings + +The supported settings default is `.github/PSModule.yml`, through `SettingsPath`. It controls module-pipeline configuration, including module release settings. Module repositories do not need a separate `.github/release.settings.yml` file. + +This is a supported naming exception under the [Naming standard](../Coding-Standards/Naming.md#solution-settings-files), not a requirement to migrate module settings. The [workflow input reference](https://psmodule.io/Process-PSModule/reference/workflow-inputs/) owns supported `SettingsPath` controls; the [settings reference](https://psmodule.io/Process-PSModule/reference/settings/) owns the module settings keys and defaults. Changing this supported interface requires a separate reader and migration change. + ## Canonical boundary Cross-org standards and reusable architecture are canonical in MSXOrg/docs, including: diff --git a/src/docs/Ways-of-Working/Repository-Standard.md b/src/docs/Ways-of-Working/Repository-Standard.md index 35de7cc..fbf53e4 100644 --- a/src/docs/Ways-of-Working/Repository-Standard.md +++ b/src/docs/Ways-of-Working/Repository-Standard.md @@ -46,7 +46,9 @@ instead of carrying repository-specific baseline files that have no function there. Its own README, agent routes, text handling, and ignore rules remain local; only supported community defaults are inherited by other repositories. -Repository types may require additional files. For example, a PowerShell module may require `.github/PSModule.yml`, while a GitHub Action may require `action.yml`. +Repository types may require additional files. For example, a PowerShell module may require [`.github/PSModule.yml`](../Initiatives/PSModule.md#module-settings), while a GitHub Action may require `action.yml`. + +Solution-owned settings filenames follow the [Naming standard](../Coding-Standards/Naming.md#solution-settings-files). ### Required files by type From 734145479ede01a7ccdeb4eb29950d405ed99a09 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 1 Nov 2026 23:11:48 +0100 Subject: [PATCH 5/7] Document the retained VS Code settings naming exception --- .../vscode-extension-framework/design.md | 2 ++ tests/PR-Format.Tests.ps1 | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/docs/Capabilities/vscode-extension-framework/design.md b/src/docs/Capabilities/vscode-extension-framework/design.md index b1f9a7e..9e48cf1 100644 --- a/src/docs/Capabilities/vscode-extension-framework/design.md +++ b/src/docs/Capabilities/vscode-extension-framework/design.md @@ -197,6 +197,8 @@ Every external Action is pinned to a commit SHA; organization- or initiative-own ## Configuration surface +`.github/vscode-extension.yml` is the documented template settings interface and a [supported naming exception](../../Coding-Standards/Naming.md#solution-settings-files). The naming convention does not change this interface or its settings keys; a filename change requires a verified reader and a separate template/caller migration. + | Surface | Where | | --- | --- | | Adoption (opt-in) | a short caller workflow that calls the reusable workflow | diff --git a/tests/PR-Format.Tests.ps1 b/tests/PR-Format.Tests.ps1 index c788be4..b9be1aa 100644 --- a/tests/PR-Format.Tests.ps1 +++ b/tests/PR-Format.Tests.ps1 @@ -249,6 +249,22 @@ Describe 'Solution-owned settings naming contract' { $moduleSettings | Should -Match 'https://psmodule\.io/Process-PSModule/reference/workflow-inputs/' $moduleSettings | Should -Match 'https://psmodule\.io/Process-PSModule/reference/settings/' } + + It 'retains the VS Code template settings interface as a documented naming exception' { + $path = [IO.Path]::Combine( + $documentationRoot, 'Capabilities', 'vscode-extension-framework', 'design.md' + ) + $guidance = [IO.File]::ReadAllText($path) + + $guidance | Should -Match ( + '`\.github/vscode-extension\.yml` is the documented template settings interface' + ) + $guidance | Should -Match 'Naming\.md#solution-settings-files' + $guidance | Should -Match 'supported naming exception' + $guidance | Should -Match 'does not change this interface or its settings keys' + $guidance | Should -Match 'a verified reader and a separate template/caller migration' + $guidance | Should -Not -Match 'vscode-extension\.settings\.yml' + } } Describe 'Repository PR-template-file policy' { From 3d7c58e7d90d7aab04aebae0ffb4ad61aa8ab332 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Mon, 2 Nov 2026 18:50:50 +0100 Subject: [PATCH 6/7] Remove documentation content tests --- src/docs/Coding-Standards/Naming.md | 2 +- tests/PR-Format.Tests.ps1 | 329 ---------------------------- 2 files changed, 1 insertion(+), 330 deletions(-) delete mode 100644 tests/PR-Format.Tests.ps1 diff --git a/src/docs/Coding-Standards/Naming.md b/src/docs/Coding-Standards/Naming.md index 126e788..a0a7b68 100644 --- a/src/docs/Coding-Standards/Naming.md +++ b/src/docs/Coding-Standards/Naming.md @@ -44,7 +44,7 @@ Tool-mandated manifests, lockfiles, workflow filenames, and YAML files that are A reader MAY expose a documented explicit path override. This convention does not remove that input or restrict otherwise supported custom paths. -A supported naming exception MUST be documented by the owning solution. Verify the reader before changing a released conventional filename, and keep exact migration actions in its [release record](../Capabilities/release-management/design.md#release-notes). Review verifies adoption against the reader contract; documentation-contract tests guard this rule and its linked guidance. +A supported naming exception MUST be documented by the owning solution. Verify the reader before changing a released conventional filename, and keep exact migration actions in its [release record](../Capabilities/release-management/design.md#release-notes). Review verifies adoption against the reader contract. ## Scope and length diff --git a/tests/PR-Format.Tests.ps1 b/tests/PR-Format.Tests.ps1 deleted file mode 100644 index b9be1aa..0000000 --- a/tests/PR-Format.Tests.ps1 +++ /dev/null @@ -1,329 +0,0 @@ -#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '6.0.0'; MaximumVersion = '6.*' } - -Describe 'PR Format authoring contract' { - BeforeAll { - $ErrorActionPreference = 'Stop' - $repositoryRoot = Split-Path -Path $PSScriptRoot -Parent - $documentationRoot = [IO.Path]::Combine($repositoryRoot, 'src', 'docs', 'Ways-of-Working') - $script:format = [IO.File]::ReadAllText([IO.Path]::Combine($documentationRoot, 'PR-Format.md')) - $script:recordExample = [regex]::Match( - $format, - '(?s)````markdown\r?\n(?.*?)\r?\n````' - ) - } - - It 'resolves artifact publication coverage before inspecting the scoped PR diff' { - $coveragePosition = $format.IndexOf('### Resolve release coverage first', [StringComparison]::Ordinal) - $reviewerPosition = $format.IndexOf('### Read the whole change', [StringComparison]::Ordinal) - - $coveragePosition | Should -BeGreaterOrEqual 0 - $reviewerPosition | Should -BeGreaterThan $coveragePosition - } - - It 'requires published and candidate identities separately from the scoped PR comparison' { - $requiredEvidence = @( - '| Product scope |' - '| Published artifact |' - '| Published source |' - '| Candidate source |' - '| Scoped PR comparison |' - ) - - foreach ($field in $requiredEvidence) { - $format | Should -Match ([regex]::Escape($field)) - } - } - - It 'retains one complete description example with one boundary and five ordered classifiers' { - $recordExample.Success | Should -BeTrue - $body = $recordExample.Groups['body'].Value - $boundary = [regex]::Escape('') - - [regex]::Matches($body, $boundary).Count | Should -Be 1 - $classifiers = @( - [regex]::Matches($body, '(?m)^## (Breaking|Removed|New|Changed|Fixed):') | - ForEach-Object { $_.Groups[1].Value } - ) - $classifiers.Count | Should -Be 5 - $classifiers -join ',' | Should -BeExactly 'Breaking,Removed,New,Changed,Fixed' - } - - It 'prompts every classifier for publication-baseline evidence' { - $recordExample.Success | Should -BeTrue - $prompt = [regex]::Escape('{{ Publication-baseline evidence:') - - [regex]::Matches($recordExample.Groups['body'].Value, $prompt).Count | Should -Be 5 - } - - It 'focuses on the authored record instead of repository file policy' { - $format | Should -Match '### Complete description example' - $format | Should -Not -Match 'PR-template|pull_request_template|GitHub PR template|inherited GitHub scaffold' - } - - It 'retains five affected-product integration-evidence prompts' { - $prompt = [regex]::Escape('For an affected integration template, identify its') - - [regex]::Matches($format, $prompt).Count | Should -Be 5 - } -} - -Describe 'Canonical release-settings authoring contract' { - BeforeAll { - $ErrorActionPreference = 'Stop' - $script:repositoryRoot = Split-Path -Path $PSScriptRoot -Parent - $script:documentationRoot = [IO.Path]::Combine($repositoryRoot, 'src', 'docs') - $releaseRoot = [IO.Path]::Combine($documentationRoot, 'Capabilities', 'release-management') - $script:releaseDesign = [IO.File]::ReadAllText([IO.Path]::Combine($releaseRoot, 'design.md')) - $script:releaseSpec = [IO.File]::ReadAllText([IO.Path]::Combine($releaseRoot, 'spec.md')) - } - - It 'uses only the canonical release.settings.yml filename in /' -ForEach @( - @{ Directory = @('Ways-of-Working'); File = 'PR-Format.md' } - @{ Directory = @('Ways-of-Working'); File = 'Automation-Labels.md' } - @{ Directory = @('Capabilities', 'release-management'); File = 'spec.md' } - @{ Directory = @('Capabilities', 'release-management'); File = 'design.md' } - @{ Directory = @('Capabilities', 'vscode-extension-framework'); File = 'design.md' } - ) { - $segments = [string[]] (@($documentationRoot) + $Directory + @($File)) - $guidance = [IO.File]::ReadAllText([IO.Path]::Combine($segments)) - - ($guidance -cmatch '\.github/release\.settings\.yml') | Should -BeTrue - ($guidance -cmatch 'release\.config\.yml') | Should -BeFalse - } - - It 'preserves the branch, bump, and path-filter settings in the examples' { - $releaseDesign | Should -Match ( - 'release-branches:\s+- branch: main\s+release-type: stable\s+' + - '- branch: dev\s+release-type: prerelease' - ) - $releaseDesign | Should -Match '(?m)^DefaultBump: minor\r?$' - $releaseDesign | Should -Match '(?m)^release-paths:\r?$' - $releaseDesign | Should -Match 'ordered\s+include/exclude globs \(excludes win\)' - } - - It 'preserves defaults, caller precedence, omission, and invalid-setting validation' { - $releaseDesign | Should -Match '`DefaultBump` accepts exactly `patch`, `minor`, or `major`' - $releaseDesign | Should -Match ( - 'default is `patch`; omitting the configuration file or field inherits that value' - ) - $releaseDesign | Should -Match ( - '(?s)shared defaults are overridden by repository settings in the optional\s+' + - '`[^`]+`, then by explicitly supplied supported caller\s+inputs for that invocation' - ) - $releaseDesign | Should -Match ( - 'Omitted caller inputs preserve repository settings;\s+' + - 'they do not overwrite them with an input''s default' - ) - $releaseDesign | Should -Match ( - 'Unknown setting names,\s+null or empty values, and values outside the documented set fail validation,\s+' + - 'even when a narrower override or bump label exists' - ) - } - - It 'keeps the optional file separate from target-route applicability' { - $releaseSpec | Should -Match ( - 'does not create a release pipeline, and its absence\s+does not opt a managed route out' - ) - $releaseDesign | Should -Match ( - 'A site deployment without a versioned artifact is\s+not by itself a release-managed route' - ) - $releaseSpec | Should -Match ( - 'A route without versioned release behavior MUST NOT require, apply, or report the ' + - '`Release decisions` block or any `release:\*` label' - ) - } - - It 'preserves required decision checks for managed routes without the optional file' { - $releaseSpec | Should -Match ( - 'Every PR targeting an invoked release route MUST receive a named release-decision CI check ' + - 'required by the branch ruleset or protection' - ) - $releaseSpec | Should -Match 'MUST block both manual and automated merge' - $releaseDesign | Should -Match ( - 'native producer routes, changes that will not publish, and repositories without\s+' + - 'a release configuration file' - ) - $releaseDesign | Should -Match 'path filters do not skip the validator' - $releaseDesign | Should -Match 'failure, pending execution, and\s+absence block merge' - } -} - -Describe 'Solution-owned settings naming contract' { - BeforeAll { - $ErrorActionPreference = 'Stop' - $repositoryRoot = Split-Path -Path $PSScriptRoot -Parent - $script:documentationRoot = [IO.Path]::Combine($repositoryRoot, 'src', 'docs') - $script:namingPath = [IO.Path]::Combine($documentationRoot, 'Coding-Standards', 'Naming.md') - $script:naming = [IO.File]::ReadAllText($namingPath) - $script:settingsRule = [regex]::Match( - $naming, - '(?s)## Solution settings files\r?\n(?.*?)(?:\r?\n## |\z)' - ) - $script:moduleSettings = [IO.File]::ReadAllText( - [IO.Path]::Combine($documentationRoot, 'Initiatives', 'PSModule.md') - ) - } - - It 'defines the conventional settings filename once in the Naming standard' { - $settingsRule.Success | Should -BeTrue - $settingsRule.Groups['body'].Value | Should -Match ( - 'Solution-owned settings MUST use `\.settings\.yml` as their conventional filename' - ) - $owners = @( - [IO.Directory]::EnumerateFiles($documentationRoot, '*.md', [IO.SearchOption]::AllDirectories) | - Where-Object { [IO.File]::ReadAllText($_).Contains('`.settings.yml`') } - ) - - $owners.Count | Should -Be 1 - $owners[0] | Should -BeExactly $namingPath - } - - It 'excludes tool-owned filenames and YAML that is not solution settings' { - $settingsRule.Groups['body'].Value | Should -Match ( - 'Tool-mandated manifests, lockfiles, workflow filenames' - ) - $settingsRule.Groups['body'].Value | Should -Match ( - 'YAML files that are not solution-owned settings' - ) - } - - It 'leaves the settings directory with the owning solution' { - $settingsRule.Groups['body'].Value | Should -Match ( - 'Each solution documents its settings location' - ) - $settingsRule.Groups['body'].Value | Should -Match 'does not impose a shared directory' - } - - It 'preserves supported explicit custom paths instead of imposing a runtime restriction' { - $settingsRule.Groups['body'].Value | Should -Match 'documented explicit path override' - $settingsRule.Groups['body'].Value | Should -Match ( - 'does not remove that input or restrict otherwise supported custom paths' - ) - } - - It 'links / to the one naming rule' -ForEach @( - @{ Directory = @('Coding-Standards'); File = 'YAML.md' } - @{ Directory = @('Ways-of-Working'); File = 'Repository-Standard.md' } - @{ Directory = @('Capabilities', 'release-management'); File = 'design.md' } - @{ Directory = @('Initiatives'); File = 'PSModule.md' } - ) { - $segments = [string[]] (@($documentationRoot) + $Directory + @($File)) - $guidance = [IO.File]::ReadAllText([IO.Path]::Combine($segments)) - - $guidance | Should -Match 'Naming\.md#solution-settings-files' - $guidance | Should -Not -Match ([regex]::Escape('`.settings.yml`')) - } - - It 'retains PSModule.yml through SettingsPath for module release settings' { - $moduleSettings | Should -Match ( - 'supported settings default is `\.github/PSModule\.yml`, through `SettingsPath`' - ) - $moduleSettings | Should -Match 'including module release settings' - $moduleSettings | Should -Match ( - 'do not need a separate `\.github/release\.settings\.yml` file' - ) - $moduleSettings | Should -Not -Match '(?i)psmodule\.settings\.yml' - } - - It 'links the module compatibility boundary from /' -ForEach @( - @{ Directory = @('Ways-of-Working'); File = 'Repository-Standard.md' } - @{ Directory = @('Capabilities', 'release-management'); File = 'design.md' } - ) { - $segments = [string[]] (@($documentationRoot) + $Directory + @($File)) - $guidance = [IO.File]::ReadAllText([IO.Path]::Combine($segments)) - - $guidance | Should -Match 'Initiatives/PSModule\.md#module-settings' - } - - It 'distinguishes the release conventional filename from an implemented reader or renamed input' { - $path = [IO.Path]::Combine($documentationRoot, 'Capabilities', 'release-management', 'design.md') - $guidance = [IO.File]::ReadAllText($path) - - $guidance | Should -Match '`ConfigurationFile`' - $guidance | Should -Match 'does not implement a reader or rename its public input' - $guidance | Should -Match 'supported explicit custom paths' - $guidance | Should -Not -Match 'auto-release\.yml|release\.config\.yml' - } - - It 'points module settings to the verified canonical framework references' { - $moduleSettings | Should -Match 'https://psmodule\.io/Process-PSModule/reference/workflow-inputs/' - $moduleSettings | Should -Match 'https://psmodule\.io/Process-PSModule/reference/settings/' - } - - It 'retains the VS Code template settings interface as a documented naming exception' { - $path = [IO.Path]::Combine( - $documentationRoot, 'Capabilities', 'vscode-extension-framework', 'design.md' - ) - $guidance = [IO.File]::ReadAllText($path) - - $guidance | Should -Match ( - '`\.github/vscode-extension\.yml` is the documented template settings interface' - ) - $guidance | Should -Match 'Naming\.md#solution-settings-files' - $guidance | Should -Match 'supported naming exception' - $guidance | Should -Match 'does not change this interface or its settings keys' - $guidance | Should -Match 'a verified reader and a separate template/caller migration' - $guidance | Should -Not -Match 'vscode-extension\.settings\.yml' - } -} - -Describe 'Repository PR-template-file policy' { - BeforeAll { - $ErrorActionPreference = 'Stop' - $script:repositoryRoot = Split-Path -Path $PSScriptRoot -Parent - $policyPath = [IO.Path]::Combine( - $repositoryRoot, 'src', 'docs', 'Ways-of-Working', 'Repository-Standard.md' - ) - $script:repositoryStandard = [IO.File]::ReadAllText($policyPath) - $script:templatePathPattern = '(^|/)pull_request_template([./]|$)' - $script:trackedFiles = @(& git --no-pager -C $repositoryRoot ls-files) - if ($LASTEXITCODE -ne 0 -or $trackedFiles.Count -eq 0) { - throw 'Could not inspect tracked source files for the repository file policy.' - } - } - - It 'keeps the authoritative no-file rule in Repository Standard' { - $repositoryStandard | Should -Match '### No PR-template files' - $repositoryStandard | Should -Match 'GitHub PR-template files MUST NOT' - } - - It 'links the file policy from ' -ForEach @( - @{ Directory = @('Ways-of-Working'); File = 'Organization-Standard.md' } - @{ Directory = @('Capabilities', 'repository-governance'); File = 'design.md' } - ) { - $segments = [string[]] (@($repositoryRoot, 'src', 'docs') + $Directory + @($File)) - $path = [IO.Path]::Combine($segments) - $guidance = [IO.File]::ReadAllText($path) - - $guidance | Should -Match 'Repository-Standard\.md#no-pr-template-files' - $guidance | Should -Not -Match '(?im)^\|\s*`\.github/pull_request_template\.md`\s*\|' - } - - It 'keeps repository-specific contribution instructions and canonical record guidance' { - $path = [IO.Path]::Combine($repositoryRoot, '.github', 'CONTRIBUTING.md') - $contribution = [IO.File]::ReadAllText($path) - - $contribution | Should -Match 'PR-Format/#complete-description-example' - $contribution | Should -Not -Match 'pull_request_template\.md' - $contribution | Should -Match 'Invoke-PesterSuite\.ps1' - $contribution | Should -Match 'Test-DocumentationLink\.ps1' - } - - It 'contains no tracked PR-template file or file-set directory' { - $templateFiles = @( - $trackedFiles | Where-Object { $_ -match $templatePathPattern } - ) - - $templateFiles.Count | Should -Be 0 - } - - It 'distinguishes the source path from unaffected guidance' -ForEach @( - @{ Path = 'PULL_REQUEST_TEMPLATE.md'; IsPrTemplate = $true } - @{ Path = '.github/pull_request_template.txt'; IsPrTemplate = $true } - @{ Path = '.github/PULL_REQUEST_TEMPLATE/change.md'; IsPrTemplate = $true } - @{ Path = '.github/ISSUE_TEMPLATE/feature.yml'; IsPrTemplate = $false } - @{ Path = 'src/docs/Ways-of-Working/PR-Format.md'; IsPrTemplate = $false } - ) { - ($Path -match $templatePathPattern) | Should -Be $IsPrTemplate - } -} From 8daf026a14036dee04786d371883e8871b5ec2f4 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Mon, 2 Nov 2026 19:06:38 +0100 Subject: [PATCH 7/7] Generate documentation indexes without a drift gate --- .github/CONTRIBUTING.md | 4 ++-- .github/scripts/Update-DocumentationIndex.ps1 | 3 ++- .github/workflows/Docs.yml | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 22f34aa..6122ad2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -85,8 +85,8 @@ index and drill down to the right page. Three conventions make that work. - **The tables are generated from front matter.** `.github/scripts/Update-DocumentationIndex.ps1` reads each page's `title` and `description`, orders them to match the navigation in - `src/zensical.toml`, and fills every index in place. CI runs the same script with `-Check` - and fails if an index is out of date. + `src/zensical.toml`, and fills every index in place. CI regenerates the indexes before + building the site instead of rejecting index drift. Choose a page's home by subject first, then by the artifact that answers the reader's question. The [Documentation Model](https://msxorg.github.io/docs/Ways-of-Working/Documentation-Model/#architecture-and-classification) diff --git a/.github/scripts/Update-DocumentationIndex.ps1 b/.github/scripts/Update-DocumentationIndex.ps1 index 047fcd4..7e18df1 100644 --- a/.github/scripts/Update-DocumentationIndex.ps1 +++ b/.github/scripts/Update-DocumentationIndex.ps1 @@ -21,11 +21,12 @@ .EXAMPLE ./Update-DocumentationIndex.ps1 Updates every section index.md in place from the current front matter. + CI runs this mode before building the site. .EXAMPLE ./Update-DocumentationIndex.ps1 -Check Verifies the indexes are current without writing; exits non-zero on drift. - This is the mode the CI build job runs. + This is an optional local diagnostic, not a CI gate. #> [CmdletBinding()] param( diff --git a/.github/workflows/Docs.yml b/.github/workflows/Docs.yml index 10d662c..de01a42 100644 --- a/.github/workflows/Docs.yml +++ b/.github/workflows/Docs.yml @@ -76,9 +76,9 @@ jobs: with: python-version: 3.x - - name: Verify documentation indexes + - name: Generate documentation indexes shell: pwsh - run: ./.github/scripts/Update-DocumentationIndex.ps1 -Check + run: ./.github/scripts/Update-DocumentationIndex.ps1 - name: Install Zensical run: pip install -r requirements.txt