Release/2.3.3#23
Merged
Merged
Conversation
Write/ingest hot-path audit (companion to #11/#12/#13): per-COMMIT full index rebuild (#15), refresh_executor RecordStore mmap clone per write (#16), RelationshipIndex nested-lock deadlock hazard (#17), swallowed relationship-index add error (#18), WAL channel blocking send (#19), hub chain-walk warn timing (#20), per-write indexed-property loop (#21), CALL IN TRANSACTIONS single-tx OOM guard (#22). Plus #14 (UNWIND+MATCH+MERGE edge upsert) already tasked.
…index commit contract guard Investigated removing the per-COMMIT rebuild_indexes_from_storage (#15): it is load-bearing because the explicit-transaction CREATE path does not synchronously maintain the typed property index (find_exact/NodeIndexSeek), so removal makes seeks miss explicit-tx-committed nodes. Kept the rebuild; documented the constraint inline. Added a contract-guard test a future incremental fix must keep green. Issue #15 stays open.
create_relationship no longer silently swallows a relationship-index update failure: it logs at error level and marks the index dirty. The next find_relationship_between rebuilds the index from storage (new rebuild_relationship_index_from_storage, shared with the startup rebuild) and clears the flag, restoring the O(1) exact-edge fast path. Correctness was already preserved by the authoritative chain-walk fallback; this prevents a silent persistent O(degree) degradation and makes the failure observable. Test: relationship_index_self_heals_when_dirty. nexus-core lib 2371 passed.
add_relationship held stats.write() while acquiring node_index.read() to set the approximate total_nodes, forming a lock-order cycle with the node_index write blocks (latent deadlock under concurrent edge inserts). Read node_index.len() into a local BEFORE taking stats.write() so the two locks are acquired sequentially, never nested. Test: concurrent_add_relationship_does_not_deadlock (8 threads x 500 edges + interleaved stats()).
find_relationship_between now emits the O(degree) hub-walk warning the moment it crosses 1000 hops, instead of only after the loop completes. This surfaces the pathology in real time and also fires when the edge is eventually found (the early return previously skipped the post-loop warning entirely). Observability-only; no behavior change.
…21) maintain_indexed_properties (runs on every node write) iterated every property x every label calling get_key_id + has_index. Add PropertyIndex::has_any_index() and early-return when no property index is registered at all (the common case for un-indexed graphs), so an un-indexed write does zero index work. Behaviour-preserving (the loop was already a no-op without indexes). Tests: has_any_index_reflects_registration + existing index-maintenance coverage.
…19) The async WAL command channel was bounded by channel_buffer_size (1000) while max_queue_depth (10000) only fed a counter, so append() blocked far earlier than configured and a full-channel stall was silent. Size the channel from max(channel_buffer_size, max_queue_depth) so the depth knob is real, and submit via try_send: on a genuinely full channel, increment a backpressure_blocks stat + warn (so the stall is observable) before the blocking send. Ordering + durability unchanged (crossbeam blocks, never drops). Test: test_backpressure_burst_does_not_deadlock (2000-entry burst into a 16-slot channel completes).
#22) Since the #12 fix runs the subquery once and materializes the full result in one transaction (per-OF-n-ROWS commit batching is unimplemented), an enormous subquery could OOM the server building all_results + the response. Cap at 1_000_000 rows: past the cap, abort the wrapper transaction and return a structured ERR_CALL_IN_TX_RESULT_TOO_LARGE instead of OOMing. Under-cap behaviour unchanged (call_in_transactions_terminates). Cap-exceed verified by inspection (a 1M-row e2e test is impractical).
The UNWIND-write path rejected a per-row MATCH after UNWIND, so the batched edge-upsert shape (UNWIND rows AS row MATCH (a {row.fk}),(b {row.tk}) MERGE (a)-[r:T]->(b) ON CREATE/ON MATCH SET ...) errored 'Unsupported clause after UNWIND' — forcing one HTTP request per edge. Two changes: (1) allow Clause::Match in the post-UNWIND loop, running process_match_clause_multi against the fresh per-row context (row.fk/row.tk resolve via the active unwind binding); (2) process_merge_relationship now applies ON CREATE / ON MATCH SET to the edge via a new apply_merge_rel_set helper (storage.update_relationship_properties; evaluate_set_expression resolves row.* + r.* self-refs). Edge analogue of the #13 node fix — one request per batch for edges. Test: unwind_match_merge_edge_upsert (edge created, ON CREATE SET w=5, idempotent, ON MATCH SET w=7). nexus-core lib 2375 passed.
…ser/clauses.rs into submodules
Pure code-move refactor — zero logic changes, public paths preserved
via pub use re-exports in facade mod.rs files. Visibility widened only
where the split moved code one module level deeper (pub(super) ->
pub(in super::super) / pub(in crate::executor::planner)).
- planner/queries.rs (4430 lines) -> queries/{mod,planner_core,strategy,
relationships,spatial,qpp,cost,expressions,notifications,unindexed}
- eval/projection.rs (4168 lines) -> projection/{mod,core,fn_string,
fn_math,fn_temporal,fn_list,fn_geo,fn_graph}
- parser/clauses.rs (3120 lines) -> clauses/{mod,read,write,pattern,
subquery,admin}
Part of phase5_split-oversized-files (rulebook task).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rators/aggregate.rs, operators/procedures.rs into submodules
Pure code-move refactor — zero logic changes, public paths preserved
via facade mod.rs re-exports. Visibility widened minimally where code
moved one module level deeper (pub(super) -> pub(in super::super),
private helpers -> pub(in crate::executor)).
- parser/expressions.rs (1652) -> expressions/{mod,identifier,literals,
precedence,primary,structured}
- parser/tests.rs (2345) -> tests/{mod,clauses,ddl,expressions,
external_ids,patterns,tokens}
- operators/aggregate.rs (2090) -> aggregate/{mod,core,columnar,
parallel,alias,tests} — 5/5 tests preserved
- operators/procedures.rs (2088) -> procedures/{mod,call,db_schema,
db_indexes,dbms,fts,spatial_procs}
Part of phase5_split-oversized-files (rulebook task).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…submodules Pure code-move refactor — zero logic changes, public paths preserved. Facade mod.rs files keep struct definitions, constructors and module declarations; impl blocks moved to cohesive submodules. Visibility widened minimally for cross-submodule calls (documented per item). - engine/mod.rs: 5853 -> 861 lines; new submodules query_pipeline, ddl, write_exec, match_exec, constraints, transactions - wal/mod.rs: 1824 -> 925 lines; new submodules record, writer - catalog/mod.rs: 1944 -> 744 lines; new submodules types, store, mappings, stats, extensions (36/36 tests preserved) Part of phase5_split-oversized-files (rulebook task). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cognition.rs into submodules
Pure code-move refactor — zero logic changes, zero assertion changes.
- engine/tests.rs (3417) -> tests/{mod,basics,crud,errors,query,write,
constraints,fulltext,indexes,transactions} — 104/104 tests preserved
- graph/correlation/mod.rs (2313 -> 172) -> +graph_types,graph_builder,
collection_query — 59/59 tests preserved
- graph/correlation/pattern_recognition.rs (1734) -> pattern_recognition/
{mod,types,detectors,overlay,quality,recommendation} — 30/30 tests
Part of phase5_split-oversized-files (rulebook task).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pi/streaming.rs into submodules
Pure code-move refactor — zero logic changes, Neo4j-compatible response
format untouched. Two split-introduced lints fixed (doc indent, tail
return). Visibility widened minimally for cross-submodule calls.
- engine/crud.rs (1561) -> crud/{mod,nodes,relationships,lookup,
index_maintenance} — 3/3 tests preserved
- api/cypher/execute.rs (1661) -> execute/{mod,handler,write_ops}
- api/streaming.rs (1720) -> streaming/{mod,service,tools,dispatcher,
handlers,tests} — 19/19 tests preserved
tests/integration_test.rs NOT split: discovered to be dead code (root
is a virtual workspace; no [[test]] target references it; it never
compiles). Follow-up task: phase5_wire-or-remove-dead-integration-test.
Part of phase5_split-oversized-files (rulebook task).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…up tasks - CHANGELOG Unreleased/Changed entry for the 17-file split - tasks.md fully checked for phase5_split-oversized-files - new tasks: phase5_wire-or-remove-dead-integration-test, phase5_split-oversized-files-wave2 (raw-line metric stragglers) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…aph/clustering.rs into submodules
Pure code-move refactor (wave 2, raw-line metric) — zero logic changes,
facade mod.rs re-exports preserve all paths.
- index/mod.rs (1797 -> 179) -> +dist,label_index,knn_index,
property_index — 49/49 tests preserved
- graph/algorithms/traversal.rs (1715) -> traversal/{mod,bfs_dfs,
shortest_path,components,centrality,similarity,mst}
- graph/clustering.rs (1669) -> clustering/ — 24/24 tests preserved
Part of phase5_split-oversized-files-wave2 (rulebook task).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…aph/procedures.rs into submodules
Pure code-move refactor (wave 2) — zero logic changes, facades preserve
all paths; parent private use bindings kept so child use super::* keeps
resolving (downward privacy inheritance).
- graph/core.rs (1641) -> core/{mod,graph,node,edge,ids,property_store,
stats} — 19/19 tests preserved
- correlation/data_flow/mod.rs (1632 -> 39) -> +tracker,types,analyzer,
optimization,statistics — 33/33 tests preserved
- graph/procedures.rs (1594) -> procedures/{mod,types,shortest_path,
centrality,community,similarity,topology,custom,registry} — 12/12
Part of phase5_split-oversized-files-wave2 (rulebook task).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…age/adjacency_list.rs, neo4j comparison test into submodules
Pure code-move refactor (wave 2 final batch) — zero logic changes,
facades preserve all paths. CHANGELOG updated for both wave-2 batches.
- executor/mod.rs (1588 -> 264) -> +types,shared,dispatch — 5/5 tests
- graph/correlation/component.rs (1542) -> component/ — 12/12 tests
- storage/adjacency_list.rs (1520) -> adjacency_list/{mod,types,store,
tests} — 34/34 tests
- tests/neo4j_result_comparison_test.rs (1591) -> directory test target
(main.rs + feature-area submodules) — 20/20 tests
No source file in crates/ exceeds 1500 lines anymore (raw wc -l).
Part of phase5_split-oversized-files-wave2 (rulebook task).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
….rs into submodules Task phase5_split-oversized-files-wave2 item 1.7: split the 1591-line neo4j_result_comparison_test.rs into tests/neo4j_result_comparison_test/ (main.rs + basic_return, expressions, functions, operators, parameters_and_null, query_clauses modules) and storage/mod.rs into record_store.rs, record_store_ops.rs, records.rs, and adjacency_list/ submodule; also splits graph/correlation/component.rs into component/ submodule.
Task phase5_wire-or-remove-dead-integration-test item 1.1 — inventory tests/integration_test.rs and diff against per-crate integration tests to quantify unique coverage. CHANGELOG entry documents finding that the 1892-line root-level file is unwired dead code (no [[test]] target in any Cargo.toml) and summarises coverage overlap.
Inventory of all 30 tests (2091 lines) across four groups (A: storage/ WAL/tx/cache; B: executor E2E; C: API error-handling; D: API perf). Coverage diff shows zero unique compilable tests — Group A (15 tests) fully duplicated by crates/nexus-core/tests/integration.rs; Groups B–D uncompilable due to stale Executor::new/NexusServer constructors and a syntax error at line 687. Design doc records findings and recommends removal pending user authorization. tasks.md marks item 1.1 [x]. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…user authorization Task phase5_wire-or-remove-dead-integration-test items 1.2-1.4 + tail. The 2091-line file was unwired dead code: no [[test]] target in any Cargo.toml, uncompilable (syntax error at line 687, stale Executor::new and NexusServer constructor signatures), and zero unique compilable coverage — all 15 storage/catalog/WAL/tx tests are identically covered by crates/nexus-core/tests/integration.rs (15/15 passing). User chose REMOVE over wire per design.md recommendation. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sts (#22) Task phase6_call-in-tx-result-cap. Extract the #22 materialization cap into check_call_in_tx_result_cap (engine/ddl.rs): default 1M rows, NEXUS_CALL_IN_TX_MAX_ROWS env override, structured ERR_CALL_IN_TX_RESULT_TOO_LARGE error, clean wrapper-tx abort at the call site. Adds boundary + env-knob tests. Corrects the stale #22 premise in docs: per-OF-n-ROWS commit batching IS implemented for top-level queries via the executor operator; the cap guards the legacy engine path only. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
#15) Task phase6_fix-rebuild-indexes-per-commit. Explicit-transaction COMMIT no longer runs rebuild_indexes_from_storage() (O(N) full scan per commit, amplified by the #11 property-index backfill). BEGIN captures storage node/rel watermarks on the session; COMMIT applies apply_committed_entity_index_updates over the watermark range union the session's created-entity lists: label bitmap + typed property B-tree per created node (the part the rebuild was load-bearing for) and the relationship index per created rel. All inserts idempotent. Commit cost now scales with the transaction's write set, not graph size. Contract guard explicit_commit_keeps_property_index_seek stays green; new equivalence test asserts incremental == full-rebuild ground truth. 2377 lib + 15 integration tests pass; clippy clean. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t on remove (#17) Task phase6_fix-relindex-nested-lock. Completes the 46bb910 hotfix: documents the lock-order invariant (type -> node -> edge -> stats, never inverse) on the struct, applies the same read-len-before-stats discipline to remove_relationship, and fixes total_nodes going stale after removals (it was only refreshed on add). Adds total_nodes_stays_correct_across_add_and_remove alongside the existing concurrency test. 5/5 module tests pass; clippy clean. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task phase6_fix-unwind-match-merge-edge-upsert. Completes the 6093bfc slice: relationship bindings in the write path now accumulate one entry per row (the per-variable insert previously kept only the last edge), and evaluate_return_expression_with_rels implements count(r) over the deduped upserted edge ids (was falling through to null). Distinct-edge semantics match the #13 node-count behavior. New multi-row test unwind_match_merge_edge_upsert_every_row (count(r)=2, per-row property values). 2379 lib tests pass; clippy clean. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ce (#21) Task phase6_prefilter-indexed-properties. Completes the 399ae32 slice: adds PropertyIndex::has_index_for_label and a prefilter in maintain_indexed_properties so that on a graph WITH property indexes, writes to nodes whose labels have no registered index skip the per-property get_key_id LMDB reads entirely. Registration set is the live (label,key) tree map itself (kept in sync by CREATE/DROP INDEX and the #11 startup rebuild). New registration-tracking test; full lib 2380/2380; clippy clean. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task phase6_propagate-relindex-add-error. Completes the 06ac218 dirty-bit/self-heal fix: adds the MERGE-no-duplicate regression test (wiped relationship index + dirty flag, repeated Cypher edge-MERGE, relationship_count unchanged), documents the Phase-8 manager decision (logged-at-warn; dirty-bit guarantee not low-cost for secondary structures that play no role in MERGE existence), and records the #18 entry in the CHANGELOG. transactions module 10/10. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task phase6_relwalk-warn-at-fallback. The find_relationship_between chain walk read read_rel(rel_ptr) without decoding the rel_id+1 pointer encoding (0 = end-of-chain sentinel), so the authoritative fallback silently returned None — or an off-by-one rel id — whenever the exact-edge index missed, letting an edge-MERGE duplicate the edge. Now decodes pointers like executor/operators/path.rs, returns the true rel id, and ignores deleted records (fast-path parity). Also adds the fallback-entry debug log (completing 412f1ac's in-loop threshold warn) and a test that captures the 1000-hop warning with a counting tracing layer against a 1100-edge hub for a FOUND edge. Full lib 2382/2382; clippy clean. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
) Task phase6_share-recordstore-arc. The core #16 implementation shipped with the storage split (9506b91): mmaps, file handles, property store and id counters live behind Arcs inside RecordStore, so the per-write refresh_executor clone is a handful of Arc::clones instead of 2-6 file-open + mmap syscalls. This task adds the structural guard test (Arc::ptr_eq on mmaps/files/property store + cross-handle write visibility + shared id counters), documents the interior-shared-handle decision over an engine-level Arc<RwLock<RecordStore>>, and records the CHANGELOG entry. Full workspace suite green (0 failures). Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task phase6_wal-async-backpressure. Extending the #19 backpressure test with a WAL-replay durability assertion found a real bug: the shutdown flag popped the writer loop while accepted Append commands still sat in the channel, silently dropping them (1990/2000 recovered). The writer thread now drains the channel on exit before the final flush, restoring the accepted => durable contract. Also documents the deliberate deviation from sync-append-on-Full (would interleave WAL entries out of order; ordered blocking send + backpressure_blocks stat instead). async_wal 6/6 (3x no flake), full lib 2383/2383, clippy clean. Task archived. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…mark Task phase6_fix-rollback-executor-created-nodes. Manual Docker validation found ROLLBACK kept a standalone in-tx Cypher CREATE alive (pre-existing; reproduces on published 2.3.2): the executor write path never reports created ids into session.created_nodes, which is all the rollback arm swept. The arm now unions the session storage watermark range captured at BEGIN (same write-set source as the #15 scoped commit), gated on an active transaction so a stray ROLLBACK cannot sweep a stale watermark. Test rollback_undoes_executor_created_nodes (rolled-back CREATE invisible, pre-existing data intact, engine usable after). Full lib 2384/2384; clippy clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… HTTP Task phase6_fix-rollback-executor-created-nodes (Docker validation finding #2). Explicit transaction commands sent via POST /cypher matched no handler branch and fell through to the bare executor clone, which silently no-opped them (HTTP 200, empty result): BEGIN never opened a transaction, ROLLBACK rolled nothing back, and COMMIT/ROLLBACK without BEGIN succeeded. The handler now detects transaction-command clauses in the parsed AST and routes them through engine.execute_cypher so the session-transaction machinery engages. Pre-existing (reproduces on published 2.3.2). nexus-server tests green; clippy clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…fter Docker validation Docker validation battery: 11/11 functional checks + 4/4 durability checks (restart) on the rebuilt 2.3.3 image — all audit fixes (#12-#22), the rollback watermark sweep, and the server transaction routing verified end-to-end over POST /cypher. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task phase6_fix-set-indexed-property-stale-index. Two index-correctness
bugs found by manual Docker validation (both reproduce on published
2.3.2): (1) SET on an indexed property left the typed B-tree stale --
seek by the new value missed the node while seek by the old value
returned it (wrong results both directions); persist_node_state now
captures the pre-write bag + labels and refreshes the typed index
(typed_index_refresh_node) alongside the FTS/spatial siblings.
(2) Non-tx Cypher CREATE (executor path) never indexed the node at all,
so it was seek-invisible and a follow-up MATCH {prop} SET no-opped; the
standalone-CREATE branch now indexes the allocated id range via a
node-count watermark (index_typed_properties_for_new_nodes). TDD tests
for both; full lib 2386/2386 x3; clippy clean. Task archived.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…struction
Backlog task documenting the third Docker-validation finding: the
legacy execute_cypher_ast read fallback re-parses format!("{:?}") AST
dumps (CypherSyntax errors), and PROFILE CALL { ... } fails to retain
the inner query string. Low impact today (legacy path internal-only);
full analysis and fix plan in the proposal.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ndoff
Task phase7_fix-query-to-string-debug-reconstruction. Three fixes:
(1) EXPLAIN/PROFILE were missing from is_clause_boundary, so any
EXPLAIN/PROFILE query parsed to an EMPTY AST and failed downstream with
'Query must contain at least one clause' (existing tests were soft and
hid it). (2) The EXPLAIN/PROFILE inner parsers had no CALL arm; added
the subquery/procedure dual shape, so PROFILE CALL { ... } IN
TRANSACTIONS works. (3) The legacy execute_cypher_ast read fallbacks
re-parsed query_to_string Debug output (never valid Cypher); they now
hand the parsed AST to the executor via the one-shot
preparsed_ast_override. New tests: profile_over_call_subquery and
legacy_call_subquery_path. Workspace 4716/0; clippy clean. Archived.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Neo4j compat suite grew to 325 tests; the 10 section-18 failures (point property accessors x/y/z/crs/longitude/latitude/height, 3D constructors, positional withinBBox) are pre-existing parity gaps -- identical 300/10 result on the published 2.3.2 image, zero regression in 2.3.3. Backlog task with full analysis registered. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes the lint version-consistency gate on PR #23 (Cargo.toml and CHANGELOG were already at 2.3.3; the README badge was missed in the release bump). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Release 2.3.3 — audit closure + Docker-validation fixes
Closes the 2.3.3 audit-task batch (GH #14–#22) and fixes seven additional pre-existing bugs found during manual Docker validation.
Closes #15 — explicit-transaction COMMIT no longer runs the O(N)
rebuild_indexes_from_storage()scan; scoped incremental maintenance over the transaction's own write set (storage watermarks captured at BEGIN + tracked created-entity lists). Commit cost now scales with the transaction's write set, not graph size. Guarded by theexplicit_commit_keeps_property_index_seekcontract test and an incremental-vs-full-rebuild equivalence test. (dfb6315b)Closes #16 —
RecordStore::cloneis now a shared handle (mmaps, file handles, property store, id counters behindArcs), so the per-writerefresh_executordoes a handful ofArc::clones instead of 2–6 file-open + mmap syscalls. Guarded byclone_is_shared_handle_not_reopen(Arc::ptr_eq+ cross-handle visibility). (310cb285/9506b912)Additional fixes (found by manual Docker validation; all reproduce on published 2.3.2)
ROLLBACKnow undoes standalone in-tx CypherCREATE(session watermark sweep)BEGIN/COMMIT/ROLLBACK/SAVEPOINToverPOST /cypherreach the engine (were silent no-ops)SETon an indexed property no longer leaves stale typed-index entries (wrong results both directions)CREATEmaintains the typed property index immediatelyEXPLAIN/PROFILEparse at top level (were returning empty ASTs);PROFILE CALL { … }worksfind_relationship_between(rel_id+1 pointer encoding)Validation
cargo test --workspace: 4716 passed / 0 failed; clippy 0 warnings; fmt cleanphase7_point-property-accessors-parity)🤖 Generated with Claude Code