feat(registry): endorsed_by_publisher_member on discovered agents — option C from #3547#3565
Merged
Merged
Conversation
Contributor
|
Issue #3573 proposes Generated by Claude Code |
Closes #3547 (option C from the decision issue). Refs #3538 Problem 6. Discovered agents whose discovered_from.publisher_domain is claimed by an AAO member (member_profiles row with publishers[] entry where is_public=true) now surface a new optional endorsed_by_publisher_member field on /api/registry/agents. Mutually exclusive with member — registered agents never carry it. Three live cases that motivated this — agent.mamamia.com.au, gatavocom.sales-agent.setupad.ai, wheelrandom.sales-agent.setupad.ai — returned member: null even though the publisher that endorsed them via adagents.json is a member. The publisher-side trust signal was being thrown away by the response builder. Option B from #3547 (collapse to registered when agent_url is also discovered) was already correct. server/src/federated-index.ts:73-75 skips a discovered row when registeredAgents has the same agent_url — verified by the new agent_url claimed by both registered + discovered collapses to registered (option B) test. Inline comment added at the merge site documenting the existing behaviour. OpenAPI regen lands in a separate commit per repo hygiene.
…name required + describe Pre-review nit: slug + display_name were marked .optional() in EndorsedByPublisherMemberSchema, but the populating code at federated-index.ts:127-131 always sets them from non-optional member_profiles.slug / .display_name. Optional schema was a footgun for clients rendering display_name. Tighten to .required() and add .openapi descriptions per the same pattern as publisher_domain.
…ber field Mechanical regen via npm run build:openapi after rebase on main. Picks up the EndorsedByPublisherMember schema definition + reference + the updated member description that points to the new endorsement signal instead of referencing #3538 Problem 6 as a placeholder.
c157038 to
5a756d9
Compare
2 tasks
This was referenced May 1, 2026
This was referenced May 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3547. Refs #3538 Problem 6.
Three live discovered agents (`agent.mamamia.com.au`, `gatavocom.sales-agent.setupad.ai`, `wheelrandom.sales-agent.setupad.ai`) return `member: null` even though their `discovered_from.publisher_domain` is claimed by an AAO member. The publisher's `adagents.json` endorsement carries trust signal — response builder threw it away.
This PR ships option C from #3547: option A as the new field, option B as the collapse verification.
Option A — `endorsed_by_publisher_member` field
New optional field on `/api/registry/agents` response. Populated only when:
Mutually exclusive with `member` (registered agent never has both). Schema in `server/src/schemas/registry.ts` carries the `.openapi({ description })` so docs explain the relationship. Lookup happens in `server/src/federated-index.ts` over the same `memberDb.listProfiles({ is_public: true })` call we already make for registered agents — no extra DB round-trip.
Example:
```json
{
"agent_url": "agent.mamamia.com.au",
"source": "discovered",
"member": null,
"discovered_from": { "publisher_domain": "mamamia.com.au" },
"endorsed_by_publisher_member": {
"slug": "mamamia",
"display_name": "Mamamia",
"publisher_domain": "mamamia.com.au"
}
}
```
Agent stays `source: 'discovered'` — the agent itself didn't opt in. The endorsement is a publisher-side signal, not an agent claim.
Option B — collapse verification
(verified) registered row already wins when `agent_url` is also discovered. `server/src/federated-index.ts:73-75` skips a discovered row when `registeredAgents` already has the same `agent_url`. Inline comment expanded at the merge site documenting the existing behaviour, and the new test case `agent_url claimed by both registered + discovered collapses to registered (option B)` pins it so a future refactor can't quietly regress it.
What changed
Backwards compatibility
Non-breaking on the wire. Adds an optional field. Consumers ignoring unknown fields are unaffected. Consumers that previously read `member: null` and assumed "no member relationship" now have the additional `endorsed_by_publisher_member` signal available — strictly more information, never less.
Test plan
Stack ordering
Independent of #3540, #3541, #3542, #3543. Lands any time. Recommended after #3542 so the schema annotations from that PR are already in main.
Out of scope