docs(specs): bound the S09 listing filter by the caller's grants
Rewrites the S09 repository-listing denied branch to bound the work by the caller's grants instead of the namespace size.
What changes
The handler asks IAM LookupResources for the caller's own direct assignment grants and restricts candidate enumeration to the returned object IDs. BatchCheck still decides each candidate, so the visible set is unchanged.
A drain that names the namespace or its organization ancestor leaves the candidate set unrestricted: the namespace-scoped Check reads the cached relationship path and the chunk reads do not, so a grant written inside one cache TTL denies at the Check and allows at every item.
A caller with no grant is answered an empty 200 with no enumeration. A LookupResources failure answers 503, as the branch's other IAM and GLAZ calls already do. IAM authorizes the drain as a self-lookup against the forwarded end-user JWT, so a subject it will not resolve that way also answers 503; an unresolvable subject is an empty page, not an error.
Why
Today one list request from a caller without a namespace role walks the whole namespace: per 9,998 repositories, one ReadRelationships over up to 10,000 objects plus one BatchCheck. Any authenticated caller can repeat it, and the load lands on IAM and GLAZ.
Sites touched
The sequence diagram's denied branch, the candidate-enumeration item, the evaluation-failure item, acceptance criterion 19, the LookupResources deferral paragraph, and the Resolutions entry on verdict rate bounding.
Merges before any step MR of the implementation plan (!2353 (merged)) opens.
Related to https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/969