Conversation page, header and management menu
F07 · 25 mapped behaviors in the Self-Healing Codebase Project. Follow the prerequisites, actions and expected results; expand the original CLI recipe to replay it.
778 behavior IDs · 28 families · 844 named recipes & support steps
16 October 2026 · PR #18334 at 9a3c3a69
Canvas 1.27.1 · Agent Server 1.55.0 · automation 1.20.0
This is the map at the revision above, including its open bug notes. It does not incorporate later changes on main or claim a fresh verification run. Setup & reading guide · Download the scenario inventory
All scenarios & marker key · Open a script to read Given / Do / Expect. Expand the exact recipe for replayable commands.
No scenarios match. Try a different word or reset.
F07 Conversation page, header and management menu
25 behaviors · 29 scripts & contracts · Maintained source
Entry points & prerequisites
What this family covers
The conversation page (/conversations/<id>) shows the chat pane: a header with the runtime status dot, the editable title, the "..." management menu and the Git actions, Overview and panel toggles, then the message history and the composer. From the header a user renames, stops or resumes the runtime, opens the skills, hooks and agent-tools dialogs, exports or downloads the conversation, jumps to usage and deletes it.
How a user gets here
- Sidebar conversation row (
conversation-card), or the home composer submit, which navigates to the new conversation. - Direct URL
/conversations/<id>. - Direct URL
/conversations/<id>/panel, or the header panel button, at phone width (up to 1024 px); at desktop width that URL redirects to/conversations/<id>with the drawer open. - Hovering a message in the history: Branch from here (local backends only).
- Chips under the composer (git control bar) for conversations in a git workspace (home Open Workspace).
- Header controls inside
testid=chat-pane-header: the status dot (server-status-menu-trigger), the title (conversation-name-title), the "..." button (ellipsis-button, aria "More options"),conversation-git-actions-toggle,conversation-overview-toggle,right-panel-toggle.
Given
Preconditions:
- Baseline state (launched, doctored,
onboard --skipdone) and an active LLM profile (control-openhands llm preset deepseek). - A finished conversation:
control-openhands conversation start --prompt "Reply with the single word: pong" --wait --timeout 240prints its<id>. - A running conversation for the active-only items:
control-openhands conversation start --prompt "Run the shell command: sleep 90 ; then reply with the word done" --wait --until running --timeout 120prints<running-id>. It finishes after about 90 s, so start it right beforeF07.stop-confirm(after a Stop it stayspauseduntil Start Runtime). - A conversation in a git workspace for the git control bar:
control-openhands fixture git-repo --name qa-f07-repo, thencontrol-openhands browser goto /(conversation startleft the browser on<id>),control-openhands browser click 'testid=open-workspace-button',control-openhands browser click 'role=dialog >> role=combobox[name="Select a workspace"]',control-openhands browser click 'role=dialog >> role=button[name="+ Add Workspace"]',control-openhands browser click 'testid=folder-browser-sidebar-workspace',control-openhands browser click 'testid=folder-browser-up'three times (to the run directory),control-openhands browser click 'testid=folder-browser-entry-workspace',control-openhands browser click 'testid=folder-browser-entry-qa-f07-repo',control-openhands browser click 'testid=folder-browser-use',control-openhands browser click 'testid=workspace-launch-button', thencontrol-openhands conversation start --prompt "Reply with the single word: ok" --stay --wait --timeout 240prints<git-id>. - An automation setup conversation for the setup-leaving bullet, made right after the finished conversation:
control-openhands browser goto /automations,control-openhands browser click 'testid=automations-add-automation',control-openhands browser click 'testid=automations-add-automation-create' --expect-url '/automations/setup',control-openhands conversation start --stay --prompt 'Reply with only the word ok. Do not run any tools.' --wait --timeout 180(prints<setup-id>), thencontrol-openhands browser goto /. - Cloud-only rows (
F07.cloud-only) are blocked without an OpenHands Cloud account. - Desktop viewport unless a bullet says otherwise.
Open by URLF07.open-by-urlKnown issueBlocked
Scenario F07--open-by-url · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /conversations/<id>.
- WaitWait for “Chat pane header” to appear.
Expect
/conversations/<id> shows header, history and composer, and remembers the id as the backend's last conversation.
Linked known issues
Known issue #16727 (F07.open-by-url): Conversation corrupted after VM restart: "Missing event file". Live prerequisite: A disposable VM interrupted at the event-write boundary or the original missing-event persisted fixture.
Known issue #16356 (F07.open-by-url): Conversation LLM config is frozen at creation time — resuming after API key rotation fails permanently with LLMAuthenticationError. Live prerequisite: A working provider key that can be rotated/revoked, an existing conversation using it, and a replacement profile.
Known issue OpenHands/software-agent-sdk#5094 (F07.open-by-url): After ACP session/load fails, the backend can create a fresh model session while Canvas still shows the old context. Live prerequisite: An authenticated Codex ACP session whose original session/load fails while persisted history remains.
Known issue #16877 (F07.open-by-url): Untitled terminal-status conversations are reported to keep the 3-second title polling interval. On frozen target fa1f724ab5737a17453ad6081129eb91c5a423c6, a real Local autotitle:false/idle conversation retained title:null, while eight browser batch GETs had 30.008–30.031-second intervals over 210 seconds. The direct adapter supplies a default display title. This does not exercise the Cloud null-title IDLE/FINISHED branch, which needs an approved Cloud conversation with a failed/unsupported title job. Run backfill-18309-coordinator-checks, Agent Server/SDK 1.54.0, automation 1.19.3; retained evidence/F07.open-by-url/16877-local-polling.json and 16877-local-idle.png. Arrange the empty conversation with api POST /api/conversations --write --data @<idle-autotitle-disabled-payload>, open /conversations/<id>, clear browser network, leave the tab foreground, then read browser network --filter ids= --last 100 and conversation status <id>. No model call or response was used.
Exact CLI recipe & bug checks
Run control-openhands browser goto /conversations/<id>, control-openhands browser wait 'testid=chat-pane-header', control-openhands browser text 'testid=conversation-name-title' and control-openhands browser count 'testid=chat-interface >> testid=agent-message'. The title is the generated one and the count is 1. control-openhands browser eval "localStorage.getItem('openhands-last-conversation-by-backend')" reads {"default-local":"<id>"}.
Leaving an automation setup conversationF07.open-by-urlKnown issueBlocked
Scenario F07--leaving-an-automation-setup-conversation · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /.
- DoChoose “Conversation panel new thread picker”.
- DoChoose “Launch no workspace”.
- DoChoose the element identified in the CLI recipe.
- WaitWait for “Chat pane header” to appear.
- DoReload the page.
- DoUse browser storage as specified in the exact recipe.
Expect
/conversations/<id> shows header, history and composer, and remembers the id as the backend's last conversation.
Linked known issues
Known issue #16727 (F07.open-by-url): Conversation corrupted after VM restart: "Missing event file". Live prerequisite: A disposable VM interrupted at the event-write boundary or the original missing-event persisted fixture.
Known issue #16356 (F07.open-by-url): Conversation LLM config is frozen at creation time — resuming after API key rotation fails permanently with LLMAuthenticationError. Live prerequisite: A working provider key that can be rotated/revoked, an existing conversation using it, and a replacement profile.
Known issue OpenHands/software-agent-sdk#5094 (F07.open-by-url): After ACP session/load fails, the backend can create a fresh model session while Canvas still shows the old context. Live prerequisite: An authenticated Codex ACP session whose original session/load fails while persisted history remains.
Known issue #16877 (F07.open-by-url): Untitled terminal-status conversations are reported to keep the 3-second title polling interval. On frozen target fa1f724ab5737a17453ad6081129eb91c5a423c6, a real Local autotitle:false/idle conversation retained title:null, while eight browser batch GETs had 30.008–30.031-second intervals over 210 seconds. The direct adapter supplies a default display title. This does not exercise the Cloud null-title IDLE/FINISHED branch, which needs an approved Cloud conversation with a failed/unsupported title job. Run backfill-18309-coordinator-checks, Agent Server/SDK 1.54.0, automation 1.19.3; retained evidence/F07.open-by-url/16877-local-polling.json and 16877-local-idle.png. Arrange the empty conversation with api POST /api/conversations --write --data @<idle-autotitle-disabled-payload>, open /conversations/<id>, clear browser network, leave the tab foreground, then read browser network --filter ids= --last 100 and conversation status <id>. No model call or response was used.
Exact CLI recipe & bug checks
A conversation tagged automationsetup: draft (started from /automations/setup, see F04.automation-setup-tag) opens as a setup page (testid=automation-setup-topbar, no chat-pane-header). Make an empty conversation: control-openhands browser goto /, control-openhands browser click 'testid=conversation-panel-new-thread-picker', control-openhands browser click 'testid=launch-no-workspace' --expect-url '/conversations/' (note <plain-id>; control-openhands api GET /api/conversations/<plain-id> --pick tags is only clientsource). Open the setup conversation from the sidebar (control-openhands browser click 'a[href*="/conversations/<setup-id>"] >> nth=0' --expect-url '/conversations/<setup-id>'), then go back the same way ('a[href*="/conversations/<plain-id>"] >> nth=0'). Expected: <plain-id> opens as a normal conversation: control-openhands browser wait 'testid=chat-pane-header', browser count 'testid=chat-pane-header' is 1, browser count 'testid=automation-setup-topbar' is 0, and api GET /api/conversations/<plain-id> --pick tags is still only clientsource, also after browser reload and after repeating the round trip; the sidebar row of <plain-id> has no Automation setup: Draft chip (browser screenshot --feature F07.open-by-url --name plain-stays-plain). The setup conversation is in this tab's openhands-automation-setup-handoffs sessionStorage entry during the check (control-openhands browser storage --session --values). The same holds at phone width through the sidebar drawer (sidebar-mobile-menu-toggle, then the rows inside testid=sidebar-mobile-drawer).
Unknown idF07.missing-redirectMapped behavior
Scenario F07--unknown-id · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /conversations/00000000-0000-0000-0000-000000000000.
- WaitWait for the element identified in the CLI recipe to appear.
Expect
an unknown id toasts "This conversation does not exist…" and redirects to /conversations.
Exact CLI recipe & bug checks
Run control-openhands browser goto /conversations/00000000-0000-0000-0000-000000000000, control-openhands browser wait-url '/conversations$' and control-openhands browser toasts. A toast reads This conversation does not exist, or you do not have permission to access it. If this is your conversation, try switching to the workspace where it was created. and the last-conversation slot is {}. It is the only toast: control-openhands browser toasts --history has no entry with does not understand.
Rename inlineF07.rename-inlineKnown failure
Scenario F07--rename-inline · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /conversations/<id>.
- DoDouble-click “Conversation name title”.
- DoEnter “QA_F07 renamed” in “Conversation name”.
- DoPress Enter.
- DoReload the page.
Expect
double-click the title (or menu Rename), Enter or blur saves with a toast; an empty value reverts.
Linked known issues
Known failure OpenHands/software-agent-sdk#5629 (F07.rename-inline), reproduced 2026-10-12 at fa1f724ab573, SDK 1.54.0. A second server's native first load rewrote a newer saved title with its startup copy; the connected Canvas header showed that older title. Recipe: create an idle conversation on A and PATCH its title to QA_SHARED_BEFORE_B_5629_REPEAT; run pinned SDK Python python .agents/skills/verify-openhands/scripts/fixtures/shared-storage-server.py --run <run> --seconds 300 in the background. It starts only a bounded no-editor SDK B sharing this run's conversation directory/cipher/session key; its private server.json supplies the port and owned operator/PGID. After B listens, PATCH A to QA_SHARED_AFTER_B_5629_REPEAT and confirm disk. Run control-openhands service stop agent-server --run <run>, then python .../fixtures/shared-storage-server.py --run <run> --load-id <id>: native B /events/count returned 200 and disk reverted to BEFORE_B. Restart A only to serve Canvas, choose default-local and doctor; use the Add Backend recipe from F25 to connect B at its recorded port with the private key file, then open its card: the header reads BEFORE_B. SIGTERM only the recorded helper operator and verify its port/PGID gone; the helper also bounds runtime and terminates remaining group descendants. Evidence: backfill-18309-surface-rechecks/F07.rename-inline/metadata-repeat-before-b-load-5629.json, metadata-repeat-after-b-load-5629.json, shared-first-load-reverted-5629.png. The native first-load request is explicit; stale catalog display alone is insufficient proof of this overwrite.
Known failure OpenHands/software-agent-sdk#4800 (F07.rename-inline), reproduced 2026-10-12 at fa1f724ab573, SDK 1.54.0. A refused rename changed the server's GET title while meta.json kept the previous title; graceful shutdown subsequently persisted the rejected title. Recipe: create an idle dummy-profile conversation, then double-click conversation-name-title, fill conversation-name-input with QA_META_BEFORE_4800 and press Enter; verify GET/disk. Record the original mode and temporarily chmod 0500 <run>/private/state/dev_conversations/<id-hex> to deny an atomic metadata replacement. Rename through that UI to QA_META_REFUSED_4800: the permission-denied toast/HTTP 500 appears, GET shows REFUSED, disk still shows BEFORE. Restore the exact original directory mode in finally, then restart, doctor, GET and reload (CLI with --run <run>): REFUSED was persisted during graceful shutdown. Only the owned temporary directory is changed; evidence contains title/timestamp fields, not stored secrets. Evidence: backfill-18309-surface-rechecks/F07.rename-inline/metadata-before-4800.json, metadata-denied-4800.json, refused-title-4800.png, metadata-after-graceful-restart-4800.json. Tags/autotitle and ownership-conflict branches remain untested.
Exact CLI recipe & bug checks
On /conversations/<id> (control-openhands browser goto /conversations/<id>; the unknown id redirected to /conversations) run control-openhands browser dblclick 'testid=conversation-name-title', control-openhands browser fill 'testid=conversation-name-input' 'QA_F07 renamed', control-openhands browser press Enter, control-openhands browser toasts (Conversation title updated successfully), then control-openhands browser reload and control-openhands browser text 'testid=conversation-name-title'. It reads QA_F07 renamed, and so does control-openhands browser text 'testid=conversation-card >> testid=conversation-card-title'.
History skeleton and sidebar entryF07.history-skeleton · F07.open-by-urlKnown issueBlocked
Scenario F07--history-skeleton-and-sidebar-entry · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /.
- DoChoose “Conversation card” / containing “QA_F07 renamed”.
Expect
opening a conversation shows a message skeleton until its history has loaded.
/conversations/<id> shows header, history and composer, and remembers the id as the backend's last conversation.
Linked known issues
Known issue #16876 (F07.history-skeleton): Planning-agent history flag stays true forever when sub-conversations fetch fails — infinite chat loading skeleton. Live prerequisite: A real planning sub-conversation whose batch lookup fails or yields null, with the main history available.
Known issue #16727 (F07.open-by-url): Conversation corrupted after VM restart: "Missing event file". Live prerequisite: A disposable VM interrupted at the event-write boundary or the original missing-event persisted fixture.
Known issue #16356 (F07.open-by-url): Conversation LLM config is frozen at creation time — resuming after API key rotation fails permanently with LLMAuthenticationError. Live prerequisite: A working provider key that can be rotated/revoked, an existing conversation using it, and a replacement profile.
Known issue OpenHands/software-agent-sdk#5094 (F07.open-by-url): After ACP session/load fails, the backend can create a fresh model session while Canvas still shows the old context. Live prerequisite: An authenticated Codex ACP session whose original session/load fails while persisted history remains.
Known issue #16877 (F07.open-by-url): Untitled terminal-status conversations are reported to keep the 3-second title polling interval. On frozen target fa1f724ab5737a17453ad6081129eb91c5a423c6, a real Local autotitle:false/idle conversation retained title:null, while eight browser batch GETs had 30.008–30.031-second intervals over 210 seconds. The direct adapter supplies a default display title. This does not exercise the Cloud null-title IDLE/FINISHED branch, which needs an approved Cloud conversation with a failed/unsupported title job. Run backfill-18309-coordinator-checks, Agent Server/SDK 1.54.0, automation 1.19.3; retained evidence/F07.open-by-url/16877-local-polling.json and 16877-local-idle.png. Arrange the empty conversation with api POST /api/conversations --write --data @<idle-autotitle-disabled-payload>, open /conversations/<id>, clear browser network, leave the tab foreground, then read browser network --filter ids= --last 100 and conversation status <id>. No model call or response was used.
Exact CLI recipe & bug checks
From / (control-openhands browser goto /) run control-openhands browser click 'testid=conversation-card >> has-text=QA_F07 renamed' --expect-url '/conversations/[0-9a-f-]+' --observe 'testid=chat-messages-skeleton' --observe-ms 3000 (run it after the rename above; before it, match the generated title instead). The observed list shows the skeleton present for a few hundred ms, then <absent>; the URL is /conversations/<id>?backend=default-local.
Stop with confirmationF07.stop-confirmMapped behavior
Scenario F07--stop-with-confirmation · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Chat pane header” / “More options”.
- DoChoose “Conversation name context menu” / “Stop”.
- DoChoose the dialog / “Cancel”.
- DoChoose the dialog / “Confirm”.
Expect
Stop Conversation asks for confirmation; Confirm Close pauses the conversation and returns to /conversations.
Exact CLI recipe & bug checks
On /conversations/<running-id> run control-openhands browser click 'testid=chat-pane-header >> testid=ellipsis-button', control-openhands browser click 'testid=conversation-name-context-menu >> testid=stop-button' and control-openhands browser snapshot 'role=dialog' (Confirm Stop Conversation, buttons Cancel and Confirm Close, test ids cancel-button and confirm-button). control-openhands browser click 'role=dialog >> testid=cancel-button' closes it and control-openhands conversation status <running-id> stays running. Repeat the two clicks, then control-openhands browser click 'role=dialog >> testid=confirm-button' --expect-url '/conversations$'; the toasts read Conversation stopped and conversation status <running-id> is paused.
Branch from a messageF07.branch-from-messageKnown failure
Scenario F07--branch-from-a-message · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /conversations/<id>.
- DoHover over “Agent message”.
- DoChoose “Agent message” / “Branch from here”.
- DoOpen /conversations/<id>.
- DoHover over “User message”.
- DoChoose “User message” / “Branch from here”.
Expect
Branch from here on a message forks the conversation as <title> (branch); on a user message the message is left out and its text goes back into the composer.
Linked known issues
After the user-message branch in F07.branch-from-message, Send stays disabled next to the prefilled text (browser enabled 'testid=submit-button' is false; Known failure #18202, see F05 Gotchas). Enter in the field sends it.
Exact CLI recipe & bug checks
On /conversations/<id> (control-openhands browser goto /conversations/<id>; Stop with confirmation ended on /conversations) run control-openhands browser hover 'testid=agent-message', then control-openhands browser click 'testid=agent-message >> role=button[name="Branch from here"]' --expect-url '/conversations/(?!<id>)[0-9a-f-]+', control-openhands browser text 'testid=conversation-name-title' (QA_F07 renamed (branch)) and control-openhands browser count 'testid=chat-interface >> testid=user-message' (1, the history is copied up to that reply). Back on /conversations/<id> (control-openhands browser goto /conversations/<id>), control-openhands browser hover 'testid=user-message' and control-openhands browser click 'testid=user-message >> role=button[name="Branch from here"]' --expect-url '/conversations/(?!<id>)[0-9a-f-]+' (it prints /conversations/<branch-id>): the new branch has 0 user messages and control-openhands browser text 'testid=chat-input' reads the original prompt Reply with the single word: pong, still there a few seconds later and not sent (control-openhands conversation events <branch-id> --kinds MessageEvent has count 0).
Delete with confirmationF07.delete-confirmMapped behavior
Scenario F07--delete-with-confirmation · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Chat pane header” / “More options”.
- DoChoose “Conversation name context menu” / “Delete”.
- DoChoose the dialog / “Cancel”.
- DoChoose the dialog / “Confirm”.
- DoOpen /conversations/<id>.
Expect
Delete Conversation names the title in a confirmation; Cancel keeps it, Confirm Delete removes it and returns to /conversations.
Exact CLI recipe & bug checks
On a disposable conversation (for example the branch from F07.branch-from-message) run control-openhands browser click 'testid=chat-pane-header >> testid=ellipsis-button', control-openhands browser click 'testid=conversation-name-context-menu >> testid=delete-button' and control-openhands browser snapshot 'role=dialog': Confirm Delete Are you sure you want to delete the "<title>" conversation? This action cannot be undone. with Cancel (cancel-button) and Confirm Delete (confirm-button). control-openhands browser click 'role=dialog >> testid=cancel-button' keeps the URL. Repeat the two clicks, then control-openhands browser click 'role=dialog >> testid=confirm-button' --expect-url '/conversations$'; control-openhands api GET '/api/conversations?ids=<id>' returns [null] and browser goto /conversations/<id> redirects as in F07.missing-redirect.
Paused conversationF07.menu-items-by-state · F07.status-menuKnown issueBlocked
Scenario F07--paused-conversation · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /conversations/<running-id>.
- DoUse browser mouse click as specified in the exact recipe.
- DoChoose “Server status menu trigger”.
- DoChoose “Server status context menu” / “Start server”.
- WaitWait for the conversation to finish.
Expect
Show Available Hooks and Stop Conversation appear only while the conversation is active.
hovering the status dot (or tapping it on touch) opens a menu with the state and Stop Runtime (active) or Start Runtime (paused).
Linked known issues
Known issue OpenHands/software-agent-sdk#4893 (F07.status-menu): A sandbox frozen mid-run can resume with a stale Running state that rejects normal resume requests. Live prerequisite: A disposable sandbox/VM frozen mid-run with a live model and persisted ownership state.
Exact CLI recipe & bug checks
Run control-openhands browser goto /conversations/<running-id>, open the "..." menu and control-openhands browser testids 'testid=conversation-name-context-menu': show-hooks-button and stop-button are absent. Close it with control-openhands browser mouse-click 900 500. Run control-openhands browser click 'testid=server-status-menu-trigger' and control-openhands browser text 'testid=server-status-context-menu' (Server Stopped / Start Runtime), then control-openhands browser click 'testid=server-status-context-menu >> testid=start-server-button' and control-openhands conversation wait <running-id> --until running,finished,idle --timeout 60. The status is running again and the menu reads Running / Stop Runtime.
HooksF07.hooks-modalMapped behavior
Scenario F07--hooks · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Conversation name context menu” / “Show hooks”.
- DoChoose “Hooks modal” / “Refresh hooks”.
- DoChoose “Close hooks modal”.
Expect
Show Available Hooks lists the workspace's .openhands/hooks.json hooks by event (read when it first opens for a conversation after a page load, and on Refresh; a reopen within 5 minutes of the last read shows the cached list), or "No hooks configured for this conversation."
Exact CLI recipe & bug checks
On /conversations/<running-id> (no workspace attached; Paused conversation left the browser there) open the "..." menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=show-hooks-button' and control-openhands browser text 'testid=hooks-modal'. It reads Available Hooks, the workspace explanation and No hooks configured for this conversation. (the backend workspace root has no hooks.json). Run control-openhands browser network --clear and control-openhands browser click 'testid=hooks-modal >> testid=refresh-hooks': the text stays and control-openhands browser network shows POST /api/hooks. control-openhands browser click 'testid=close-hooks-modal' closes it.
SkillsF07.skills-modalMapped behavior
Scenario F07--skills · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Conversation name context menu” / “Show skills”.
- DoChoose “Skills modal” / “github Knowledge”.
- DoPress Escape.
Expect
Show Available Skills lists the loaded skills with expandable rows and Refresh.
Exact CLI recipe & bug checks
Open the menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=show-skills-button', control-openhands browser snapshot 'role=dialog' (Public skills 12 and one button per skill), control-openhands browser click 'testid=skills-modal >> role=button[name="github Knowledge"]'; the row expands to Triggers and Content. control-openhands browser press Escape closes it (browser count 'testid=skills-modal' is 0).
Project skills and configured hooksF07.skills-modal-project · F07.hooks-modalMapped behavior
Scenario F07--project-skills-and-configured-hooks · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoStart a conversation with the prompt “Reply with the single word: hi”.
- DoChoose “Conversation name context menu” / “Show skills”.
- DoChoose “Skills modal” / “qa-f07-skill AgentSkills”.
- DoChoose “Skills modal” / “Refresh skills”.
- DoPress Escape.
- DoChoose “Conversation name context menu” / “Show hooks”.
- DoChoose “Hooks modal” / “Pre Tool Use 1 hook”.
- DoChoose “Close hooks modal”.
- DoChoose “Conversation name context menu” / “Show hooks”.
- DoChoose “Hooks modal” / “Refresh hooks”.
- DoChoose “Hooks modal” / “Stop 1 hook”.
- DoChoose “Close hooks modal”.
Expect
a workspace with .agents/skills/<name>/SKILL.md adds a "Project skills" section above the public ones; each row expands to its triggers and body. The list is read with the page and on Refresh; opening the dialog within 10 minutes of the last read shows the cached list.
Show Available Hooks lists the workspace's .openhands/hooks.json hooks by event (read when it first opens for a conversation after a page load, and on Refresh; a reopen within 5 minutes of the last read shows the cached list), or "No hooks configured for this conversation."
Exact CLI recipe & bug checks
Arrange (outside the UI) a project skill and a hook in the git fixture: mkdir -p <run>/workspace/qa-f07-repo/.agents/skills/qa-f07-skill <run>/workspace/qa-f07-repo/.openhands, write <run>/workspace/qa-f07-repo/.agents/skills/qa-f07-skill/SKILL.md with front matter name: qa-f07-skill, description: QA fixture skill for F07., triggers: [qaf07trigger] and the body QA_F07 skill body., and write <run>/workspace/qa-f07-repo/.openhands/hooks.json as {"pre_tool_use":[{"matcher":"terminal","hooks":[{"type":"command","command":"true","timeout":10}]}]}. Then control-openhands conversation start --workspace qa-f07-repo --prompt "Reply with the single word: hi" --wait --timeout 240 prints <hooks-id>; control-openhands api GET /api/conversations/<hooks-id> shows that hook_config.pre_tool_use holds the terminal matcher. On /conversations/<hooks-id> open the menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=show-skills-button' and control-openhands browser snapshot 'role=dialog': Project skills 1 with button "qa-f07-skill AgentSkills" above Public skills 12. control-openhands browser click 'testid=skills-modal >> role=button[name="qa-f07-skill AgentSkills"]' expands it to Triggers qaf07trigger Content QA_F07 skill body.; control-openhands browser click 'testid=skills-modal >> testid=refresh-skills' re-reads the workspace (browser network shows POST /api/skills). Close with control-openhands browser press Escape. Hooks: open the menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=show-hooks-button' and control-openhands browser snapshot 'testid=hooks-modal': one collapsed event, button "Pre Tool Use 1 hook". control-openhands browser click 'testid=hooks-modal >> role=button[name="Pre Tool Use 1 hook"]' expands it to Matcher terminal Commands true Type: command Timeout: 10s (control-openhands browser screenshot --feature F07.hooks-modal --name workspace-hooks). Close it with control-openhands browser click 'testid=close-hooks-modal' and write <run>/workspace/qa-f07-repo/.openhands/hooks.json as {"pre_tool_use":[{"matcher":"terminal","hooks":[{"type":"command","command":"true","timeout":10}]}],"stop":[{"hooks":[{"type":"command","command":"echo qa-f07-stop"}]}]}. A reopen keeps the list it read: run control-openhands browser network --clear, open the menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=show-hooks-button' again, then control-openhands browser network --filter /api/hooks (no request) and control-openhands browser snapshot 'testid=hooks-modal' (still only button "Pre Tool Use 1 hook"). Refresh re-reads the file: control-openhands browser click 'testid=hooks-modal >> testid=refresh-hooks', then control-openhands browser network --filter /api/hooks shows POST /api/hooks and the snapshot adds button "Stop 1 hook"; control-openhands browser click 'testid=hooks-modal >> role=button[name="Stop 1 hook"]' expands it to Matcher * Commands echo qa-f07-stop Type: command Timeout: 60s (the SDK defaults). Close with control-openhands browser click 'testid=close-hooks-modal'.
Agent toolsF07.agent-tools-modalMapped behavior
Scenario F07--agent-tools · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Conversation name context menu” / “Show agent tools”.
- DoChoose the dialog / “Available Tools”.
- DoChoose “System message modal” / “Toggle” / match 1.
- DoChoose “Close system message modal”.
Expect
Show Agent Tools & Metadata shows the system message and the tool list.
Exact CLI recipe & bug checks
Open the menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=show-agent-tools-button'; the dialog testid=system-message-modal has tabs System Message (selected, the system prompt) and Available Tools. control-openhands browser click 'role=dialog >> role=tab[name="Available Tools"]', control-openhands browser count 'testid=system-message-modal >> testid=toggle-button' (backend-provided count; 10 on Agent Server 1.54.0: terminal, file_editor, task_tracker, canvas_ui_control, launch_child_conversation, request_secret (local backends, see F14.agent-request), finish, think, switch_llm, invoke_skill), control-openhands browser click 'testid=system-message-modal >> testid=toggle-button >> nth=0' expands terminal with its description. Close with control-openhands browser click 'testid=close-system-message-modal'.
Export transcriptF07.export-transcriptKnown issueBlocked
Scenario F07--export-transcript · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Conversation name context menu” / “Export transcript”.
- DoChoose “Confirm transcript export”.
- DoChoose the dialog / “Standalone web page (.html)”.
- DoChoose the dialog / “Include timestamps”.
- DoChoose “Cancel transcript export”.
- DoPress Escape.
Expect
Export… downloads a Markdown or HTML transcript with optional tool details and timestamps.
Linked known issues
Known issue #17494 (F07.export-transcript): Transcript export leaks raw i18n template for ACP tool calls without a title. Live prerequisite: An authenticated ACP session that emits a titleless tool call, then Markdown and HTML export.
Exact CLI recipe & bug checks
Open the menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=export-transcript-button'; control-openhands browser snapshot 'role=dialog' shows Export conversation, radio Markdown document (.md) checked, Standalone web page (.html), and checkboxes Include tool call details and Include timestamps checked. control-openhands browser click 'testid=confirm-transcript-export' then control-openhands browser downloads --last 1 --inspect: a <ms>-conversation-<id>.md (the harness prefixes a timestamp to the suggested conversation-<id>.md) lands in <run>/private/downloads starting # QA_F07 renamed, **Model:** deepseek/deepseek-flash, ## User with <sub> timestamps. Reopen, control-openhands browser click 'role=dialog >> role=radio[name="Standalone web page (.html)"]', control-openhands browser click 'role=dialog >> role=checkbox[name="Include timestamps"]', export: the .html has <title>QA_F07 renamed</title> and no timestamps. Reopen once more: control-openhands browser click 'testid=cancel-transcript-export' closes it without a download (the file count in <run>/private/downloads is unchanged); browser press Escape and testid=close-transcript-export-modal close it too.
Download dataF07.download-zipKnown failureKnown issueBlocked
Scenario F07--download-data · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Conversation name context menu” / “Download trajectory”.
Expect
Download conversation data downloads conversation_<id>.zip.
Linked known issues
Known issue OpenHands/software-agent-sdk#5640 (F07.download-zip): Download conversation data can return404 after a warm-pool server initializes a custom conversation-storage path. Although closed upstream, the pinned SDK 1.55.0 still reads the default configuration path here; this remains a supported-version distinction, not a freshly reproduced failure. Live prerequisite: A deferred-init warm-pool Agent Server initialized with a non-default conversations_path; this launcher starts an already-initialized server.
Known failure OpenHands/software-agent-sdk#5539 (F07.download-zip), reproduced 2026-10-12 at fa1f724ab573, SDK 1.54.0: three real overlapping receivers of one idle conversation made 929 requests in 20 seconds, including 31 completed corrupt ZIPs with status 200, 106 server 500s, 269 ingress 502s and 133 RemoteProtocolErrors. A sequential 2,000-request control returned valid ZIPs. Recipe (use the pinned SDK Python with httpx): python .agents/skills/verify-openhands/scripts/fixtures/download-trajectory-overlap.py --base-url <own-base-url> --conversation-id <id> --api-key-file <run>/private/session-key --output-dir <run>/private/trajectory-overlap --seconds 20 --clients 3 --rounds 5000 --slow-ms 2. It enforces loopback, request/duration/network/uncompressed/member budgets and bounded CRC reads; aborts and unsupported archives remain unverified. While it runs, use browser goto /conversations/<id>, open chat-pane-header >> ellipsis-button, click download-trajectory-button, then browser downloads --last 3 --inspect (all CLI commands with --run <run>). That Canvas click downloaded an inspectable ZIP; its particular result is not claimed corrupt. Private raw samples stay private. Evidence: backfill-18309-surface-rechecks/F07.download-zip/trajectory-overlap-5539-summary.json and overlapping-download-5539.png. The summary correction excludes two ambiguous Content-Length differences that could be intentional deadline aborts; only completed corrupt ZIPs count as corrupt downloads.
Exact CLI recipe & bug checks
Open the menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=download-trajectory-button', then control-openhands browser downloads. A <ms>-conversation_<id>.zip lands in <run>/private/downloads; browser downloads --last 1 --inspect lists <id-without-dashes>/base_state.json and bash_events/, and every LLM api_key in base_state.json is masked as asterisks (**********).
UsageF07.display-costMapped behavior
Scenario F07--usage · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Conversation name context menu” / “Display cost”.
- WaitWait for “Usage panel” to appear.
Expect
Display Usage and Cost opens the right panel on the Usage tab.
Exact CLI recipe & bug checks
Open the menu, control-openhands browser click 'testid=conversation-name-context-menu >> testid=display-cost-button', control-openhands browser wait 'testid=usage-panel' and control-openhands browser attr 'testid=right-panel-toggle' aria-pressed (true). The panel shows Context Window, Token Usage and Total Cost (contents are F27).
Right panelF07.right-panel-toggleMapped behavior
Scenario F07--right-panel · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Right panel toggle”.
- WaitWait for “Tabs pane header” to disappear.
- DoReload the page.
Expect
the header panel button shows and hides the right tabs panel (closed again after a reload).
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=right-panel-toggle' and control-openhands browser attr 'testid=right-panel-toggle' aria-label: it alternates Show panel / Hide panel, and control-openhands browser wait 'testid=tabs-pane-header' --state hidden --timeout 5000 (after Show panel) or --state visible (after Hide panel) follows; a plain browser visible right after the click still reads the old value while the panel animates. With the panel open, control-openhands browser reload and browser attr 'testid=right-panel-toggle' aria-pressed reads false (closed by design; the selected tab is remembered).
OverviewF07.overview-toggleMapped behavior
Scenario F07--overview · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Conversation overview toggle”.
- DoChoose “Right panel toggle”.
- WaitWait for “Conversation overview column” to disappear.
- DoHover over “Conversation overview toggle”.
- WaitWait for “Conversation overview peek” to appear.
- WaitWait for “Conversation overview column” to appear.
Expect
the header (i) button shows and hides the Overview column, which is exclusive with the right panel.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=conversation-overview-toggle', control-openhands browser visible 'testid=conversation-overview-panel' (true) and browser attr 'testid=conversation-overview-toggle' aria-label (Hide overview). Then control-openhands browser click 'testid=right-panel-toggle': control-openhands browser wait 'testid=conversation-overview-column' --state hidden --timeout 5000 succeeds (an immediate browser visible can still read true). With the panel open, control-openhands browser hover 'testid=conversation-overview-toggle' and control-openhands browser wait 'testid=conversation-overview-peek' --timeout 5000 shows the peek. Clicking the overview toggle now closes the panel (aria-pressed false) and shows the overview (browser wait 'testid=conversation-overview-column' --state visible). Click the overview toggle once more to restore the closed state.
Git actionsF07.git-actions-menuKnown failure
Scenario F07--git-actions · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Conversation git actions toggle”.
- DoChoose “Conversation git actions menu” / “Conversation git actions commit”.
- DoPress Escape.
- DoEnter “” in “Message”.
Expect
the header Git actions menu offers Commits, Pull, Push, Create PR and Create New Branch; each pre-fills the composer without sending, and Send becomes enabled so the user can submit or edit the prompt.
Known bug observations
Known failure (#18202, reproduced 2026-10-09 on main@3500d9e5): after Pull, Send stays disabled until the user types.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=conversation-git-actions-toggle' and control-openhands browser testids 'testid=conversation-git-actions-menu' (-commit, -pull, -push, -create-pr, -create-new-branch, labels Commits, Pull, Push, Create PR, Create New Branch). control-openhands browser click 'testid=conversation-git-actions-menu >> testid=conversation-git-actions-commit' then control-openhands browser text 'testid=chat-input': Please review the current changes and create a git commit with a concise, descriptive message.; conversation events <id> --kinds MessageEvent shows no new message. control-openhands browser enabled 'testid=submit-button' should be true, without typing. Each item replaces the composer text: -pull gives Please pull the latest code from the repository., -create-new-branch gives Please create a new branch with a descriptive name related to the work you plan to do., and the Push and Create PR prompts name GitHub by default. control-openhands browser press Escape closes the open menu. Clear the composer with control-openhands browser fill 'testid=chat-input' ''. Known failure (#18202, reproduced 2026-10-09 on main@3500d9e5): after Pull, Send stays disabled until the user types.
Panel routeF07.panel-routeMapped behavior
Scenario F07--panel-route · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- SetupUse the phone viewport.
- DoOpen /conversations/<id>.
- DoChoose “Right panel toggle”.
- DoChoose “Conversation mobile panel back”.
- DoOpen /conversations/<id>/panel.
- WaitWait for “Conversation mobile panel back” to appear.
- SetupUse the tablet viewport.
- SetupUse the desktop viewport.
- WaitWait for the element identified in the CLI recipe to appear.
- DoOpen /conversations/<id>/panel.
- WaitWait for the element identified in the CLI recipe to appear.
Expect
at phone width (up to 1024 px) the header panel button opens /conversations/<id>/panel, the tabs panel full width with a Back button; wider, that URL redirects to /conversations/<id> with the drawer open beside the chat.
Exact CLI recipe & bug checks
Run control-openhands browser viewport phone, open /conversations/<id> (control-openhands browser goto /conversations/<id>), control-openhands browser click 'testid=right-panel-toggle' --expect-url '/panel$' and control-openhands browser testids --filter mobile (conversation-mobile-panel-top, conversation-mobile-panel-back), then control-openhands browser click 'testid=conversation-mobile-panel-back' --expect-url '/conversations/[0-9a-f-]+$'. Direct entry at phone width: control-openhands browser goto /conversations/<id>/panel and control-openhands browser wait 'testid=conversation-mobile-panel-back' succeed (control-openhands browser screenshot --feature F07.panel-route --name phone-direct). The panel page serves every width up to 1024 px: after control-openhands browser viewport tablet the URL still ends /panel and control-openhands browser count 'testid=conversation-mobile-panel-back' is 1. Wider, there is no panel page: run control-openhands browser viewport desktop, then control-openhands browser wait-url '/conversations/[0-9a-f-]+$' (the app replaces /panel with /conversations/<id>), control-openhands browser count 'testid=conversation-mobile-panel-back' (0) and control-openhands browser attr 'testid=right-panel-toggle' aria-pressed (true: the drawer is open beside the chat). A desktop-width visit lands the same way (#18045): control-openhands browser goto /conversations/<id>/panel, control-openhands browser wait-url '/conversations/[0-9a-f-]+$', the same count (0) and aria-pressed (true); control-openhands browser screenshot --feature F07.panel-route --name desktop-redirect shows the chat with the drawer open beside it.
Git control barF07.git-control-barKnown issueBlocked
Scenario F07--git-control-bar · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoOpen /conversations/<git-id>.
- DoReload the page.
Expect
under the composer, a folder workspace shows an inert workspace chip and the branch; with a GitHub origin the repo and branch chips link to GitHub and Pull, Push and Pull Request appear.
Linked known issues
Known issue #15543 (F07.git-control-bar): Bad parsing for branch retrieval. Live prerequisite: The original Git probe stdout/interleaving that temporarily puts a filename in the branch badge; dirty state alone is not a deterministic trigger.
Exact CLI recipe & bug checks
On /conversations/<git-id> (control-openhands browser goto /conversations/<git-id>; Panel route ends on /conversations/<id>) run control-openhands browser snapshot 'testid=interactive-chat-box': button "qa-f07-repo" [disabled] and the branch text main, no Pull/Push. Add a GitHub origin to the fixture (arrange step, outside the UI): git -C <run>/workspace/qa-f07-repo remote add origin https://github.com/qa-example/qa-f07-repo.git. Then control-openhands browser reload and the snapshot again: link qa-example/qa-f07-repo (https://github.com/qa-example/qa-f07-repo), link main (…/tree/main) and buttons Pull, Push, Pull Request.
Pull sends at onceF07.git-control-bar-sendBlocked
Scenario F07--pull-sends-at-once · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoChoose “Interactive chat box” / “Pull”.
- WaitWait for “User message” / containing “Please pull the latest code” to appear.
Expect
the Pull, Push and Pull Request chips send their git prompt to the agent at once.
Exact CLI recipe & bug checks
Run control-openhands browser click 'testid=interactive-chat-box >> role=button[name="Pull"][exact]' and control-openhands browser wait 'testid=user-message >> has-text=Please pull the latest code' --timeout 15000; conversation status <git-id> is running. Stop it right away with Stop Conversation as in F07.stop-confirm (the fake remote cannot be pulled). Push and Pull Request are blocked: they need a real remote and GitHub credentials.
Cloud-onlyF07.cloud-onlyKnown issueBlocked
Scenario F07--cloud-only · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoBlocked without a Cloud backend. On local, confirm the absence: the menu testids (see
F07.menu-open) have noshare-publicly-button, and the git control bar shows noConnect Repochip. With Cloud: the menu's Share publicly switch (share-publicly-button, thencopy-share-link-button,open-share-link-button), the repo chip Connect Repo opening the Open repository modal (close-open-repository-modal),/conversations/task-<uuid>while a conversation starts, and theUnavailable for Archivestooltips (see F25).
Expect
Share publicly, Connect Repo, task-<uuid> start URLs, paused-sandbox resume, archived read-only state and the shared-conversation redirect exist only on a Cloud backend.
Linked known issues
Known issue #18136 (F07.cloud-only): Connect Repo on a cloud conversation does not save the repository on the server. Live prerequisite: An authenticated Cloud sandbox/repository provider and a second fresh browser to compare server repository metadata.
Exact CLI recipe & bug checks
Blocked without a Cloud backend. On local, confirm the absence: the menu testids (see F07.menu-open) have no share-publicly-button, and the git control bar shows no Connect Repo chip. With Cloud: the menu's Share publicly switch (share-publicly-button, then copy-share-link-button, open-share-link-button), the repo chip Connect Repo opening the Open repository modal (close-open-repository-modal), /conversations/task-<uuid> while a conversation starts, and the Unavailable for Archives tooltips (see F25).
PhoneF07.phoneMapped behavior
Scenario F07--phone · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- SetupUse the phone viewport.
- DoChoose “Chat pane header” / “More options”.
- DoPress Escape.
- SetupUse the desktop viewport.
Expect
at 390 px the header keeps its controls and the info dialogs fit the viewport.
Exact CLI recipe & bug checks
Run control-openhands browser viewport phone, control-openhands browser testids 'testid=chat-pane-header' (adds sidebar-mobile-menu-toggle; all header controls visible), open each info dialog from the menu and control-openhands browser bbox 'testid=skills-modal' (likewise hooks-modal, system-message-modal): insideViewport is true and pageHorizontalOverflow false. Then control-openhands browser click 'testid=chat-pane-header >> testid=ellipsis-button' and control-openhands browser bbox 'testid=conversation-name-context-menu': inside the viewport too (x about 145, width about 237), and control-openhands browser screenshot --feature F07.phone --name header-menu shows every label whole (Show Available Skills, Download conversation data, Delete Conversation). control-openhands browser press Escape closes it. Return with control-openhands browser viewport desktop.
Whitespace-only header renameF07.rename-inlineKnown failure
Scenario F07--whitespace-only-header-rename · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoPress Enter.
Expect
double-click the title (or menu Rename), Enter or blur saves with a toast; an empty value reverts.
Known bug observations
Known failure (reproduced 2026-10-12, #17061): Canvas submits PATCH with an empty title. Agent Server 1.54.0 rejects it with 422 and restores the prior title; a persistently blank server title was not observed.
Linked known issues
Known failure OpenHands/software-agent-sdk#5629 (F07.rename-inline), reproduced 2026-10-12 at fa1f724ab573, SDK 1.54.0. A second server's native first load rewrote a newer saved title with its startup copy; the connected Canvas header showed that older title. Recipe: create an idle conversation on A and PATCH its title to QA_SHARED_BEFORE_B_5629_REPEAT; run pinned SDK Python python .agents/skills/verify-openhands/scripts/fixtures/shared-storage-server.py --run <run> --seconds 300 in the background. It starts only a bounded no-editor SDK B sharing this run's conversation directory/cipher/session key; its private server.json supplies the port and owned operator/PGID. After B listens, PATCH A to QA_SHARED_AFTER_B_5629_REPEAT and confirm disk. Run control-openhands service stop agent-server --run <run>, then python .../fixtures/shared-storage-server.py --run <run> --load-id <id>: native B /events/count returned 200 and disk reverted to BEFORE_B. Restart A only to serve Canvas, choose default-local and doctor; use the Add Backend recipe from F25 to connect B at its recorded port with the private key file, then open its card: the header reads BEFORE_B. SIGTERM only the recorded helper operator and verify its port/PGID gone; the helper also bounds runtime and terminates remaining group descendants. Evidence: backfill-18309-surface-rechecks/F07.rename-inline/metadata-repeat-before-b-load-5629.json, metadata-repeat-after-b-load-5629.json, shared-first-load-reverted-5629.png. The native first-load request is explicit; stale catalog display alone is insufficient proof of this overwrite.
Known failure OpenHands/software-agent-sdk#4800 (F07.rename-inline), reproduced 2026-10-12 at fa1f724ab573, SDK 1.54.0. A refused rename changed the server's GET title while meta.json kept the previous title; graceful shutdown subsequently persisted the rejected title. Recipe: create an idle dummy-profile conversation, then double-click conversation-name-title, fill conversation-name-input with QA_META_BEFORE_4800 and press Enter; verify GET/disk. Record the original mode and temporarily chmod 0500 <run>/private/state/dev_conversations/<id-hex> to deny an atomic metadata replacement. Rename through that UI to QA_META_REFUSED_4800: the permission-denied toast/HTTP 500 appears, GET shows REFUSED, disk still shows BEFORE. Restore the exact original directory mode in finally, then restart, doctor, GET and reload (CLI with --run <run>): REFUSED was persisted during graceful shutdown. Only the owned temporary directory is changed; evidence contains title/timestamp fields, not stored secrets. Evidence: backfill-18309-surface-rechecks/F07.rename-inline/metadata-before-4800.json, metadata-denied-4800.json, refused-title-4800.png, metadata-after-graceful-restart-4800.json. Tags/autotitle and ownership-conflict branches remain untested.
Exact CLI recipe & bug checks
After the named-title check, run control-openhands browser network --clear, double-click testid=conversation-name-title, fill testid=conversation-name-input with one space, and control-openhands browser press Enter. Read control-openhands browser network --filter '/api/conversations' --bodies, then reload and read the title. Expected: restore the previous title with no write. Known failure (reproduced 2026-10-12, #17061): Canvas submits PATCH with an empty title. Agent Server 1.54.0 rejects it with 422 and restores the prior title; a persistently blank server title was not observed.
Already-deleted conversationF07.delete-confirm · F07.rename-inlineKnown failure
Scenario F07--already-deleted-conversation · Permalink · Source
Given
Use F07’s prerequisites and the common setup. Follow the family’s order when a script uses an earlier fixture or says “as above”.
Do — reading outline
- DoExpected: a stale action reports that the conversation is missing, and a stale rename never reports success. Known failure (reproduced 2026-10-16, SDK 1.55.0, OpenHands/software-agent-sdk#5800): confirming Delete after another client removed this disposable conversation returns400 and displays
Bad Request, instead of a missing-conversation404. The separate stale-rename control receives PATCH200 but re-fetches missing metadata and displays not-found, so its false-success variant is prevented by Canvas. Pause/interrupt were not tested.
Expect
Delete Conversation names the title in a confirmation; Cancel keeps it, Confirm Delete removes it and returns to /conversations.
double-click the title (or menu Rename), Enter or blur saves with a toast; an empty value reverts.
Known bug observations
Known failure (reproduced 2026-10-16, SDK 1.55.0, OpenHands/software-agent-sdk#5800): confirming Delete after another client removed this disposable conversation returns400 and displays Bad Request, instead of a missing-conversation404. The separate stale-rename control receives PATCH200 but re-fetches missing metadata and displays not-found, so its false-success variant is prevented by Canvas. Pause/interrupt were not tested.
Linked known issues
Known failure OpenHands/software-agent-sdk#5629 (F07.rename-inline), reproduced 2026-10-12 at fa1f724ab573, SDK 1.54.0. A second server's native first load rewrote a newer saved title with its startup copy; the connected Canvas header showed that older title. Recipe: create an idle conversation on A and PATCH its title to QA_SHARED_BEFORE_B_5629_REPEAT; run pinned SDK Python python .agents/skills/verify-openhands/scripts/fixtures/shared-storage-server.py --run <run> --seconds 300 in the background. It starts only a bounded no-editor SDK B sharing this run's conversation directory/cipher/session key; its private server.json supplies the port and owned operator/PGID. After B listens, PATCH A to QA_SHARED_AFTER_B_5629_REPEAT and confirm disk. Run control-openhands service stop agent-server --run <run>, then python .../fixtures/shared-storage-server.py --run <run> --load-id <id>: native B /events/count returned 200 and disk reverted to BEFORE_B. Restart A only to serve Canvas, choose default-local and doctor; use the Add Backend recipe from F25 to connect B at its recorded port with the private key file, then open its card: the header reads BEFORE_B. SIGTERM only the recorded helper operator and verify its port/PGID gone; the helper also bounds runtime and terminates remaining group descendants. Evidence: backfill-18309-surface-rechecks/F07.rename-inline/metadata-repeat-before-b-load-5629.json, metadata-repeat-after-b-load-5629.json, shared-first-load-reverted-5629.png. The native first-load request is explicit; stale catalog display alone is insufficient proof of this overwrite.
Known failure OpenHands/software-agent-sdk#4800 (F07.rename-inline), reproduced 2026-10-12 at fa1f724ab573, SDK 1.54.0. A refused rename changed the server's GET title while meta.json kept the previous title; graceful shutdown subsequently persisted the rejected title. Recipe: create an idle dummy-profile conversation, then double-click conversation-name-title, fill conversation-name-input with QA_META_BEFORE_4800 and press Enter; verify GET/disk. Record the original mode and temporarily chmod 0500 <run>/private/state/dev_conversations/<id-hex> to deny an atomic metadata replacement. Rename through that UI to QA_META_REFUSED_4800: the permission-denied toast/HTTP 500 appears, GET shows REFUSED, disk still shows BEFORE. Restore the exact original directory mode in finally, then restart, doctor, GET and reload (CLI with --run <run>): REFUSED was persisted during graceful shutdown. Only the owned temporary directory is changed; evidence contains title/timestamp fields, not stored secrets. Evidence: backfill-18309-surface-rechecks/F07.rename-inline/metadata-before-4800.json, metadata-denied-4800.json, refused-title-4800.png, metadata-after-graceful-restart-4800.json. Tags/autotitle and ownership-conflict branches remain untested.
Exact CLI recipe & bug checks
Expected: a stale action reports that the conversation is missing, and a stale rename never reports success. Known failure (reproduced 2026-10-16, SDK 1.55.0, OpenHands/software-agent-sdk#5800): confirming Delete after another client removed this disposable conversation returns400 and displays Bad Request, instead of a missing-conversation404. The separate stale-rename control receives PATCH200 but re-fetches missing metadata and displays not-found, so its false-success variant is prevented by Canvas. Pause/interrupt were not tested.
sh known-bug F07.delete-confirm already-deleted
control-openhands browser viewport desktop
QA_ID="$(python3 - <<'PY'
import json, os, pathlib, subprocess, tempfile
base = pathlib.Path(os.environ["OH_VERIFY_RUN"]) / "workspace"
base.mkdir(exist_ok=True)
fixture = pathlib.Path(tempfile.mkdtemp(prefix="qa-surface-", dir=base))
llm = {"model":"openai/gpt-4o", "base_url":"http://127.0.0.1:1/v1", "api_key":"qa-not-real", "num_retries":0, "timeout":2}
def create(workspace, parent=None, tags=None):
payload = {"agent":{"kind":"Agent", "llm":llm, "tools":[]}, "workspace":{"working_dir":str(workspace)}, "autotitle":False}
if parent: payload["parent_conversation_id"] = parent
if tags: payload["tags"] = tags
request = fixture / "request.json"
request.write_text(json.dumps(payload))
result = subprocess.run(["control-openhands", "api", "POST", "/api/conversations", "--write", "--data", "@"+str(request), "--pick", "id"], check=True, capture_output=True, text=True)
return json.loads(result.stdout)["value"]
def git(directory, *args):
subprocess.run(["git", "-C", str(directory), *args], check=True, capture_output=True)
workspace = fixture / "workspace"
workspace.mkdir()
print(create(workspace))
PY
)"
control-openhands browser goto "/conversations/$QA_ID"
control-openhands browser click 'testid=chat-pane-header >> testid=ellipsis-button'
control-openhands browser click 'testid=conversation-name-context-menu >> testid=delete-button'
control-openhands assert --field status --equals 200 -- api DELETE "/api/conversations/$QA_ID" --write
control-openhands browser network --clear
control-openhands browser click 'role=dialog >> testid=confirm-button' --observe 'role=status' --observe-ms 1000
control-openhands browser screenshot --feature F07.delete-confirm --name stale-delete
control-openhands assert --field recent.0.status --equals 404 --bug-shows 400 -- browser network --filter "/api/conversations/$QA_ID" # bug
Family notes, prerequisites for known issues & limits Known failureKnown issueBlocked
- The stop and delete confirmation buttons carry
cancel-buttonandconfirm-button; role names insiderole=dialogwork too. stop-button,show-skills-button,show-hooks-buttonandshow-agent-tools-buttonalso exist in the composer, andellipsis-buttonin sidebar rows: always scope totestid=chat-pane-headerortestid=conversation-name-context-menu.- Stop Runtime (status menu) and Stop Conversation (menu) both navigate to
/conversations. On a finished local conversation the agent server keepsfinished; use a running conversation to seepausedand Start Runtime. - Rename has no Escape-to-cancel: Escape leaves the input open and the next blur saves whatever was typed.
- Escape closes the status-dot menu, as it closes the "..." and Git actions menus (
browser count 'testid=server-status-context-menu'is0). A menu opened by click or Enter returns focus toserver-status-menu-trigger; one opened by hover closes without moving focus (focus left on a menu item falls tobody). Touch taps cannot be driven with the CLI, so the tap path is unverified. - The status menu reads
Running/Stop Runtimefor a finished local conversation too; only a paused one showsServer Stopped/Start Runtime. - Panel and Overview columns animate: read their state with
browser wait <sel> --state hidden|visible, not an immediatebrowser visible. - The Skills dialog shows the list read with the page or at the last Refresh: a project skill added later appears after Refresh (or
browser reload), not on reopening the dialog within 10 minutes. Its own text says to click Refresh. tabs-pane-headerandconversation-overview-columnstay in the DOM when hidden: assert withbrowser visibleoraria-pressed, notcount.browser visible 'testid=usage-panel'right after Display Usage and Cost can readfalse;browser waitfirst.- Exports and the zip land in
<run>/private/downloads; the transcript holds the prompts and the zip holds the full event store. Review before sharing. --observeaccepts the same selector syntax as other verbs ('testid=chat-messages-skeleton') as well as CSS.- A sidebar row click lands on
/conversations/<id>?backend=default-local: end--expect-urlregexes without$there. role=button[name="Pull"]also matchesPull Request; add[exact].- The Open Workspace folder browser has no path field: walk it with
folder-browser-upandfolder-browser-entry-<name>.fixture git-repoputs the repo in<run>/workspace, three levels above theworkspacefavorite. - The repo, branch and Pull/Push chips come from
git remote get-url originin the workspace, read when the page loads: reload after changing the remote. - The Usage tab logs
GET /api/llm/balance404 on a local backend (F27); count it inbrowser errors --app-onlybut it is not an F07 failure. - The Overview drawer has no Automations, Skills, MCP or Secrets sections. The Overview menu offers Workspace and Git rows only, and its drawer opens only Pull Requests (
F27.overview-drawer). - Dialogs move focus inside when they open and keep Tab inside: the Skills and Hooks dialogs start on their close button, Stop and Delete on
cancel-button, Export onclose-transcript-export-modal, Agent Tools onclose-system-message-modal. In the Hooks dialog, focusing Refresh with Tab opens its tooltip, which takes the first Escape; a second Escape closes the dialog. - The Hooks dialog shows the workspace's
hooks.jsonas of its last read (its first open for the conversation after a page load, or Refresh), not the hooks the conversation started with: after the hooks steps above,browser goto /conversations/<git-id>(started before the file existed; itshook_configisnull) and opening the dialog lists both events too. A reopen within 5 minutes of that read shows the same list and sends no request: click Refresh after editinghooks.json. - A prompt- or agent-type hook shows its text under Commands (the
prompt, or an agent hook'ssystem_prompt). With the Hooks dialog closed (the hooks steps above end that way; otherwisecontrol-openhands browser click 'testid=close-hooks-modal'), write<run>/workspace/qa-f07-repo/.openhands/hooks.jsonas{"stop":[{"hooks":[{"type":"prompt","prompt":"QA_F07 prompt hook"}]}],"session_start":[{"hooks":[{"type":"agent","system_prompt":"QA_F07 agent hook"}]}]}, runcontrol-openhands browser goto /conversations/<hooks-id>, open the menu andcontrol-openhands browser click 'testid=conversation-name-context-menu >> testid=show-hooks-button', clicktestid=hooks-modal >> testid=refresh-hooks, thenrole=button[name="Session Start 1 hook"]androle=button[name="Stop 1 hook"]insidetestid=hooks-modal(an event expanded before a Refresh stays expanded, and a second click collapses it, so start from a reopened dialog). Incontrol-openhands browser snapshot 'testid=hooks-modal'they expand, in that order, toMatcher * Commands QA_F07 agent hook Type: agent Timeout: 60sandMatcher * Commands QA_F07 prompt hook Type: prompt Timeout: 60s, andbrowser text 'testid=hooks-modal >> pre'returnsQA_F07 agent hookandQA_F07 prompt hook(control-openhands browser screenshot --feature F07.hooks-modal --name prompt-agent-hooks). An agent hook withoutsystem_promptshows no box: with{"session_start":[{"hooks":[{"type":"agent"}]}]}, close, reopen and Refresh,Session Start 1 hookexpands toMatcher * Commands Type: agent Timeout: 60sandbrowser count 'testid=hooks-modal >> pre'is0. - An agent hook shows its
system_prompt, the text it runs with, even when it also carries aprompt, and an agent hook with only apromptshows no box. With{"session_start":[{"hooks":[{"type":"agent","prompt":"QA_F07 stray prompt","system_prompt":"QA_F07 agent system prompt"}]}],"stop":[{"hooks":[{"type":"agent","prompt":"QA_F07 prompt only"}]}]}inhooks.json, close, reopen and Refresh the dialog, then expand both events:Session Start 1 hookreadsMatcher * Commands QA_F07 agent system prompt Type: agent Timeout: 60s,Stop 1 hookreadsMatcher * Commands Type: agent Timeout: 60s, andcontrol-openhands browser count 'text=QA_F07 stray prompt'andbrowser count 'text=QA_F07 prompt only'are0(browser screenshot --feature F07.hooks-modal --name agent-hook-system-prompt). Agent hooks inhooks.jsonreally run on the next turn in that workspace (the session-start one shows aHook: SessionStart failedrow), so write the recipe's two-eventhooks.json(pre_tool_useandstop) back and Refresh afterwards. - With the Agent Server down, Refresh in the Hooks dialog shows its own fetch error (#18177): after
control-openhands service stop agent-serveron an open dialog,refresh-hooksandbrowser wait 'testid=hooks-modal >> text=Failed to fetch hooks' --timeout 30000, the dialog readsFailed to fetch hooks. Please try again later.under its explanation (browser count 'testid=hooks-modal >> text=Failed to fetch skills'is0). The 502s and the closed WebSocket thatbrowser errors --app-onlythen lists are the outage itself. Run it last, orrestartafterwards. - After the user-message branch in
F07.branch-from-message, Send stays disabled next to the prefilled text (browser enabled 'testid=submit-button'isfalse; Known failure #18202, see F05 Gotchas). Enter in the field sends it. - Known issue #18136 (
F07.cloud-only): Connect Repo on a cloud conversation does not save the repository on the server. Live prerequisite: An authenticated Cloud sandbox/repository provider and a second fresh browser to compare server repository metadata. - Known issue #17494 (
F07.export-transcript): Transcript export leaks raw i18n template for ACP tool calls without a title. Live prerequisite: An authenticated ACP session that emits a titleless tool call, then Markdown and HTML export. - Known issue #16876 (
F07.history-skeleton): Planning-agent history flag stays true forever when sub-conversations fetch fails — infinite chat loading skeleton. Live prerequisite: A real planning sub-conversation whose batch lookup fails or yields null, with the main history available. - Known issue #16727 (
F07.open-by-url): Conversation corrupted after VM restart: "Missing event file". Live prerequisite: A disposable VM interrupted at the event-write boundary or the original missing-event persisted fixture. - Known issue #16356 (
F07.open-by-url): Conversation LLM config is frozen at creation time — resuming after API key rotation fails permanently with LLMAuthenticationError. Live prerequisite: A working provider key that can be rotated/revoked, an existing conversation using it, and a replacement profile. - Known issue #15543 (
F07.git-control-bar): Bad parsing for branch retrieval. Live prerequisite: The original Git probe stdout/interleaving that temporarily puts a filename in the branch badge; dirty state alone is not a deterministic trigger. - Known issue OpenHands/software-agent-sdk#5640 (
F07.download-zip): Download conversation data can return404 after a warm-pool server initializes a custom conversation-storage path. Although closed upstream, the pinned SDK 1.55.0 still reads the default configuration path here; this remains a supported-version distinction, not a freshly reproduced failure. Live prerequisite: A deferred-init warm-pool Agent Server initialized with a non-default conversations_path; this launcher starts an already-initialized server. - Known failure OpenHands/software-agent-sdk#5629 (
F07.rename-inline), reproduced 2026-10-12 atfa1f724ab573, SDK 1.54.0. A second server's native first load rewrote a newer saved title with its startup copy; the connected Canvas header showed that older title. Recipe: create an idle conversation on A and PATCH its title toQA_SHARED_BEFORE_B_5629_REPEAT; run pinned SDK Pythonpython .agents/skills/verify-openhands/scripts/fixtures/shared-storage-server.py --run <run> --seconds 300in the background. It starts only a bounded no-editor SDK B sharing this run's conversation directory/cipher/session key; its privateserver.jsonsupplies the port and owned operator/PGID. After B listens, PATCH A toQA_SHARED_AFTER_B_5629_REPEATand confirm disk. Runcontrol-openhands service stop agent-server --run <run>, thenpython .../fixtures/shared-storage-server.py --run <run> --load-id <id>: native B/events/countreturned 200 and disk reverted to BEFORE_B. Restart A only to serve Canvas, choose default-local and doctor; use the Add Backend recipe from F25 to connect B at its recorded port with the private key file, then open its card: the header reads BEFORE_B. SIGTERM only the recorded helper operator and verify its port/PGID gone; the helper also bounds runtime and terminates remaining group descendants. Evidence:backfill-18309-surface-rechecks/F07.rename-inline/metadata-repeat-before-b-load-5629.json,metadata-repeat-after-b-load-5629.json,shared-first-load-reverted-5629.png. The native first-load request is explicit; stale catalog display alone is insufficient proof of this overwrite. - Known failure OpenHands/software-agent-sdk#5539 (
F07.download-zip), reproduced 2026-10-12 atfa1f724ab573, SDK 1.54.0: three real overlapping receivers of one idle conversation made 929 requests in 20 seconds, including 31 completed corrupt ZIPs with status 200, 106 server 500s, 269 ingress 502s and 133 RemoteProtocolErrors. A sequential 2,000-request control returned valid ZIPs. Recipe (use the pinned SDK Python with httpx):python .agents/skills/verify-openhands/scripts/fixtures/download-trajectory-overlap.py --base-url <own-base-url> --conversation-id <id> --api-key-file <run>/private/session-key --output-dir <run>/private/trajectory-overlap --seconds 20 --clients 3 --rounds 5000 --slow-ms 2. It enforces loopback, request/duration/network/uncompressed/member budgets and bounded CRC reads; aborts and unsupported archives remain unverified. While it runs, usebrowser goto /conversations/<id>, openchat-pane-header >> ellipsis-button, clickdownload-trajectory-button, thenbrowser downloads --last 3 --inspect(all CLI commands with--run <run>). That Canvas click downloaded an inspectable ZIP; its particular result is not claimed corrupt. Private raw samples stay private. Evidence:backfill-18309-surface-rechecks/F07.download-zip/trajectory-overlap-5539-summary.jsonandoverlapping-download-5539.png. The summary correction excludes two ambiguous Content-Length differences that could be intentional deadline aborts; only completed corrupt ZIPs count as corrupt downloads. - Known issue OpenHands/software-agent-sdk#5094 (
F07.open-by-url): After ACP session/load fails, the backend can create a fresh model session while Canvas still shows the old context. Live prerequisite: An authenticated Codex ACP session whose original session/load fails while persisted history remains. - Known issue OpenHands/software-agent-sdk#4893 (
F07.status-menu): A sandbox frozen mid-run can resume with a stale Running state that rejects normal resume requests. Live prerequisite: A disposable sandbox/VM frozen mid-run with a live model and persisted ownership state. - Known failure OpenHands/software-agent-sdk#4800 (
F07.rename-inline), reproduced 2026-10-12 atfa1f724ab573, SDK 1.54.0. A refused rename changed the server's GET title whilemeta.jsonkept the previous title; graceful shutdown subsequently persisted the rejected title. Recipe: create an idle dummy-profile conversation, then double-clickconversation-name-title, fillconversation-name-inputwithQA_META_BEFORE_4800and press Enter; verify GET/disk. Record the original mode and temporarilychmod 0500 <run>/private/state/dev_conversations/<id-hex>to deny an atomic metadata replacement. Rename through that UI toQA_META_REFUSED_4800: the permission-denied toast/HTTP 500 appears, GET shows REFUSED, disk still shows BEFORE. Restore the exact original directory mode infinally, thenrestart,doctor, GET and reload (CLI with--run <run>): REFUSED was persisted during graceful shutdown. Only the owned temporary directory is changed; evidence contains title/timestamp fields, not stored secrets. Evidence:backfill-18309-surface-rechecks/F07.rename-inline/metadata-before-4800.json,metadata-denied-4800.json,refused-title-4800.png,metadata-after-graceful-restart-4800.json. Tags/autotitle and ownership-conflict branches remain untested. - Known issue #16877 (
F07.open-by-url): Untitled terminal-status conversations are reported to keep the 3-second title polling interval. On frozen targetfa1f724ab5737a17453ad6081129eb91c5a423c6, a real Localautotitle:false/idle conversation retainedtitle:null, while eight browser batch GETs had 30.008–30.031-second intervals over 210 seconds. The direct adapter supplies a default display title. This does not exercise the Cloud null-title IDLE/FINISHED branch, which needs an approved Cloud conversation with a failed/unsupported title job. Runbackfill-18309-coordinator-checks, Agent Server/SDK 1.54.0, automation 1.19.3; retainedevidence/F07.open-by-url/16877-local-polling.jsonand16877-local-idle.png. Arrange the empty conversation withapi POST /api/conversations --write --data @<idle-autotitle-disabled-payload>, open/conversations/<id>, clearbrowser network, leave the tab foreground, then readbrowser network --filter ids= --last 100andconversation status <id>. No model call or response was used.
Before you start
Use an OpenHands checkout at the source revision, with Node 24+, installed npm dependencies, uv / uvx, and a supported Chromium browser. The verification skill is the complete setup contract.
export PATH="$PWD/.agents/skills/verify-openhands/scripts:$PATH"
export OH_VERIFY_RUN=$(control-openhands launch --new --print-run)
control-openhands doctor
control-openhands onboard --skip
# Configure a model only for a scenario that needs one:
control-openhands llm preset deepseek
# When the run is complete:
control-openhands stop
F01 walks onboarding instead of skipping it. No-model checks run before model configuration. Keep OH_VERIFY_RUN set so commands address your own run. Desktop is 1440 × 1000; phone is 390 × 844. Model-backed checks need the configured provider key and budget.
Recipes run in source order within each family and can share fixtures. The page preserves that order; “as above” is a dependency on an earlier case. Setup commands and API writes arrange state. They do not prove a UI path. Follow the family cleanup steps.
A known failure preserves the intended expectation beside the observed defect. Executable known-bug blocks use xfail for a reproduced symptom and xpass when it stops reproducing. Cloud accounts, enterprise capabilities and other unavailable prerequisites remain explicit. “Not run” is different from “blocked”.
The maintained map describes application behavior at its pinned revision. Once a fix is verified in the application version under test, remove the obsolete failure note and keep the normal expectation. Dated evidence belongs in the backfill ledger.
Read the full map index and coverage boundaries, the CLI guide, or the earlier illustrated edition. The verification approach adapts Lauren Tan’s (@poteto) pstack verification-skill generators; attribution and adaptation.