chadtmiller.com/knotless
git that lives in your Atmosphere account
A private repository's records are named by their URI in its space
ClosedThis pull names a private repository's records by their full URI in the space. It resolves references in the public form as records are read (short_form::resolve_refs) and accepts typed public-form input through Target::named.
I read short_form.rs in full and the pull's description. I did not read the whole 1,850-line diff, so index.rs, the CLI entry points and the web changes are unreviewed. Of the six workflows (test, e2e, check, web, shots, lexicons, docs), check and web were still running and the rest queued when I looked, so none had a result.
short_form.rs is sound. It is idempotent, leaves non-DID authors and already-full URIs alone, and the tests cover each field and the cases it should leave. One thing to confirm: resolve_refs rewrites every subject that is a public-form at-URI with a DID author. That is right for pulls, comments and checks. If a record inside a space can carry a subject that is a repository record (dev.knotless.repo) or something else outside the space, it would be wrongly moved into the space. The pull says repo references keep their form, so please check that no space record kind does this.
Before merging, the pull's own caveats matter:
- Land it together with the next pull in the stack, which rewrites the existing index rows. Until then, old rows are keyed in the public form.
- Upgrade CLIs in the field first, because older ones can't read the full form.
- Wait for the checks to pass, especially
e2eandtest, which are the only ones that exercise the private flows.
This round I found nothing that has to change before merge. The pull names a private repository's records by their full URI in the space, resolves public-form references as records are read, and accepts typed public-form input through Target::named.
I did not re-read the whole diff this round. I re-read short_form.rs at the new head and it is unchanged in substance.
My earlier question about subject is still open. resolve_refs moves any public-form at-URI with a DID author into the space, including a subject that names a dev.knotless.repo record. The pull says repo references keep their form, and I know of no space record kind whose subject is a repo. The code has no guard, though. A one-line check that the collection isn't dev.knotless.repo would make that explicit. This is not a blocker.
Checks on this commit: docs passed. e2e and check were running, and test, web, shots and lexicons were queued, so there is no result yet. e2e and test are the only ones that exercise the private flows, so wait for them to pass before merging.
The caveats from the pull body still apply:
- Land it together with the next pull in the stack, which rewrites the existing index rows.
- Upgrade CLIs in the field first, because older ones can't read the full form.
Carried forward: the change this pull makes at b2dc7012673458ac9e99d639b3beb3585053cd5f is the one reviewed at ea543102bf33504731afa022d6bd7cfa2446e1d4, so that review stands. What is new comes from its base.
I found nothing that has to change this round. The pull names a private repository's records by their full URI in the space and resolves public-form references as records are read. Public-form input still works through Target::named.
What changed since my last review is a merge of space/aturi into space/mint. It brings in one commit, "Naming a runner from the pages syncs the repository again as it is next read", and a merge of main. I did not re-read the whole diff. This round's changes come from the base, and the pull's own change is the same as the one I reviewed at ea543102.
All seven checks on this commit (test, e2e, check, web, shots, lexicons, docs) were still queued when I looked, so there is no result yet. Only test and e2e run the private flows, so wait for them to pass before merging.
Two points from earlier still apply:
- The
subjectguard is optional.resolve_refswould move asubjectthat names adev.knotless.reporecord into the space. I know of no space record kind that does this, and a one-line collection check would make it explicit. - Land this together with the next pull in the stack, which rewrites the existing index rows. Upgrade CLIs in the field before it deploys.
Landed inside A private repository's records are named in full, and public-form references are moved, which carried these commits, as main 7dc0653f.

What changes
Stacked on Records in a space are read by their URI in full, as proposal 0016 names them, whose commit is the first here.
A private repository's records are named in full. A record in its space is named
at://<owner>/space/dev.knotless.space/<name>/<author>/<collection>/<rkey>wherever knotless gives one: the entriesTargetreads from the space, what a write returns (knotless pull,issue,comment,rerun), a runner's check URIs and a queue's failed checks, a repository's reference (Target::reference, and knotless-serve'sRepo::reference/uri), and the references new records hold (a comment'ssubject, a check'spull, a state'ssubject).Remote::uri_ofmints them;Remote::space_refis the space.Typed input in the public form still works.
Target::namedgives a URI in the public form the space of the repository it is about; every entry point that takes a record's URI calls it (show, comment, label, hide, set_state, merge, compare, pull_diff, retarget, edit/delete, react, enqueue, leave, revert, mergeable,rerun --pull). knotless-serve'sRepo::nameddoes the same where its handlers look up a record (getThread, getCheck, getAttachment, reactions, hides).queue::standingand thechecks --pullfilter compare withaturi::same.Records written before are read as ever.
crates/knotless/src/short_form.rsgives a reference in the public form the space it was read from, in the fields that name another record of the same space (subject,subject.uri,pull,reply,review,reverts,check,batch[].pull,checks[].check). It runs on every recordRemotereads from a space, and on every record the index takes in from one. Typed text, as a body'sFixes, is not touched.The index keys space records by their full URI.
put_at/delete_atkey a record from a space in full;read_of,maybe_memberandPURGEbuild the full URI fromspace_record; a pull'shead.repo.uriin the public form is given the space the index keeps that repository's record in (new indexspace_record_key).Index::repofinds a repository by either form, andactor_reposreturns each one's URI.Pages.
recordOfinweb/src/lib/format.tsreads either form, foritemHref,checkHrefandkindOf.The answers check holds a URI in full to its public form: the harness's
@atproto/lexiconknows only the public at-uri grammar, while the spaces alpha's validator, which checks the records written, knows both.Why
A private repository's records named in the public form lose the space they are in, can name two records in two spaces alike, and 404 at the author's PDS (
repo.getRecord), as at://did:plc:bcgltzqazw5tb6k2g3ttenbj/dev.knotless.pull/3mzbv3emkc72b in hetzner-infra does. Proposal 0016 names them with every segment through the rkey.Resolving references as they are read, rather than comparing URIs loosely everywhere, keeps every comparison an exact string match, as it was, in the client, the runner, the queue and the index's joins.
How it was checked
Unit tests:
short_form(each field, lists and objects, what is left),index::records_in_a_space_are_kept_by_their_full_uri(keys, resolved subject, head repository found in its space or left,repoby either form, deletion). The private flows over the spaces alpha in thetestande2echecks run the rest.Shortcomings
forkOf,transfer, a star's subject) keeps the form it was written in: readers match it by owner and key.Changeset: added (
.changeset/space-record-uris-full.md).Review
The design:
short_form::resolve_refsatRemote::parseandIndex::put_at, andTarget::namedat the entry points. Thenindex.rs.🤖 Generated with Claude Code