generated from coulomb/repo-seed
Establish Railiance Fabric graph model
This commit is contained in:
207
docs/adoption-guide.md
Normal file
207
docs/adoption-guide.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Adoption Guide
|
||||
|
||||
This guide shows another repo how to adopt Railiance Fabric declarations without
|
||||
reading Railiance Fabric source code.
|
||||
|
||||
## 1. Add The Directory Layout
|
||||
|
||||
Create the declaration directories in your repo:
|
||||
|
||||
```text
|
||||
fabric/
|
||||
services/
|
||||
capabilities/
|
||||
interfaces/
|
||||
dependencies/
|
||||
bindings/
|
||||
```
|
||||
|
||||
Start with only the files you need. A repo can adopt Fabric with one service
|
||||
and one capability, or with one dependency on a capability provided elsewhere.
|
||||
|
||||
## 2. Declare A Service
|
||||
|
||||
Create `fabric/services/<repo>-<service>.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: railiance.fabric/v1alpha1
|
||||
kind: ServiceDeclaration
|
||||
metadata:
|
||||
id: your-repo.your-service
|
||||
name: Your Service
|
||||
owner: your-repo
|
||||
repo: your-repo
|
||||
domain: railiance
|
||||
source_links:
|
||||
- label: Service README
|
||||
path: README.md
|
||||
spec:
|
||||
lifecycle: active
|
||||
environments: [dev, staging, prod]
|
||||
description: What this service does.
|
||||
service_type: app-service
|
||||
provides_capabilities: []
|
||||
exposes_interfaces: []
|
||||
```
|
||||
|
||||
Use lower-case dotted IDs. Prefer IDs that begin with the owning repo slug.
|
||||
|
||||
## 3. Declare A Provided Capability
|
||||
|
||||
Create `fabric/capabilities/<repo>-<capability>.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: railiance.fabric/v1alpha1
|
||||
kind: CapabilityDeclaration
|
||||
metadata:
|
||||
id: your-repo.your-service.runtime-secrets
|
||||
name: Runtime secrets
|
||||
owner: your-repo
|
||||
repo: your-repo
|
||||
domain: railiance
|
||||
source_links:
|
||||
- label: Capability docs
|
||||
path: docs/runtime-secrets.md
|
||||
spec:
|
||||
lifecycle: active
|
||||
environments: [dev, staging, prod]
|
||||
description: What this capability provides.
|
||||
capability_type: runtime-secrets
|
||||
service_id: your-repo.your-service
|
||||
interface_ids:
|
||||
- your-repo.your-service.kv-v2
|
||||
criticality: high
|
||||
data_classification: secret
|
||||
```
|
||||
|
||||
Pick `capability_type` from `catalog/capability-types.yaml`.
|
||||
|
||||
## 4. Declare An Interface
|
||||
|
||||
Create `fabric/interfaces/<repo>-<interface>.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: railiance.fabric/v1alpha1
|
||||
kind: InterfaceDeclaration
|
||||
metadata:
|
||||
id: your-repo.your-service.http-api
|
||||
name: Your Service HTTP API
|
||||
owner: your-repo
|
||||
repo: your-repo
|
||||
domain: railiance
|
||||
source_links:
|
||||
- label: API docs
|
||||
path: docs/api.md
|
||||
spec:
|
||||
lifecycle: active
|
||||
environments: [dev, staging, prod]
|
||||
description: How consumers call this interface.
|
||||
interface_type: http-api
|
||||
version: v1
|
||||
service_id: your-repo.your-service
|
||||
capability_ids:
|
||||
- your-repo.your-service.some-capability
|
||||
auth:
|
||||
method: oidc
|
||||
data_classification: internal
|
||||
```
|
||||
|
||||
Pick `interface_type` from `catalog/interface-types.yaml`.
|
||||
|
||||
## 5. Declare A Dependency
|
||||
|
||||
Create `fabric/dependencies/<repo>-<dependency>.yaml`:
|
||||
|
||||
```yaml
|
||||
apiVersion: railiance.fabric/v1alpha1
|
||||
kind: DependencyDeclaration
|
||||
metadata:
|
||||
id: your-repo.your-service.needs-runtime-secrets
|
||||
name: Runtime secrets dependency
|
||||
owner: your-repo
|
||||
repo: your-repo
|
||||
domain: railiance
|
||||
source_links:
|
||||
- label: Deployment values
|
||||
path: deploy/values.yaml
|
||||
spec:
|
||||
lifecycle: active
|
||||
environments: [dev, staging, prod]
|
||||
consumer_service_id: your-repo.your-service
|
||||
requires:
|
||||
capability_type: runtime-secrets
|
||||
interface:
|
||||
type: openbao-kv-v2-mount
|
||||
version_constraint: ">=v1 <v2"
|
||||
auth:
|
||||
method: kubernetes_service_account
|
||||
criticality: high
|
||||
data_classification: secret
|
||||
fallback:
|
||||
mode: none
|
||||
description: Service cannot start without runtime secrets.
|
||||
```
|
||||
|
||||
Active production dependencies should include at least one source link.
|
||||
|
||||
## 6. Add A Binding Only When Needed
|
||||
|
||||
Most bindings can be computed by the graph loader from dependency requirements
|
||||
and provider capabilities. Add a `BindingAssertion` when you need to pin,
|
||||
override, dispute, or document a planned provider:
|
||||
|
||||
```yaml
|
||||
apiVersion: railiance.fabric/v1alpha1
|
||||
kind: BindingAssertion
|
||||
metadata:
|
||||
id: your-repo.your-service.runtime-secrets-to-openbao
|
||||
name: Runtime secrets binding
|
||||
owner: your-repo
|
||||
repo: your-repo
|
||||
domain: railiance
|
||||
spec:
|
||||
lifecycle: active
|
||||
environments: [dev, staging, prod]
|
||||
dependency_id: your-repo.your-service.needs-runtime-secrets
|
||||
provider_capability_id: railiance-platform.openbao.runtime-secrets
|
||||
provider_interface_id: railiance-platform.openbao.kv-v2
|
||||
status: compatible
|
||||
rationale: This service uses OpenBao KV v2 for runtime secrets.
|
||||
```
|
||||
|
||||
## 7. Validate Locally
|
||||
|
||||
From the Railiance Fabric repo:
|
||||
|
||||
```bash
|
||||
railiance-fabric validate /path/to/your-repo
|
||||
```
|
||||
|
||||
During early bootstrapping:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=. python -m railiance_fabric.cli validate /path/to/your-repo
|
||||
```
|
||||
|
||||
Useful discovery checks:
|
||||
|
||||
```bash
|
||||
railiance-fabric providers runtime-secrets /path/to/your-repo
|
||||
railiance-fabric consumers runtime-secrets /path/to/your-repo
|
||||
railiance-fabric unresolved /path/to/your-repo
|
||||
```
|
||||
|
||||
For multi-repo validation, pass multiple roots:
|
||||
|
||||
```bash
|
||||
railiance-fabric validate /path/to/repo-a /path/to/repo-b
|
||||
```
|
||||
|
||||
## 8. Export For State Hub
|
||||
|
||||
```bash
|
||||
railiance-fabric export --format json /path/to/your-repo
|
||||
```
|
||||
|
||||
State Hub should ingest that export as a read model. Do not edit declarations in
|
||||
State Hub; change them in the owning repo and re-export.
|
||||
252
docs/declaration-schema.md
Normal file
252
docs/declaration-schema.md
Normal file
@@ -0,0 +1,252 @@
|
||||
# Declaration Schema
|
||||
|
||||
Railiance Fabric declarations are small YAML documents owned by the repository
|
||||
that provides or consumes the declared thing. The first schema version is
|
||||
`railiance.fabric/v1alpha1`.
|
||||
|
||||
## File Layout
|
||||
|
||||
Participating repositories should use this layout:
|
||||
|
||||
```text
|
||||
fabric/
|
||||
services/*.yaml
|
||||
capabilities/*.yaml
|
||||
interfaces/*.yaml
|
||||
dependencies/*.yaml
|
||||
bindings/*.yaml
|
||||
```
|
||||
|
||||
Railiance Fabric itself keeps reusable schemas in `schemas/` and examples in
|
||||
`examples/declarations/`.
|
||||
|
||||
## Shared Shape
|
||||
|
||||
Every declaration has:
|
||||
|
||||
```yaml
|
||||
apiVersion: railiance.fabric/v1alpha1
|
||||
kind: ServiceDeclaration
|
||||
metadata:
|
||||
id: railiance-platform.openbao
|
||||
name: OpenBao
|
||||
owner: railiance-platform
|
||||
repo: railiance-platform
|
||||
domain: railiance
|
||||
spec:
|
||||
lifecycle: active
|
||||
environments: [dev, staging, prod]
|
||||
```
|
||||
|
||||
`metadata.id` is the stable graph identifier. Use lower-case dotted IDs that
|
||||
begin with the owning repo slug when possible:
|
||||
|
||||
```text
|
||||
<repo>.<service>
|
||||
<repo>.<service>.<capability>
|
||||
<repo>.<service>.<interface>
|
||||
<repo>.<consumer>.<dependency>
|
||||
```
|
||||
|
||||
## Shared Fields
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `apiVersion` | Schema API version. Currently `railiance.fabric/v1alpha1`. |
|
||||
| `kind` | Declaration kind: service, capability, interface, dependency, or binding assertion. |
|
||||
| `metadata.id` | Stable graph identifier used for references and bindings. |
|
||||
| `metadata.name` | Human-readable display name. |
|
||||
| `metadata.owner` | Owning team, repo, or domain owner. |
|
||||
| `metadata.repo` | Repo slug that owns the declaration. |
|
||||
| `metadata.domain` | Domain slug, such as `railiance` or `custodian`. |
|
||||
| `metadata.source_links` | Optional source pointers to docs, code, manifests, ADRs, or workplans. |
|
||||
| `spec.lifecycle` | `planned`, `active`, `deprecated`, or `retired`. |
|
||||
| `spec.environments` | One or more of `dev`, `staging`, `prod`, or `all`. |
|
||||
|
||||
## Declaration Kinds
|
||||
|
||||
### ServiceDeclaration
|
||||
|
||||
A deployable or callable unit produced by a repo.
|
||||
|
||||
Required type-specific fields:
|
||||
|
||||
- `spec.description`
|
||||
|
||||
Optional relationship fields:
|
||||
|
||||
- `spec.service_type`
|
||||
- `spec.provides_capabilities`
|
||||
- `spec.exposes_interfaces`
|
||||
|
||||
Schema: `schemas/service.schema.yaml`
|
||||
|
||||
### CapabilityDeclaration
|
||||
|
||||
A stable semantic ability that consumers depend on.
|
||||
|
||||
Required type-specific fields:
|
||||
|
||||
- `spec.description`
|
||||
- `spec.capability_type`
|
||||
- `spec.service_id`
|
||||
- `spec.criticality`
|
||||
- `spec.data_classification`
|
||||
|
||||
Optional relationship fields:
|
||||
|
||||
- `spec.interface_ids`
|
||||
- `spec.compatibility`
|
||||
|
||||
Schema: `schemas/capability.schema.yaml`
|
||||
|
||||
`spec.capability_type` should match a type in
|
||||
`catalog/capability-types.yaml`. Unknown types are allowed by the document
|
||||
schema but should fail graph validation.
|
||||
|
||||
### InterfaceDeclaration
|
||||
|
||||
A concrete integration surface through which a capability is consumed.
|
||||
|
||||
Required type-specific fields:
|
||||
|
||||
- `spec.description`
|
||||
- `spec.interface_type`
|
||||
- `spec.version`
|
||||
- `spec.service_id`
|
||||
- `spec.auth.method`
|
||||
- `spec.data_classification`
|
||||
|
||||
Optional relationship fields:
|
||||
|
||||
- `spec.capability_ids`
|
||||
- `spec.endpoint`
|
||||
- `spec.auth.audience`
|
||||
- `spec.auth.scopes`
|
||||
- `spec.compatibility`
|
||||
|
||||
Schema: `schemas/interface.schema.yaml`
|
||||
|
||||
`spec.interface_type` should match a type in `catalog/interface-types.yaml`.
|
||||
Unknown types are allowed by the document schema but should fail graph
|
||||
validation.
|
||||
|
||||
### DependencyDeclaration
|
||||
|
||||
A consumer's declared requirement for a capability or interface.
|
||||
|
||||
Required type-specific fields:
|
||||
|
||||
- `spec.consumer_service_id`
|
||||
- `spec.requires.capability_type`
|
||||
- `spec.criticality`
|
||||
- `spec.data_classification`
|
||||
|
||||
Optional constraint fields:
|
||||
|
||||
- `spec.requires.capability_id`
|
||||
- `spec.interface.type`
|
||||
- `spec.interface.version_constraint`
|
||||
- `spec.auth.method`
|
||||
- `spec.fallback`
|
||||
- `spec.compatibility`
|
||||
|
||||
Schema: `schemas/dependency.schema.yaml`
|
||||
|
||||
`spec.requires.capability_type` and `spec.interface.type` should match the
|
||||
type catalogs. Unknown types are allowed by the document schema but should fail
|
||||
graph validation.
|
||||
|
||||
### BindingAssertion
|
||||
|
||||
A source-controlled assertion that resolves a dependency to a provider
|
||||
capability and, optionally, a provider interface. Most bindings should be
|
||||
computed by the graph loader; binding assertions are for overrides, disputes,
|
||||
or planned relationships that need an explicit record.
|
||||
|
||||
Required type-specific fields:
|
||||
|
||||
- `spec.dependency_id`
|
||||
- `spec.provider_capability_id`
|
||||
- `spec.status`
|
||||
- `spec.rationale`
|
||||
|
||||
Optional relationship fields:
|
||||
|
||||
- `spec.provider_interface_id`
|
||||
- `spec.compatibility`
|
||||
|
||||
Schema: `schemas/binding.schema.yaml`
|
||||
|
||||
## Shared Value Sets
|
||||
|
||||
### Lifecycle
|
||||
|
||||
```text
|
||||
planned, active, deprecated, retired
|
||||
```
|
||||
|
||||
### Environment
|
||||
|
||||
```text
|
||||
dev, staging, prod, all
|
||||
```
|
||||
|
||||
Use `all` only when the declaration truly applies across every environment.
|
||||
|
||||
### Data Classification
|
||||
|
||||
```text
|
||||
public, internal, confidential, restricted, secret
|
||||
```
|
||||
|
||||
### Criticality
|
||||
|
||||
```text
|
||||
low, medium, high, critical
|
||||
```
|
||||
|
||||
### Auth Method
|
||||
|
||||
```text
|
||||
none, oidc, jwt, mtls, kubernetes_service_account, openbao_token,
|
||||
static_secret, database_role, sts_token, api_key, unknown
|
||||
```
|
||||
|
||||
`unknown` is allowed for discovery-stage declarations but should not remain on
|
||||
active production dependencies.
|
||||
|
||||
## Compatibility
|
||||
|
||||
The optional `compatibility` object records machine-checkable or human-reviewed
|
||||
constraints:
|
||||
|
||||
```yaml
|
||||
compatibility:
|
||||
version: "v1"
|
||||
requires:
|
||||
- "decision-envelope >=1.0 <2.0"
|
||||
compatible_with:
|
||||
- "flex-auth.decision-api.v1"
|
||||
breaks:
|
||||
- "decision-envelope v0"
|
||||
notes: "Envelope v1 is required for tenant-scoped decisions."
|
||||
```
|
||||
|
||||
T05 will decide which compatibility fields are advisory and which should fail
|
||||
validation.
|
||||
|
||||
## Source Links
|
||||
|
||||
Use `metadata.source_links` when a declaration is based on a concrete source:
|
||||
|
||||
```yaml
|
||||
source_links:
|
||||
- label: OpenBao Helm values
|
||||
path: charts/openbao/values.yaml
|
||||
- label: Runtime secrets workplan
|
||||
url: https://example.invalid/workplans/openbao-runtime-secrets
|
||||
```
|
||||
|
||||
At least one source link is recommended for `active` declarations. T05 will
|
||||
make source-link requirements stricter for active production dependencies.
|
||||
85
docs/discovery-queries.md
Normal file
85
docs/discovery-queries.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Discovery Queries And Exports
|
||||
|
||||
Railiance Fabric includes a first CLI surface for inspecting local declaration
|
||||
graphs.
|
||||
|
||||
All commands accept a repo root, `fabric/` directory, or declaration files. When
|
||||
paths are omitted, commands read `./fabric`.
|
||||
|
||||
## Providers
|
||||
|
||||
List providers for a capability type or capability id:
|
||||
|
||||
```bash
|
||||
railiance-fabric providers runtime-secrets
|
||||
railiance-fabric providers railiance-platform.openbao.runtime-secrets
|
||||
```
|
||||
|
||||
Output columns:
|
||||
|
||||
```text
|
||||
provider_id service_id lifecycle environments interfaces
|
||||
```
|
||||
|
||||
## Consumers
|
||||
|
||||
List consumers of a capability type/id or interface type/id:
|
||||
|
||||
```bash
|
||||
railiance-fabric consumers runtime-secrets
|
||||
railiance-fabric consumers railiance-platform.openbao.kv-v2
|
||||
```
|
||||
|
||||
Output columns:
|
||||
|
||||
```text
|
||||
consumer_service_id dependency_id requires provider_capability_id provider_interface_id status
|
||||
```
|
||||
|
||||
## Dependency Path
|
||||
|
||||
Show dependency paths for a service:
|
||||
|
||||
```bash
|
||||
railiance-fabric dependency-path flex-auth.api
|
||||
```
|
||||
|
||||
This walks declared dependencies and binding assertions recursively through
|
||||
provider services.
|
||||
|
||||
## Unresolved Dependencies
|
||||
|
||||
Show dependencies with no matching provider or a `missing`/`disputed` binding:
|
||||
|
||||
```bash
|
||||
railiance-fabric unresolved
|
||||
```
|
||||
|
||||
## Blast Radius
|
||||
|
||||
Show consumers affected by an interface type or interface id:
|
||||
|
||||
```bash
|
||||
railiance-fabric blast-radius openbao-kv-v2-mount
|
||||
railiance-fabric blast-radius railiance-platform.openbao.kv-v2
|
||||
```
|
||||
|
||||
## Exports
|
||||
|
||||
Export the graph as JSON:
|
||||
|
||||
```bash
|
||||
railiance-fabric export --format json
|
||||
```
|
||||
|
||||
Export the graph as Mermaid:
|
||||
|
||||
```bash
|
||||
railiance-fabric export --format mermaid
|
||||
```
|
||||
|
||||
The JSON export has two top-level arrays:
|
||||
|
||||
- `nodes`: service, capability, interface, dependency, and binding nodes
|
||||
- `edges`: graph relationships such as `provides`, `exposes`,
|
||||
`available_via`, `consumes`, `binds:<status>`, and `uses_interface`
|
||||
200
docs/ecosystem-registry-service.md
Normal file
200
docs/ecosystem-registry-service.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# Ecosystem Registry Service Direction
|
||||
|
||||
This note compares Railiance Fabric with adjacent projects and standards before
|
||||
starting a service implementation for registering repositories, libraries,
|
||||
services, capabilities, interfaces, and dependencies.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Build a small Railiance Ecosystem Registry service as the API and indexed read
|
||||
model over repo-owned Fabric declarations.
|
||||
|
||||
The registry should not replace the `fabric/` files in each repo. Repositories
|
||||
remain the source of truth. The service validates, snapshots, queries, and
|
||||
projects that model so agents, humans, and State Hub can interact with the
|
||||
ecosystem graph without cloning every repo or rerunning the local CLI.
|
||||
|
||||
The closest external model to compare against is CNCF xRegistry. xRegistry is
|
||||
specifically about metadata registries, with both file/document and API views.
|
||||
Railiance should borrow that shape where useful, especially for versioned
|
||||
resources, import/export, filtering, and contract registries. Railiance should
|
||||
not begin by claiming xRegistry compliance; it should keep a compatible path.
|
||||
|
||||
## Standards And Projects To Compare
|
||||
|
||||
| Project or standard | What it is good at | What Railiance should borrow | What not to copy as the core |
|
||||
|---------------------|--------------------|-------------------------------|------------------------------|
|
||||
| [CNCF xRegistry](https://xregistry.io/) | Vendor-neutral metadata registries with REST APIs, document views, versioned resources, endpoint/schema/message extensions. | Use as the primary comparison for registry API shape, versioned metadata, import/export, filtering, document/API symmetry, and future endpoint/message/schema projections. | Do not make every Fabric concept an xRegistry resource on day one; keep the Railiance graph model readable and repo-native first. |
|
||||
| [Backstage Software Catalog](https://github.com/backstage/backstage/blob/master/docs/features/software-catalog/descriptor-format.md) | Developer portal catalog entities such as Component, API, Resource, System, Domain, ownership, relations, and `catalog-info.yaml`. | Support Backstage export/import projections for teams that want a portal later. Borrow the ownership and domain/system vocabulary where it aligns. | Do not make Backstage the authoritative store or require its plugin/runtime model before Railiance needs a portal. |
|
||||
| [CycloneDX](https://cyclonedx.org/specification/overview/) | Supply-chain inventory for components, services, dependencies, relationships, and vulnerability/security context. | Use CycloneDX SBOM/SaaSBOM imports for libraries, packages, third-party services, component dependency graphs, and provenance facets. | Do not stretch CycloneDX into the whole ecosystem model; it is strongest for bill-of-materials and supply-chain evidence. |
|
||||
| [OpenAPI](https://spec.openapis.org/oas/latest) | Machine-readable HTTP API contracts. | Attach OpenAPI documents to Fabric `InterfaceDeclaration` records for HTTP APIs and expose them through the registry. | Do not use OpenAPI to describe non-HTTP dependencies or ownership relationships. |
|
||||
| [AsyncAPI](https://www.asyncapi.com/docs/reference/specification/v3.0.0) | Machine-readable event/message-driven API contracts with channels, messages, operations, and protocol bindings. | Attach AsyncAPI documents to event-stream interfaces and use its vocabulary for channel/message contracts. | Do not use AsyncAPI for general service inventory. |
|
||||
| [CloudEvents](https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md) | Common event envelope metadata across services, platforms, and systems. | Use CloudEvents as the preferred event envelope for registry events and for Fabric event interfaces when the ecosystem needs portable event metadata. | Do not use CloudEvents as a catalog model; it is an event envelope. |
|
||||
| [Open Service Broker API](https://www.openservicebrokerapi.org/) | Lifecycle commands for service catalogs, provisioning, binding, unbinding, and deprovisioning. | Borrow the clear distinction between service catalog, service instance, and binding if Railiance later adds self-service provisioning. | Do not implement provisioning as part of the initial registry; registration and discovery come first. |
|
||||
| [Score](https://developer.humanitec.com/app-humanitec-io/docs/score/overview/) | Platform-agnostic workload intent for container workloads, with runtime requirements resolved by a platform. | Optionally import workload requirements into Fabric dependencies when repos already use Score. | Do not make Score mandatory; it is workload runtime intent, not an ecosystem graph. |
|
||||
| [OpenLineage](https://openlineage.io/docs/spec/object-model/) | Job, run, dataset, and facet model for observing data movement and transformation. | Use its facet idea for extensible metadata and consider data-lineage projections later. | Do not use it as the general service/capability/dependency model. |
|
||||
|
||||
## Service Boundary
|
||||
|
||||
The registry service should own:
|
||||
|
||||
- repository registration and repository metadata snapshots
|
||||
- ingestion of validated Fabric graph exports
|
||||
- validation results per repo and commit
|
||||
- indexed graph queries across all registered repos
|
||||
- version history and drift comparisons between snapshots
|
||||
- optional ingestion of supporting artifacts such as CycloneDX SBOMs,
|
||||
OpenAPI documents, AsyncAPI documents, and Score workload files
|
||||
- State Hub export or event emission for coordination views
|
||||
|
||||
The registry service should not own:
|
||||
|
||||
- hand-editing repo declarations through a central UI
|
||||
- deployment orchestration
|
||||
- service provisioning
|
||||
- policy enforcement gates before the model has adoption
|
||||
- replacing State Hub workstreams, tasks, progress, or planning state
|
||||
- replacing a developer portal
|
||||
|
||||
## Initial Data Model
|
||||
|
||||
Railiance Fabric already has first-class declarations for:
|
||||
|
||||
- `ServiceDeclaration`
|
||||
- `CapabilityDeclaration`
|
||||
- `InterfaceDeclaration`
|
||||
- `DependencyDeclaration`
|
||||
- `BindingAssertion`
|
||||
|
||||
The registry service should add service-level records around those declarations:
|
||||
|
||||
| Entity | Purpose |
|
||||
|--------|---------|
|
||||
| Repository | Registered source repo, URL, default branch, State Hub repo id, scan config, last accepted snapshot. |
|
||||
| Snapshot | Immutable ingest result for a repo at a commit. |
|
||||
| Graph Node | Indexed projection of a service, capability, interface, dependency, or binding. |
|
||||
| Graph Edge | Indexed relationship such as provides, exposes, consumes, binds, or uses interface. |
|
||||
| Artifact | Supporting document such as CycloneDX SBOM, OpenAPI, AsyncAPI, Score, README, or source link. |
|
||||
| Validation Result | Errors, warnings, schema versions, catalog versions, and unresolved references. |
|
||||
| Registry Event | Change event emitted when a repo, snapshot, node, edge, or validation result changes. |
|
||||
|
||||
## API Shape
|
||||
|
||||
Start with a small HTTP API that mirrors the local CLI answers:
|
||||
|
||||
```text
|
||||
POST /repositories
|
||||
GET /repositories
|
||||
GET /repositories/{repo_slug}
|
||||
|
||||
POST /repositories/{repo_slug}/snapshots
|
||||
GET /repositories/{repo_slug}/snapshots
|
||||
GET /repositories/{repo_slug}/snapshots/latest
|
||||
|
||||
GET /graph/nodes
|
||||
GET /graph/nodes/{graph_id}
|
||||
GET /graph/providers?capability_type=runtime-secrets
|
||||
GET /graph/consumers?target=railiance-platform.openbao.kv-v2
|
||||
GET /graph/unresolved
|
||||
GET /graph/blast-radius?interface_id=openbao-kv-v2-mount
|
||||
|
||||
POST /artifacts
|
||||
GET /artifacts/{artifact_id}
|
||||
|
||||
GET /exports/state-hub
|
||||
GET /exports/backstage
|
||||
GET /exports/xregistry
|
||||
```
|
||||
|
||||
`POST /repositories/{repo_slug}/snapshots` should accept the current
|
||||
`FabricGraphExport` plus source metadata:
|
||||
|
||||
```json
|
||||
{
|
||||
"repo_slug": "railiance-fabric",
|
||||
"commit": "git-sha",
|
||||
"generated_at": "2026-05-17T00:00:00Z",
|
||||
"graph": {
|
||||
"apiVersion": "railiance.fabric/v1alpha1",
|
||||
"kind": "FabricGraphExport",
|
||||
"nodes": [],
|
||||
"edges": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Interoperability Direction
|
||||
|
||||
The first implementation should be Railiance-native but deliberately
|
||||
projection-friendly:
|
||||
|
||||
- Backstage projection: export `Component`, `API`, `Resource`, `System`, and
|
||||
`Domain` entities from Fabric nodes where possible.
|
||||
- xRegistry projection: expose schemas, messages, endpoints, and possibly
|
||||
Fabric-specific registry groups once the internal model settles.
|
||||
- CycloneDX import: attach SBOM components, services, and dependencies to repo
|
||||
and service nodes.
|
||||
- OpenAPI/AsyncAPI attachment: connect contract documents to interface nodes
|
||||
and validate that declared interface type/version metadata is consistent.
|
||||
- CloudEvents events: emit registry changes such as
|
||||
`railiance.fabric.repository.registered`,
|
||||
`railiance.fabric.snapshot.accepted`, and
|
||||
`railiance.fabric.validation.failed`.
|
||||
- Score import: map workload resources and dependencies into draft Fabric
|
||||
dependency declarations only when a repo opts in.
|
||||
|
||||
## Suggested Architecture
|
||||
|
||||
```text
|
||||
repo-local fabric/*.yaml
|
||||
|
|
||||
v
|
||||
railiance-fabric validate/export
|
||||
|
|
||||
v
|
||||
Ecosystem Registry ingest API
|
||||
|
|
||||
+--> snapshot store
|
||||
+--> graph index
|
||||
+--> artifact index
|
||||
+--> validation result store
|
||||
|
|
||||
+--> State Hub export/events
|
||||
+--> Backstage/xRegistry projections
|
||||
+--> query API for agents and humans
|
||||
```
|
||||
|
||||
Keep the first service boring: the existing Python loader and validator should
|
||||
be reused. A lightweight Python HTTP service with a local relational store is
|
||||
enough for the first useful version. Once ingestion and query semantics are
|
||||
stable, the backing store can be replaced or expanded.
|
||||
|
||||
## First Implementation Slice
|
||||
|
||||
1. Service scaffold using the existing loader, validator, and graph export
|
||||
model.
|
||||
2. Repository registration endpoint with repo slug, URL, default branch, and
|
||||
optional State Hub repo id.
|
||||
3. Snapshot ingest endpoint that validates a `FabricGraphExport` and stores it
|
||||
atomically.
|
||||
4. Query endpoints for providers, consumers, unresolved dependencies, dependency
|
||||
paths, and blast radius.
|
||||
5. State Hub export endpoint matching `docs/state-hub-integration.md`.
|
||||
6. Contract attachment for OpenAPI and AsyncAPI documents.
|
||||
7. CycloneDX SBOM attachment for library/package inventory.
|
||||
8. CloudEvents-style registry events once mutation endpoints exist.
|
||||
|
||||
## Open Design Questions
|
||||
|
||||
- Should the registry pull repos itself, or should repos/agents push validated
|
||||
exports from CI? Push is simpler and keeps credentials narrower.
|
||||
- Should repository registration live first in State Hub and sync into Fabric
|
||||
Registry, or should Fabric Registry own its own repo registry and annotate
|
||||
State Hub ids? The current boundary suggests Fabric Registry owns graph
|
||||
registration, State Hub owns planning/coordination.
|
||||
- Should the first storage backend be SQLite for local operations or Postgres
|
||||
from the start? SQLite is enough for proving semantics; Postgres is better
|
||||
once multiple agents write concurrently.
|
||||
- Should xRegistry compatibility be a projection only, or should the internal
|
||||
registry model follow xRegistry group/resource/version terminology? Start as
|
||||
projection; revisit after the first API is exercised.
|
||||
54
docs/first-rollout.md
Normal file
54
docs/first-rollout.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# First Rollout
|
||||
|
||||
The first rollout is represented by the seed declarations under `fabric/`.
|
||||
Those files are intentionally centralized in Railiance Fabric for bootstrap;
|
||||
the long-term target is for each owning repo to carry its own `fabric/`
|
||||
declarations.
|
||||
|
||||
## Seeded Repos
|
||||
|
||||
| Repo | Seeded Service(s) | First Capability |
|
||||
|------|-------------------|------------------|
|
||||
| `railiance-platform` | OpenBao, CNPG, Valkey | runtime secrets, PostgreSQL, Redis-compatible cache |
|
||||
| `net-kingdom` | IAM Profile contract | IAM Profile issuer |
|
||||
| `key-cape` | IAM Profile API | IAM Profile issuer implementation |
|
||||
| `flex-auth` | flex-auth API, Topaz | authorization decisions |
|
||||
| `artifact-store` | object storage service | object storage, credential vending |
|
||||
| `repo-scoping` | scope generator | scope generation |
|
||||
| `the-custodian` | State Hub | coordination read model |
|
||||
|
||||
## Promotion Path
|
||||
|
||||
For each owning repo:
|
||||
|
||||
1. Copy the matching seed files from `railiance-fabric/fabric/` into the owning
|
||||
repo's own `fabric/` directory.
|
||||
2. Replace seed source links with repo-local source links.
|
||||
3. Validate the owning repo by itself.
|
||||
4. Validate the owning repo together with `railiance-fabric` and other
|
||||
providers/consumers it depends on.
|
||||
5. Export the multi-repo graph for State Hub ingestion.
|
||||
6. Once repo-local declarations are authoritative, remove or mark the central
|
||||
seed declarations as bootstrap-only.
|
||||
|
||||
## Suggested Order
|
||||
|
||||
1. `railiance-platform`: owns OpenBao, CNPG, and Valkey provider declarations.
|
||||
2. `key-cape`: owns the first concrete IAM Profile implementation.
|
||||
3. `flex-auth`: owns authorization decisions and concrete consumers of OpenBao
|
||||
and IAM Profile capabilities.
|
||||
4. `the-custodian/state-hub`: owns coordination read-model declarations and is
|
||||
the first export consumer.
|
||||
5. `repo-scoping`: owns scope-generation provider declarations.
|
||||
6. `artifact-store`: can promote planned object-storage declarations when its
|
||||
interfaces stabilize.
|
||||
|
||||
## Completion Signal
|
||||
|
||||
The rollout is good enough for the next phase when:
|
||||
|
||||
- each repo can validate its own declarations
|
||||
- the combined graph has no unresolved dependencies
|
||||
- State Hub can ingest a `FabricGraphExport`
|
||||
- dashboard/search views can answer provider, consumer, unresolved, and blast
|
||||
radius questions from the ingested graph
|
||||
159
docs/state-hub-integration.md
Normal file
159
docs/state-hub-integration.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# State Hub Integration Contract
|
||||
|
||||
Railiance Fabric is the authoring and validation layer for ecosystem graph
|
||||
declarations. State Hub should ingest Fabric outputs as a read model for
|
||||
coordination, search, dashboards, and planning. It should not become the
|
||||
primary authoring surface for services, capabilities, interfaces, dependencies,
|
||||
or bindings.
|
||||
|
||||
## Source-Of-Truth Boundary
|
||||
|
||||
| Layer | Owns | Does Not Own |
|
||||
|-------|------|--------------|
|
||||
| Participating repos | Declaration files under `fabric/` | Global graph interpretation |
|
||||
| Railiance Fabric | Schemas, type catalogs, validation, graph construction, exports | State Hub tasks/progress/decisions |
|
||||
| State Hub | Read-model storage, links to repos/workstreams/tasks/progress, dashboard/search views | Editing Fabric declarations |
|
||||
|
||||
The flow is:
|
||||
|
||||
```text
|
||||
repo-local fabric/*.yaml
|
||||
|
|
||||
v
|
||||
railiance-fabric validate/export
|
||||
|
|
||||
v
|
||||
State Hub graph read model
|
||||
|
|
||||
v
|
||||
dashboard, search, planning, progress links
|
||||
```
|
||||
|
||||
## Export Shape
|
||||
|
||||
The CLI emits `FabricGraphExport` JSON:
|
||||
|
||||
```bash
|
||||
railiance-fabric export --format json
|
||||
```
|
||||
|
||||
Schema: `schemas/state-hub-export.schema.yaml`
|
||||
|
||||
Top-level shape:
|
||||
|
||||
```yaml
|
||||
apiVersion: railiance.fabric/v1alpha1
|
||||
kind: FabricGraphExport
|
||||
nodes: []
|
||||
edges: []
|
||||
```
|
||||
|
||||
Node fields:
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `id` | Stable graph id from declaration metadata. |
|
||||
| `kind` | Declaration kind: service, capability, interface, dependency, or binding. |
|
||||
| `name` | Human-readable name. |
|
||||
| `repo` | Owning repo slug. |
|
||||
| `domain` | Owning domain slug. |
|
||||
| `lifecycle` | Declaration lifecycle. |
|
||||
|
||||
Edge fields:
|
||||
|
||||
| Field | Meaning |
|
||||
|-------|---------|
|
||||
| `from` | Source node id. |
|
||||
| `to` | Target node id. |
|
||||
| `type` | Relationship type, such as `provides`, `exposes`, `available_via`, `consumes`, `binds:exact`, or `uses_interface`. |
|
||||
|
||||
## Proposed State Hub Read Model
|
||||
|
||||
Add a State Hub ingestion endpoint or job that stores the latest graph export
|
||||
per source repo:
|
||||
|
||||
```text
|
||||
POST /fabric/graph-exports
|
||||
```
|
||||
|
||||
Suggested payload:
|
||||
|
||||
```json
|
||||
{
|
||||
"repo_slug": "railiance-fabric",
|
||||
"commit": "<git-sha>",
|
||||
"generated_at": "2026-05-17T00:00:00Z",
|
||||
"graph": {
|
||||
"apiVersion": "railiance.fabric/v1alpha1",
|
||||
"kind": "FabricGraphExport",
|
||||
"nodes": [],
|
||||
"edges": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Suggested storage:
|
||||
|
||||
```text
|
||||
fabric_graph_exports
|
||||
id
|
||||
repo_id
|
||||
commit
|
||||
generated_at
|
||||
graph_json
|
||||
created_at
|
||||
|
||||
fabric_graph_nodes
|
||||
export_id
|
||||
graph_id
|
||||
kind
|
||||
name
|
||||
repo_slug
|
||||
domain_slug
|
||||
lifecycle
|
||||
|
||||
fabric_graph_edges
|
||||
export_id
|
||||
from_graph_id
|
||||
to_graph_id
|
||||
edge_type
|
||||
```
|
||||
|
||||
The normalized node/edge tables are optional at first. State Hub can begin with
|
||||
`fabric_graph_exports.graph_json` and materialize node/edge tables once query
|
||||
needs harden.
|
||||
|
||||
## Linking To Existing State Hub Entities
|
||||
|
||||
State Hub should enrich graph nodes by matching:
|
||||
|
||||
- `node.repo` -> `managed_repos.slug`
|
||||
- `node.domain` -> `domains.slug`
|
||||
- workplan source links -> `workstreams.slug` or file-backed workplan index
|
||||
- progress events -> `repo_id` and related workstream/task when available
|
||||
|
||||
These links are annotations on the read model. They should never overwrite the
|
||||
repo-owned declaration files.
|
||||
|
||||
## Ingestion Rules
|
||||
|
||||
1. Reject exports that fail `schemas/state-hub-export.schema.yaml`.
|
||||
2. Record the source repo and commit for every accepted export.
|
||||
3. Replace the previous latest export for the same repo only after the new
|
||||
export validates.
|
||||
4. Preserve historical exports long enough to compare graph drift.
|
||||
5. Surface validation errors as State Hub progress events or human-review tasks,
|
||||
but do not auto-edit declaration files.
|
||||
|
||||
## Initial Dashboard Queries
|
||||
|
||||
State Hub should be able to answer:
|
||||
|
||||
- providers for a capability type
|
||||
- consumers of a capability or interface
|
||||
- unresolved dependencies
|
||||
- blast radius for an interface id or type
|
||||
- graph nodes by repo/domain/lifecycle
|
||||
|
||||
These are the same query families exposed locally by Railiance Fabric. The hub
|
||||
read model should match local answers for the same export.
|
||||
68
docs/type-catalog.md
Normal file
68
docs/type-catalog.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Core Type Catalog
|
||||
|
||||
The type catalog names the stable semantic capabilities and concrete
|
||||
integration surfaces used by Railiance Fabric declarations.
|
||||
|
||||
The catalog has two jobs:
|
||||
|
||||
- prevent ad hoc strings in repo-owned declaration files
|
||||
- give the future validator enough metadata to warn about mismatched
|
||||
capability/interface combinations
|
||||
|
||||
Machine-readable catalog files:
|
||||
|
||||
- `catalog/capability-types.yaml`
|
||||
- `catalog/interface-types.yaml`
|
||||
|
||||
## Capability Types
|
||||
|
||||
| Type | Lifecycle | Default Criticality | Default Data | Expected Interfaces |
|
||||
|------|-----------|---------------------|--------------|---------------------|
|
||||
| `runtime-secrets` | active | critical | secret | `openbao-kv-v2-mount`, `kubernetes-secret` |
|
||||
| `iam-profile-issuer` | active | critical | restricted | `oidc-discovery`, `http-api` |
|
||||
| `authorization-decision-service` | active | critical | restricted | `http-api`, `policy-package` |
|
||||
| `postgresql-database-service` | active | high | confidential | `database-connection`, `openbao-dynamic-credential-role` |
|
||||
| `redis-compatible-cache` | active | medium | internal | `database-connection`, `kubernetes-secret` |
|
||||
| `object-storage` | planned | high | confidential | `object-storage-bucket`, `http-api` |
|
||||
| `object-storage-credential-vending` | planned | high | secret | `http-api`, `openbao-dynamic-credential-role`, `sts-token` |
|
||||
| `audit-event-sink` | planned | high | confidential | `event-stream`, `http-api` |
|
||||
| `scope-generation` | active | medium | internal | `cli`, `http-api` |
|
||||
| `coordination-read-model` | active | high | internal | `http-api`, `event-stream` |
|
||||
|
||||
## Interface Types
|
||||
|
||||
| Type | Lifecycle | Category | Typical Auth |
|
||||
|------|-----------|----------|--------------|
|
||||
| `http-api` | active | api | `none`, `oidc`, `jwt`, `mtls`, `api_key` |
|
||||
| `oidc-discovery` | active | identity | `none` |
|
||||
| `kubernetes-secret` | active | kubernetes | `kubernetes_service_account` |
|
||||
| `kubernetes-crd` | active | kubernetes | `kubernetes_service_account` |
|
||||
| `helm-release` | active | deployment | `kubernetes_service_account` |
|
||||
| `cli` | active | tooling | `none`, `oidc`, `api_key`, `unknown` |
|
||||
| `database-connection` | active | data | `database_role`, `static_secret`, `openbao_token` |
|
||||
| `object-storage-bucket` | planned | storage | `sts_token`, `static_secret`, `openbao_token` |
|
||||
| `event-stream` | planned | events | `jwt`, `mtls`, `api_key`, `unknown` |
|
||||
| `policy-package` | active | policy | `none`, `oidc`, `jwt` |
|
||||
| `openbao-kv-v2-mount` | active | secrets | `kubernetes_service_account`, `openbao_token` |
|
||||
| `openbao-dynamic-credential-role` | active | credentials | `kubernetes_service_account`, `openbao_token` |
|
||||
| `sts-token` | planned | credentials | `oidc`, `jwt`, `mtls` |
|
||||
|
||||
## Validation Rules For T05
|
||||
|
||||
The graph validator should initially enforce:
|
||||
|
||||
- every `CapabilityDeclaration.spec.capability_type` exists in
|
||||
`capability-types.yaml`
|
||||
- every `InterfaceDeclaration.spec.interface_type` exists in
|
||||
`interface-types.yaml`
|
||||
- every `DependencyDeclaration.spec.requires.capability_type` exists in
|
||||
`capability-types.yaml`
|
||||
- every `DependencyDeclaration.spec.interface.type`, when present, exists in
|
||||
`interface-types.yaml`
|
||||
- provider interface types should be among the capability type's
|
||||
`expected_interface_types`, unless a declaration includes a documented
|
||||
compatibility note
|
||||
|
||||
The validator should warn, not fail, when a declaration uses a planned type in
|
||||
an active production dependency. That keeps early adoption possible while still
|
||||
surfacing rollout risk.
|
||||
40
docs/validator.md
Normal file
40
docs/validator.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Validator
|
||||
|
||||
The first validator entry point is:
|
||||
|
||||
```bash
|
||||
railiance-fabric validate <repo-or-file>...
|
||||
```
|
||||
|
||||
It accepts:
|
||||
|
||||
- a repo root containing `fabric/`
|
||||
- a `fabric/` directory
|
||||
- one or more declaration YAML files
|
||||
|
||||
The validator currently checks:
|
||||
|
||||
- YAML load errors
|
||||
- declaration schema conformance
|
||||
- duplicate graph IDs
|
||||
- unknown capability and interface types
|
||||
- missing service, capability, interface, dependency, and binding references
|
||||
- missing provider capabilities for dependencies
|
||||
- binding provider/dependency capability type mismatches
|
||||
- active production dependencies without `metadata.source_links`
|
||||
- active production dependencies whose providers do not cover the environment
|
||||
- service dependency cycles from binding assertions
|
||||
|
||||
Exit behavior:
|
||||
|
||||
- exits `0` when there are no errors
|
||||
- exits `1` when errors are present
|
||||
- exits `1` for warnings only when `--warnings-as-errors` is used
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=. python -m railiance_fabric.cli validate .
|
||||
PYTHONPATH=. python -m railiance_fabric.cli validate fabric/
|
||||
PYTHONPATH=. python -m railiance_fabric.cli validate examples/declarations/invalid/*.yaml
|
||||
```
|
||||
Reference in New Issue
Block a user