Files
railiance-fabric/docs/ecosystem-registry-service.md

257 lines
12 KiB
Markdown

# 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 accepted Fabric graph snapshots, discovery evidence, and supporting
inventory.
The registry should not become the authoring surface for Fabric ownership or
boundaries. Repo-local `fabric/` files remain useful evidence, while financial
fabric membership, tenant boundaries, ownership, and cross-boundary utility
relations are resolved from accountability roots and accepted snapshots. 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}
GET /repositories/{repo_slug}/inventory
POST /repositories/{repo_slug}/snapshots
GET /repositories/{repo_slug}/snapshots
GET /repositories/{repo_slug}/snapshots/latest
GET /repositories/{repo_slug}/snapshots/diff
GET /search?q=jsonschema
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.
## First Service Slice
The initial implementation is deliberately dependency-light:
- `railiance_fabric.registry` owns SQLite persistence, snapshot validation, and
graph query helpers.
- `railiance_fabric.server` exposes a stdlib HTTP service.
- `railiance-fabric-registry` starts the service.
The first endpoint set is:
```text
GET /health
POST /repositories
GET /repositories
GET /repositories/{repo_slug}
GET /repositories/{repo_slug}/inventory
POST /repositories/{repo_slug}/snapshots
GET /repositories/{repo_slug}/snapshots
GET /repositories/{repo_slug}/snapshots/latest
GET /repositories/{repo_slug}/snapshots/diff
GET /search?q=jsonschema
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
GET /graph/dependency-path?service_id=flex-auth.api
POST /artifacts
GET /artifacts
GET /artifacts/{artifact_id}
GET /libraries
GET /libraries/{library_id}
GET /repositories/{repo_slug}/libraries
POST /repositories/{repo_slug}/libraries/cyclonedx
GET /exports/state-hub
GET /exports/backstage
GET /exports/xregistry
GET /exports/libraries/xregistry
```
The local CLI can feed a running registry:
```bash
railiance-fabric registry sync --repo-slug railiance-fabric .
railiance-fabric registry ingest-cyclonedx bom.json --repo-slug railiance-fabric
```
## 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.