Skip to content

SignalQL v0.4 roadmap — the Operational Graph (draft)

Status: Roadmap / not specified. This document captures direction for a v0.4 release, not ratified grammar. Nothing here is implemented. It exists to frame the next layer — graph-native querying and reasoning lineage — and to keep that layer faithful to SignalQL's core principles. The motivating consumer is an AspectGraph-style system of record for organizational reasoning, but every construct below stays domain-agnostic; product vocabularies live in domain packs.

Premise

v0.1–v0.3 made SignalQL a credible evidence-retrieval and shaping language: events, entities, relationships, signals, probabilities, provenance, versioning, aggregation, sufficient statistics, governed metrics, catalog introspection, and a typed result envelope. The events/aggregation path executes as direct Postgres SQL; the entity/graph path parses and compiles to execution plans.

The next layer is not more aggregation. It is graph-native querying and, above it, reasoning lineage — the ability to answer why do we believe this?, not just what happened?. That is the layer AI systems actually need, and the one with the most strategic upside.

Already shipped in v0.3 (not v0.4 work)

To avoid re-proposing what exists, the following are done and only need incremental extension, not new foundations:

  • Governed metricsFROM metric(name) binding with versioned definitions (name, version, source, measure, owner, unit, dimensions). v0.4 extension: treat a metric as a queryable entity with history (DESCRIBE metric(...)).
  • Catalog introspectionDESCRIBE entities/events/signals/metrics/relationships. v0.4 extension: a DESCRIBE CAPABILITIES summary for cross-tool portability.
  • AS OF anchoring — reproducible window anchoring for retrieve/funnel. v0.4 extension: bitemporal AS OF across entity versions (see below).
  • context_bundle is already a core-safe entity type; the typed result envelope is the first step toward context-shaped output.

Core principles carried forward (non-negotiable)

v0.4 does not relax the v0.2/v0.3 contract:

  • No interpretation labels in core. States like at_risk, blocked, priority, stale are not operators or keywords. They are derived signal(...) values or domain-pack interpretations. A query asks WHERE signal(risk_score) > 0.8, never … AT RISK.
  • No mutation. Retrieval and shaping only; writes remain out of core.
  • Domain vocab is external. Typed relationship names (supports, blocks, depends_on, validates, derived_from, ships_in, …) live in packs such as aspectgraph-work-pack, not in core grammar.

1. Graph pattern operators

Today's traversal is intentionally low-level:

signalql
FROM entity(decision) TRAVERSE references DEPTH <= 2 RETURN entity_id

v0.4 adds higher-level, still-non-interpretive pattern operators so agents can express connection and absence directly:

ebnf
graph_query   ::= "MATCH" node_pattern ( edge_pattern node_pattern )*
                  where_clause? select_clause
edge_pattern  ::= "-[" relationship ( "*" depth_bound )? "]->"
                | "<-[" relationship "]-"
absence_pred  ::= "WITHOUT" relationship                 (* anti-join / negation *)
reach_query   ::= "FIND" node_pattern "CONNECTED TO" entity_ref ( "VIA" relationship )?
path_query    ::= "PATH" "FROM" entity_ref "TO" entity_ref ( "VIA" relationship )?

Examples (all structural, no business opinion):

signalql
FIND entity(decision) CONNECTED TO entity(experiment) WHERE name = "onboarding-v2"
signalql
MATCH entity(assumption) WITHOUT validated_by RETURN entity_id
signalql
PATH FROM entity(assumption) TO entity(release) VIA derived_from

Note WITHOUT validated_by is the structural "assumptions lacking evidence" query — it is an absence pattern, not an at_risk label. The relationship name validated_by comes from a domain pack.

2. Reasoning lineage (the headline feature)

The primitives already exist — provenance fields (source, created_by, derived_from, confidence, observed_at) and traversal. What is missing is a lineage-shaped query and result: walk the provenance/derivation edges and return the ordered chain, not a flat set.

A dedicated verb (not EXPLAIN, which is reserved for execution-plan explainability):

ebnf
trace_query ::= "TRACE" entity_ref ( "VIA" relationship )? ( "DEPTH" "<=" integer )?
signalql
TRACE entity(ticket) WHERE id = "123" VIA derived_from

returns the lineage as an ordered, typed chain:

text
customer_interview → activation_drop_signal → experiment_result → decision → ticket → release

Result shape: an ordered list of { entity_id, kind, relationship, confidence, observed_at } steps, so an agent can render why this exists and an auditor can verify the chain. SignalQL returns the lineage; it renders no judgment about whether the reasoning was good.

3. Context bundles (graph-shaped output)

SELECT returns rows. RETURN returns evidence. v0.4 adds context: a single operator that assembles a bounded subgraph optimized for LLM consumption.

ebnf
context_query ::= "CONTEXT" "FOR" entity_ref ( "DEPTH" "<=" integer )?
                  ( "INCLUDE" include_list )?
include_list  ::= include_item ( "," include_item )*
include_item  ::= "entities" | "relationships" | "decisions" | "evidence" | "signals"
signalql
CONTEXT FOR entity(roadmap) WHERE quarter = "Q3" DEPTH <= 2

returns a typed bundle (an extension of the v0.3 result envelope):

jsonc
{
  "root": { "entity_id": "...", "kind": "roadmap" },
  "entities": [ /* ... */ ],
  "relationships": [ /* {from, to, kind} */ ],
  "evidence": [ /* provenance-bearing records */ ],
  "metadata": { "as_of": "...", "depth": 2, "truncated": false }
}

This is the "SignalQL returns context, not rows" idea made concrete, and it builds directly on the existing context_bundle entity and typed envelope.

4. Bitemporal AS OF (time-travel graph)

v0.3 AS OF anchors the event-time window. v0.4 generalizes it to entity version time, using the existing version / superseded / updated_at fields, so a query reconstructs the graph as it was believed at a point in time:

signalql
CONTEXT FOR entity(roadmap) WHERE quarter = "Q3" AS OF "2026-03-01"
signalql
TRACE entity(decision) WHERE id = "d-42" AS OF "2026-03-01"

Answers "what did we believe then / what evidence existed then / why did we prioritize this then" — high-value for audit and for AI that must reason about past states, not just the present.

5. Graph execution engine (the real lift)

The honest dependency: today the entity/graph surface parses and plans but does not execute as direct SQL (it emits JSON execution plans for an unimplemented runtime; semantic_match is capability-gated on vector infra). Graph patterns, TRACE, CONTEXT FOR, and bitemporal AS OF all require a real graph/recursive execution backend (recursive CTEs for bounded traversal, an edge store, optional vector index). This is the largest piece of v0.4 and gates the rest — the grammar is the easy part.

Out of scope for v0.4 core

  • Interpretive state operators (AT RISK, BLOCKED, STALE) — derive via signal(...) or domain packs.
  • Standard relationship vocabularies — ship as aspectgraph-work-pack and peers.
  • Mutation / write-back — remains a separate protocol decision.
  • Judging reasoning quality — SignalQL returns the chain; the AI layer evaluates it.

Sequencing

  1. Graph execution engine (recursive traversal backend) — unblocks everything.
  2. Graph pattern operators + absence patterns.
  3. TRACE lineage query + ordered-chain result.
  4. CONTEXT FOR bundle output.
  5. Bitemporal AS OF across entity versions.
  6. aspectgraph-work-pack (relationship vocab, lineage conventions) as the first consumer that proves the core stayed domain-agnostic.

Normative references