Repository navigation
fix(graph): get_neighbors may not leave its owner, and stop rescanning per hop - #188
Merged
Merged
Conversation
…g per hop `get_neighbors` returned a neighbour's content filtered by LAYER only — no user_id on the returned node, none on the start node. So the agent graph of one owner handed back text belonging to another: measured on the live bases, a depth-1 walk from a `default` node returned 14 rows owned by `test_hooks` in every one of the three, and a depth-2 walk in CowAgent returned 301. The owner is now taken from the start node itself, not from a new parameter — forgetting to pass one is exactly the defect being fixed. Every hop, not just the final row, must land inside `member` (same layer AND same user_id), so a foreign node cannot bridge two of the owner's nodes. A missing start node, or one in another layer, returns `[]` rather than raising: if the owner is unknown, nothing is returned. The first version of this fix was 6x slower at depth 2 on the largest user layer (0.22 s -> 1.30 s) because `IN (SELECT node_id FROM member)` was evaluated per hop. `member AS MATERIALIZED` joined on `target_id` brings that to 58.6 ms on Hermes depth 2 against 1105.8 ms for the `IN` form (identical row sets), and depth 3 from 27.2 s to 7.0 s. Without `MATERIALIZED` the join is inlined into the recursive step and re-scans `epi_nodes` — 4.7 s, worse than what it replaced — so the hint is load-bearing, not decoration. Depth 1 pays 3.6 ms for it. Only tests call this method today (`rag/multi_source.py` and `rag/edm.py` use their own SQL and already scope user_id on the returned node), so the leak was latent — but it is a public method and would have returned foreign content the first day anything called it.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Что
get_neighborsвозвращал содержимое соседа, фильтруя только по слою — ниuser_idна возвращаемом узле, ни на стартовом. Поэтому граф слояagentодного владельца отдавал текст другого.Замер на живых базах (read-only): depth-1 от узла
defaultвозвращал 14 строк, принадлежащихtest_hooks, во всех трёх базах; depth-2 в CowAgent — 301.Контракт
Владелец берётся из самого стартового узла, а не из нового параметра: забыть передать параметр — ровно тот дефект, который чиним.
member(тот же слой И тот жеuser_id) — чужой узел не может сработать мостом;[], без исключения: не знаем владельца — не отдаём ничего;depth,relation,tagработают как раньше.Оптимизация
Первая версия фикса была 6× медленнее на depth-2 в самом большом user-слое (0.22 с → 1.30 с):
IN (SELECT node_id FROM member)считался на каждом хопе.member AS MATERIALIZED+ JOIN поtarget_id:INJOIN + MATERIALIZEDНаборы строк идентичны (сверено хэшами). Без
MATERIALIZEDJOIN инлайнится в рекурсивный шаг и пересканируетepi_nodes— 4.7 с, хуже исходного. Подсказка несущая, не косметика. Depth-1 платит 3.6 мс.Про латентность
Сейчас метод зовут только тесты.
rag/multi_source.pyиrag/edm.pyделают свой SQL иuser_idна возвращаемом узле уже проверяют. То есть утечка латентная — но метод публичный, и он вернул бы чужое в первый же день, когда его позвали бы.Проверка
get_neighborsreturn another owner's content on any path? — NO»;depth=0, два владельца в одном слое — чужое не возвращается;