Skip to content

feat(discovery): add a small immutable Registry Discovery index - #748

Open
jeremi wants to merge 9 commits into
mainfrom
feat/federation-v1
Open

feat(discovery): add a small immutable Registry Discovery index#748
jeremi wants to merge 9 commits into
mainfrom
feat/federation-v1

Conversation

@jeremi

@jeremi jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member

Summary

Replace the managed Federation V1 direction with Registry Discovery: Evidence
and Relay publish deterministic public descriptions, a catalog operator runs a
one-shot build from approved URLs, and a read-only service supports exact
search and evidence-type resolution from one immutable index.

Discovery is a curated index. The adopter remains responsible for native
Evidence or Relay trust and invokes the selected provider directly.

Scope

  • Closed registry-discovery-v1alpha1 JSON-LD provider-publication profile.
  • Offline RDFLib/pySHACL conformance oracle and Draft 2020-12 schema/Rust
    parity corpus.
  • Deterministic Evidence and Relay public-description generation and serving.
  • Bounded approved-origin build and immutable index.
  • Health, readiness, OpenAPI, exact service search, and evidence-type
    resolution only.
  • Rust, Node.js, and Python clients for bounded search, resolution, and inert
    exact selection, with no native invocation or trust ownership.
  • Checksum-covered Node.js and Python release artifacts with installed-package
    smoke tests and exact npm/PyPI promotion from candidate bytes.
  • Aggregate query, response-media, URL, method, shutdown, and blocking-work
    limits enforced consistently across the server, client, schemas, and
    generated OpenAPI.
  • One Evidence and one Relay local acceptance journey, plus a clean-checkout
    adopter tutorial exercised in CI.

Non-goals

  • No scheduler, harvester, writable database, hot reload, catalog mutation,
    ranking, keyword search, pagination, aggregate catalog, or native proxy.
  • No Discovery trust-store schema, credentials, authorization policy,
    provider routing, registration workflow, or Evidence procedure.
  • No Discovery runtime installer or OCI image in this change.

Refactor record

The file-level current-PR decision record is
products/discovery/SALVAGE-LEDGER.md. Deferred but
useful work is recorded in
products/discovery/FUTURE-WORK.md, not left as dormant
production code.

Architecture decisions

The approved boundary and standards decisions are recorded in
products/discovery/DECISIONS.md. Discovery remains a curated
index, provider descriptions remain owned by Evidence and Relay, exact
capability bindings remain distinct in RDF and the runtime index, and index
changes remain an explicit build-and-restart operation.

Security notes

  • Descriptions have one pinned local JSON-LD context and a closed strict
    parser. No remote context, RDF graph, schema, SHACL, link, or vocabulary is
    resolved at runtime.
  • Evidence and Relay descriptions are closed public projections. Tests reject
    capability drift, prove private configuration cannot enter the publication,
    and preserve exact capability correlation through distinct binding IDs.
  • Provider description routes serve only the packaged bytes without
    authentication, source access, signing, or audit work. Relay tests prove
    even a malformed bearer cannot turn that public route into authentication.
    The Relay exception is scoped to discovery-description; a regression test
    preserves supplied-bearer authentication for every other public artifact.
  • The build owns exact approved HTTPS target, redirect, proxy, private-network,
    resource-bound, provenance, and atomic-write controls.
  • Discovery output cannot create native trust or cause credentials or provider
    traffic before the adopter's existing local acceptance.
  • Problems and diagnostics are value-free and bounded.

Security traceability: products/discovery/contracts/security-invariant-matrix.yaml.

Remaining risks

  • The profile is v1alpha1 and pre-1.0. Adopters must pin it and coordinate
    profile or wire-contract upgrades.
  • TLS and approved origins confine collection, but Discovery does not certify a
    provider, claim, or authorization decision. Consumers must keep their native
    Evidence or Relay trust configuration authoritative.
  • Origin and mapping freshness is operationally managed through explicit
    rebuild and restart. There is intentionally no scheduler or hot reload.

Verification

[x] cargo fmt --all -- --check
[x] cargo check --locked --workspace --all-targets
[x] cargo clippy --locked --workspace --all-targets -- -D warnings
[x] cargo test --locked --workspace
[x] ~/.cargo/bin/cargo-deny check
[x] products/discovery/scripts/check-contracts.sh
[x] products/discovery/scripts/test-http.sh
[x] products/discovery/scripts/test-adopter-tutorial.sh
[x] products/evidence/scripts/check-contracts.sh
[x] products/evidence/scripts/check-source-neutrality.sh
[x] products/evidence/scripts/check-verifier-portability.sh
[x] products/relay-v2/scripts/check-contracts.sh
[x] products/relay-v2/scripts/check-authoring-schema.sh
[x] products/relay-v2/scripts/test-http.sh
[x] products/identifiers/scripts/check.sh
[x] Evidence and Relay Node clients: npm ci, build:debug, test, check:types
[x] Discovery Node and Python clients: build, tests, generated types, installed-package smokes
[x] Registry release plan, candidate inventory, and client-package promotion tests
[x] python3 .github/scripts/test_ci_changes.py
[x] cd docs/site && npm test
[x] cd docs/site && npm run check

Comment thread crates/registry-federation-client-py/tests/python/bootstrap.py Fixed
Comment thread crates/registry-evidence-client-node/federation.js Fixed
Comment thread crates/registry-evidence-client-node/federation.js Fixed
Comment thread crates/registry-evidence-client-node/federation.js Fixed
Comment thread crates/registry-evidence-client-node/federation.js Fixed
Comment thread crates/registry-evidence-client-node/federation.js Fixed
Comment thread crates/registry-federation-client-node/index.js Fixed
Comment thread crates/registry-evidence-client-node/__test__/federation.test.js Fixed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ee22934df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-federation/src/startup.rs Outdated
Comment thread AGENTS.md Outdated
Comment thread crates/registry-federation-client-core/src/trust.rs Outdated
Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
Comment thread crates/registry-federation/src/query.rs Outdated
Comment thread crates/registry-federation-client-core/src/model.rs Outdated
Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
Comment thread crates/registry-federation/src/query.rs Outdated
Comment thread crates/registry-federation/src/query.rs Outdated
Comment thread crates/registry-evidencectl/src/federation.rs Outdated
@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1699de0c09

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-federation/src/query.rs Outdated
Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
Comment thread crates/registry-federation/src/server.rs Outdated
Comment thread crates/registry-federationctl/src/main.rs Outdated
Comment thread crates/registry-federation-client-py/src/lib.rs Outdated
Comment thread crates/registry-federation/src/query.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e852af8644

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
Comment thread crates/registry-federation/src/query.rs Outdated
Comment thread crates/registry-federation/src/compiler.rs Outdated
Comment thread crates/registry-federation/src/contracts.rs Outdated
Comment thread crates/registry-federation/src/compiler.rs Outdated
@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@codex review

1 similar comment
@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2cd82520ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
Comment thread crates/registry-federation/src/query.rs Outdated
Comment thread crates/registry-federation/src/contracts.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread crates/registry-federation-client-core/src/model.rs Outdated
Comment thread crates/registry-federation/src/compiler.rs Outdated
Comment thread crates/registry-federation/src/contracts.rs Outdated
Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d60a4e14e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
Comment thread crates/registry-federation-client-core/src/model.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread crates/registry-evidence-client/src/federation.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@codex review

@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

CI update: every Federation, Rust, native binding, docs, security, contract, tutorial, fuzz, and source-proof check passed on 6338f25. The only failure is release/scripts/registry-release validate-current: the released v0.21.0 manifest records the pre-#749 identifier-catalog digest while current main contains the regenerated catalog. This is tracked separately in #761. I am intentionally not rewriting the historical v0.21.0 manifest or creating a release as part of this PR.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6338f253e3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-federation/src/query.rs Outdated
Comment thread crates/registry-federation-client-core/src/model.rs Outdated
Comment thread crates/registry-federation/src/compiler.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread .github/scripts/ci_changes.py Outdated
Comment thread crates/registry-federation-client-py/src/lib.rs Outdated
@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@codex review

@jeremi
jeremi force-pushed the feat/federation-v1 branch from 655167c to 99edb59 Compare August 13, 2026 09:29
@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

Rebased onto current main, which now contains the identifier-catalog pin and runtime identity-label contract. The historical v0.21.0 manifest remains unchanged by this branch and registry-release validate-current now passes. Federation OCI labels were aligned with the new main contract; the full local OCI smoke and repeatability check pass. @codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 99edb598f9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-federation/src/compiler.rs Outdated
Comment thread crates/registry-federation/src/compiler.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread crates/registry-evidencectl/src/federation.rs Outdated
Comment thread crates/registry-federation/src/compiler.rs Outdated
Comment thread crates/registry-federation-client-core/src/directory.rs Outdated
@jeremi

jeremi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

Addressed all six current-head review findings in 7fd370f with focused regressions. Combined tests, clippy, formatting, generated-contract drift, sealed-package reproduction, source neutrality, and diff checks pass. The changes add no adopter parameters or workflow branches. @codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7fd370fc6b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/registry-federation/src/compiler.rs Outdated
Comment thread crates/registry-relayctl/src/federation.rs Outdated
Comment thread crates/registry-federation/src/tooling.rs Outdated
Comment thread crates/registry-federation/src/package.rs Outdated
Comment thread crates/registry-federation-client-core/src/model.rs Outdated
Comment thread crates/registry-federation-client-core/src/model.rs Outdated
Comment thread crates/registry-federation/src/contracts.rs Outdated
Comment thread crates/registry-federation/src/compiler.rs Outdated
Comment thread crates/registry-federation/src/server.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 44e6616b6b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +261 to +262
.map(|mapping| (mapping.mapping_id.as_str(), mapping))
.collect::<BTreeMap<_, _>>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve every authored mapping revision in diffs

When a project retains a superseded mapping beside the active revision for the same mappingId, this map silently overwrites one revision according to filename-derived ordering. If the unchanged superseded file sorts after the active file in both projects, changing the active mapping's alternatives, authority, jurisdiction, or constraints produces no mapping-semantic-change, hiding a governed change from federationctl diff; compare all authored revisions rather than collapsing them by immutable identity.

Useful? React with 👍 / 👎.

Comment on lines +285 to +286
.map(|vocabulary| (vocabulary.id.as_str(), vocabulary))
.collect::<BTreeMap<_, _>>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve every routing-vocabulary revision in diffs

Fresh evidence in the current implementation is that routing vocabularies are now compared, but collecting them by id still overwrites coexisting active and superseded revisions. Because the compiler permits inactive history to reuse a vocabulary identity, an unchanged superseded file that sorts after the active file can mask changes to the active vocabulary's values, lifecycle, title, or purpose entirely; compare the complete revision sets instead of retaining one record per ID.

Useful? React with 👍 / 👎.

Comment on lines +212 to +216
fn review_digest(path: &std::path::Path) -> Result<String, CliError> {
const MAX_AUTHORED_BYTES: u64 = 2 * 1024 * 1024;
let metadata = fs::symlink_metadata(path)
.map_err(|_| CliError::Tooling(registry_federation::tooling::ToolingError::Read))?;
if !metadata.file_type().is_file() || metadata.len() > MAX_AUTHORED_BYTES {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept complete registration files in review-digest

When an imported Evidence registration is larger than 2 MiB but within the compiler's 16 MiB bound—for example, one carrying the schema-permitted provider classifications—federationctl check accepts it, but the mandated review-digest step rejects it before parsing. Operators therefore cannot calculate the revision and approval digest needed to package a registration the authoring workflow accepts; use the compiler's authored-file bound here as well.

Useful? React with 👍 / 👎.

Comment on lines +379 to +380
|| publication.registry_identifier.is_some()
|| publication.authority_id.is_some() =>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject Relay-only fields in Evidence publications

When an Evidence publication also supplies authoritativeScope, publicSemanticClasses, or publicOperationFamilies, this branch rejects the other Relay-only fields but allows these three through. import-service consequently reports success and writes a mixed-kind registration that the compiler rejects on the next check; enforce the same complete service-kind closure promised by the publication schema before creating project files.

Useful? React with 👍 / 👎.

Comment on lines +350 to +352
match publication.service_kind {
ServiceKind::Evidence
if publication.issued_by.is_none()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate provider-classification bounds during import

For an Evidence publication, this validation never checks providerClassifications, so inputs with more than 32 classification keys, more than 100 values under a key, or malformed classification identifiers are accepted and written to the project. The compiler then rejects the newly imported registration, making import-service claim success for an artifact that violates the publication schema; apply the publication's structural classification bounds before writing either output file.

Useful? React with 👍 / 👎.

Comment on lines +452 to +453
} else {
(DiffProminence::LabelOnly, "label-only-change")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Classify approval and provenance changes as review-required

When a valid service revision changes only review or provenance fields such as approval, registrationRevision, sourceRevision, sourceDigest, sourceOrganization, submissionReference, or importerId, neither comparison branch examines them and the change falls through as label-only-change. In particular, an approval renewal or replacement is presented as cosmetic even though it changes the governance material consumed by production packaging; classify these fields as review-required rather than label-only.

Useful? React with 👍 / 👎.

Comment on lines +233 to +235
pub fn from_json(bytes: &[u8]) -> Result<Self, FederationClientError> {
if bytes.len() > 1024 * 1024 {
return Err(FederationClientError::Configuration);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Size trust documents for the accepted entry count

When a trust store contains two individually valid near-maximum entries, their combined JSON can exceed 1 MiB because each entry permits 100 jurisdictions and 100 required conformance URIs of up to 4,096 bytes. from_entries accepts as many as 1,000 such entries, but from_json—which is also the construction path used by the Python and Node bindings—rejects this much smaller valid store before parsing; derive the aggregate bound from the accepted entry shape/count or impose the same bound on every constructor.

Useful? React with 👍 / 👎.

jeremi added 3 commits August 14, 2026 18:57
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
@jeremi
jeremi force-pushed the feat/federation-v1 branch from 44e6616 to d0214b2 Compare August 14, 2026 12:04
@jeremi jeremi changed the title feat(federation): implement managed Federation V1 feat(discovery): add a small immutable Registry Discovery index Aug 14, 2026
Comment thread products/discovery/scripts/test_standards_oracle.py Fixed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d0214b2edd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +423 to +425
let mut rendered = canonicalize_json(&value)?;
rendered.push(b'\n');
Ok(rendered)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the description bound while rendering

When a constructed description uses otherwise valid collection and string limits, render_description can return more than MAX_DESCRIPTION_BYTES because only parse_description enforces the 1 MiB aggregate bound. For example, one service may contain 128 jurisdictions, conformance identifiers, and evidence types of up to 4,096 characters each, yielding packaged provider bytes that the same profile parser—and therefore discoveryctl build—immediately rejects; enforce the byte limit before returning rendered output or constrain construction so every rendered description can be parsed.

Useful? React with 👍 / 👎.

Comment on lines +383 to +384
if query.len() > MAXIMUM_QUERY_BYTES {
return Err(DiscoveryClientError::Query);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Size queries for the published filter shape

Fresh evidence in the new Discovery surface is that the OpenAPI permits 100 values of up to 4,096 characters for each non-kind filter, but this 64 KiB aggregate check cannot serialize even one near-maximum 100-value filter (over 400 KiB), let alone combined filters. The maintained client therefore rejects a contracted request locally, and the server applies the same bound; increase the aggregate limit to cover the accepted shape or narrow the generated parameter contract.

AGENTS.md reference: AGENTS.md:L286-L290

Useful? React with 👍 / 👎.

Comment on lines +503 to +506
let loopback = matches!(
parsed.host_str(),
Some("localhost") | Some("127.0.0.1") | Some("::1")
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recognize bracketed IPv6 loopback hosts

When a provider publishes the schema-valid endpoint http://[::1]:8080, url::Url::host_str() returns the serialized host [::1], so this comparison against ::1 rejects it. This prevents Evidence or Relay from generating a valid local IPv6 publication despite the committed profile schema explicitly allowing [::1]; the same comparison in registry-discoveryctl/src/project.rs also rejects such origins under --allow-loopback, so both checks should use the parsed Host::Ipv6(...).is_loopback() representation.

Useful? React with 👍 / 👎.

Comment thread crates/registry-discovery/src/server.rs Outdated
Comment on lines +80 to +83
.route(HEALTH_ROUTE, get(health))
.route(READY_ROUTE, get(ready))
.route(OPENAPI_ROUTE, get(openapi))
.route(SERVICES_ROUTE, get(search_services))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject implicit HEAD methods

Fresh evidence beyond the earlier Federation finding is that the new Discovery router again uses Axum get(...) routes without explicit HEAD rejection. Axum dispatches HEAD to each GET handler and removes the body, so HEAD requests to the four GET paths return success even though the fixed route inventory and generated OpenAPI expose only GET; the method-not-allowed fallback is never reached, so reject HEAD explicitly or add it to and regenerate the public contract.

AGENTS.md reference: AGENTS.md:L286-L290

Useful? React with 👍 / 👎.

jurisdictions: &[String],
) -> Result<Vec<u8>, ArtifactError> {
let mut bindings = BTreeSet::new();
for resource in &registry.resources {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include public statistical dataflows in Discovery bindings

When a Relay contains a public statistical dataset, this projection inspects only registry.resources, so the dataset never contributes an Aggregate Data statistical-dataflow capability. The maintained labour-statistics acceptance project has resources: [] and a public dataset, meaning this code takes the empty fallback and publishes a Relay binding with no searchable capability even though its acceptance matrix requires the statistical-dataflow capability; derive bindings from public statistical_datasets as well as resource operations.

AGENTS.md reference: AGENTS.md:L60-L62

Useful? React with 👍 / 👎.

Comment on lines +133 to +135
match tokio::time::timeout(limits.request_timeout, exchange).await {
Ok(response) => response,
Err(_) => ProblemCode::Unavailable.response(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce request deadlines inside synchronous queries

When an anonymous search exercises a large index and many valid filter values, Directory::search_services and serde_json::to_vec execute synchronously during a single poll of next.run. Tokio's timeout cannot fire until that future yields, so a CPU-heavy query can run well past requestTimeoutSeconds and occupy a runtime worker despite this middleware promising a 503 deadline; make the query/serialization work cooperatively deadline-aware or run it behind a bounded execution mechanism that the timeout can actually preempt.

Useful? React with 👍 / 👎.

Comment on lines +52 to +55
pub origin_id: String,
pub origin_url: String,
pub origin_content_digest: String,
pub catalog_revision: String,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retain the origin fetch time in saved selections

When an application persists a ServiceSelection, it loses originFetchedAt even though the selected ServiceRecord contains it and the Discovery explanation explicitly says selections retain the origin fields so applications can retain provenance. Because catalogRevision deliberately excludes fetch provenance, a later fetch of identical bytes does not repair this omission; add the timestamp to ServiceSelection and copy it in select_exact, or weaken the public provenance claim.

AGENTS.md reference: docs/site/AGENTS.md:L25-L28

Useful? React with 👍 / 👎.

Comment thread crates/registry-discovery/src/model.rs Outdated
Comment on lines +515 to +520
pub fn valid_public_url(value: &str) -> bool {
if value.chars().count() > MAXIMUM_IDENTIFIER_CHARACTERS {
return false;
}
let Ok(url) = Url::parse(value) else {
return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject unnormalized public URLs before parsing

Fresh evidence in the new Discovery validators is that Url::parse follows WHATWG behavior and trims surrounding C0 controls/spaces and removes embedded ASCII tabs or newlines, while this function retains the original string in the index. Consequently an endpoint or origin URL such as "https://provider.example/catalog\n" can pass index validation and client protocol checks even though the normalized parsed URL differs from the published value; discoveryctl repeats the issue in valid_catalog_url, so reject whitespace and control characters before parsing in both paths.

Useful? React with 👍 / 👎.

Comment thread crates/registry-evidence/src/config.rs Outdated
Comment on lines +1058 to +1059
validate_string(&self.title, 1, 4096, "publication title")?;
validate_string(&self.description, 1, 4096, "publication description")?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate publication text with the shared profile rules

When publication.title or publication.description has surrounding whitespace or a non-NUL control character, these calls accept it because validate_string checks only byte length and NUL, but registry_discovery_profile::ServiceDescription later rejects it while rendering the mandatory catalog. Conversely, schema-valid multibyte text can exceed the byte count while remaining below the shared 4,096-character limit and is rejected here; apply the profile's scalar-count, trim, and control-character rules during configuration validation so accepted Evidence publication configuration can always be projected.

AGENTS.md reference: AGENTS.md:L144-L145

Useful? React with 👍 / 👎.

Comment on lines +205 to +207
if status.is_success() {
if content_type.as_deref() != Some(JSON) {
return Err(DiscoveryClientError::Protocol);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Compare response media types case-insensitively

When a conforming Discovery implementation returns Application/JSON or another case variation of the application/json or application/problem+json media type, this exact string comparison rejects the response as a protocol failure. HTTP media type type/subtype tokens are case-insensitive, and the Discovery server already applies eq_ignore_ascii_case to request content types; normalize or compare response media types the same way so the maintained client interoperates with compliant servers.

Useful? React with 👍 / 👎.

jeremi added 3 commits August 14, 2026 21:39
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2a2a77ab71

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +642 to +650
if publication.jurisdictions.is_empty()
|| publication
.jurisdictions
.iter()
.any(|value| !valid_global_identifier(value))
|| publication
.jurisdictions
.windows(2)
.any(|pair| pair[0] >= pair[1])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the publication jurisdiction limit

When publication.jurisdictions contains 129 sorted, distinct valid URIs, this condition accepts it and relayctl check reports success—the generated authoring schema is also unbounded—but artifact generation passes the collection to ServiceDescription::new, whose shared profile caps identifier collections at 128, so generation and packaging subsequently fail. Enforce the shared bound in the compiler and regenerate the strict authoring schema.

AGENTS.md reference: AGENTS.md:L64-L67

Useful? React with 👍 / 👎.

Comment thread crates/registry-evidence/src/server.rs Outdated
.route(EVIDENCE_ROUTE, post(create_evidence))
.route(EVIDENCE_BATCH_ROUTE, post(create_evidence_batch))
.route(DEFINITIONS_ROUTE, get(discover_evidence))
.route(DISCOVERY_ROUTE, get(discovery_description))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject HEAD on the new catalog route

When a caller sends HEAD /catalog.jsonld, Axum's get(...) router dispatches it to discovery_description and strips the body, returning success whenever publication is configured even though the generated Evidence OpenAPI and documented route inventory declare only GET; the method-not-allowed fallback is therefore bypassed. Add an explicit HEAD rejection as the Discovery router does, or add HEAD to the generated contract deliberately.

AGENTS.md reference: AGENTS.md:L286-L290

Useful? React with 👍 / 👎.

Comment on lines +83 to +85
"crates/registry-evidencectl/src/authoring.rs",
"crates/registry-evidencectl/src/build.rs",
"crates/registry-evidencectl/tests/production_build.rs",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Route fixture publication changes through Discovery CI

When a PR changes only crates/registry-evidencectl/src/fixtures.rs, which now supplies the Evidence binary to the editable-project compiler that emits catalog.jsonld, classify selects the Evidence and developer-tools jobs but leaves discovery_contracts false because this path is absent from the explicit provider inputs. A regression in this publication path can therefore skip the cross-product contract and adopter-journey gates that the tuple is intended to enforce; add this implementation path and a focused classifier case.

Useful? React with 👍 / 👎.

Comment thread docs/site/src/data/contracts.yaml Outdated
source_of_truth:
label: Relay V2 contract and runtime types
url: https://github.com/registrystack/registry-stack/blob/2573f77d0fb59cbdae10c3b554c1b2328eeb32be/crates/registry-relay-v2/src/contract.rs
url: https://github.com/registrystack/registry-stack/blob/e126c55a98507188e6a5eece818ebf67b3e5b9ed/crates/registry-relay-v2/src/contract.rs

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Cite only a main-reachable contract source

This public source-of-truth link pins e126c55…, which is reachable only from the review branch and not from pushed main; when the session commits are squashed or otherwise rewritten, the durable docs retain a review-only SHA that may become unavailable or stale. Point the source record at a main-reachable revision or a stable path instead.

AGENTS.md reference: AGENTS.md:L277-L279

Useful? React with 👍 / 👎.

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Comment thread crates/registry-discovery-client-node/__test__/surface.test-d.ts Fixed
Comment thread crates/registry-discovery-client-node/index.js Fixed
jeremi added 2 commits August 15, 2026 01:53
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1707444a9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const native = require('./index');

const MAX_JSON_DEPTH = 128;
const MAX_JSON_NODES = 100_000;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve large search responses through Node selection

When a valid search response contains more than 100,000 JSON nodes—for example, a few hundred Relay records with schema-valid metadata collections—searchServices can return it within the supported 16 MiB response limit, but selectExact immediately passes that same response through requestValue/cloneJson and raises a query error at this cap. This prevents the maintained Node client from completing its search-to-exact-selection flow for a contracted response; size the bridge for the accepted wire shape or avoid reconverting SDK-produced responses.

AGENTS.md reference: AGENTS.md:L77-L79

Useful? React with 👍 / 👎.

const MAXIMUM_TRUSTED_ROOT_CERTIFICATE_BYTES: usize = 4 * 1024 * 1024;
const MAXIMUM_JSON_DEPTH: usize = 128;
const MAXIMUM_JSON_NODES: usize = 100_000;
const MAXIMUM_JSON_STRING_BYTES: usize = 4 * 1024 * 1024;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve large search responses through Python selection

When maximum_response_bytes permits a valid result containing more than 4 MiB of string data—such as records aggregated from several near-maximum provider descriptions—search_services returns it because rust_to_python allows 16 MiB, but select_exact sends the same dictionary through python_to_json and rejects it at this smaller string budget. Align the inbound selection conversion with the supported response bound so every returned search response remains selectable.

AGENTS.md reference: AGENTS.md:L77-L79

Useful? React with 👍 / 👎.

fail-fast: false
matrix:
client: [evidence, relay]
client: [discovery, evidence, relay]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate Discovery publication jobs by candidate version

When this workflow is dispatched for a v0.21.1 candidate, verify sets client_registries to true because the registry-package threshold is v0.21.1, but the candidate inventory deliberately contains Discovery packages only from v0.22.0. This unconditional matrix therefore schedules a Discovery job whose validate-dist step fails on missing tarballs; the unconditional Discovery entry in the PyPI matrix fails similarly on missing wheels. Since the workflow accepts historical tags from v0.19 onward, include Discovery only when the candidate version reaches its v0.22.0 minimum.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants