docs(plans): plan the LookupResources list-visibility adoption
Implementation plan for bounding the repository-list visibility filter by the caller's grants, plus its docs/plans/README.md index row.
Problem. The listing route's denied branch walks the whole namespace to answer one page: per 9,998 repositories, one IAM ReadRelationships over up to 10,000 objects plus one GLAZ BatchCheck over the keys. Any authenticated caller can repeat it, and the load lands on IAM and GLAZ.
Plan. One LookupResources drain per list request for the caller's own direct grants, then candidate enumeration restricted to what it returns. BatchCheck still decides each candidate, so the visible set does not change. A drain naming the namespace or its organization ancestor leaves the set unrestricted: the probe reads the cached IAM resolver and the filter the uncached one, so a grant written inside one cache TTL denies at the probe and allows at every item. No grant means an empty 200 with no enumeration.
A lookup failure fails the list closed rather than falling back to the scan. Three fail-closed 503 arms do change behaviour and are named as accepted: a subject IAM will not resolve, a request reaching the branch with no identity, and a caller past either drain ceiling. The third hits a caller IAM did authorize, by their instance-wide grant count rather than by the namespace they asked for, so the plan says why 503 beats a truncated list.
Steps.
chore—internal/iamgainsLookupResourcesbehind aResourceLookupseam.chore—ListRepositoriesParamsgains an optionalIDsrestriction honored by both repository page statements.feat— the listing filter composes them, with the escape hatch, the drain ceiling, and the composition-root wiring.
Spec and ADR side are done. !2356 (merged) amended S09 and merged, so main describes the drain, both its arms, the ceiling's 503, and an acceptance criterion for the escape hatch. handbook!21010 merged too, so ADR-020 carries the RPC on the data path and ADR-021 records the adoption with its scan open question narrowed rather than retired. !2405 (merged) merged the S25 half. The one merge order left is !2343 (merged) (verdicts step 6), still open and holding unmerged changes to Step 3's files.
Related to https://gitlab.com/gitlab-org/ops/artifact-registry/-/work_items/969