Skip to content

Commit 50ddc08

Browse files
committed
fix(sdk,demo): validate causal-read precondition; clarify embedded install path
- cypher() now raises ValueError client-side when after_index > 0 is combined with non-majority write_concern. The server rejects this combination; surfacing it earlier gives a clearer error and matches the documented contract. Unit coverage added. - Notebook ImportError message on missing coordinode-embedded now lists the explicit local install path (git+ pip install from the repo subdirectory, Rust toolchain note, ~5 min build) alongside the Colab install-cell hint and the server-mode escape hatch. - Notebook 00 markdown drops the hard-coded /tmp fallback phrasing; success print shows the runtime COORDINODE_EMBEDDED_PATH verbatim. - Notebook 01/02 comment block now accurately describes coordinode as git-pinned in Colab and unpinned outside, rather than claiming it is always unpinned.
1 parent ced47e8 commit 50ddc08

6 files changed

Lines changed: 44 additions & 11 deletions

File tree

coordinode/coordinode/client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,14 @@ async def cypher(
275275
ExecuteCypherRequest,
276276
)
277277

278+
# Causal reads (after_index > 0) are only satisfiable when writes were
279+
# acknowledged by a majority; otherwise the referenced index may never
280+
# replicate and the read would hang. Mirror the server's rejection.
281+
if after_index is not None and after_index > 0 and (write_concern or "").lower() != "majority":
282+
raise ValueError(
283+
"after_index > 0 requires write_concern='majority' — causal reads "
284+
"depend on majority-committed writes. Pass write_concern='majority'."
285+
)
278286
req = ExecuteCypherRequest(
279287
query=query,
280288
parameters=dict_to_props(params or {}),

demo/notebooks/00_seed_data.ipynb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"Populates CoordiNode with a **tech industry knowledge graph**.\n",
1313
"\n",
1414
"> **Note:** Embedded mode writes to `COORDINODE_EMBEDDED_PATH` (default\n",
15-
"> `/content/coordinode-demo.db` in Colab, `/tmp/coordinode-demo.db` locally), so\n",
15+
"> `/content/coordinode-demo.db` in Colab, the OS temp dir locally), so\n",
1616
"> the seeded graph persists across cell reruns and is visible to sibling demo\n",
1717
"> notebooks within the same runtime. Delete the file or set a different path to\n",
1818
"> reset. Connecting to a real CoordiNode server via `COORDINODE_ADDR` is also\n",
@@ -146,7 +146,7 @@
146146
"\n",
147147
"- **Colab**: uses `LocalClient(COORDINODE_EMBEDDED_PATH)` \u2014 in-process embedded engine backed by a file under `/content/`, no server required.\n",
148148
"- **Local with server**: set `COORDINODE_ADDR=host:port` to point at a running CoordiNode (no auto-probe \u2014 explicit only).\n",
149-
"- **Local without server**: uses `coordinode-embedded` (file-backed at `COORDINODE_EMBEDDED_PATH`, default `/tmp/coordinode-demo.db`). Raises `RuntimeError` with install instructions if the package is missing."
149+
"- **Local without server**: uses `coordinode-embedded` (file-backed at `COORDINODE_EMBEDDED_PATH`, defaulting to the OS temp dir). Raises `RuntimeError` with install instructions if the package is missing."
150150
]
151151
},
152152
{
@@ -186,7 +186,11 @@
186186
" except ImportError as exc:\n",
187187
" raise RuntimeError(\n",
188188
" \"coordinode-embedded is not installed. \"\n",
189-
" \"Run the install cell above, or start a CoordiNode server and set COORDINODE_ADDR.\"\n",
189+
" \"In Colab, rerun the install cell above. \"\n",
190+
" \"Locally, install from source: \"\n",
191+
" \"pip install 'git+https://github.com/structured-world/coordinode-python.git#subdirectory=coordinode-embedded' \"\n",
192+
" \"(requires Rust toolchain, ~5 min build). \"\n",
193+
" \"Alternatively start a CoordiNode server and set COORDINODE_ADDR.\"\n",
190194
" ) from exc\n",
191195
"\n",
192196
" client = LocalClient(COORDINODE_EMBEDDED_PATH)\n",
@@ -466,7 +470,7 @@
466470
"\n",
467471
"print(\"\\n\u2713 Demo data seeded.\")\n",
468472
"print(\"To query it from notebooks 01\u201303:\")\n",
469-
"print(\" - Embedded mode: open them with the same COORDINODE_EMBEDDED_PATH (default /content/coordinode-demo.db in Colab, /tmp/coordinode-demo.db locally) \u2014 they will see this seeded graph.\")\n",
473+
"print(f\" - Embedded mode: open them with the same COORDINODE_EMBEDDED_PATH (this run: {COORDINODE_EMBEDDED_PATH}) \u2014 they will see this seeded graph.\")\n",
470474
"print(\" - Server mode: point them at the same running CoordiNode via COORDINODE_ADDR.\")\n",
471475
"client.close()"
472476
]

demo/notebooks/01_llama_index_property_graph.ipynb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@
9999
"\n",
100100
"# coordinode-embedded is pinned to a specific git commit because it requires a Rust\n",
101101
"# build (maturin/pyo3) and the embedded engine must match the Python SDK version.\n",
102-
"# The remaining packages (coordinode, llama-index, etc.) are installed without pins:\n",
103-
"# they are pure Python, release frequently, and pip resolves a compatible version.\n",
102+
"# coordinode (SDK) is git-pinned in Colab via _coordinode_spec to keep the\n",
103+
"# SDK/proto in sync with this PR; outside Colab it resolves from PyPI.\n",
104+
"# Other packages (LangChain / llama-index / nest_asyncio) are unpinned \u2014 pure\n",
105+
"# Python, release frequently, pip resolves a compatible version.\n",
104106
"_coordinode_spec = (\n",
105107
" \"git+https://github.com/structured-world/coordinode-python.git@c2d62b0595867651df43c2b3d3fdbec4341d6642#subdirectory=coordinode\"\n",
106108
" if IN_COLAB\n",
@@ -220,7 +222,11 @@
220222
" except ImportError as exc:\n",
221223
" raise RuntimeError(\n",
222224
" \"coordinode-embedded is not installed. \"\n",
223-
" \"Run the install cell above, or start a CoordiNode server and set COORDINODE_ADDR.\"\n",
225+
" \"In Colab, rerun the install cell above. \"\n",
226+
" \"Locally, install from source: \"\n",
227+
" \"pip install 'git+https://github.com/structured-world/coordinode-python.git#subdirectory=coordinode-embedded' \"\n",
228+
" \"(requires Rust toolchain, ~5 min build). \"\n",
229+
" \"Alternatively start a CoordiNode server and set COORDINODE_ADDR.\"\n",
224230
" ) from exc\n",
225231
"\n",
226232
" _lc = LocalClient(COORDINODE_EMBEDDED_PATH)\n",

demo/notebooks/02_langchain_graph_chain.ipynb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@
9999
"# must match the Python SDK version.\n",
100100
"# - langchain-coordinode is pinned to the same commit so CoordinodeGraph(client=...)\n",
101101
"# is available; this parameter is not yet released to PyPI.\n",
102-
"# The remaining packages (coordinode, LangChain, etc.) are installed without pins:\n",
103-
"# they are pure Python, release frequently, and pip resolves a compatible version.\n",
102+
"# coordinode (SDK) is git-pinned in Colab via _coordinode_spec to keep the\n",
103+
"# SDK/proto in sync with this PR; outside Colab it resolves from PyPI.\n",
104+
"# Other packages (LangChain / llama-index / nest_asyncio) are unpinned \u2014 pure\n",
105+
"# Python, release frequently, pip resolves a compatible version.\n",
104106
"_coordinode_spec = (\n",
105107
" \"git+https://github.com/structured-world/coordinode-python.git@c2d62b0595867651df43c2b3d3fdbec4341d6642#subdirectory=coordinode\"\n",
106108
" if IN_COLAB\n",
@@ -221,7 +223,11 @@
221223
" except ImportError as exc:\n",
222224
" raise RuntimeError(\n",
223225
" \"coordinode-embedded is not installed. \"\n",
224-
" \"Run the install cell above, or start a CoordiNode server and set COORDINODE_ADDR.\"\n",
226+
" \"In Colab, rerun the install cell above. \"\n",
227+
" \"Locally, install from source: \"\n",
228+
" \"pip install 'git+https://github.com/structured-world/coordinode-python.git#subdirectory=coordinode-embedded' \"\n",
229+
" \"(requires Rust toolchain, ~5 min build). \"\n",
230+
" \"Alternatively start a CoordiNode server and set COORDINODE_ADDR.\"\n",
225231
" ) from exc\n",
226232
"\n",
227233
" _lc = LocalClient(COORDINODE_EMBEDDED_PATH)\n",

demo/notebooks/03_langgraph_agent.ipynb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,11 @@
174174
" except ImportError as exc:\n",
175175
" raise RuntimeError(\n",
176176
" \"coordinode-embedded is not installed. \"\n",
177-
" \"Run the install cell above, or start a CoordiNode server and set COORDINODE_ADDR.\"\n",
177+
" \"In Colab, rerun the install cell above. \"\n",
178+
" \"Locally, install from source: \"\n",
179+
" \"pip install 'git+https://github.com/structured-world/coordinode-python.git#subdirectory=coordinode-embedded' \"\n",
180+
" \"(requires Rust toolchain, ~5 min build). \"\n",
181+
" \"Alternatively start a CoordiNode server and set COORDINODE_ADDR.\"\n",
178182
" ) from exc\n",
179183
"\n",
180184
" client = LocalClient(COORDINODE_EMBEDDED_PATH)\n",

tests/integration/test_sdk.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,3 +728,8 @@ def test_cypher_rejects_invalid_consistency_values(client):
728728
client.cypher("RETURN 1", read_preference="leader")
729729
with pytest.raises(ValueError, match="after_index must be a non-negative integer"):
730730
client.cypher("RETURN 1", after_index=-1)
731+
# Causal reads (after_index > 0) require write_concern='majority'.
732+
with pytest.raises(ValueError, match="after_index > 0 requires write_concern='majority'"):
733+
client.cypher("RETURN 1", after_index=42)
734+
with pytest.raises(ValueError, match="after_index > 0 requires write_concern='majority'"):
735+
client.cypher("RETURN 1", after_index=42, write_concern="w1")

0 commit comments

Comments
 (0)