chadtmiller.com/knotless
git that lives in your Atmosphere account
Repositories have websites, served on knotless.page
MergedAt this head the pull is only the first part of the feature: the design page docs/design/pages.md, its sidebar and index entries, and the dev.knotless.site lexicon. The knotless site and serve pulls from the body are not on feature/pages yet, so I reviewed what is there. The page is coherent. The handle-to-label scheme is injective and cannot collide with the did:plc form, and I found nothing wrong with the one-record-per-repo design or the lexicon. All seven checks were still queued when I looked, so none has run.
Notes, none of which block this:
- The body calls the client command
knotless site, but the design page saysknotless publish --site. Make them agree before the client pull lands. - The design page links to
../reference/cli.mdand../reference/workflows.mdfor the new flag, but it does not change either file. Update them when the client code lands (AGENTS.md asks for docs with the change). - The page refers to
deploy/README.mdfor certificates and DNS. The body says those changes are still to come, so that section needs to exist before this goes tomain. - When the client and serve code reach this branch, check that publishing rejects
fallbackornotFoundpaths that are not infiles. The lexicon cannot say that itself.
At this head feature/pages now carries the design page and lexicon plus the client: knotless site (site.rs, cli.rs, the SiteRecord types), a change file, a docs/reference/cli.md entry and CLI tests. I read all of it except tests/cli.rs, the lexicon, the design page and the docs-site config. I read those in round 1, or they only add entries. Nothing in the code looks wrong to me.
What my earlier review asked for:
knotless sitevspublish --site: done. The design page no longer mentionspublish --site.cli.mddocumentation: done, with asiterow.fallbackandnotFoundmust be files of the site: done.deploychecks both before any upload, and the check happens before the network calls.deploy/README.mdsection: still open. The design page points at it, and the body says thedeploy/changes are still to come. It must exist before this goes tomain.
The serve pull is not on this branch yet, so I reviewed no serving code.
All seven checks are queued at this head. The previous head's checks all passed.
One small thing: in deploy, a path that fails valid_path is reported as "longer than a site's path can be". valid_path also rejects empty, . and .. segments, so the message can be wrong. Those segments can't come from walk, so this is cosmetic.
At this head feature/pages now holds the whole feature. Since my last round it adds serving (sites.rs, the site index table and its firehose/backfill wiring, --pages-domain) and the deploy/ changes (setup.sh, deploy.sh, compose, README, deploy.yml). I found nothing that must change.
I read sites.rs, the index, lib.rs, plans.rs, release.rs, jetstream.rs, the deploy files and the new serve tests. I did not re-read site.rs, cli.rs or the lexicon and design docs: I reviewed them in earlier rounds, and this round's changes are in the serve and deploy files above.
What I checked:
- Hash handling. Only 64-character lowercase hex hashes are indexed, and
fetchchecks again before using one as a filename. A hash cannot point outside the kept directory, and the index test covers that. - Redirects. A repository name containing
\or a control character is refused before any redirect is built, so the open-redirect case is closed. The tests cover it. - Hosts. Only GET and HEAD are answered on the domain. A handle label is accepted only if its DID claims the handle back.
- Takedowns. The
siteindex lookup respects thedownlist. - Purge and forget.
PURGEbinds?2and?3, andpurgepasses only as many arguments as a statement takes, so the newsitestatement is safe. TheFORGET_REPOstatement builds the record URI correctly. setup.sh. The compose heredoc is now unquoted so$CADDYexpands. The rest of the compose file has no$, so nothing else changes. The token goes over ssh stdin into a0600file, and the script stops when it is needed and absent.
What my earlier reviews asked for:
deploy/README.mdsection: done.knotless sitevspublish --site: done in round 2.cli.mddocumentation: done in round 2.fallbackandnotFoundmust be files of the site: done in round 2.
At this head the check and docs runs from the batch that landed the deploy pull (3mzgzwunfvl3t) passed. The full test workflow passed there, and e2e passed at this commit. This pull's own test, e2e, web, shots and lexicons runs were still queued or running when I looked.
Two small notes, neither blocking:
Found::Movedand the/{name}/redirect put the decoded path inLocationwithout re-encoding. A name or directory with a space or non-ASCII character falls back to/or an invalid header. Re-encoding the segment would fix it.- Nothing serves
knotless.pageuntil the Caddy block, the wildcard certificate and the DNS exist on the host, as the body says.
Carried forward: the change this pull makes at 20dbf7d1511d27e9d6b6463f2fad3b886cbe3dd2 is the one reviewed at d067ffc98471b363ed7563cd91cd8fd2c25e70f0, so that review stands. What is new comes from its base.
Since my last round, the only change at this head is a merge of origin/main into feature/pages. The merge brings in main's own pulls: the queue's failed stage, the searching_code quarantine, the release-hash fix and the space-sync fix. None of them touch the pages code I reviewed earlier, so I did not re-read the pages files. I did not read the merged main changes either, since they were reviewed in their own pulls.
My earlier reviews asked for four things, and all are done:
- the
deploy/README.mdsection - one name for the
knotless sitecommand - the
cli.mdentry - the check that
fallbackandnotFoundare files of the site
The two cosmetic notes from last round still apply and don't block. Location headers are built from decoded paths without re-encoding. Nothing serves knotless.page until the Caddy block, certificate and DNS exist on the host.
At this head, check and docs passed. test, web, e2e and shots were still queued or running when I looked, so I can't say how they ended.
The only change since my last round is one commit, 157049d, which takes up two notes from my earlier reviews. It's correct.
- UTF-8 names:
walknow refuses a file whose name isn't UTF-8 and names it. Before, two such names could be read lossily into the same path, which a site record can't hold. A Linux-only unit test covers it. - Refusal message: a path rejected by
valid_pathnow says it breaks any of the path rules, not only the length. The CLI test checks the new wording.
My earlier asks are all done, and I have nothing new to ask for. The Location re-encoding note and the missing Caddy block, certificate and DNS on the host still stand. Neither blocks this.
Checks at this head: the batch run of test, e2e and check passed. web, shots, lexicons and docs were skipped as nothing they cover changed. This pull's own runs were still queued or running when I looked.
What changes
Pages: a repository's static website, kept as blobs in its owner's account under one
dev.knotless.siterecord and served by knotless-serve athttps://<owner>.knotless.page/<repo>/(docs/design/pages.md). It is built up on feature/pages through these pulls:knotless site, knotless site deploys a directory as a repository's websiteWhy
It stays off main until it works end to end, since the
dev.knotless.sitelexicon is published once it lands there.How it was checked
This pull's own checks run the whole of feature/pages against main as it is now. It is not queued until the feature is ready.
Shortcomings
Still to come: the
deploy/changes (Caddy with the Cloudflare DNS module, the wildcard certificate, DNS, and--pages-domainin deploy.yml), redirects for a renamed repository's old path, and an MCP tool.🤖 Generated with Claude Code