registry: the search field in the header of package pages #306

Closed
opened 2026-10-10 10:45:40 +00:00 by orion · 4 comments
Collaborator

Goal

Every package page of the registry carries the search field in its header (registryPageHtml(..., searchAction: Some("/search/"))), sending q to the search page of #241 (landed, closed), and the pages already in the storage get it too.

Source

  • docs/design/RELEASE.md 7.11, the bullet "The package pages are static files too" (which ends "The search field of the header of a package page ... [is] not built") and the bullet of the search page (#241).
  • tools/registry/src/packages.trb (packagePageHtml, last line calls registryPageHtml without searchAction), tools/registry/src/registry.trb (Registry.fillPages, pageFileWritten; the model is ownerFileFilled, which compares the stored text with the text the row makes), tools/registry/src/main.trb (the start-up call), the shell in compiler/src/documentation/site-registry.trb (already renders the registry-search form, nothing to change there).

Design (decided by the loop, see the comment below)

fillPages stops asking "is there a page?" and asks "is the stored page the one the database makes now?": it builds packagePageOf(database, package), reads the stored text (textAt) and writes only where it differs or is missing. No marker or hash is stored in the page; the page itself is the comparison, so any later change of the shell is picked up the same way.

Acceptance criteria

  • packagePageHtml calls registryPageHtml with searchAction: Some("/search/"); a test in tools/registry/tests/packages.test.trb asserts the page contains <form class="registry-search" method="get" action="/search/" role="search"> and the name="q" input (on sample() and on a page written by a publish).
  • Registry.fillPages rewrites a package page whose stored text differs from the one packagePageOf makes, and writes a missing one, as before; it leaves an equal page untouched and does not count it. It answers the number of pages it wrote; the doc comment of fillPages and the start-up line in main.trb ("wrote the pages of N packages") stay true.
  • A test replaces the stored page of a package by the same page without the search form (an old shell), runs fillPages (answers Ok(1) for that package), asserts the page now has the form, and a second fillPages answers Ok(0); the existing missing-page test keeps passing.
  • docs/design/RELEASE.md 7.11 states that a package page has the search field, that fillPages rewrites every page that differs from the one the database makes (so a registry of a newer toolchain brings its shell), and drops "The search field of the header of a package page ... are not built" for the field (the capability summary #51 stays "not built").
  • Gates green in the forge CI of the PR (tools/gates.sh a), tools/check-commits.sh clean.

Seed impact

None. Registry application code (tools/registry) and a design record only; no syntax, native, driver flag or std name looked up by string.

Size and dependencies

One PR, two Conventional Commits: feat(registry): the search field in the header of a package page (packages.trb + test) and feat(registry): rewrite the package pages that differ at start (registry.trb + test + RELEASE.md), or one if it fits. Depends on #241: landed (closed, e069025, 7d1a30d). No open dependency.

Out of scope

The account pages (account.trb) also call registryPageHtml without searchAction; they are not package pages and keep their current header.

## Goal Every package page of the registry carries the search field in its header (`registryPageHtml(..., searchAction: Some("/search/"))`), sending `q` to the search page of #241 (landed, closed), and the pages already in the storage get it too. ## Source - `docs/design/RELEASE.md` 7.11, the bullet "The package pages are static files too" (which ends "The search field of the header of a package page ... [is] not built") and the bullet of the search page (#241). - `tools/registry/src/packages.trb` (`packagePageHtml`, last line calls `registryPageHtml` without `searchAction`), `tools/registry/src/registry.trb` (`Registry.fillPages`, `pageFileWritten`; the model is `ownerFileFilled`, which compares the stored text with the text the row makes), `tools/registry/src/main.trb` (the start-up call), the shell in `compiler/src/documentation/site-registry.trb` (already renders the `registry-search` form, nothing to change there). ## Design (decided by the loop, see the comment below) `fillPages` stops asking "is there a page?" and asks "is the stored page the one the database makes now?": it builds `packagePageOf(database, package)`, reads the stored text (`textAt`) and writes only where it differs or is missing. No marker or hash is stored in the page; the page itself is the comparison, so any later change of the shell is picked up the same way. ## Acceptance criteria - [ ] `packagePageHtml` calls `registryPageHtml` with `searchAction: Some("/search/")`; a test in `tools/registry/tests/packages.test.trb` asserts the page contains `<form class="registry-search" method="get" action="/search/" role="search">` and the `name="q"` input (on `sample()` and on a page written by a publish). - [ ] `Registry.fillPages` rewrites a package page whose stored text differs from the one `packagePageOf` makes, and writes a missing one, as before; it leaves an equal page untouched and does not count it. It answers the number of pages it wrote; the doc comment of `fillPages` and the start-up line in `main.trb` ("wrote the pages of N packages") stay true. - [ ] A test replaces the stored page of a package by the same page without the search form (an old shell), runs `fillPages` (answers `Ok(1)` for that package), asserts the page now has the form, and a second `fillPages` answers `Ok(0)`; the existing missing-page test keeps passing. - [ ] `docs/design/RELEASE.md` 7.11 states that a package page has the search field, that `fillPages` rewrites every page that differs from the one the database makes (so a registry of a newer toolchain brings its shell), and drops "The search field of the header of a package page ... are not built" for the field (the capability summary #51 stays "not built"). - [ ] Gates green in the forge CI of the PR (`tools/gates.sh a`), `tools/check-commits.sh` clean. ## Seed impact None. Registry application code (`tools/registry`) and a design record only; no syntax, native, driver flag or std name looked up by string. ## Size and dependencies One PR, two Conventional Commits: `feat(registry): the search field in the header of a package page` (packages.trb + test) and `feat(registry): rewrite the package pages that differ at start` (registry.trb + test + RELEASE.md), or one if it fits. Depends on #241: landed (closed, `e069025`, `7d1a30d`). No open dependency. ## Out of scope The account pages (`account.trb`) also call `registryPageHtml` without `searchAction`; they are not package pages and keep their current header.
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261013 until 2026-10-13T06:35Z

[loop:torbscript] claim refine by session:loop-torbscript-20261013 until 2026-10-13T06:35Z
Author
Collaborator

[loop:torbscript] decided by the loop: existing pages are brought up to date by comparing, not by a marker and not by rewriting all. Registry.fillPages builds the page with packagePageOf, reads the stored text with textAt and writes only on a difference, the same way ownerFileFilled already does for owner files. Why: (1) exact - it catches any change of the shell or of the page code, where a marker/hash would need a version constant kept in step by hand; (2) rewrite-all would PUT every file at every start (20 000 writes, churned ETags for the CDN) while compare writes only the changed ones; (3) the work is the existing per-package exists check plus the 5 reads packagePageOf already does and one file read per package, sequential under the write lock before the first request, so the cost is a one-time start-up read pass, not a new class of work. Not measured: the choice does not turn on the number (compare reads what rewrite-all would read and writes less), and the forge CI would only time a seeded database; if a later release shows a start-up that is too slow at scale, a marker is the follow-up, with that number.

[loop:torbscript] decided by the loop: existing pages are brought up to date by comparing, not by a marker and not by rewriting all. `Registry.fillPages` builds the page with `packagePageOf`, reads the stored text with `textAt` and writes only on a difference, the same way `ownerFileFilled` already does for owner files. Why: (1) exact - it catches any change of the shell or of the page code, where a marker/hash would need a version constant kept in step by hand; (2) rewrite-all would PUT every file at every start (20 000 writes, churned ETags for the CDN) while compare writes only the changed ones; (3) the work is the existing per-package exists check plus the 5 reads `packagePageOf` already does and one file read per package, sequential under the write lock before the first request, so the cost is a one-time start-up read pass, not a new class of work. Not measured: the choice does not turn on the number (compare reads what rewrite-all would read and writes less), and the forge CI would only time a seeded database; if a later release shows a start-up that is too slow at scale, a marker is the follow-up, with that number.
Author
Collaborator

[loop:torbscript] refine: verified #241 landed (closed; search page at e069025, shell script 7d1a30d), no open dependency; checked packages.trb, registry.trb fillPages/pageFileWritten/ownerFileFilled, main.trb, site-registry.trb (shell already renders the search form) and RELEASE.md 7.11 (still says the field is not built); tightened the acceptance criteria in the body (exact form markup, compare strategy, fill test with an old-shell page, doc change), seed impact none, size one PR of two commits, label ready set, next: implement

[loop:torbscript] refine: verified #241 landed (closed; search page at e069025, shell script 7d1a30d), no open dependency; checked packages.trb, registry.trb fillPages/pageFileWritten/ownerFileFilled, main.trb, site-registry.trb (shell already renders the search form) and RELEASE.md 7.11 (still says the field is not built); tightened the acceptance criteria in the body (exact form markup, compare strategy, fill test with an old-shell page, doc change), seed impact none, size one PR of two commits, label ready set, next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261013 until 2026-10-13T13:04Z

[loop:torbscript] claim implement by session:loop-torbscript-20261013 until 2026-10-13T13:04Z
argus closed this issue 2026-10-13 09:48:32 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
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#306
No description provided.