Skip to content

fix: connected-node fast path drops valid neighbors (0.0.11)#25

Merged
eldonm merged 1 commit into
mainfrom
fix/connected-nodes-subtype-and-limit
Jul 2, 2026
Merged

fix: connected-node fast path drops valid neighbors (0.0.11)#25
eldonm merged 1 commit into
mainfrom
fix/connected-nodes-subtype-and-limit

Conversation

@eldonm

@eldonm eldonm commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

Fixes two regressions in the 0.0.10 single-hop find_connected_nodes fast path that made .node(node=T) / .nodes(node=T, limit=n) silently drop valid neighbors. Found via an end-to-end failure of the embedded jvagent agent in integral (agent turns died with no_memory then session_resolution_error); root-caused to graph traversal, not agent code.

Bug 1 — limit-before-filter. limit was pushed into the DB scan before the Python node-type filter, so nodes(node=T, limit=1) returned nothing when a non-matching neighbor sorted first, even though matching neighbors existed. (In integral: an agent with 20 Memory neighbors → node(node="Memory") returned Noneget_memory() failed.) Fix: push limit to the DB only when there is no node filter; otherwise apply after filtering.

Bug 2 — subtype resolution under an entity-name collision. The fast path deserialized every row with the base Node class, so when two Node subclasses persisted in one database share an entity name — e.g. an app User and an embedded-agent Userfind_subclass_by_name(Node, "User") returned the first global match and _matches_node_filter's isinstance check dropped the valid neighbor. (In integral: conversation.node(direction="in", node=User) returned None → the session looked "foreign".) Fix: hydrate using the caller's requested concrete type as the resolution hint.

Why the suite missed it

The stock JsonDB exposes no find_connected_nodes, so every existing test fell back to the slow edge-scan path and never exercised the fast path. The new test installs a find_connected_nodes shim.

Test plan

  • tests/core/test_connected_nodes_fast_path.py — 2 tests; both fail on 0.0.10, pass here.
  • Existing traversal/graph suite: green (61 passed locally).
  • Verified end-to-end: the integral embedded agent completes a full turn (reasoning + tool calls + answer) with this fix.

Bumps version to 0.0.11 + CHANGELOG.

🤖 Generated with Claude Code

The 0.0.10 single-hop find_connected_nodes fast path had two regressions,
both invisible to the suite because JsonDB exposes no find_connected_nodes
(tests fell back to the slow edge scan):

1. Limit-before-filter: `limit` was pushed to the DB scan before the Python
   node-type filter, so node(node=T) / nodes(node=T, limit=n) could return
   nothing when a non-matching neighbor sorted first. Push `limit` to the DB
   only when there is no node filter; otherwise apply it after filtering.

2. Subtype resolution under an entity-name collision: rows were deserialized
   with the base Node class, so when two Node subclasses in one database share
   an entity name (e.g. an app User and an embedded-agent User),
   find_subclass_by_name returned the first global match and isinstance-based
   filtering dropped the valid neighbor. Deserialize using the caller's
   requested concrete type as the resolution hint.

Adds tests/core/test_connected_nodes_fast_path.py, which installs a
find_connected_nodes shim so the fast path is actually exercised; both tests
fail on 0.0.10 and pass here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Benchmark comparison

Threshold: ±25% (informational, does not block merge)

benchmark baseline (s) current (s) delta status
tests/benchmarks/test_deferred_save_benchmarks.py::test_bench_deferred_save_batched_100 0.037416 0.045561 +21.8% OK
tests/benchmarks/test_deferred_save_benchmarks.py::test_bench_immediate_save_100 0.037331 0.046178 +23.7% OK
tests/benchmarks/test_jsondb_benchmarks.py::test_bench_jsondb_batched_saves_500 0.373731 0.610958 +63.5% REGRESSION (+63.5%)
tests/benchmarks/test_jsondb_benchmarks.py::test_bench_jsondb_count_empty_query 0.799700 1.256767 +57.2% REGRESSION (+57.2%)
tests/benchmarks/test_jsondb_benchmarks.py::test_bench_jsondb_count_filtered 0.921327 1.216108 +32.0% REGRESSION (+32.0%)
tests/benchmarks/test_jsondb_benchmarks.py::test_bench_jsondb_find_filtered 0.705985 0.898894 +27.3% REGRESSION (+27.3%)
tests/benchmarks/test_jsondb_benchmarks.py::test_bench_jsondb_save_throughput 0.001366 0.001868 +36.7% REGRESSION (+36.7%)
tests/benchmarks/test_sqlite_benchmarks.py::test_bench_sqlite_count_empty 0.244740 0.312800 +27.8% REGRESSION (+27.8%)
tests/benchmarks/test_sqlite_benchmarks.py::test_bench_sqlite_count_fallback_via_regex 0.330283 0.389930 +18.1% OK
tests/benchmarks/test_sqlite_benchmarks.py::test_bench_sqlite_count_pushdown 0.273784 0.369238 +34.9% REGRESSION (+34.9%)
tests/benchmarks/test_sqlite_benchmarks.py::test_bench_sqlite_find_fallback_via_regex 0.289234 0.385192 +33.2% REGRESSION (+33.2%)
tests/benchmarks/test_sqlite_benchmarks.py::test_bench_sqlite_find_pushdown 0.242726 0.328375 +35.3% REGRESSION (+35.3%)
tests/benchmarks/test_sqlite_benchmarks.py::test_bench_sqlite_sort_limit_pushdown 0.294411 0.359027 +21.9% OK

@eldonm eldonm self-assigned this Jul 2, 2026
@eldonm eldonm merged commit 3c71445 into main Jul 2, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant