feat: version state hub fabric export contract

This commit is contained in:
2026-05-24 01:06:49 +02:00
parent be0299e528
commit 63379ca329
5 changed files with 898 additions and 126 deletions

View File

@@ -1,26 +1,27 @@
# State Hub Integration Contract # State Hub Integration Contract
Railiance Fabric is the authoring and validation layer for ecosystem graph Railiance Fabric is the discovery, validation, and versioning layer for the
declarations. State Hub should ingest Fabric outputs as a read model for Railiance infrastructure-responsibility graph. State Hub should ingest Fabric
coordination, search, dashboards, and planning. It should not become the outputs as a read model for coordination, search, dashboards, and planning. It
primary authoring surface for services, capabilities, interfaces, dependencies, should not become the primary authoring surface for Fabric topology,
or bindings. ownership, fabric membership, or cross-boundary utility relations.
## Source-Of-Truth Boundary ## Source-Of-Truth Boundary
| Layer | Owns | Does Not Own | | Layer | Owns | Does Not Own |
|-------|------|--------------| |-------|------|--------------|
| Participating repos | Declaration files under `fabric/` | Global graph interpretation | | Deployment/accountability roots | Durable evidence of infrastructure, deployment, ownership, utility, and payment responsibility | State Hub task state |
| Railiance Fabric | Schemas, type catalogs, validation, graph construction, exports | State Hub tasks/progress/decisions | | Participating repos | Self-description evidence such as code, manifests, API contracts, package metadata, and legacy `fabric/` declarations | All external deployment/fabric relations |
| State Hub | Read-model storage, links to repos/workstreams/tasks/progress, dashboard/search views | Editing Fabric declarations | | Railiance Fabric | Schemas, discovery, validation, graph construction, accepted snapshots, exports | State Hub tasks/progress/decisions |
| State Hub | Read-model storage, links to repos/workstreams/tasks/progress, dashboard/search views | Editing Fabric topology or inventing ownership |
The flow is: The flow is:
```text ```text
repo-local fabric/*.yaml accountability roots + durable deployment evidence + repo evidence
| |
v v
railiance-fabric validate/export railiance-fabric scan/validate/export
| |
v v
State Hub graph read model State Hub graph read model
@@ -31,7 +32,7 @@ dashboard, search, planning, progress links
## Export Shape ## Export Shape
The CLI emits `FabricGraphExport` JSON: The CLI and registry emit `FabricGraphExport` JSON:
```bash ```bash
railiance-fabric export --format json railiance-fabric export --format json
@@ -39,7 +40,16 @@ railiance-fabric export --format json
Schema: `schemas/state-hub-export.schema.yaml` Schema: `schemas/state-hub-export.schema.yaml`
Top-level shape: The schema now accepts two export families:
- `railiance.fabric/v1alpha1`: legacy declaration-centered graph export.
- `railiance.fabric/v1alpha2` with `schema_version:
financial-fabric-v1`: financial Fabric graph export.
### Legacy v1alpha1 Shape
The legacy top-level shape remains supported for compatibility with
`STATE-WP-0050`:
```yaml ```yaml
apiVersion: railiance.fabric/v1alpha1 apiVersion: railiance.fabric/v1alpha1
@@ -74,6 +84,57 @@ Edge fields:
| `display_only` | `true` when the edge is a visualization/layout relationship rather than a canonical graph claim. | | `display_only` | `true` when the edge is a visualization/layout relationship rather than a canonical graph claim. |
| `evidence_state` | Evidence state for the claim: `observed`, `declared`, `inferred`, `proposed`, or `gap`. | | `evidence_state` | Evidence state for the claim: `observed`, `declared`, `inferred`, `proposed`, or `gap`. |
### Financial v1alpha2 Shape
The financial Fabric export adds first-class responsibility and value
semantics:
```yaml
apiVersion: railiance.fabric/v1alpha2
kind: FabricGraphExport
schema_version: financial-fabric-v1
netkingdom:
id: railiance.netkingdom
king_actor_id: actor.railiance.king
actors: []
fabrics: []
nodes: []
edges: []
unresolved: []
```
Additional top-level sections:
| Field | Meaning |
|-------|---------|
| `schema_version` | Financial Fabric export schema identity. |
| `netkingdom` | Root responsibility context and king actor. |
| `actors` | King, lord, tenant, operator, and steward actors. |
| `fabrics` | Fabric and subfabric boundaries. |
| `unresolved` | Ownership, containment, or import gaps to display for review. |
Additional node fields:
| Field | Meaning |
|-------|---------|
| `containment` | Netkingdom, fabric, optional subfabric, environment, and optional deployment scenario. |
| `ownership` | Owner actor, owner role, and ownership resolution state. |
| `accounting` | Optional cost/profit center and allocation metadata. |
| `evidence` | Evidence state, review state, confidence, and evidence references. |
Additional edge fields:
| Field | Meaning |
|-------|---------|
| `relationship_category` | `containment`, `ownership`, `technical`, `utility`, `accounting`, or `evidence`. |
| `provider` / `consumer` | Owner and boundary context for utility edges. |
| `boundary` | Whether the edge crosses fabric or subfabric boundaries. |
| `utility` | Utility type, contract, payment schema, metering basis, and business model. |
| `accounting` | Optional cost/profit attribution for the relationship. |
| `evidence` | Evidence state, review state, confidence, and evidence references. |
Example payload: `examples/exports/financial-fabric-v1.json`.
## Proposed State Hub Read Model ## Proposed State Hub Read Model
Add a State Hub ingestion endpoint or job that stores the latest graph export Add a State Hub ingestion endpoint or job that stores the latest graph export
@@ -126,9 +187,20 @@ fabric_graph_edges
edge_type edge_type
``` ```
The normalized node/edge tables are optional at first. State Hub can begin with The `STATE-WP-0050` implementation already stores a v1alpha1 read model. The
`fabric_graph_exports.graph_json` and materialize node/edge tables once query `STATE-WP-0051` follow-up should extend that storage with:
needs harden.
- import/export schema version;
- netkingdom id;
- fabric and subfabric ids;
- actor ids and roles;
- node containment;
- node owner actor, owner role, and ownership resolution;
- edge relationship category;
- utility provider/consumer ownership context;
- fabric/subfabric boundary crossing flags;
- node and edge accounting attribution;
- unresolved ownership or containment gaps.
## Linking To Existing State Hub Entities ## Linking To Existing State Hub Entities
@@ -140,7 +212,7 @@ State Hub should enrich graph nodes by matching:
- progress events -> `repo_id` and related workstream/task when available - progress events -> `repo_id` and related workstream/task when available
These links are annotations on the read model. They should never overwrite the These links are annotations on the read model. They should never overwrite the
repo-owned declaration files. Fabric export or source evidence.
## Ingestion Rules ## Ingestion Rules
@@ -150,7 +222,22 @@ repo-owned declaration files.
export validates. export validates.
4. Preserve historical exports long enough to compare graph drift. 4. Preserve historical exports long enough to compare graph drift.
5. Surface validation errors as State Hub progress events or human-review tasks, 5. Surface validation errors as State Hub progress events or human-review tasks,
but do not auto-edit declaration files. but do not auto-edit Fabric topology, ownership, or source evidence.
6. For `v1alpha2`, preserve unresolved ownership/containment gaps rather than
inventing State Hub-owned values.
7. For `v1alpha2`, expose cost/profit center fields as accounting views, not as
fabric membership changes.
## Current State Hub Limitations
As of `STATE-WP-0050`, State Hub imports the legacy `v1alpha1` export as a
read model. It does not yet materialize the `v1alpha2` financial Fabric fields.
Until `STATE-WP-0051` is implemented, a `v1alpha2` export is a contract and
registry capability in `railiance-fabric`, not a fully queryable State Hub read
model. Operators should keep importing the current `v1alpha1` export for
existing dashboard/query behavior and use `v1alpha2` payloads for contract
verification and follow-on implementation.
## Initial Dashboard Queries ## Initial Dashboard Queries

View File

@@ -0,0 +1,192 @@
{
"apiVersion": "railiance.fabric/v1alpha2",
"kind": "FabricGraphExport",
"schema_version": "financial-fabric-v1",
"generated_at": "2026-05-24T00:00:00Z",
"source": {
"producer": "railiance-fabric",
"registry": "registry",
"commit": "example",
"generation_reason": "operator_refresh"
},
"compatibility": {
"legacy_v1alpha1_supported": true,
"breaking_reset": false
},
"netkingdom": {
"id": "railiance.netkingdom",
"name": "Railiance Netkingdom",
"king_actor_id": "actor.railiance.king"
},
"actors": [
{
"id": "actor.railiance.king",
"kind": "FabricActor",
"role": "king",
"name": "Railiance King"
},
{
"id": "actor.railiance.primary-lord",
"kind": "FabricActor",
"role": "lord",
"name": "Railiance Primary Lord"
},
{
"id": "actor.coulomb.tenant",
"kind": "FabricActor",
"role": "tenant",
"name": "Coulomb Tenant"
}
],
"fabrics": [
{
"id": "fabric.railiance.primary",
"kind": "Fabric",
"name": "Railiance Primary Fabric",
"netkingdom_id": "railiance.netkingdom",
"lord_actor_id": "actor.railiance.primary-lord",
"parent_fabric_id": null,
"status": "active",
"boundary": {
"boundary_type": "fabric",
"criterion": "financial_and_operational_accountability"
},
"evidence_refs": []
},
{
"id": "subfabric.railiance.tenant.coulomb",
"kind": "Subfabric",
"name": "Coulomb Tenant Subfabric",
"netkingdom_id": "railiance.netkingdom",
"parent_fabric_id": "fabric.railiance.primary",
"tenant_actor_id": "actor.coulomb.tenant",
"status": "planned",
"boundary": {
"boundary_type": "subfabric",
"criterion": "restricted_paid_tenant_utility"
},
"evidence_refs": []
}
],
"nodes": [
{
"id": "state-hub.http",
"kind": "UtilityInterface",
"name": "State Hub HTTP API",
"repo": "state-hub",
"domain": "custodian",
"lifecycle": "active",
"containment": {
"netkingdom_id": "railiance.netkingdom",
"fabric_id": "fabric.railiance.primary",
"subfabric_id": null,
"environment": "local",
"deployment_scenario_id": null
},
"ownership": {
"owner_actor_id": "actor.railiance.primary-lord",
"owner_role": "lord",
"resolution": "inherited",
"inherited_from": "fabric.railiance.primary",
"supporting_actor_ids": []
},
"accounting": {
"cost_center_id": "cc.platform.shared",
"allocation_model": "direct"
},
"evidence": {
"state": "declared",
"review_state": "accepted",
"confidence": 0.9,
"refs": []
},
"canon_category": "endpoint",
"canon_anchor": "model/network",
"mapping_fit": "partial",
"evidence_state": "declared",
"attributes": {
"description": "Example tenant-facing State Hub API utility."
}
},
{
"id": "coulomb.automation-client",
"kind": "Service",
"name": "Coulomb Automation Client",
"repo": "coulomb-automation",
"domain": "railiance",
"lifecycle": "planned",
"containment": {
"netkingdom_id": "railiance.netkingdom",
"fabric_id": "fabric.railiance.primary",
"subfabric_id": "subfabric.railiance.tenant.coulomb",
"environment": "local",
"deployment_scenario_id": null
},
"ownership": {
"owner_actor_id": "actor.coulomb.tenant",
"owner_role": "tenant",
"resolution": "explicit",
"supporting_actor_ids": []
},
"accounting": {
"cost_center_id": "cc.coulomb.automation",
"allocation_model": "direct"
},
"evidence": {
"state": "declared",
"review_state": "accepted",
"confidence": 0.8,
"refs": []
},
"attributes": {}
}
],
"edges": [
{
"id": "utility:state-hub-http:coulomb-client",
"from": "state-hub.http",
"to": "coulomb.automation-client",
"type": "provides_utility_to",
"relationship_category": "utility",
"canonical_type": "depends_on",
"canon_anchor": "model/landscape",
"mapping_fit": "partial",
"display_only": false,
"evidence_state": "declared",
"provider": {
"owner_actor_id": "actor.railiance.primary-lord",
"fabric_id": "fabric.railiance.primary",
"subfabric_id": null
},
"consumer": {
"owner_actor_id": "actor.coulomb.tenant",
"fabric_id": "fabric.railiance.primary",
"subfabric_id": "subfabric.railiance.tenant.coulomb"
},
"boundary": {
"crosses_fabric_boundary": false,
"crosses_subfabric_boundary": true
},
"utility": {
"utility_type": "coordination_api",
"contract_id": "state-hub.http",
"payment_schema_id": "payment.internal-tenant-access",
"metering_basis": "unknown",
"business_model": "tenant_utility"
},
"accounting": {
"provider_profit_center_id": "pc.tenant-utilities",
"consumer_cost_center_id": "cc.coulomb.automation",
"allocation_model": "usage_weighted"
},
"evidence": {
"state": "declared",
"review_state": "accepted",
"confidence": 0.8,
"refs": []
},
"attributes": {}
}
],
"unresolved": []
}

View File

@@ -1,119 +1,578 @@
$schema: "https://json-schema.org/draft/2020-12/schema" $schema: "https://json-schema.org/draft/2020-12/schema"
$id: "https://railiance.local/fabric/schemas/state-hub-export.schema.yaml" $id: "https://railiance.local/fabric/schemas/state-hub-export.schema.yaml"
title: "FabricGraphExport" title: "FabricGraphExport"
type: object oneOf:
additionalProperties: false - $ref: "#/$defs/legacyGraphExport"
required: - $ref: "#/$defs/financialGraphExport"
- apiVersion
- kind $defs:
- nodes legacyGraphExport:
- edges
properties:
apiVersion:
type: string
const: railiance.fabric/v1alpha1
kind:
type: string
const: FabricGraphExport
generated_at:
type: string
format: date-time
source:
type: object type: object
additionalProperties: false additionalProperties: false
required:
- apiVersion
- kind
- nodes
- edges
properties: properties:
apiVersion:
type: string
const: railiance.fabric/v1alpha1
kind:
type: string
const: FabricGraphExport
generated_at:
type: string
format: date-time
source:
type: object
additionalProperties: false
properties:
repo:
type: string
commit:
type: string
path:
type: string
nodes:
type: array
items:
$ref: "#/$defs/legacyNode"
edges:
type: array
items:
$ref: "#/$defs/legacyEdge"
financialGraphExport:
type: object
additionalProperties: false
required:
- apiVersion
- kind
- schema_version
- netkingdom
- actors
- fabrics
- nodes
- edges
properties:
apiVersion:
type: string
const: railiance.fabric/v1alpha2
kind:
type: string
const: FabricGraphExport
schema_version:
type: string
const: financial-fabric-v1
generated_at:
type: string
format: date-time
source:
type: object
additionalProperties: true
compatibility:
type: object
additionalProperties: true
netkingdom:
$ref: "#/$defs/netkingdom"
actors:
type: array
items:
$ref: "#/$defs/actor"
fabrics:
type: array
items:
$ref: "#/$defs/fabricBoundary"
nodes:
type: array
items:
$ref: "#/$defs/financialNode"
edges:
type: array
items:
$ref: "#/$defs/financialEdge"
unresolved:
type: array
items:
$ref: "#/$defs/unresolvedGap"
legacyNode:
type: object
additionalProperties: false
required:
- id
- kind
- name
- repo
- domain
- lifecycle
properties:
id:
$ref: "./common.schema.yaml#/$defs/graphId"
kind:
type: string
name:
type: string
repo: repo:
type: string type: string
commit: domain:
type: string type: string
path: lifecycle:
type: string type: string
nodes: canon_category:
type: array type: string
items: canon_anchor:
type: object type: string
additionalProperties: false mapping_fit:
required: $ref: "#/$defs/mappingFit"
- id evidence_state:
- kind $ref: "#/$defs/evidenceState"
- name attributes:
- repo type: object
- domain additionalProperties: true
- lifecycle
properties: legacyEdge:
id: type: object
additionalProperties: false
required:
- from
- to
- type
properties:
from:
$ref: "./common.schema.yaml#/$defs/graphId"
to:
$ref: "./common.schema.yaml#/$defs/graphId"
type:
type: string
canonical_type:
type: string
canon_anchor:
type: string
mapping_fit:
$ref: "#/$defs/mappingFit"
display_only:
type: boolean
evidence_state:
$ref: "#/$defs/evidenceState"
attributes:
type: object
additionalProperties: true
netkingdom:
type: object
additionalProperties: false
required:
- id
- name
- king_actor_id
properties:
id:
$ref: "./common.schema.yaml#/$defs/graphId"
name:
type: string
minLength: 1
king_actor_id:
$ref: "./common.schema.yaml#/$defs/graphId"
actor:
type: object
additionalProperties: true
required:
- id
- kind
- role
- name
properties:
id:
$ref: "./common.schema.yaml#/$defs/graphId"
kind:
type: string
const: FabricActor
role:
type: string
enum:
- king
- lord
- tenant
- operator
- steward
name:
type: string
minLength: 1
fabricBoundary:
type: object
additionalProperties: true
required:
- id
- kind
- name
- netkingdom_id
- status
properties:
id:
$ref: "./common.schema.yaml#/$defs/graphId"
kind:
type: string
enum:
- Fabric
- Subfabric
name:
type: string
minLength: 1
netkingdom_id:
$ref: "./common.schema.yaml#/$defs/graphId"
parent_fabric_id:
anyOf:
- $ref: "./common.schema.yaml#/$defs/graphId"
- type: "null"
lord_actor_id:
$ref: "./common.schema.yaml#/$defs/graphId"
tenant_actor_id:
$ref: "./common.schema.yaml#/$defs/graphId"
status:
type: string
minLength: 1
boundary:
type: object
additionalProperties: true
evidence_refs:
type: array
items:
$ref: "#/$defs/evidenceRef"
financialNode:
type: object
additionalProperties: false
required:
- id
- kind
- name
- containment
- ownership
- evidence
properties:
id:
$ref: "./common.schema.yaml#/$defs/graphId"
kind:
type: string
name:
type: string
minLength: 1
repo:
type: string
domain:
type: string
lifecycle:
type: string
containment:
$ref: "#/$defs/containment"
ownership:
$ref: "#/$defs/ownership"
accounting:
$ref: "#/$defs/accounting"
evidence:
$ref: "#/$defs/evidence"
canon_category:
type: string
canon_anchor:
type: string
mapping_fit:
$ref: "#/$defs/mappingFit"
evidence_state:
$ref: "#/$defs/evidenceState"
attributes:
type: object
additionalProperties: true
financialEdge:
type: object
additionalProperties: false
required:
- from
- to
- type
- relationship_category
- evidence
properties:
id:
type: string
minLength: 1
from:
$ref: "./common.schema.yaml#/$defs/graphId"
to:
$ref: "./common.schema.yaml#/$defs/graphId"
type:
type: string
minLength: 1
relationship_category:
type: string
enum:
- containment
- ownership
- technical
- utility
- accounting
- evidence
canonical_type:
type: string
canon_anchor:
type: string
mapping_fit:
$ref: "#/$defs/mappingFit"
display_only:
type: boolean
evidence_state:
$ref: "#/$defs/evidenceState"
provider:
$ref: "#/$defs/utilitySide"
consumer:
$ref: "#/$defs/utilitySide"
boundary:
$ref: "#/$defs/boundaryCrossing"
utility:
$ref: "#/$defs/utility"
accounting:
$ref: "#/$defs/accounting"
evidence:
$ref: "#/$defs/evidence"
attributes:
type: object
additionalProperties: true
allOf:
- if:
properties:
relationship_category:
const: utility
then:
required:
- provider
- consumer
- boundary
- utility
containment:
type: object
additionalProperties: false
required:
- netkingdom_id
- fabric_id
properties:
netkingdom_id:
$ref: "./common.schema.yaml#/$defs/graphId"
fabric_id:
$ref: "./common.schema.yaml#/$defs/graphId"
subfabric_id:
anyOf:
- $ref: "./common.schema.yaml#/$defs/graphId"
- type: "null"
environment:
anyOf:
- type: string
minLength: 1
- type: "null"
deployment_scenario_id:
anyOf:
- type: string
minLength: 1
- type: "null"
ownership:
type: object
additionalProperties: false
required:
- owner_actor_id
- owner_role
- resolution
properties:
owner_actor_id:
$ref: "./common.schema.yaml#/$defs/graphId"
owner_role:
type: string
enum:
- king
- lord
- tenant
- operator
- steward
resolution:
type: string
enum:
- explicit
- inherited
- unresolved
- ambiguous
inherited_from:
anyOf:
- $ref: "./common.schema.yaml#/$defs/graphId"
- type: "null"
supporting_actor_ids:
type: array
items:
$ref: "./common.schema.yaml#/$defs/graphId" $ref: "./common.schema.yaml#/$defs/graphId"
kind:
type: string utilitySide:
name: type: object
type: string additionalProperties: false
repo: required:
type: string - owner_actor_id
domain: - fabric_id
type: string properties:
lifecycle: owner_actor_id:
type: string $ref: "./common.schema.yaml#/$defs/graphId"
canon_category: fabric_id:
type: string $ref: "./common.schema.yaml#/$defs/graphId"
canon_anchor: subfabric_id:
type: string anyOf:
mapping_fit: - $ref: "./common.schema.yaml#/$defs/graphId"
type: string - type: "null"
enum:
- direct boundaryCrossing:
- partial type: object
- conflict additionalProperties: false
- gap required:
- unknown - crosses_fabric_boundary
evidence_state: - crosses_subfabric_boundary
type: string properties:
enum: crosses_fabric_boundary:
- observed type: boolean
- declared crosses_subfabric_boundary:
- inferred type: boolean
- proposed
- gap utility:
attributes: type: object
type: object additionalProperties: true
additionalProperties: true required:
edges: - utility_type
type: array properties:
items: utility_type:
type: object type: string
additionalProperties: false minLength: 1
required: contract_id:
- from type: string
- to payment_schema_id:
- type type: string
properties: metering_basis:
from: type: string
$ref: "./common.schema.yaml#/$defs/graphId" business_model:
to: type: string
$ref: "./common.schema.yaml#/$defs/graphId"
type: accounting:
type: string type: object
canonical_type: additionalProperties: true
type: string properties:
canon_anchor: cost_center_id:
type: string type: string
mapping_fit: profit_center_id:
type: string type: string
enum: provider_profit_center_id:
- direct type: string
- partial consumer_cost_center_id:
- conflict type: string
- gap allocation_model:
- unknown type: string
display_only: payment_schema_id:
type: boolean type: string
evidence_state: metering_basis:
type: string type: string
enum: valid_from:
- observed type: string
- declared valid_until:
- inferred anyOf:
- proposed - type: string
- gap - type: "null"
attributes:
type: object evidence:
additionalProperties: true type: object
additionalProperties: false
required:
- state
- review_state
properties:
state:
$ref: "#/$defs/evidenceState"
review_state:
type: string
enum:
- accepted
- candidate
- needs_review
- rejected
confidence:
type: number
minimum: 0
maximum: 1
refs:
type: array
items:
$ref: "#/$defs/evidenceRef"
evidenceRef:
type: object
additionalProperties: true
properties:
id:
type: string
source_kind:
type: string
source_path:
type: string
source_url:
type: string
source_repo:
type: string
source_commit:
type: string
scanner:
type: string
scanner_version:
type: string
content_hash:
type: string
observed_at:
type: string
format: date-time
unresolvedGap:
type: object
additionalProperties: true
required:
- target_id
- kind
- message
properties:
target_id:
type: string
minLength: 1
kind:
type: string
minLength: 1
severity:
type: string
message:
type: string
minLength: 1
evidence_refs:
type: array
items:
$ref: "#/$defs/evidenceRef"
mappingFit:
type: string
enum:
- direct
- partial
- conflict
- gap
- unknown
evidenceState:
type: string
enum:
- observed
- declared
- inferred
- proposed
- gap

View File

@@ -8,6 +8,7 @@ from pathlib import Path
from railiance_fabric.cli import main as cli_main from railiance_fabric.cli import main as cli_main
from railiance_fabric.graph import build_graph from railiance_fabric.graph import build_graph
from railiance_fabric.financial import materialize_financial_graph_export
from railiance_fabric.registry import ( from railiance_fabric.registry import (
RESET_CONFIRMATION_TOKEN, RESET_CONFIRMATION_TOKEN,
RegistryError, RegistryError,
@@ -21,6 +22,7 @@ from railiance_fabric.registry import (
validate_graph_export, validate_graph_export,
xregistry_projection, xregistry_projection,
) )
from railiance_fabric.schema_validation import draft202012_validator
from railiance_fabric.server import RegistryHandler from railiance_fabric.server import RegistryHandler
@@ -261,6 +263,20 @@ def test_graph_export_validation_rejects_unflagged_display_edges() -> None:
raise AssertionError("expected RegistryError for unflagged display-only edge") raise AssertionError("expected RegistryError for unflagged display-only edge")
def test_state_hub_export_schema_accepts_legacy_and_financial_shapes() -> None:
validator = draft202012_validator(Path("schemas/state-hub-export.schema.yaml"))
legacy_graph = {
"apiVersion": "railiance.fabric/v1alpha1",
"kind": "FabricGraphExport",
"nodes": [],
"edges": [],
}
financial_graph = materialize_financial_graph_export(_financial_graph())
assert list(validator.iter_errors(legacy_graph)) == []
assert list(validator.iter_errors(financial_graph)) == []
def test_financial_graph_export_requires_resolvable_owner() -> None: def test_financial_graph_export_requires_resolvable_owner() -> None:
graph = _financial_graph() graph = _financial_graph()
del graph["nodes"][0]["ownership"] del graph["nodes"][0]["ownership"]

View File

@@ -190,7 +190,7 @@ Result:
```task ```task
id: RAIL-FAB-WP-0017-T04 id: RAIL-FAB-WP-0017-T04
status: todo status: done
priority: high priority: high
state_hub_task_id: "d10f120d-746d-468d-b208-d946b54c2707" state_hub_task_id: "d10f120d-746d-468d-b208-d946b54c2707"
``` ```
@@ -215,6 +215,24 @@ Done when:
- compatibility tests cover both old baseline import behavior and the new - compatibility tests cover both old baseline import behavior and the new
vNext export behavior, or intentionally document a controlled breaking reset. vNext export behavior, or intentionally document a controlled breaking reset.
Result:
- Updated `schemas/state-hub-export.schema.yaml` to accept both the legacy
`railiance.fabric/v1alpha1` declaration-centered export and the
`railiance.fabric/v1alpha2` / `financial-fabric-v1` export.
- Added schema fields for netkingdom, actors, fabrics, node containment,
node ownership, accounting attribution, evidence, utility edge
provider/consumer context, boundary crossing flags, and unresolved gaps.
- Added `examples/exports/financial-fabric-v1.json` as a materialized sample
payload.
- Updated `docs/state-hub-integration.md` to describe the v1alpha1/v1alpha2
contract split, State Hub import expectations, and the current limitation
that `STATE-WP-0050` only materializes v1alpha1 until `STATE-WP-0051`.
- Added schema compatibility coverage for both old and financial graph export
shapes.
- Verified with `python3 -m pytest tests/test_registry.py -q` and full
`python3 -m pytest`.
## T05 - Seed The Current Railiance Netkingdom Baseline ## T05 - Seed The Current Railiance Netkingdom Baseline
```task ```task