Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
61734c3
Repair Windows Wire completion capture gesture
coneilen Nov 5, 2026
b0aa65d
Validate locked Wire endpoints before Create
coneilen Nov 5, 2026
77abc6c
Merge main after restart refusal delivery fix
coneilen Nov 5, 2026
1b94aef
Add functional-only Windows Wire validation
coneilen Nov 6, 2026
3dc651f
Keep functional Wire daemon provenance explicit
coneilen Nov 6, 2026
1e687e0
Bound advisory exclusion diagnostic serialization
coneilen Nov 6, 2026
efa3b5e
Support verified explicit compiler input for capture fixtures
coneilen Nov 6, 2026
88df225
Add bounded opt-in Wire receiver diagnostics
coneilen Nov 6, 2026
f9d5d44
Preserve Wire drag on verified same-window recapture
coneilen Nov 6, 2026
91d5abe
Align CI topology contracts with verified compiler arguments
coneilen Nov 6, 2026
582f282
Retain scalar facts when owned window census text queries fail
coneilen Nov 6, 2026
8ac3d36
Add a first-census-only Wire diagnostic with retained topology
coneilen Nov 6, 2026
6204a0a
Scope owned window census to the explicit root family
coneilen Nov 6, 2026
98752b7
Refuse selected window ancestry drift before text observation
coneilen Nov 6, 2026
1c65bf9
Publish partial receipt controls with atomic snapshot replacement
coneilen Nov 6, 2026
53d77b8
Observe structural sheet readiness before full Wire text census
coneilen Nov 7, 2026
9082dcb
Use the shipping Create caption for new edge forms
coneilen Nov 7, 2026
e25544e
Keep native footer regression outside data-only edge filters
coneilen Nov 7, 2026
1df1c57
Retain exact Wire Create predicate observations and primary errors
coneilen Nov 7, 2026
71a1386
Initialize capture clients through the validated native UIA proxy loader
coneilen Nov 7, 2026
57c772d
Preserve post-exit descendant discovery error details
coneilen Nov 7, 2026
495b54f
Harden held-process image query output handling
coneilen Nov 7, 2026
1a5514a
Merge main release metadata into Wire closure
coneilen Nov 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions Tools/windows/FixtureCompiler.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
function Resolve-CapFixtureCompiler {
param([string]$InputPath, [string]$InputSha256, [string]$Directory, [string]$Role)

if ($InputPath -or $InputSha256) {
if (-not $InputPath -or $InputSha256 -cnotmatch '\A[A-F0-9]{64}\z' -or
-not [IO.Path]::IsPathFullyQualified($InputPath) -or
-not [IO.File]::Exists($InputPath)) {
throw 'FixtureCompilerInput: an absolute existing JSON path and uppercase SHA256 are required together.'
}
$bytes = [IO.File]::ReadAllBytes($InputPath)
if ([Convert]::ToHexString([Security.Cryptography.SHA256]::HashData($bytes)) -cne $InputSha256) {
throw 'FixtureCompilerInput: input digest differs.'
}
try { $inputRecord = [Text.Encoding]::UTF8.GetString($bytes) | ConvertFrom-Json -ErrorAction Stop }
catch { throw 'FixtureCompilerInput: invalid JSON.' }
$fields = @('schemaVersion','installationPath','msvcVersion','compilerSha256','vcvarsSha256','sdkRoot','sdkVersion')
if ($inputRecord -isnot [pscustomobject] -or
@($inputRecord.PSObject.Properties).Count -ne $fields.Count -or
@($fields | Where-Object { $_ -cnotin $inputRecord.PSObject.Properties.Name }).Count -ne 0) {
throw 'FixtureCompilerInput: exact schema fields are required.'
}
if ($inputRecord.schemaVersion -isnot [long] -and $inputRecord.schemaVersion -isnot [int]) {
throw 'FixtureCompilerInput: schemaVersion must be an integer.'
}
if ($inputRecord.schemaVersion -ne 1 -or $inputRecord.msvcVersion -cnotmatch '\A\d+\.\d+\.\d+\z' -or
$inputRecord.sdkVersion -cnotmatch '\A\d+\.\d+\.\d+\.\d+\z') {
throw 'FixtureCompilerInput: unsupported schema or tool version.'
}
foreach ($field in $fields | Where-Object { $_ -cne 'schemaVersion' }) {
if ($inputRecord.$field -isnot [string] -or [string]::IsNullOrWhiteSpace($inputRecord.$field)) {
throw "FixtureCompilerInput: $field must be a nonempty string."
}
}
foreach ($field in @('installationPath','sdkRoot')) {
$path = $inputRecord.$field
if (-not [IO.Path]::IsPathFullyQualified($path) -or $path -match '[\r\n"%!&|<>^]' -or
-not [IO.Directory]::Exists($path)) {
throw "FixtureCompilerInput: $field must be an existing batch-safe absolute directory."
}
}
$installation = [IO.Path]::GetFullPath($inputRecord.installationPath)
$version = $inputRecord.msvcVersion
$vcvars = Join-Path $installation 'VC\Auxiliary\Build\vcvars64.bat'
$compiler = Join-Path $installation "VC\Tools\MSVC\$version\bin\Hostx64\x64\cl.exe"
foreach ($pair in @(@($compiler,'compilerSha256'),@($vcvars,'vcvarsSha256'))) {
if ($inputRecord.($pair[1]) -cnotmatch '\A[A-F0-9]{64}\z' -or -not [IO.File]::Exists($pair[0]) -or
(Get-FileHash -LiteralPath $pair[0] -Algorithm SHA256).Hash -cne $inputRecord.($pair[1])) {
throw "FixtureCompilerInput: $($pair[1]) does not bind the actual selected file."
}
}
foreach ($relative in @("Include\$($inputRecord.sdkVersion)\um\Windows.h",
"Include\$($inputRecord.sdkVersion)\ucrt\stdio.h",
"Lib\$($inputRecord.sdkVersion)\um\x64\kernel32.lib",
"Lib\$($inputRecord.sdkVersion)\ucrt\x64\ucrt.lib")) {
if (-not [IO.File]::Exists((Join-Path $inputRecord.sdkRoot $relative))) {
throw "FixtureCompilerInput: required SDK input is missing: $relative"
}
}
return [pscustomobject]@{
mode = 'explicit'; inputPath = [IO.Path]::GetFullPath($InputPath); inputSha256 = $InputSha256
installationPath = $installation; msvcVersion = $version; sdkVersion = $inputRecord.sdkVersion
sdkRoot = [IO.Path]::GetFullPath($inputRecord.sdkRoot); vcvars = $vcvars; compiler = $compiler
compilerSha256 = $inputRecord.compilerSha256; vcvarsSha256 = $inputRecord.vcvarsSha256
discoveryDirectory = Join-Path $installation '..\..\Installer'
}
}

$vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
if (-not (Test-Path -LiteralPath $vswhere -PathType Leaf)) {
throw 'Existing MSVC discovery is unavailable; this offline suite does not install a compiler.'
}
$discovery = Invoke-CapBoundedChild -FilePath $vswhere -Arguments @(
'-latest', '-products', '*', '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
'-property', 'installationPath'
) -Directory $Directory -Role $Role
if ($discovery.exitCode -ne 0 -or [string]::IsNullOrWhiteSpace($discovery.stdout)) {
throw 'Existing MSVC was not found.'
}
$installation = $discovery.stdout.Trim()
$version = [IO.File]::ReadAllText((Join-Path $installation 'VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt')).Trim()
return [pscustomobject]@{
mode = 'discovery'; inputPath = $null; inputSha256 = $null
installationPath = $installation; msvcVersion = $version; sdkVersion = $null
vcvars = Join-Path $installation 'VC\Auxiliary\Build\vcvars64.bat'
compiler = Join-Path $installation "VC\Tools\MSVC\$version\bin\Hostx64\x64\cl.exe"
discoveryDirectory = Split-Path -Parent $vswhere
}
}

function Assert-CapFixtureCompilerEnvironment {
param($Selection, [string]$Stdout)
if ($Selection.mode -cne 'explicit') { return }
$values = @{}
foreach ($line in $Stdout -split '\r?\n') {
if ($line -cmatch '\A(VCToolsVersion|VCToolsInstallDir|WindowsSdkDir|WindowsSDKVersion|INCLUDE|LIB)=(.*)\z') {
if ($values.ContainsKey($Matches[1])) { throw 'FixtureCompilerInput: duplicate compiler environment observation.' }
$values[$Matches[1]] = $Matches[2]
}
}
foreach ($name in @('VCToolsVersion','VCToolsInstallDir','WindowsSdkDir','WindowsSDKVersion','INCLUDE','LIB')) {
if (-not $values.ContainsKey($name)) { throw "FixtureCompilerInput: actual vcvars environment missing $name." }
}
if ($values.VCToolsVersion -cne $Selection.msvcVersion -or
$values.VCToolsInstallDir.TrimEnd('\') -ine (Join-Path $Selection.installationPath "VC\Tools\MSVC\$($Selection.msvcVersion)") -or
$values.WindowsSdkDir.TrimEnd('\') -ine $Selection.sdkRoot.TrimEnd('\') -or
$values.WindowsSDKVersion.TrimEnd('\') -cne $Selection.sdkVersion) {
throw 'FixtureCompilerInput: actual vcvars compiler/SDK selection differs.'
}
foreach ($pair in @(@('INCLUDE',(Join-Path $Selection.sdkRoot "Include\$($Selection.sdkVersion)\um")),
@('INCLUDE',(Join-Path $Selection.sdkRoot "Include\$($Selection.sdkVersion)\ucrt")),
@('LIB',(Join-Path $Selection.sdkRoot "Lib\$($Selection.sdkVersion)\um\x64")),
@('LIB',(Join-Path $Selection.sdkRoot "Lib\$($Selection.sdkVersion)\ucrt\x64")),
@('INCLUDE',(Join-Path $Selection.installationPath "VC\Tools\MSVC\$($Selection.msvcVersion)\include")),
@('LIB',(Join-Path $Selection.installationPath "VC\Tools\MSVC\$($Selection.msvcVersion)\lib\x64")))) {
$expected = $pair[1]
$actualPaths = @($values.($pair[0]) -split ';' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } |
ForEach-Object { [IO.Path]::GetFullPath($_).TrimEnd('\') })
if ($expected -inotin $actualPaths) {
throw "FixtureCompilerInput: actual $($pair[0]) does not contain the selected compiler/SDK inputs."
}
}
foreach ($pair in @(@($Selection.compiler,'compilerSha256'),@($Selection.vcvars,'vcvarsSha256'))) {
if ((Get-FileHash -LiteralPath $pair[0] -Algorithm SHA256).Hash -cne $Selection.($pair[1])) {
throw 'FixtureCompilerInput: selected tool bytes changed during compilation.'
}
}
}
60 changes: 45 additions & 15 deletions Tools/windows/Invoke-MatchedActionSupplement.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ param(
[Parameter(Mandatory)][string]$OwnedRoot,
[Parameter(Mandatory)][string]$ActionPlanPath,
[Parameter(Mandatory)][ValidatePattern('^[A-Fa-f0-9]{64}$')][string]$ActionPlanSha256,
[switch]$DryRun
[switch]$DryRun,
[switch]$FunctionalWireOnly,
[switch]$WireCensusDiagnostic
)
$ErrorActionPreference='Stop'
if ($WireCensusDiagnostic -and (-not $FunctionalWireOnly -or $DryRun)) {
throw 'Wire census diagnostic requires FunctionalWireOnly and refuses DryRun.'
}
$root=[IO.Path]::GetFullPath($OwnedRoot).TrimEnd('\')
$repositoryRoot=[IO.Path]::GetFullPath($Repository).TrimEnd('\')
$planPath=[IO.Path]::GetFullPath($ActionPlanPath)
Expand All @@ -14,6 +19,12 @@ if (-not $planPath.StartsWith($root + '\',[StringComparison]::OrdinalIgnoreCase)
throw 'Action supplement plan path or hash mismatch.'
}
$plan=Get-Content $planPath -Raw | ConvertFrom-Json -DateKind String
$functional=[bool]($plan.PSObject.Properties['functionalWireOnly'] -and $plan.functionalWireOnly)
if ($functional -ne $FunctionalWireOnly.IsPresent -or ($functional -and
($plan.group -cne 'WireCompletion' -or $plan.maximumResultPngs -ne 0 -or
@($plan.imageBindings.PSObject.Properties).Count -ne 0))) {
throw 'Functional Wire execution requires the explicit W1-only no-image opt-in.'
}
if ($plan.status -cne 'PREPARED_NO_AUTHORITY' -or $plan.pngArtifacts -ne 0 -or
$plan.processLaunches -ne 0 -or @(Get-ChildItem $root -Recurse -File -Filter '*.png').Count -ne 0) {
throw 'Action supplement plan no-authority boundary differs.'
Expand All @@ -29,6 +40,8 @@ $workerPath=Join-Path $repositoryRoot 'Tools\windows\Invoke-UiCaptureWorker.ps1'
$stubPath=Join-Path $repositoryRoot 'Tools\windows\Stub-Daemon.ps1'
$actionRunnerPath=$PSCommandPath
$actionSeedHelperPath=Join-Path $repositoryRoot 'Tools\windows\Start-MatchedActionSessions.ps1'
$sceneInput=if ($functional) {@($plan.functionalWireState.path,$plan.functionalWireState.sha256)}
else {@($plan.existingSceneManifestPath,$plan.existingSceneManifestSha256)}
foreach ($binding in @(
@($modulePath,$plan.moduleSha256),
@($workerPath,$plan.workerSha256),
Expand All @@ -37,7 +50,7 @@ foreach ($binding in @(
@($actionSeedHelperPath,$plan.actionSeedHelperSha256),
@($plan.jobPath,$plan.jobSha256),
@($plan.preflightReceiptPath,$plan.preflightReceiptSha256),
@($plan.existingSceneManifestPath,$plan.existingSceneManifestSha256)
@($sceneInput[0],$sceneInput[1])
)) {
if (-not (Test-Path $binding[0] -PathType Leaf) -or
(Get-FileHash $binding[0] -Algorithm SHA256).Hash -ne [string]$binding[1]) {
Expand Down Expand Up @@ -88,7 +101,10 @@ $authorizationHandle=Open-CapActionAuthorization -Path $authorizationPath -Sha25
$selfProcess=$null
try {
$job=Get-Content $plan.jobPath -Raw | ConvertFrom-Json -DateKind String
if (-not $DryRun) {$matchedCapturePlan=Get-CapMatchedCapturePlan -Job $job}
if ((Test-CapFunctionalWireJob -Job $job -Group $plan.group) -ne $functional) {
throw 'Functional Wire job and explicit execution opt-in differ.'
}
if (-not $DryRun -and -not $functional) {$matchedCapturePlan=Get-CapMatchedCapturePlan -Job $job}
$fixturePath=Join-Path $root 'fixtures\fixture.json'
$peerScript=Join-Path $root 'inputs\offline-peer-source.ps1'
$runDirectory=$actionRunDirectory
Expand All @@ -103,6 +119,7 @@ $leaseWindow=$authorizationHandle.Window
$leaseDeadlineUtc=$leaseWindow.WorkerDeadlineUtc
$focusedCapture=$true
$actionSupplementMode=$true
$wireCensusDiagnosticMode=$WireCensusDiagnostic.IsPresent
$rehearsal=$false
$transitionRehearsal=$false
$fixtureHash=(Get-FileHash $fixturePath -Algorithm SHA256).Hash
Expand All @@ -128,6 +145,7 @@ $dryRunLauncher=$null
$dryRunProof=$null
try {
Assert-CapWorkerDeadline 'action entry'
if (-not $DryRun) {Initialize-CapUiaClient}
$boundWindows=@(Assert-CapActionWindowContext)
$wireTargetPreflight=if ($plan.group -cne 'TerminalActions') {Get-CapWorkerWireBinding} else {$null}
$windowPreflight=@(foreach ($binding in $boundWindows) {
Expand Down Expand Up @@ -194,9 +212,9 @@ try {
geometry=$null
preconditionsEvaluated=$true
}
if (-not (Test-CapMatchedDpiAdapter)) {throw 'Action dry run requires the production matched DPI contract.'}
if (-not (Test-CapMatchedDpiAdapter) -and -not $functional) {throw 'Action dry run requires the production matched DPI contract.'}
$dryRunProof.geometry=$windowPreflight[0].geometry
} else {
} elseif (-not $functional) {
$matchedFixture=Get-Content $fixturePath -Raw | ConvertFrom-Json -DateKind String
Initialize-CapMatchedWorktrees -Fixture $matchedFixture
}
Expand All @@ -214,11 +232,20 @@ try {
throw 'Terminal action supplement receipt or provider count differs.'
}
} elseif ($plan.group -ceq 'WireCompletion') {
$receipt=Invoke-CapWireCompletionSupplement -StubDaemonPath $stubPath
$receipt | Add-Member -NotePropertyName actionIds -NotePropertyValue @('W1')
$receipt | Add-Member -NotePropertyName imageBindingSha256 `
-NotePropertyValue ([string]$plan.imageBindings.'s-goal-unwired-unselected')
$actionSupplementReceipts.Add($receipt)
$receipt=Invoke-CapWireCompletionSupplement -StubDaemonPath $stubPath `
-FirstCensusDiagnostic:$WireCensusDiagnostic
if ($WireCensusDiagnostic) {
if ($null -ne $receipt -or $actionSupplementReceipts.Count -ne 0 -or $images.Count -ne 0) {
throw 'Wire census diagnostic produced an action receipt or image.'
}
} else {
$receipt | Add-Member -NotePropertyName actionIds -NotePropertyValue @('W1')
if (-not $functional) {
$receipt | Add-Member -NotePropertyName imageBindingSha256 `
-NotePropertyValue ([string]$plan.imageBindings.'s-goal-unwired-unselected')
}
$actionSupplementReceipts.Add($receipt)
}
} else {
$wireReceipt=Invoke-CapWireCompletionSupplement -StubDaemonPath $stubPath
$wireReceipt | Add-Member -NotePropertyName actionIds -NotePropertyValue @('W1')
Expand Down Expand Up @@ -272,8 +299,9 @@ try {
[StringComparison]::OrdinalIgnoreCase)
} | Select-Object ProcessId,Name,ExecutablePath)
}
$successfulStatus=if ($WireCensusDiagnostic) {'DIAGNOSTIC_NOT_W1_ACCEPTANCE'} else {'COMPLETE'}
$terminalOutcome=if (-not $primaryFailure -and $cleanupFailures.Count -eq 0 -and
$independent.Count -eq 0) {'COMPLETE'} else {'FAILED'}
$independent.Count -eq 0) {$successfulStatus} else {'FAILED'}
try {
Write-CapWorkerJournalSnapshot -Kind 'Terminal' -Outcome $terminalOutcome
} catch {
Expand All @@ -283,13 +311,15 @@ try {
$manifest=[ordered]@{
schemaVersion=1L
status=$(if (-not $primaryFailure -and $cleanupFailures.Count -eq 0 -and
$independent.Count -eq 0) {'COMPLETE'} else {'FAILED'})
$independent.Count -eq 0) {$successfulStatus} else {'FAILED'})
group=$plan.group
sourceHead=$head
sourceTree=$tree
actionPlanSha256=$ActionPlanSha256.ToUpperInvariant()
authorizationSha256=$authorizationHandle.Sha256
executionMode=$(if ($DryRun) {'DRY_RUN_NO_AUTHORITY'} else {'MATCHED_ACTION_SUPPLEMENT'})
executionMode=$(if ($DryRun) {'DRY_RUN_NO_AUTHORITY'}
elseif ($WireCensusDiagnostic) {'DIAGNOSTIC_NOT_W1_ACCEPTANCE'}
elseif ($functional) {'FUNCTIONAL_W1_STATE_ONLY_NOT_VISUAL_PARITY'} else {'MATCHED_ACTION_SUPPLEMENT'})
dryRun=$dryRunProof
startedUtc=$startedUtc.ToString('o')
finishedUtc=[DateTime]::UtcNow.ToString('o')
Expand All @@ -316,7 +346,7 @@ $manifestPath=Join-Path $output 'action-manifest.json'
[Text.UTF8Encoding]::new($false))
$release=[ordered]@{
schemaVersion=1L
status=$(if ($manifest.status -ceq 'COMPLETE') {'RELEASED_ZERO_SURVIVORS'}
status=$(if ($manifest.status -ceq $successfulStatus) {'RELEASED_ZERO_SURVIVORS'}
elseif ($independent.Count -eq 0) {'FAILED_ZERO_SURVIVORS'} else {'CLEANUP_UNPROVEN'})
cleanupState=$(if ($runs.Count -eq 0 -and $independent.Count -eq 0 -and $cleanupFailures.Count -eq 0) {
'NO_PROCESS_LAUNCHES'
Expand All @@ -335,7 +365,7 @@ $release=[ordered]@{
$releasePath=Join-Path $output 'action-release.json'
[IO.File]::WriteAllText($releasePath,($release|ConvertTo-Json -Depth 20),
[Text.UTF8Encoding]::new($false))
if ($manifest.status -cne 'COMPLETE' -or $release.status -cne 'RELEASED_ZERO_SURVIVORS') {
if ($manifest.status -cne $successfulStatus -or $release.status -cne 'RELEASED_ZERO_SURVIVORS') {
throw "Action supplement failed: $($manifest.failures -join '; ') cleanup=$($cleanupFailures -join '; ') survivors=$($independent.Count)"
}
if ($manifest.pngCount -ne $(if ($DryRun) {0L} else {[long]$plan.maximumResultPngs})) {
Expand Down
6 changes: 5 additions & 1 deletion Tools/windows/Invoke-UiCapture.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -1420,11 +1420,15 @@ try {
$workerLaunchAttempted = $true
[CapProcessJob]::ClearStandardHandleInheritance()
$workerJob = [CapProcessJob]::Create()
$workerEnvironment=@{}
if ([Environment]::GetEnvironmentVariables('Process').Contains('GRAPHCODE_VALIDATION_ASSEMBLY')) {
$workerEnvironment['GRAPHCODE_VALIDATION_ASSEMBLY']=$env:GRAPHCODE_VALIDATION_ASSEMBLY
}
$workerRun = Start-CapManagedProcess -FilePath $pwshPath -ArgumentList @(
'-NoProfile', '-File', $workerPath,
'-AuthorizationPath', $authorizationPath,
'-AuthorizationSha256', $authorizationHash, '-OwnedRoot', $root, '-AwaitSupervisorGate'
) -WorkingDirectory $runDirectory -Role 'b-capture-worker' -HoldStdin
) -WorkingDirectory $runDirectory -Role 'b-capture-worker' -HoldStdin -Environment $workerEnvironment
[CapProcessJob]::Assign($workerJob, $workerRun.Identity.Process.Handle)
$journalBinding = New-CapJournalBinding -RunId ([IO.Path]::GetFileName($runDirectory)) `
-LeaseId $authorityId -JobSha256 $jobHash -ModuleSha256 $moduleHash `
Expand Down
Loading
Loading