Skip to content

Commit 04d146c

Browse files
author
Agent Runner
committed
feat: project loop topology into runbook results (#1905)
1 parent 01d3888 commit 04d146c

2 files changed

Lines changed: 89 additions & 2 deletions

File tree

scripts/Invoke-IntegrationRunbook.ps1

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ function Invoke-PhaseLoop {
257257
param($r,$ctx)
258258
Write-PhaseBanner $r.name
259259
$env:LOOP_SIMULATE = '' # ensure real
260+
$loopFinalStatusPath = Join-Path ([System.IO.Path]::GetTempPath()) ("runbook-loop-final-status-" + [guid]::NewGuid().ToString() + ".json")
260261
# Optional quick/override controls via env (non-breaking defaults)
261262
try {
262263
if (-not $PSBoundParameters.ContainsKey('LoopIterations')) {
@@ -270,9 +271,36 @@ function Invoke-PhaseLoop {
270271
try { if ($env:RUNBOOK_LOOP_QUICK -match '^(?i:1|true|yes|on)$') { $failOn = $true } } catch {}
271272
$env:LOOP_FAIL_ON_DIFF = ($failOn ? 'true' : 'false')
272273
try {
273-
& (Join-Path (Get-Location) 'scripts' 'Run-AutonomousIntegrationLoop.ps1')
274+
& (Join-Path (Get-Location) 'scripts' 'Run-AutonomousIntegrationLoop.ps1') -FinalStatusJsonPath $loopFinalStatusPath
274275
$code = $LASTEXITCODE
275276
$r.details.exitCode = $code
277+
$r.details.finalStatusPath = $loopFinalStatusPath
278+
if (Test-Path -LiteralPath $loopFinalStatusPath -PathType Leaf) {
279+
try {
280+
$finalStatus = Get-Content -LiteralPath $loopFinalStatusPath -Raw | ConvertFrom-Json -ErrorAction Stop
281+
$r.details.loopIterations = $finalStatus.iterations
282+
if ($finalStatus.PSObject.Properties.Name -contains 'harness' -and $finalStatus.harness) {
283+
$r.details.harness = $finalStatus.harness
284+
$r.details.executionTopology = [ordered]@{
285+
runtimeSurface = $finalStatus.harness.runtimeSurface
286+
processModelClass = $finalStatus.harness.processModelClass
287+
windowsOnly = $finalStatus.harness.windowsOnly
288+
requestedSimultaneous = $finalStatus.harness.requestedSimultaneous
289+
cellClass = $finalStatus.harness.cellClass
290+
executionCellLeasePath = $finalStatus.harness.executionCellLeasePath
291+
executionCellId = $finalStatus.harness.executionCellId
292+
executionCellLeaseId = $finalStatus.harness.executionCellLeaseId
293+
harnessInstanceLeasePath = $finalStatus.harness.harnessInstanceLeasePath
294+
harnessInstanceLeaseId = $finalStatus.harness.harnessInstanceLeaseId
295+
harnessInstanceId = $finalStatus.harness.harnessInstanceId
296+
}
297+
}
298+
} catch {
299+
$r.details.finalStatusReadError = $_.Exception.Message
300+
}
301+
} else {
302+
$r.details.finalStatusMissing = $true
303+
}
276304
if ($code -eq 0) { $r.status='Passed' } else { $r.status='Failed' }
277305
} catch {
278306
$r.details.error = $_.Exception.Message
@@ -387,4 +415,3 @@ if ($env:GITHUB_STEP_SUMMARY) {
387415
if ($PassThru) { return $final }
388416

389417
if ($overallFailed) { exit 1 } else { exit 0 }
390-

tests/IntegrationRunbook.Tests.ps1

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,66 @@ Describe 'IntegrationRunbook - Phase Selection & JSON' -Tag 'Unit' {
115115
Remove-Item Env:LV_HEAD_VI -ErrorAction SilentlyContinue
116116
}
117117
}
118+
119+
It 'projects loop execution topology from the loop final status into Loop phase details' {
120+
$tempRepo = Join-Path $TestDrive 'runbook-loop-topology'
121+
$scriptsDir = Join-Path $tempRepo 'scripts'
122+
New-Item -ItemType Directory -Path $scriptsDir -Force | Out-Null
123+
124+
$runbookCopy = Join-Path $scriptsDir 'Invoke-IntegrationRunbook.ps1'
125+
Copy-Item -LiteralPath $runScript -Destination $runbookCopy -Force
126+
127+
$loopStub = @"
128+
param([string]`$FinalStatusJsonPath)
129+
`$payload = [ordered]@{
130+
schema = 'loop-final-status-v1'
131+
timestamp = '2026-03-24T12:30:00Z'
132+
iterations = 2
133+
diffs = 0
134+
errors = 0
135+
succeeded = `$true
136+
harness = [ordered]@{
137+
runtimeSurface = 'windows-native-teststand'
138+
processModelClass = 'parallel-process-model'
139+
windowsOnly = `$true
140+
requestedSimultaneous = `$true
141+
cellClass = 'worker'
142+
executionCellLeasePath = 'tests/results/_agent/runtime/execution-cell-hooke-loop.json'
143+
executionCellId = 'exec-cell-hooke-loop-01'
144+
executionCellLeaseId = 'lease-hooke-loop-01'
145+
harnessInstanceLeasePath = 'tests/results/_agent/runtime/harness-instance-hooke-loop.json'
146+
harnessInstanceLeaseId = 'harness-lease-hooke-loop-01'
147+
harnessInstanceId = 'ts-hooke-loop-01'
148+
}
149+
}
150+
(`$payload | ConvertTo-Json -Depth 8) | Set-Content -LiteralPath `$FinalStatusJsonPath -Encoding UTF8
151+
exit 0
152+
"@
153+
Set-Content -LiteralPath (Join-Path $scriptsDir 'Run-AutonomousIntegrationLoop.ps1') -Value $loopStub -Encoding UTF8
154+
155+
Set-Content -LiteralPath (Join-Path $tempRepo 'VI1.vi') -Value '' -Encoding utf8
156+
Set-Content -LiteralPath (Join-Path $tempRepo 'VI2.vi') -Value '' -Encoding utf8
157+
158+
$tmp = Join-Path $tempRepo 'tmp-runbook-loop-topology.json'
159+
Push-Location $tempRepo
160+
try {
161+
& $runbookCopy -Phases 'Prereqs,ViInputs,Loop' -JsonReport $tmp | Out-Null
162+
$LASTEXITCODE | Should -Be 0
163+
} finally {
164+
Pop-Location
165+
}
166+
167+
Test-Path $tmp | Should -BeTrue
168+
$json = Get-Content $tmp -Raw | ConvertFrom-Json
169+
$loopPhase = $json.phases | Where-Object name -eq 'Loop'
170+
$loopPhase.status | Should -Be 'Passed'
171+
$loopPhase.details.loopIterations | Should -Be 2
172+
$loopPhase.details.executionTopology.runtimeSurface | Should -Be 'windows-native-teststand'
173+
$loopPhase.details.executionTopology.processModelClass | Should -Be 'parallel-process-model'
174+
$loopPhase.details.executionTopology.executionCellLeaseId | Should -Be 'lease-hooke-loop-01'
175+
$loopPhase.details.executionTopology.harnessInstanceLeaseId | Should -Be 'harness-lease-hooke-loop-01'
176+
$loopPhase.details.executionTopology.harnessInstanceId | Should -Be 'ts-hooke-loop-01'
177+
}
118178
}
119179

120180
Describe 'IntegrationRunbook - Schema Shape Minimal Validation' -Tag 'Unit' {

0 commit comments

Comments
 (0)