Repository navigation
fix: Test Gateway MSIX host check hangs on GitHub-hosted runners - #107
Conversation
Spectre.Console's default profile enrichers re-decide console capabilities from ambient CI variables. On GitHub-hosted runners, GITHUB_ACTIONS=true turned Interactive off and Ansi on after ClawCtlConsole.CreateConsole had requested an interactive, color-cleared console, so the live status fell back to plain lines and never drew a spinner frame. GatewayNarrationPreservesUnicodeCapabilityForNonConsoleOutput waited for a spinner frame without a bound, so the Test Gateway MSIX host job stalled until the six-hour limit with 1101 of 1107 tests complete. The reported "Unrecognized command or argument '--recovery'" crash reason was the expected parse error of GatewayServiceRestartRejectsTheRecoveryMarker, written to the test host's stderr, not a VSTest incompatibility. - Disable Spectre's default enrichers in CreateConsole so clawctl's color policy and console detection stay the only capability owner. - Wait for the rendered stage instead of a spinner frame, so a lost live display fails the frame assertion instead of hanging. - Capture the parser test's output and assert on the rejected token. - Bound the CI test step with blame hang detection and upload the dump. - Record the ownership rule in the output style guide. Fixes #105 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs maintainer review before merge. Reviewed September 23, 2026, 2:26 PM ET / 18:26 UTC. ClawSweeper reviewWhat this changesThe branch keeps Regression provenancePossible regression — probable (reproduction; reviewed change). No predecessor PR is attributed. Merge readiness✅ Ready for maintainer review This PR remains useful: current main still has the CI-sensitive console behavior and unbounded spinner wait. The branch addresses both, and the supplied Windows before-and-after runs support the fix. No introduced defect or unresolved merge concern was found. Priority: P2 Review scores
Verification
How this fits togetherWindows packaging CI runs launcher tests on a hosted Windows worker. The launcher chooses terminal capabilities before Spectre renders gateway progress; the test result feeds the MSIX CI check. flowchart LR
A[CI environment] --> B[Launcher color policy]
B --> C[Spectre console]
C --> D[Gateway progress]
D --> E[Test observation]
E --> F[MSIX CI result]
F --> G[Hang diagnostics]
Before mergeNone. Agent review detailsSecurityNone. Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Technical reviewBest possible solution: Keep the launcher as the console-capability owner and retain a test that reports missing spinner rendering promptly, with bounded CI diagnostics for future hangs. Do we have a high-confidence way to reproduce the issue? Yes. The supplied current-main CI trace identifies the unfinished narration test, and a Windows run reproduces its hang with GITHUB_ACTIONS=true. Is this the best way to solve the issue? Yes. The patch changes the existing console factory where capabilities are chosen and preserves a spinner assertion while removing the test's reported unbounded wait. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 84092f0ffe11. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
Closes #105
What Problem This Solves
Fixes: the GitHub Actions
Test Gateway MSIX hostcheck hangs until the six-hour job limit when it runs on a GitHub-hosted runner, although the suite finishes in seconds locally.User Impact
User impact: contributors get a
Test Gateway MSIX hostresult in minutes again instead of a six-hour cancellation, and a test that stops making progress now fails the job after three minutes with the unfinished test named and a minidump attached.clawctloutput for users is unchanged except under a CI provider such as GitHub Actions or Azure Pipelines, where it now followsclawctl's documented color and interactivity policy instead of Spectre.Console's own CI detection.Why This Change Was Made
clawctldecides color, interactivity, width, and Unicode itself, but Spectre.Console's default profile enrichers overrode those choices whenever a CI provider variable was set. Disabling the enrichers whereclawctlcreates its consoles leavesclawctlas the only owner of those decisions. The narration test that waited without a bound for a spinner frame now waits for the reported stage, which every renderer writes, so a lost live display fails its assertion instead of holding the test host open. The workflow's test step now fails after three minutes without test activity and uploads the hang dump.Root cause
GITHUB_ACTIONS=truemakes Spectre's GitHub enricher turnInteractiveoff andAnsion, overriding the interactive consoleclawctlrequested. The live status then writes plain stage lines and never draws a spinner frame.GatewayNarrationPreservesUnicodeCapabilityForNonConsoleOutput, added in fix: preserve automatic gateway startup feedback #97, awaited a spinner frame with no bound, so it never finished. xUnit runs a class's tests in sequence, so the five tests after it inClawCtlConsoleTestsnever started. That is why CI reported 1101 passing tests instead of 1107.Unrecognized command or argument '--recovery'text in the abort reason is not a VSTest or Microsoft.Testing.Platform mismatch, and no package versions change here.GatewayServiceRestartRejectsTheRecoveryMarkerdeliberately parses--recovery, and System.CommandLine wrote the rejection to the test host's real standard error, which VSTest appended to its crash reason when blame killed the host. That test now captures its own output and asserts on the rejected token.Evidence
Evidence head:
cf6b88c6b8bfe06b6b06854100d654ae5d261973, based on96770f14d73edfcba41964c08cd2f64f39420278.mainhas since gained #106, which changes none of these files; this PR's CI run tested the merge with it. Local runs were on Windows x64 from the working tree committed as this head.When it started. The Gateway MSIX workflow on
mainpassed through #102. Every run since #97 added the test has stalled in theTeststep:maincommitTeststepfc5b15b(#102)092e451(#97)96770f1(#101)84092f0(#106)Before the fix.
GatewayNarrationPreservesUnicodeCapabilityForNonConsoleOutputthe only incomplete one. The five that never started are the rest ofClawCtlConsoleTests.GITHUB_ACTIONS=true: that test alone aborts at the blame timeout, and without the variable it passes in 216 ms. Running it together withGatewayServiceRestartRejectsTheRecoveryMarkerreproduces the exact CI lineTest host process crashed : Unrecognized command or argument '--recovery'.CreateConsole's settings: the default enrichers changeInteractive,Ansi, andLinksonly whenGITHUB_ACTIONSorTF_BUILDis set. With the enrichers disabled, every environment reports the requested capabilities, and a live status draws spinner frames again.Regression proof. With the updated tests and the unfixed console factory under
GITHUB_ACTIONS=true, the narration test fails in 184 ms withAssert.Contains() Failure: Filter not matched in collectioninstead of hanging.On a GitHub-hosted runner. CI run 35902102316 for this head passed, including the workflow's merge gate:
Test Gateway MSIX hostTeststep took 14 s for 1107/1107 under--blame-hang-timeout 3min, so the hang upload was skipped. 27 NativeAOT scenarios passed.Build unsigned x64 Gateway MSIX,Build unsigned arm64 Gateway MSIXBuild unsigned multi-architecture Gateway MSIX bundleGateway MSIX CILocally after the fix.
dotnet test .\OpenClaw.Gateway.MSIX.slnx --configuration Release --blame-hang-timeout 3min --blame-hang-dump-type miniwithGITHUB_ACTIONS=trueandCI=truedotnet test .\OpenClaw.Gateway.MSIX.slnx --configuration Release --no-buildwithout CI variablesClawCtlConsoleTests,ClawCtlCommandLineTests,AgentGatewayGuidanceTests, andGatewayAddressTestswithTF_BUILD=TrueGITHUB_ACTIONSandCI.\scripts\Test-DotNetQuality.ps1 -Configuration Release.\scripts\Test-NativeAotCli.Tests.ps1 -Configuration Release.\scripts\Test-WorkflowSigningConfiguration.ps1,.\scripts\Test-WorkflowPackageVersion.Tests.ps1,.\scripts\Test-PackagingRelevance.Tests.ps1.\scripts\Test-DocReferences.ps1;git diff --checkA local ClawSweeper
review --local-rangeof this head reported the patch correct with no review comments, cleared security, and rated the proof sufficient.Not run: test signing, which this workflow runs only for a manual dispatch in
testsigning mode; the proof-release identity transition, which runs only for pull requests that change versioning; and ARM64 execution, since no ARM64 host was available and CI only builds ARM64.CI log before the fix (run 35841172733)
Tests listed locally but absent from that run's sequence file:
CI log after the fix (run 35902102316)
Local reproduction and regression output
On the base commit, with
$env:GITHUB_ACTIONS = 'true':The same command without
GITHUB_ACTIONS:With
GITHUB_ACTIONS=trueand the filter widened toFullyQualifiedName~GatewayNarrationPreservesUnicodeCapabilityForNonConsoleOutput|FullyQualifiedName~GatewayServiceRestartRejectsTheRecoveryMarker:The updated tests with the unfixed
CreateConsole, underGITHUB_ACTIONS=true:Spectre.Console capability probe
Each console mirrors
CreateConsoleand varies only the environment and the default enrichers:Resulting profile capabilities.
markupHasEscaperecords whether[bold]bold[/] plainrendered an escape sequence:A live status with the Dots spinner, run for 600 ms under
GITHUB_ACTIONS=true:Local output after the fix
With
$env:GITHUB_ACTIONS = 'true'and$env:CI = 'true':Without CI variables:
With
$env:TF_BUILD = 'True', filtered to the console, command-line, gateway guidance, and gateway address tests:The narration test repeated with
--blame-hang-timeout 30s: