On this page

Context graph

The context graph holds a project's entities and how they relate: the nodes and relationships describing its world. Of the project's four stores it is the only one that is a graph, and the only one you query by traversing relationships. If you have not yet chosen between the four, start at where your data goes.

Nodes and relationships

A node is a thing — a customer, a deployment, a ticket, a person, a file. It carries a label naming its type, a merge key, and properties.

A relationship is a named, directed connection from one node to another. It has a type, a start node, an end node, and properties of its own. Relationship properties are stored and read back; they are not decoration.

The content you save into and query out of the context graph is called context. What kinds of node and relationship may exist is decided by the project ontology, layered over the platform schema that every project shares.

The merge key

Every node you save names one of its own properties as the merge key. Saving the same label with the same merge-key value twice updates one node rather than creating two. That is what makes repeated saves safe: something that re-reports the same entity every hour converges on one node instead of accumulating duplicates. The merge key must be present in the properties you send, and a node without one is refused rather than guessed at.

What saving context does

save-context takes a list of nodes and a list of relationships and merges them into the project's context graph. Four things happen that are worth knowing before you call it.

The project is filled in for you. The project the write lands in is taken from your scope and stamped onto every node. You never pass it, and passing it is refused — see scope and server-bound arguments.

The vocabulary extends itself. New labels and relationship types you use are registered as you save, so there is no separate step to declare a type before writing data of that type. That is the Simple-mode behaviour. In Advanced mode save-context is not available at all: the call is refused with a message directing you to create-ontology and its governed flow. Which mode applies is a property of the project — see project mode.

Property values are flattened. Scalars store as they are. Arrays and nested objects are stored JSON-encoded, so they read back as a string rather than as a list or an object. A property whose value is null is not stored at all. If you need something to come back as structured data, model it as nodes and relationships rather than as a nested value.

Some names are not yours to use. Property names may not begin with an underscore, which the graph reserves for its own metadata. A small set of labels is platform-managed and is refused outright; that refusal is the subject of the platform schema page, and it is the single most common surprise on this path.

What querying context does

query-context runs a read-only Cypher query against the project's context graph and returns rows. It is the traversal surface: patterns of the form (a)-[:RELATES_TO]->(b) are what it exists for.

Three constraints shape how you write one.

It is read-only. Write clauses are rejected. The ways into the graph are saving context, ingestion and code sync; a query is not one of them.

It is pinned to your project. Your query filters on project_id = $project_id, and that parameter is bound server-side from your scope rather than from anything you send. A caller cannot widen a query past what they were granted by editing the parameter, because the parameter is not theirs to set.

It is bounded. Returned rows are clamped to a maximum, and so is the query timeout. You can ask for the query plan instead of the rows when you want to know why something is slow before you run it.

Two things it is deliberately not for. It is not a text search over code — use search-code and then fetch-code, which read the code graph properly. And for other large string properties, a full-text index call retrieves better than a CONTAINS scan does.

Why traversal is the point

A store that matches records one at a time can tell you that a thing exists. A graph can tell you what a thing is connected to, and what those are connected to, without you knowing in advance how many steps away the answer is. That is the whole reason the context graph is a graph: the questions worth asking about an organization are usually questions about connections.

It is also the cleanest test for whether you want this store at all. If your question does not depend on how things are connected, another store will answer it faster and more precisely.

What it is not

It is not the knowledge base. The knowledge base holds prose and finds it by meaning; the context graph holds structure and finds it by traversal. Text that happens to sit on a node is a property of that node, not a document, and nothing searches it by similarity.

It is not the data catalog either. The catalog describes data that lives outside Wexa; the context graph holds content of its own.

How it is filled

Three paths, all landing in the same store, and all passing the same policy decisions and writing the same audit record:

  • directly, by saving context through any of the four surfaces;
  • through ingestion, which brings a connected source's data in;
  • through code sync, which maintains the code graph for a connected repository.