fix: Aside readiness probe reports a false ASIDE_NOT_RUNNING on zsh - #2854
Open
csarigoz wants to merge 1 commit into
Open
fix: Aside readiness probe reports a false ASIDE_NOT_RUNNING on zsh#2854csarigoz wants to merge 1 commit into
csarigoz wants to merge 1 commit into
Conversation
The BROWSER SETUP probe built its deadline command into a variable (`_T="gtimeout 30"`) and then invoked it unquoted (`$_T aside repl ...`), relying on bash word-splitting. zsh does not word-split unquoted parameter expansions, so it tried to exec a single command literally named "gtimeout 30", got `command not found`, missed the ASIDE_READY sentinel, and reported ASIDE_NOT_RUNNING on a machine where Aside was running fine. The consequence is worse than a bad status line: every browsing skill then silently falls back to the bundled headless browser, which carries none of the user's cookies or signed-in sessions. A page behind a login returns a signed-out view with no error, and the skill blames the site rather than the probe. On zsh hosts this made the "Aside is the browser gstack drives first" contract (garrytan#2810) unreachable. The perl branch was broken on bash too: unquoted, the `;` in `_T="perl -e alarm(shift);exec(@argv) 30"` split it into two commands. Applies the deadline through a shell function instead, which behaves identically in bash, zsh, and sh. Keeps the gtimeout -> timeout -> perl alarm chain, the GSTACK_SKIP_ASIDE=1 opt-out, and the version echo. Verified on macOS 15 (zsh 5.9), aside 1.26.906.1630: before, zsh: ASIDE_NOT_RUNNING (Aside running the whole time) after, zsh: READY: aside 1.26.906.1630 after, bash: READY: aside 1.26.906.1630 after, sh: READY: aside 1.26.906.1630 after, GSTACK_SKIP_ASIDE=1: NEEDS_ASIDE Fix lands in scripts/resolvers/aside.ts, so it reaches both {{ASIDE_SETUP}} and {{ASIDE_RESEARCH}} and all 20 skills that carry the probe. Test pins updated to the function form, plus a regression pin rejecting any `$_T` word-splitting reliance. The three ship goldens are regenerated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NqkBGJEhwh8H6FMH4BuUdu
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
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.
Why (in your own words)
On any machine whose shell is zsh, the BROWSER SETUP probe reports
ASIDE_NOT_RUNNINGwhile Aside is running perfectly. The status line is thesmall part. The real damage is that every browsing skill then drops to the
bundled headless browser, which has none of the user's cookies or signed-in
sessions — so a page behind a login comes back signed-out with no error, and
the skill blames the site instead of the probe. #2810 made Aside the browser
gstack drives first; on zsh hosts that contract was quietly unreachable.
I hit this doing real outreach work: I needed live newsletter metrics off a
media-kit page, the probe said Aside was down, and I spent the task on the
headless fallback before noticing Aside had been up the whole time.
The cause is a bash-ism. The probe builds its deadline into a variable and
invokes it unquoted:
zsh does not word-split unquoted parameter expansions, so
$_Texpands to oneword and it execs a command literally named
"gtimeout 30". Command not found,sentinel missed, false negative. The perl branch was broken on bash too —
unquoted, the
;in_T="perl -e alarm(shift);exec(@ARGV) 30"split it intotwo commands.
Fix applies the deadline through a shell function, which behaves the same in
bash, zsh, and sh. The gtimeout → timeout → perl alarm chain, the
GSTACK_SKIP_ASIDE=1opt-out, and the version echo all survive.Live evidence
Environment: macOS 15 (Darwin 25.6.0), zsh 5.9, aside 1.26.906.1630.
The false negative, before the fix. Aside was running throughout:
The mechanism, isolated:
After the fix — the probe extracted from the regenerated
browse/SKILL.mdand run under each shell:
The perl branch still enforces its deadline (2s alarm against a 10s sleep):
End to end through the fixed path — the same page that started this,
now read through Aside rather than the fallback:
Tests:
The 2 failures are
name: gstack-ship/name: gstack-codexvs theunprefixed upstream names — pre-existing on any
skill_prefix: trueinstallafter
gstack-relink, present before this branch, and untouched by it. Thegoldens in this PR are regenerated unprefixed so they stay correct for a clean
checkout.
Scope
scripts/resolvers/aside.ts(the probe, single source for{{ASIDE_SETUP}}and{{ASIDE_RESEARCH}});test/aside-driver.test.ts(pins moved to the function form, plus a regression pin rejecting any
$_Tword-splitting reliance); the 20 regenerated SKILL.md files; the three ship
goldens;
llms.txtand the agents digest from the same regen.confirming the opt-out; confirming the perl deadline fires; driving a real
page through Aside end to end; the test runs above.
gtimeout, so thetimeoutbranch is the live one there — exercised only via the isolated function
test above, not a full run). Did not run the complete
bun testsuite: ithung with no output past 10 minutes on this machine, before and independent
of this change.
yours to cut. Happy to add an entry if you want it in the PR.
Liveness proof (required)
Not attached yet — @csarigoz will add it as the first comment on this PR.
Being straight with you about why, because the check exists precisely for this
case. The code here was written by Claude Code in Cagri's session, on his
machine, against a bug he hit doing real work. He authorized opening the PR.
The liveness screenshot attests that a human opened it, so producing one from
inside the agent session would be manufacturing exactly the evidence the check
is designed to catch — no matter that the terminal and the typing would be
real. That's not Cagri's to waive on your behalf, so it is left for him.
Close this if an unattested PR is not worth your queue time. The diff and the
evidence above stand on their own either way, and the bug is reproducible on
any zsh host in two lines:
Checklist
Authored by Claude Code (Opus 5) in @csarigoz's session. Regression-pinned in
test/aside-driver.test.tsso the bash-ism cannot return.