From 119d2c049556f240e6b457d08c5c6d564ece011e Mon Sep 17 00:00:00 2001 From: goodboy Date: Wed, 10 Jun 2026 13:11:42 -0400 Subject: [PATCH] Declare per-daemon-kind backend mod groups Prep for the `brokerd` -> (`datad` + `brokerd`) actor split by having each (split-style) backend declare which of its submods host which daemon-kind's eps, exactly per the `piker.data.validate._eps` groupings; `ib` already had `_brokerd_mods`/`_datad_mods` so extend the convention to `kraken`, `binance` and `deribit` (and add `'api'` to ib's datad set since both kinds need the `Client` layer). `__enable_modules__` stays as the (deduped) union so this is a ZERO behavior change; flat backends (`kucoin` etc.) just don't declare the split yet. Also, - add `validate.get_eps()` returning a backend's defined eps per daemon-kind for spawn-time introspection. - import `NoBsWs`/`open_autorecon_ws` from `piker.data._web_bs` directly in `.kraken.broker` (they were only re-exported via `.kraken.feed`) so the trading mod doesn't depend on the feed mod for ws primitives. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code Co-Authored-By: Claude Fable 5 Prompt-IO: ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md --- .../20260610T171105Z_bc6e18d7_prompt_io.md | 54 +++++++++++++++++++ ...20260610T171105Z_bc6e18d7_prompt_io.raw.md | 46 ++++++++++++++++ piker/brokers/binance/__init__.py | 22 ++++++-- piker/brokers/deribit/__init__.py | 18 +++++-- piker/brokers/ib/__init__.py | 5 +- piker/brokers/kraken/__init__.py | 18 ++++++- piker/brokers/kraken/broker.py | 6 ++- piker/data/validate.py | 18 +++++++ 8 files changed, 175 insertions(+), 12 deletions(-) create mode 100644 ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md create mode 100644 ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.raw.md diff --git a/ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md b/ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md new file mode 100644 index 00000000..a76f24db --- /dev/null +++ b/ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md @@ -0,0 +1,54 @@ +--- +model: claude-fable-5[1m] +service: claude +session: 32d15f9a-b2d3-4c26-bdc9-190219141a25 +timestamp: 2026-06-10T17:11:05Z +git_ref: datad_service +diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md +scope: code +substantive: true +raw_file: 20260610T171105Z_bc6e18d7_prompt_io.raw.md +--- + +## Prompt + +Same session-initiating `brokerd`-split instruction (see +`20260610T170859Z_75cefe10_prompt_io.md`); this is the +approved plan's "stage 0" prep. Plan-shaping user +decisions captured via in-session Q&A: + +- `datad.` topology: sibling of + `brokerd.` under `pikerd` (vs. child + subactor). +- migration: hard cutover, staged by layer (no + dual-mode runtime flag). +- post-split `brokerd` scope: trading-only + + EMS-lazy-spawned (charts/CLI never touch it). + +## Response summary + +Declare per-daemon-kind backend submod groups +(`_datad_mods`/`_brokerd_mods`) in the split-style +backends, keyed to the pre-existing +`piker.data.validate._eps` contract; add a +`validate.get_eps()` introspection helper; ws-import +hygiene in `.kraken.broker`. Zero behavior change +(`__enable_modules__` unions unchanged). + +## Files changed + +- `piker/data/validate.py` — add `get_eps()` +- `piker/brokers/kraken/__init__.py` — mod groups +- `piker/brokers/binance/__init__.py` — mod groups + (note: no `symbols.py`; search eps live in `.feed`) +- `piker/brokers/deribit/__init__.py` — datad-only + groups (no `broker.py` yet) +- `piker/brokers/ib/__init__.py` — add `'api'` to the + pre-existing `_datad_mods` +- `piker/brokers/kraken/broker.py` — import + `NoBsWs`/`open_autorecon_ws` from + `piker.data._web_bs` directly + +## Human edits + +None — committed as generated. diff --git a/ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.raw.md b/ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.raw.md new file mode 100644 index 00000000..1ce080c9 --- /dev/null +++ b/ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.raw.md @@ -0,0 +1,46 @@ +--- +model: claude-fable-5[1m] +service: claude +timestamp: 2026-06-10T17:11:05Z +git_ref: datad_service +diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T171105Z_bc6e18d7_prompt_io.md +--- + +NOTE: diff-ref mode entry (code committed in the same +commit as this log); backfilled from the live dev +session transcript per the `/prompt-io` skill rules. + +> `git log -1 -p --follow -- piker/data/validate.py` + +Generated: `get_eps(mod, kind) -> dict[str, Callable]` +returning the daemon-kind's ep funcs defined by a +backend mod, keyed by ep name, missing eps excluded; +sourced from the existing `_eps` grouping table +(`'middleware' | 'datad' | 'brokerd'`). + +> `git log -1 -p --follow -- piker/brokers/kraken/__init__.py` +> `git log -1 -p --follow -- piker/brokers/binance/__init__.py` +> `git log -1 -p --follow -- piker/brokers/deribit/__init__.py` +> `git log -1 -p --follow -- piker/brokers/ib/__init__.py` +> `git log -1 -p --follow -- piker/brokers/kraken/broker.py` + +Key exploration findings driving the design (from the +planning phase, 3 parallel explore agents + 1 architect +agent): + +- the codebase already anticipated this split: + `validate._eps` groups eps into 'datad' vs 'brokerd' + kinds and `ib/__init__.py` already declared + `_brokerd_mods`/`_datad_mods`; `brokers/_daemon.py` + carried the literal TODO "rename the daemon to datad + prolly once we split up broker vs. data tasks into + separate actors?". +- the feared kraken feed<->broker "shared ws state" + hazard is mild: `NoBsWs`/`open_autorecon_ws` + originate in `piker.data._web_bs` (re-exported via + `.kraken.feed`); only `stream_messages` is feed-local + and it's a pure parser — in-process imports only, + each actor opens its own ws conn. +- `enable_modules` gates RPC entry, NOT python imports, + so backend trading mods may keep importing feed-side + helpers in-process post-split. diff --git a/piker/brokers/binance/__init__.py b/piker/brokers/binance/__init__.py index 830b1acf..75c50916 100644 --- a/piker/brokers/binance/__init__.py +++ b/piker/brokers/binance/__init__.py @@ -52,9 +52,25 @@ __all__ = [ ] -# `brokerd` modules -__enable_modules__: list[str] = [ +# per-daemon-kind (sub)mod groups: declares which of our +# submods host the eps run by each daemon-actor kind as +# defined by `piker.data.validate._eps`. +# NOTE: `get_mkt_info` and `open_symbol_search` both live +# in `.feed` for this backend (no `symbols.py`). +_brokerd_mods: list[str] = [ 'api', - 'feed', 'broker', ] + +_datad_mods: list[str] = [ + 'api', + 'feed', +] + + +# tractor RPC enable arg +__enable_modules__: list[str] = list(dict.fromkeys( + _brokerd_mods + + + _datad_mods +)) diff --git a/piker/brokers/deribit/__init__.py b/piker/brokers/deribit/__init__.py index 4c0c1850..6e1a4c80 100644 --- a/piker/brokers/deribit/__init__.py +++ b/piker/brokers/deribit/__init__.py @@ -47,13 +47,25 @@ __all__ = [ ] -# tractor RPC enable arg -__enable_modules__: list[str] = [ +# per-daemon-kind (sub)mod groups: declares which of our +# submods host the eps run by each daemon-actor kind as +# defined by `piker.data.validate._eps`. +# NOTE: datad-only backend (no `broker.py` yet)! +_brokerd_mods: list[str] = [] + +_datad_mods: list[str] = [ 'api', 'feed', -# 'broker', ] + +# tractor RPC enable arg +__enable_modules__: list[str] = list(dict.fromkeys( + _brokerd_mods + + + _datad_mods +)) + # passed to ``tractor.ActorNursery.start_actor()`` _spawn_kwargs = { 'infect_asyncio': True, diff --git a/piker/brokers/ib/__init__.py b/piker/brokers/ib/__init__.py index e07ad482..e9f73b70 100644 --- a/piker/brokers/ib/__init__.py +++ b/piker/brokers/ib/__init__.py @@ -65,17 +65,18 @@ _brokerd_mods: list[str] = [ ] _datad_mods: list[str] = [ + 'api', 'feed', 'symbols', ] # tractor RPC enable arg -__enable_modules__: list[str] = ( +__enable_modules__: list[str] = list(dict.fromkeys( _brokerd_mods + _datad_mods -) +)) # passed to ``tractor.ActorNursery.start_actor()`` _spawn_kwargs = { diff --git a/piker/brokers/kraken/__init__.py b/piker/brokers/kraken/__init__.py index 1f5bc876..7254958a 100644 --- a/piker/brokers/kraken/__init__.py +++ b/piker/brokers/kraken/__init__.py @@ -66,10 +66,24 @@ __all__ = [ ] -# tractor RPC enable arg -__enable_modules__: list[str] = [ +# per-daemon-kind (sub)mod groups: declares which of our +# submods host the eps run by each daemon-actor kind as +# defined by `piker.data.validate._eps`. +_brokerd_mods: list[str] = [ 'api', 'broker', +] + +_datad_mods: list[str] = [ + 'api', 'feed', 'symbols', ] + + +# tractor RPC enable arg +__enable_modules__: list[str] = list(dict.fromkeys( + _brokerd_mods + + + _datad_mods +)) diff --git a/piker/brokers/kraken/broker.py b/piker/brokers/kraken/broker.py index 521dbdc6..92709d78 100644 --- a/piker/brokers/kraken/broker.py +++ b/piker/brokers/kraken/broker.py @@ -73,10 +73,12 @@ from piker.log import ( get_logger, ) from piker.data import open_symcache -from . import api -from .feed import ( +from piker.data._web_bs import ( open_autorecon_ws, NoBsWs, +) +from . import api +from .feed import ( stream_messages, ) from .ledger import ( diff --git a/piker/data/validate.py b/piker/data/validate.py index 38bd4086..f460bd71 100644 --- a/piker/data/validate.py +++ b/piker/data/validate.py @@ -91,6 +91,24 @@ _eps: dict[str, list[str]] = { } +def get_eps( + mod: ModuleType, + kind: str, # 'middleware' | 'datad' | 'brokerd' + +) -> dict[str, Callable]: + ''' + Return the daemon-kind's ep funcs defined by the backend + `mod`, keyed by ep name; any eps from `_eps[kind]` not + implemented by the backend are excluded. + + ''' + return { + name: ep + for name in _eps[kind] + if (ep := getattr(mod, name, None)) + } + + def validate_backend( mod: ModuleType, syms: list[str],