#Requires -Version 7.0 param([Parameter(Mandatory=$true)][ValidatePattern('^(before|after|(list|focused|all|clippy|build)-(before|after))$')][string]$Stage) Set-StrictMode -Version Latest $ErrorActionPreference='Stop' $taskWorkspace='C:\Users\User\Documents\Git\ARCADIA-Studio\.local\scenario-workspace-ytr83r-20260913' $taskPin='2c9cd2b3e661ef85f11590c7128dcb2f502d0c26' function Hash-Input([string]$Path){(Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()} $taskOutput=Join-Path $PSScriptRoot ('inputs-complete-'+$Stage+'.json') if(Test-Path -LiteralPath $taskOutput){throw 'Preserve existing input evidence; use a new directory for retries.'} $pinRecord=Get-Content -Raw -LiteralPath (Join-Path $PSScriptRoot 'expected-inputs.json')|ConvertFrom-Json $enumeration=Get-Content -Raw -LiteralPath (Join-Path $PSScriptRoot 'enumeration.json')|ConvertFrom-Json $external=Get-Content -Raw -LiteralPath (Join-Path $PSScriptRoot 'external-inputs.json')|ConvertFrom-Json if($pinRecord.base -cne $taskPin -or $enumeration.base -cne $taskPin -or $external.base -cne $taskPin){throw 'Wrong input pin.'} Push-Location -LiteralPath $taskWorkspace try { $taskBase=git rev-parse HEAD if($LASTEXITCODE -ne 0 -or $taskBase -cne $taskPin){throw 'Wrong source commit.'} $status=@(git status --porcelain) if($LASTEXITCODE -ne 0 -or $status.Count){throw 'Frozen worktree changed.'} $taskRoots=@($enumeration.rootInputs);$taskScopes=@($enumeration.scopes) $tracked=@(git ls-files -- @taskRoots @taskScopes) if($LASTEXITCODE -ne 0){throw 'Git enumeration failed.'} $tracked=@($tracked | ForEach-Object {$_.Replace('\','/')} | Sort-Object -Unique) $present=@(rg --files @taskScopes) if($LASTEXITCODE -ne 0){throw 'Actual input enumeration failed.'} $taskPaths=@(($present+$taskRoots) | ForEach-Object {$_.Replace('\','/')} | Sort-Object -Unique) if(@(Compare-Object $tracked $taskPaths).Count -or @(Compare-Object @($enumeration.gitPaths) $tracked).Count){throw 'Frozen input membership changed.'} $taskEntries=@($taskPaths | ForEach-Object {$item=Get-Item -LiteralPath $_;[ordered]@{path=$_;bytes=$item.Length;sha256=(Hash-Input $_)}}) $externalNow=@(foreach($f in $external.files){ $present=Test-Path -LiteralPath $f.path if($present -ne $f.present){throw ('External config presence changed: '+$f.path)} if($present){$item=Get-Item -LiteralPath $f.path;$hash=Hash-Input $f.path;if($item.Length -ne $f.bytes -or $hash -cne $f.sha256){throw ('External input changed: '+$f.path)};[ordered]@{path=$f.path;present=$true;bytes=$item.Length;sha256=$hash}} else{[ordered]@{path=$f.path;present=$false}} }) $taskRecord=[ordered]@{capturedUtc=[DateTime]::UtcNow.ToString('o');workspace=$taskWorkspace;base=$taskBase;count=$taskEntries.Count;files=$taskEntries;externalInputs=$externalNow;expectedInputsSha256=(Hash-Input (Join-Path $PSScriptRoot 'expected-inputs.json'));enumerationSha256=(Hash-Input (Join-Path $PSScriptRoot 'enumeration.json'))} $taskRecord|ConvertTo-Json -Depth 8|Set-Content -LiteralPath $taskOutput -Encoding utf8 if($taskEntries.Count -ne $pinRecord.count){throw 'Pinned dynamic count changed.'} $expected=@{} foreach($f in $pinRecord.files){if($expected.ContainsKey($f.path)){throw 'Duplicate pinned input.'};$expected[$f.path]=$f} foreach($f in $taskEntries){if(-not $expected.ContainsKey($f.path)){throw 'Unexpected input.'};$old=$expected[$f.path];if($f.bytes -ne $old.bytes -or $f.sha256 -cne $old.sha256){throw ('Input changed: '+$f.path)};$expected.Remove($f.path)} if($expected.Count){throw 'Missing input.'} if($Stage -ne 'before'){ $baseline=Get-Content -Raw -LiteralPath (Join-Path $PSScriptRoot 'inputs-complete-before.json')|ConvertFrom-Json if($baseline.base -cne $taskPin -or $baseline.count -ne $pinRecord.count -or $baseline.expectedInputsSha256 -cne $taskRecord.expectedInputsSha256 -or $baseline.enumerationSha256 -cne $taskRecord.enumerationSha256){throw 'Baseline binding changed.'} } Write-Output ('Captured and verified '+$taskEntries.Count+' inputs: '+$Stage) } finally {Pop-Location}