Read-only access used to be enforced by the application. Somebody with a read-only role saw no controls, and the application refused their changes — but the rule lived only in the paths that remembered to check it.
It now lives in the database. A read-only member cannot record a change by any route: not through the interface, not by calling the API directly, not from a device syncing work recorded elsewhere. Every operational record is covered, with no exceptions to remember.
Read access is unchanged. A read-only member still sees everything their membership allows, which is the point of the role.
Nobody was affected: there are no read-only members on any account yet. This closes the gap before the first one is invited.