fix(studio): memoize only a launch that was actually attempted - #515
Merged
KnockOutEZ merged 2 commits intoAug 28, 2026
Merged
Conversation
A launcher decline, the memoMs:0 read/write asymmetry, a thenable read as an outcome, and the shipped 60s window all land as arms before the fix. normalizeLaunch is exported so the shape rejection is asserted at its own seam rather than inferred from a null two layers away.
A decline arrived back through the shared promise as a bare null, so it was remembered for 60s exactly like a launch that ran and timed out. The commonest decline is the substrate presence TTL disagreeing with an uncached record read, which a reinstall resolves in the next second — so a fixed machine was locked out for the rest of the window. The pass now reports whether anything was started, and only that case is remembered. memoMs 0 is honoured at the read as well as the write, so the documented escape hatch is not silently declined by another caller's window. normalizeLaunch throws on a thenable or on an object with no boolean started, instead of reading undefined as a decline and skipping the poll.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes wigolo-studio-run#185 (PX0 exit-4, K1/K3/K5 + coverage gap 2).
What was wrong
ensureStudioRunning's memo was written on the shared promise from a barenull, which cannotdistinguish a launch that ran and produced no handle from one that never started. A launcher
DECLINE — the normal outcome when
substratePresent()'s 5s TTL disagrees withdefaultLaunch'suncached record read — was therefore remembered for 60s, so a substrate reinstalled a second later
was declined with zero spawn attempts: the lockout the memo's own docstring forbids.
Three siblings landed with it:
memoMs: 0disabled the write but not the read, so the documentedescape hatch was silently declined by another caller's window;
normalizeLaunchread any object asan outcome, so an async launcher's Promise (
.started === undefined) became a silent instantdecline with the poll skipped; and
DEFAULT_NO_HANDLE_MEMO_MSwas unpinned — raising it to an hourleft all 103 arms green because every memo arm passed
memoMsexplicitly.What changed
{ handle, attempted }. Onlyattempted && !handleis memoized, whichmakes the comment above the gate true. A launcher that threw counts as not attempted for the same
reason a decline does — nothing started, nothing waited for, re-attempt costs one throw.
memoMs: 0is honoured at the read as well as the write. It does not disable single-flight.normalizeLaunchthrows on a thenable, and on an object with no booleanstarted.equality assert.
Decisions recorded in DECISIONS-AUTO as A-185-1 (read-honouring for
memoMs: 0) and A-185-2 (athrow is not memoized), each with its reversal condition.
Demo — red before / green after
Arm (a), against the tip before the fix:
After:
Tests 34 passed (34).Mutation probe for the coverage arm —
DEFAULT_NO_HANDLE_MEMO_MSset to3_600_000:Constant restored by reverse-edit; suite green again.
Verification
CI deferred — quota.