Graph Data Pillar
AlphaSwarm's relationship, temporal-fact and provenance capability is one governed pillar, not four parallel stacks. This page is the map: which repo owns what, which vocabulary everyone speaks, and where the boundaries are.
The umbrella decision is
ADR 032 — Graph as a first-class data-layer pillar,
Proposed and awaiting human ratification. The ten program-level records
(GDP-ADR-001..010) sit under it in
alphaswarm_internal/docs/architecture/graph-data-pillar/ and are likewise
Proposed.
The contracts described below are implemented and shipped; the decisions governing them still await ratification.
The problem it solves
Four repos carried graph code, and three of them described alphaswarm_graph
as "the thing they mirror" — by copy, not by import. That produced:
- the node/edge taxonomy written out three times,
- the bitemporal envelope in at least six shapes, across two different vocabularies,
- the Cypher read-guard deny-list implemented three times — where a clause present in one copy and missing from another is a write path that one boundary permits and the others reject,
- a label fork inside a single repo:
alphaswarm_kbwrites:KBDataPointand its own graph-retrieval channel queries:SokgNode.
None of these were caught by a test, because nothing compared the copies.
Two things, deliberately separated
alphaswarm_graph is the graph plane
The SOKG service owns the running graph: the store, the governance model (stage → quarantine → promote → release), tenancy enforcement, the growth loop, retrieval profiles and the schema registry. Its invariants are the platform's graph invariants. Other services reach it over HTTP only (ADR-005 / ADR-014 / ADR-0021) — never by importing it.
alphaswarm_core.graph is the vocabulary
Because the service boundary is HTTP-only, the shapes crossing it still have
to be shared. Every participating repo already depends on alphaswarm_core,
which makes it the one place a contract can live without breaching a boundary.
| Module | Owns |
|---|---|
taxonomy.py | NodeKind (111) / EdgeKind (75) StrEnums, a JSON-exportable registry, and the structural minimum consumers cannot derive — which relations are exclusive, which identity standard anchors a kind |
envelope.py | BitemporalStamp, ProvenanceStamp, EvidenceClass / QualityStatus, canonical field-name constants, legacy aliases for boundary adapters |
wire.py | The shapes that cross seams: SokgSeedBatch and its records, staged assertion/event candidates, the KB handoff assertions |
citation.py | GraphCitation — one citation shape for every retrieval channel |
guard.py | Read-path invariants: the write-clause deny-list, READ_LIMIT_CAP, and the as-of / no-look-ahead discipline |
The package is dependency-light on purpose: pydantic and the standard library only. No driver, no Cypher, no I/O. Evolution is additive — members and fields may be added; renames and removals require a major-version migration plan.
One bitemporal vocabulary
valid_from / valid_to / tx_from / tx_to. Half-open intervals
[from, to). Timezone-aware UTC, normalized on construction.
Two independent axes:
- valid time — when the fact is true in the world.
valid_to is Nonemeans still true. - transaction time — when the platform recorded or retracted it.
tx_to is Nonemeans still the current record.
Conflicts invalidate, never delete: superseding a fact stamps the prior
fact's valid_to/tx_to rather than removing it, so "what did we believe at
backtest date T?" stays answerable.
Legacy vocabularies (the Graphiti-style valid_at/invalid_at/created_at/
expired_at) survive only inside boundary adapters, which translate at the
edge and are deleted once their source migrates. See
Bi-temporal PermissionedDataPoint for the KB's
envelope and how it maps.
The as-of discipline
Every research- or training-facing read must call the core guard, or reproduce it under test:
visible_as_of(record, t, t_known)— the point-in-time filter (valid_from <= t < valid_to AND tx_from <= t_known < tx_to).assert_no_lookahead(records, as_of)— the defensive proof that the filter worked.
These are separate on purpose. The filter is the intent; the assertion is the evidence. A leaked future-dated fact is a silent correctness failure in a training fold, not a crash, so the export path has to prove itself rather than be trusted.
The predecessor of assert_no_lookahead compared ISO-8601 strings
lexicographically. That is only correct when both sides carry the same UTC
offset. A stamp written 2023-06-01T08:00:00-05:00 is 13:00 UTC — genuinely
after a 12:00 UTC cutoff — yet sorts below it as text, so the leak passed
the guard. The core version parses both sides to aware datetimes.
How each repo participates
| Repo | Role |
|---|---|
alphaswarm_graph | The authoritative plane. Re-exports the core taxonomy so its own public API is unchanged; its seed / assertion / event models are the core wire types |
alphaswarm_kb | SOKG projection models re-based on core wire; SecurityCitation is a GraphCitation subclass; alphaswarm_kb.ontology re-exports the taxonomy and adds KB-local identifier validators (LEI, FIGI, MIC, GICS) |
alphaswarm_learning | Bitemporal re-bases on BitemporalStamp; the read guard takes its deny-list and caps from core. Keeps service-local vocabulary (code graph, pedagogy) with a parity test pinning the overlap |
alphaswarm_data | Stays self-contained by design, so it converges through an optional bridge plus parity tests rather than a hard dependency — including one asserting the payload it POSTs parses as a core SokgSeedBatch |
Boundaries that do not move
- HTTP-only between services. No repo imports
alphaswarm_graphoralphaswarm_kb; none imports thealphaswarmmonolith. - Cross-service writes go through sanctioned paths only — durable outbox
projections delivering idempotent
SokgSeedBatches, or the staged assertion/event governance path. Direct Bolt into another service's graph is prohibited. - The taxonomy is closed. The growth loop quarantines any extracted triple
whose kinds are not members — that is the entity-grounding guardrail. Adding
a kind is a governance act: propose it in
alphaswarm_core/docs/graph-taxonomy-proposals.md, obtainalphaswarm-graph-expertreview, land it in core, then bump the pin.
Related
- Self-Organizing Knowledge Graph (SOKG) — the plane itself
- Bi-temporal
PermissionedDataPoint— the KB envelope - Finance knowledge graph — the financial schema
- Memory engines — Graphiti and friends as adapters