chadtmiller.com/knotless
git that lives in your Atmosphere account
A private repository's owner can cancel its runs
MergedThis adds dev.knotless.cancel to the dev.knotless.space lexicon, so a PDS grants it to a private repository's owner at login. It also names the collections written in each space type once (nsid::SPACE and ORG_SPACE, via space::collections) and checks them in a unit test and a debug_assert! in Remote::apply. Finally, the CLI and MCP no longer tell a login that already asked for the scope that it is "older". That message now appears only when login_behind is true.
I read the whole diff and found nothing that needs changing:
- The 21-entry
SPACElist matches the lexicon's collections plus the newcancel. - The refusal wording branches correctly on
login_behindandin_space. - The docs and the changeset are updated as AGENTS.md asks.
check,lexiconsanddocspass.test,e2e,webandioswere still running when I looked, so I haven't seen their results. I didn't run the new unit tests myself.
One note for the merge: the fix only reaches the owner after publish-lexicons has run from main and they run knotless login again. The pull body already says this.
My earlier approval stands. Since then the only change is in knotless-mcp: grant now takes &dyn Fn() -> bool instead of impl FnOnce, and the caller and the unit test are adjusted to match. This does not change what grant does. The last test case no longer uses unreachable!(), but a message that isn't a scope refusal returns before the closure is called, so it still checks the same thing. I did not run the tests myself.
10 passed, 1 skipped
knotless run cancelon a private repository was refused for want of scope, and the CLI then said the login was older, which logging in again did not fix. The private repository's space type now listsdev.knotless.cancel, a test keeps every space write listed, and that refusal says what is true.Claude Opus 5.5 · high
What changes
The lexicon.
dev.knotless.spacelistsdev.knotless.cancel, besidedev.knotless.rerun, and its description says the owner's requests of its runners are kept there.dev.knotless.orgSpaceneeds nothing: knotless writes onlyorgMemberandorgAcceptancethere; a rerun or cancel of an organization's private repository goes in that repository'sdev.knotless.spacespace.What knotless writes in a space, named once.
nsid::SPACE(the 21 collections written in a private repository's space: its records, the forge's, reactions, checks, reruns, cancels, the organization's member records and its site) andnsid::ORG_SPACE, reached by space type throughspace::collections.Remote::apply, the one way the CLI, MCP, serve's gateway and the runner's deletes write in a space,debug_assert!s each write's collection is in its type's list (the runner'sReporter::putwrites onlydev.knotless.check). The audit foundcancelthe only one missing: releases and stars are refused on a private repository, and minutes, themes and profiles are public.The test.
oauth::tests::space_lexicons_list_every_collection_writtenfails when a collection in either list is missing from its type's lexicon, or when the gateway's scope names one in a space that is not in its list.The message. A refusal for want of scope said
your login is older than what knotless asks for nowwhatever the login asked. Now the CLI says that only when the login is behind (oauth::login_behind, the same check its end-of-command note makes). One that asked saysyour login asks for this, but your PDS did not grant it, and, for a write in a space (oauth::in_space), that a PDS grants writes in a space as the lexicon knotless publishes for its type listed them at login, soknotless loginagain grants it once that lists it. MCP's tools and resources say the same, throughServer::failedandServer::advise.Why
The CLI asks for each space type by name (
space:dev.knotless.space?authority=*&manage=…), and the authorization server grants the collections the type's lexicon lists at approval (pds.jsf0591fde, as the reference PDS does).d9ed4f9addeddev.knotless.cancelto the scope'srepo:list but not to the lexicon, so pds.js refused the create (checkSpaceScope). Tests log in with app passwords, so nothing caught it.Publishing
publish-lexiconspublishes the changeddev.knotless.spaceonce main's seven checks pass at the merge commit: it runs on a push to main that toucheslexicons/**, writing thecom.atproto.lexicon.schemarecord inlexicons.knotless.dev(deploy/README.md). No DNS change: the authority is unchanged. After it runs, a PDS that cached the old lexicon (pds.js keeps one an hour) reads the new one, and the owner logs in again (knotless login chadtmiller.com) to be grantedcancel.How it was checked
node harness/lexicons.mjspasses (style, and only grown from main). The unit tests inoauth.rs,cli.rsandknotless-mcp'slib.rsare left to CI.Shortcomings
The pages still answer any refusal for want of scope with
LOGIN_BEHIND(web.rs'sbehind, which has no viewer): unchanged here.