From 609f716b15eeab62d7e05a80306580072c2e1772 Mon Sep 17 00:00:00 2001 From: fourbroad Date: Fri, 6 Nov 2026 10:09:17 +0800 Subject: [PATCH] export v0.1.8: session-scope-guard human-only three-channel ruling (#6617) + browser-debug nested OOPIF skill update --- core/rules/session-scope-guard.md | 13 +++ core/skills/browser-debug/SKILL.md | 181 ++++++++++++++++------------- package.json | 4 +- 3 files changed, 113 insertions(+), 85 deletions(-) diff --git a/core/rules/session-scope-guard.md b/core/rules/session-scope-guard.md index df0d30e..c75d4d3 100644 --- a/core/rules/session-scope-guard.md +++ b/core/rules/session-scope-guard.md @@ -84,6 +84,19 @@ and the provision wrapper (adds the worktree + Tier-1 runs scaffold). The manual 3-step is the fallback where the scripts are unavailable, same re-verification. +**Human-only tickets ([org-internal #6617]-P1).** A ticket marked +human-only in ANY of three machine-readable forms — title `[人工执行]` +(ASCII/【】 fullwidth variants), label `executor/human-only`, or a body +line `executor: human` / `executor: human-only` (line-anchored, +blockquote-tolerant) — is NOT claimable by an agent: the claim script +refuses (exit 4, stage=precheck; takeover mode too — taking over a dead +claim is not taking over execution rights). The title channel keeps the +`--allow-human-only` override (explicit human instruction only, visible in +the invoking transcript); the label/body channels have NO override — an +explicit marker is a hard refusal for agents ([org-internal #6617] merged +ruling). Never claim, execute, self-accept or close such a ticket on agent +initiative. + **Merge-time equivalence check.** Before merging, scan the remote main branch's recent commits for `#` — surfacing an equivalent implementation already on main *before* the merge rejection. diff --git a/core/skills/browser-debug/SKILL.md b/core/skills/browser-debug/SKILL.md index 7734c25..36ac699 100644 --- a/core/skills/browser-debug/SKILL.md +++ b/core/skills/browser-debug/SKILL.md @@ -1,21 +1,33 @@ --- name: browser-debug description: > - Use ONLY when an agent needs to interact with a live browser to debug, verify, - or iterate on Web UI work in packages/app — navigate to the dev server, snapshot - the DOM/accessibility tree, capture console and network errors, screenshot - component states, and exercise user flows end-to-end. Triggers on UI bugs, - visual regressions, layout/positioning issues, keyboard-focus problems, - console-error reports, and any "open the page and check X" task. Loads the - Playwright MCP toolset (browser_navigate, browser_snapshot, - browser_take_screenshot, browser_console_messages, browser_evaluate, etc.). - Use ONLY for interactive browser work; for writing Playwright *test files* - use the existing e2e/ suites under packages/app, not this skill. + Use ONLY when an agent must interact with a live browser to debug, verify, + or iterate on Web UI work in packages/app. Triggers on UI bugs, visual + regressions, layout/positioning issues, keyboard-focus problems, + console-error reports, and any "open the page and check X" task. Uses the + built-in unified browser tool surface (browser_open, browser_snapshot, + browser_take_screenshot, browser_console_messages, browser_evaluate, + browser_close) — contract shared/browser-tool-surface-v1 ([org-internal #4972]); the + playwright MCP server is retired ([org-internal #4977]). Use ONLY for interactive browser + work; for writing Playwright *test files* use the existing e2e/ suites under + packages/app, not this skill. +tools: + - browser_open + - browser_close + - browser_snapshot + - browser_console_messages + - browser_take_screenshot + - browser_evaluate + - browser_click + - browser_type + - browser_act_batch + - browser_handle_dialog + - browser_highlight + - browser_generate_locator triggers: - browser debug - open the page - check the page - - screenshot the - inspect element - console error - visual bug @@ -26,8 +38,6 @@ triggers: - tab order - 浏览器调试 - 打开页面 - - 截图 - - 视觉 - 布局错乱 - 对齐 - 焦点 @@ -36,13 +46,15 @@ role: Producer --- > Core 中立版(Increment 6a 改写,原 deferHard verbatimDir)。机制、结构与 frontmatter 保持;实例术语(工具名、路径、工单号)按 `core/adapters/TERMINOLOGY.md` 绑定到具体实例。 - # Browser Debug Interactive browser automation for Web UI work in `packages/app`. This skill -teaches the *recipe* for driving the Playwright MCP toolset — when to reach -for it, which tool for which job, and how to capture evidence a reviewer can -trust. +teaches the *recipe* for driving the unified browser tool surface — when to +reach for it, which tool for which job, and how to capture evidence a reviewer +can trust. The former playwright MCP server is retired ([org-internal #4977], Epic [org-internal #4972] +N-05); the tools below are built-in and mount into the session tool face +when this skill activates (default-off the LLM face for weight economy, +[org-internal #5131]) — a user-configured tools_exclude vetoes the mounts. ## When this skill applies @@ -68,37 +80,41 @@ Do **not** reach for it when: ## Preconditions -1. **Playwright MCP is configured.** The project `octopus.jsonc` carries a - `mcp.playwright` block launching `@playwright/mcp`. If the MCP tools are - not visible, run `/kickoff` or follow the `codegraph-setup` skill's - recipe (the closest analog for debugging missing MCP servers). +1. **Unified browser tools are built-in and skill-mounted.** `browser_open`, + `browser_snapshot`, `browser_console_messages`, `browser_take_screenshot`, + `browser_evaluate`, and `browser_close` are registered for every session + (no MCP server needed) but default-off the LLM face — activating this skill + mounts them onto the session tool face ([org-internal #5131]); a user tools_exclude + vetoes the mounts + config needed (the playwright MCP is retired, [org-internal #4977]). If the tools are + not visible, the session runs a pre-[org-internal #4972] build — update. 2. **Dev server is running.** The app under test must be reachable. For - `packages/app`, run `bash script/dev-fresh.sh --full` for the dev server - (Windows workstations: `bash script/dev-fresh-windows.sh` — dev-fresh.sh's - stop path depends on setsid/ss, silently ineffective under Git Bash; see - local-workstation-quirks.md §5); - frontend is at `http://localhost:4444` and backend at `http://localhost:4096` - (see AGENTS.md Dev services section). -3. **Chromium is installed.** First run of `@playwright/mcp` downloads it - automatically; if the tool reports a missing browser, run + `packages/app`, run `bash script/dev-fresh.sh --full` for the dev server + (Windows workstations: `bash script/dev-fresh-windows.sh` — dev-fresh.sh's + stop path depends on setsid/ss, silently ineffective under Git Bash; see + local-workstation-quirks.md §5); + frontend is at `http://localhost:4444` and backend at `http://localhost:4096` + (see AGENTS.md Dev services section). +3. **Chromium is installed.** The headless backend drives an isolated + Chromium; if a tool reports a missing browser, run `bunx playwright install chromium` once in any shell. ## Tool selection recipe -The Playwright MCP exposes many tools. Pick by *what you need to observe*, -not by familiarity: +The unified surface exposes focused read/navigation tools. Pick by *what you +need to observe*, not by familiarity. Cost discipline applies: the snapshot +answers structure/state questions, the screenshot only visual ones — take +both in one cycle only when a visual verdict is itself the deliverable: | Need | Tool | Why | | --- | --- | --- | -| Open a URL | `browser_navigate` | Always the first call. | +| Open a URL | `browser_open` | Always the first call (opens the user-visible browser pane / isolated browser). Pass `surface: "headless"` when the intent is headless — the user's pane is never touched (no confirmation bar, no pane binding) and later browser_* tools operate on the isolated headless copy; if already bound to the pane, `browser_pane_release` first. | | See the page structure (roles, names) | `browser_snapshot` | Returns the accessibility tree — stable across CSS refactors. Prefer this over `browser_take_screenshot` when asserting "does element X exist / is it labelled Y?". | -| See the page *visually* | `browser_take_screenshot` | For layout, spacing, color, overflow. Attach the PNG to your report. | +| See the page *visually* | `browser_take_screenshot` | For layout, spacing, color, overflow. Attach the PNG to your report. **Vision-model guard (#screenshot-guard):** the PNG is pixels, not text — a session model without vision CANNOT read it. If YOU cannot see images, you must delegate reading via `Task(role: "Tool")` per the `image-interpret` skill (returns a structured text spec); never attempt to interpret the PNG yourself. Pixel questions → image-interpret; DOM/state questions → `browser_evaluate`. | | Read console errors / warnings | `browser_console_messages` | Filter by level (`error`, `warn`). The first stop for any "page is blank" bug. | -| Read failed network calls | `browser_network_requests` | Locate 4xx/5xx, CORS failures, hanging fetches. | -| Click, type, hover, select | `browser_click`, `browser_type`, `browser_hover`, `browser_select_option` | Drive the flow. Always `browser_snapshot` first to get the `ref` for the target element. | | Assert computed style / DOM state | `browser_evaluate` | Last resort. Snapshots cover 90%; reach for `evaluate` only when you need `getComputedStyle`, scroll positions, or arbitrary JS state. | -| Keyboard navigation | `browser_press_key` | For tab order, focus rings, escape-to-close. | -| Record a video / trace | `browser_start_tracing`, `browser_stop_tracing` | Heavy; use only when a bug is timing-sensitive and console+snapshot can't catch it. | +| Close the session | `browser_close` | Tear down when done; see the session cleanup section. | + ## Pane-first recipe (prefer over headless) @@ -109,8 +125,8 @@ or exceed Playwright for the hard cases: | Need | Pane tool / pattern | Notes | | --- | --- | --- | | Open / bind pane | `browser_open` (default surface) | Never touch the user's pane from a headless-only intent — pass `surface: "headless"` or `browser_pane_release` first. | -| Structure + refs | `browser_snapshot` | Open shadow is pierced; cross-origin iframes expose `f{seq}/e{n}` synthetic refs — prefer those over attr ids when acting into child frames. | -| Act (click/type/…) | `browser_act` / `browser_act_batch` | Locators (`role=` / `text=` / …) walk open shadow. Cross-origin click/type route through CDP trusted events. | +| Structure + refs | `browser_snapshot` | Open shadow is pierced; closed shadow is CDP-merged (`closedShadow:true`, no `e`). Cross-origin iframes expose `f{seq}/e{n}` synthetic refs — prefer those over attr ids when acting into child frames. Closed hosts inside stitched OOPIF subtrees carry `closedShadow:true` (CDP merge after stitch). | +| Act (click/type/…) | `browser_click` / `browser_type` / `browser_act_batch` | Locators (`role=` / `text=` / …) walk open shadow; after a JS miss, pane CDP pierces **closed** shadow for locate/wait/scroll (nested closed-in-open + same-origin iframe contentDocument + cross-origin OOPIF via Target.attachToTarget, including nested OOPIF-in-OOPIF host-offset chains; `DOM.focus` for type). `css=` stays light-DOM. Cross-origin click/type route through CDP trusted events. | | Native dialogs | `browser_handle_dialog` **before** the act | Prefer `mode: "arm"` (or `act_batch.dialog_prearm`) so the pane parks the answer before the click that opens confirm/prompt — avoids the 1.5s auto-dismiss / widget-cancel race. Bind with `messageIncludes` when the page can raise multiple dialogs. Call `mode: "disarm"` if the trigger was cancelled. | | Highlight / locator | `browser_highlight`, `browser_generate_locator` | Dual-leg: both pane and headless. Use highlight to confirm the ref before a write. | | Failure recovery | re-snapshot + path candidates | Act/locator failures may return `pathCandidates` (frame/shadow path hints). Heal scores framePath so sibling iframes do not auto-heal across frames. | @@ -124,28 +140,30 @@ on the pane. Follow these steps in order. Do not skip the snapshot step: the `ref` it returns is the stable handle every subsequent tool needs. -1. `browser_navigate` to the page where the bug lives. +1. `browser_open` the page where the bug lives. 2. `browser_console_messages` — record any errors *before* touching anything. Many "interaction bugs" are actually load-time errors. -3. `browser_snapshot` — locate the target element; capture its `ref` and - accessible name. -4. Drive the interaction with `browser_click` / `browser_type` / - `browser_press_key` until the bug reproduces. -5. Re-read `browser_console_messages` and `browser_network_requests` — - capture the *delta* introduced by the interaction. +3. `browser_snapshot` — locate the target element; capture its accessible + name. +4. If the reproduction needs interaction beyond reading, use + `browser_evaluate` sparingly to probe state — the unified surface is + read-focused; drive deep flows via the e2e suites when needed. +5. Re-read `browser_console_messages` — capture the *delta* introduced by + the interaction / page state. 6. `browser_take_screenshot` (or a second `browser_snapshot`) to freeze the broken state. -7. Report: URL, the minimal interaction sequence, console delta, network - delta, screenshot, and the suspected component path in - `packages/app/src/...`. +7. Report: URL, the observation sequence, console delta, screenshot, and the + suspected component path in `packages/app/src/...`. ## Standard recipe — verify a UI fix -1. `browser_navigate` to the affected page. +1. `browser_open` the affected page. 2. `browser_snapshot` — confirm the fixed element is present with the expected accessible name. -3. `browser_take_screenshot` — full page **and** element-cropped if the fix - is local. +3. `browser_take_screenshot` — only when the fix is visual (layout, styling, + rendering); full page **and** element-cropped if the fix is local. For + non-visual fixes (logic, state, wiring) the snapshot plus console delta is + the evidence — skip the screenshot. 4. If the fix touched layout, `browser_evaluate` a `getBoundingClientRect()` or `getComputedStyle()` on the key node and paste the value into your report. Numbers beat adjectives. @@ -169,7 +187,7 @@ When a `verify` work item has an E2E or UI DoD entry: reference (UI-touching PRs, `verify` skill Phase 2.7 / contract `browser-evidence-4486/shared/evidence-ref-v1`), promote the captures into an evidence pack first — feed COPIES through - `writeEvidencePack` (`/src/browser/evidence-pack.ts`, + `writeEvidencePack` (`packages/octopus/src/browser/evidence-pack.ts`, the single mandatory sanitize boundary; the `.playwright-mcp/` layer keeps its current semantics, additive not replaced) and cite the pack directory. Evidence ladder: raw capture → `.playwright-mcp/` working @@ -182,9 +200,9 @@ When a `verify` work item has an E2E or UI DoD entry: | --- | --- | | "The unit test already covers it." | Unit tests assert component logic, not what Chromium actually renders. Visual and focus bugs live in the gap. | | "I can tell from the JSX that it's aligned." | Computed layout depends on parent containers, fonts, and viewport. Screenshot the real page. | -| "Browser automation is overkill for a small change." | A `browser_navigate` + `browser_take_screenshot` pair is ~2 seconds. The cost is in *not* looking. | +| "Browser automation is overkill for a small change." | A `browser_open` + `browser_snapshot` read is ~2 seconds — cheap. The cost is in *not* looking; add the screenshot only where the question is visual. | | "I'll just run the whole e2e suite." | The suite answers "did anything break?" — it does not answer "does this specific change look right?". | -| "Snapshot is enough, skip the screenshot." | Accessibility trees hide overflow, clipping, and z-index bugs. Take both for visual changes. | +| "Snapshot is enough, skip the screenshot." | Depends on the claim. For a visual change it is backwards — accessibility trees hide overflow, clipping, and z-index bugs, so take the screenshot too. For a non-visual claim (presence, label, state) the snapshot alone IS the observation; don't pad it with pixels. | ## Boundaries @@ -203,18 +221,12 @@ When a `verify` work item has an E2E or UI DoD entry: ## Session cleanup (mandatory) -A Playwright MCP browser is a real Chrome with a `/tmp` user-data-dir — its -mode follows `mcp.playwright.headless` (`headless-field-v1`, [org-internal #4393]): the repo -default `auto` spawns headed on desktop (win32/darwin; linux only with -DISPLAY/WAYLAND_DISPLAY set) and headless otherwise; an explicit `true`/`false` -or `OCTOPUS_MCP_HEADLESS=1|0` pins it. The mode is fixed per new session — -switching the config does not hot-switch a running browser. It -stays alive as long as its MCP server runs, and the MCP server stays alive as -long as its parent octopus backend runs. When a browser-debug session ends -without an explicit `browser_close`, OR the octopus session times out mid-task, -the Chrome + its MCP server are orphaned and accumulate across sessions — -burning CPU and leaving dead profile dirs (issue [org-internal #1315]); in headed mode the -orphan is a visible stray window. +The unified surface's isolated backend is a real Chrome with a `/tmp` +user-data-dir. It stays alive as long as its parent octopus backend runs. +When a browser-debug session ends without an explicit `browser_close`, OR the +octopus session times out mid-task, the Chrome is orphaned and accumulates +across sessions — burning CPU and leaving dead profile dirs (issue [org-internal #1315]); in +headed mode the orphan is a visible stray window. **Iron rule: every browser-debug session MUST close its browser before ending.** @@ -236,19 +248,16 @@ orphan is a visible stray window. **Why this matters:** a single forgotten `browser_close` leaves a Chrome subtree (8+ processes) running indefinitely. Over days this is hundreds of -orphaned processes and wasted CPU. The MCP server does not auto-close its -browser on disconnect — only an explicit `browser_close` (or process reaping) -releases it. +orphaned processes and wasted CPU. Only an explicit `browser_close` (or +process reaping) releases it. ## Screenshot output paths -The Playwright MCP server is launched WITHOUT `--output-dir` (see -`octopus.jsonc` → `mcp.playwright.command`): its default output location is -`.playwright-mcp/` in the process cwd (the worktree root), gitignored and -auto-evicted at 100 MB via `--output-max-size`. Auto-named output (no -`filename`) lands there — but an explicit `filename` can resolve against the -cwd and drop the PNG into the repo root, where the `/*.png` gitignore -backstop hides it from `git status` and nothing ever cleans it up. +Screenshots from `browser_take_screenshot` land in `.playwright-mcp/` in the +process cwd (the worktree root), gitignored. An explicit `filename` can +resolve against the cwd and drop the PNG into the repo root, where the +`/*.png` gitignore backstop hides it from `git status` and nothing ever +cleans it up. **Iron rule: 截图文件名必须写进 `.playwright-mcp/`。** Every `filename` passed to `browser_take_screenshot` (or any tool that writes a file) MUST @@ -281,10 +290,10 @@ Two valid destinations for screenshots, by purpose: octopus UI. The endpoint exists but has returned 500 on this instance; verify before relying on it. 3. **Publish to the wiki evidence namespace `{slug}/verify/evidence/{name}` - via `wiki 读写 API(见 TERMINOLOGY)`** — last resort only, when no other channel + via git direct-push to `octopus.wiki.git` (`_shared/gitea-write-patterns.md` top-of-file, [org-internal #6180])** — last resort only, when no other channel works AND the evidence must outlive the worktree (this is the same durable channel `verify` mandates for DoD evidence entries — see - `core/skills/verify/SKILL.md` References). Keep it small: + `.octopus/skills/verify/SKILL.md` References). Keep it small: ≤5 images per PR, each ≤200KB (compress/downscale, prefer element crops over full-page). @@ -302,13 +311,19 @@ prefix is the real fix; rely on that, not on the backstop. ## References -- `core/skills/frontend/SKILL.md` — where UI changes are planned; invoke +- `.octopus/skills/image-interpret/SKILL.md` — REQUIRED when the session model + has no vision: `browser_take_screenshot` writes a PNG the driving model + cannot read. Delegate reading via `Task(role: "Tool")` (structured text spec + back); never self-interpret pixel content. Pixel questions (layout, color, + spacing) → image-interpret; DOM/state questions (form values, validation) → + `browser_evaluate`. +- `.octopus/skills/frontend/SKILL.md` — where UI changes are planned; invoke this skill during Phase 3 / Phase 4 to verify each state visually. -- `core/skills/implement/SKILL.md` — Frontend Mode; pair with +- `.octopus/skills/implement/SKILL.md` — Frontend Mode; pair with `browser-debug` when the work item touches rendering. -- `core/skills/implement/SKILL.md` (Mode: bugfix) — Phase 1 reproduction; use this skill +- `.octopus/skills/implement/SKILL.md` (Mode: bugfix) — Phase 1 reproduction; use this skill to capture the failing state before isolating root cause. -- `core/skills/verify/SKILL.md` — Phase 2 / DoD matrix; use this skill +- `.octopus/skills/verify/SKILL.md` — Phase 2 / DoD matrix; use this skill to generate screenshot evidence for UI-tagged DoD entries. - `packages/app/e2e/` — permanent Playwright test suites; this skill is the ad-hoc complement, not a replacement. diff --git a/package.json b/package.json index 384990f..4de8ad1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "octopus-workflow", - "version": "0.1.7", + "version": "0.1.8", "description": "Standalone workflow core: provider-neutral agent workflow corpus (skills / rules / checklists / templates / schemas) with drift guards, extracted from the octopus agent platform.", "license": "MIT", "private": false, @@ -16,4 +16,4 @@ "type": "git", "url": "https://eightarms.net/Octopus/octopus-workflow" } -} +} \ No newline at end of file