registry: the brand's shell and the package page (BRAND slice 2) #12

Closed
opened 2026-10-05 21:07:10 +00:00 by orion · 6 comments
Collaborator

Context

The website and docs carry the brand (slice 1); the registry's pages do not yet.

Source

Acceptance criteria

  • The registry's pages use the shell of the docs site and brand/tokens.css
  • The package page of BRAND.md section 11
  • BRAND.md slice 2 marked done

Dependencies

None known.

Moved from the planning lists of the docs; the design record stays the specification.

## Context The website and docs carry the brand (slice 1); the registry's pages do not yet. ## Source - [BRAND.md slice 2](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/design/BRAND.md#L693) ## Acceptance criteria - [ ] The registry's pages use the shell of the docs site and `brand/tokens.css` - [ ] The package page of BRAND.md section 11 - [ ] BRAND.md slice 2 marked done ## Dependencies None known. _Moved from the planning lists of the docs; the design record stays the specification._
Author
Collaborator

[loop:torbscript] intake: in scope as an issue (author orion, label loop), with an owner question: the registry (packages.torb.dev) is outward-facing beyond the repo per contract. Repo-side work on the registry pages is fine; deploying is not. To be settled in refine, no deploy by the loop. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (queued)

[loop:torbscript] intake: in scope as an issue (author orion, label loop), with an owner question: the registry (packages.torb.dev) is outward-facing beyond the repo per contract. Repo-side work on the registry pages is fine; deploying is not. To be settled in refine, no deploy by the loop. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (queued)
Author
Collaborator

[loop:torbscript] refine: still queued behind the intake order. next: waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z

[loop:torbscript] refine: still queued behind the intake order. next: waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261010 until 2026-10-10T02:20Z (the earlier 'ready buffer full' marker is stale: #4, #163 are closed and the startable items are in implementation; #12 blocks #241)

[loop:torbscript] claim refine by session:loop-torbscript-20261010 until 2026-10-10T02:20Z (the earlier 'ready buffer full' marker is stale: #4, #163 are closed and the startable items are in implementation; #12 blocks #241)
Author
Collaborator

[loop:torbscript] refine: ready. These criteria supersede the body's three checkboxes (the account pages and the "slice 2 done" mark moved to #295).

Goal. The registry gets the docs site's shell in the brand's tokens and a package page per BRAND.md section 11 ("packages.torb.dev"): the header with the lockup and a packages label in Geist Mono 500 text-muted, no sub-brand. Today the registry has no package page at all (only the account HTML of account.trb, unstyled), so this builds the first one.

Decided by the loop (technical design; reasoning: RELEASE.md section 7 says reading is static files, the documentation worker already writes pages that way, and the s3: driver of #242 must keep working):

  • Package pages are static files written by the write service through its storage driver at /packages/<owner>/<name>/index.html, rewritten in the batch that records a publish, a yank or an unyank (where search.rewriteStatements already rewrites the search rows) and at start for packages that have none. A fixed /packages/ prefix collides with no owner name (index, docs, api, account stay as they are), so names.trb needs no new reserved words. No server-rendered page on request, no change to what Traefik routes.
  • The shell is a public function in the compiler's documentation package (next to site-layout.trb/site-style.trb), so the registry reuses it through its existing path: dependency and never copies it: top rule, header, packages label, theme toggle, footer, favicons, theme-color, tokens by role (--torb-*), never raw hex. The registry variant sets no inline script (the pages carry strangers' text and nginx serves them under a script-src 'self' policy): the theme script is an external file.
  • Registry-only rules (chips, version table, yank tint, install block) live in one stylesheet part the site generator also writes, so torb docs site and the registry serve the same /assets/ (fonts, icons, css) from the site image; the registry's nginx server block gets an /assets/ location and a /packages/ location with the docs location's policy.

Acceptance criteria

  • A public shell function in compiler/src/documentation/ takes title, body, optional searchAction: String? and returns the whole page; the registry variant has the packages label, data-theme toggle, no inline script, and uses only token roles (a test asserts no raw hex in the registry stylesheet part and that brandTokens still equals brand/tokens.css).
  • The package page shows: owner/name in Geist Mono 700; the latest stable (else highest pre-release) non-yanked version in tabular figures; description; keywords and capabilities as a row of neutral chips (no capability: the word "none", not an empty row); a primary ink button that copies torb add owner/name (works as a selectable code block without the script); runtime dependencies of that release; the number of dependents and the publish date; a link to the version's documentation when documentation.state = rendered; a table of all versions with publish date, where a yanked one has the warning tint, the word "yanked" and its reason.
  • Every database or index field is escaped as text (test with a description, keyword and yank reason containing markup); the page has no <script> other than an external src of its own host, no inline style=/handler.
  • Pages are rewritten on publish, yank and unyank and filled at start for a package without one; a test per case with a temporary file: storage; a package with all versions yanked still has a page.
  • tools/deploy/nginx.conf and Dockerfile.site/compose.example.yml serve /packages/ and /assets/ on the registry host; documented in RELEASE.md 7.11 and the registry README; docs/tooling/torb-docs-site.md lists the new asset/shell; generated skills/ and torb docs site --check green; BRAND.md slice 2 gets "package page built, account pages in #295" (the mark "done" is #295's).
  • Not in this item (listed so nobody builds it twice): the security-advisory block (no advisory database exists yet), README and license on the page (not stored by torb publish yet), the richer per-file capability summary (#51), the search page (#241), the account pages (#295).

Interface for #241 and #51

  • #241: the shell function takes searchAction: String?; #12 passes None (no header search field while no /search/ exists), #241 passes Some("/search/"), which renders a plain <form method="get" action="/search/" role="search"><input name="q"> that works without script. #241 builds its page with the same shell function and linked stylesheet part, and its rows link to /packages/<owner>/<name>/. The URL scheme above is the contract; #241 should state it instead of "the package page of #12".
  • #51: the page renders capabilities through one function (capabilityChips(List<String>)) fed by the release's index capabilities line; #51 replaces that call with its summary block (direct, transitive, files, "gained since") without touching the shell.

Design record points. BRAND.md section 11 ("packages.torb.dev") and slice 2; RELEASE.md section 7.7 (documentation link), 7.8 (capability summary, chips only here), 7.9 (the search row source), 7.11 (hosting, static read side) and the readiness row 13.

Seed impact. None expected: a site generator function, a registry module, CSS and nginx config; no syntax, native, driver flag, or std name looked up by string (the new code uses only features the seed's compiler already accepts; the gates verify).

Size. One PR, two Conventional Commits: feat(docs): the registry's shell and package page styles (compiler documentation package, stylesheet part, tests, docs page) and feat(registry): static package pages (renderer, storage writes, hooks, tests, nginx, README/RELEASE/BRAND). The account pages are split into #295 (depends on this). Worker: sonnet/medium (docs and tooling). Deploying the registry stays outside the loop (the nginx and compose files are repo files only); this answers the intake's owner question: no decision needed, repo-side only.

[loop:torbscript] refine: ready. These criteria supersede the body's three checkboxes (the account pages and the "slice 2 done" mark moved to #295). **Goal.** The registry gets the docs site's shell in the brand's tokens and a package page per BRAND.md section 11 ("packages.torb.dev"): the header with the lockup and a `packages` label in Geist Mono 500 `text-muted`, no sub-brand. Today the registry has no package page at all (only the account HTML of `account.trb`, unstyled), so this builds the first one. **Decided by the loop** (technical design; reasoning: RELEASE.md section 7 says reading is static files, the documentation worker already writes pages that way, and the `s3:` driver of #242 must keep working): - Package pages are **static files written by the write service** through its storage driver at `/packages/<owner>/<name>/index.html`, rewritten in the batch that records a publish, a yank or an unyank (where `search.rewriteStatements` already rewrites the search rows) and at start for packages that have none. A fixed `/packages/` prefix collides with no owner name (`index`, `docs`, `api`, `account` stay as they are), so `names.trb` needs no new reserved words. No server-rendered page on request, no change to what Traefik routes. - The shell is a **public function in the compiler's documentation package** (next to `site-layout.trb`/`site-style.trb`), so the registry reuses it through its existing `path:` dependency and never copies it: top rule, header, `packages` label, theme toggle, footer, favicons, `theme-color`, tokens by role (`--torb-*`), never raw hex. The registry variant sets no inline script (the pages carry strangers' text and nginx serves them under a script-src 'self' policy): the theme script is an external file. - Registry-only rules (chips, version table, yank tint, install block) live in one stylesheet part the site generator also writes, so `torb docs site` and the registry serve the same `/assets/` (fonts, icons, css) from the site image; the registry's nginx server block gets an `/assets/` location and a `/packages/` location with the docs location's policy. **Acceptance criteria** - [ ] A public shell function in `compiler/src/documentation/` takes title, body, optional `searchAction: String?` and returns the whole page; the registry variant has the `packages` label, `data-theme` toggle, no inline script, and uses only token roles (a test asserts no raw hex in the registry stylesheet part and that `brandTokens` still equals `brand/tokens.css`). - [ ] The package page shows: `owner/name` in Geist Mono 700; the latest stable (else highest pre-release) non-yanked version in tabular figures; description; keywords and capabilities as a row of neutral chips (no capability: the word "none", not an empty row); a primary **ink** button that copies `torb add owner/name` (works as a selectable code block without the script); runtime dependencies of that release; the number of dependents and the publish date; a link to the version's documentation when `documentation.state = rendered`; a table of all versions with publish date, where a yanked one has the warning tint, the word "yanked" and its reason. - [ ] Every database or index field is escaped as text (test with a description, keyword and yank reason containing markup); the page has no `<script>` other than an external `src` of its own host, no inline `style=`/handler. - [ ] Pages are rewritten on publish, yank and unyank and filled at start for a package without one; a test per case with a temporary `file:` storage; a package with all versions yanked still has a page. - [ ] `tools/deploy/nginx.conf` and `Dockerfile.site`/`compose.example.yml` serve `/packages/` and `/assets/` on the registry host; documented in RELEASE.md 7.11 and the registry README; `docs/tooling/torb-docs-site.md` lists the new asset/shell; generated `skills/` and `torb docs site --check` green; BRAND.md slice 2 gets "package page built, account pages in #295" (the mark "done" is #295's). - [ ] Not in this item (listed so nobody builds it twice): the security-advisory block (no advisory database exists yet), README and license on the page (not stored by `torb publish` yet), the richer per-file capability summary (#51), the search page (#241), the account pages (#295). **Interface for #241 and #51** - #241: the shell function takes `searchAction: String?`; #12 passes `None` (no header search field while no `/search/` exists), #241 passes `Some("/search/")`, which renders a plain `<form method="get" action="/search/" role="search"><input name="q">` that works without script. #241 builds its page with the same shell function and linked stylesheet part, and its rows link to `/packages/<owner>/<name>/`. The URL scheme above is the contract; #241 should state it instead of "the package page of #12". - #51: the page renders capabilities through one function (`capabilityChips(List<String>)`) fed by the release's index `capabilities` line; #51 replaces that call with its summary block (direct, transitive, files, "gained since") without touching the shell. **Design record points.** BRAND.md section 11 ("packages.torb.dev") and slice 2; RELEASE.md section 7.7 (documentation link), 7.8 (capability summary, chips only here), 7.9 (the search row source), 7.11 (hosting, static read side) and the readiness row 13. **Seed impact.** None expected: a site generator function, a registry module, CSS and nginx config; no syntax, native, driver flag, or `std` name looked up by string (the new code uses only features the seed's compiler already accepts; the gates verify). **Size.** One PR, two Conventional Commits: `feat(docs): the registry's shell and package page styles` (compiler documentation package, stylesheet part, tests, docs page) and `feat(registry): static package pages` (renderer, storage writes, hooks, tests, nginx, README/RELEASE/BRAND). The account pages are split into #295 (depends on this). Worker: sonnet/medium (docs and tooling). Deploying the registry stays outside the loop (the nginx and compose files are repo files only); this answers the intake's owner question: no decision needed, repo-side only.
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261010 until 2026-10-10T06:25Z (ready; PR #292 of #279 touches the same registry hooks, rebase onto it as it lands)

[loop:torbscript] claim implement by session:loop-torbscript-20261010 until 2026-10-10T06:25Z (ready; PR #292 of #279 touches the same registry hooks, rebase onto it as it lands)
Author
Collaborator

[loop:torbscript] implement: PR #296 rebased (head c169e224, mergeable), argus requested; the worker's CLI run aborted after the push, so this write-back comes from the loop session. CI on the new head is pending. next: waiting (review by argus; if CI fails, the next tick re-claims for a fix)

[loop:torbscript] implement: PR https://git.torb.dev/torbscript/language/pulls/296 rebased (head c169e224, mergeable), argus requested; the worker's CLI run aborted after the push, so this write-back comes from the loop session. CI on the new head is pending. next: waiting (review by argus; if CI fails, the next tick re-claims for a fix)
argus closed this issue 2026-10-10 08:16:34 +00:00
Sign in to join this conversation.
No labels
loop
ready
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#12
No description provided.