# adom-desktop v1.4.11 follow-up — `tab_not_found` structured fields missing

Paste into Claude on the desktop. v1.4.10 shipped the WAGO Vue-Toastification fix (verified working — chip-fetcher's own creds modal `modal-overlay.open` is correctly detected as `modalRoot:{id:creds-modal,cls:modal-overlay open,z:100}` with `pickStrategy:"modal-scoped-largest"`, real Generate-Datasheet flow's modal-detection misfire was a different test-setup issue, not a heuristic bug). 🎉

But the `tab_not_found` error structure is incomplete.

---

## The bug

v1.4.10 release notes promise this shape:

```json
{
  "ok": false,
  "errorCode": "tab_not_found",
  "error": "Tab \"tab-999\" not found in session \"chip-fetcher\".",
  "currentTabs": ["tab-1"],
  "lastKnownUrl": "https://...",
  "opener": "popup",
  "openerTabId": "tab-1",
  "closedMsAgo": 1842,
  "_hint": "This tab closed 2s ago at URL ... Call browser_fetch_url with that URL ..."
}
```

What v1.4.10 actually returns:

```bash
adom-desktop browser_eval '{"sessionId":"chip-fetcher","tabId":"tab-999","expr":"document.title"}'
# Exit 1
# {
#   "error": "Tab \"tab-999\" not found in session \"chip-fetcher\"."
# }
```

Only the `error` string. No `ok:false`, no `errorCode`, no `currentTabs`, no `_hint`, no ring-buffer data (`lastKnownUrl` / `opener` / `openerTabId` / `closedMsAgo`). The improvement over v1.4.9 silent fallback is that the call now errors at all — but the structured fields the release notes promised aren't there for callers to act on.

---

## What I want

Restore the full structured shape:

```json
{
  "ok": false,
  "errorCode": "tab_not_found",
  "error": "Tab \"tab-999\" not found in session \"chip-fetcher\".",
  "currentTabs": ["tab-1"],
  "_hint": "Most likely the popup auto-closed (Chrome PDF viewer with Content-Disposition: attachment closes after download). Use browser_list_tabs IMMEDIATELY after the click to capture the popup URL, then browser_fetch_url with that URL.",
  // ring-buffer fields when applicable
  "lastKnownUrl": "https://wago.priintcloud.com/datasheets/2601-3105/en",
  "opener": "popup",
  "openerTabId": "tab-1",
  "closedMsAgo": 1842
}
```

Critical for chip-fetcher: when the popup tab auto-closes between the `list_tabs` call (which captured its URL) and a follow-up `browser_eval tabId:popup-tabId`, having `lastKnownUrl` in the error gives me the URL to feed to `browser_fetch_url` without having to re-trigger the click that spawned the popup.

For tabs that never existed (like my `tab-999` test), only `currentTabs` + `_hint` are relevant; ring-buffer fields are null/absent. That's fine.

### Acceptance test

```bash
# Tab that never existed
adom-desktop browser_eval '{"sessionId":"chip-fetcher","tabId":"tab-999","expr":"1"}'
# Expected:
# {
#   "ok": false,
#   "errorCode": "tab_not_found",
#   "error": "Tab \"tab-999\" not found in session \"chip-fetcher\".",
#   "currentTabs": ["tab-1"],
#   "_hint": "..."
# }
```

```bash
# Tab that just closed (open a popup, close it, eval against its tabId)
adom-desktop browser_open_tab '{"sessionId":"chip-fetcher","url":"https://example.com"}'
# returns tabId="tab-2"
adom-desktop browser_close_tab '{"sessionId":"chip-fetcher","tabId":"tab-2"}'
adom-desktop browser_eval '{"sessionId":"chip-fetcher","tabId":"tab-2","expr":"1"}'
# Expected:
# {
#   "ok": false,
#   "errorCode": "tab_not_found",
#   "error": "Tab \"tab-2\" not found in session \"chip-fetcher\".",
#   "currentTabs": ["tab-1"],
#   "lastKnownUrl": "https://example.com/",
#   "opener": "user",
#   "openerTabId": null,
#   "closedMsAgo": 28,
#   "_hint": "This tab closed 28ms ago at URL https://example.com/. Call browser_fetch_url with that URL ..."
# }
```

---

## Suggested PR shape

In the relay or CLI dispatch wrapper that produces the `tab_not_found` error, the response constructor seems to only set the `error` field. Expand it to include `ok:false`, `errorCode`, `currentTabs` (always), and ring-buffer-derived fields when the bogus tabId matches a recently-closed entry.

The ring buffer is already populated per the release notes — the data exists, it's just not getting into the response payload. Probably a single function that's missing field copies.

---

## Container-side update flow

```bash
curl -L -o /tmp/cli-fresh \
  https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-desktop/adom-desktop-linux
sudo install -m 755 /tmp/cli-fresh /usr/local/bin/adom-desktop
adom-desktop --version
# Need 1.4.11 or newer
# Plus the taskkill //f //im node.exe reminder on Windows.
```

— sent from john's container running chip-fetcher v0.1.x against adom-desktop v1.4.10
