Skip to content

feat(scripts): add -UpdateCommitted to the derived-artifacts gate - #145

Merged
juemerson-at-purestorage merged 1 commit into
dmann000:mainfrom
juemerson-at-purestorage:feat/derived-artifacts-update-committed
Aug 25, 2026
Merged

feat(scripts): add -UpdateCommitted to the derived-artifacts gate#145
juemerson-at-purestorage merged 1 commit into
dmann000:mainfrom
juemerson-at-purestorage:feat/derived-artifacts-update-committed

Conversation

@juemerson-at-purestorage

Copy link
Copy Markdown
Collaborator

What

Adds -UpdateCommitted to scripts/Assert-PfbDerivedArtifacts.ps1.

When the gate reports a stale artifact, it already holds — in its scratch tree — exactly the
content the comparison demanded. Until now the caller was told to copy those files over the
committed copies by hand. -UpdateCommitted does the copy, exits 0, and lists the repo-relative
path of every file it wrote:

Updated 1 committed artifact(s) from this run's regeneration:
    Data/PfbResponseShapeMap.json

Review, then commit:
    git diff --stat -- Data/PfbResponseShapeMap.json

Paths are printed bare and one per line so each is selectable alone and the block pastes into a
git command — the two things a reader does next.

Why

The manual copy is mechanical and has two quiet ways to go wrong: missing one file of a
.json/.md pair, or round-tripping through an editor and introducing a BOM. Neither shows up
until the next gate run.

Scope of the write

  • Only artifacts the run found stale are written — an up-to-date artifact is not rewritten
    byte-identically, so git status afterwards names exactly what moved.
  • Only within -Artifact when that narrows the set.
  • Nothing infers the switch: no environment variable, no CI default.

Without it, behaviour is unchanged — stale still throws, exit 1. The workflow
(verify-derived-artifacts.yml) passes only -WorkDirectory and -KeepWorkDirectory and cannot
reach the write path.

Two decisions worth review

Exit 0 after a successful update. Remediating is what the switch asks for, so doing it is
success, and a non-zero exit from a run that just fixed the problem breaks any caller chaining on
it. Callers that want the unremediated answer are the ones that must not pass the switch.

The header comment is amended, not dropped. It read "THE WORKING TREE IS NEVER TOUCHED... a
gate that rewrites Data/ as a side effect of checking it is not a gate." That reasoning is about
side effects rather than writes, and an explicit opt-in is not a side effect — so the paragraph now
states the exception and why the distinction holds, rather than sitting in contradiction with the
code below it.

Copy-Item rather than read-transform-write, because the committed artifacts carry no BOM and a
Set-Content round-trip is one -Encoding default away from adding one. Preserving bytes also
settles the line-ending question instead of reopening it: the comparison already normalizes CRLF,
so a whole-file copy lands exactly the content the gate demanded.

Verification

Behaviour exercised end to end against the real spec cache (29 pinned versions, 2.0–2.28), by
corrupting Data/PfbResponseShapeMap.json and running the gate:

Case Result
stale + -UpdateCommitted UPDATED, exit 0, git status empty — restored byte-exact
stale, no switch still throws, exit 1
already clean + switch reports up to date, exit 0, no rewrite

The git status result also confirms no BOM was introduced and no line endings were damaged.

Tests/AssertDerivedArtifacts.Tests.ps1: 25 passed, 0 failed on both PowerShell 7.5 and Windows
PowerShell 5.1
(run together with Tests/Build-PfbPipelineSelectorMap.Tests.ps1, the other file
referencing this script).

Two new tests, both mutation-checked — removing the if ($UpdateCommitted) guard and switching the
report to absolute paths each red exactly one test:

  • the write is asserted to sit inside the guard by AST containment, not by grepping for the
    switch name. A Copy-Item moved one brace out of the guard still sits a few lines from the word
    UpdateCommitted and would keep a text match green while the gate rewrote Data/ on every run.
  • -UpdateCommitted is asserted to be a [switch] with no default, since as a [bool] it could
    bind positionally or by conversion.

Live-test exemption

Exempt. The diff leaves the module source and the manifest entirely untouched, so nothing here
can alter a request the module sends or a response it parses. Changed files are
scripts/Assert-PfbDerivedArtifacts.ps1, Tests/AssertDerivedArtifacts.Tests.ps1 and
Reports/README.md.

Docs

Reports/README.md now documents -UpdateCommitted as the fix path, with -KeepWorkDirectory
kept as the inspect-before-overwriting alternative. The stale-artifact error message points at the
switch for the same reason.

No version bump or CHANGELOG entry — those are the maintainer's call.

When the gate reports a stale artifact it already holds, in its scratch
tree, exactly the content the comparison demanded. Until now the caller
was told to copy those files over the committed copies by hand -- a
mechanical step with two ways to get it wrong (missing a file of a
.json/.md pair, or round-tripping through an editor and adding a BOM).

-UpdateCommitted writes them instead, then exits 0 and lists the
repo-relative path of every file it wrote, so the paths paste straight
into git diff or git add. Only artifacts the run found stale are
written, and only within -Artifact when that narrows the set, so
git status afterwards names exactly what moved.

Exiting 0 is deliberate: remediating is what the switch asks for, and a
non-zero exit from a run that just fixed the problem breaks any caller
chaining on it. Without the switch the behaviour is unchanged -- stale
still throws, and CI, which passes only -WorkDirectory and
-KeepWorkDirectory, cannot reach the write path.

The script's header previously said the working tree is never touched.
That reasoning was about side effects, not writes, so it is amended
rather than dropped: an explicit opt-in is not a side effect, and
nothing infers the switch from the environment.

Copy-Item rather than read-transform-write, because the committed
artifacts carry no BOM and a Set-Content round-trip is one -Encoding
default away from adding one. Preserving bytes also settles the
line-ending question -- verified by corrupting an artifact, running with
the switch, and confirming git status came back empty.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@juemerson-at-purestorage
juemerson-at-purestorage merged commit 2f33b2e into dmann000:main Aug 25, 2026
6 checks passed
@juemerson-at-purestorage
juemerson-at-purestorage deleted the feat/derived-artifacts-update-committed branch August 25, 2026 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant