authn: name the grant scope dolt.sr.ht/DATABASES api-meta.json published the scope as lowercase "repos" while every other service on the instance publishes it upper case — git.sr.ht/REPOSITORIES, todo.sr.ht/TRACKERS, paste.sr.ht/PASTES, builds.sr.ht/JOBS. Upstream derives those from a GraphQL enum; this service has no @access directive to derive from, so the spelling was free and drifted. It matters because meta.sr.ht compares the string verbatim. Its oauth2 blueprint fetches every service's api-meta.json once at import time and validates a requested grant with `scope in service_scopes[svc]` — no case folding, no aliasing. So a grant typed by hand as dolt.sr.ht/REPOS:RO was refused, by analogy with every neighbouring service. DATABASES rather than REPOS: that is what the surface calls the object everywhere a user meets it — the GraphQL databases connection, the web pages, the docs. The storage layer underneath still says "repo"; renaming that is a deeper change and is not what a token grant names. No backward compatibility. auth.Grants.Has is a map lookup, so a PAT minted against the old spelling is refused rather than quietly honoured, and two table cases assert that instead of leaving it implied. Deploying this is two-sided: meta.sr.ht has to be restarted before anyone can mint a token carrying the new name. The federation gateway is unaffected — it forwards the client's Authorization header to each service and never reads api-meta.json. sr-ht-dolt-xic
doltsrht: serve /query and the api-meta.json beside it The schema is mounted where /mcp is and for the same three reasons — before web's same-origin group, before the cookie middleware, in a group of its own — plus one of its own: it answers anonymous callers, so it cannot ride core-go's WithSchema, whose router 401s an un-cookied request. It does need the config and database middleware, which is why the group sits below them. The file beside it is not optional. meta.sr.ht fetches api-meta.json from every service it discovers and iterates each one's scopes to build the personal-token page, so a service that mounts its own /query owes the instance this too — and the scope list is what makes "dolt.sr.ht/repos:RO" offerable there at all. The never-null rule that makes a mistake here a 500 for the WHOLE instance lives in ecore's apimeta; a test asserts the name this service advertises is the one authn.RepoScope enforces. README says what the surface serves and what it deliberately does not, and that `hut graphql dolt` needs the patched hut — upstream segfaults on any service outside its hard-coded list.