Skip to content

feat(graph): POST /graph/project for pre-typed entity/relation projection - #246

Merged
RichardHightower merged 2 commits into
mainfrom
feat/235-graph-project
Sep 3, 2026
Merged

feat(graph): POST /graph/project for pre-typed entity/relation projection#246
RichardHightower merged 2 commits into
mainfrom
feat/235-graph-project

Conversation

@RichardHightower

Copy link
Copy Markdown
Contributor

Summary

Implements #235: a projection ingestion path so research-graph (and any other projector) can write pre-typed entities and relations into the property graph with no LLM/AST extraction.

This is Gap A / Phase B from docs/plans/research-graph-make-it-real.md. Projector logic stays in the consumer; Agent Brain only accepts explicit facts.

API

POST /graph/project
{
  "entities":  [{"type": "okf:Claim", "id": "claim.1", "properties": {}}],
  "relations": [{"src": "finding.1", "predicate": "asserts", "dst": "claim.1"}],
  "source_tag": "research-graph",
  "replace": false
}
  • Upsert — re-projecting the same id updates in place.
  • replace=true / DELETE /graph/project?source_tag= — delete-by-tag so destroy-and-rebuild is deterministic and does not wipe SCHEMA-01 extraction output.
  • Namespaced types (okf:Claim) and extra snake_case predicates (asserts, evidenced_by) are accepted alongside SCHEMA-01/03. Invented un-namespaced types still 400.
  • GET /graph/entity/okf:Finding/{id} accepts the same vocabulary so the typed spine is traversable.
  • Writes go through spawn isolation (project_isolated), same SIGSEGV in kuzu::NodeTable::lookupPK during sustained GraphRAG indexing (v10.0.7) #178 contract as build_from_documents_isolated. A kuzu-native crash is 503 kuzu_unavailable, not a dead server.
  • Additive and gated by ENABLE_GRAPH_INDEX / graphrag.enabled. No extractor is invoked.

Tests

  • API: tests/unit/api/test_graph_project_endpoint.py plus namespaced-type coverage on GET /graph/entity
  • Store: tests/unit/storage/test_graph_project.py (simple backend: spine, idempotent reproject, replace, tag isolation)
  • Isolation: tests/indexing/test_graph_project_isolation.py (SIGSEGV-class child exit)

Verified locally against SimplePropertyGraphStore: Finding→asserts→Claim→evidenced_by→Evidence round-trips, delete-by-tag spares untagged SCHEMA-01 nodes, replace rebuild converges.

Closes #235.

…tion (#235)

Add a deterministic projection ingestion path so an external projector
(research-graph Layer 1) can write typed facts with GRAPH_DOC_EXTRACTOR=none
and no LLM/AST extraction.

- POST /graph/project upserts {entities, relations, source_tag}; replace=true
  deletes prior facts with that tag first
- DELETE /graph/project?source_tag= for a clean rebuild
- Namespaced types (okf:Claim) and extra snake_case predicates (asserts)
  are accepted alongside SCHEMA-01/03; GET /graph/entity accepts the same
- Writes run through spawn isolation so a kuzu crash cannot take down the
  server (#178)
@RichardHightower
RichardHightower merged commit 172a989 into main Sep 3, 2026
3 checks passed
@RichardHightower
RichardHightower deleted the feat/235-graph-project branch September 3, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(graph): POST /graph/project — deterministic typed-entity/relation projection (no extraction)

1 participant