Goal
Remove RequiresCapabilities from workflow definitions.
From now on, each Step.Type is the single source of truth for required provider capabilities. Planning derives required capabilities from a step metadata catalog (trusted extension point provided by step packs / host), not from workflow configuration.
This is a breaking change (pre-1.0). Existing workflows, examples, and tests must be updated.
Motivation
- Avoid duplication: the step implementation already knows which provider features it needs.
- Reduce workflow author burden and misconfiguration risk.
- Keep planning-time capability validation deterministic while moving requirements closer to the code that enforces them.
Proposed design
1) Workflow schema change (remove RequiresCapabilities)
- Remove
RequiresCapabilities from the list of allowed step keys in workflow schema validation.
- Workflows that still contain
RequiresCapabilities must fail validation with an actionable message.
2) Add a trusted Step Metadata Catalog
Introduce a new trusted extension point (similar to StepRegistry) that maps Step.Type to metadata.
Input location (host-controlled):
Providers.StepMetadata (hashtable), or Providers['StepMetadata'] (hashtable), analogous to Providers.StepRegistry.
Shape:
- Key: Step.Type (string)
- Value: hashtable (data-only), minimum contract:
@{
RequiredCapabilities = @('IdLE.Identity.Disable', 'IdLE.Identity.Read')
}
Validation rules (fail fast):
- Must be a hashtable.
- Keys must be non-empty strings.
- Values must be hashtables.
RequiredCapabilities (if present) must be:
- missing /
$null (treated as empty)
- string
- string array
- Capability identifiers must follow the repo rules (dot-separated, no whitespace).
- Reject ScriptBlocks anywhere in the metadata (data-only boundary).
3) Built-in step packs provide their metadata
-
Each first-party step pack (e.g. IdLE.Steps.Common) must expose a function that returns its metadata, for example:
Get-IdleStepMetadataCatalog returning a hashtable keyed by Step.Type.
-
IdLE.Core adds a helper Get-IdleStepMetadataCatalog -Providers $Providers that:
- loads built-in step metadata catalogs (module-qualified discovery like
Get-IdleStepRegistry)
- merges host-provided
Providers.StepMetadata
- uses case-insensitive keys
- applies deterministic precedence:
- host metadata overrides built-in metadata for the same Step.Type
4) Planning changes (how required capabilities are derived)
- During plan build (
New-IdlePlan / New-IdlePlanObject):
- Resolve StepRegistry as today (trusted).
- Resolve StepMetadataCatalog (trusted).
- For each workflow step:
- look up metadata by
Step.Type
- normalize
RequiredCapabilities and attach it to the plan step as RequiresCapabilities
- Capability validation uses the plan step’s derived
RequiresCapabilities.
Fail-fast behavior:
- If a workflow references a Step.Type that exists in the StepRegistry but has no metadata entry, plan build fails with:
- missing StepMetadata for Step.Type
- guidance: host must add
Providers.StepMetadata['<StepType>'] = @{ RequiredCapabilities = ... }
5) Compatibility and contracts
- StepRegistry remains:
Step.Type -> handler function name (string). No ScriptBlocks.
- StepMetadata is a separate catalog. This keeps StepRegistry shape stable.
- Workflow remains data-only; this change reduces “policy” surface in workflow.
Breaking changes
- Workflow PSD1 files that contain
RequiresCapabilities become invalid.
- Hosts that provide custom steps must provide both:
- a StepRegistry mapping (existing)
- a StepMetadata mapping (new)
Implementation tasks
Core
- Update workflow schema validation to reject
RequiresCapabilities.
- Add
Get-IdleStepMetadataCatalog (new private helper) mirroring the style and validation approach of Get-IdleStepRegistry.
- Update plan build:
- remove normalization of
RequiresCapabilities from workflow steps
- derive required capabilities from StepMetadataCatalog
- keep the plan step property name
RequiresCapabilities so downstream validation and plan export remain transparent.
Docs
- Update provider capability documentation to reflect that steps no longer declare
RequiresCapabilities in workflows.
- Update step metadata documentation to include
RequiredCapabilities as a normative field.
- Update workflow documentation / examples to remove
RequiresCapabilities.
Tests
- Refactor existing capability tests to use step metadata instead of workflow
RequiresCapabilities.
- Add tests for:
- workflow containing
RequiresCapabilities fails schema validation
- missing StepMetadata for referenced Step.Type fails plan build
- host metadata overrides built-in metadata
- invalid metadata shapes (non-hashtable, ScriptBlock, invalid capability values)
Examples
- Update sample workflows under
examples/workflows/ to remove RequiresCapabilities.
- Ensure demo runner still succeeds with built-in metadata discovery.
Generated references
- Optional (but recommended): extend
tools/Generate-IdleStepReference.ps1 to include RequiredCapabilities if the metadata is discoverable.
- This keeps
docs/reference/steps.md informative without relying on workflow files.
Acceptance criteria
Definition of Done
Goal
Remove
RequiresCapabilitiesfrom workflow definitions.From now on, each Step.Type is the single source of truth for required provider capabilities. Planning derives required capabilities from a step metadata catalog (trusted extension point provided by step packs / host), not from workflow configuration.
This is a breaking change (pre-1.0). Existing workflows, examples, and tests must be updated.
Motivation
Proposed design
1) Workflow schema change (remove
RequiresCapabilities)RequiresCapabilitiesfrom the list of allowed step keys in workflow schema validation.RequiresCapabilitiesmust fail validation with an actionable message.2) Add a trusted Step Metadata Catalog
Introduce a new trusted extension point (similar to StepRegistry) that maps Step.Type to metadata.
Input location (host-controlled):
Providers.StepMetadata(hashtable), orProviders['StepMetadata'](hashtable), analogous toProviders.StepRegistry.Shape:
Validation rules (fail fast):
RequiredCapabilities(if present) must be:$null(treated as empty)3) Built-in step packs provide their metadata
Each first-party step pack (e.g.
IdLE.Steps.Common) must expose a function that returns its metadata, for example:Get-IdleStepMetadataCatalogreturning a hashtable keyed by Step.Type.IdLE.Coreadds a helperGet-IdleStepMetadataCatalog -Providers $Providersthat:Get-IdleStepRegistry)Providers.StepMetadata4) Planning changes (how required capabilities are derived)
New-IdlePlan/New-IdlePlanObject):Step.TypeRequiredCapabilitiesand attach it to the plan step asRequiresCapabilitiesRequiresCapabilities.Fail-fast behavior:
Providers.StepMetadata['<StepType>'] = @{ RequiredCapabilities = ... }5) Compatibility and contracts
Step.Type -> handler function name(string). No ScriptBlocks.Breaking changes
RequiresCapabilitiesbecome invalid.Implementation tasks
Core
RequiresCapabilities.Get-IdleStepMetadataCatalog(new private helper) mirroring the style and validation approach ofGet-IdleStepRegistry.RequiresCapabilitiesfrom workflow stepsRequiresCapabilitiesso downstream validation and plan export remain transparent.Docs
RequiresCapabilitiesin workflows.RequiredCapabilitiesas a normative field.RequiresCapabilities.Tests
RequiresCapabilities.RequiresCapabilitiesfails schema validationExamples
examples/workflows/to removeRequiresCapabilities.Generated references
tools/Generate-IdleStepReference.ps1to includeRequiredCapabilitiesif the metadata is discoverable.docs/reference/steps.mdinformative without relying on workflow files.Acceptance criteria
RequiresCapabilitieswith an actionable error.Definition of Done
./tools/Invoke-IdlePesterTests.ps1)./tools/Invoke-IdleScriptAnalyzer.ps1)./tools/Generate-IdleStepReference.ps1)