# Graph Response Schema # Defines the canonical response structure for all graph API endpoints. # # Layer model: # L1 — Intra-Container (single container's entity subgraph) # L2 — Cross-Container (entities spanning multiple containers) # L3 — Schema-Level (type hierarchy / ontological graph) # L4 — Cross-System (federated XRI, future) # # Design principles: # - Server returns topology (nodes + edges); client handles layout # - Metrics are DERIVED (P10) — computed at query time, never stored # - Predicate vocabulary references relationship-vocabulary-schema.kno # - Responses are self-describing: layer, source, and query context included # # Three-Gate Test: # Gate 1 (Distinctness): Graph response ≠ any existing schema. # Nearest neighbor is diagram-schema.kno (view config), but this # defines the API *data* format, not rendering configuration. # Gate 2 (Reusability): 3+ endpoints return graphs: # GET /graph/:type/:slug, POST /graph/query, # GET /ontology/schema-graph, GET /ontology/types/:type/graph # Gate 3 (Clarity): Graph topology is a distinct concept with its own # vocabulary (nodes, edges, metrics, layers). $schema: kno@0.0.9 # --- BASIC (kernel) --- id: 01KJEKGTGDJ33CPP6WHJQ3PABN slug: graph-response-schema type: spec version: 0.1.0 # --- STANDARD --- title: "Graph Response Schema" purpose: | Canonical response structure for all graph API endpoints in the Possibility ontology layer. Every graph endpoint — whether returning an intra-container subgraph (L1), a cross-container traversal (L2), or a schema-level ontological view (L3) — wraps its response in this envelope. **Key separation of concerns:** | Concern | Owned by | NOT in this schema | |-----------------|----------------------------------|----------------------| | Topology | This schema (nodes, edges) | — | | Metrics | This schema (derived at runtime) | — | | Layout | Client / diagram-schema.kno | x, y, positions | | Visual mapping | Client / style-guide-schema.kno | colors, sizes, fonts | | Relationship vocab | relationship-vocabulary-schema | predicate definitions| **Subtypes by layer:** | Layer | Scope | source_xri pattern | |-------|----------------------|--------------------------------| | L1 | Intra-Container | pspace://{type}/{id} | | L2 | Cross-Container | pspace://{type}:* | | L3 | Schema-Level | pspace://spec/* | | L4 | Cross-System (future)| {remote}://{type}/{id} | # --- RICH --- provenance: origin: id: 01KJEKGTGDJ33CPP6WHJQ3PABN timestamp: "2026-02-26T00:00:00Z" tool: ai-assisted-authoring taxonomy: topics: - graph-theory - api-response - ontology keywords: - graph - node - edge - metrics - traversal - topology relationships: depends_on: - xri: "pspace://spec:kno-spec" reason: "Inherits kernel tier structure" - xri: "pspace://spec:relationship-vocabulary-schema" reason: "Edge predicates drawn from the relationship vocabulary" related_to: - xri: "pspace://spec:diagram-schema" reason: "Diagram schema handles view/layout config for rendered graphs" - xri: "pspace://spec:ontology-response-schema" reason: "Ontology responses may embed graph response fragments" enables: - xri: "pspace://spec:api-spec" reason: "Graph endpoints return instances of this schema" quality: completeness: 0.70 last_reviewed: "2026-02-26" review_status: draft # --- HISTORY --- _history: version: 1 created: "2026-02-26" created_by: "claude" modified: "2026-02-26" modified_by: "claude" # --- SPECIFICATION --- spec: status: Draft changelog: - version: "0.1.0" date: "2026-02-26" changes: - "Initial graph response schema — Phase 0, Milestone 14" - "Defines GraphNode, GraphEdge, GraphMetrics, GraphResponse" - "Supports layers L1–L4" schema: type: object required: - $schema - layer - nodes - edges properties: # ── Response Envelope ────────────────────────────────────── $schema: type: string description: "Schema declaration. Must be graph-response@0.1" example: "graph-response@0.1" layer: type: string enum: [L1, L2, L3, L4] description: | Graph layer this response represents. L1 = intra-container, L2 = cross-container, L3 = schema-level, L4 = cross-system (future). source_xri: type: string description: | XRI of the root entity or scope that produced this graph. For L1: the container XRI. For L2: a wildcard scope. For L3: "pspace://spec/*" or specific schema XRI. example: "pspace://playbook/01HXYZ..." # ── Query Context (optional, included when query-driven) ── query: type: object description: | The query parameters that produced this graph. Included for reproducibility and caching. properties: depth: type: integer description: "Traversal depth limit" minimum: 0 predicates: type: array items: type: string description: "Predicate filter applied to edges" types: type: array items: type: string description: "Node type filter applied" root_xri: type: string description: "Starting node for traversal queries" # ── Nodes ────────────────────────────────────────────────── nodes: type: array items: $ref: "#/definitions/GraphNode" description: "All nodes in the graph response" # ── Edges ────────────────────────────────────────────────── edges: type: array items: $ref: "#/definitions/GraphEdge" description: "All edges in the graph response" # ── Metrics (derived at runtime — P10) ───────────────────── metrics: $ref: "#/definitions/GraphMetrics" description: | Derived graph metrics computed at query time. Never stored — always recalculated from topology. Conforms to P10 (Derivable Structure). # ── Pagination (for large graphs) ────────────────────────── pagination: type: object description: "Cursor-based pagination for large graph responses" properties: total_nodes: type: integer description: "Total node count in full graph" total_edges: type: integer description: "Total edge count in full graph" cursor: type: string description: "Opaque cursor for next page" has_more: type: boolean description: "Whether more results exist" # ── Type Definitions ────────────────────────────────────────── definitions: GraphNode: type: object required: [id, label, type] description: | A node in the graph. Represents an entity or schema. Does NOT include layout coordinates — those are a client-side rendering concern. properties: id: type: string description: | Unique node identifier. For entity nodes: the entity ULID. For schema nodes: the schema slug. example: "01HXYZ123ABC456DEF789" xri: type: string description: "Full XRI of the entity this node represents" example: "pspace://playbook/01HXYZ..." label: type: string description: "Human-readable display label" example: "My Playbook" type: type: string description: | Entity type (e.g., playbook, user, spec) or schema type. Used for node styling and filtering. example: "playbook" domain: type: string description: | Domain classification for grouping. For L1: content domain (principle, procedure, pattern, etc.). For L3: schema domain (format, domain, tier). example: "principle" schema_xri: type: string description: "XRI of the schema this entity conforms to" example: "pspace://spec:playbook-schema" summary: type: string description: | Brief text summary for tooltips or previews. Truncated to 200 characters maximum. properties: type: object description: | Arbitrary key-value properties for this node. Schema-specific fields that don't fit the standard node structure. Kept minimal per DC-2. additionalProperties: true GraphEdge: type: object required: [source, target, predicate] description: | A directed edge in the graph. Predicate values must be from the relationship vocabulary (relationship-vocabulary-schema.kno). properties: source: type: string description: "Source node ID (must match a node in nodes[])" target: type: string description: "Target node ID (must match a node in nodes[])" predicate: type: string description: | Relationship predicate from the vocabulary. Must be a valid kernel, container, or domain predicate. example: "depends_on" reason: type: string description: | Human-readable explanation of why this relationship exists. Copied from the entity's relationships[] block. example: "Playbook extends the base document schema" weight: type: number description: | Edge weight for weighted graph algorithms. Defaults to 1.0. Inferred edges may have lower weight than declared edges. minimum: 0 maximum: 1 default: 1.0 inferred: type: boolean description: | Whether this edge was inferred (true) or explicitly declared in the entity's relationships[] block (false). Supports the living graph model where some edges are materialized by observation. default: false tier: type: string enum: [kernel, container, domain] description: | Which vocabulary tier this predicate belongs to. Enables filtering by relationship formality level. GraphMetrics: type: object description: | Derived graph metrics computed at query time. All values are derived from topology — never stored. This aligns with P10 (Derivable Structure): implicit structure derived from explicit content. properties: node_count: type: integer description: "Total number of nodes in the response" edge_count: type: integer description: "Total number of edges in the response" density: type: number description: | Graph density: actual edges / possible edges. Range [0, 1]. 0 = no edges, 1 = complete graph. minimum: 0 maximum: 1 connected_components: type: integer description: "Number of connected components (weakly connected)" avg_degree: type: number description: "Average node degree (in + out)" max_depth: type: integer description: | Maximum depth from root node (for traversal queries). Null for non-rooted queries. type_distribution: type: object description: | Count of nodes by type. Example: { playbook: 3, spec: 5 } additionalProperties: type: integer predicate_distribution: type: object description: | Count of edges by predicate. Example: { depends_on: 4, extends: 2 } additionalProperties: type: integer # --- EXAMPLES --- examples: - title: "L1 Intra-Container Graph" description: | A playbook's internal concept graph — the subgraph formed by its _contains entries and their relationships. content: | $schema: graph-response@0.1 layer: L1 source_xri: "pspace://playbook/01HXYZ..." nodes: - id: "entry-1" label: "DRY Principle" type: "entry" domain: "principle" - id: "entry-2" label: "Extract Method" type: "entry" domain: "procedure" - id: "entry-3" label: "Code Duplication" type: "entry" domain: "anti_pattern" edges: - source: "entry-1" target: "entry-2" predicate: "enables" reason: "DRY principle motivates the Extract Method procedure" inferred: false tier: "kernel" - source: "entry-3" target: "entry-1" predicate: "contradicts" reason: "Code duplication violates the DRY principle" inferred: false tier: "container" metrics: node_count: 3 edge_count: 2 density: 0.33 connected_components: 1 avg_degree: 1.33 type_distribution: entry: 3 predicate_distribution: enables: 1 contradicts: 1 - title: "L3 Schema-Level Graph" description: | The schema inheritance/extension graph showing how domain schemas relate to the kernel spec. content: | $schema: graph-response@0.1 layer: L3 source_xri: "pspace://spec/*" query: depth: 2 types: ["spec"] nodes: - id: "kno-spec" label: "KNO Format Spec" type: "spec" domain: "kernel" xri: "pspace://spec:kno-spec" - id: "document-schema" label: "Document Schema" type: "spec" domain: "domain" xri: "pspace://spec:document-schema" - id: "playbook-schema" label: "Playbook Schema" type: "spec" domain: "domain" xri: "pspace://spec:playbook-schema" edges: - source: "document-schema" target: "kno-spec" predicate: "extends" reason: "Document schema extends the kernel spec" tier: "kernel" - source: "playbook-schema" target: "document-schema" predicate: "extends" reason: "Playbook is a specialized document type" tier: "kernel" metrics: node_count: 3 edge_count: 2 density: 0.33 connected_components: 1 avg_degree: 1.33 max_depth: 2 type_distribution: spec: 3 predicate_distribution: extends: 2