Refactor/walis - #2
Conversation
The gate took the first python3 on PATH. When that is older than 3.12 it cannot import oneagent/installer.py at all, so the gate failed with a tomllib ModuleNotFoundError instead of either comparing writers or skipping. It was silently red rather than green or skipped. Probe each candidate for the version the Python core requires before choosing it, so a usable interpreter is found when one exists and the gate skips cleanly when none does. ONEAGENT_REQUIRE_PARITY still turns a skip into a failure for CI. Co-Authored-By: Claude <noreply@anthropic.com>
The site pages were written against two generated JSON files that a Python step produced from the release artifacts. Those scripts are gone, so the pages need the same shapes from what remains: agents.lock.json for the catalog, and the GitHub Releases API for the downloads. catalog.ts gains `command`, `configPath` and `groups`, which the explorer and the activation demo already display, and now declares its types by importing explorer.ts rather than redeclaring them. Re-declaring was how a new protocol could reach the pages while the explorer still called it unsupported. release-channel.ts is new. It maps a release into the channel shape the download and security pages consume, and reports what the API cannot tell it as unknown instead of filling it in: `native_build: false` and `cleanroom: "not-recorded"` are the honest readings of "the release feed does not carry build provenance". Asserting `true` here would put a verification badge on the site that nothing checked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports the public site work from main: the i18n routing layer with its hreflang and canonical handling, five English pages, the compatibility explorer, the activation demo that plays itself once scrolled into view, and the theme and locale controls. Every page that read a generated JSON file now reads the typed catalog and release-channel modules instead, which also removes eleven `as unknown as` and `as any` casts that only existed to give an untyped JSON import a shape. The security pages needed more than a rewire. They asserted that a specific macOS arm64 build had passed a cleanroom review — a claim the release feed cannot support. They now state what is checkable against the release page (channel, version, platform, digest) and say plainly that the build-provenance conclusions are recorded by the release process rather than asserted here. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`npm run build` ended in `npm run validate`, but the validate script had been removed from package.json — so every build failed on a missing script after reporting success. Restored. validate-build.mjs used to re-hash each artifact in dist/downloads/ and compare it against the digest the release index claimed, which meant a page could not print a checksum the file did not have. That check has no subject now: the site links to GitHub Releases instead of hosting the artifacts, so there is no local file to hash. Removed, with a comment recording the cost — a wrong digest from the feed now reaches the page unchallenged — and what restoring an equivalent gate would take. release-index.json also came off the required-outputs list, since the site no longer emits it. The download-page tests skip, with a stated reason, when no release is published: the picker they drive is replaced by the unavailable notice, and this repository's release feed is currently empty. Skipping keeps them around to catch a regression once artifacts exist, where deleting them would let the download flow rot unnoticed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
exec.Cmd copies stdout and stderr on separate goroutines, so the listener passed to RunWithOutput was entered from both at once. The install runtime hands it a closure that redacts and forwards (internal/app/install.go), and that closure holds no lock — so this was a data race in production, not only under test. It shows up whenever a command writes to both streams, which npm does on every install. The lock lives in the runner rather than in each caller: "calls are serialised" is the contract a listener should be able to rely on. Both streamWriters share one mutex, since a mutex per writer would have the two goroutines taking different locks and entering the listener together anyway. TestOSRunnerSerialisesListenerAcrossStreams drives 50 interleaved writes to each stream through a listener that appends without locking, mirroring the production shape. Reverting the fix makes it fail with DATA RACE, which the previous tests only did by accident: they left stderr empty, so `-cover` adding a "GOCOVERDIR not set" warning was what exposed the race at all. That warning also polluted three assertions about captured output, so the helper now gets a scratch GOCOVERDIR of its own. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
manifest_embed.go says a checked-in .keep makes the stage-0 shell buildable before Vite has produced dist. The file was never in the repository: two `dist/` rules excluded the directory itself, and excluding a directory stops git descending into it, so the `!frontend/dist/.keep` exception that was already sitting in the root .gitignore could never take effect. The consequence is that `go:embed all:frontend/dist` had nothing to embed in a fresh clone, and `go vet ./...` and `go build` failed on a missing embed pattern until someone happened to build the frontend first. Both rules now list their entries (`dist/*` plus the negation) instead of excluding the directory, and the root rule is anchored to `/dist/` so it stops matching at arbitrary depth. Build output stays ignored — verified that frontend/dist/index.html and site/dist/ still are. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port the public site onto the Go core, and fix a listener data race
|
Closing rather than merging: Merging was not a viable route.
|
No description provided.