ADR-0014 — a community's shared delivery points are readable over HTTP, per community, naming no one outside it
Date: 2026-10-01 Status: accepted
Context
ADR-0013 gave operators a CLI report of delivery points held by more than one active member,
reading the whole registry through the export grant, and left an HTTP route for a console to
be decided when one was wanted. The operator console — onboarding — now wants it (plan
decision F8, the requester, 2026-10-01): an operator correcting a member's POD needs to see
which of the community's points the registry will refuse (delivery_point_held, ADR-0012)
before a write is refused.
The console holds rec-registry.read, not the export grant. Giving it the export grant would
hand it every community's members; reading the export and filtering in the console would do
the same with extra steps.
Decision
- A per-community read:
GET /admin/communities/{ck}/delivery-points/duplicates, in the community's delivery-point read family, derivingreadlike every otherGETunder/admin. No new action or scope. - For each point an active member of the community holds that another active member also holds: the compared form, this community's holders by member key with the spelling each stored, a count of active holders in other communities, and the total.
- Holders outside the community are a count, never a member key or a community — the rule
the
delivery_point_heldrefusal already follows (ADR-0012), because which member of which other community holds a point is the enumeration disclosure the registry refuses everywhere. The CLI report (ADR-0013), behind the export grant, stays the cross-community view. - One definition of a duplicate: the route feeds one query's rows — every active holder of
every point the community's active members hold — to the CLI's finder,
find_duplicate_delivery_points, moved beside the compared form incore/delivery_point_id.py. The read and the report cannot disagree.
Consequences
An operator can see that a point is held elsewhere and not by whom. Resolving such a clash still needs whoever holds the export grant to run the CLI report, or the member to be asked, as the console's refusal message already says.
held_elsewhere is a count, and a count is a little information about other
communities: that some number of their active members hold this point. It is the least the
console needs to tell "two of ours" from "one of ours and someone else's", and it names
nobody.
duplicates becomes a fixed segment under …/delivery-points/: the access-log redaction
leaves this one path as it is, and the derivation tests carry it among the routes whose ids
are hostile. A future route under the same prefix has to do the same.