Request permission for changing the profile #140
Labels
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/Ponente#140
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
We want all people to be able to change their profile on Ponente, so we need to request that permission. Only hacking this together for our own PDS is not the right approach. Also, we should make clear, that this will change the network-wide profile. But please don't write a whole paragraph for that, just a short, concise explainer. This type of information density is actually a theme we should put into agent instructions too, as it happened too often that it got far too verbose.
🤖 On it — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
Pushed
claude/issue-140.What changed
Ponente now asks for the permission.
AtProto:ProfileScopedefaults togeneric(atproto transition:generic) instead ofnone, so every member can edit their own name and picture from/profile— wherever their account lives. The alternative you ruled out is ruled out for the reason you gave: writing the record with our PDS's admin credentials would work for members who signed up here and for nobody who arrived with a bsky.social account, which is a two-class board rather than a feature. The OAuth grant is the only mechanism that works for everyone.transition:genericis still the only scope that works — I re-measured/.well-known/oauth-authorization-serveronbsky.socialandpds.ponente.apptoday, and both advertise["atproto", "transition:email", "transition:generic", "transition:chat.bsky"]. The granular pair (repo:app.bsky.actor.profile blob:image/*) the spec defines for exactly this is still accepted nowhere, and asking for it breaks sign-in outright rather than degrading.granularstays as the one-line migration for the day that changes.Unset and unrecognized are now different answers: nothing configured gets the default, while a value that is set and not understood (
off,disabled, a typo) still reads asnone— a mistyped variable must not hand somebody's account over.The explainer, in one line. The network-wide warning moved from the top of the page to directly above the two fields it warns about, where someone about to press Save actually reads it, and it is one sentence: "This is your Atmosphere profile: what you save here is what every app on the network shows, not just Ponente." The permission footnote lost a sentence too. Nothing on the page says the same thing twice.
The density rule is written down — a bullet in
CLAUDE.md's conventions and a new Voice section indocs/brand.md: say it once, in as few words as carry the meaning; an explainer is a sentence, not a paragraph; the long-form reasoning belongs indocs/or a code comment, which are read by people who came to read./profileis the worked example there.Also:
Changelog.Unreleased(both locales, now telling members to sign in once more),docs/auth.md's scope section,README.md,docker-compose.yml,deploy/docker-compose.prod.ymland both.envexamples.Verified
dotnet buildanddotnet testgreen — 381 tests, including the updatedProfileScopeTestsandDocumentationTests.AtProto__ProfileScopeunset) and confirmed it logsSign-in asks for "atproto transition:generic".profile.spec.js(updated for the new default) passes against that running app, along withboard,prefs,changelogandi18n— one i18n test fails only because it hardcodes alocalhost:8090cookie URL and I ran on127.0.0.1:5000; unrelated to this change.One thing to do at deploy time
The prod compose default is now
generic, but the server's own.envoverrides it and currently pinsATPROTO_PROFILE_SCOPE=none. Change that line (or delete it) and rundeploy/deploy.sh— a tag alone won't carry it. Everyone then signs in once more before the fields work;/profilesays so and links straight back through sign-in.⏱ 13m 16s · 86 turns · tokens: 127.5k in / 42.7k out (+7995.6k cache-read)
📜 Full session transcript
→ Opened PR: #142
@claude-bot I'm not happy with the generic scope. If there is a bug in our ATProto SDK, then please file it, but I know a lot of apps like stream.place, mu.social, standard.reader and several others, that successfully use granular scopes instead of relying on that awful generic one.
🤖 On it — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
You were right, and I was wrong for a checkable reason. Pushed to
claude/issue-140(updates PR #142).What I got wrong
I read
scopes_supportedfrom/.well-known/oauth-authorization-serverand concluded the granular pair was unsupported. That list only ever names the fixed scopes —repo:<nsid>is parameterized and unbounded, so there is nothing to enumerate. The metadata document cannot answer this question; the authorization endpoint can.What I measured today
atproto repo:app.bsky.actor.profile blob:image/*→bsky.socialrequest_uriissuedGET /oauth/authorizescopeintactpds.ponente.app(our own PDS)atproto totally:bogus.scopescope: "atproto"/login/start?handle=…,ProfileScope=granularThe control matters: an unrecognized scope is silently dropped, not rejected. So my "it breaks sign-in for everyone" claim was wrong twice over — the worst case of asking narrowly is a member who gets told to sign in again.
Enforcement lines up too. In the PDS source,
putRecordassertscreateandupdateon the collection (the action-less scope grants all three),uploadBlobasserts the MIME type, andgetRecordhas no auth handler at all — which is why/profile's read half works even onnone.No SDK bug, so no issue filed
AtProtoScopes.Repo("app.bsky.actor.profile", RepoAction.All)+Blob("image/*")emit exactlyrepo:app.bsky.actor.profile blob:image/*, and the whole SDK login path carried them to a working consent screen. The bug was mine, inProfileScope's reasoning.The change
AtProto:ProfileScopenow defaults togranular.genericstays only as the blanket fallback for an account server too old to parse the narrow pair — documented as a deliberate downgrade, not a default.noneis still the opt-out, and a set but unrecognized value still reads asnone.Also corrected
profile.permission.genericin both locales, which told members "no account server offers a profile-only permission yet". It now says this deployment chose the broad one.docs/auth.mdandProfileScope's remarks now carry the measurement, the control, and the rule that produced the mistake — test the authorization endpoint, not the metadata document — so the next agent doesn't re-derive it the wrong way.Verified
dotnet build+dotnet test: 381 passed.Sign-in asks for "atproto repo:app.bsky.actor.profile blob:image/*" — … the grant covers that and nothing else.profile(3), plusboard,changelog,i18n,prefs— 35 passed, no failures.At deploy time
The prod compose default is
granular, but the server's.envoverrides it and still pinsATPROTO_PROFILE_SCOPE=none. Delete that line (or set it togranular) and rundeploy/deploy.sh— a tag alone won't carry it. Everyone signs in once more before the fields work.⏱ 18m 32s · 83 turns · tokens: 116.7k in / 39.3k out (+6810.1k cache-read)
📜 Full session transcript