generated from coulomb/repo-seed
257 lines
12 KiB
Markdown
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.
|