---
model: claude-fable-5[1m]
service: claude
timestamp: 2026-06-10T21:35:49Z
git_ref: datad_service
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T213549Z_f084e899_prompt_io.md
---

NOTE: diff-ref mode entry (code committed in the same
commit as this log); recorded from the live debug
session per the `/prompt-io` skill rules.

> `git log -1 -p --follow -- piker/brokers/ib/broker.py`
> `git log -1 -p --follow -- piker/brokers/ib/api.py`

Key diagnostic chain (from session):

- pdb showed `Client._contracts == {}` inside
  `brokerd.ib`'s `submit_limit()`; the cache has
  exactly TWO write sites: `Client.find_contracts()`
  (api.py, keys `f'{sym}.{exch}.ib'`) and
  `symbols.get_mkt_info()` (key `mkt.bs_fqme`, eg.
  'nvda.nasdaq' — NO `.ib` suffix).
- `BrokerdOrder.symbol` arrives as the bs_fqme form
  ('nvda.nasdaq') so ONLY the `get_mkt_info()` write
  site produces the key `submit_limit()` reads —
  ie. pre-split it was the feed's in-proc
  `get_mkt_info(sym, proxy=proxy)` call keeping orders
  working, NOT `find_contracts()`.
- the existing TODO at `symbols.py:642-644` literally
  predicted this: "this is going to be problematic
  if/when we split out the datad vs. brokerd actors
  since the mktmap lookup table will now be
  inaccessible.."
- instance identity verified: `proxy._aio_ns` IS the
  same `Client` obj as `_accounts2clients[account]`
  (both sourced from the `load_aio_clients()` cache via
  `open_client_proxies()`), so a brokerd-side
  `get_mkt_info(fqme, proxy=proxies[account])` warms
  exactly the dict `submit_limit()` reads. It also
  populates `client._cons2mkts` which the
  position-audit path (`broker.py` backup-table code)
  needs in this actor anyway.
- the `TrioTaskExited` storm in the user's log
  (`recv_trade_updates`, `open_aio_client_method_relay`
  aio tasks) is teardown cascade: the raise crashed
  `handle_order_requests` -> nursery teardown ripped
  the trio sides of still-running aio relay tasks.
  Hence the added per-order try/except ->
  `BrokerdError` relay hardening so a single bad
  submission degrades to an EMS error msg instead of
  killing the backend's entire order-ctl dialog.

Verification: `tests/test_services.py` (5 passed) +
`tests/test_ems.py` (6 passed) regression-green; live
`ib` submission retest delegated to the human (needs a
running TWS/gw).
