Repository navigation
refactor(harness): one runner release listing shape and layout-derived package checks - #74
Open
namikmesic wants to merge 3 commits into
Open
namikmesic wants to merge 3 commits into
namikmesic wants to merge 3 commits into
Conversation
added 3 commits
October 4, 2026 23:20
The server's download listing, the runner self-update's listing and the app's listing each declared their own asset record. They now share ListedRunnerAsset and RunnerReleaseListing in src/harness/runner-releases.ts. A listed asset is the manifest's RunnerReleaseAsset plus the version it belongs to and its download URL. readRunnerReleaseListing is the one lenient reader, and the app and the runner both read the listing through it. The server writes the same type.
…kage layout SHIPPED repeated the package's top-level entries. It is now derived from RUNNER_PACKAGE_ENTRIES, in table order. A test checks that it covers exactly the layout's top level, and that a full package swaps every entry in and keeps the previous ones.
…he layout The copied install script listed the files it requires and the ones it must execute by hand. It now builds both lists from RUNNER_PACKAGE_ENTRIES: every regular file is required, and the ones with an execute bit must be executable. README.md, LICENSE and bin/node.LICENSE are now required too, as the layout already says. The sandbox tests build the fake package from the table. They check that the script lists exactly the table's files and executables, and that a package missing any file, or unable to execute any executable, is never published. Closes #59
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Deliver puck issue #59, "runner release: one listing shape and one layout table" (#59). Prefactor for the verified-release module. The four record shapes for a release asset (the shared format, the server's download listing, the runner self-update's listing and the app's listing) become one shape in the shared layer with one lenient reader. The runner self-update's shipped-file list and the install script the renderer copies derive from the package layout table instead of restating it. Acceptance criteria: one release asset record type and one listing reader exist in the shared layer; the server, the runner and the app import them; the self-update's shipped-file list and the renderer's install script are generated from the package layout table; a test asserts they match it; release listing tests on the server, the runner and the app pass against the one shape. Closes #59.
What Changed
src/harness/runner-releases.tsnow holds the only release asset types:ListedRunnerAsset, which is the manifest'sRunnerReleaseAssetplusversionandurl, andRunnerReleaseListing. It also addsreadRunnerReleaseListing, the one lenient reader for listings. These replace four separate copies:RunnerAsset/RunnerReleases/readReleasesinserver-api.ts,ReleaseAsset/Releasesinpuck-runner/api.ts, andRunnerAssetinserver/downloads.ts. The server's/v1/runner/releasesroute now builds aRunnerReleaseListing, and the app (main/server/api.ts,bridge.ts, renderer runners view) and the runner (ServerApi.releases, which now parses through the reader rather than casting) both read it with that reader. The reader is stricter than the one it replaces: it drops any asset whoseos/archisn't a knownRunnerOs/RunnerArch.SHIPPED, the list of files the runner self-update swaps in, now comes from the top level ofRUNNER_PACKAGE_ENTRIESinstead of a hand-kept list. The renderer's copy-paste install script builds its "required" and "executable" file checks from the same table. As a result the script also requiresREADME.md,LICENSEandbin/node.LICENSE.SHIPPEDmust match the layout's top level, and a test swaps in a full package. The install script's required and executable lists must come from the table, with one "missing file" case per regular file. The shared reader has its own coverage, and the existing server, runner and app listing tests now run against the one shape.Closes #59.
🤖 Generated with Claude Code
Risk Assessment
✅ Low: A type-and-reader consolidation prefactor: the one shared
ListedRunnerAsset/RunnerReleaseListingshape andreadRunnerReleaseListingare imported by the server, the runner and the app, the reader's lenient semantics match the old app-side reader (os/arch now narrowed to values the server's filename regex already guarantees),SHIPPEDand the install script's required/executable lists derive fromRUNNER_PACKAGE_ENTRIESand are proven by behavioral tests (realswapInand sandboxed script execution), and no acceptance criterion is contradicted.Testing
I stood up the real Puck server built from this branch, serving freshly packaged runner tarballs. I drove the release listing through the server's HTTP route, the runner's ServerApi and the app's shared reader, and confirmed all three agree on one shape. I ran the renderer-generated install script live against the served package and installed a working 0.1.0 runner. Against a tampered package missing README.md, the same script failed with "Runner package is missing README.md." and left nothing behind; the old hand-written list did not include that file. I also performed a real runner self-update whose swapped files are exactly the layout table's top level, with the registration kept and the previous files preserved. The targeted release-listing and layout test files pass. On this heavily loaded host (load average about 20), runners-view hits shell-spawn timeouts in tests this change did not touch. Those tests fail identically at the base commit, and all 99 pass with a longer timeout. No screenshot was taken: the app's Add-runner dialog needs a signed-in Puck/GitHub session, which isn't available here. The command that dialog copies was executed live instead.
Evidence: Live server release listing (HTTP response)
Evidence: Runner and app read the live listing identically
Evidence: Generated install script (layout-derived checks) installs a working runner
Evidence: Generated install script refuses a package missing README.md
Evidence: Real self-update swaps the layout's top-level files
Evidence: Live driver script
Evidence: Generated layout checks
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
src/harness/runner-releases.ts:459-isRunnerOsandisRunnerArchare a fresh spelling of the supported os/arch set that the module already defines inRUNNER_TARGETS(and thatrunnerTargetForat line 105-106 also inlines). The listing reader could derive them, e.g.RUNNER_TARGETS.some((t) => t.os === v)/.some((t) => t.arch === v), so a future target is added in one table. Not a defect: the server'sFILE_REin src/server/downloads.ts:28 emits exactly these values, and the independent os/arch check matches the server's regex semantics. Mechanical dedup only.test/unit/runners-view.test.ts:264- On this host under heavy load, test/unit/runners-view.test.ts 'installs with https/http transport', 'cleans staging after … failures' and 'checks prerequisites' time out at the default 5s (and the sandbox kills each shell at 10s), because each test spawns many shells. The same tests fail identically at the base commit 0e6add2, so this is a host-speed flake, not a regression. All 99 pass with --testTimeout=120000.npm run build:serverthen two live servers:PUCK_DEVELOPMENT=true PUCK_RUNNER_DOWNLOADS=<evidence>/downloads PUCK_RUNNER_MIN_VERSION=0.0.5 node .webpack/server/puck-server.js(port 18089) and a second one serving a tampered 0.1.1 package (port 18090)node scripts/package-runner.mjs --mode development --targets macos-arm64,linux-x64 --out <evidence>/downloads(real runner tarballs with bundled Node)curl -i http://localhost:18089/v1/runner/releases(server listing shape)jiti drive.ts listing: runnerServerApi.releases()and appreadRunnerReleaseListingagainst the live listing, sha256 cross-checked with the packaged .sha256 filesjiti drive.ts install: renderercommandsFor(assetFor(listing,'macos-arm64'))download block executed with sh against the live server, then the installedbin/puck-runner.cjs version --jsonrunjiti drive.ts install-missing: the same generated script against a live-served package missing README.mdjiti drive.ts self-update:findUpdate+applyUpdate(real tar, real sha256 check, real smoke test of the new bundled node) from 0.0.9 to the served 0.1.0npx vitest run test/unit/runner-releases.test.ts test/unit/runner-release-download.test.ts test/unit/runner-update.test.ts test/unit/server-downloads.test.ts(pass)npx vitest run test/unit/runners-view.test.ts -t "layout table|never publishes|cannot execute"(30 layout-derived tests pass)npx vitest run test/unit/runners-view.test.ts --testTimeout=120000(99/99 pass)Base-commit comparison:git checkout 0e6add2 -- src testthen the same failing runners-view tests (they time out identically), restored withgit checkout HEAD -- src test✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.