Fix `pytest` config-dir isolation in subactors
The old (commented-out) `get_app_dir()` override gated on `'pytest' in sys.modules` which can NEVER work in spawned subactors (fresh procs, no pytest import); as a result test `paperboi`/daemon actors were writing into the user's REAL `~/.config/piker/accounting/` files.. friggin yikes. Deats, - add `config._maybe_use_test_dir()` which lazily (at conf-path access time, NOT import time) reads the `piker_test_dir` entry from `tractor.runtime._state._runtime_vars['piker_vars']` as pre-loaded by `open_piker_runtime()` from the `tests.conftest._open_test_pikerd()` overrides. - hook it in `get_conf_dir()` and route `get_conf_path()` + `load()`'s mkdir through `get_conf_dir()`. - route `.accounting._ledger` / `._pos` dir derivation through `config.get_conf_dir()` (was reading the `_config_dir` global directly, bypassing the override); also `mkdir(parents=True, exist_ok=True)` for nested tmp-dir creation. (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 <noreply@anthropic.com> Prompt-IO: ai/prompt-io/claude/20260610T170859Z_75cefe10_prompt_io.mddatad_service
parent
75cefe10f1
commit
4485f2b9ce
|
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
model: claude-fable-5[1m]
|
||||||
|
service: claude
|
||||||
|
session: 32d15f9a-b2d3-4c26-bdc9-190219141a25
|
||||||
|
timestamp: 2026-06-10T17:08:59Z
|
||||||
|
git_ref: datad_service
|
||||||
|
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T170859Z_75cefe10_prompt_io.md
|
||||||
|
scope: code
|
||||||
|
substantive: true
|
||||||
|
raw_file: 20260610T170859Z_75cefe10_prompt_io.raw.md
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
Session-initiating instruction (driving all 7 commits in
|
||||||
|
this series):
|
||||||
|
|
||||||
|
> ok i want you to become the distributed runtime and
|
||||||
|
> concurrency expert for this project - namely acquire
|
||||||
|
> a deep understanding of tractor and how it's used.
|
||||||
|
> then i want you to attempt to factor our current
|
||||||
|
> brokerd service daemon into 2 daemons: a brokerd
|
||||||
|
> which only hosts live/paper trading endpoint tasks
|
||||||
|
> [..] a new `datad` subdaemon which in a separate
|
||||||
|
> subactor serves all the data feed service tasks [..]
|
||||||
|
> give me a mega detailed plan on how to approach this,
|
||||||
|
> and a staged approach for the implementation.
|
||||||
|
|
||||||
|
Proximate driver for THIS commit: during the approved
|
||||||
|
plan's stage-0 test gate the agent discovered test
|
||||||
|
subactors were writing into the user's REAL
|
||||||
|
`~/.config/piker/accounting/` files (a bogus paper fill
|
||||||
|
landed in `account.kraken.paper.toml`) because the old
|
||||||
|
test-dir override in `config.get_app_dir()` was
|
||||||
|
commented out and could never work in spawned
|
||||||
|
subactors anyway. Fix applied autonomously under the
|
||||||
|
approved plan; no explicit per-fix user prompt.
|
||||||
|
|
||||||
|
## Response summary
|
||||||
|
|
||||||
|
Restore `pytest` config-dir isolation by resolving the
|
||||||
|
per-test tmp dir lazily (at conf-path access time) from
|
||||||
|
`tractor` runtime-vars, which propagate down the actor
|
||||||
|
tree; route all conf-path derivation through
|
||||||
|
`config.get_conf_dir()` so the override is effective in
|
||||||
|
every (sub)actor.
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `piker/config.py` — add `_maybe_use_test_dir()`;
|
||||||
|
hook in `get_conf_dir()`; route `get_conf_path()` +
|
||||||
|
`load()` mkdir through it
|
||||||
|
- `piker/accounting/_ledger.py` — derive ledger dir
|
||||||
|
via `config.get_conf_dir()` (not the global)
|
||||||
|
- `piker/accounting/_pos.py` — same for account files
|
||||||
|
|
||||||
|
## Human edits
|
||||||
|
|
||||||
|
None — committed as generated.
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
model: claude-fable-5[1m]
|
||||||
|
service: claude
|
||||||
|
timestamp: 2026-06-10T17:08:59Z
|
||||||
|
git_ref: datad_service
|
||||||
|
diff_cmd: git log -1 -p --follow -- ai/prompt-io/claude/20260610T170859Z_75cefe10_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/config.py`
|
||||||
|
|
||||||
|
Generated: `config._maybe_use_test_dir()` — lazily
|
||||||
|
reads `piker_test_dir` from
|
||||||
|
`tractor.runtime._state._runtime_vars['piker_vars']`
|
||||||
|
(pre-loaded by `open_piker_runtime()` from the
|
||||||
|
`tests.conftest._open_test_pikerd()` overrides) and
|
||||||
|
calls `_override_config_dir()` when set. Hooked at the
|
||||||
|
top of `get_conf_dir()`; `get_conf_path()` and
|
||||||
|
`load()`'s dir-creation rerouted through
|
||||||
|
`get_conf_dir()`.
|
||||||
|
|
||||||
|
> `git log -1 -p --follow -- piker/accounting/_ledger.py`
|
||||||
|
> `git log -1 -p --follow -- piker/accounting/_pos.py`
|
||||||
|
|
||||||
|
Generated: ledger/account dir derivation switched from
|
||||||
|
the `config._config_dir` module global to
|
||||||
|
`config.get_conf_dir()` + `mkdir(parents=True,
|
||||||
|
exist_ok=True)` for nested tmp-dir creation.
|
||||||
|
|
||||||
|
Key diagnostic reasoning (verbatim from session):
|
||||||
|
|
||||||
|
The old (commented-out) `get_app_dir()` override gated
|
||||||
|
on `'pytest' in sys.modules` which can NEVER work in
|
||||||
|
spawned subactors (fresh procs, no pytest import); as
|
||||||
|
a result test `paperboi`/daemon actors were writing
|
||||||
|
into the user's REAL `~/.config/piker/accounting/`
|
||||||
|
files. Evidence: `account.kraken.paper.toml` gained a
|
||||||
|
single 0.001 xbtusdt clear stamped 2026-06-09T18:47Z
|
||||||
|
(a test fill), and `trades_kraken_paper.toml` (252B)
|
||||||
|
contained only that fill. The resolution must be
|
||||||
|
checked lazily at config-path access time (NOT import
|
||||||
|
time) since sub-actors only receive runtime-vars once
|
||||||
|
their `tractor` runtime has fully booted.
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
# AI Prompt I/O Log — claude
|
||||||
|
|
||||||
|
This directory tracks prompt inputs and model
|
||||||
|
outputs for AI-assisted development using
|
||||||
|
`claude` (claude-code CLI).
|
||||||
|
|
||||||
|
## Policy
|
||||||
|
|
||||||
|
Prompt logging follows the
|
||||||
|
[NLNet generative AI policy][nlnet-ai].
|
||||||
|
All substantive AI contributions are logged
|
||||||
|
with:
|
||||||
|
- Model name and version
|
||||||
|
- Timestamps
|
||||||
|
- The prompts that produced the output
|
||||||
|
- Unedited model output (`.raw.md` files)
|
||||||
|
|
||||||
|
[nlnet-ai]: https://nlnet.nl/foundation/policies/generativeAI/
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Entries are created by the `/prompt-io` skill
|
||||||
|
or automatically via `/commit-msg` integration.
|
||||||
|
|
||||||
|
Each commit carrying AI-generated changes links
|
||||||
|
to its provenance entry via a `Prompt-IO:`
|
||||||
|
commit-msg trailer; entries use "diff-ref mode"
|
||||||
|
(pointers into `git log -p` instead of verbatim
|
||||||
|
code copies) to avoid duplicating committed
|
||||||
|
code.
|
||||||
|
|
||||||
|
Human contributors remain accountable for all
|
||||||
|
code decisions. AI-generated content is never
|
||||||
|
presented as human-authored work.
|
||||||
|
|
@ -324,10 +324,13 @@ def load_ledger(
|
||||||
ldir: Path = (
|
ldir: Path = (
|
||||||
dirpath
|
dirpath
|
||||||
or
|
or
|
||||||
config._config_dir / 'accounting' / 'ledgers'
|
config.get_conf_dir() / 'accounting' / 'ledgers'
|
||||||
)
|
)
|
||||||
if not ldir.is_dir():
|
if not ldir.is_dir():
|
||||||
ldir.mkdir()
|
ldir.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
|
||||||
fname = f'trades_{brokername}_{acctid}.toml'
|
fname = f'trades_{brokername}_{acctid}.toml'
|
||||||
fpath: Path = ldir / fname
|
fpath: Path = ldir / fname
|
||||||
|
|
|
||||||
|
|
@ -785,9 +785,16 @@ def load_account(
|
||||||
legacy_fn: str = f'pps.{brokername}.{acctid}.toml'
|
legacy_fn: str = f'pps.{brokername}.{acctid}.toml'
|
||||||
fn: str = f'account.{brokername}.{acctid}.toml'
|
fn: str = f'account.{brokername}.{acctid}.toml'
|
||||||
|
|
||||||
dirpath: Path = dirpath or (config._config_dir / 'accounting')
|
dirpath: Path = (
|
||||||
|
dirpath
|
||||||
|
or
|
||||||
|
(config.get_conf_dir() / 'accounting')
|
||||||
|
)
|
||||||
if not dirpath.is_dir():
|
if not dirpath.is_dir():
|
||||||
dirpath.mkdir()
|
dirpath.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
|
||||||
conf, path = config.load(
|
conf, path = config.load(
|
||||||
path=dirpath / fn,
|
path=dirpath / fn,
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,48 @@ def _override_config_dir(
|
||||||
_config_dir = path
|
_config_dir = path
|
||||||
|
|
||||||
|
|
||||||
|
def _maybe_use_test_dir() -> None:
|
||||||
|
'''
|
||||||
|
When running under the `pytest` harness, override
|
||||||
|
the config dir to the per-test-tmp dir "passed down"
|
||||||
|
the actor tree via `tractor`'s runtime-vars
|
||||||
|
inheritance mechanism.
|
||||||
|
|
||||||
|
See the `tractor_runtime_overrides` usage in our
|
||||||
|
`tests.conftest._open_test_pikerd()` as well as
|
||||||
|
`.service._actor_runtime.open_piker_runtime()` for
|
||||||
|
the root-actor's pre-loading of the var state.
|
||||||
|
|
||||||
|
NOTE: this must be checked lazily at config-path
|
||||||
|
access time (NOT import time) since sub-actors only
|
||||||
|
receive runtime-vars once their `tractor` runtime
|
||||||
|
has fully booted.
|
||||||
|
|
||||||
|
'''
|
||||||
|
global _config_dir
|
||||||
|
import tractor
|
||||||
|
actor = tractor.current_actor(
|
||||||
|
err_on_no_runtime=False,
|
||||||
|
)
|
||||||
|
if actor is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
rvs: dict = tractor.runtime._state._runtime_vars
|
||||||
|
pvars: dict|None = rvs.get('piker_vars')
|
||||||
|
if (
|
||||||
|
pvars
|
||||||
|
and
|
||||||
|
(testdir := pvars.get('piker_test_dir'))
|
||||||
|
):
|
||||||
|
testdirpath = Path(testdir)
|
||||||
|
assert testdirpath.exists(), (
|
||||||
|
f'piker test harness might be borked!?\n'
|
||||||
|
f'testdirpath: {testdirpath!r}\n'
|
||||||
|
)
|
||||||
|
if _config_dir != testdirpath:
|
||||||
|
_override_config_dir(testdirpath)
|
||||||
|
|
||||||
|
|
||||||
def _conf_fn_w_ext(
|
def _conf_fn_w_ext(
|
||||||
name: str,
|
name: str,
|
||||||
) -> str:
|
) -> str:
|
||||||
|
|
@ -201,6 +243,7 @@ def get_conf_dir() -> Path:
|
||||||
on the local filesystem.
|
on the local filesystem.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
_maybe_use_test_dir()
|
||||||
return _config_dir
|
return _config_dir
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -226,7 +269,7 @@ def get_conf_path(
|
||||||
assert str(conf_name) in _conf_names
|
assert str(conf_name) in _conf_names
|
||||||
|
|
||||||
fn = _conf_fn_w_ext(conf_name)
|
fn = _conf_fn_w_ext(conf_name)
|
||||||
return _config_dir / Path(fn)
|
return get_conf_dir() / Path(fn)
|
||||||
|
|
||||||
|
|
||||||
def repodir() -> Path:
|
def repodir() -> Path:
|
||||||
|
|
@ -271,8 +314,9 @@ def load(
|
||||||
|
|
||||||
'''
|
'''
|
||||||
# create the $HOME/.config/piker dir if dne
|
# create the $HOME/.config/piker dir if dne
|
||||||
if not _config_dir.is_dir():
|
conf_dir: Path = get_conf_dir()
|
||||||
_config_dir.mkdir(
|
if not conf_dir.is_dir():
|
||||||
|
conf_dir.mkdir(
|
||||||
parents=True,
|
parents=True,
|
||||||
exist_ok=True,
|
exist_ok=True,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue