Summary
grapharc.observe re-exports most of its public surface from grapharc/observe/__init__.py, but two functions that grapharc/observe/cost.py defines and documents are missing from it: by_node and tokens_by_model. Callers have to reach past the package and import from the submodule directly.
Why this matters
Reading a run afterwards is half of what makes graph engineering auditable rather than hopeful — if a function that answers "which node spent this?" is only reachable by knowing the submodule path, people stop asking the question. attribute and attribute_thread are already exported; these two belong beside them.
Where in the code
grapharc/observe/__init__.py — the from grapharc.observe.cost import (...) block and __all__
grapharc/observe/cost.py — where by_node and tokens_by_model are defined
Confirm the gap:
grep -n "by_node\|tokens_by_model" grapharc/observe/__init__.py # currently no hits
grep -n "^def by_node\|^def tokens_by_model" grapharc/observe/cost.py
What to change
- Add
by_node and tokens_by_model to the import block in grapharc/observe/__init__.py.
- Add both names to
__all__, keeping the list's existing alphabetical grouping.
- Add a short test asserting they are importable from the package root, so the gap cannot reopen.
How to verify
./.venv/bin/python -c "from grapharc.observe import by_node, tokens_by_model; print('ok')"
uv run pytest tests/test_replay.py -q
uv run ruff check .
Acceptance criteria
Skill level — good first issue
A genuinely small, self-contained change: two lines of imports, two __all__ entries, and one test. It is a good way to see how this repo expects every change to arrive with a test that would fail without it. Ask here if anything is unclear and someone will help you through it.
Summary
grapharc.observere-exports most of its public surface fromgrapharc/observe/__init__.py, but two functions thatgrapharc/observe/cost.pydefines and documents are missing from it:by_nodeandtokens_by_model. Callers have to reach past the package and import from the submodule directly.Why this matters
Reading a run afterwards is half of what makes graph engineering auditable rather than hopeful — if a function that answers "which node spent this?" is only reachable by knowing the submodule path, people stop asking the question.
attributeandattribute_threadare already exported; these two belong beside them.Where in the code
grapharc/observe/__init__.py— thefrom grapharc.observe.cost import (...)block and__all__grapharc/observe/cost.py— whereby_nodeandtokens_by_modelare definedConfirm the gap:
What to change
by_nodeandtokens_by_modelto the import block ingrapharc/observe/__init__.py.__all__, keeping the list's existing alphabetical grouping.How to verify
Acceptance criteria
from grapharc.observe import by_node, tokens_by_modelworks__all__uv run pyteststays green anduv run ruff check .is cleanSkill level — good first issue
A genuinely small, self-contained change: two lines of imports, two
__all__entries, and one test. It is a good way to see how this repo expects every change to arrive with a test that would fail without it. Ask here if anything is unclear and someone will help you through it.