GQL-T: a temporal extension of ISO GQL for bitemporal and provenance-aware graph queries.
Substrate provides both a query language (GQL-T) and an RPC API. GQL-T extends ISO GQL with first-class bitemporal and provenance support.
AT SYSTEM <timestamp> Query at a specific system time (what we knew then)
AT VALID <timestamp> Query at a specific valid time (what was true then)
BETWEEN SYSTEM <t1> AND <t2> Find changes in a system-time window
PROVENANCE() Return provenance metadata for matched elements
CITE() Return artifact citations (hash, byte ranges, commit ref)
Show dependencies that were true on Nov 15, using current knowledge.
FROM GRAPH glitchy
AT SYSTEM HEAD()
AT VALID TIMESTAMP("2025-11-15T00:00:00Z")
MATCH (s:Service { name:"affiliate-api" })
-[:DEPENDS_ON*1..4]->(d:Service)
RETURN d.name, d.owner, PATH Show who we thought owned billing on January 5th.
FROM GRAPH glitchy
AT SYSTEM TIMESTAMP("2026-01-05T10:00:00Z")
AT VALID HEAD_VALID()
MATCH (s:Service { name:"billing" })
RETURN s.owner, PROVENANCE(s.owner) Find all changes recorded in the first week of January.
FROM GRAPH glitchy
BETWEEN SYSTEM TIMESTAMP("2026-01-01T00:00:00Z")
AND TIMESTAMP("2026-01-08T00:00:00Z")
MATCH (c:Change)
RETURN c.kind, c.subject, c.field,
c.old_value, c.new_value, c.assertion_id Find all services and teams affected if offer-ingester fails.
FROM GRAPH glitchy
AT SYSTEM HEAD()
AT VALID HEAD_VALID()
MATCH (s:Service { name:"offer-ingester" })
MATCH (s)-[:DEPENDS_ON*0..5]->(d:Service)
MATCH (d)<-[:OWNED_BY]-(team:Team)
RETURN d.name, team.name Trace how a specific version was derived.
FROM GRAPH glitchy
AT SYSTEM HEAD()
MATCH (v:Version { version_id:"ver_abc123" })
MATCH (a:Assertion)-[:ASSERTED]->(v)
MATCH (a)-[:DERIVES_FROM*0..6]->(a2:Assertion)
RETURN a, a2, PATH Find facts with old valid-time but recent system-time (backfills).
FROM GRAPH glitchy
AT SYSTEM HEAD()
MATCH (v:Version)
WHERE v.valid_from < TIMESTAMP("2025-01-01T00:00:00Z")
AND v.sys_from > TIMESTAMP("2026-01-01T00:00:00Z")
RETURN v.subject, v.field, v.valid_from,
v.sys_from, v.assertion_id
LIMIT 1000 Get the software bill of materials for a specific build.
FROM GRAPH glitchy
AT SYSTEM HEAD()
MATCH (b:Build { id:"build_789" })
MATCH (b)-[:HAS_SBOM]->(a:Artifact)
RETURN a.artifact_ref, a.format, PROVENANCE(a) Reconstruct an incident with linked artifacts and citations.
FROM GRAPH glitchy
AT SYSTEM HEAD()
MATCH (i:Incident { id:"inc_2026_001" })
MATCH (i)-[:HAS_EVENT]->(e:Event)
OPTIONAL MATCH (e)-[:EVIDENCE]->(art:Artifact)
RETURN e.time, e.type, e.summary, CITE(art)
ORDER BY e.time Syntax check, type check, schema validation.
Rewrite query with relationship checks and label filters from the caller's permissions. Policy first, not last.
Map system-time to snapshot bucket. For historical queries, identify base snapshot + delta overlay.
Start from most selective seed (indexed property lookups). Prefer pushing filters early.
Adjacency indexes support temporal stabbing. Valid-time filtering happens at index level.
Attach provenance/citations as joins during traversal, not post-processing. Ensures redaction applies correctly.
Every query has hard limits. Breaching a limit returns partial results with a "truncated" flag and an audit entry.
Limit on total edges traversed per query
Cap on unique nodes touched (default: 50k)
Bounded depth for variable-length paths
Query timeout prevents runaway execution
Cap on response payload size
Never fetch-then-filter; filter at storage
Bulk analytics: Queries lacking bounds are rejected
unless the caller has bulk_analytics capability and
runs in a batch queue with separate resource limits.