Compass has two complementary query paths: focused discovery/traversal and the CompassQL compiler/executor. Both operate over the same indexed graph model.
Who this page is for: contributors changing query ranking, traversal, CompassQL syntax/plans/execution, or machine output.
You will learn: loading, indexes, discovery scoring, traversal, affected, CompassQL compilation and execution, caching, limits, profiling, and tests.
Prerequisites: Graph model and Workspace tour.
Reading time: 15 minutes.
GraphDocument::load:
- requires the normal JSON extension;
- enforces the graph size cap;
- reuses a binary cache only when its signature matches;
- retains unknown document fields and attributes.
Graph::from_document:
- consolidates duplicate node IDs by extending attributes;
- ensures edge endpoints can be indexed;
- preserves parallel edges for multigraph documents;
- builds ID lookup;
- builds incoming/outgoing adjacency;
- builds
QueryIndexand a schema fingerprint.
Read commands can force stored direction when compatibility documents require it.
question
-> query_terms()
-> score_nodes()
-> choose anchors
-> query_graph_text() with BFS/DFS and budget
-> focused text subgraph
compass-query::text:
- normalizes labels and questions;
- removes common question noise;
- produces search tokens;
- normalizes context filters.
This is deterministic token matching, not embedding inference.
score_nodes uses indexed label/attribute evidence to rank candidates.
find_node and pick_scored_endpoint support commands that need one entity.
Ranking changes can alter which subgraph users see even when graph data is unchanged. Protect them with realistic query fixtures and stable tie behavior.
query_graph_text traverses from anchors using:
- BFS or DFS;
- depth/working budget;
- optional relation context filters;
- hub avoidance/bounds;
- directed adjacency.
The renderer labels nodes and edges with provenance and source context.
render_explanation separates incoming from outgoing relations and reports
degree. Human output may list a multigraph neighbor once while retaining
parallel edge degree.
render_shortest_path preserves stored arrow direction:
A --calls--> B
When queried in reverse, the rendered arrow points backward rather than pretending the relation reversed.
Path tests must cover:
- forward/reverse rendering;
- no path;
- repeated labels;
- directed/legacy graphs;
- parallel edges;
- tie ordering.
Impact analysis needs only:
- node ID/label/location;
- edge endpoints and relation.
GraphDocument::load_for_affected can use a compact binary cache and avoids
retaining irrelevant attributes. affected_nodes traverses incoming
impact-relevant relation families under a depth.
This specialized projection improves cold performance without changing the full graph/query model.
compass-cypher compiles:
bytes
-> tokens with spans
-> AST
-> semantic scope/type checks
-> logical operators
-> optimizer records
-> LogicalPlan
Compile limits bound:
- source bytes;
- token count;
- nesting;
- path depth.
Diagnostics carry stable codes and byte spans. Unsupported read/write syntax is rejected during compile/semantic analysis.
compass-query::cql executes a logical plan over Graph.
Execution supports:
- indexed node candidates;
- directed expansion and bounded paths;
- repeated-variable joins;
- optional matching;
- correlated one-level existence checks;
- unwinding;
- filters and expressions;
- projection, distinct, union, order, skip, limit;
- aggregation;
- shortest-path families;
- typed values.
Runtime limits track:
- deadline/cancellation;
- returned rows;
- expanded relationships;
- working memory;
- path depth.
Limit checks occur during work, not only after a huge result is constructed.
The plan cache key includes:
exact source
language/planner versions
ordered parameter types
planning limits
graph schema fingerprint
It excludes:
- parameter values;
- graph values;
- result rows;
- deadline and cancellation state.
This allows safe plan reuse without leaking prior execution data.
QueryResult contains:
- versioned schema;
- column metadata;
- typed rows;
- optional explain plan;
- optional profile.
Renderers produce:
- table;
compass.cql.result/1JSON;compass.cql.jsonl/1header/rows/summary.
Output-to-file uses atomic completion. A failed execution must not leave a valid-looking partial result.
EXPLAIN returns logical operators and optimization records without executing.
PROFILE adds per-operator/clause:
- input/output rows;
- candidate nodes;
- expanded relationships;
- working-memory estimates;
- elapsed time;
- cancellation checkpoints.
Profiles are part of performance diagnosis. They must not include parameter values or secrets.
--at REV is resolved in the CLI/history service:
- resolve exact commit;
- open history;
- find and validate preferred realization;
- materialize synchronously if missing;
- reconstruct
GraphDocument; - build the same
LoadedGraph/query indexes.
The query engine does not need separate semantics for current and historical graphs after loading.
Cover normalization, scoring, traversal, direction, affected, execution, limits, caching, profiles, and output values.
Cover lexer/parser/semantic/plan diagnostics, support records, optimization, and language-version behavior.
compassql_cli.rs and read-command tests cover:
- option sources;
- stdin/file/REPL;
- parameters;
- stdout/stderr/exits;
- output atomicity;
--graph/--at;- JSON/JSONL schemas.
The repository carries an attributed subset of the openCypher TCK and optional Neo4j differential evidence. New support should update the matrix and add portable feature coverage.
scripts/benchmark_compassql.sh measures compile/plan, cache hits, fixed
matches, paths, aggregation, optional matching, cancellation latency,
expansions, rows, and memory.
When adding CompassQL syntax:
- lexer/token/spans;
- AST and parser;
- semantic scope/type rules;
- plan operator;
- optimizer effect;
- bounded execution;
- typed result;
- diagnostic code for invalid forms;
- support matrix;
- TCK/unit/CLI/differential/benchmark evidence.
When changing discovery ranking:
- realistic question tokens;
- multilingual/noise behavior;
- stable ties;
- hub/context filtering;
- result budget;
- compatibility snapshots;
- cold/warm query performance.
Next step: run a CompassQL query with EXPLAIN, then locate each logical
operator in compass-cypher and its executor in compass-query.