From 0e8f237d2a5ef57a6ddc70986d51de821baa2e99 Mon Sep 17 00:00:00 2001 From: Ankit Ranjan Date: Thu, 20 Aug 2026 16:02:22 +0530 Subject: [PATCH] skills: SESSION_BUSY is two CLI invocations, not an in-page lock Show overlapping webcmd --session commands as the way to contend for a Session. Wait and retry; do not lock inside page.evaluate. Closes #385 --- skill-src/webcmd-browser/SKILL.src.md | 21 ++++++++++++++++++++- skill-src/webcmd-usage/SKILL.src.md | 14 +++++++++----- skills/webcmd-browser/SKILL.md | 17 ++++++++++++++++- skills/webcmd-usage/SKILL.md | 11 ++++++----- src/skills.test.ts | 2 ++ 5 files changed, 53 insertions(+), 12 deletions(-) diff --git a/skill-src/webcmd-browser/SKILL.src.md b/skill-src/webcmd-browser/SKILL.src.md index 60de9aba..f6759e72 100644 --- a/skill-src/webcmd-browser/SKILL.src.md +++ b/skill-src/webcmd-browser/SKILL.src.md @@ -151,6 +151,20 @@ JS If you split work across calls, use fresh snapshots between page transitions. Do not assume an observation from a prior route is still valid. +To contend for one Session, issue a second `webcmd --session …` while the first invocation is still running. Do not start a second driver inside one `run` (`Promise.all` of two writes, a homemade busy flag, or `page.evaluate` locking). + +```bash +# Terminal A — long run holding the Session +webcmd --session session_abc browser run --file long.js + +# Terminal B — second command against the same Session +webcmd --session session_abc browser run --stdin --no-snapshot-diff <<'JS' +return { url: page.url() }; +JS +``` + +If the second command returns `SESSION_BUSY`, wait for the listed holder, then retry that same command. Do not `--force` close a live holder. + --- ## Sitemaps @@ -248,6 +262,7 @@ Use `run` and inspect `page.frames()`; target the frame by URL/name and keep ifr - **Do not submit forms via `page.evaluate(() => document.forms[0].submit())`.** Modern sites intercept real click/submit events and silently drop direct DOM submission. Use Playwright locators and verify the post-action state. - **Do not reuse observations across a page transition.** Navigations, form submits, SPA route changes, login, and human handoff invalidate earlier observations. Take a fresh snapshot. +- **Do not implement Session occupancy inside the page.** Overlap two CLI invocations on the same `--session` id. A homemade busy flag is not `SESSION_BUSY`. - **Do not run a trigger before arming the waiter.** If a request matters, create `page.waitForResponse(...)` before the click/fill/keypress that triggers it. - **Do not trust autocomplete or masked inputs blindly.** Fill/type can appear to work while the app rejects the value. Verify visible text, `inputValue()`, or post-action state. - **Do not solve CAPTCHA or auth challenges programmatically.** Use human handoff and verification. @@ -270,7 +285,7 @@ Use `run` and inspect `page.frames()`; target the frame by URL/name and keep ifr | `run` times out before returning | Increase `--timeout` only after checking whether the wait condition is wrong. | | Write may have happened before timeout | Take a fresh snapshot before retrying. Avoid duplicate submissions. | | `SESSION_REQUIRED` | Create a Session, then retry with root `--session `. | -| `SESSION_BUSY` | Wait for the listed holder; if it is dead, `webcmd session close --force` is the last resort. | +| `SESSION_BUSY` | Wait for the listed holder, then retry the same command. If it is dead, `webcmd session close --force` is the last resort. Do not lock inside `page.evaluate`. | | `SESSION_PAUSED_FOR_HUMAN_HANDOFF` | Finish the handoff and run the returned verifier before retrying. | | Login wall appears | Use the Authentication and human handoff recipe. | | User reports login complete | Run the returned verifier first. Without one, inspect fresh state and verify identity/post-action state. | @@ -294,4 +309,8 @@ Author-only. Stripped by litprompt, so it costs the running agent nothing. Append one dated line whenever a correction lands, or whenever an approach is tried and rejected. Record what was tried and why it failed, not just what won. + +- 2026-08-20: Agents treated an in-page mutex as the session safety signal. + `SESSION_BUSY` is a CLI error from a second `webcmd --session` invocation, not + a flag inside `page.evaluate`. --> diff --git a/skill-src/webcmd-usage/SKILL.src.md b/skill-src/webcmd-usage/SKILL.src.md index 2654e3c7..5e580e99 100644 --- a/skill-src/webcmd-usage/SKILL.src.md +++ b/skill-src/webcmd-usage/SKILL.src.md @@ -73,11 +73,12 @@ webcmd session close session_abc Adapter commands may omit `--session` and use the selected profile's adapter-default session. Pass `--session ` to route one into an explicit session. Raw browser commands never omit it; the retired positional session form is invalid. Structured Session failures are runtime state, not adapter breakage. `SESSION_REQUIRED` -means add a root `--session ` selector before `browser`; `SESSION_BUSY` -means another holder owns the same Session or site scope, so wait, inspect -`webcmd session list`, and use `webcmd session close --force` only -when the holder is dead. `SESSION_PAUSED_FOR_HUMAN_HANDOFF` means finish the -handoff and run its verifier before retrying. +means add a root `--session ` selector before `browser`. `SESSION_BUSY` +means another CLI invocation already drives that Session: wait for the listed holder, +then retry the same command. Produce it by issuing a second `webcmd --session …` +while the first is still running — not by locking inside `page.evaluate`. Use +`webcmd session close --force` only when the holder is dead. +`SESSION_PAUSED_FOR_HUMAN_HANDOFF` means finish the handoff and run its verifier before retrying. ## Prerequisites By Strategy @@ -282,4 +283,7 @@ Author-only. Stripped by litprompt, so it costs the running agent nothing. Append one dated line whenever a correction lands, or whenever an approach is tried and rejected. Record what was tried and why it failed, not just what won. + +- 2026-08-20: `SESSION_BUSY` was named in troubleshooting but not as two overlapping + CLI invocations. In-page locks are not that error. --> diff --git a/skills/webcmd-browser/SKILL.md b/skills/webcmd-browser/SKILL.md index f972f5b7..8eb7ea0f 100644 --- a/skills/webcmd-browser/SKILL.md +++ b/skills/webcmd-browser/SKILL.md @@ -151,6 +151,20 @@ JS If you split work across calls, use fresh snapshots between page transitions. Do not assume an observation from a prior route is still valid. +To contend for one Session, issue a second `webcmd --session …` while the first invocation is still running. Do not start a second driver inside one `run` (`Promise.all` of two writes, a homemade busy flag, or `page.evaluate` locking). + +```bash +# Terminal A — long run holding the Session +webcmd --session session_abc browser run --file long.js + +# Terminal B — second command against the same Session +webcmd --session session_abc browser run --stdin --no-snapshot-diff <<'JS' +return { url: page.url() }; +JS +``` + +If the second command returns `SESSION_BUSY`, wait for the listed holder, then retry that same command. Do not `--force` close a live holder. + --- ## Sitemaps @@ -248,6 +262,7 @@ Use `run` and inspect `page.frames()`; target the frame by URL/name and keep ifr - **Do not submit forms via `page.evaluate(() => document.forms[0].submit())`.** Modern sites intercept real click/submit events and silently drop direct DOM submission. Use Playwright locators and verify the post-action state. - **Do not reuse observations across a page transition.** Navigations, form submits, SPA route changes, login, and human handoff invalidate earlier observations. Take a fresh snapshot. +- **Do not implement Session occupancy inside the page.** Overlap two CLI invocations on the same `--session` id. A homemade busy flag is not `SESSION_BUSY`. - **Do not run a trigger before arming the waiter.** If a request matters, create `page.waitForResponse(...)` before the click/fill/keypress that triggers it. - **Do not trust autocomplete or masked inputs blindly.** Fill/type can appear to work while the app rejects the value. Verify visible text, `inputValue()`, or post-action state. - **Do not solve CAPTCHA or auth challenges programmatically.** Use human handoff and verification. @@ -270,7 +285,7 @@ Use `run` and inspect `page.frames()`; target the frame by URL/name and keep ifr | `run` times out before returning | Increase `--timeout` only after checking whether the wait condition is wrong. | | Write may have happened before timeout | Take a fresh snapshot before retrying. Avoid duplicate submissions. | | `SESSION_REQUIRED` | Create a Session, then retry with root `--session `. | -| `SESSION_BUSY` | Wait for the listed holder; if it is dead, `webcmd session close --force` is the last resort. | +| `SESSION_BUSY` | Wait for the listed holder, then retry the same command. If it is dead, `webcmd session close --force` is the last resort. Do not lock inside `page.evaluate`. | | `SESSION_PAUSED_FOR_HUMAN_HANDOFF` | Finish the handoff and run the returned verifier before retrying. | | Login wall appears | Use the Authentication and human handoff recipe. | | User reports login complete | Run the returned verifier first. Without one, inspect fresh state and verify identity/post-action state. | diff --git a/skills/webcmd-usage/SKILL.md b/skills/webcmd-usage/SKILL.md index 56173691..e6c470eb 100644 --- a/skills/webcmd-usage/SKILL.md +++ b/skills/webcmd-usage/SKILL.md @@ -73,11 +73,12 @@ webcmd session close session_abc Adapter commands may omit `--session` and use the selected profile's adapter-default session. Pass `--session ` to route one into an explicit session. Raw browser commands never omit it; the retired positional session form is invalid. Structured Session failures are runtime state, not adapter breakage. `SESSION_REQUIRED` -means add a root `--session ` selector before `browser`; `SESSION_BUSY` -means another holder owns the same Session or site scope, so wait, inspect -`webcmd session list`, and use `webcmd session close --force` only -when the holder is dead. `SESSION_PAUSED_FOR_HUMAN_HANDOFF` means finish the -handoff and run its verifier before retrying. +means add a root `--session ` selector before `browser`. `SESSION_BUSY` +means another CLI invocation already drives that Session: wait for the listed holder, +then retry the same command. Produce it by issuing a second `webcmd --session …` +while the first is still running — not by locking inside `page.evaluate`. Use +`webcmd session close --force` only when the holder is dead. +`SESSION_PAUSED_FOR_HUMAN_HANDOFF` means finish the handoff and run its verifier before retrying. ## Prerequisites By Strategy diff --git a/src/skills.test.ts b/src/skills.test.ts index bfe8b5c8..803eb699 100644 --- a/src/skills.test.ts +++ b/src/skills.test.ts @@ -290,6 +290,8 @@ describe('webcmd skills content', () => { expect(browser).toContain('SESSION_BUSY'); expect(browser).toContain('SESSION_PAUSED_FOR_HUMAN_HANDOFF'); expect(browser).toContain('webcmd session close --force'); + expect(usage).toMatch(/second `webcmd --session /); + expect(browser).toContain('Do not implement Session occupancy inside the page'); for (const skill of [usage, browser, autofix]) { expect(skill).toMatch(/handoff is scoped to (?:its|the) Session/i); expect(skill).toMatch(/(?:verify_command|handoff\.verifyCommand)[\s\S]{0,200}verbatim[\s\S]{0,120}`--session`/i);