Skip to content

Modules declare themselves with a descriptor instead of six registration edits #17

Description

@DireDoch

Chapter 7 of the manual documents adding a Module as "four small edits, all in
files you already have." It is really six, across three files, and the manual is
honest about it — which is the tell. A seam that needs a six-item checklist
outside the Module is not a seam.

Today, src/Config-MyThing.ps1 must also be declared in:

  1. Invoke-WcdConfiguration.ps1 -> the $modules array
  2. Invoke-WcdConfiguration.ps1 -> the switch ($modName) dispatch arm
  3. WcdHelpers.ps1 -> Get-WcdModuleProgressPlan
  4. WcdHelpers.ps1 -> Get-WcdTechnicalStepLabels
  5. Invoke-WcdConfiguration.ps1 -> $T.Checklist, in both language tables
  6. Invoke-WcdConfiguration.ps1 -> Get-WcdFinalChecklistEntries

Miss one and nothing fails. A missing progress-plan entry drops the Module from
the run silently — the $moduleStepPlan.ContainsKey guard treats "not planned"
and "planned as empty" differently, and a Module absent from the hashtable runs
with a $null step list. A missing $T.Checklist key renders a blank label on
the checklist.

The descriptor

Each Config-*.ps1 exports one function returning what the orchestrator needs:

function Get-WcdMyThingDescriptor {
    param([pscustomobject]$ExecutionOptions, [hashtable]$Config)

    [pscustomobject]@{
        Name  = 'Config-MyThing'
        Steps = @(
            @{ Key = 'MyStep';      Label = 'My thing' }
            @{ Key = 'MyOtherStep'; Label = 'My other thing' }
        )
        Rows  = @(
            @{ Label = 'MyThing'; Steps = @('MyStep', 'MyOtherStep') }
        )
        Invoke = { param($ctx) Set-WcdMyThingConfiguration -LogPath $ctx.LogPath -ProgressCallback $ctx.ProgressCallback }
    }
}

The orchestrator globs src/Config-*.ps1 in run order, dot-sources each, calls
its descriptor, and builds the progress plan, the step labels and the checklist
rows from what comes back. Get-WcdModuleProgressPlan and
Get-WcdTechnicalStepLabels become the thing that assembles descriptors
rather than the thing that hardcodes twelve Modules.

What the descriptor has to handle

The current hardcoded tables are not uniform, and the descriptor has to absorb
that or it is not an improvement:

  • Form-Factor-dependent Steps. Config-Power plans five Steps on a Laptop
    and two on a Desktop; the checklist row has the same split. Hence
    $ExecutionOptions as a descriptor parameter.
  • Manifest-derived Steps. Config-Applications and Config-Printer get
    their Step keys and labels from the manifest at runtime. Hence $Config.
  • Conditional Modules. Config-Identity plans zero Steps when the
    technician declined both, and the orchestrator skips the Module entirely.
    An empty Steps array must keep meaning exactly that.
  • Rows that are not one-per-Module. Config-Disk produces two rows,
    Config-WindowsUpdate folds two Steps into one row, and the restart row is
    raised from Results across two Modules. The restart row is special enough to
    stay in the Diagnostic rather than move into a descriptor.
  • Run order. Glob order is alphabetical, not run order. Keep an explicit
    ordered list of Module names, or add an Order field — but that is one
    registration point, not six.

Ordering

Do #16 first. This rewrites Get-WcdFinalChecklistEntries, and that
function currently has no test to rewrite it against.

Done when

  • Every Config-*.ps1 exports a descriptor function
  • The orchestrator discovers Modules instead of hardcoding $modules
  • The switch ($modName) dispatch is deleted
  • Get-WcdModuleProgressPlan and Get-WcdTechnicalStepLabels assemble from descriptors
  • A descriptor missing a required field fails at load, loudly
  • Laptop and Desktop runs plan the same Steps as before
  • A run declining both identity options still skips Config-Identity
  • Checklist output byte-identical before and after, in both languages
  • tests/ gains a descriptor-contract test every Module is run through
  • Manual chapter 7 rewritten: one file, one code block

Activity

added
refactorRestructuring without changing behaviour
area:architectureModule seams, orchestrator, test surface
on Sep 3, 2026
added a commit that references this issue on Sep 3, 2026

DireDoch commented on Sep 3, 2026

@DireDoch
OwnerAuthor

Fait dans 5da3ed2 (PR #32).

Chaque src/Config-*.ps1 exporte Get-Wcd<Nom>Descriptor. L'orchestrateur globe Config-*.ps1; le tableau $modules et le switch ($modName) ont disparu, et Get-WcdModuleProgressPlan / Get-WcdTechnicalStepLabels assemblent des descripteurs.

Un ecart avec l'issue. L'issue dit "la checklist, en ordre d'execution". Elle ne l'est pas, et ne l'a jamais ete: les Modules tournent Identity -> Power -> Decimal -> Taskbar -> Language -> Applications -> ..., la checklist se lit Identity -> Restart -> Taskbar -> Language -> Keyboard -> Decimal -> Power -> ... Un descripteur porte donc Order et RowOrder. Les deux vivent dans le fichier du Module: c'est toujours un point d'enregistrement, pas six.

Ce que le descripteur absorbe:

  • Etapes dependantes du Form Factor — une Etape porte Planned = $false plutot que d'etre absente. Config-Power planifie toujours cinq Etapes sur portable et deux sur bureau, et les trois libelles batterie/capot survivent pour le Diagnostic.
  • Etapes issues du manifeste — le descripteur recoit $Config.
  • Modules conditionnels — Steps = @() veut toujours dire "sauter ce Module", et ses lignes sont quand meme emises: un renommage refuse doit toujours au technicien une Etape manuelle qui le dit.
  • Lignes qui ne sont pas une-par-Module — une ligne est soit @{ Label; Steps } soit un @{ Label; Kind; Detail } fixe, avec MissingKind / MissingDetail / OmitWhenMissing pour les cas qui en ont besoin.
  • La ligne de redemarrage reste dans le Diagnostic, comme l'issue le demande, mais nommee: Resolve-WcdRestartEntry. Les Etapes manuelles finales aussi — elles n'appartiennent a aucun Module.

Les descripteurs prennent -Translations plutot que de lire $script:T, donc un Module reste testable seul.

Sortie identique octet pour octet, verifiee. Un harnais point-source les deux arbres et compare le plan de progression, chaque ligne de checklist (Step, Label, Kind, Detail) et le rendu, pour 7 scenarios x 2 langues — portable/bureau, workstation/vdi, applications refusees, identite appliquee, redemarrage en attente, sans imprimante, winget absent, rien n'a tourne, alimentation non elevee. 554 lignes, zero difference.

tests/ModuleDescriptor.Tests.ps1 passe les douze Modules par Test-WcdModuleDescriptor sous trois profils d'execution, verifie l'unicite de Order/RowOrder, verifie que chaque ligne ne reference que des Etapes que le Module declare, et verifie que le garde rejette bien chaque champ manquant.

Supprimes comme morts: $T.ModuleNotFound dans les deux tables (un fichier globe ne peut pas etre introuvable) et les libelles PrinterAdd / PrinterSkip, qu'aucun Module n'emettait.

Chapitre 7 du manuel reecrit: un fichier, un bloc de code, plus un tableau expliquant chaque champ. Le libelle de ligne dans les deux tables $T est signale comme la seule chose encore hors du fichier — et le test de parite de #20 attrape l'oubli du second.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:architectureModule seams, orchestrator, test surfacerefactorRestructuring without changing behaviour

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions