registry: search #18
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
A visitor or a client can find packages in the registry by text:
GET /api/1/searchanswers a ranked list over owner, name, description and keywords of what is published. The search page and a client command are not part of this issue (see "Not in this issue").Source
keywords;keywordsis added, not static, in the lock'ssettings, required by nothing; ranking after text relevance by dependents, then the registry's package checks)tools/registry/README.md, "Not built yet"Findings from refine
releaseshas only package, version, hash, publisher, yank state; the index record is signed and resolution-only, and stays exactly as it is. The description is in the archive'sproject.lock.trbsettingsblock, whichcheckedUploadalready reads on every publish.keywordsis not in the vocabulary yet (std/projectProject,Manifest, the lock'ssettings); every other setting 7.9 needs exists.torb search(7.13 listsadd,remove,update,install,publish; 7.13 "Not built yet" namesyank,owner,login; nothing namessearch). The acceptance bullet "torb search... if RELEASE.md asks for it" therefore resolves to: not built here.Design (decided by the loop, reasoning in the comment below)
keywords "http", "client"inproject.trb, variadic likeauthors: a variadic method ofProjectinstd/project,Manifest.keywords, read bymanifestOfand written bysettingsLinesinto the lock'ssettings, listed inunreadWords(never evaluated by itself).publishProblemsrefuses at publish: more than 5 keywords, a keyword that is not 2 to 24 characters of lowercasea-z,0-9,-starting with a letter or digit, or a duplicate. Nothing else changes for a package without keywords.search(package, owner, name, version, description, keywords, capabilities, published) holding one row per package that has at least one non-yanked release, plussearch_dependencies (package, dependency)for the runtime dependencies of that same release. The row describes the latest non-yanked release (highest stable version; the highest pre-release only when no stable one is published). It is rewritten in the same statement batch as the release row on publish and on yank/unyank, under the existingWriteLock; a package whose releases are all yanked has no row. The index is the truth and is not touched; the table is derived and can be rebuilt.searchrow is filled from the archive of its latest non-yanked release (unpacked and read the waycheckedUploaddoes); a package that fails is logged and skipped, never fatal.instrover lower-cased text); the sum is the relevance. Order: relevance, then dependents (distinct packages whose latest release lists it as a runtime dependency), then newest publish, then package name. A term with/is matched againstowner/name. Downloads are not ranked on (7.9).GET /api/1/search?q=<text>&limit=<1..50, default 20>&offset=<default 0>, public, no token. Answer200:{"query": "...", "total": N, "limit": N, "offset": N, "packages": [{"package": "acme/http", "owner": "acme", "name": "http", "version": "1.2.4", "description": "...", "keywords": ["http"], "capabilities": ["network"], "dependents": 3, "published": 1790000000}]}(integers are seconds since 1970 like the other calls). An emptyqor one without a term, a badlimitoroffset:400with the usual{"error", "problems"}.Cache-Control: public, max-age=60.sqlite3shell, whose build options are the container's and the CI's business; aninstrscan over the derived table needs none. Measured with SQLite 3.40 on 20 000 synthetic packages (12 words of description, 4 keywords each): 18 ms per query including the client; the registry will hold orders of magnitude fewer for a long time. Revisit only when a measurement shows more than 100 ms.Acceptance criteria
keywordsexists instd/project,Manifest, the manifest reader and the lock'ssettings(round trip throughtorb lockandtorb lock --check);torb publish --dry-runand the registry refuse the keyword cases above with one sentence each; a lock withoutkeywordsreads and writes exactly as before.docs/tooling/project-trb.mdand the settings table ofdocs/design/PROJECT.mdlist it;skills/regenerated.tools/registrymigrates an existing database in place (new tables created, existing accounts, tokens and releases untouched) and backfills thesearchrows at start.searchrow from the lock'ssettingsof the archive; a newer version replaces it; a yank of the latest version moves the row to the next newest non-yanked one, a yank of the only version removes it, an unyank restores it; the signed index and the archives are byte-identical to what they were before this change for the same inputs.GET /api/1/searchmatches owner, name, description and keywords, requires every term, orders by the rules above (tests with fixtures that pin each tier: exact name above prefix above contains above keyword above description; equal relevance ordered by dependents), honourslimitandoffset, reportstotal, returns an emptypackageslist for no match, and refuses the malformed requests with400.',%,_,;, control characters, 64+ characters) is matched literally or refused, never executed (test).tests/server.test.trb(or a new test file) covers each case once as it works and once as it is refused;torb test tools/registry/testsgreen natively and in the VM;compilertests for thekeywordsround trip and refusals.tools/registry/README.md(calls table, "Not built yet"), RELEASE.md 7.9 and the write service's "as built" notes (7.11) updated: search is built over/api/1; ranking on the registry's package checks stays open until those checks exist.Seed impact
None: TorbScript in
std/project,compiler/src/project,compiler/src/packageandtools/registryon existingstd; no syntax change, no native, no driver flag, no std name the compiler looks up by string (an oldertorbignores akeywordsline in a lock'ssettings, asmanifestOfskips unknown words).Size and dependencies
One PR, two Conventional Commits:
feat(project): keywords setting(std/project, manifest, lock, publish check, docs, skills) andfeat(registry): search over /api/1(schema, publish/yank/backfill, endpoint, tests, README, RELEASE.md). No blocking dependency. Overlap: the open PR #237 (documentation worker) and #223 (sessions and account page) also changetools/registry(database.trbmigration,registry.trb,api.trb,main.trb, README, RELEASE.md rows); whichever lands second rebases, and the migrations are independent (each only adds tables).Not in this issue
torb searchcommand: not asked by RELEASE.md; may be filed later together withtorb login/owner(#22).[loop:torbscript] intake: in scope (author orion, label loop). Registry search over the index via
/api/1; the ranking/matching rules and whethertorb searchis wanted are a library design choice if RELEASE.md does not fix them, to settle in refine (possible owner decision). Deploy is outward-facing, not done by the loop. Release freeze for 0.1.0 (2026-10-06) holds new PRs, next: refine (queued)[loop:torbscript] claim refine by session:loop-torbscript-20261009 until 2026-10-09T03:14:00Z
[loop:torbscript] decided by the loop: (1) Search is a derived
searchtable scanned withinstr, not FTS5 and not the signed index. The index stays resolution-only and signed (7.4); description and keywords come from the archive's locksettingsat publish and are stored in SQLite, rewritten with the release row under the existing write lock, backfilled at start. A scan needs no SQLite build option (the registry uses thesqlite3shell); measured 18 ms per query on 20 000 synthetic packages (SQLite 3.40, client included), revisit above 100 ms. (2) Ranking follows 7.9: text relevance (exact name 16, prefix 8, contains 4, keyword 4, owner 2, description 1, AND over terms), then dependents, then newest publish, then name; ranking on package checks waits for their data (#17, #51). (3) API:GET /api/1/search?q&limit&offset, public, JSON in the style of the other calls (seconds since 1970,{"error","problems"}refusals),limit1..50 default 20, shortCache-Control. (4)keywords: variadic likeauthors, non-static, in the lock'ssettings, at most 5 of 2..24 characters[a-z0-9-], checked at publish only (crates.io-like limits against spam; no published package has any, so no contract breaks; an oldertorbignores the line). (5) Search page split to #241 (static page of the site over the API, no server-rendered HTML in the write service);torb searchis not asked by RELEASE.md and is not built. Out of scope: deploying or restarting the production registry. Overlap: PR #237 and #223 also changetools/registry; migrations are additive, the later one rebases, refine does not wait.[loop:torbscript] refine: checked the requirements against ROADMAP, RELEASE.md 7.4/7.9/7.11/7.13, CONCEPT and
tools/registryonmain; the issue body now has goal, design, testable acceptance criteria, seed impact (none) and size (one PR, two Conventional Commits:feat(project): keywords setting,feat(registry): search over /api/1). The search page is split off,torb searchis not asked by RELEASE.md (not built), deploy is out of scope; choices are recorded in the decided-by-the-loop comment. No owner decision needed. Overlap with #237 and #223 noted, not waited for. next: implement (ready). Worker usage: about 90k tokens (sonnet).[loop:torbscript] claim implement by session:loop-torbscript-20261009 until 2026-10-09T08:31Z
--sandbox#49--sandbox#49PR: #245 (CI green on
5f71106, review requested from argus).[loop:torbscript] implement: PR #245 CI green on
5f71106after two tier A reruns (each red run failed on one different timing-dependent test incompiler/tests/language-server.test.trb, tracked in #244; the PR touches no language-server code), approved and merged by argus. next: close (main CI on the landed commit)[loop:torbscript] PR #245 merged by argus (
911b10d). Issue closed by the merge. No after-merge steps in the PR; the registry deploy is outward-facing and not done by the loop.[loop:torbscript] close: landed in
911b10d25d(PR #245); main CI is green on that commit (13 checks success, 11 platform/seed lanes skipped for this change). Issue closed.