Files
ARCADIA-Studio/harness/experiments/scenario-validation-preflight-5d4a6a4-20260913/original/capture.ps1
T

48 lines
4.1 KiB
PowerShell

#Requires -Version 7.0
param([Parameter(Mandatory=$true)][ValidatePattern('^(before|after|(strict-preflight|list|focused|focused-batch[0-9]{2}|all|clippy|build|diagnostic)-(before|after))$')][string]$Stage)
Set-StrictMode -Version Latest
$ErrorActionPreference='Stop'
$taskWorkspace='C:\Users\User\Documents\Git\ARCADIA-Studio\.local\scenario-spacing-ytr83r-20260913'
$taskPin='5d4a6a47ce1085b818498bb281a41c3bc6a83847'
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}