--- id: STATE-WP-0050 type: workplan title: "Railiance Fabric Graph Read Model Ingest" domain: custodian repo: state-hub status: finished owner: codex topic_slug: custodian created: "2026-05-23" updated: "2026-05-23" state_hub_workstream_id: "22f15fd4-2bec-4fea-adbc-2b02b7f4c1f3" --- # STATE-WP-0050 - Railiance Fabric Graph Read Model Ingest ## Goal Add State Hub support for ingesting Railiance Fabric graph exports as a read model, so Fabric can remain the graph source of truth while State Hub can query, summarize, and display the latest cross-repository graph state. ## Background RAIL-FAB-WP-0016 completed a canon-aligned reset and reingest in `railiance-fabric`. The renewed Fabric registry now exposes a schema-valid `FabricGraphExport` at `/exports/state-hub`. The current blocker is on the State Hub side: no graph read-model ingest endpoint or pull job exists in `state-hub`, so the renewed Fabric export cannot yet be stored as a State Hub read model. The integration must preserve Fabric as the source of truth and treat State Hub data as cache/index/query state. Current verified Fabric export baseline from 2026-05-23: - Source repo: `railiance-fabric` - Export endpoint: `http://127.0.0.1:8765/exports/state-hub` - Schema: `schemas/state-hub-export.schema.yaml` in `railiance-fabric` - Export kind: `FabricGraphExport` - Node count: 49 - Edge count: 58 - Representative canonical edge relationships: `exposes`, `depends_on`, `implements` ## T01 - Read-model storage and identity ```task id: STATE-WP-0050-T01 status: done priority: high state_hub_task_id: "d80b74bd-57ee-4e7a-81d7-406c02da52bc" ``` Design and implement persistent State Hub storage for imported Fabric graph exports. Requirements: - Store import run metadata, source repo slug, source URL, export timestamp, content hash, node count, edge count, validation status, and error details. - Store latest graph nodes and edges as a read model keyed by stable export identity, not as authoritative State Hub work items. - Preserve canon metadata fields from Fabric exports, including canonical type, canon category/anchor, mapping fit, evidence state, and display-only flags. - Make repeated ingest of the same export idempotent. - Include migrations and repository/service helpers. Result: - Added `fabric_graph_imports`, `fabric_graph_nodes`, and `fabric_graph_edges` read-model tables with import metadata, canonical content hash identity, source metadata, validation state, raw payload retention, and materialized node/edge query columns. - Preserved canon metadata fields on materialized nodes and edges, including canonical type/category/anchor, mapping fit, evidence state, and display-only flags. - Added service helpers that validate, hash, materialize, and idempotently refresh latest markers for repeated graph imports. ## T02 - Ingest API and pull job ```task id: STATE-WP-0050-T02 status: done priority: high state_hub_task_id: "3a94655d-703a-4aec-b724-46cafce14fdb" ``` Add an operator-usable ingestion path for Railiance Fabric graph exports. Requirements: - Provide either an HTTP endpoint, a CLI/scripted job, or both, that can ingest a `FabricGraphExport` JSON payload from `railiance-fabric`. - Validate payload shape before persisting; reject malformed exports without partially mutating the read model. - Support a pull mode from a configured Fabric registry URL, initially `http://127.0.0.1:8765/exports/state-hub`. - Record import progress/errors in normal State Hub progress surfaces. - Keep the integration explicit to `railiance-fabric` at first, while leaving source metadata general enough for future graph producers. Result: - Added `POST /fabric/graph-exports` for direct `FabricGraphExport` payloads and the documented wrapper shape. - Added `POST /fabric/graph-exports/pull` with a default pull source of `http://127.0.0.1:8765/exports/state-hub` and source repo `railiance-fabric`. - Invalid exports record failed import metadata and a `fabric_graph_import` progress row without writing graph nodes or edges. ## T03 - Query surfaces and dashboard readiness ```task id: STATE-WP-0050-T03 status: done priority: medium state_hub_task_id: "6b4ed6fe-bc84-43c8-a4b0-55ee93918bac" ``` Expose read-only query surfaces for the imported graph. Requirements: - Return latest import status and counts by source repo. - Query nodes and edges by source repo, domain, repo, canonical category, canonical relationship, evidence state, and mapping fit. - Provide summary counts suitable for dashboard cards. - Include representative examples for graph nodes and graph edges. - Do not allow graph read-model queries to mutate State Hub workstreams, tasks, messages, decisions, or progress rows. Result: - Added read-only query endpoints for import listing/latest status, graph summary counts, graph nodes, and graph edges. - Node queries filter by source repo, domain, repo, canonical category, evidence state, mapping fit, and kind. - Edge queries filter by source repo, canonical relationship, edge type, evidence state, mapping fit, display-only state, and endpoints. - Summary output includes dashboard-ready counts plus representative node and edge examples. ## T04 - Verification with RAIL-FAB-WP-0016 export ```task id: STATE-WP-0050-T04 status: done priority: high state_hub_task_id: "fdf5275a-f04d-43a3-b18a-12cfe0dcc2f7" ``` Verify the integration against the renewed Railiance Fabric registry export. Requirements: - Import the 2026-05-23 post-reset Fabric export successfully. - Confirm stored counts match the verified baseline: 49 nodes and 58 edges. - Confirm representative canonical relationships are queryable: `exposes`, `depends_on`, and `implements`. - Add regression tests for validation failure, idempotent reingest, latest import selection, and read-only query behavior. - Document the operator command for refreshing the State Hub graph read model after a Fabric reset/reingest. Result: - Verified against the live Railiance Fabric registry export on `http://127.0.0.1:8765/exports/state-hub` via a temporary State Hub server: latest import `130ffb56-7e30-4963-a3b1-b7527f685b45` stored 49 nodes and 58 edges. - Verified idempotent live reingest returned the same import id. - Confirmed relationship queries returned `exposes` 31, `depends_on` 15, and `implements` 12. - Added regression tests covering validation failure, idempotent reingest, latest import selection, and read-only query behavior. - Documented the operator refresh command in `docs/fabric-graph-read-model.md`. ## Acceptance - State Hub has a documented endpoint or job for importing the `railiance-fabric` graph export. - Import validates the payload and is idempotent. - Imported graph data is stored only as a read model/cache. - Query surfaces can answer latest counts and representative node/edge queries. - RAIL-FAB-WP-0016's renewed export can be imported with matching counts. - Tests cover import, validation, idempotency, and read-only query behavior.