Operator-curated teams for the teams rail (GitHub
GET /featured/teams
The featured_items placements with subject_kind = 'team' at
scope = 'org', in curation order — the slot that runs first in
the teams rail.
org rather than public is deliberate and it is what the write
endpoint already produces: POST /admin/featured writes
scope = 'org', and ADR 0065 defines org as the internal,
signed-in audience — which is exactly this rail’s audience, since
it renders only for a signed-in reader holding teams.read. A
public placement is a separate audience with a separate surface
(GET /featured) and is not read here.
A placement is not a grant. Featuring a team makes nothing
visible that was not already: the join drops any team that is not
live, the endpoint holds the same teams.read gate as the rest
of the teams rail, and each team’s picture goes through the
render-time hero re-check (#982) rather than the stored pointer,
so a hero whose asset stopped being public falls back to initials
here exactly as it does everywhere else.
Sits under /featured rather than /teams/featured so the path
cannot be confused with /teams/{id} by a router or a reader.
Authorizations
Section titled “Authorizations ”Responses
Section titled “ Responses ”Featured teams the caller may see, in curation order.
object
URL-friendly identifier, unique per origin server. Used in display and (eventually) federation actor URIs.
Example
aurora-rndExample
Aurora R&DSet on rows mirroring a federated team. NULL = locally owned.
The team’s picture (#982) — fetch it from
/assets/{hero_asset_id}/variants/col. NULL means the
client falls back to the team’s initials tile.
THIS IS THE RENDER ANSWER, NOT THE STORED SETTING. The
server re-derives it on every read, and it is absent
whenever the chosen asset no longer qualifies: set to
restricted, moved to another team, soft-deleted, or still
missing its col rendition. The stored pointer survives all
of those, so restoring the asset brings the picture back
without an admin re-picking it — but until then the wire
says “no hero” and the client paints initials.
One field rather than the setting/render pair Collection
carries, because the two cannot disagree PER READER here.
ADR 0088 gates a representative image per viewer; #982
narrows that for a team, because the followed-teams rail is
a navigation strip and a strip that shows some teams’
pictures and not others depending on who is looking is noise
rather than security. A team hero is admissible only if it
is public AND owned by that team — visible to everyone or
to no one — so a single field cannot be misread.
It does NOT federate: a local asset id names something that exists only on this server.
Direct parent teams (single hop). Empty for root teams.
Closure-walked ancestors live behind the listTeams
ancestor filter; this field is just the edges out of
the current node.
object
Direct memberships. Present on listTeams — the directory
card shows it (#684) — and ABSENT from getTeam.
The asymmetry is deliberate and is about staleness, not
taste. getTeam reads through an LRU that only the
team-row and parent-edge endpoints invalidate; adding a
membership does not, and never needed to, because nothing
membership-shaped was cached. A count served from that
entry would go stale the first time somebody joined. The
list path is uncached, so it can carry the number honestly.
A team page that wants the count reads
GET /teams/{id}/members, which it already fetches for the
member strip.
Live (non-soft-deleted) assets carrying this team_id — the
directory card’s “how much is in here” hint (#684). Present
on listTeams only, for the same caching reason as
member_count.
NOT visibility-filtered, deliberately. It counts assets
whose fields the caller may not read. That discloses
nothing new: this operation needs teams.read, so the
caller is signed in, and the authenticated asset predicate
already hands them restricted rows as placeholders — the
same number is reachable by paging
/assets?team_id=X. Filtering it would make the card
disagree with the page it links to.
Authentication required, missing, or invalid
object
Human-readable error summary
Example
the request could not be completedExample
{ "error": "authentication required: sign in and retry with a valid session or API token"}Authenticated but missing required capabilities
object
Human-readable error summary
Example
the request could not be completed