~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

Pages are designed, with the dev.knotless.site record

Merged
Merged chadtmiller.com asked to merge into feature/pages from chadtmiller.com/knotless:pages/design

What changes

A design page, docs/design/pages.md, in the docs site's sidebar and the design index. It covers how a repository's website is kept and served: one dev.knotless.site record per repository in its owner's account, its files as blobs, replaced on each deploy by knotless publish --site, and served by knotless-serve at https://<owner>.knotless.page/<repo>/. The owner's subdomain is their handle as one DNS label: each - becomes --, then each . a -.

The record's lexicon, lexicons/dev/knotless/site.json. Its files have the same shape as a release's (size, sha256, blob parts), plus a path and an optional contentType. The record also has optional notFound and fallback pages, and the commit and check that built it.

Why

This is the first part of pages, on feature/pages, so the design and the schema can still change while serve and the client are built against them. Nothing reaches main, and no lexicon is published, until the whole feature lands.

There is one record per repository, replaced on each deploy, rather than a record per deploy as releases have. The PDS frees the old deploy's blobs, serve reads the site with one getRecord, and a deploy swaps in one write. The page explains why sites are not served from a branch, and why they get a registrable domain of their own on the Public Suffix List.

How it was checked

node harness/lexicons.mjs and goat lex lint pass on the new schema. The docs check (links, anchors, the site build) is left to CI.

Shortcomings

No code yet: the page describes what serve and knotless publish --site are to do. Custom domains are left for later.

🤖 Generated with Claude Code

Approved

This adds the Pages design page (in the sidebar and the design index) and the dev.knotless.site lexicon. I read all four changed files and the base's AGENTS.md and lexicons/AGENTS.md. I found nothing that has to change.

  • Design: The page is internally consistent. The handle-to-label encoding is injective and the table examples are correct. The DID subdomain can't collide with a handle label, because a plc id has no - and every handle label has one. The reasons for the Public Suffix List domain, a single label and one record per repository hold up. The code references I checked exist: Records::fetch in releases.rs and KNOTLESS_CHUNK_SIZE with its 4,000,000 default.
  • Lexicon: The shape matches the page. The rules the schema can't express are only in the prose: distinct paths, no . or .. segment, and notFound and fallback naming a file in files. Whoever builds publish and serve will have to enforce them, and serve must not trust the record to have done so.
  • Checks: check passed. The other checks were still queued or running when I looked, including lexicons and docs. The body leaves docs to CI, which is fine.

AGENTS.md lists docs/design/serve.md as the page to update for pages. It is reasonable to wait until the serve code lands, but remember to add a short pointer there then.

Approved

The new commit limits fallback to page requests: those that ask for text/html, or whose last path segment has no extension. Everything else missing gets notFound or a plain 404. I read the diff, and the design page and the lexicon description say the same thing. A missing script now returns a 404 instead of the app's HTML, which is the right behaviour. My earlier review asked for nothing, so nothing is outstanding. The one thing to remember is still the pointer in docs/design/serve.md once the serve code lands.

Approved

The new commit adds a "Private sites" section to docs/design/pages.md and changes "has no site" to "has no site yet" in the section on what isn't served, with a link to the new section. It is a plan only: publishing still refuses private repositories, and no code changes. I found nothing that has to change.

  • Gate: Membership is the gate, and the ticket flow holds up. The ticket is signed, names one DID and one host, lasts a minute and is single-use. The cookie is __Host-, HttpOnly, Secure and signed. Membership is checked again on each request, and responses are private, no-store.
  • Origin: Giving each private site its own host under private.knotless.page is the right call. The reason the page gives is correct: a script on the owner's public site could fetch the private site with the visitor's cookie. The host can't collide with another, because neither a repo key nor a plc id contains a -.
  • Remaining work: The "Certificates and DNS" section should also mention *.private.knotless.page and its Public Suffix List entry when it gets a wildcard certificate. The docs/design/serve.md pointer is still outstanding for when the serve code lands.

My earlier reviews asked for nothing, so nothing from them is outstanding.

Merged as eb30376