Prevents regressions where someone translates solaris→sunos or uses
arch=universal2. The Node classifier already knows solaris, illumos, and
sunos as distinct OS values. It does NOT know universal2 — use x86_64.
Cache validation checks:
- terraform/syncthing: solaris filenames must have os=solaris (not sunos)
- syncthing: illumos filenames must have os=illumos (not sunos)
- node: sunos filenames must have os=sunos (baseline)
- cmake/hugo: universal filenames must have arch=x86_64 (not universal2)
cmake resolves to v3.19.1 (stable is v4.2.3) and hugo to v0.101.0
(stable is v0.157.0) because universal2 entries are dropped by the
classifier. Marked as known failures until GOER fixes legacy export.
The Go cache classifies musl builds as libc='musl' but production
(normalize.js) defaults musl → 'none' (static). Only 7 packages
have "hard musl" (actual runtime dependency): node, bun, julia,
pwsh, pg/postgres/psql, atomicparsley, cmake.
Tests all 99 cached packages x 2 platforms (macOS arm64, Linux amd64).
192/198 pass. 6 failures all match production behavior (git, gpg, iterm2,
mariadb — packages without downloadable binaries for these platforms).
Three fixes to the installer resolution path:
1. Triplet enumeration order: put specific OS before ANYOS and specific
arch before ANYARCH. This prevents .git source URLs (ANYOS/ANYARCH)
from shadowing platform-specific binaries (jq, caddy).
2. WATERFALL libc→gnu+musl: glibc hosts ('libc' in UA) now try
['none', 'gnu', 'musl', 'libc'] instead of ['none', 'libc']. This
lets packages with gnu-linked builds (bat, rg, node) and static musl
builds (rg v15+) match for glibc hosts.
3. Version-first iteration: findMatchingPackages now iterates versions
newest-first then tries each triplet, matching the Go resolver's
approach. Prevents picking an ancient version from a low-priority
triplet when a newer version exists in another triplet (e.g. rg
v0.1.6 gnu vs v15.1.0 musl).
Tests updated: all 15 installer-resolve cases pass (was 9+6 known),
30/32 live-diff cases pass (2 known: node Linux amd64 where our code
is better than live, hugo macOS arm64 classifier limitation).
Direct behavioral equivalence: fetches live installer from webinstall.dev
with same UA, compares WEBI_* variables against local serveInstaller().
Tests alias resolution (golang→go, ripgrep→rg). Marks jq as known
(.git regression in Go cache).
Three test layers against live webinstall.dev APIs:
1. Unfiltered release API — OS/ext vocabulary, version format
2. Filtered release API — correct package for specific OS/arch
3. Installer script rendering — WEBI_* vars, download URLs
47 pass, 2 known format-preference diffs (node .pkg/.7z vs .tar.gz/.zip),
5 known Go-cache improvements (excluding .deb/.pem non-installable formats).
none = static (no runtime dep, works everywhere)
musl = requires musl runtime (e.g. node-musl)
gnu = requires glibc (crashes on Alpine)
libc = host UA value meaning "I have glibc"
The webinstall.dev server passes formats=['tar','exe','zip','xz','dmg']
by default — not empty. Fixed Windows UA to use 'Windows' (not
'Windows_NT'). Identified .git source URLs in Go cache as a regression
vs production (not just a priority issue). Updated PROD_NOTES.md with
webinstall.dev serve-releases.js libc bug finding.
Exercises the helper() function that `curl webi.sh/bat` actually hits.
9 passing, 6 known issues documented:
- WATERFALL libc->gnu gap (build-classifier submodule)
- ANYOS/ANYARCH .git source URLs matched before platform binaries
Compares local cache-only output against golden data fetched from
the live API. Tests OS/arch/ext vocabulary, version format, and
filtered query results for bat, go, node, rg, jq, caddy.
These files are no longer loaded at runtime. All release data now comes
from _cache/YYYY-MM/{pkg}.json files generated by the Go webicached daemon.
Deleted:
- 94 {pkg}/releases.js files (per-package upstream fetchers)
- 8 _common/*.js files (github.js, gitea.js, git-tag.js, fetcher.js, etc.)
Updated:
- _webi/classify-one.js: reads from cache instead of require(releases.js)
- Fixed hardcoded triplet key to use dynamic lookup
The legacy release API endpoint now reads from _cache/YYYY-MM/{pkg}.json
instead of require()ing {pkg}/releases.js and fetching upstream.
Cache data is re-normalized through normalize.js (with pre-classified
fields cleared first) to preserve the legacy API format where darwin
is reported as 'macos', versions lack 'v' prefix, etc.
Removed: Releases.get(), stale/expired age timers, background renewal,
promise chaining, sleep/timeout workarounds.
Project type detection no longer require()s {pkg}/releases.js to
determine if a package is valid. Instead it checks for a cache file
at _cache/YYYY-MM/{pkg}.json. This means:
- Packages with Go-generated cache but no releases.js (vim plugins,
pg-essentials, etc.) are now correctly detected as 'valid'
- The 'not_found' type (broken npm deps) is removed — no longer relevant
- releases.js files are no longer loaded at runtime for type detection
The Go webicached daemon now handles all upstream API fetching and cache
generation. The Node server reads only from _cache/YYYY-MM/{pkg}.json
files and never fetches from upstream APIs itself.
Removed:
- getLatestBuilds() and getLatestBuildsInner() — upstream fetch functions
- freshenRandomPackage() — background refresh timer
- Stale cache re-fetch in getPackages() process.nextTick block
- _staleAge config (no longer relevant)
When a package has no cache file, getPackages() returns empty metadata
instead of falling through to fetch.
Detailed instructions for the next step: making the Node.js server
read only from Go-generated _cache/ files, removing all upstream
API fetching from the Node.js code path.
Adds releases.js, install.sh, install.ps1, and README.md for monorel,
a Go monorepo release tool from therootcompany/golib. Filters monorepo
releases by tools/monorel/ prefix and auto-installs prerequisites
(git, gh, goreleaser).