# Graph API schema outline (prep for GRAPH-API-28-001) Status: draft outline · Date: 2025-11-22 · Owner: Graph API Guild Scope: Establish OpenAPI/JSON schema primitives for search/query/paths/diff/export endpoints, tile streaming, budgets, and RBAC headers. This is a staging note for sprint 0207 Wave 1. ## 1) Shared headers and security - `X-Stella-Tenant` (required, string) - `Authorization: Bearer `; scopes: `graph:read`, `graph:query`, `graph:export` as applicable per route. - `X-Request-Id` optional; echoed in responses. - Rate limit headers: `X-RateLimit-Remaining`, `Retry-After` for 429 cases. ## 2) Tile envelope (streaming NDJSON) ```jsonc { "type": "node" | "edge" | "stats" | "cursor" | "diagnostic", "seq": 1, "cost": { "consumed": 12, "remaining": 988, "limit": 1000 }, "data": { /* node/edge/payload depending on type */ } } ``` - Deterministic ordering: breadth-first by hop for paths/query; lexicographic by `id` inside each hop when stable ordering is needed. - Cursor tile: `{"type":"cursor","token":"opaque"}` for resume. - Stats tile: counts, depth reached, cache hit ratios. ## 3) `/graph/search` (POST) Request body (summary): - `query` (string; prefix/exact semantics), `kinds` (array of `node` kinds), `limit`, `tenant`, `filters` (labels, ecosystem, scope), `ordering`. Response: stream of tiles (`node` + minimal neighbor context), plus final cursor/diagnostic tile. Validation rules: enforce `limit <= 500`, reject empty query unless `filters` present. ## 4) `/graph/query` (POST) - Body: DSL expression or structured filter object; includes `budget` (nodes/edges cap, time cap), `overlays` requested (`policy`, `vex`, `advisory`), `explain`: `none|minimal|full`. - Response: streaming tiles with mixed `node`, `edge`, `stats`, `cursor`; budgets decremented per tile. - Errors: `429` budget exhausted with diagnostic tile including partial cursor. ## 5) `/graph/paths` (POST) - Body: `source_ids[]`, `target_ids[]`, `max_depth <= 6`, `constraints` (edge kinds, tenant, overlays allowed), `fanout_cap`. - Response: tiles grouped by path id; includes `hop` field for ordering; optional `overlay_trace` when policy layer requested. ## 6) `/graph/diff` (POST) - Body: `snapshot_a`, `snapshot_b`, optional `filters` (tenant, kinds, advisory keys). - Response: tiles of `node_added`, `node_removed`, `edge_added`, `edge_removed`, `overlay_delta` (policy/vex/advisory), plus `manifest` tile with counts and checksums. ## 7) `/graph/export` (POST) - Body: `formats[]` (`graphml`, `csv`, `ndjson`, `png`, `svg`), `snapshot_id` or `query_ref`, `include_overlays`. - Response: job ticket `{ job_id, status_url, checksum_manifest_url }`; downloads streamed with deterministic manifests. ## 8) Error schema (shared) ```jsonc { "error": "GRAPH_BUDGET_EXCEEDED" | "GRAPH_VALIDATION_FAILED" | "GRAPH_RATE_LIMITED", "message": "human-readable", "details": {}, "request_id": "..." } ``` ## 9) Open questions to settle before sign-off - Final DSL surface vs structured filters for `/graph/query`. - Exact cache key and eviction policy for overlays requested via query. - PNG/SVG render payload (pre-signed URL vs inline streaming) and size caps. ## 10) Next steps - Convert this outline into OpenAPI components + schemas in repo (`docs/api/graph-gateway-spec-draft.yaml`) by 2025-11-24. - Add JSON Schema fragments for tiles and error payloads to reuse in SDKs. - Review with Policy Engine Guild to lock overlay contract version for GRAPH-API-28-006.