Skip to content
Registry StackDocsv0.25.0

Registry Discovery is an index

View as Markdown

Registry Discovery is a curated index of public Evidence Gateway and Registry Relay advertisements. It resembles a Yahoo-style directory: the catalog operator decides which public descriptions to index, and an application decides whether to trust and directly use a selected provider.

A small role between providers and applications

Section titled “A small role between providers and applications”

A provider publishes one closed JSON-LD description containing its public service advertisement. The catalog operator keeps an explicit allowlist of those description URLs and performs a bounded, one-shot build. The build records each origin URL, fetched-byte digest, and fetch time beside every indexed service record.

The profile uses a selected set of Data Catalog Vocabulary (DCAT) 3, DCAT-AP 3.0.1, and BRegDCAT-AP terms. Registry Discovery does not claim full DCAT-AP or BRegDCAT-AP conformance. Its offline tooling transforms only this pinned context and evaluates a selected Shapes Constraint Language (SHACL) subset; the service runtime does not perform RDF or SHACL processing.

An index record preserves a service’s public title, description, endpoint URL, roles, jurisdictions, profile identifiers, and product-specific capability identifiers. Evidence Gateway advertisements carry evidence type IDs. Registry Relay advertisements carry semantic class IDs or operation family IDs. A protected-only Relay may intentionally expose neither public capability collection.

The origin fields answer a narrower question than provider trust: which approved URL supplied these bytes for this index revision? They let an application retain provenance during selection. They do not attest that the provider, its endpoint, or its claims are trustworthy.

Registry Discovery is neither a provider federation nor an application gateway. It has no provider registration flow, trust store, authorization decision, credentials, request proxy, procedure model, ranking rule, writable catalog, or mutation route. Its fixed service surface is health, readiness, OpenAPI, service search, and evidence-type resolution.

That boundary keeps responsibility in the native products. Evidence Gateway remains the product that answers a fixed requirement and issues its signed, minimum-disclosure assertion. Registry Relay remains the product that exposes its governed protected read surface. Discovery only helps an application find their public advertisements.

For Evidence Gateway, an application resolves a requirement and jurisdiction to Evidence Type alternatives. Each alternative is an AND-list. The application searches and selects one provider for every required type. For Registry Relay, the application searches the public semantic class and operation family as one correlated tuple, then explicitly selects one record. Discovery preserves the complete Evidence resolution context, Relay tuple, catalog revision, and origin provenance.

After selection, the application makes a local native trust decision and calls the advertised endpoint directly with its Evidence Gateway or Registry Relay client. Discovery selection contains public metadata only. It cannot carry a trust anchor, credential, request, or response into that native call.

The same client workflow in Rust, Node.js, and Python

Section titled “The same client workflow in Rust, Node.js, and Python”

The maintained clients expose the same three steps in each language: resolve an Evidence requirement when needed, search with exact filters, then convert one exact record into a serializable selection. Node.js applications use @registrystack/discovery-client; Python applications use registry-discovery-client; Rust applications use registry-discovery-client.

const {
DiscoveryClient,
selectEvidenceAlternative,
selectEvidenceService,
validateSelection,
} = require('@registrystack/discovery-client');
const { EvidenceClient } = require('@registrystack/evidence-client');
const discovery = new DiscoveryClient('https://discovery.example/');
const resolved = await discovery.resolveEvidenceTypes({
requirementId: 'urn:example:requirement',
jurisdiction: 'urn:example:jurisdiction',
});
const context = selectEvidenceAlternative(resolved, 'urn:example:evidence-type-list');
for (const evidenceTypeId of context.evidenceTypeIds) {
const results = await discovery.searchEvidenceServices({
evidenceTypeId,
...(context.jurisdiction ? { jurisdiction: context.jurisdiction } : {}),
});
const record = await adopterChooseRecord(results.items);
const selection = selectEvidenceService(results, {
recordId: record.recordId,
evidenceTypeId,
resolution: context,
});
const checked = validateSelection(selection);
adopterTrust.requireEvidence(checked);
const evidence = new EvidenceClient({ baseUrl: checked.endpointUrl, ...nativeConfig });
if (!checked.evidenceResolution) throw new Error('missing Evidence resolution');
const prepared = evidence.prepare({
...localEvidencePolicy,
requirement: checked.evidenceResolution.requirementId,
evidenceType: checked.matchedCapability.id,
});
const verified = await evidence.requestAndVerify(prepared);
for (const claim of verified.evidence.supportedValues) {
console.log(claim.providesValueFor, claim.value);
}
}
from registry_discovery_client import (
DiscoveryClient,
select_relay_service,
validate_selection,
)
from registry_relay_client import RelayClient
discovery = DiscoveryClient("https://discovery.example/")
results = discovery.search_relay_services({
"semanticClassId": "urn:example:registered-business",
"operationFamilyId": "urn:example:consultation-list",
})
record = adopter_choose_record(results["items"])
selection = select_relay_service(results, {
"recordId": record["recordId"],
"capabilityMatch": {
"semanticClassId": "urn:example:registered-business",
"operationFamilyId": "urn:example:consultation-list",
},
})
checked = validate_selection(selection)
resource = adopter_trust.require_relay(checked)
relay = RelayClient(checked["endpointUrl"], authorization=native_authorization)
page = relay.list_records(resource, page_size=1)
if page["kind"] != "complete" or not page["value"]["items"]:
raise RuntimeError("Relay returned no records")
record = page["value"]["items"][0]
print(record["recordIdentifier"], record["domainData"])

The chooser is application-owned because Discovery does not rank results. The libraries validate the server response, complete Evidence alternative or Relay tuple, exact capability match, and any loaded selection before returning the native base URL. They do not decide whether the selected origin, issuer, operator, endpoint, or capability is trusted. Keep that decision in the application’s native Evidence or Relay trust configuration. Native definitions and local policy still supply Evidence purpose, audience, issuer and provider identity, configuration revision, selectors, and expected outputs. The JavaScript example reads values only from the payload that the native Evidence client has verified. Native Relay metadata supplies the concrete resource and operation. In the Python example, the adopter-owned trust mapping returns that reviewed resource identifier, and list_records performs the native Relay request. The returned record remains a Relay response, not Discovery metadata.

The provider maintains one public description URL. The catalog operator maintains a small explicit origins file, any evidence-type mappings, and an intentional build-and-restart loop. The application maintains native provider trust where it already belongs. No component must synchronize a central provider registration database, shared credentials, or a proxy policy.