← Commit history
dev-skills/developing-the-bridge/SKILL.md+28@@ -320,3 +320,31 @@ which thread announced what, and whether AD actually rendered it. **Do NOT force-minimize what the browser intends to surface.** Background stays the default when a genuinely new window IS created (verify `minimized:true`); when it cannot be honored, announce instead of wrestling the window manager.++## ⭐ Caller provenance: WHO asked (AD 1.9.180+, wiki #345/#351)+AD stamps `X-Adom-Caller-Thread` / `-Container` / `-Reason` on every relayed request. **Self-asserted:+attribution, logging, UX, arbitration hints - NEVER authorization.** What this bridge does with it:+1. **Log it** - `logActivity` stamps the calling thread on every entry (`nbrowser_activity` returns+ `caller`, filterable with `callerThread`).+2. **Forward it** on every AD callback made while carrying out that thread's verb, plus+ `X-Adom-Caller-Delegate: native-browser`, so AD shows `chip-fetcher tab 3 (via native-browser)`.+ Self-initiated work (timers, sweeps, reapers) sends `native-browser bridge (self)` instead - never a+ stale identity.+3. **Arbitrate** - `sessionCaller` records the owning thread; a DIFFERENT thread driving that session+ gets `_concurrentAgents` naming the owner (warn, never refuse; destructive cross-thread ops were+ already refused).+4. **Label the window** - `desktop_set_window_identity {appId:'Adom.NativeBrowser', displayName:+ 'Adom · <thread> · <purpose>'}` so a glance at the taskbar says which conversation owns which window.++**Three traps this cost me, all invisible until tested end-to-end:**+- **`args.caller` is RESERVED.** AD/the CLI inject the identity there on EVERY call. I used `args.caller`+ as an activity FILTER and silently emptied the trail (8 logged, 0 returned). Use your own arg name.+- **AsyncLocalStorage does NOT survive the socket reply path.** Verbs resolve through the extension's+ `pending` map, outside the HTTP request's async scope, so ALS is empty in `onHostFrame` - every badge+ paint and window-identity call from there would forward "self". Capture the caller INTO the pending+ record and `callerCtx.run(...)` around the reply handler.+- **A var set in `dispatch` is not visible in `onHostFrame`.** They are different functions; carry+ cross-cutting state (the arbitration warning) on the pending record too.+- **And the standing one:** widening what you LOG means nothing if the query PROJECTION drops the field.+ I have now hit that exact bug three times (`hwnd`/`ops`, then `caller`). Update the projection in the+ same commit as the log field.