Skip to content
24/48h shipping across Italy
Skip to content
Documentation navigation

ADR 0003: Do Not Adopt A Runtime Graph Database Yet

  • Status: accepted no-adoption decision after bounded spike
  • Date: 2026-08-20

Context

The P6 backlog proposed a runtime graph database. k0smos already stores the relevant operational relationships as indexed foreign keys in tenant SQL databases. Adding a graph store would create a second, eventually consistent projection with its own credentials, queues, reconciliation, tenant filters, backup expectations, monitoring, and failure modes.

The first candidate was an operational impact traversal from Client to Project and Ticket, followed by Calendar and Deadline links. It is representative of the currently requested relationship depth and uses real table and foreign-key names from those four modules.

doc/public/en/development/graphify.md describes an optional repository-analysis artifact generated from source code. It is not a runtime application datastore, is not canonical business data, and has no bearing on this decision.

Spike

The analysis-only OperationalImpactSqlProbe executes one bounded SQL CTE. It accepts a positive client identifier, fixes the traversal to three levels, caps results at 500, and never exposes arbitrary SQL or a general graph-query API. The executable tests prove deterministic ordering, correct relationship expansion, result/depth bounds, and absence of nodes belonging only to another client.

The reproducible local benchmark used SQLite in memory with the same indexed relationship shape:

Measure Result
Clients 200
Projects 1,000
Tickets 10,000
Calendar events 3,000
Deadlines 1,000
Measured iterations 250
Rows per traversal 75
p50 0.480 ms
p95 0.571 ms
maximum 2.152 ms

This synthetic result is not a production SLO. It is sufficient for the architecture gate because the candidate is a shallow traversal over direct, indexed relationships and the SQL implementation is both small and fast. A graph adapter cannot improve the demonstrated use case enough to offset a new projection and its consistency/operations cost.

Decision

Do not add a runtime graph database, provider-neutral graph contracts, Neo4j adapter, projection messages, graph credentials, or graph-specific health and rebuild operations in 0.26.0.

SQL remains canonical and adequate for the only named query. If the query is promoted into the product, it must live in the application/module boundary that owns its authorization, use the tenant's existing SQL connection, apply the caller's module ACL before execution, and retain explicit depth/result bounds. The spike itself remains test/benchmark support and is deliberately not a core runtime service.

Reopen the decision only when a named product use case supplies all of:

  • a relationship traversal that is materially less maintainable in SQL or misses an agreed p95 target on a production-shaped dataset;
  • at least two stable projection consumers, or an explicit approved exception to the core-promotion rule;
  • an authorization model for every returned node/edge and a zero-foreign-tenant test;
  • measured projection throughput, lag, rebuild/recovery time, storage, and operational cost;
  • a provider-neutral spike followed, not preceded, by any Neo4j commitment.

Consequences

Discovery use case — 2026-09-13

The public navigator adds three named product traversals: visitor need through an approved concept and documented feature to content; topic through a related concept to published articles; and content through linked documents to approved supporting evidence. Discovery owns indexed SQL nodes/assertions/edges and bounded traversal (maximum depth three, node and result limits), with tenant and public eligibility checked at every hop. This is a functional SQL graph, not adoption of a graph database or a provider-neutral graph framework.

The frozen 54-query IT/EN relevance fixture measures graph-case nDCG@10 of 0.70973 with documents/vectors and 0.94620 with reviewed graph paths (four synthetic cases). The 10,000-content / 100,000-point / 200,000-edge fixture initially missed the serving budgets: graph/retrieval p95 1,262.46/4,769.42 ms. Query-plan inspection identified scans in concept/edge frontiers and point identity resolution. Ordered indexes and bounded exact-term SQL preserve the original global seed order and MySQL collation semantics; the repeated fixture now records 31.03 ms graph / 367.09 ms retrieval p95, excluding embedding.

SQL is in-memory SQLite with actual migrations, canonical leaf reads are synthetic, and Qdrant reuses one real vector. MySQL separately passes semantic, collation, concurrent-review and index down/up checks. These observations are not production-owner SQL or real-model capacity measurements. Keep SQL: there is still no second stable consumer or complete supported-engine cost/recovery comparison. All five reopening criteria remain applicable. The original operational-impact timings do not establish Discovery's SLO. Detailed methods, resource context and failed/passing artifacts live in modules/Discovery/src/EVALUATION.Discovery.md and tools/benchmarks/evidence/discovery-scale-remediation-20260913.json.

Operational consequences

  • No external graph service is required by this decision.
  • Existing tenant isolation, database backup, and module ACL boundaries remain authoritative.
  • No external graph index, cross-store graph write or arbitrary Cypher surface is introduced. Discovery's SQL projection still requires freshness and recovery checks against canonical owners.
  • The original graph investigation is complete with a measured no-adoption result. Discovery has a functional SQL graph meeting its warm synthetic serving budgets; external-engine adoption requires all reopening gates.