Skip to content

fix(registry): the public catalog defaults to verified-only - #953

Open
lilyshen0722 wants to merge 2 commits into
mainfrom
fix/registry-catalog-verified-only
Open

fix(registry): the public catalog defaults to verified-only#953
lilyshen0722 wants to merge 2 commits into
mainfrom
fix/registry-catalog-verified-only

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

fable-lead's "do now regardless of ratification" item, and a live leak.

What was exposed

GET /api/registry/agents returned 66 rows, 52 unverified — and among those, every internal and smoke-test agent we have ever created:

smoke-claude · demo-claude · demo-claude2 · demo-target · demo-clean2
smokea50698-{agent,scribe,helper,organic} · smoke-stub · test-agent · test-agent2
pod-architect · cl-critic · cl-strategist · claude-on-dev
sam-claude · sam-local-codex · nova-claude · hq-support · carol

search() already excluded ephemeral rows, so that was never the leak — these are ordinary registry documents from our own dev work.

The landing-page footer links this endpoint, so a logged-out visitor could browse the lot. It's also where the 2026-08-14 casualty picked the claude-code template that produced their dead seat.

The fix

verified is exactly the axis that separates them — every leaked row is commonly-community + unverified, while the curated set is verified. So the default flips to verified-only.

Nothing becomes unreachable. An explicit ?verified=false still works; only the default stops being "show everything we ever wrote."

The property worth testing

A garbage value resolves to the restrictive side. The old code treated unparseable as "no filter," i.e. show all — which is the wrong direction for a default on a public surface.

Scope

Stopgap, not the answer. ADR-022 (#950) replaces this surface with a persona catalog, at which point the curated set is the catalog by construction.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8

lilyshen0722 and others added 2 commits August 14, 2026 02:29
fable-lead's "do now regardless of ratification" item, and a live leak.

Measured 2026-08-14: GET /api/registry/agents returned 66 rows, 52 unverified
— and among those were every internal and smoke-test agent we have ever
created: smoke-claude, demo-claude, demo-claude2, demo-target, demo-clean2,
the smokea50698-* family, smoke-stub, test-agent, test-agent2, plus our own
working seats pod-architect, cl-critic, cl-strategist, claude-on-dev,
sam-claude, sam-local-codex, nova-claude, hq-support and carol.

`search()` already excluded ephemeral rows, so that was never the leak — the
internal rows are ordinary registry documents from our own dev work. The
landing-page footer links this endpoint, so a logged-out visitor could browse
the lot, and it is where the 2026-08-14 casualty picked the `claude-code`
template that produced their dead seat.

`verified` is exactly the axis that separates them: every leaked row is
commonly-community + unverified, while the curated set is verified. So the
default flips to verified-only.

Nothing becomes unreachable — an explicit ?verified=false still works. Only
the default stops being "show everything we ever wrote." A garbage value
resolves to the RESTRICTIVE side, which is the property worth testing: the old
code treated unparseable as "no filter", i.e. show all.

Stopgap, not the answer: ADR-022 (#950) replaces this surface with a persona
catalog, at which point the curated set is the catalog by construction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8
… filter

Replaces this branch's first attempt, which CI correctly rejected.

**Why the filter was wrong.** Defaulting the catalog to verified-only broke
`self-serve-install.test.js` — `public-marketplace-bot` is a legitimately
published third-party agent and is also unverified. The filter would have
hidden real publishers in order to hide our fixtures. `verified` is a TRUST
signal, not a visibility one, and the junk is not distinguishable by schema —
it is distinguishable by being OURS.

**The right lever already exists.** `ephemeral` means exactly "private to its
owner; getByName still resolves it, marketplace browse does not"
(AgentRegistry.search:167 filters it; ADR-006 self-serve rows use it for the
same reason). Our test seats fit that definition, so this is a data
correction, not a new concept — and no code change at all.

Names are enumerated, never pattern-matched. A regex over agent names would
eventually swallow a real user's agent called "demo-something", and the blast
radius of a wrong guess is a publisher silently delisted.

**The dry run found the list is INCOMPLETE, and that is the finding.** All 21
named rows exist and are unmarked — but the catalog would still hold ~28 more
internal rows afterwards: fc-verify, target, filebot, laptop-codex,
cloud-codex, duo, pixel-stub, lily-live, solo, diana, codex-impl, bob, alice,
clark, xu-claude-code-local, xu-codex-local, fable-lead, asker, reader,
codex-bot, echobot, aria, dex, ux-lead, sprint-impl, sprint-review,
local-claude — plus a row with an EMPTY agentName, which is data corruption
worth its own look.

Deliberately NOT applied. Sorting genuine catalog entries (pod-welcomer,
task-clerk, scout, claude-code, openclaw, webhook, newshound, …) from internal
seats across those 28 is a judgement call that delists a real publisher if
wrong, and the script's own contract is to leave unrecognised rows alone and
report them.

Next session: extend the list, dry-run, then --apply.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8
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.

1 participant