Cleanup: remove LocalScriptService timing-race workarounds (PR #275 fixed at root)
Summary
- Removes 9
Start-Sleep N/sleep Ntiming-workaround prefixes that PRs #267, #273, and several first-runners added to chase the LocalScriptService race - PR #275 fixed the race at the root (
CompleteScriptnow drains async stream readers viaWaitForExit()before reading logs). The workarounds are now redundant - This cleanup IS the validation of #275's fix — if any test flakes post-cleanup, the root-cause fix isn't sufficient and we have a clean diagnostic
What's removed
Linux deploy E2E (TentacleLinuxDeployE2ETests)
| Test | Before | After |
|---|---|---|
| LD7h Output variable | sleep 1; echo "##squid..." |
echo "##squid..." |
| LD8h Polling EchoScript | sleep 1; echo |
echo |
| LD11h File transfer | sleep 1; cat '<file>' |
cat '<file>' |
| LD12h Sensitive variable | sleep 1; echo "##squid... sensitive='True'" |
echo "##squid..." |
| LD13h Multi-file transfer | sleep 1; cat ... cat ... cat |
cat ... cat ... cat |
Windows deploy E2E (TentacleDeployE2ETests)
| Test | Before | After |
|---|---|---|
| D1.h Listening EchoScript | SleepThenEcho(2, ...) |
Echo(...) |
| D2.h Polling EchoScript | SleepThenEcho(1, ...) |
Echo(...) |
| D13.h Unicode | SleepThenEcho(2, ...) |
Echo(...) |
EmitServiceMessage helper |
Start-Sleep -Seconds 2\n... / sleep 2\n...
|
(no prefix) — affects D7h plain + sensitive output variables and D7.u1 base64 variant |
What's preserved (intentional, NOT race workarounds)
-
LD5h
sleep 3and Windows D9.hSleepThenEcho(3)— testing long-running script behaviour, not a workaround -
LD10h
sleep 2per-ticket — concurrent overlap timing for isolation test (3 tickets running concurrently for ~2s window) -
Windows D10h staggered
SleepThenEcho(2/4/6)— staggered emit ordering for concurrent multiplex isolation. Different concern from PR #275's race — the latter is per-ticket async-reader drain; the former is cross-ticket emit ordering at the agent's pipeline. Keeping conservative — can revisit once we have data on whether #275's fix subsumes this case too
Why now
Prior to PR #275, every short-lived dispatch test had a sleep prefix like sleep 1 or Start-Sleep 2 to give pwsh.exe / bash spawn time before the marker emit. These were painful to maintain (round 1 → round 9 of escalation across multiple PRs), CI-time-expensive (~25-30s per Linux runner, ~30-40s per Windows runner), and obscured the underlying production bug.
PR #275's fix in LocalScriptService.CompleteScript:
if (!running.Process.HasExited)
running.Process.WaitForExit(TimeSpan.FromSeconds(30));
// ALWAYS drain async stream readers
running.Process.WaitForExit(); // ← no-arg flush
var logs = ReadLogs(running, ...);
Per .NET docs: WaitForExit() (no-arg) flushes async event handlers before returning. With this on every CompleteScript path, async readers always drain BEFORE log file reads — regardless of how fast the script exited.
Validation strategy
This cleanup PR is itself the validation. Three possible CI outcomes:
-
All green → PR #275's fix subsumes the timing race; the workarounds were correctly redundant.
✅ - A specific test flakes → PR #275's fix is insufficient for some specific path; revert that specific sleep, and add a comment explaining why
- Many tests flake → PR #275's fix has a subtle bug; revert the entire cleanup and dig deeper
Test plan
-
dotnet buildboth projects — 0 errors -
CI on ubuntu-latest(Tentacle Linux E2E) — all 70+ tests still green -
CI on windows-latest(Tentacle Windows E2E) — all 90+ tests still green -
Re-run both workflows 2-3 times (manual workflow_dispatch) to confirm no flakes — important because the prior workarounds were specifically chasing intermittent failures
CI time savings (after merge)
- Linux runner: ~25-30s saved per run (5 tests × ~5s sleep average)
- Windows runner: ~30-40s saved per run (4 tests × ~7s sleep average + EmitServiceMessage's 2s × 3 tests)