diff --git a/ai/prompt-io/opencode/20261019T123725Z_eed58566_logger_compat_prompt_io.md b/ai/prompt-io/opencode/20261019T123725Z_eed58566_logger_compat_prompt_io.md new file mode 100644 index 00000000..9d6f2b0f --- /dev/null +++ b/ai/prompt-io/opencode/20261019T123725Z_eed58566_logger_compat_prompt_io.md @@ -0,0 +1,51 @@ +--- +created_at: 2026-10-19T12:37:25Z +generated_by: + harness: opencode + provider: openai + model: openai/gpt-6.1-sol +git_ref: eed58566 +scope: code +substantive: true +raw_file: 20261019T123725Z_eed58566_logger_compat_prompt_io.raw.md +--- + +## Prompt + +During the requested downstream/manual IB evaluation, the user reported +immediate chart startup failure at the stale assertion +`assert log.name == 'piker.service'` in maybe_spawn_daemon(). +The user then asked why continuing the post-mortem debugger ended with +KeyboardInterrupt from the chart window's closeEvent(). + +## Response summary + +Located the existing downstream logger compatibility commit +c07e3cbde21807a4e193b3527ef8686a22cf4d96 and reproduced its code and +existing regression tests in the evaluation worktree, unstaged. +Preserved the earlier editable Tractor/dependency setup. +Explained that closeEvent() sends SIGINT during chart teardown, adding +a secondary KeyboardInterrupt after the original assertion unwinds. +No window-close behaviour was modified. + +## Files changed + +- piker/log.py: exact package-prefix removal in both logger factories. +- piker/service/_daemon.py: remove stale parent logger assertion. +- piker/data/_daemon.py: retain setup, remove assertion-only local. +- piker/brokers/_daemon.py: same broker startup compatibility fix. +- piker/clearing/_ems.py: same EMS startup compatibility fix. +- tests/test_logging.py: original four logger namespace regressions. + +## Verification + +- Logger regressions: four passed with --noconftest. +- Normal pytest collection blocked by duplicate --ll registration. +- Separate local TCP registrar smoke: pikerd/data daemon startup, + registration and teardown succeeded; no provider feed opened. +- Imports resolve to this evaluation worktree and the evaluated + Tractor logging worktree. + +## Human edits + +None observed in this compatibility patch at capture time. diff --git a/ai/prompt-io/opencode/20261019T123725Z_eed58566_logger_compat_prompt_io.raw.md b/ai/prompt-io/opencode/20261019T123725Z_eed58566_logger_compat_prompt_io.raw.md new file mode 100644 index 00000000..3fdeeef1 --- /dev/null +++ b/ai/prompt-io/opencode/20261019T123725Z_eed58566_logger_compat_prompt_io.raw.md @@ -0,0 +1,46 @@ +--- +created_at: 2026-10-19T12:37:25Z +generated_by: + harness: opencode + provider: openai + model: openai/gpt-6.1-sol +git_ref: eed58566 +diff_cmd: git diff HEAD -- piker/log.py piker/service/_daemon.py piker/data/_daemon.py piker/brokers/_daemon.py piker/clearing/_ems.py +--- + +## Captured response + +Found it: downstream `c07e3cbd` (“Preserve exact `piker` +logger namespaces”) removes this assertion and the equivalent +ones in data, broker and EMS startup. It also fixes the logger +prefix handling. + +That compatibility patch was present in our earlier evaluation +stack but is absent from this base. I’ll apply its code and +existing regression tests here as an unstaged patch. + +## Patch provenance + +The five production-file changes and tests/test_logging.py reproduce +the code/test changes from c07e3cbde21807a4e193b3527ef8686a22cf4d96. +This is a working-tree transplant, not a new commit or cherry-pick. +The test file's Git blob is 437554461de44833940b24d77a565160fc3ac6e0, +matching the original commit. piker/log.py matches that commit. + +## Verification output + +Logger tests with --noconftest: 4 passed in 0.36s. +Normal pytest startup failed before collection because both Piker and +modern Tractor register --ll. The logger tests use no project fixtures. +An external disposable-registrar smoke script exercised open_pikerd(), +maybe_spawn_datad('kraken'), registration and teardown successfully: +Data daemon startup: OK + +## Follow-up response + +Yep—the traceback shows the window’s `closeEvent()` explicitly +sending SIGINT to its own process, which raises `KeyboardInterrupt`. +Continuing a post-mortem REPL lets the original assertion unwind; +it doesn’t resume successful startup. The resulting window close +then adds that KBI. It’s secondary shutdown behaviour, and it +makes the original failure harder to read. diff --git a/piker/brokers/_daemon.py b/piker/brokers/_daemon.py index dafb3b81..8aa45f33 100644 --- a/piker/brokers/_daemon.py +++ b/piker/brokers/_daemon.py @@ -77,12 +77,11 @@ async def _setup_persistent_brokerd( # any further (level) configuration on their own B) actor: tractor.Actor = tractor.current_actor() tll: str = actor.loglevel - log = get_console_log( + get_console_log( level=loglevel or tll, name=f'{_util.subsys}.{brokername}', with_tractor_log=bool(tll), ) - assert log.name == _util.subsys # unblock caller await ctx.started() diff --git a/piker/clearing/_ems.py b/piker/clearing/_ems.py index 1d152926..4280dee0 100644 --- a/piker/clearing/_ems.py +++ b/piker/clearing/_ems.py @@ -810,11 +810,10 @@ async def _setup_persistent_emsd( ) -> None: if loglevel: - _log = get_console_log( + get_console_log( level=loglevel, name=subsys, ) - assert _log.name == 'piker.clearing' global _router diff --git a/piker/data/_daemon.py b/piker/data/_daemon.py index 116d1346..27f27a90 100644 --- a/piker/data/_daemon.py +++ b/piker/data/_daemon.py @@ -86,12 +86,11 @@ async def _setup_persistent_datad( # their own B) actor: tractor.Actor = tractor.current_actor() tll: str = actor.loglevel - log = get_console_log( + get_console_log( level=loglevel or tll, name=f'{_util.subsys}.{brokername}', with_tractor_log=bool(tll), ) - assert log.name == _util.subsys # XXX: ALSO enable console logging for the provider # backend's mod subtree (eg. `piker.brokers.ib.*`) diff --git a/piker/log.py b/piker/log.py index 0145debf..f5989fbf 100644 --- a/piker/log.py +++ b/piker/log.py @@ -36,6 +36,15 @@ from pygments import ( _proj_name: str = 'piker' +def _relative_name( + name: str|None, +) -> str|None: + if name: + return name.removeprefix(f'{_proj_name}.') + + return None + + def get_logger( name: str|None = None, **tractor_log_kwargs, @@ -47,17 +56,9 @@ def get_logger( See `tractor.log.get_logger()` for details. ''' - pkg_name: str = _proj_name - if ( - name - and - pkg_name in name - ): - name: str = name.lstrip(f'{_proj_name}.') - return tractor.log.get_logger( - name=name, - pkg_name=pkg_name, + name=_relative_name(name), + pkg_name=_proj_name, **tractor_log_kwargs, ) @@ -81,14 +82,6 @@ def get_console_log( You do it.. Bp ''' - pkg_name: str = _proj_name - if ( - name - and - pkg_name in name - ): - name: str = name.lstrip(f'{_proj_name}.') - tll: str|None = None if ( with_tractor_log is not False @@ -111,8 +104,8 @@ def get_console_log( return tractor.log.get_console_log( level=level, - name=name, - pkg_name=pkg_name, + name=_relative_name(name), + pkg_name=_proj_name, **tractor_log_kwargs, ) diff --git a/piker/service/_daemon.py b/piker/service/_daemon.py index e6e372df..d89bcaf2 100644 --- a/piker/service/_daemon.py +++ b/piker/service/_daemon.py @@ -72,7 +72,6 @@ async def maybe_spawn_daemon( level=loglevel, name=__name__, ) - assert log.name == 'piker.service' # serialize access to this section to avoid # 2 or more tasks racing to create a daemon diff --git a/tests/test_logging.py b/tests/test_logging.py new file mode 100644 index 00000000..43755446 --- /dev/null +++ b/tests/test_logging.py @@ -0,0 +1,44 @@ +''' +Package logger namespace regression tests. + +''' +import pytest + +from piker.log import ( + get_console_log, + get_logger, +) + + +@pytest.mark.parametrize( + 'factory', + [ + get_logger, + get_console_log, + ], +) +@pytest.mark.parametrize( + 'name', + [ + 'piker.service._daemon', + 'piker.paper', + ], +) +def test_package_logger_name( + factory, + name: str, +): + ''' + `str.lstrip('piker.')` treated the package prefix as a set of + removable characters. A submodule beginning with any of those + characters, such as `piker.paper`, was silently renamed to + `piker.aper`, while service code asserted a stale parent name. + + Exercise both logger factories with service and prefix-sensitive + submodule names, proving they retain the exact requested package + namespace. + + ''' + log = factory(name=name) + + assert log.name == name