From 1a10585c038735900d867fd102ae25072c63841f Mon Sep 17 00:00:00 2001 From: Jeremi Joslin Date: Thu, 2 Jul 2026 09:59:13 +0700 Subject: [PATCH] Document registry identifier contracts Signed-off-by: Jeremi Joslin --- .../src/content/docs/reference/contracts.mdx | 2 +- .../src/content/docs/reference/errors.mdx | 2 +- lab/docs/README.md | 4 +- lab/docs/domain-consolidation-plan.md | 128 ++++++++++++++++++ 4 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 lab/docs/domain-consolidation-plan.md diff --git a/docs/site/src/content/docs/reference/contracts.mdx b/docs/site/src/content/docs/reference/contracts.mdx index 252ffb84..74a50478 100644 --- a/docs/site/src/content/docs/reference/contracts.mdx +++ b/docs/site/src/content/docs/reference/contracts.mdx @@ -10,7 +10,7 @@ source_repos: - registry-manifest - registry-notary - registry-lab -last_reviewed: "2026-06-21" +last_reviewed: "2026-07-02" doc_type: reference locale: en standards_referenced: diff --git a/docs/site/src/content/docs/reference/errors.mdx b/docs/site/src/content/docs/reference/errors.mdx index 51755eec..3fa838a7 100644 --- a/docs/site/src/content/docs/reference/errors.mdx +++ b/docs/site/src/content/docs/reference/errors.mdx @@ -7,7 +7,7 @@ source_repos: - registry-notary - registry-relay - registry-platform -last_reviewed: "2026-06-20" +last_reviewed: "2026-07-02" doc_type: reference locale: en standards_referenced: [] diff --git a/lab/docs/README.md b/lab/docs/README.md index 19a6a69d..1888ae2a 100644 --- a/lab/docs/README.md +++ b/lab/docs/README.md @@ -13,7 +13,7 @@ available `just` commands. The tutorials below focus on one working path each. flowchart TD Root["Root README
setup, ports, just commands"] Ops["Operations posture lab contract
admin posture and credentials"] - Lab2["Lab 2 governed operations demo spec
signed config verification and apply"] + Lab2["Lab 2 governed ops
signed config verification and apply"] Tutorials["First credential tutorials
OpenCRVS, DHIS2, OpenFn"] Citizen["Citizen and wallet flows
OID4VCI and subject binding"] Agri["Agriculture demo specs
registry and consumer demos"] @@ -77,5 +77,7 @@ flowchart TD - [Evidence Gateway packs](evidence-gateway-packs.md): current pack IDs, binding IDs, identifier/demographic lookup support, and fast test commands. +- [Identifier domain consolidation plan](domain-consolidation-plan.md): deferred + plan to consolidate machine identifiers onto `id.registrystack.org`. - [Commons release cleanup plan](commons-release-cleanup-plan.md): maintainer cleanup plan for shared Platform, Notary, Relay, and Manifest release work. diff --git a/lab/docs/domain-consolidation-plan.md b/lab/docs/domain-consolidation-plan.md new file mode 100644 index 00000000..7b50f57d --- /dev/null +++ b/lab/docs/domain-consolidation-plan.md @@ -0,0 +1,128 @@ +# Identifier Domain Consolidation Plan + + + +**Status:** Deferred (planned, not executed) +**Created:** 2026-06-27 +**Origin:** Surfaced during the `id.registrystack.org` static resolver review. The resolver already publishes every identifier under `id.registrystack.org`; the registry-stack source still emits non-resolvable placeholder hosts. This plan captures the source-side consolidation so it is not lost. **Executing it is out of scope for the resolver review.** + +## Problem + +Registry-stack runtime code and committed artifacts emit machine identifiers (problem `type` URIs, JSON Schema `$id`, JSON-LD namespace prefixes, SHACL shape IRIs) under six domains that do not exist and never resolve: + +| Host | Occurrences | Used for | +| --- | --- | --- | +| `docs.registry-notary.dev` | 76 | Notary problem `type` URIs + doc links | +| `registry-relay.dev` | 46 | Relay problem `type` base, SHACL shape/namespace IRIs | +| `schemas.registry-relay.org` | 9 | Relay JSON Schema `$id`, provenance context `dg` prefix | +| `registry-notary.dev` | 9 | Notary identifiers / spec prose | +| `registry-manifest.dev` | 7 | Manifest identifiers | +| `registry-platform.dev` | 6 | Platform (httpsec) problem `type` URIs | + +153 occurrences across **61 files**. A consumer that dereferences any of these gets nothing. + +The resolver at `apps/registrystack-id` already re-homes all of these to `id.registrystack.org` in its generated output, so the *published* surface is correct. The gap is that the source of truth emits the placeholders, so the resolver is compensating by hand-copying and host-rewriting rather than mirroring what the services actually serve. + +## Target state + +A single canonical host for all machine identifiers: **`id.registrystack.org`**, using the path layout the resolver already defines. + +| Kind | Today (example) | Target | +| --- | --- | --- | +| Relay problem type | `https://registry-relay.dev/problems/...` | `https://id.registrystack.org/problems/registry-relay/...` | +| Notary problem type | `https://docs.registry-notary.dev/problems/...` | `https://id.registrystack.org/problems/registry-notary/...` | +| Platform problem type | `https://registry-platform.dev/problems/...` | `https://id.registrystack.org/problems/registry-platform/...` | +| Relay schema `$id` | `https://schemas.registry-relay.org//v1.json` | `https://id.registrystack.org/schemas/registry-relay//v1.json` | +| Provenance context `dg` | `https://schemas.registry-relay.org/provenance/v1#` | `https://id.registrystack.org/ns/registry-relay/provenance/v1#` | +| Relay SHACL namespace | `https://registry-relay.dev/ns#` | `https://id.registrystack.org/ns/registry-relay/...#` | +| Manifest identifiers | `https://registry-manifest.dev/...` | `https://id.registrystack.org/.../registry-manifest/...` | + +The target equals the resolver's current output, so consolidation makes the source mirror the resolver instead of diverging from it. + +**Explicitly NOT in scope (leave as-is):** + +- `registrystack.org`, `docs.registrystack.org`, `stats.registrystack.org`: real org/docs/stats hosts. +- `*.lab.registrystack.org` (17 hostnames): intentional lab/demo environment hosts under the real domain. +- Third-party hosts (`registry.npmjs.org`, `registry.scalar.com`, `spdci.org`, `iana.org`, `w3.org`, `json-schema.org`). + +## Decisions to settle before execution + +1. **URN problem types.** Federation problems use `urn:registry-notary:problem:federation:*` (and there are `urn:registry-notary:predicate:*` identifiers). URNs are non-resolvable by design, so they are not "fake hosts," but they are inconsistent with an HTTPS-resolvable scheme. Decide: harmonize federation/predicate URNs to `https://id.registrystack.org/...`, or keep URNs as a deliberate non-dereferenceable namespace. This is separable from the host consolidation and can ship later. +2. **Single source for the base.** Today the base host is scattered as literals (e.g. `registry-relay/src/error.rs:36 PROBLEM_TYPE_BASE`, `registry-relay/src/metadata/shacl.rs:1067`). Decide whether to introduce one shared constant/config per product so the host appears once. Recommended: yes, it makes this migration and any future move a one-line change. +3. **Relay schema/context: config vs artifact.** Relay provenance emission uses operator-configured base URLs (`config/provenance.rs`: `schema_base_url`, `context_base_url`), while the committed resource files (`resources/schemas/*`, `resources/jsonld/*`) hardcode `$id`/`dg`. Both must move to `id.registrystack.org`, and the lab configs that currently set placeholder bases must be updated too. +4. **Resolver follow-up.** Once the source emits `id.registrystack.org` natively, two resolver simplifications become possible: (a) `build.mjs` no longer needs to host-rewrite copied artifacts; (b) `scripts/check-upstream-artifacts.mjs` can tighten from "normalize `$id`/`dg`" to exact `$id` match. Track as a cleanup after this lands. + +## Scope inventory (61 files) + +**A. Runtime emitters (source of truth), edit directly (6):** + +- `crates/registry-relay/src/error.rs` (`PROBLEM_TYPE_BASE`) +- `crates/registry-relay/src/metadata/shacl.rs` (shape namespace IRI) +- `crates/registry-notary-server/src/lib.rs` +- `crates/registry-notary-server/src/openapi.rs` (problem `type` URLs in the generated spec) +- `crates/registry-platform-httpsec/src/lib.rs` +- `crates/registry-manifest-core/src/lib.rs` + +**B. Committed resource artifacts + hash pins (4):** + +- `crates/registry-relay/resources/schemas/entity-record/v1.json` (`$id`) +- `crates/registry-relay/resources/schemas/aggregate-result/v1.json` (`$id`) +- `crates/registry-relay/resources/jsonld/provenance/v1/context.jsonld` (`dg` prefix) +- `crates/registry-relay/resources/MANIFEST.toml`: re-pin the three SHA-256 values; a test re-hashes and asserts equality. Hash space documented in `decisions/wave-3-data-provenance.md` §10 (update the note if it cites the old host). + +**C. SHACL turtle (2):** + +- `crates/registry-relay/scripts/shacl/dcat-ap-catalog-smoke.ttl` +- `crates/registry-relay/scripts/shacl/bregdcat-ap-catalog-smoke.ttl` + +**D. Lab/operator config (9):** `lab/config/**` YAML setting placeholder base URLs. + +**E. Generated/derived: regenerate, do not hand-edit (~25):** + +- 14 insta snapshots: `crates/registry-relay/tests/snapshots/error_taxonomy__*.snap` (regenerate with `cargo insta accept`). +- Manifest golden JSON (3): `crates/registry-manifest-core/tests/fixtures/golden/example-civil-registration.*.json`. +- Relay VC fixtures (2): `crates/registry-relay/tests/fixtures/vc/{entity-record,aggregate-result}-v1/payload.json`. +- Generated OpenAPI: `products/notary/openapi/registry-notary.openapi.json` (regenerate from notary source). +- Binding tests with inline expectations: `products/notary/bindings/node/test/client.test.js`, `products/notary/bindings/python/tests/test_client.py`. +- Manifest CPSV-AP fixture: `products/manifest/fixtures/cpsv-ap/health-linked-child-support.cpsv-ap.jsonld`. + +**F. Test assertions with inline URL expectations, update with the source (Rust):** + +- `crates/registry-relay/tests/error_taxonomy.rs`, `vc_external_verifier.rs` +- `crates/registry-notary-client/tests/{client_contract,facade_contract}.rs` +- `crates/registry-notary-server/tests/standalone_http.rs` +- `crates/registry-platform-httpsec/tests/integration.rs` +- `crates/registry-platform-testing/tests/cross_crate_integration.rs` +- `crates/registry-manifest-core/tests/metadata_core.rs` + +**G. Docs/specs (4):** + +- `docs/site/src/content/docs/tutorials/verify-claim-registry-api.mdx` +- `products/notary/docs/release-notes.md` +- `products/notary/specs/federated-notary-manifest-spec.md` +- (plus the resolver-side docs already covered in the review) + +## Execution sequence + +1. **Settle the four decisions above** (URNs, shared constant, config vs artifact, resolver follow-up). +2. **Centralize the base** per product (optional but recommended) so the host is defined once. +3. **Edit the source of truth:** group A (runtime emitters), B (artifacts), C (ttl), D (config). Keep one host string per product. +4. **Re-pin hashes:** regenerate the three `MANIFEST.toml` SHA-256 values; update `decisions/wave-3-data-provenance.md` §10 if it names the old host. +5. **Regenerate derived artifacts** (group E): `cargo insta accept`, golden/fixture updates, OpenAPI regen. Never hand-edit these. +6. **Update inline test expectations** (group F) and docs/specs (group G). +7. **Verify:** full `cargo test` (workspace) green; docs site build green; then in the resolver run `npm run check:upstream` (should still pass), and afterward tighten it to exact `$id` match (decision 4). +8. **Land atomically** across `registry-relay`, `registry-notary-*`, `registry-manifest-*`, `registry-platform-*` so a single release never mixes old and new hosts. + +## Risks + +- **Hash re-pin is load-bearing.** Editing the three vendored artifacts breaks the `MANIFEST.toml` re-hash assertion until the pins are regenerated. Easy to miss; it is the first thing CI will fail on. +- **Snapshot/golden churn.** ~25 derived files change. Regenerate them with the proper tooling and review the diffs; do not hand-edit, or they will drift from source. +- **Atomicity.** A partial migration produces responses where, e.g., the problem `type` is `id.registrystack.org` but an embedded schema `$id` is still `schemas.registry-relay.org`. Land per-product changes together. +- **Already-issued references.** Any VC or problem document already emitted points at the old hosts. Because those hosts never resolved, external breakage is near-zero, but note it in release notes. +- **URN scope creep.** If decision 1 chooses to harmonize URNs, that expands the diff (predicate identifiers, federation problem types, their tests/snapshots). Keep it a separate, clearly-bounded follow-up. + +## Related + +- Resolver review: `apps/registrystack-id` (publishes `id.registrystack.org`). +- Drift guard added during the review: `apps/registrystack-id/scripts/check-upstream-artifacts.mjs` (`npm run check:upstream`). +- Problem-code accuracy corrections: `docs/site/src/content/docs/reference/errors.mdx`.