diff --git a/apps/browser-demos/pages/homebrew-fb-smoke/index.html b/apps/browser-demos/pages/homebrew-fb-smoke/index.html
new file mode 100644
index 000000000..5ecef4f98
--- /dev/null
+++ b/apps/browser-demos/pages/homebrew-fb-smoke/index.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Kandelo Homebrew Framebuffer Smoke
+
+
+
+ Loading
+
+
+
+
+
diff --git a/apps/browser-demos/pages/homebrew-fb-smoke/main.ts b/apps/browser-demos/pages/homebrew-fb-smoke/main.ts
new file mode 100644
index 000000000..753c1f42f
--- /dev/null
+++ b/apps/browser-demos/pages/homebrew-fb-smoke/main.ts
@@ -0,0 +1,263 @@
+import { BrowserKernel } from "@host/browser-kernel-host";
+import { ABI_VERSION } from "@host/generated/abi";
+import { MemoryFileSystem } from "@host/vfs/memory-fs";
+import { attachCanvas } from "@host/framebuffer/canvas-renderer";
+import kernelWasmUrl from "@kernel-wasm?url";
+
+/**
+ * Headless framebuffer/device smoke page for Kandelo Homebrew sidecars.
+ *
+ * Two device paths:
+ * - "fb": raw /dev/fb0 programs (fbdoom). Observes FramebufferRegistry
+ * bind + pixel-write activity and renders via attachCanvas (2D).
+ * - "kms": /dev/dri/card0 GLES programs (modeset). Transfers an
+ * OffscreenCanvas to the kernel worker via kmsAttachCanvas and
+ * reads page-flip / commit telemetry from a stats SAB.
+ *
+ * A program that binds a framebuffer + pushes writes ("fb"), or commits
+ * page-flips through the CRTC ("kms"), has reached the browser display path.
+ */
+interface FbSmokeRequest {
+ vfsUrl: string;
+ argv: string[];
+ mode?: "fb" | "kms";
+ crtcId?: number;
+ cwd?: string;
+ env?: string[];
+ observeMs?: number;
+ writeThreshold?: number;
+}
+
+interface FbSmokeResult {
+ mode: "fb" | "kms";
+ binds: number;
+ unbinds: number;
+ writes: number;
+ writeBytes: number;
+ kmsBlits: number;
+ kmsCommits: number;
+ boundPid: number | null;
+ width: number;
+ height: number;
+ fmt: string | null;
+ canvasNonBlankPixels: number;
+ exitedEarly: boolean;
+ exitCode: number | null;
+ durationMs: number;
+ stdoutTail: string;
+ stderrTail: string;
+}
+
+declare global {
+ interface Window {
+ __homebrewFbSmokeReady: boolean;
+ __runHomebrewFbSmoke: (request: FbSmokeRequest) => Promise;
+ }
+}
+
+const MODESET_FB_W = 1920;
+const MODESET_FB_H = 1080;
+
+const statusEl = document.getElementById("status")!;
+const logEl = document.getElementById("log")!;
+const canvas = document.getElementById("fb") as HTMLCanvasElement;
+const decoder = new TextDecoder();
+
+let kernelBytes: ArrayBuffer | null = null;
+
+function appendLog(text: string): void {
+ logEl.textContent += text;
+}
+
+async function fetchBytes(url: string, label: string): Promise {
+ const response = await fetch(url);
+ if (!response.ok) throw new Error(`${label} fetch failed: ${response.status} ${response.statusText}`);
+ return response.arrayBuffer();
+}
+
+function tail(text: string, max = 2000): string {
+ return text.length > max ? text.slice(text.length - max) : text;
+}
+
+function delay(ms: number): Promise {
+ return new Promise((resolve) => window.setTimeout(resolve, ms));
+}
+
+function countNonBlankPixels(): number {
+ const ctx = canvas.getContext("2d");
+ if (!ctx) return 0;
+ let data: ImageData;
+ try {
+ data = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ } catch {
+ return 0;
+ }
+ const px = data.data;
+ const first = [px[0], px[1], px[2]];
+ let nonBlank = 0;
+ for (let i = 0; i < px.length; i += 4) {
+ if (px[i] !== first[0] || px[i + 1] !== first[1] || px[i + 2] !== first[2]) nonBlank += 1;
+ }
+ return nonBlank;
+}
+
+async function runFbSmoke(request: FbSmokeRequest): Promise {
+ if (!kernelBytes) throw new Error("kernel wasm is not loaded");
+ if (!request.vfsUrl) throw new Error("vfsUrl is required");
+ if (!Array.isArray(request.argv) || request.argv.length === 0) throw new Error("argv must contain at least argv[0]");
+
+ const mode = request.mode ?? "fb";
+ const crtcId = request.crtcId ?? 1;
+ const observeMs = request.observeMs ?? 15_000;
+ const writeThreshold = request.writeThreshold ?? 1;
+ const start = performance.now();
+ let stdout = "";
+ let stderr = "";
+
+ const vfsBytes = new Uint8Array(await fetchBytes(request.vfsUrl, "Homebrew VFS"));
+ MemoryFileSystem.assertImageKernelAbi(vfsBytes, ABI_VERSION, "Homebrew fb smoke VFS");
+
+ const kernel = new BrowserKernel({
+ kernelOwnedFs: true,
+ onStdout: (data) => { const t = decoder.decode(data); stdout += t; appendLog(t); },
+ onStderr: (data) => { const t = decoder.decode(data); stderr += t; appendLog(t); },
+ });
+
+ // Shared metrics
+ let binds = 0, unbinds = 0, writes = 0, writeBytes = 0;
+ let boundPid: number | null = null;
+ let detachCanvas: (() => void) | null = null;
+ let width = 0, height = 0;
+ let fmt: string | null = null;
+
+ // KMS (modeset) telemetry via a stats SAB: [blit_count, ts_ms, width, height, tick_us, commit_count, last_frame_us]
+ let statsView: Int32Array | null = null;
+ const kmsCounts = () => ({
+ blits: statsView ? Atomics.load(statsView, 0) : 0,
+ commits: statsView ? Atomics.load(statsView, 5) : 0,
+ w: statsView ? Atomics.load(statsView, 2) : 0,
+ h: statsView ? Atomics.load(statsView, 3) : 0,
+ });
+
+ let offChange: (() => void) | null = null;
+ let offWrite: (() => void) | null = null;
+
+ // Prepare the KMS scanout canvas up front (transferControlToOffscreen
+ // detaches it from the main thread), but attach it to the kernel worker
+ // only after boot() — the worker does not exist before boot.
+ let kmsOffscreen: OffscreenCanvas | null = null;
+ let kmsStatsSab: SharedArrayBuffer | null = null;
+ if (mode === "kms") {
+ canvas.width = MODESET_FB_W;
+ canvas.height = MODESET_FB_H;
+ kmsStatsSab = new SharedArrayBuffer(7 * 4);
+ statsView = new Int32Array(kmsStatsSab);
+ kmsOffscreen = canvas.transferControlToOffscreen();
+ } else {
+ offChange = kernel.framebuffers.onChange((pid, ev) => {
+ if (ev === "bind") {
+ binds += 1;
+ const binding = kernel.framebuffers.get(pid);
+ if (binding) { width = binding.w; height = binding.h; fmt = binding.fmt; }
+ if (boundPid === null) {
+ boundPid = pid;
+ try {
+ if (width > 0 && height > 0) { canvas.width = width; canvas.height = height; }
+ detachCanvas = attachCanvas(canvas, kernel.framebuffers, pid, {
+ getProcessMemory: (p) => kernel.getProcessMemory(p),
+ });
+ } catch (err) {
+ appendLog(`attachCanvas failed: ${err instanceof Error ? err.message : String(err)}\n`);
+ }
+ }
+ } else {
+ unbinds += 1;
+ }
+ });
+ offWrite = kernel.framebuffers.onWrite((_pid, _offset, bytes) => { writes += 1; writeBytes += bytes.length; });
+ }
+
+ let exitedEarly = false;
+ let exitCode: number | null = null;
+
+ try {
+ const defaultEnv = [
+ "HOME=/tmp", "TMPDIR=/tmp", "TERM=xterm-256color", "LANG=en_US.UTF-8",
+ "PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/bin:/usr/bin:/bin",
+ ];
+ const { exit } = await kernel.boot({
+ kernelWasm: kernelBytes,
+ vfsImage: vfsBytes,
+ argv: request.argv,
+ cwd: request.cwd ?? "/",
+ env: [...defaultEnv, ...(request.env ?? [])],
+ uid: 0,
+ gid: 0,
+ // Framebuffer/KMS programs set up keyboard input via /dev/tty and query
+ // terminal settings; without a PTY they exit at keyboard init.
+ pty: true,
+ });
+ exit.then((code) => { exitedEarly = true; exitCode = code; }).catch(() => {});
+
+ // Attach the KMS scanout canvas now that the kernel worker exists. The
+ // worker holds the CRTC framebuffer and scans it out to this canvas once
+ // modeset binds /dev/dri/card0 and commits page flips.
+ if (mode === "kms" && kmsOffscreen && kmsStatsSab) {
+ kernel.kmsAttachCanvas(crtcId, kmsOffscreen, kmsStatsSab, { mode: "webgl2" });
+ }
+
+ const hasActivity = () =>
+ mode === "kms" ? (kmsCounts().commits >= 1 || kmsCounts().blits >= 1) : (writes >= writeThreshold && binds >= 1);
+
+ const deadline = performance.now() + observeMs;
+ while (performance.now() < deadline) {
+ if (hasActivity()) { await delay(800); break; }
+ if (exitedEarly) break;
+ await delay(200);
+ }
+ await delay(400);
+ } finally {
+ offChange?.();
+ offWrite?.();
+ detachCanvas?.();
+ await kernel.destroy().catch(() => {});
+ }
+
+ const kms = kmsCounts();
+ if (mode === "kms") { width = kms.w; height = kms.h; }
+
+ return {
+ mode,
+ binds,
+ unbinds,
+ writes,
+ writeBytes,
+ kmsBlits: kms.blits,
+ kmsCommits: kms.commits,
+ boundPid,
+ width,
+ height,
+ fmt,
+ canvasNonBlankPixels: mode === "kms" ? -1 : countNonBlankPixels(),
+ exitedEarly,
+ exitCode,
+ durationMs: Math.round(performance.now() - start),
+ stdoutTail: tail(stdout),
+ stderrTail: tail(stderr),
+ };
+}
+
+async function init(): Promise {
+ kernelBytes = await fetchBytes(kernelWasmUrl, "kernel.wasm");
+ window.__runHomebrewFbSmoke = runFbSmoke;
+ window.__homebrewFbSmokeReady = true;
+ statusEl.textContent = "Ready";
+}
+
+window.__homebrewFbSmokeReady = false;
+init().catch((err) => {
+ const message = err instanceof Error ? err.message : String(err);
+ statusEl.textContent = `Error: ${message}`;
+ appendLog(`${message}\n`);
+ console.error("Homebrew fb smoke init failed:", err);
+});
diff --git a/apps/browser-demos/pages/homebrew-smoke/index.html b/apps/browser-demos/pages/homebrew-smoke/index.html
new file mode 100644
index 000000000..b560e65ff
--- /dev/null
+++ b/apps/browser-demos/pages/homebrew-smoke/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+ Kandelo Homebrew Browser Smoke
+
+
+
+ Loading
+
+
+
+
diff --git a/apps/browser-demos/pages/homebrew-smoke/main.ts b/apps/browser-demos/pages/homebrew-smoke/main.ts
new file mode 100644
index 000000000..4e1bc925a
--- /dev/null
+++ b/apps/browser-demos/pages/homebrew-smoke/main.ts
@@ -0,0 +1,128 @@
+import { BrowserKernel } from "@host/browser-kernel-host";
+import { ABI_VERSION } from "@host/generated/abi";
+import { MemoryFileSystem } from "@host/vfs/memory-fs";
+import kernelWasmUrl from "@kernel-wasm?url";
+
+interface HomebrewSmokeRequest {
+ vfsUrl: string;
+ argv: string[];
+ timeoutMs?: number;
+ cwd?: string;
+ env?: string[];
+ stdin?: string;
+}
+
+interface HomebrewSmokeResult {
+ exitCode: number;
+ stdout: string;
+ stderr: string;
+ combined: string;
+ durationMs: number;
+}
+
+declare global {
+ interface Window {
+ __homebrewSmokeReady: boolean;
+ __runHomebrewSmoke: (request: HomebrewSmokeRequest) => Promise;
+ }
+}
+
+const statusEl = document.getElementById("status")!;
+const logEl = document.getElementById("log")!;
+const decoder = new TextDecoder();
+
+let kernelBytes: ArrayBuffer | null = null;
+
+function appendLog(text: string): void {
+ logEl.textContent += text;
+}
+
+async function fetchBytes(url: string, label: string): Promise {
+ const response = await fetch(url);
+ if (!response.ok) {
+ throw new Error(`${label} fetch failed: ${response.status} ${response.statusText}`);
+ }
+ return response.arrayBuffer();
+}
+
+function timeoutAfter(ms: number): Promise {
+ return new Promise((_, reject) => {
+ window.setTimeout(() => reject(new Error("TIMEOUT")), ms);
+ });
+}
+
+async function runHomebrewSmoke(request: HomebrewSmokeRequest): Promise {
+ if (!kernelBytes) throw new Error("kernel wasm is not loaded");
+ if (!request.vfsUrl) throw new Error("vfsUrl is required");
+ if (!Array.isArray(request.argv) || request.argv.length === 0) {
+ throw new Error("argv must contain at least argv[0]");
+ }
+
+ const start = performance.now();
+ let stdout = "";
+ let stderr = "";
+ const vfsBytes = new Uint8Array(await fetchBytes(request.vfsUrl, "Homebrew VFS"));
+ MemoryFileSystem.assertImageKernelAbi(vfsBytes, ABI_VERSION, "Homebrew smoke VFS");
+
+ const kernel = new BrowserKernel({
+ kernelOwnedFs: true,
+ onStdout: (data) => {
+ const text = decoder.decode(data);
+ stdout += text;
+ appendLog(text);
+ },
+ onStderr: (data) => {
+ const text = decoder.decode(data);
+ stderr += text;
+ appendLog(text);
+ },
+ });
+
+ try {
+ const defaultEnv = [
+ "HOME=/tmp",
+ "TMPDIR=/tmp",
+ "TERM=xterm-256color",
+ "LANG=en_US.UTF-8",
+ "PATH=/home/linuxbrew/.linuxbrew/bin:/usr/local/bin:/usr/bin:/bin",
+ ];
+ const { exit } = await kernel.boot({
+ kernelWasm: kernelBytes,
+ vfsImage: vfsBytes,
+ argv: request.argv,
+ cwd: request.cwd ?? "/",
+ env: [...defaultEnv, ...(request.env ?? [])],
+ uid: 0,
+ gid: 0,
+ stdin: request.stdin === undefined ? new Uint8Array(0) : new TextEncoder().encode(request.stdin),
+ });
+ const exitCode = await Promise.race([
+ exit,
+ timeoutAfter(request.timeoutMs ?? 180_000),
+ ]);
+ return {
+ exitCode,
+ stdout,
+ stderr,
+ combined: `${stdout}${stderr}`,
+ durationMs: Math.round(performance.now() - start),
+ };
+ } finally {
+ await kernel.destroy().catch(() => {});
+ }
+}
+
+async function init(): Promise {
+ kernelBytes = await fetchBytes(kernelWasmUrl, "kernel.wasm");
+ window.__runHomebrewSmoke = runHomebrewSmoke;
+ window.__homebrewSmokeReady = true;
+ statusEl.textContent = "Ready";
+}
+
+window.__homebrewSmokeReady = false;
+init().catch((err) => {
+ const message = err instanceof Error ? err.message : String(err);
+ statusEl.textContent = `Error: ${message}`;
+ appendLog(`${message}\n`);
+ console.error("Homebrew smoke init failed:", err);
+});
diff --git a/apps/browser-demos/vite.config.ts b/apps/browser-demos/vite.config.ts
index f517aaba2..11d4567fe 100644
--- a/apps/browser-demos/vite.config.ts
+++ b/apps/browser-demos/vite.config.ts
@@ -403,6 +403,8 @@ const defaultDemoInputs = {
const demoInputs = {
...defaultDemoInputs,
+ "homebrew-smoke": path.resolve(__dirname, "pages/homebrew-smoke/index.html"),
+ "homebrew-fb-smoke": path.resolve(__dirname, "pages/homebrew-fb-smoke/index.html"),
"sqlite-test": path.resolve(__dirname, "pages/sqlite-test/index.html"),
// The perl, python, ruby, erlang, texlive, and redis package entries
// are not bundled into this static build while their slow builds
diff --git a/docs/homebrew-publishing.md b/docs/homebrew-publishing.md
index d14760066..37425fb2b 100644
--- a/docs/homebrew-publishing.md
+++ b/docs/homebrew-publishing.md
@@ -215,6 +215,57 @@ path calls `scripts/homebrew-publish-sidecars.sh --status failed` so the failed
attempt is durable while the previous successful bottle remains selectable when
its fallback fields are complete.
+The default trusted sidecar wrapper,
+`scripts/homebrew-generate-sidecars-from-env.sh`, derives non-hello link
+manifests from package kind. Program Formulae link their installed
+`bin/` into the Homebrew prefix. Library Formulae link the declared
+`[outputs]` headers, static libraries, and pkg-config files from the keg into
+the prefix. Package-specific Node and browser outcome text may be supplied via
+`KANDELO_HOMEBREW_NODE_SMOKE_COMMAND`,
+`KANDELO_HOMEBREW_BROWSER_SMOKE_STATUS`, and
+`KANDELO_HOMEBREW_BROWSER_SMOKE_REASON`; browser compatibility is recorded
+only when `KANDELO_HOMEBREW_BROWSER_SMOKE_STATUS=success` and the browser VFS
+smoke artifact environment is complete.
+
+### Fork Instrumentation Disposition
+
+Every bottle records a `fork_instrumentation` disposition. The schema and the
+composite-status planner accept only four values:
+
+- `required`: the program forks/execs at runtime (shell pipelines, command
+ substitution, subshells, `:!` shell-outs, hooks, pagers, credential
+ helpers), so `wasm-fork-instrument` transformed the binary and the kernel
+ must provide the fork import.
+- `not-required`: the program never forks; `wasm-fork-instrument` was a no-op
+ and the binary is byte-identical.
+- `disabled`: fork instrumentation was deliberately turned off for the binary.
+- `unknown`: the disposition has not been determined.
+
+`auto` is a build-time placeholder, not a publishable value; it must never
+reach a sidecar. The trusted wrapper derives the bottle disposition from the
+per-output `fork_instrumentation` declared in `packages/registry//
+package.toml`. Declare it on each `[[outputs]]` entry (or once at the package
+top level). Outputs are aggregated conservatively: any `required` output makes
+the whole bottle `required`; a package that declares nothing is reported as
+`unknown` rather than an invalid `auto`. Whether a program forks matches
+whether its `build-.sh` applies `wasm-fork-instrument` to a forking
+binary (see `docs/fork-instrumentation.md`).
+
+### Bottle URLs Must Be Publishable
+
+A bottle's `url` (and any `fallback_url`) must be an `https://` address, the
+canonical publish destination for the bytes:
+
+- GHCR OCI blob (what `scripts/homebrew-ghcr-upload.sh` produces):
+ `https://ghcr.io/v2/automattic/kandelo-homebrew//blobs/sha256:`.
+
+A `file://` url is only a local pre-publish build artifact. It fails both the
+sidecar schema (`httpsUrl`) and the composite-status planner, so it is never a
+publishable disposition. The bottle bytes still have to be uploaded to that
+`https` destination by the trusted publish flow before the url resolves;
+recording the canonical url makes the sidecar structurally publishable, and the
+upload is the remaining publication step.
+
## VFS Planning And Building
Homebrew-derived VFS images are built from sidecars and verified bottle bytes,
@@ -265,6 +316,26 @@ It clones or reads the tap, builds a Homebrew VFS from published sidecars, runs
`/home/linuxbrew/.linuxbrew/bin/hello --version` through `NodeKernelHost`, and
checks negative ABI-mismatch and missing-bottle cases.
+For the sqlite/bzip2/xz pilot and later non-hello package checks, use the
+generic package smoke runner against a generated tap root:
+
+```bash
+npx tsx scripts/homebrew-package-node-smoke.ts \
+ --tap-root /path/to/kandelo-homebrew \
+ --formula sqlite \
+ --formula bzip2 \
+ --formula xz \
+ --arch wasm32 \
+ --result-dir test-runs/homebrew-package-node-smoke
+```
+
+The runner builds Homebrew VFS images from sidecars, writes passed, failed,
+and skipped outcome lists, runs program package version smokes from the poured
+prefix, and compiles SQLite's `sqlite_basic.c` against the poured headers and
+static library before running the validation Wasm on Node. Dry-run bottle
+evidence remains local evidence until the trusted workflow publishes GHCR
+bottle bytes and tap sidecars.
+
Browser compatibility requires a separate browser smoke. For the current
`hello` path, the trusted publisher builds a precomposed wasm32 VFS image,
serves it through the browser demo, runs Chromium Playwright against
diff --git a/homebrew/kandelo-homebrew/Formula/dash.rb b/homebrew/kandelo-homebrew/Formula/dash.rb
new file mode 100644
index 000000000..bf2dd6847
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/dash.rb
@@ -0,0 +1,33 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Dash < Formula
+ include KandeloFormulaSupport
+
+ desc "POSIX shell for Kandelo"
+ homepage "http://gondor.apana.org.au/~herbert/dash/"
+ url "http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.12.tar.gz"
+ sha256 "6a474ac46e8b0b32916c4c60df694c82058d3297d8b385b74508030ca4a8f28a"
+ license all_of: ["BSD-3-Clause", "GPL-2.0-or-later"]
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8"
+ end
+
+ skip_clean "bin/dash"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["DASH_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.12.tar.gz", source_sha256: "6a474ac46e8b0b32916c4c60df694c82058d3297d8b385b74508030ca4a8f28a")
+ system "bash", "#{root}/packages/registry/dash/build-dash.sh"
+ install_kandelo_wasm(out_dir, "dash.wasm", "dash")
+ end
+
+ test do
+ assert_kandelo_wasm "dash"
+ assert_match "dash-homebrew-smoke", shell_output_kandelo_wasm("dash", ["-c", "echo dash-homebrew-smoke"])
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/fbdoom.rb b/homebrew/kandelo-homebrew/Formula/fbdoom.rb
new file mode 100644
index 000000000..67de69781
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/fbdoom.rb
@@ -0,0 +1,31 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Fbdoom < Formula
+ include KandeloFormulaSupport
+
+ desc "fbDOOM framebuffer game port for Kandelo"
+ homepage "https://github.com/maximevince/fbDOOM"
+ url "https://github.com/maximevince/fbDOOM.git", branch: "master"
+ version "0.1.0"
+ license "GPL-2.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c"
+ end
+
+ skip_clean "bin/fbdoom"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/maximevince/fbDOOM", source_sha256: "0000000000000000000000000000000000000000000000000000000000000000")
+ system "bash", "#{root}/packages/registry/fbdoom/build-fbdoom.sh"
+ install_kandelo_wasm(out_dir, "fbdoom.wasm", "fbdoom")
+ end
+
+ test do
+ assert_kandelo_wasm "fbdoom"
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/git.rb b/homebrew/kandelo-homebrew/Formula/git.rb
new file mode 100644
index 000000000..600a54894
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/git.rb
@@ -0,0 +1,39 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Git < Formula
+ include KandeloFormulaSupport
+
+ desc "Distributed revision control system for Kandelo"
+ homepage "https://git-scm.com/"
+ url "https://github.com/git/git/archive/refs/tags/v2.47.1.tar.gz"
+ sha256 "30654cc6c0142fa68050cc7b0ee6a2a65944288b907821781112efaf24293b23"
+ license "GPL-2.0-only"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f"
+ end
+
+ skip_clean "bin/git"
+ skip_clean "bin/git-remote-http"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["GIT_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/git/git/archive/refs/tags/v2.47.1.tar.gz", source_sha256: "30654cc6c0142fa68050cc7b0ee6a2a65944288b907821781112efaf24293b23")
+ system "bash", "#{root}/packages/registry/git/build-git.sh"
+ install_kandelo_wasm(out_dir, "git.wasm", "git")
+ install_kandelo_wasm(out_dir, "git-remote-http.wasm", "git-remote-http")
+ bin.install_symlink "git-remote-http" => "git-remote-https"
+ bin.install_symlink "git-remote-http" => "git-remote-ftp"
+ bin.install_symlink "git-remote-http" => "git-remote-ftps"
+ end
+
+ test do
+ assert_kandelo_wasm "git"
+ assert_kandelo_wasm "git-remote-http"
+ assert_match "git version", shell_output_kandelo_wasm("git", ["--version"])
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/less.rb b/homebrew/kandelo-homebrew/Formula/less.rb
new file mode 100644
index 000000000..02a9a7f17
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/less.rb
@@ -0,0 +1,33 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Less < Formula
+ include KandeloFormulaSupport
+
+ desc "Terminal pager for Kandelo"
+ homepage "https://www.greenwoodsoftware.com/less/"
+ url "https://www.greenwoodsoftware.com/less/less-668.tar.gz"
+ sha256 "2819f55564d86d542abbecafd82ff61e819a3eec967faa36cd3e68f1596a44b8"
+ license "GPL-3.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061"
+ end
+
+ skip_clean "bin/less"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["LESS_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://www.greenwoodsoftware.com/less/less-668.tar.gz", source_sha256: "2819f55564d86d542abbecafd82ff61e819a3eec967faa36cd3e68f1596a44b8")
+ system "bash", "#{root}/packages/registry/less/build-less.sh"
+ install_kandelo_wasm(out_dir, "less.wasm", "less")
+ end
+
+ test do
+ assert_kandelo_wasm "less"
+ assert_match "less", shell_output_kandelo_wasm("less", ["--version"])
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/lsof.rb b/homebrew/kandelo-homebrew/Formula/lsof.rb
new file mode 100644
index 000000000..c839f2f55
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/lsof.rb
@@ -0,0 +1,32 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Lsof < Formula
+ include KandeloFormulaSupport
+
+ desc "Kandelo /proc file descriptor lister"
+ homepage "https://github.com/brandonpayton/kandelo"
+ url "https://github.com/Automattic/kandelo/archive/1ab41fe2ad5553f4fa4bb0223f2d804b13149578.tar.gz"
+ sha256 "446dd26b6e3f909f25f21f77950a3b11a07c633721dbff698a85b4f05fbbc493"
+ version "0.1.0"
+ license "GPL-2.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b"
+ end
+
+ skip_clean "bin/lsof"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/Automattic/kandelo/archive/1ab41fe2ad5553f4fa4bb0223f2d804b13149578.tar.gz", source_sha256: "446dd26b6e3f909f25f21f77950a3b11a07c633721dbff698a85b4f05fbbc493")
+ system "bash", "#{root}/packages/registry/lsof/build-lsof.sh"
+ install_kandelo_wasm(out_dir, "lsof.wasm", "lsof")
+ end
+
+ test do
+ assert_kandelo_wasm "lsof"
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/modeset.rb b/homebrew/kandelo-homebrew/Formula/modeset.rb
new file mode 100644
index 000000000..6e0fe049f
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/modeset.rb
@@ -0,0 +1,32 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Modeset < Formula
+ include KandeloFormulaSupport
+
+ desc "DRI/GLES framebuffer fluid simulation for Kandelo"
+ homepage "https://github.com/brandonpayton/kandelo"
+ url "https://github.com/Automattic/kandelo/archive/1ab41fe2ad5553f4fa4bb0223f2d804b13149578.tar.gz"
+ sha256 "446dd26b6e3f909f25f21f77950a3b11a07c633721dbff698a85b4f05fbbc493"
+ version "0.1.0"
+ license "GPL-2.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88"
+ end
+
+ skip_clean "bin/modeset"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/Automattic/kandelo/archive/1ab41fe2ad5553f4fa4bb0223f2d804b13149578.tar.gz", source_sha256: "446dd26b6e3f909f25f21f77950a3b11a07c633721dbff698a85b4f05fbbc493")
+ system "bash", "#{root}/packages/registry/modeset/build-modeset.sh"
+ install_kandelo_wasm(out_dir, "modeset.wasm", "modeset")
+ end
+
+ test do
+ assert_kandelo_wasm "modeset"
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/msmtpd.rb b/homebrew/kandelo-homebrew/Formula/msmtpd.rb
new file mode 100644
index 000000000..72d447d34
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/msmtpd.rb
@@ -0,0 +1,32 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Msmtpd < Formula
+ include KandeloFormulaSupport
+
+ desc "SMTP capture daemon from msmtp for Kandelo"
+ homepage "https://marlam.de/msmtp/"
+ url "https://marlam.de/msmtp/releases/msmtp-1.8.32.tar.xz"
+ sha256 "20cd58b58dd007acf7b937fa1a1e21f3afb3e9ef5bbcfb8b4f5650deadc64db4"
+ license "GPL-3.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "ff2c0e456efbfe2d03b30dea2f8462a7f3818146715e3dc78ab5f21580a88691"
+ end
+
+ skip_clean "bin/msmtpd"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ out_dir = prepare_kandelo_package_env(source_url: "https://marlam.de/msmtp/releases/msmtp-1.8.32.tar.xz", source_sha256: "20cd58b58dd007acf7b937fa1a1e21f3afb3e9ef5bbcfb8b4f5650deadc64db4")
+ system "bash", "#{root}/packages/registry/msmtpd/build-msmtpd.sh"
+ install_kandelo_wasm(out_dir, "msmtpd.wasm", "msmtpd")
+ end
+
+ test do
+ assert_kandelo_wasm "msmtpd"
+ assert_match(/msmtp|msmtpd/i, shell_output_kandelo_wasm("msmtpd", ["--version"]))
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/nano.rb b/homebrew/kandelo-homebrew/Formula/nano.rb
new file mode 100644
index 000000000..cf2188889
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/nano.rb
@@ -0,0 +1,33 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Nano < Formula
+ include KandeloFormulaSupport
+
+ desc "Terminal text editor for Kandelo"
+ homepage "https://www.nano-editor.org/"
+ url "https://ftpmirror.gnu.org/gnu/nano/nano-8.0.tar.xz"
+ sha256 "c17f43fc0e37336b33ee50a209c701d5beb808adc2d9f089ca831b40539c9ac4"
+ license "GPL-3.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0"
+ end
+
+ skip_clean "bin/nano"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["NANO_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://ftpmirror.gnu.org/gnu/nano/nano-8.0.tar.xz", source_sha256: "c17f43fc0e37336b33ee50a209c701d5beb808adc2d9f089ca831b40539c9ac4")
+ system "bash", "#{root}/packages/registry/nano/build-nano.sh"
+ install_kandelo_wasm(out_dir, "nano.wasm", "nano")
+ end
+
+ test do
+ assert_kandelo_wasm "nano"
+ assert_match(/GNU nano|nano/i, shell_output_kandelo_wasm("nano", ["--version"]))
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/netcat.rb b/homebrew/kandelo-homebrew/Formula/netcat.rb
new file mode 100644
index 000000000..b310390ee
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/netcat.rb
@@ -0,0 +1,34 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Netcat < Formula
+ include KandeloFormulaSupport
+
+ desc "GNU netcat network utility for Kandelo"
+ homepage "https://sourceforge.net/projects/netcat/"
+ url "https://downloads.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz"
+ sha256 "30719c9a4ffbcf15676b8f528233ccc54ee6cba96cb4590975f5fd60c68a066f"
+ license "GPL-2.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd"
+ end
+
+ skip_clean "bin/nc"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["NETCAT_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://downloads.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz", source_sha256: "30719c9a4ffbcf15676b8f528233ccc54ee6cba96cb4590975f5fd60c68a066f")
+ system "bash", "#{root}/packages/registry/netcat/build-netcat.sh"
+ install_kandelo_wasm(out_dir, "nc.wasm", "nc")
+ bin.install_symlink "nc" => "netcat"
+ end
+
+ test do
+ assert_kandelo_wasm "nc"
+ assert_match(/netcat|listen|connect|usage/i, shell_output_kandelo_wasm("nc", ["--help"]))
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/vim.rb b/homebrew/kandelo-homebrew/Formula/vim.rb
new file mode 100644
index 000000000..461cfcf70
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/vim.rb
@@ -0,0 +1,34 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Vim < Formula
+ include KandeloFormulaSupport
+
+ desc "Vim terminal editor for Kandelo"
+ homepage "https://www.vim.org/"
+ url "https://github.com/vim/vim/archive/refs/tags/v9.1.0900.tar.gz"
+ sha256 "30efb714ed82c5d7a1491f3e4aac6487d2c493d33c834d7ef043e6f45176772e"
+ license "Vim"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae"
+ end
+
+ skip_clean "bin/vim"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["VIM_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/vim/vim/archive/refs/tags/v9.1.0900.tar.gz", source_sha256: "30efb714ed82c5d7a1491f3e4aac6487d2c493d33c834d7ef043e6f45176772e")
+ system "bash", "#{root}/packages/registry/vim/build-vim.sh"
+ install_kandelo_wasm(out_dir, "vim.wasm", "vim")
+ (share/"vim").install out_dir/"runtime" if (out_dir/"runtime").directory?
+ end
+
+ test do
+ assert_kandelo_wasm "vim"
+ assert_match(/VIM|Vi IMproved/i, shell_output_kandelo_wasm("vim", ["--version"]))
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Formula/wget.rb b/homebrew/kandelo-homebrew/Formula/wget.rb
new file mode 100644
index 000000000..ade787e42
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Formula/wget.rb
@@ -0,0 +1,33 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Wget < Formula
+ include KandeloFormulaSupport
+
+ desc "GNU Wget network downloader for Kandelo"
+ homepage "https://www.gnu.org/software/wget/"
+ url "https://ftpmirror.gnu.org/gnu/wget/wget-1.25.0.tar.gz"
+ sha256 "766e48423e79359ea31e41db9e5c289675947a7fcf2efdcedb726ac9d0da3784"
+ license "GPL-3.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad"
+ end
+
+ skip_clean "bin/wget"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["WGET_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://ftpmirror.gnu.org/gnu/wget/wget-1.25.0.tar.gz", source_sha256: "766e48423e79359ea31e41db9e5c289675947a7fcf2efdcedb726ac9d0da3784")
+ system "bash", "#{root}/packages/registry/wget/build-wget.sh"
+ install_kandelo_wasm(out_dir, "wget.wasm", "wget")
+ end
+
+ test do
+ assert_kandelo_wasm "wget"
+ assert_match(/GNU Wget|Wget/i, shell_output_kandelo_wasm("wget", ["--version"]))
+ end
+end
diff --git a/homebrew/kandelo-homebrew/Kandelo/kandelo_formula_support.rb b/homebrew/kandelo-homebrew/Kandelo/kandelo_formula_support.rb
new file mode 100644
index 000000000..58113b069
--- /dev/null
+++ b/homebrew/kandelo-homebrew/Kandelo/kandelo_formula_support.rb
@@ -0,0 +1,73 @@
+module KandeloFormulaSupport
+ def kandelo_root
+ root = ENV["HOMEBREW_KANDELO_ROOT"] || ENV["KANDELO_HOMEBREW_KANDELO_ROOT"]
+ odie "HOMEBREW_KANDELO_ROOT must point at a Kandelo checkout" if root.to_s.empty?
+ root
+ end
+
+ def kandelo_arch
+ ENV.fetch("HOMEBREW_KANDELO_ARCH", ENV.fetch("KANDELO_HOMEBREW_ARCH", "wasm32"))
+ end
+
+ def configure_kandelo_environment(root = kandelo_root)
+ %w[
+ CC CXX OBJC OBJCXX CFLAGS CPPFLAGS CXXFLAGS LDFLAGS CPATH
+ C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH SDKROOT
+ MACOSX_DEPLOYMENT_TARGET
+ ].each { |key| ENV.delete(key) }
+
+ ENV.prepend_path "PATH", "#{root}/sdk/bin"
+ if (node = ENV["HOMEBREW_KANDELO_NODE"]).to_s != ""
+ ENV.prepend_path "PATH", File.dirname(node)
+ end
+ if (llvm_bin = ENV["HOMEBREW_KANDELO_LLVM_BIN"]).to_s != ""
+ ENV["WASM_POSIX_LLVM_DIR"] = llvm_bin
+ ENV["LLVM_BIN"] = llvm_bin
+ ENV.prepend_path "PATH", llvm_bin
+ end
+ if (rust_bin = ENV["HOMEBREW_KANDELO_RUST_BIN"]).to_s != ""
+ ENV.prepend_path "PATH", rust_bin
+ end
+ if (binaryen_bin = ENV["HOMEBREW_KANDELO_BINARYEN_BIN"]).to_s != ""
+ ENV.prepend_path "PATH", binaryen_bin
+ end
+ if (pkg_config = ENV["HOMEBREW_KANDELO_PKG_CONFIG"]).to_s != ""
+ ENV["PKG_CONFIG"] = pkg_config
+ end
+ end
+
+ def prepare_kandelo_package_env(source_url:, source_sha256:)
+ out_dir = buildpath/"kandelo-package-out"
+ ENV["WASM_POSIX_DEP_VERSION"] = version.to_s
+ ENV["WASM_POSIX_DEP_SOURCE_URL"] = source_url
+ ENV["WASM_POSIX_DEP_SOURCE_SHA256"] = source_sha256
+ ENV["WASM_POSIX_DEP_OUT_DIR"] = out_dir.to_s
+ ENV["WASM_POSIX_DEP_WORK_DIR"] = (buildpath/"kandelo-package-work").to_s
+ ENV["WASM_POSIX_DEP_TARGET_ARCH"] = kandelo_arch
+ ENV["WASM_POSIX_SKIP_LOCAL_BINARY_INSTALL"] = "1"
+ ENV["CARGO_TARGET_DIR"] = (buildpath/"kandelo-cargo-target").to_s
+ out_dir
+ end
+
+ def install_kandelo_wasm(out_dir, wasm_name, installed_name = wasm_name.delete_suffix(".wasm"))
+ source = out_dir/wasm_name
+ chmod 0755, source
+ bin.install source => installed_name
+ chmod 0755, bin/installed_name
+ end
+
+ def assert_kandelo_wasm(installed_name)
+ assert_equal "\0asm".b, File.binread(bin/installed_name, 4)
+ end
+
+ def shell_output_kandelo_wasm(installed_name, args = [], stderr: true)
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ test_wasm = testpath/"#{installed_name}.wasm"
+ File.binwrite(test_wasm, File.binread(bin/installed_name))
+ redirect = stderr ? " 2>&1" : ""
+ shell_output(
+ "cd #{root.shellescape} && node --experimental-wasm-exnref --import tsx/esm examples/run-example.ts #{test_wasm.to_s.shellescape} #{args.shelljoin}#{redirect}",
+ )
+ end
+end
diff --git a/host/src/homebrew-vfs-planner.ts b/host/src/homebrew-vfs-planner.ts
index 721a0cd0e..a3b8085da 100644
--- a/host/src/homebrew-vfs-planner.ts
+++ b/host/src/homebrew-vfs-planner.ts
@@ -4,6 +4,19 @@ export type HomebrewBottleArch = "wasm32" | "wasm64";
export type HomebrewRuntime = "node" | "browser";
export type HomebrewBottleStatus = "success" | "failed" | "pending" | "building";
export type HomebrewBottleSourceStatus = "success" | "fallback";
+export type HomebrewRuntimeStatusKind = "supported" | "unsupported" | "failed" | "not-validated";
+
+export interface HomebrewRuntimeArtifactPolicyFailure {
+ path: string;
+ failures: string[];
+}
+
+export interface HomebrewRuntimeStatus {
+ status: HomebrewRuntimeStatusKind;
+ reason_code?: string;
+ reason?: string;
+ artifact_policy_failures?: HomebrewRuntimeArtifactPolicyFailure[];
+}
export interface HomebrewDependency {
name: string;
@@ -17,6 +30,7 @@ export interface HomebrewMetadataBottle {
cellar: string;
prefix: string;
runtime_support: HomebrewRuntime[];
+ runtime_status?: Partial>;
browser_compatible: boolean;
fork_instrumentation: string;
status: HomebrewBottleStatus;
@@ -151,6 +165,30 @@ export class HomebrewVfsPlanError extends Error {
}
}
+export class HomebrewVfsUnsupportedError extends HomebrewVfsPlanError {
+ readonly packageName: string;
+ readonly arch: HomebrewBottleArch;
+ readonly runtime: HomebrewRuntime;
+ readonly runtimeStatus?: HomebrewRuntimeStatus;
+
+ constructor(args: {
+ packageName: string;
+ arch: HomebrewBottleArch;
+ runtime: HomebrewRuntime;
+ runtimeStatus?: HomebrewRuntimeStatus;
+ }) {
+ const reason = args.runtimeStatus?.reason_code
+ ? ` (${args.runtimeStatus.reason_code})`
+ : "";
+ super(`package ${quote(args.packageName)} bottle ${args.arch} does not support ${args.runtime}${reason}`);
+ this.name = "HomebrewVfsUnsupportedError";
+ this.packageName = args.packageName;
+ this.arch = args.arch;
+ this.runtime = args.runtime;
+ this.runtimeStatus = args.runtimeStatus;
+ }
+}
+
interface SelectedBottle {
metadataStatus: HomebrewBottleStatus;
sourceStatus: HomebrewBottleSourceStatus;
@@ -164,7 +202,7 @@ interface SelectedBottle {
const PACKAGE_RE = /^[a-z0-9][a-z0-9._-]*$/;
const SHA256_RE = /^[0-9a-f]{64}$/;
-const SAFE_REL_SEGMENT_RE = /^[A-Za-z0-9._@%+=:-]+$/;
+const SAFE_REL_SEGMENT_RE = /^[A-Za-z0-9._@%+=:\[\]-]+$/;
export async function planHomebrewVfs(
metadataValue: unknown,
@@ -263,6 +301,7 @@ function parseMetadataBottle(value: unknown, label: string): HomebrewMetadataBot
const runtimeSupport = requiredArray(bottle, "runtime_support", label).map((entry, index) =>
parseRuntime(entry, `${label}.runtime_support[${index}]`)
);
+ const runtimeStatus = parseRuntimeStatusByHost(bottle.runtime_status, `${label}.runtime_status`);
const browserCompatible = requiredBoolean(bottle, "browser_compatible", label);
return {
@@ -272,6 +311,7 @@ function parseMetadataBottle(value: unknown, label: string): HomebrewMetadataBot
cellar: requiredString(bottle, "cellar", label),
prefix: requiredString(bottle, "prefix", label),
runtime_support: runtimeSupport,
+ runtime_status: runtimeStatus,
browser_compatible: browserCompatible,
fork_instrumentation: requiredString(bottle, "fork_instrumentation", label),
status,
@@ -507,14 +547,52 @@ function validateBottleIdentity(
`package ${quote(pkg.name)} bottle ${bottle.arch} has bottle_tag ${quote(bottle.bottle_tag)}, expected ${quote(expectedTag)}`,
);
}
+ validateRuntimeStatusConsistency(pkg, bottle);
if (runtime !== undefined && !bottle.runtime_support.includes(runtime)) {
- fail(`package ${quote(pkg.name)} bottle ${bottle.arch} does not support ${runtime}`);
+ throw new HomebrewVfsUnsupportedError({
+ packageName: pkg.name,
+ arch: bottle.arch,
+ runtime,
+ runtimeStatus: bottle.runtime_status?.[runtime],
+ });
}
if (runtime === "browser" && !bottle.browser_compatible) {
fail(`package ${quote(pkg.name)} bottle ${bottle.arch} is not browser compatible`);
}
}
+function validateRuntimeStatusConsistency(
+ pkg: HomebrewMetadataPackage,
+ bottle: HomebrewMetadataBottle,
+): void {
+ let hasArtifactPolicyFailures = false;
+ for (const runtime of ["node", "browser"] as const) {
+ const status = bottle.runtime_status?.[runtime];
+ const supportsRuntime = bottle.runtime_support.includes(runtime);
+ if (bottle.runtime_support.length === 0 && status === undefined) {
+ fail(`package ${quote(pkg.name)} bottle ${bottle.arch} empty runtime_support requires runtime_status.${runtime}`);
+ }
+ if (status === undefined) continue;
+
+ if (status.status === "supported" && !supportsRuntime) {
+ fail(`package ${quote(pkg.name)} bottle ${bottle.arch} runtime_status.${runtime}=supported requires runtime_support to include ${runtime}`);
+ }
+ if (status.status !== "supported" && supportsRuntime) {
+ fail(`package ${quote(pkg.name)} bottle ${bottle.arch} runtime_status.${runtime}=${status.status} is incompatible with runtime_support containing ${runtime}`);
+ }
+ if (status.status === "unsupported" && (!status.reason_code || !status.reason)) {
+ fail(`package ${quote(pkg.name)} bottle ${bottle.arch} runtime_status.${runtime}=unsupported requires reason_code and reason`);
+ }
+ if ((status.artifact_policy_failures?.length ?? 0) > 0) {
+ hasArtifactPolicyFailures = true;
+ }
+ }
+
+ if (hasArtifactPolicyFailures && bottle.runtime_support.length > 0) {
+ fail(`package ${quote(pkg.name)} bottle ${bottle.arch} artifact_policy_failures are incompatible with runtime_support`);
+ }
+}
+
function selectBottle(
pkg: HomebrewMetadataPackage,
bottle: HomebrewMetadataBottle,
@@ -639,6 +717,67 @@ function parseRuntime(value: unknown, label: string): HomebrewRuntime {
fail(`${label} must be node or browser`);
}
+function parseRuntimeStatusByHost(
+ value: unknown,
+ label: string,
+): Partial> | undefined {
+ if (value === undefined) return undefined;
+ const record = requireRecord(value, label);
+ const out: Partial> = {};
+ for (const [host, statusValue] of Object.entries(record)) {
+ const runtime = parseRuntime(host, `${label} host`);
+ out[runtime] = parseRuntimeStatus(statusValue, `${label}.${host}`);
+ }
+ return out;
+}
+
+function parseRuntimeStatus(value: unknown, label: string): HomebrewRuntimeStatus {
+ const record = requireRecord(value, label);
+ const status = parseRuntimeStatusKind(requiredString(record, "status", label), `${label}.status`);
+ const reasonCode = optionalString(record, "reason_code", label);
+ const reason = optionalString(record, "reason", label);
+ const artifactPolicyFailures = parseArtifactPolicyFailures(
+ record.artifact_policy_failures,
+ `${label}.artifact_policy_failures`,
+ );
+ return {
+ status,
+ ...(reasonCode === undefined ? {} : { reason_code: reasonCode }),
+ ...(reason === undefined ? {} : { reason }),
+ ...(artifactPolicyFailures === undefined ? {} : { artifact_policy_failures: artifactPolicyFailures }),
+ };
+}
+
+function parseRuntimeStatusKind(value: string, label: string): HomebrewRuntimeStatusKind {
+ if (
+ value === "supported" ||
+ value === "unsupported" ||
+ value === "failed" ||
+ value === "not-validated"
+ ) {
+ return value;
+ }
+ fail(`${label} must be supported, unsupported, failed, or not-validated`);
+}
+
+function parseArtifactPolicyFailures(
+ value: unknown,
+ label: string,
+): HomebrewRuntimeArtifactPolicyFailure[] | undefined {
+ if (value === undefined) return undefined;
+ if (!Array.isArray(value)) fail(`${label} must be an array`);
+ return value.map((entry, index) => {
+ const record = requireRecord(entry, `${label}[${index}]`);
+ const path = requiredString(record, "path", `${label}[${index}]`);
+ validateRelativePath(path, `${label}[${index}].path`);
+ const failures = requiredArray(record, "failures", `${label}[${index}]`).map((failure, failureIndex) =>
+ requireStringValue(failure, `${label}[${index}].failures[${failureIndex}]`)
+ );
+ if (failures.length === 0) fail(`${label}[${index}].failures must not be empty`);
+ return { path, failures };
+ });
+}
+
function parseStatus(value: string, label: string): HomebrewBottleStatus {
if (value === "success" || value === "failed" || value === "pending" || value === "building") {
return value;
diff --git a/packages/registry/bash/package.toml b/packages/registry/bash/package.toml
index 7fed52338..914468b3f 100644
--- a/packages/registry/bash/package.toml
+++ b/packages/registry/bash/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/bash/build-bash.sh"
[[outputs]]
name = "bash"
+fork_instrumentation = "required"
wasm = "bash.wasm"
diff --git a/packages/registry/bzip2/package.toml b/packages/registry/bzip2/package.toml
index b10127527..5b125f552 100644
--- a/packages/registry/bzip2/package.toml
+++ b/packages/registry/bzip2/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/bzip2/build-bzip2.sh"
[[outputs]]
name = "bzip2"
+fork_instrumentation = "not-required"
wasm = "bzip2.wasm"
diff --git a/packages/registry/curl/package.toml b/packages/registry/curl/package.toml
index 95d16f356..b2035fca3 100644
--- a/packages/registry/curl/package.toml
+++ b/packages/registry/curl/package.toml
@@ -29,4 +29,5 @@ script_path = "packages/registry/curl/build-curl.sh"
[[outputs]]
name = "curl"
+fork_instrumentation = "not-required"
wasm = "curl.wasm"
diff --git a/packages/registry/dash/build-dash.sh b/packages/registry/dash/build-dash.sh
index 64f11edfc..1ca660592 100755
--- a/packages/registry/dash/build-dash.sh
+++ b/packages/registry/dash/build-dash.sh
@@ -9,7 +9,9 @@ set -euo pipefail
DASH_VERSION="${DASH_VERSION:-0.5.12}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
-SRC_DIR="$SCRIPT_DIR/dash-src"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$SCRIPT_DIR}"
+SRC_DIR="$WORK_DIR/dash-src"
+BIN_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR/bin}"
SYSROOT="$REPO_ROOT/sysroot"
# --- Prerequisites ---
@@ -167,17 +169,17 @@ mv "$DASH_BIN.instr" "$DASH_BIN"
echo "==> dash built successfully!"
# Copy to bin/ with .wasm extension (consistent with coreutils/grep/sed, needed for Vite)
-mkdir -p "$SCRIPT_DIR/bin"
-cp "$DASH_BIN" "$SCRIPT_DIR/bin/dash.wasm"
+mkdir -p "$BIN_DIR"
+cp "$DASH_BIN" "$BIN_DIR/dash.wasm"
# Install into local-binaries/ so the resolver picks it up as an override.
source "$REPO_ROOT/scripts/install-local-binary.sh"
-install_local_binary dash "$SCRIPT_DIR/bin/dash.wasm"
+install_local_binary dash "$BIN_DIR/dash.wasm"
# sh ships as an alias for dash in the release; install the same bytes
# under that name so `programs/sh.wasm` also resolves locally.
-install_local_binary sh "$SCRIPT_DIR/bin/dash.wasm"
+install_local_binary sh "$BIN_DIR/dash.wasm"
-ls -lh "$SCRIPT_DIR/bin/dash.wasm"
+ls -lh "$BIN_DIR/dash.wasm"
echo ""
echo "Run with:"
echo " npx tsx packages/registry/shell/demo/serve.ts"
diff --git a/packages/registry/dash/package.toml b/packages/registry/dash/package.toml
index 0cfaccc9f..daf1c87ec 100644
--- a/packages/registry/dash/package.toml
+++ b/packages/registry/dash/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/dash/build-dash.sh"
[[outputs]]
name = "dash"
+fork_instrumentation = "required"
wasm = "dash.wasm"
diff --git a/packages/registry/fbdoom/build-fbdoom.sh b/packages/registry/fbdoom/build-fbdoom.sh
index 7186c5575..4e946601f 100755
--- a/packages/registry/fbdoom/build-fbdoom.sh
+++ b/packages/registry/fbdoom/build-fbdoom.sh
@@ -4,15 +4,19 @@
# framebuffer mmap; the canvas renderer (host/src/framebuffer/canvas-renderer.ts)
# consumes them.
#
-# Output: packages/registry/fbdoom/fbdoom.wasm
+# Output: $WASM_POSIX_DEP_OUT_DIR/fbdoom.wasm when invoked by the
+# package resolver, or packages/registry/fbdoom/fbdoom.wasm otherwise.
#
# Usage: bash packages/registry/fbdoom/build-fbdoom.sh
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$HERE/../../.." && pwd)"
-SRC="$HERE/fbdoom-src"
-CDOOM_SRC="$HERE/chocolate-doom-src"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$HERE}"
+OUT_DIR="${WASM_POSIX_DEP_OUT_DIR:-$HERE}"
+SRC="$WORK_DIR/fbdoom-src"
+CDOOM_SRC="$WORK_DIR/chocolate-doom-src"
+OUT="$OUT_DIR/fbdoom.wasm"
# Pin to chocolate-doom 3.1.0. fbDOOM stripped its OPL/MIDI/MUS sources
# when removing SDL; we vendor them back so the music path compiles.
@@ -23,6 +27,8 @@ CDOOM_COMMIT="35fb1372d10756ca27eca05665bd8a7cebc71c05" # chocolate-doom-3.1.0
source "$REPO_ROOT/sdk/activate.sh"
export WASM_POSIX_SYSROOT="$REPO_ROOT/sysroot"
+mkdir -p "$WORK_DIR" "$OUT_DIR"
+
if [ ! -d "$SRC" ]; then
echo "==> Cloning maximevince/fbDOOM..."
git clone --depth 1 https://github.com/maximevince/fbDOOM "$SRC"
@@ -101,13 +107,13 @@ make CC=wasm32posix-cc \
LIBS="-lm" \
NOSDL=1
-cp fbdoom "$HERE/fbdoom.wasm"
+cp fbdoom "$OUT"
# fbDOOM doesn't fork — no wasm-fork-instrument step needed.
# (vs other ports here: dash forks via popen/system, so its build-dash.sh
# runs `wasm-fork-instrument` for the fork path.)
-ls -la "$HERE/fbdoom.wasm"
+ls -la "$OUT"
echo "==> fbdoom.wasm built."
# Install into local-binaries/ (resolver priority 1) and the resolver
@@ -124,4 +130,4 @@ echo "==> fbdoom.wasm built."
# caches it via the Cache API — see apps/browser-demos/pages/doom/main.ts.
cd "$REPO_ROOT"
source "$REPO_ROOT/scripts/install-local-binary.sh"
-install_local_binary fbdoom "$HERE/fbdoom.wasm" fbdoom.wasm
+install_local_binary fbdoom "$OUT" fbdoom.wasm
diff --git a/packages/registry/fbdoom/package.toml b/packages/registry/fbdoom/package.toml
index 0bef67b92..fa5eb8f46 100644
--- a/packages/registry/fbdoom/package.toml
+++ b/packages/registry/fbdoom/package.toml
@@ -26,4 +26,5 @@ script_path = "packages/registry/fbdoom/build-fbdoom.sh"
[[outputs]]
name = "fbdoom"
+fork_instrumentation = "not-required"
wasm = "fbdoom.wasm"
diff --git a/packages/registry/git/build-git.sh b/packages/registry/git/build-git.sh
index ee68889a6..338973b4a 100755
--- a/packages/registry/git/build-git.sh
+++ b/packages/registry/git/build-git.sh
@@ -25,8 +25,9 @@ set -euo pipefail
GIT_VERSION="${GIT_VERSION:-2.47.1}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
-SRC_DIR="$SCRIPT_DIR/git-src"
-BIN_DIR="$SCRIPT_DIR/bin"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$SCRIPT_DIR}"
+SRC_DIR="$WORK_DIR/git-src"
+BIN_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR/bin}"
# Explicit env wins; else the in-tree sysroot. Matches build-libcurl.sh:49.
SYSROOT="${WASM_POSIX_SYSROOT:-$REPO_ROOT/sysroot}"
diff --git a/packages/registry/git/package.toml b/packages/registry/git/package.toml
index ea9c7441f..cf29929e9 100644
--- a/packages/registry/git/package.toml
+++ b/packages/registry/git/package.toml
@@ -17,8 +17,10 @@ script_path = "packages/registry/git/build-git.sh"
[[outputs]]
name = "git"
+fork_instrumentation = "required"
wasm = "git.wasm"
[[outputs]]
name = "git-remote-http"
+fork_instrumentation = "not-required"
wasm = "git-remote-http.wasm"
diff --git a/packages/registry/less/build-less.sh b/packages/registry/less/build-less.sh
index 8a54a9bea..9e1c25ffe 100755
--- a/packages/registry/less/build-less.sh
+++ b/packages/registry/less/build-less.sh
@@ -14,8 +14,9 @@ set -euo pipefail
LESS_VERSION="${LESS_VERSION:-661}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
-SRC_DIR="$SCRIPT_DIR/less-src"
-BIN_DIR="$SCRIPT_DIR/bin"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$SCRIPT_DIR}"
+SRC_DIR="$WORK_DIR/less-src"
+BIN_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR/bin}"
SYSROOT="$REPO_ROOT/sysroot"
# --- Prerequisites ---
@@ -32,7 +33,7 @@ fi
export WASM_POSIX_SYSROOT="$SYSROOT"
# --- Build termcap stub library ---
-TERMCAP_DIR="$SCRIPT_DIR/libtermcap"
+TERMCAP_DIR="$WORK_DIR/libtermcap"
if [ ! -f "$TERMCAP_DIR/libtermcap.a" ]; then
echo "==> Building termcap stub library..."
mkdir -p "$TERMCAP_DIR/include"
@@ -124,4 +125,4 @@ echo "Binary: $BIN_DIR/less.wasm"
# Install into local-binaries/ so the resolver picks the freshly-built
# binary over the fetched release.
source "$REPO_ROOT/scripts/install-local-binary.sh"
-[ -f "$SCRIPT_DIR/bin/less.wasm" ] && install_local_binary less "$SCRIPT_DIR/bin/less.wasm" || true
+[ -f "$BIN_DIR/less.wasm" ] && install_local_binary less "$BIN_DIR/less.wasm" || true
diff --git a/packages/registry/less/package.toml b/packages/registry/less/package.toml
index 518ac5335..a571f2d66 100644
--- a/packages/registry/less/package.toml
+++ b/packages/registry/less/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/less/build-less.sh"
[[outputs]]
name = "less"
+fork_instrumentation = "not-required"
wasm = "less.wasm"
diff --git a/packages/registry/lsof/build-lsof.sh b/packages/registry/lsof/build-lsof.sh
index 24c01e773..4037b1c7c 100755
--- a/packages/registry/lsof/build-lsof.sh
+++ b/packages/registry/lsof/build-lsof.sh
@@ -8,7 +8,8 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
SRC="$REPO_ROOT/examples/lsof.c"
-OUT_BIN="$SCRIPT_DIR/lsof.wasm"
+OUT_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR}"
+OUT_BIN="$OUT_DIR/lsof.wasm"
if [ ! -f "$SRC" ]; then
echo "ERROR: source not found at $SRC" >&2
@@ -82,6 +83,7 @@ LINK_FLAGS=(
)
echo "==> Building lsof.wasm from $SRC"
+mkdir -p "$OUT_DIR"
"$CC" "${CFLAGS[@]}" "$SRC" "${LINK_FLAGS[@]}" -o "$OUT_BIN"
if [ -n "$WASM_OPT" ]; then
diff --git a/packages/registry/lsof/package.toml b/packages/registry/lsof/package.toml
index 5f340acf3..9110678d3 100644
--- a/packages/registry/lsof/package.toml
+++ b/packages/registry/lsof/package.toml
@@ -22,4 +22,5 @@ script_path = "packages/registry/lsof/build-lsof.sh"
[[outputs]]
name = "lsof"
+fork_instrumentation = "not-required"
wasm = "lsof.wasm"
diff --git a/packages/registry/modeset/build-modeset.sh b/packages/registry/modeset/build-modeset.sh
index 83146d114..1dafa1477 100755
--- a/packages/registry/modeset/build-modeset.sh
+++ b/packages/registry/modeset/build-modeset.sh
@@ -3,6 +3,8 @@ set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$HERE/../../.." && pwd)"
+OUT_DIR="${WASM_POSIX_DEP_OUT_DIR:-$HERE}"
+OUT="$OUT_DIR/modeset.wasm"
source "$REPO_ROOT/sdk/activate.sh"
export WASM_POSIX_SYSROOT="$REPO_ROOT/sysroot"
@@ -20,6 +22,7 @@ PKG_CFLAGS="$(wasm32posix-pkg-config --cflags libdrm gbm egl glesv2)"
PKG_LIBS="$(wasm32posix-pkg-config --libs gbm libdrm egl glesv2)"
echo "==> Building modeset fluid simulation..."
+mkdir -p "$OUT_DIR"
wasm32posix-cc \
-std=c11 \
-O2 \
@@ -31,13 +34,13 @@ wasm32posix-cc \
"$REPO_ROOT/programs/modeset.c" \
$PKG_LIBS \
-lm \
- -o "$HERE/modeset.wasm"
+ -o "$OUT"
"$REPO_ROOT/scripts/run-wasm-fork-instrument.sh" \
- "$HERE/modeset.wasm" \
- -o "$HERE/modeset.wasm.instr"
-mv "$HERE/modeset.wasm.instr" "$HERE/modeset.wasm"
+ "$OUT" \
+ -o "$OUT.instr"
+mv "$OUT.instr" "$OUT"
cd "$REPO_ROOT"
source "$REPO_ROOT/scripts/install-local-binary.sh"
-install_local_binary modeset "$HERE/modeset.wasm" modeset.wasm
+install_local_binary modeset "$OUT" modeset.wasm
diff --git a/packages/registry/modeset/package.toml b/packages/registry/modeset/package.toml
index 74179ec48..f8ccd5ba1 100644
--- a/packages/registry/modeset/package.toml
+++ b/packages/registry/modeset/package.toml
@@ -18,4 +18,5 @@ script_path = "packages/registry/modeset/build-modeset.sh"
[[outputs]]
name = "modeset"
+fork_instrumentation = "not-required"
wasm = "modeset.wasm"
diff --git a/packages/registry/msmtpd/build-msmtpd.sh b/packages/registry/msmtpd/build-msmtpd.sh
index ac6a47308..93cf90cd3 100755
--- a/packages/registry/msmtpd/build-msmtpd.sh
+++ b/packages/registry/msmtpd/build-msmtpd.sh
@@ -11,9 +11,11 @@ SHA256="20cd58b58dd007acf7b937fa1a1e21f3afb3e9ef5bbcfb8b4f5650deadc64db4"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
-SRC_DIR="$SCRIPT_DIR/msmtp-src"
-BIN_DIR="$SCRIPT_DIR/bin"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$SCRIPT_DIR}"
+SRC_DIR="$WORK_DIR/msmtp-src"
+BIN_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR/bin}"
OUT="$BIN_DIR/msmtpd.wasm"
+TARBALL_PATH="$WORK_DIR/$TARBALL"
if [ -f "$OUT" ]; then
echo "==> Reusing existing msmtpd artifact in $BIN_DIR (skip rebuild)."
@@ -27,14 +29,15 @@ if ! command -v wasm32posix-cc >/dev/null 2>&1; then
exit 1
fi
-if [ ! -f "$SCRIPT_DIR/$TARBALL" ]; then
+mkdir -p "$WORK_DIR"
+if [ ! -f "$TARBALL_PATH" ]; then
echo "==> Downloading msmtp $VERSION..."
curl --retry 10 --retry-delay 5 --retry-max-time 300 --retry-all-errors -fsSL \
- -o "$SCRIPT_DIR/$TARBALL" \
+ -o "$TARBALL_PATH" \
"$URL"
fi
-actual_sha="$(shasum -a 256 "$SCRIPT_DIR/$TARBALL" | awk '{print $1}')"
+actual_sha="$(shasum -a 256 "$TARBALL_PATH" | awk '{print $1}')"
if [ "$actual_sha" != "$SHA256" ]; then
echo "ERROR: checksum mismatch for $TARBALL" >&2
echo " expected: $SHA256" >&2
@@ -45,8 +48,8 @@ fi
if [ ! -d "$SRC_DIR/src" ]; then
echo "==> Extracting msmtp $VERSION..."
rm -rf "$SRC_DIR"
- tar xf "$SCRIPT_DIR/$TARBALL" -C "$SCRIPT_DIR"
- mv "$SCRIPT_DIR/msmtp-$VERSION" "$SRC_DIR"
+ tar xf "$TARBALL_PATH" -C "$WORK_DIR"
+ mv "$WORK_DIR/msmtp-$VERSION" "$SRC_DIR"
fi
cd "$SRC_DIR/src"
@@ -86,14 +89,8 @@ wasm32posix-cc \
netrc.c \
-o "$OUT"
-FORK_INSTRUMENT="$REPO_ROOT/tools/bin/wasm-fork-instrument"
-if [ ! -x "$FORK_INSTRUMENT" ]; then
- echo "ERROR: wasm-fork-instrument not found at $FORK_INSTRUMENT." >&2
- exit 1
-fi
-
echo "==> Applying wasm-fork-instrument to msmtpd.wasm..."
-"$FORK_INSTRUMENT" "$OUT" -o "$OUT.instr"
+"$REPO_ROOT/scripts/run-wasm-fork-instrument.sh" "$OUT" -o "$OUT.instr"
mv "$OUT.instr" "$OUT"
ls -lh "$OUT"
diff --git a/packages/registry/nano/build-nano.sh b/packages/registry/nano/build-nano.sh
index c97a201bc..ea3658129 100755
--- a/packages/registry/nano/build-nano.sh
+++ b/packages/registry/nano/build-nano.sh
@@ -13,8 +13,9 @@ set -euo pipefail
NANO_VERSION="${NANO_VERSION:-8.3}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
-SRC_DIR="$SCRIPT_DIR/nano-src"
-BIN_DIR="$SCRIPT_DIR/bin"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$SCRIPT_DIR}"
+SRC_DIR="$WORK_DIR/nano-src"
+BIN_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR/bin}"
# Explicit env wins; else the in-tree sysroot. Matches build-curl.sh:49.
SYSROOT="${WASM_POSIX_SYSROOT:-$REPO_ROOT/sysroot}"
@@ -222,4 +223,4 @@ echo "Binary: $BIN_DIR/nano.wasm"
# Install into local-binaries/ so the resolver picks the freshly-built
# binary over the fetched release.
source "$REPO_ROOT/scripts/install-local-binary.sh"
-install_local_binary nano "$SCRIPT_DIR/bin/nano.wasm"
+install_local_binary nano "$BIN_DIR/nano.wasm"
diff --git a/packages/registry/nano/package.toml b/packages/registry/nano/package.toml
index 76817f71e..87a0b0f9e 100644
--- a/packages/registry/nano/package.toml
+++ b/packages/registry/nano/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/nano/build-nano.sh"
[[outputs]]
name = "nano"
+fork_instrumentation = "not-required"
wasm = "nano.wasm"
diff --git a/packages/registry/ncurses/package.toml b/packages/registry/ncurses/package.toml
index c61d091dd..2c9b8716f 100644
--- a/packages/registry/ncurses/package.toml
+++ b/packages/registry/ncurses/package.toml
@@ -31,40 +31,50 @@ script_path = "packages/registry/ncurses/build-ncurses.sh"
[[outputs]]
name = "clear"
+fork_instrumentation = "not-required"
wasm = "clear.wasm"
[[outputs]]
name = "reset"
+fork_instrumentation = "not-required"
wasm = "reset.wasm"
[[outputs]]
name = "tset"
+fork_instrumentation = "not-required"
wasm = "tset.wasm"
[[outputs]]
name = "tput"
+fork_instrumentation = "not-required"
wasm = "tput.wasm"
[[outputs]]
name = "tabs"
+fork_instrumentation = "not-required"
wasm = "tabs.wasm"
[[outputs]]
name = "tic"
+fork_instrumentation = "not-required"
wasm = "tic.wasm"
[[outputs]]
name = "infocmp"
+fork_instrumentation = "not-required"
wasm = "infocmp.wasm"
[[outputs]]
name = "toe"
+fork_instrumentation = "not-required"
wasm = "toe.wasm"
[[outputs]]
name = "captoinfo"
+fork_instrumentation = "not-required"
wasm = "captoinfo.wasm"
[[outputs]]
name = "infotocap"
+fork_instrumentation = "not-required"
wasm = "infotocap.wasm"
diff --git a/packages/registry/netcat/build-netcat.sh b/packages/registry/netcat/build-netcat.sh
index 1ae238268..e340e429a 100755
--- a/packages/registry/netcat/build-netcat.sh
+++ b/packages/registry/netcat/build-netcat.sh
@@ -6,8 +6,9 @@ set -euo pipefail
NETCAT_VERSION="${NETCAT_VERSION:-0.7.1}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
-SRC_DIR="$SCRIPT_DIR/netcat-src"
-BIN_DIR="$SCRIPT_DIR/bin"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$SCRIPT_DIR}"
+SRC_DIR="$WORK_DIR/netcat-src"
+BIN_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR/bin}"
SYSROOT="${WASM_POSIX_SYSROOT:-$REPO_ROOT/sysroot}"
if ! command -v wasm32posix-cc &>/dev/null; then
@@ -42,17 +43,31 @@ PATCH_SET=(
"disable-pktinfo.patch"
)
echo "==> Verifying Kandelo netcat portability patches..."
-for patch_name in "${PATCH_SET[@]}"; do
- patch_file="$SCRIPT_DIR/patches/$patch_name"
- if patch --reverse --dry-run -p1 < "$patch_file" >/dev/null 2>&1; then
- echo " $patch_name already applied"
- elif patch --forward --dry-run -p1 < "$patch_file" >/dev/null 2>&1; then
- patch -p1 < "$patch_file"
- else
- echo "ERROR: $patch_name does not apply and is not already present" >&2
- exit 1
- fi
-done
+
+if awk '
+ /if \(netcat_mode == NETCAT_LISTEN\)/ { in_listen = 1; next }
+ in_listen && /glob_ret = EXIT_SUCCESS;/ { ok = 1; exit }
+ in_listen && /if \(opt_exec\)/ { exit }
+ END { exit ok ? 0 : 1 }
+' src/netcat.c; then
+ echo " listen-success-exit.patch already applied"
+else
+ patch --batch -p1 < "$SCRIPT_DIR/patches/listen-success-exit.patch"
+fi
+
+udp_marker_count=$(grep -c "Kandelo exposes normal POSIX UDP sockets" src/core.c || true)
+case "$udp_marker_count" in
+ 0) patch --batch -p1 < "$SCRIPT_DIR/patches/udp-listen-single-socket.patch" ;;
+ 1) echo " udp-listen-single-socket.patch already applied" ;;
+ *) echo "ERROR: udp-listen-single-socket.patch marker count is $udp_marker_count, expected 0 or 1" >&2; exit 1 ;;
+esac
+
+if grep -q "/\\* # define USE_PKTINFO \\*/" src/netcat.h; then
+ echo " disable-pktinfo.patch already applied"
+else
+ patch --batch -p1 < "$SCRIPT_DIR/patches/disable-pktinfo.patch"
+fi
+
printf '%s\n' "${PATCH_SET[*]}" > "$PATCH_MARKER"
if ! awk '
diff --git a/packages/registry/netcat/package.toml b/packages/registry/netcat/package.toml
index 14e28a33b..ec8694bf7 100644
--- a/packages/registry/netcat/package.toml
+++ b/packages/registry/netcat/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/netcat/build-netcat.sh"
[[outputs]]
name = "nc"
+fork_instrumentation = "not-required"
wasm = "nc.wasm"
diff --git a/packages/registry/netcat/patches/udp-listen-single-socket.patch b/packages/registry/netcat/patches/udp-listen-single-socket.patch
index 6a3a0999e..e5cd4e25d 100644
--- a/packages/registry/netcat/patches/udp-listen-single-socket.patch
+++ b/packages/registry/netcat/patches/udp-listen-single-socket.patch
@@ -2,11 +2,18 @@ diff --git a/src/core.c b/src/core.c
index 7e6f3dd..d8d17c1 100644
--- a/src/core.c
+++ b/src/core.c
-@@ -98,2 +98,6 @@ static int core_udp_listen(nc_sock_t *ncsock)
+@@ -94,7 +94,13 @@ static int core_udp_listen(nc_sock_t *ncsock)
+ if (ncsock->local_host.iaddrs[0].s_addr)
+ need_udphelper = FALSE;
#endif
-
++
+#if 1
+ /* Kandelo exposes normal POSIX UDP sockets, but not GNU netcat's legacy
+ helper protocol. Use one bound datagram socket for UDP listen mode. */
+ need_udphelper = FALSE;
+#endif
++
+ if (!need_udphelper) {
+ /* simulates a udphelper_sockets_open() call */
+ sockbuf = calloc(2, sizeof(int));
diff --git a/packages/registry/nethack/package.toml b/packages/registry/nethack/package.toml
index c96607af3..c53cb64ff 100644
--- a/packages/registry/nethack/package.toml
+++ b/packages/registry/nethack/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/nethack/build-nethack.sh"
[[outputs]]
name = "nethack"
+fork_instrumentation = "not-required"
wasm = "nethack.wasm"
diff --git a/packages/registry/vim/build-vim.sh b/packages/registry/vim/build-vim.sh
index ffb30d52d..5e6fa347f 100755
--- a/packages/registry/vim/build-vim.sh
+++ b/packages/registry/vim/build-vim.sh
@@ -16,8 +16,10 @@ set -euo pipefail
VIM_VERSION="${VIM_VERSION:-9.1.0900}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
-SRC_DIR="$SCRIPT_DIR/vim-src"
-BIN_DIR="$SCRIPT_DIR/bin"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$SCRIPT_DIR}"
+SRC_DIR="$WORK_DIR/vim-src"
+BIN_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR/bin}"
+RUNTIME_DIR="$WORK_DIR/runtime"
# Explicit env wins; else the in-tree sysroot. Keeps neighbour-worktree
# invocations viable (WASM_POSIX_SYSROOT=/sysroot). Same shape as
# build-curl.sh:49.
@@ -250,7 +252,7 @@ echo "Binary: $BIN_DIR/vim.wasm"
# vim.wasm + runtime/* and is self-sufficient (consumers don't need
# to re-fetch upstream source to assemble vim.zip).
echo "==> Bundling Vim runtime (for archive)..."
-bash "$SCRIPT_DIR/bundle-runtime.sh"
+VIM_SRC_DIR="$SRC_DIR" VIM_RUNTIME_OUT="$RUNTIME_DIR" bash "$SCRIPT_DIR/bundle-runtime.sh"
source "$REPO_ROOT/scripts/install-local-binary.sh"
install_local_binary vim "$BIN_DIR/vim.wasm"
@@ -260,8 +262,8 @@ install_local_binary vim "$BIN_DIR/vim.wasm"
# the resolver, $WASM_POSIX_DEP_OUT_DIR is unset and this is a
# no-op — direct invocations of build-vim.sh just leave runtime/
# at its source-tree location.
-if [ -n "${WASM_POSIX_DEP_OUT_DIR:-}" ] && [ -d "$SCRIPT_DIR/runtime" ]; then
+if [ -n "${WASM_POSIX_DEP_OUT_DIR:-}" ] && [ -d "$RUNTIME_DIR" ]; then
rm -rf "$WASM_POSIX_DEP_OUT_DIR/runtime"
- cp -R "$SCRIPT_DIR/runtime" "$WASM_POSIX_DEP_OUT_DIR/runtime"
+ cp -R "$RUNTIME_DIR" "$WASM_POSIX_DEP_OUT_DIR/runtime"
echo " staged runtime tree into resolver scratch"
fi
diff --git a/packages/registry/vim/bundle-runtime.sh b/packages/registry/vim/bundle-runtime.sh
index 7bd510aa2..3db4961c8 100755
--- a/packages/registry/vim/bundle-runtime.sh
+++ b/packages/registry/vim/bundle-runtime.sh
@@ -28,9 +28,9 @@ set -euo pipefail
# Output: packages/registry/vim/runtime/ (directory tree)
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
-SRC_DIR="$SCRIPT_DIR/vim-src"
+SRC_DIR="${VIM_SRC_DIR:-$SCRIPT_DIR/vim-src}"
RUNTIME_SRC="$SRC_DIR/runtime"
-RUNTIME_OUT="$SCRIPT_DIR/runtime"
+RUNTIME_OUT="${VIM_RUNTIME_OUT:-$SCRIPT_DIR/runtime}"
if [ ! -d "$RUNTIME_SRC" ]; then
echo "ERROR: Vim source not found. Run build-vim.sh first." >&2
diff --git a/packages/registry/vim/package.toml b/packages/registry/vim/package.toml
index 19e3f4d60..f723ee709 100644
--- a/packages/registry/vim/package.toml
+++ b/packages/registry/vim/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/vim/build-vim.sh"
[[outputs]]
name = "vim"
+fork_instrumentation = "required"
wasm = "vim.wasm"
diff --git a/packages/registry/wget/build-wget.sh b/packages/registry/wget/build-wget.sh
index 9de5ee73c..9bb8f796e 100755
--- a/packages/registry/wget/build-wget.sh
+++ b/packages/registry/wget/build-wget.sh
@@ -13,8 +13,9 @@ set -euo pipefail
WGET_VERSION="${WGET_VERSION:-1.24.5}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
-SRC_DIR="$SCRIPT_DIR/wget-src"
-BIN_DIR="$SCRIPT_DIR/bin"
+WORK_DIR="${WASM_POSIX_DEP_WORK_DIR:-$SCRIPT_DIR}"
+SRC_DIR="$WORK_DIR/wget-src"
+BIN_DIR="${WASM_POSIX_DEP_OUT_DIR:-$SCRIPT_DIR/bin}"
# Explicit env wins; else the in-tree sysroot. Matches build-curl.sh:49.
SYSROOT="${WASM_POSIX_SYSROOT:-$REPO_ROOT/sysroot}"
@@ -258,4 +259,4 @@ echo "Binary: $BIN_DIR/wget.wasm"
# Install into local-binaries/ so the resolver picks the freshly-built
# binary over the fetched release.
source "$REPO_ROOT/scripts/install-local-binary.sh"
-[ -f "$SCRIPT_DIR/bin/wget.wasm" ] && install_local_binary wget "$SCRIPT_DIR/bin/wget.wasm" || true
+[ -f "$BIN_DIR/wget.wasm" ] && install_local_binary wget "$BIN_DIR/wget.wasm" || true
diff --git a/packages/registry/wget/package.toml b/packages/registry/wget/package.toml
index 66daab920..aba46868d 100644
--- a/packages/registry/wget/package.toml
+++ b/packages/registry/wget/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/wget/build-wget.sh"
[[outputs]]
name = "wget"
+fork_instrumentation = "not-required"
wasm = "wget.wasm"
diff --git a/packages/registry/xz/package.toml b/packages/registry/xz/package.toml
index 21e4e652b..6a30aac88 100644
--- a/packages/registry/xz/package.toml
+++ b/packages/registry/xz/package.toml
@@ -17,4 +17,5 @@ script_path = "packages/registry/xz/build-xz.sh"
[[outputs]]
name = "xz"
+fork_instrumentation = "not-required"
wasm = "xz.wasm"
diff --git a/scripts/homebrew-bottle-build.sh b/scripts/homebrew-bottle-build.sh
index c418f9c82..4072b13f0 100755
--- a/scripts/homebrew-bottle-build.sh
+++ b/scripts/homebrew-bottle-build.sh
@@ -66,6 +66,7 @@ esac
TAP_ROOT="$(cd "$TAP_ROOT" && pwd)"
mkdir -p "$OUT_DIR"
OUT_DIR="$(cd "$OUT_DIR" && pwd)"
+mkdir -p "$OUT_DIR/homebrew-temp"
FORMULA_PATH="$TAP_ROOT/Formula/$FORMULA.rb"
if [ ! -f "$FORMULA_PATH" ]; then
@@ -88,6 +89,7 @@ mkdir -p "$OUT_DIR/bottles"
WORK_DIR="$(mktemp -d)"
BREW_REPO=""
BREW_OVERLAY=""
+TAP_SOURCE="$TAP_ROOT"
cleanup() {
if [ -n "$BREW_REPO" ] && [ -n "$BREW_OVERLAY" ] && [ -d "$BREW_OVERLAY" ]; then
@@ -113,14 +115,37 @@ export HOMEBREW_NO_AUTO_UPDATE="${HOMEBREW_NO_AUTO_UPDATE:-1}"
export HOMEBREW_NO_INSTALL_CLEANUP="${HOMEBREW_NO_INSTALL_CLEANUP:-1}"
export HOMEBREW_NO_ANALYTICS="${HOMEBREW_NO_ANALYTICS:-1}"
export HOMEBREW_DEVELOPER="${HOMEBREW_DEVELOPER:-1}"
+export HOMEBREW_NO_REQUIRE_TAP_TRUST="${HOMEBREW_NO_REQUIRE_TAP_TRUST:-1}"
+export HOMEBREW_AVOID_NESTED_SANDBOXING="${HOMEBREW_AVOID_NESTED_SANDBOXING:-1}"
+export HOMEBREW_TEMP="${HOMEBREW_TEMP:-$OUT_DIR/homebrew-temp}"
export KANDELO_HOMEBREW_ARCH="$ARCH"
export KANDELO_HOMEBREW_KANDELO_ROOT="$KANDELO_ROOT"
export HOMEBREW_KANDELO_ARCH="$ARCH"
export HOMEBREW_KANDELO_ROOT="$KANDELO_ROOT"
export HOMEBREW_KANDELO_NODE="$(command -v node)"
export HOMEBREW_KANDELO_LLVM_BIN="${LLVM_BIN:-${WASM_POSIX_LLVM_DIR:-}}"
+if command -v cargo >/dev/null 2>&1; then
+ export HOMEBREW_KANDELO_RUST_BIN="$(dirname "$(command -v cargo)")"
+fi
+if command -v wasm-opt >/dev/null 2>&1; then
+ export HOMEBREW_KANDELO_BINARYEN_BIN="$(dirname "$(command -v wasm-opt)")"
+fi
+if command -v pkg-config >/dev/null 2>&1; then
+ export HOMEBREW_KANDELO_PKG_CONFIG="$(command -v pkg-config)"
+fi
+
+if [ ! -d "$TAP_SOURCE/.git" ]; then
+ TAP_SOURCE="$WORK_DIR/tap-source"
+ mkdir -p "$TAP_SOURCE"
+ rsync -a --exclude .git "$TAP_ROOT/" "$TAP_SOURCE/"
+ git -C "$TAP_SOURCE" init -q
+ git -C "$TAP_SOURCE" config user.name "kandelo-homebrew-local"
+ git -C "$TAP_SOURCE" config user.email "kandelo-homebrew-local@example.invalid"
+ git -C "$TAP_SOURCE" add .
+ git -C "$TAP_SOURCE" commit -q -m "stage Kandelo Homebrew tap"
+fi
-"$BREW_BIN" tap "$TAP_NAME" "$TAP_ROOT"
+"$BREW_BIN" tap "$TAP_NAME" "$TAP_SOURCE"
FORMULA_REF="$TAP_NAME/$FORMULA"
TAPPED_TAP_ROOT="$("$BREW_BIN" --repository "$TAP_NAME")"
TAPPED_FORMULA_PATH="$TAPPED_TAP_ROOT/Formula/$FORMULA.rb"
diff --git a/scripts/homebrew-composite-status.ts b/scripts/homebrew-composite-status.ts
new file mode 100644
index 000000000..faf2f589f
--- /dev/null
+++ b/scripts/homebrew-composite-status.ts
@@ -0,0 +1,461 @@
+/**
+ * Classify Homebrew-backed composite VFS packages from generated sidecars.
+ *
+ * This does not build images. It records whether each composite package has
+ * enough successful, runtime-supported Homebrew bottle metadata to proceed to
+ * image or bundle materialization, and emits durable outcome lists for the
+ * blockers that remain.
+ */
+import {
+ mkdirSync,
+ readFileSync,
+ writeFileSync,
+} from "node:fs";
+import { join, resolve } from "node:path";
+
+type Runtime = "node" | "browser";
+type Status = "pass" | "fail" | "skip";
+
+interface CliOptions {
+ metadataPaths: string[];
+ resultDir: string;
+ arch: "wasm32" | "wasm64";
+ runtimes: Runtime[];
+ beadId: string;
+}
+
+interface CompositeSpec {
+ name: string;
+ artifactKind: "vfs_image" | "lazy_archive";
+ packages: string[];
+ composites?: string[];
+}
+
+interface BottleMetadata {
+ arch?: string;
+ status?: string;
+ url?: string;
+ sha256?: string;
+ bytes?: number;
+ cache_key_sha?: string;
+ link_manifest?: string;
+ runtime_support?: string[];
+ runtime_status?: Record;
+ }>;
+ browser_compatible?: boolean;
+ fork_instrumentation?: string;
+}
+
+interface PackageDependency {
+ name?: string;
+}
+
+interface PackageMetadata {
+ name?: string;
+ version?: string;
+ dependencies?: PackageDependency[];
+ bottles?: BottleMetadata[];
+}
+
+interface MetadataFile {
+ packages?: PackageMetadata[];
+}
+
+interface Outcome {
+ name: string;
+ composite: string;
+ runtime: Runtime;
+ direct_packages: string[];
+ closure_packages: string[];
+ status: Status;
+ details: string;
+ blockers: string[];
+}
+
+const SPECS: CompositeSpec[] = [
+ {
+ name: "rootfs",
+ artifactKind: "vfs_image",
+ packages: [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite",
+ ],
+ },
+ {
+ name: "shell",
+ artifactKind: "vfs_image",
+ composites: ["rootfs"],
+ packages: [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset",
+ ],
+ },
+ {
+ name: "python-vfs",
+ artifactKind: "vfs_image",
+ packages: ["cpython"],
+ },
+ {
+ name: "perl-vfs",
+ artifactKind: "vfs_image",
+ packages: ["perl"],
+ },
+ {
+ name: "erlang-vfs",
+ artifactKind: "vfs_image",
+ packages: ["erlang"],
+ },
+ {
+ name: "vim-browser-bundle",
+ artifactKind: "lazy_archive",
+ packages: ["vim"],
+ },
+ {
+ name: "nethack-browser-bundle",
+ artifactKind: "lazy_archive",
+ packages: ["nethack"],
+ },
+ {
+ name: "node-vfs",
+ artifactKind: "vfs_image",
+ composites: ["shell"],
+ packages: ["node"],
+ },
+];
+const HTTPS_URL_RE = /^https:\/\/\S+$/;
+const SHA256_RE = /^[0-9a-f]{64}$/;
+const FORK_INSTRUMENTATION = new Set(["not-required", "required", "disabled", "unknown"]);
+
+async function main(): Promise {
+ const options = parseArgs(process.argv.slice(2));
+ mkdirSync(options.resultDir, { recursive: true });
+ mkdirSync(join(options.resultDir, "outcome-lists"), { recursive: true });
+
+ const packageIndex = readPackageIndex(options.metadataPaths);
+ const outcomes: Outcome[] = [];
+ const byCompositeRuntime = new Map();
+
+ for (const runtime of options.runtimes) {
+ for (const spec of SPECS) {
+ const blockers: string[] = [];
+ for (const composite of spec.composites ?? []) {
+ const dependency = byCompositeRuntime.get(`${composite}:${runtime}`);
+ if (!dependency || dependency.status !== "pass") {
+ blockers.push(
+ `composite ${composite} is not ready for ${runtime}: ${dependency?.details ?? "not evaluated"}`,
+ );
+ }
+ }
+ const closurePackages = collectPackageClosure(packageIndex, spec.packages);
+ for (const pkg of closurePackages) {
+ const blocker = packageBlocker(packageIndex.get(pkg), pkg, runtime, options.arch);
+ if (blocker) blockers.push(blocker);
+ }
+
+ const outcome: Outcome = {
+ name: `${spec.name}_${runtime}_${spec.artifactKind}`,
+ composite: spec.name,
+ runtime,
+ direct_packages: spec.packages,
+ closure_packages: closurePackages,
+ status: blockers.length === 0 ? "pass" : "skip",
+ details: blockers.length === 0
+ ? `${spec.name} ${spec.artifactKind} has ${closurePackages.length} Homebrew package inputs ready for ${runtime}/${options.arch}`
+ : blockers.join("; "),
+ blockers,
+ };
+ outcomes.push(outcome);
+ byCompositeRuntime.set(`${spec.name}:${runtime}`, outcome);
+ }
+ }
+
+ writeSummary(options, outcomes, packageIndex);
+ writeOutcomeLists(options.resultDir, outcomes);
+ const failed = outcomes.filter((outcome) => outcome.status === "fail");
+ process.exit(failed.length === 0 ? 0 : 1);
+}
+
+function collectPackageClosure(
+ packageIndex: Map,
+ requested: string[],
+): string[] {
+ const seen = new Set();
+ const ordered: string[] = [];
+ const visit = (name: string): void => {
+ if (seen.has(name)) return;
+ seen.add(name);
+ ordered.push(name);
+ const pkg = packageIndex.get(name);
+ if (!pkg) return;
+ for (const dep of pkg.dependencies ?? []) {
+ if (dep.name) visit(dep.name);
+ }
+ };
+
+ for (const name of requested) visit(name);
+ return ordered;
+}
+
+function packageBlocker(
+ pkg: PackageMetadata | undefined,
+ name: string,
+ runtime: Runtime,
+ arch: string,
+): string | null {
+ if (!pkg) return `${name}: no generated Homebrew sidecar metadata found`;
+ const bottle = (pkg.bottles ?? []).find((candidate) => candidate.arch === arch);
+ if (!bottle) return `${name}: no ${arch} bottle metadata found`;
+ if (bottle.status !== "success") return `${name}: ${arch} bottle status is ${bottle.status ?? "missing"}`;
+ const bottleBlocker = bottleMetadataBlocker(name, bottle, arch);
+ if (bottleBlocker) return bottleBlocker;
+ const support = bottle.runtime_support ?? [];
+ if (!support.includes(runtime)) {
+ const runtimeStatus = bottle.runtime_status?.[runtime];
+ const reason = runtimeStatus
+ ? formatRuntimeStatus(runtimeStatus)
+ : `runtime_support does not include ${runtime}`;
+ return `${name}: ${runtime} unsupported (${reason})`;
+ }
+ if (runtime === "browser" && bottle.browser_compatible !== true) {
+ return `${name}: browser runtime is not marked browser_compatible`;
+ }
+ return null;
+}
+
+function bottleMetadataBlocker(name: string, bottle: BottleMetadata, arch: string): string | null {
+ const blockers: string[] = [];
+ if (!bottle.url || !HTTPS_URL_RE.test(bottle.url)) {
+ blockers.push(`url ${bottle.url ?? ""} is not an https URL`);
+ }
+ if (!bottle.sha256 || !SHA256_RE.test(bottle.sha256)) {
+ blockers.push("sha256 is missing or invalid");
+ }
+ if (!Number.isInteger(bottle.bytes) || (bottle.bytes ?? 0) <= 0) {
+ blockers.push("bytes is missing or invalid");
+ }
+ if (!bottle.cache_key_sha || !SHA256_RE.test(bottle.cache_key_sha)) {
+ blockers.push("cache_key_sha is missing or invalid");
+ }
+ if (!bottle.link_manifest) {
+ blockers.push("link_manifest is missing");
+ }
+ if (!bottle.fork_instrumentation || !FORK_INSTRUMENTATION.has(bottle.fork_instrumentation)) {
+ blockers.push(`fork_instrumentation ${bottle.fork_instrumentation ?? ""} is invalid`);
+ }
+ if (blockers.length === 0) return null;
+ return `${name}: ${arch} bottle metadata is not publishable (${blockers.join("; ")})`;
+}
+
+function formatRuntimeStatus(status: NonNullable[string]): string {
+ const parts = [
+ `status=${status.status ?? "unknown"}`,
+ status.reason_code ? `reason_code=${status.reason_code}` : "",
+ status.reason ? `reason=${status.reason}` : "",
+ ].filter(Boolean);
+ for (const failure of status.artifact_policy_failures ?? []) {
+ parts.push(`artifact=${failure.path ?? ""}:${(failure.failures ?? []).join("|")}`);
+ }
+ return parts.join(", ");
+}
+
+function readPackageIndex(paths: string[]): Map {
+ const index = new Map();
+ for (const path of paths) {
+ const metadata = JSON.parse(readFileSync(path, "utf8")) as MetadataFile;
+ if (!Array.isArray(metadata.packages)) {
+ throw new Error(`${path}: metadata packages must be an array`);
+ }
+ for (const pkg of metadata.packages) {
+ if (!pkg.name) continue;
+ const existing = index.get(pkg.name);
+ if (!existing || preferPackage(pkg, existing)) {
+ index.set(pkg.name, pkg);
+ }
+ }
+ }
+ return index;
+}
+
+function preferPackage(candidate: PackageMetadata, existing: PackageMetadata): boolean {
+ const candidateScore = packageScore(candidate);
+ const existingScore = packageScore(existing);
+ return candidateScore > existingScore;
+}
+
+function packageScore(pkg: PackageMetadata): number {
+ let score = 0;
+ for (const bottle of pkg.bottles ?? []) {
+ if (bottle.status === "success") {
+ score += 4;
+ if (bottle.arch && bottleMetadataBlocker(pkg.name ?? "", bottle, bottle.arch) === null) {
+ score += 8;
+ }
+ }
+ if ((bottle.runtime_support ?? []).includes("node")) score += 2;
+ if ((bottle.runtime_support ?? []).includes("browser")) score += 2;
+ if (bottle.browser_compatible) score += 1;
+ }
+ return score;
+}
+
+function writeSummary(
+ options: CliOptions,
+ outcomes: Outcome[],
+ packageIndex: Map,
+): void {
+ const counts = countOutcomes(outcomes);
+ const summary = {
+ suite: "Homebrew composite VFS status",
+ bead_id: options.beadId,
+ generated_at: new Date().toISOString(),
+ result_dir: options.resultDir,
+ arch: options.arch,
+ runtimes: options.runtimes,
+ metadata: options.metadataPaths,
+ package_count: packageIndex.size,
+ counts,
+ outcomes,
+ };
+ writeFileSync(join(options.resultDir, "summary.json"), `${JSON.stringify(summary, null, 2)}\n`);
+}
+
+function writeOutcomeLists(resultDir: string, outcomes: Outcome[]): void {
+ const listsDir = join(resultDir, "outcome-lists");
+ const passed = outcomes.filter((outcome) => outcome.status === "pass");
+ const failed = outcomes.filter((outcome) => outcome.status === "fail");
+ const skipped = outcomes.filter((outcome) => outcome.status === "skip");
+ writeFileSync(
+ join(listsDir, "passed-tests.tsv"),
+ ["test\tcomposite\truntime\tdetails", ...passed.map((outcome) =>
+ `${outcome.name}\t${outcome.composite}\t${outcome.runtime}\t${tsv(outcome.details)}`,
+ )].join("\n") + "\n",
+ );
+ writeFileSync(
+ join(listsDir, "failed-tests.tsv"),
+ ["test\tcomposite\truntime\terror", ...failed.map((outcome) =>
+ `${outcome.name}\t${outcome.composite}\t${outcome.runtime}\t${tsv(outcome.details)}`,
+ )].join("\n") + "\n",
+ );
+ writeFileSync(
+ join(listsDir, "skipped-tests.tsv"),
+ ["test\tcomposite\truntime\treason", ...skipped.map((outcome) =>
+ `${outcome.name}\t${outcome.composite}\t${outcome.runtime}\t${tsv(outcome.details)}`,
+ )].join("\n") + "\n",
+ );
+}
+
+function countOutcomes(outcomes: Outcome[]): Record {
+ return {
+ pass: outcomes.filter((outcome) => outcome.status === "pass").length,
+ fail: outcomes.filter((outcome) => outcome.status === "fail").length,
+ skip: outcomes.filter((outcome) => outcome.status === "skip").length,
+ };
+}
+
+function tsv(value: string): string {
+ return value.replace(/\t/g, " ").replace(/\r?\n/g, " ");
+}
+
+function parseArgs(args: string[]): CliOptions {
+ const options: CliOptions = {
+ metadataPaths: [],
+ resultDir: "test-runs/homebrew-composite-status",
+ arch: "wasm32",
+ runtimes: ["node", "browser"],
+ beadId: "unknown",
+ };
+
+ for (let i = 0; i < args.length; i += 1) {
+ const arg = args[i];
+ switch (arg) {
+ case "--metadata":
+ options.metadataPaths.push(resolve(requireValue(args, ++i, arg)));
+ break;
+ case "--result-dir":
+ options.resultDir = resolve(requireValue(args, ++i, arg));
+ break;
+ case "--arch":
+ options.arch = parseArch(requireValue(args, ++i, arg));
+ break;
+ case "--runtime":
+ options.runtimes = [parseRuntime(requireValue(args, ++i, arg))];
+ break;
+ case "--bead-id":
+ options.beadId = requireValue(args, ++i, arg);
+ break;
+ case "--help":
+ case "-h":
+ usage(0);
+ break;
+ default:
+ usage(2, `unexpected argument ${arg}`);
+ }
+ }
+
+ if (options.metadataPaths.length === 0) usage(2, "at least one --metadata is required");
+ return options;
+}
+
+function parseArch(value: string): "wasm32" | "wasm64" {
+ if (value === "wasm32" || value === "wasm64") return value;
+ usage(2, `--arch must be wasm32 or wasm64, got ${value}`);
+}
+
+function parseRuntime(value: string): Runtime {
+ if (value === "node" || value === "browser") return value;
+ usage(2, `--runtime must be node or browser, got ${value}`);
+}
+
+function requireValue(args: string[], index: number, flag: string): string {
+ const value = args[index];
+ if (!value || value.startsWith("--")) usage(2, `${flag} requires a value`);
+ return value;
+}
+
+function usage(code: number, message?: string): never {
+ if (message) console.error(`homebrew-composite-status: ${message}`);
+ console.error(`usage: npx tsx scripts/homebrew-composite-status.ts \\
+ --metadata [--metadata ...] \\
+ [--result-dir ] [--arch wasm32|wasm64] [--runtime node|browser]`);
+ process.exit(code);
+}
+
+main().catch((err) => {
+ console.error(err);
+ process.exit(1);
+});
diff --git a/scripts/homebrew-generate-sidecars-from-env.sh b/scripts/homebrew-generate-sidecars-from-env.sh
index e77db3910..ada217cf8 100755
--- a/scripts/homebrew-generate-sidecars-from-env.sh
+++ b/scripts/homebrew-generate-sidecars-from-env.sh
@@ -108,89 +108,176 @@ for dep in package_toml.get("depends_on", []):
deps.append({"name": dep})
version = str(bottle_formula["pkg_version"])
+package_kind = package_toml.get("kind", "program")
+if package_kind not in {"library", "program"}:
+ raise SystemExit(f"unsupported Homebrew sidecar package kind for {formula}: {package_kind!r}")
+
+def package_links_and_env():
+ if package_kind == "library":
+ outputs = package_toml.get("outputs", {})
+ links = []
+ for key in ("headers", "libs", "pkgconfig"):
+ for rel in sorted(outputs.get(key, [])):
+ links.append({
+ "type": "file",
+ "source": rel,
+ "target": rel,
+ "mode": "0644",
+ })
+ if not links:
+ raise SystemExit(f"library formula {formula} has no declared package outputs to link")
+ return links, {}
+
+ outputs = package_toml.get("outputs", [])
+ links = []
+ if isinstance(outputs, list):
+ for output in outputs:
+ name = output.get("name")
+ if name:
+ links.append({"type": "symlink", "source": f"bin/{name}", "target": f"bin/{name}"})
+ if not links:
+ links.append({"type": "symlink", "source": f"bin/{formula}", "target": f"bin/{formula}"})
+ return links, {"PATH_prepend": ["bin"]}
+
+def package_fork_instrumentation():
+ # The Homebrew sidecar schema only accepts these four values. "auto" is a
+ # build-time placeholder, not a publishable disposition, so it must never
+ # reach the emitted metadata. The bottle-level value is aggregated from the
+ # per-output policies declared in package.toml: if any output forks the
+ # whole bottle requires fork instrumentation; a package that declares no
+ # policy is honestly reported as "unknown" rather than an invalid "auto".
+ valid = {"not-required", "required", "disabled", "unknown"}
+
+ def check(value, where):
+ if value not in valid:
+ raise SystemExit(
+ f"package {formula}: invalid fork_instrumentation {value!r} in "
+ f"{where}; expected one of {sorted(valid)}"
+ )
+ return value
+
+ top = package_toml.get("fork_instrumentation")
+ if top is not None and top != "auto":
+ return check(top, "package.toml [fork_instrumentation]")
+
+ declared = []
+ outputs = package_toml.get("outputs", [])
+ if isinstance(outputs, list):
+ for output in outputs:
+ value = output.get("fork_instrumentation")
+ if value is not None and value != "auto":
+ declared.append(check(value, f"output {output.get('name', '?')!r}"))
+
+ if not declared:
+ return "unknown"
+ if any(policy == "required" for policy in declared):
+ return "required"
+ if all(policy == "disabled" for policy in declared):
+ return "disabled"
+ return "not-required"
+
+def primary_program_name():
+ if package_kind != "program":
+ return formula
+ outputs = package_toml.get("outputs", [])
+ if isinstance(outputs, list):
+ for output in outputs:
+ if output.get("name"):
+ return output["name"]
+ return formula
+
+def default_node_smoke_text():
+ if package_kind == "library":
+ return (
+ f"Formula test compiled packages/registry/{formula}/test/{formula}_basic.c "
+ "against the installed keg and ran the resulting Wasm through "
+ "node --import tsx/esm examples/run-example.ts"
+ )
+ if formula == "bzip2":
+ return (
+ "Formula test ran bzip2 --help through "
+ "node --import tsx/esm examples/run-example.ts"
+ )
+ return (
+ f"Formula test ran {primary_program_name()} through "
+ "node --import tsx/esm examples/run-example.ts"
+ )
+
+def skipped_outcome(name, reason):
+ return {
+ "name": name,
+ "status": "skipped",
+ "passed": [],
+ "failed": [],
+ "skipped": [reason],
+ "skip_reason": reason,
+ }
+
+def failed_outcome(name, reason):
+ return {
+ "name": name,
+ "status": "failed",
+ "passed": [],
+ "failed": [reason],
+ "skipped": [],
+ }
+
+links, link_env = package_links_and_env()
browser_smoke_status = os.environ.get("KANDELO_HOMEBREW_BROWSER_SMOKE_STATUS", "skipped")
-if browser_smoke_status not in {"success", "skipped"}:
+if browser_smoke_status not in {"success", "skipped", "failed"}:
raise SystemExit(f"invalid KANDELO_HOMEBREW_BROWSER_SMOKE_STATUS={browser_smoke_status!r}")
browser_compatible = browser_smoke_status == "success"
if browser_compatible and arch != "wasm32":
raise SystemExit("browser smoke can only mark wasm32 bottles browser-compatible")
runtime_support = ["node", "browser"] if browser_compatible else ["node"]
-browser_smoke_outcome = {
- "name": "browser_smoke",
- "status": "skipped",
- "passed": [],
- "failed": [],
- "skipped": ["browser_compatible is false for this bottle"],
- "skip_reason": "No successful browser VFS smoke was recorded for this bottle.",
-}
-vfs_image_outcome = {
- "name": "homebrew_vfs_image",
- "status": "skipped",
- "passed": [],
- "failed": [],
- "skipped": ["precomposed browser VFS image was not built"],
- "skip_reason": "Browser-compatible gallery publication requires kd-8ho.10 browser smoke.",
-}
-gallery_outcome = {
- "name": "browser_gallery",
- "status": "skipped",
- "passed": [],
- "failed": [],
- "skipped": ["browser gallery assets were not generated"],
- "skip_reason": "Gallery assets require a successful browser VFS smoke.",
-}
+browser_reason = os.environ.get(
+ "KANDELO_HOMEBREW_BROWSER_SMOKE_REASON",
+ f"No successful browser VFS smoke was recorded for {formula} {arch}.",
+)
+browser_smoke_outcome = skipped_outcome("browser_smoke", browser_reason)
+if browser_smoke_status == "failed":
+ browser_smoke_outcome = failed_outcome("browser_smoke", browser_reason)
if browser_compatible:
vfs_image = os.environ.get("KANDELO_HOMEBREW_VFS_IMAGE", "")
vfs_report = os.environ.get("KANDELO_HOMEBREW_VFS_REPORT", "")
- gallery_root = os.environ.get("KANDELO_HOMEBREW_GALLERY_ROOT", "")
browser_url = os.environ.get("KANDELO_HOMEBREW_BROWSER_SMOKE_URL", "")
browser_command = os.environ.get(
"KANDELO_HOMEBREW_BROWSER_SMOKE_COMMAND",
- "/home/linuxbrew/.linuxbrew/bin/hello --version",
+ f"/home/linuxbrew/.linuxbrew/bin/{formula} --version",
)
missing = [
name for name, value in [
("KANDELO_HOMEBREW_VFS_IMAGE", vfs_image),
("KANDELO_HOMEBREW_VFS_REPORT", vfs_report),
- ("KANDELO_HOMEBREW_GALLERY_ROOT", gallery_root),
("KANDELO_HOMEBREW_BROWSER_SMOKE_URL", browser_url),
] if not value
]
if missing:
raise SystemExit("browser smoke success is missing env: " + ", ".join(missing))
- browser_smoke_outcome = {
- "name": "browser_smoke",
- "status": "success",
- "passed": [
- f"Playwright chromium launched {browser_url}",
- f"terminal command passed: {browser_command}",
- ],
- "failed": [],
- "skipped": [],
- }
- vfs_image_outcome = {
- "name": "homebrew_vfs_image",
- "status": "success",
- "passed": [
- f"built {vfs_image}",
- f"wrote report {vfs_report}",
- ],
- "failed": [],
- "skipped": [],
- }
- gallery_outcome = {
- "name": "browser_gallery",
- "status": "success",
- "passed": [
+ browser_passed = [
+ f"built precomposed VFS image {vfs_image}",
+ f"wrote VFS report {vfs_report}",
+ f"Playwright chromium launched {browser_url}",
+ f"terminal command passed: {browser_command}",
+ ]
+ gallery_root = os.environ.get("KANDELO_HOMEBREW_GALLERY_ROOT", "")
+ if gallery_root:
+ browser_passed.extend([
f"generated {gallery_root}/gallery.json",
f"generated {gallery_root}/index.toml",
"scripts/validate-software-gallery.mjs accepted generated gallery assets",
- ],
+ ])
+ browser_smoke_outcome = {
+ "name": "browser_smoke",
+ "status": "success",
+ "passed": browser_passed,
"failed": [],
"skipped": [],
}
+node_smoke_text = os.environ.get("KANDELO_HOMEBREW_NODE_SMOKE_COMMAND", default_node_smoke_text())
+
manifest = {
"schema": 1,
"tap_repository": os.environ["KANDELO_HOMEBREW_TAP_REPOSITORY"],
@@ -219,7 +306,7 @@ manifest = {
"prefix": "/home/linuxbrew/.linuxbrew",
"runtime_support": runtime_support,
"browser_compatible": browser_compatible,
- "fork_instrumentation": "not-required",
+ "fork_instrumentation": package_fork_instrumentation(),
"status": "success",
"built_by": os.environ["RUN_URL"],
"built_at": os.environ["GENERATED_AT"],
@@ -227,11 +314,9 @@ manifest = {
"url": os.environ["KANDELO_HOMEBREW_BOTTLE_URL"],
"cache_key_sha": os.environ["CACHE_KEY_SHA"],
"payload_root": f"{formula}/{version}",
- "links": [
- {"type": "symlink", "source": f"bin/{formula}", "target": f"bin/{formula}"}
- ],
+ "links": links,
"receipts": [f".brew/{formula}.rb", "INSTALL_RECEIPT.json"],
- "env": {"PATH_prepend": ["bin"]},
+ "env": link_env,
"build": {
"github_run": os.environ["RUN_URL"],
"job": os.environ.get("GITHUB_JOB", "local"),
@@ -260,8 +345,8 @@ manifest = {
"status": "skipped",
"passed": [],
"failed": [],
- "skipped": ["brew audit was not part of kd-8ho.5 local verification"],
- "skip_reason": "kd-8ho.5 validates the first bottle build and sidecars; tap audit can run in the real tap publication gate.",
+ "skipped": ["brew audit was not part of this local dry-run verification"],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
},
{
"name": "bottle_build",
@@ -278,15 +363,11 @@ manifest = {
{
"name": "node_smoke",
"status": "success",
- "passed": [
- "Formula test ran hello --version through node --import tsx/esm examples/run-example.ts"
- ],
+ "passed": [node_smoke_text],
"failed": [],
"skipped": [],
},
- vfs_image_outcome,
browser_smoke_outcome,
- gallery_outcome,
],
},
}
diff --git a/scripts/homebrew-package-browser-smoke.ts b/scripts/homebrew-package-browser-smoke.ts
new file mode 100644
index 000000000..1d3314a5f
--- /dev/null
+++ b/scripts/homebrew-package-browser-smoke.ts
@@ -0,0 +1,915 @@
+/**
+ * Browser smoke coverage for Kandelo Homebrew package sidecars.
+ *
+ * The runner consumes generated Kandelo/Homebrew sidecars, materializes each
+ * requested wasm32 package into a candidate VFS without requiring existing
+ * browser-compatible metadata, boots that image through BrowserKernel in
+ * Chromium, and runs package-specific checks.
+ */
+import { execFileSync, spawn, type ChildProcess } from "node:child_process";
+import {
+ appendFileSync,
+ copyFileSync,
+ existsSync,
+ mkdirSync,
+ readFileSync,
+ renameSync,
+ rmSync,
+ writeFileSync,
+} from "node:fs";
+import { basename, dirname, join, resolve } from "node:path";
+import { fileURLToPath } from "node:url";
+import type { Browser } from "playwright";
+import { ABI_VERSION } from "../host/src/generated/abi";
+import type {
+ HomebrewBottleArch,
+ HomebrewTapMetadata,
+ HomebrewVfsPackagePlan,
+} from "../host/src/homebrew-vfs-planner";
+import type { MemoryFileSystem } from "../host/src/vfs/memory-fs";
+import {
+ HOMEBREW_CELLAR,
+ browserFormulaUnsupportedReason,
+ browserSmokeCasesForFormula,
+ browserUnsupportedReason,
+ parseHomebrewSmokeFormula,
+ SQLITE_BROWSER_CONSUMER_PATH,
+ type BrowserSmokeCase,
+ type HomebrewSmokeFormula,
+} from "./homebrew-package-smoke-cases";
+import {
+ countOutcomes,
+ SkipCase,
+ type SmokeOutcome,
+ writeOutcomeLists,
+} from "./homebrew-smoke-outcomes";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const repoRoot = resolve(__dirname, "..");
+const browserDemoDir = join(repoRoot, "apps", "browser-demos");
+const publicSmokeRoot = join(browserDemoDir, "public", "__kandelo-homebrew-smoke");
+const publicSmokePath = "/__kandelo-homebrew-smoke";
+
+interface CliOptions {
+ resultDir: string;
+ tapRoot: string;
+ formulas: HomebrewSmokeFormula[];
+ arch: HomebrewBottleArch;
+ bottleCache: string;
+ timeoutMs: number;
+ maxBytes: number;
+ beadId: string;
+ port: number;
+ runId: string;
+ browserChannel: string;
+}
+
+interface BuiltBrowserVfs {
+ formula: HomebrewSmokeFormula;
+ fs: MemoryFileSystem;
+ imagePath: string;
+ reportPath: string;
+ publicPath: string;
+ publicUrl: string;
+}
+
+interface BrowserDiagnostics {
+ console: string[];
+ pageErrors: string[];
+ requestFailures: string[];
+}
+
+interface BrowserSmokeResult {
+ exitCode: number;
+ stdout: string;
+ stderr: string;
+ combined: string;
+ durationMs: number;
+}
+
+type PackageStatus = "success" | "failed" | "skipped";
+
+async function main(): Promise {
+ const options = parseArgs(process.argv.slice(2));
+ mkdirSync(options.resultDir, { recursive: true });
+ mkdirSync(join(options.resultDir, "outcome-lists"), { recursive: true });
+ mkdirSync(options.bottleCache, { recursive: true });
+
+ const unsupportedReason = browserUnsupportedReason(options.arch);
+ const metadataPath = join(options.tapRoot, "Kandelo", "metadata.json");
+ const metadata = unsupportedReason ? undefined : readJsonFile(metadataPath);
+ const tapCommit = tryGitRevParse(options.tapRoot) ?? metadata?.tap_commit ?? "unknown";
+ const startedAt = new Date();
+ const outcomes: SmokeOutcome[] = [];
+ const builtByFormula = new Map();
+ const publicRunDir = join(publicSmokeRoot, options.runId);
+
+ writeCurrentRun(options, {
+ status: "running",
+ startedAt,
+ tapCommit,
+ outcomes,
+ currentCase: "startup",
+ });
+
+ try {
+ if (unsupportedReason) {
+ for (const formula of options.formulas) {
+ await runCase(outcomes, options, tapCommit, `browser_smoke_${formula}_unsupported_arch`, async () => {
+ throw new SkipCase(unsupportedReason);
+ }, formulaDir(options, formula));
+ }
+ } else {
+ mkdirSync(publicRunDir, { recursive: true });
+ for (const formula of options.formulas) {
+ await runCase(outcomes, options, tapCommit, `homebrew_browser_vfs_build_${formula}`, async () => {
+ if (!metadata) throw new Error(`missing Homebrew metadata: ${metadataPath}`);
+ const built = await buildFormulaVfs(metadata, formula, options);
+ builtByFormula.set(formula, built);
+ return `image=${built.imagePath}; report=${built.reportPath}; browser_url=${built.publicUrl}`;
+ }, formulaDir(options, formula));
+ }
+
+ let vite: ChildProcess | undefined;
+ let browser: Browser | undefined;
+ await runCase(outcomes, options, tapCommit, "browser_server_start", async () => {
+ vite = await startViteServer(options);
+ const { chromium } = await import("playwright");
+ browser = await chromium.launch({
+ channel: options.browserChannel,
+ headless: true,
+ });
+ return `vite=http://127.0.0.1:${options.port}; channel=${options.browserChannel}`;
+ }, join(options.resultDir, "vite.log"));
+
+ try {
+ for (const formula of options.formulas) {
+ const formulaReason = browserFormulaUnsupportedReason(formula);
+ if (formulaReason) {
+ await runCase(
+ outcomes,
+ options,
+ tapCommit,
+ `browser_smoke_${formula}_unsupported`,
+ async () => {
+ throw new SkipCase(formulaReason);
+ },
+ join(formulaDir(options, formula), `${formula}-unsupported.txt`),
+ );
+ continue;
+ }
+ for (const smokeCase of browserSmokeCasesForFormula(formula)) {
+ await runCase(
+ outcomes,
+ options,
+ tapCommit,
+ `browser_smoke_${formula}_${smokeCase.name}`,
+ async () => {
+ const built = builtByFormula.get(formula);
+ if (!built) throw new SkipCase(`requires successful homebrew_browser_vfs_build_${formula}`);
+ if (!browser) throw new Error("browser did not start");
+ return runBrowserSmokeCase(browser, built, smokeCase, options);
+ },
+ join(formulaDir(options, formula), `${smokeCase.name}-terminal.txt`),
+ );
+ }
+ }
+ } finally {
+ await browser?.close().catch(() => {});
+ await stopProcess(vite);
+ }
+ }
+ } finally {
+ rmSync(publicRunDir, { recursive: true, force: true });
+ }
+
+ writeOutcomeLists(options.resultDir, outcomes, { includeArtifactPath: true });
+ writeSummary(options, {
+ startedAt,
+ completedAt: new Date(),
+ tapCommit,
+ outcomes,
+ builtByFormula,
+ });
+ writeCurrentRun(options, {
+ status: outcomes.some((outcome) => outcome.status === "fail") ? "failed" : "complete",
+ startedAt,
+ tapCommit,
+ outcomes,
+ currentCase: "complete",
+ });
+
+ process.exit(outcomes.some((outcome) => outcome.status === "fail") ? 1 : 0);
+}
+
+async function buildFormulaVfs(
+ metadata: HomebrewTapMetadata,
+ formula: HomebrewSmokeFormula,
+ options: CliOptions,
+): Promise {
+ const [
+ { buildHomebrewVfs },
+ { planHomebrewVfs },
+ { MemoryFileSystem },
+ { saveImage },
+ ] = await Promise.all([
+ import("../host/src/homebrew-vfs-builder"),
+ import("../host/src/homebrew-vfs-planner"),
+ import("../host/src/vfs/memory-fs"),
+ import("../images/vfs/scripts/vfs-image-helpers"),
+ ]);
+ const plan = await planHomebrewVfs(metadata, {
+ packages: [formula],
+ arch: options.arch,
+ expectedAbi: ABI_VERSION,
+ loadLinkManifest: (relPath) => readJsonFile(join(options.tapRoot, relPath)),
+ });
+ const fs = createFs(MemoryFileSystem, options.maxBytes);
+ const result = await buildHomebrewVfs(plan, {
+ fs,
+ createdBy: "scripts/homebrew-package-browser-smoke.ts",
+ loadBottleBytes: (pkg) => loadBottleBytes(pkg, options),
+ });
+
+ if (formula === "sqlite") {
+ await compileAndInjectSqliteConsumer(fs, options);
+ }
+
+ const dir = formulaDir(options, formula);
+ mkdirSync(dir, { recursive: true });
+ const reportPath = join(dir, `${formula}-${options.arch}-homebrew-vfs-report.json`);
+ const imagePath = join(dir, `${formula}-${options.arch}-homebrew.vfs.zst`);
+ writeFileSync(reportPath, `${JSON.stringify({ ...result.report, image: imagePath }, null, 2)}\n`);
+ await saveImage(fs, imagePath, {
+ metadata: {
+ version: 1,
+ kernelAbi: plan.kandeloAbi,
+ createdBy: "scripts/homebrew-package-browser-smoke.ts",
+ homebrew: {
+ tapRepository: plan.tapRepository,
+ tapCommit: plan.tapCommit,
+ releaseTag: plan.releaseTag,
+ packages: plan.packages.map((pkg) => ({
+ name: pkg.name,
+ version: pkg.version,
+ arch: pkg.arch,
+ sourceStatus: pkg.sourceStatus,
+ cacheKeySha: pkg.cacheKeySha,
+ })),
+ },
+ },
+ });
+
+ const publicDir = join(publicSmokeRoot, options.runId);
+ mkdirSync(publicDir, { recursive: true });
+ const publicPath = join(publicDir, basename(imagePath));
+ copyFileSync(imagePath, publicPath);
+ const publicUrl = `http://127.0.0.1:${options.port}${publicSmokePath}/${encodeURIComponent(options.runId)}/${encodeURIComponent(basename(imagePath))}`;
+
+ return { formula, fs, imagePath, reportPath, publicPath, publicUrl };
+}
+
+async function compileAndInjectSqliteConsumer(fs: MemoryFileSystem, options: CliOptions): Promise {
+ const { ensureDirRecursive, writeVfsBinary } = await import("../images/vfs/scripts/vfs-image-helpers");
+ const stage = join(formulaDir(options, "sqlite"), "sqlite-consumer-build", options.arch);
+ rmSync(stage, { recursive: true, force: true });
+ mkdirSync(join(stage, "include"), { recursive: true });
+ mkdirSync(join(stage, "lib"), { recursive: true });
+
+ const version = findPackageVersion(fs, "sqlite");
+ writeFileSync(
+ join(stage, "include", "sqlite3.h"),
+ readVfsFile(fs, `${HOMEBREW_CELLAR}/sqlite/${version}/include/sqlite3.h`),
+ );
+ writeFileSync(
+ join(stage, "include", "sqlite3ext.h"),
+ readVfsFile(fs, `${HOMEBREW_CELLAR}/sqlite/${version}/include/sqlite3ext.h`),
+ );
+ writeFileSync(
+ join(stage, "lib", "libsqlite3.a"),
+ readVfsFile(fs, `${HOMEBREW_CELLAR}/sqlite/${version}/lib/libsqlite3.a`),
+ );
+
+ const cc = join(repoRoot, "sdk", "bin", `${options.arch}posix-cc`);
+ if (!existsSync(cc)) {
+ throw new SkipCase(`sqlite consumer compiler is unavailable: ${cc}`);
+ }
+ const testSrc = join(repoRoot, "packages", "registry", "sqlite", "test", "sqlite_basic.c");
+ const outWasm = join(stage, "sqlite_basic.wasm");
+ try {
+ execFileSync(cc, [
+ `-I${join(stage, "include")}`,
+ testSrc,
+ join(stage, "lib", "libsqlite3.a"),
+ "-lm",
+ "-o",
+ outWasm,
+ ], {
+ cwd: repoRoot,
+ env: {
+ ...process.env,
+ PATH: `${join(repoRoot, "sdk", "bin")}:${process.env.PATH ?? ""}`,
+ WASM_POSIX_SYSROOT: join(repoRoot, "sysroot"),
+ },
+ stdio: "pipe",
+ });
+ } catch (err) {
+ const message = err instanceof Error ? err.message : String(err);
+ const stderr = readProcessErrorStderr(err);
+ throw new Error(`sqlite consumer compilation failed: ${stderr || message}`);
+ }
+
+ ensureDirRecursive(fs, dirname(SQLITE_BROWSER_CONSUMER_PATH));
+ writeVfsBinary(fs, SQLITE_BROWSER_CONSUMER_PATH, new Uint8Array(readFileSync(outWasm)), 0o755);
+}
+
+async function runBrowserSmokeCase(
+ browser: Browser,
+ built: BuiltBrowserVfs,
+ smokeCase: BrowserSmokeCase,
+ options: CliOptions,
+): Promise {
+ const dir = formulaDir(options, smokeCase.formula);
+ const terminalPath = join(dir, `${smokeCase.name}-terminal.txt`);
+ const eventsPath = join(dir, `${smokeCase.name}-browser-events.json`);
+ const screenshotPath = join(dir, `${smokeCase.name}-failure.png`);
+ const tracePath = join(dir, `${smokeCase.name}-trace.zip`);
+ const diagnostics: BrowserDiagnostics = {
+ console: [],
+ pageErrors: [],
+ requestFailures: [],
+ };
+ const context = await browser.newContext();
+ await context.tracing.start({ screenshots: true, snapshots: true });
+ const page = await context.newPage();
+ page.on("console", (msg) => {
+ if (msg.type() === "warning" || msg.type() === "error") {
+ diagnostics.console.push(`[${msg.type()}] ${msg.text()}`);
+ }
+ });
+ page.on("pageerror", (err) => diagnostics.pageErrors.push(err.stack ?? err.message));
+ page.on("requestfailed", (request) => {
+ diagnostics.requestFailures.push(`${request.method()} ${request.url()} ${request.failure()?.errorText ?? ""}`.trim());
+ });
+
+ let failed = false;
+ try {
+ await page.goto(`http://127.0.0.1:${options.port}/pages/homebrew-smoke/`, {
+ waitUntil: "domcontentloaded",
+ timeout: options.timeoutMs,
+ });
+ await page.waitForFunction(() => window.__homebrewSmokeReady === true, undefined, {
+ timeout: options.timeoutMs,
+ });
+ const result = await page.evaluate(
+ async ({ vfsUrl, argv, stdin, env, timeoutMs }) =>
+ window.__runHomebrewSmoke({ vfsUrl, argv, stdin, env, timeoutMs }),
+ {
+ vfsUrl: built.publicUrl,
+ argv: smokeCase.argv,
+ stdin: smokeCase.stdin,
+ env: smokeCase.env,
+ timeoutMs: options.timeoutMs,
+ },
+ ) as BrowserSmokeResult;
+ const output = [
+ `command: ${smokeCase.command}`,
+ `argv: ${JSON.stringify(smokeCase.argv)}`,
+ `exitCode: ${result.exitCode}`,
+ `durationMs: ${result.durationMs}`,
+ "",
+ "stdout:",
+ result.stdout,
+ "",
+ "stderr:",
+ result.stderr,
+ ].join("\n");
+ writeFileSync(terminalPath, output);
+ writeFileSync(eventsPath, `${JSON.stringify(diagnostics, null, 2)}\n`);
+
+ if (result.exitCode !== 0) {
+ throw new Error(`${smokeCase.name} exited ${result.exitCode}; output=${JSON.stringify(output)}`);
+ }
+ smokeCase.expected.lastIndex = 0;
+ if (!smokeCase.expected.test(result.combined)) {
+ throw new Error(`${smokeCase.name} output did not match ${smokeCase.expected}: ${JSON.stringify(output)}`);
+ }
+ return `command=${smokeCase.command}; url=${built.publicUrl}; output=${terminalPath}`;
+ } catch (err) {
+ failed = true;
+ await page.screenshot({ path: screenshotPath, fullPage: true }).catch(() => {});
+ const message = err instanceof Error ? err.message : String(err);
+ writeFileSync(eventsPath, `${JSON.stringify({ ...diagnostics, error: message }, null, 2)}\n`);
+ throw err;
+ } finally {
+ await context.tracing.stop(failed ? { path: tracePath } : undefined).catch(() => {});
+ await context.close().catch(() => {});
+ }
+}
+
+async function runCase(
+ outcomes: SmokeOutcome[],
+ options: CliOptions,
+ tapCommit: string,
+ name: string,
+ fn: () => Promise,
+ artifactPath?: string,
+): Promise {
+ writeCurrentRun(options, {
+ status: "running",
+ tapCommit,
+ outcomes,
+ currentCase: name,
+ });
+ const started = Date.now();
+ try {
+ const details = await fn();
+ outcomes.push({ name, status: "pass", durationMs: Date.now() - started, details, artifactPath });
+ } catch (err) {
+ const error = err instanceof Error ? err : new Error(String(err));
+ const skipped = error instanceof SkipCase;
+ outcomes.push({
+ name,
+ status: skipped ? "skip" : "fail",
+ durationMs: Date.now() - started,
+ details: error.message,
+ ...(skipped ? {} : { error: error.stack ?? error.message }),
+ artifactPath,
+ });
+ }
+ writeCurrentRun(options, {
+ status: "running",
+ tapCommit,
+ outcomes,
+ currentCase: name,
+ });
+}
+
+async function startViteServer(options: CliOptions): Promise {
+ const logPath = join(options.resultDir, "vite.log");
+ writeFileSync(logPath, "");
+ return new Promise((resolvePromise, reject) => {
+ const proc = spawn("npx", [
+ "vite",
+ "--config",
+ join(browserDemoDir, "vite.config.ts"),
+ "--host",
+ "127.0.0.1",
+ "--port",
+ String(options.port),
+ "--strictPort",
+ ], {
+ cwd: browserDemoDir,
+ stdio: ["ignore", "pipe", "pipe"],
+ env: {
+ ...process.env,
+ KANDELO_BROWSER_TEST_NO_HMR: "1",
+ KANDELO_BROWSER_DEMO_INPUTS: "homebrew-smoke",
+ KANDELO_PLAYWRIGHT_PORT: String(options.port),
+ },
+ });
+
+ let started = false;
+ const timeout = setTimeout(() => {
+ if (!started) {
+ proc.kill();
+ reject(new Error(`Vite server did not start within 30000ms; see ${logPath}`));
+ }
+ }, 30_000);
+ const onData = (data: Buffer) => {
+ const text = data.toString();
+ appendFileSync(logPath, text);
+ if (!started && /Local:\s+http:\/\/127\.0\.0\.1:/.test(text)) {
+ started = true;
+ clearTimeout(timeout);
+ setTimeout(() => resolvePromise(proc), 500);
+ }
+ };
+ proc.stdout?.on("data", onData);
+ proc.stderr?.on("data", onData);
+ proc.on("exit", (code) => {
+ if (!started) {
+ clearTimeout(timeout);
+ reject(new Error(`Vite exited with code ${code}; see ${logPath}`));
+ }
+ });
+ proc.on("error", (err) => {
+ if (!started) {
+ clearTimeout(timeout);
+ reject(err);
+ }
+ });
+ });
+}
+
+async function stopProcess(proc: ChildProcess | undefined): Promise {
+ if (!proc || proc.exitCode !== null || proc.signalCode !== null) return;
+ await new Promise((resolvePromise) => {
+ const timer = setTimeout(() => {
+ proc.kill("SIGKILL");
+ resolvePromise();
+ }, 5_000);
+ proc.once("exit", () => {
+ clearTimeout(timer);
+ resolvePromise();
+ });
+ proc.kill();
+ });
+}
+
+async function loadBottleBytes(
+ pkg: HomebrewVfsPackagePlan,
+ options: CliOptions,
+): Promise {
+ if (pkg.url.startsWith("file://")) {
+ return new Uint8Array(readFileSync(fileURLToPath(pkg.url)));
+ }
+
+ const cachePath = join(options.bottleCache, `${pkg.sha256}.tar.gz`);
+ if (existsSync(cachePath)) return new Uint8Array(readFileSync(cachePath));
+ if (!pkg.url.startsWith("https://")) {
+ throw new Error(
+ `package ${pkg.name}@${pkg.version} bottle URL must be https:// or file://, got ${pkg.url}`,
+ );
+ }
+
+ const { fetchHomebrewBottleBytes } = await import("../host/src/homebrew-vfs-fetch");
+ const bytes = await fetchHomebrewBottleBytes(pkg.url);
+ writeFileSync(cachePath, bytes);
+ return bytes;
+}
+
+function findPackageVersion(fs: MemoryFileSystem, formula: string): string {
+ const info = JSON.parse(new TextDecoder().decode(readVfsFile(fs, "/etc/kandelo/homebrew-vfs.json")));
+ const pkg = info.packages?.find((candidate: { name?: string }) => candidate.name === formula);
+ if (!pkg) throw new Error(`package ${formula} missing from /etc/kandelo/homebrew-vfs.json`);
+ const keg = String(pkg.keg ?? "");
+ const prefix = `${HOMEBREW_CELLAR}/${formula}/`;
+ if (!keg.startsWith(prefix)) throw new Error(`unexpected ${formula} keg path: ${keg}`);
+ return keg.slice(prefix.length);
+}
+
+function readVfsFile(fs: MemoryFileSystem, path: string): Uint8Array {
+ const st = fs.stat(path);
+ const fd = fs.open(path, 0, 0);
+ try {
+ const out = new Uint8Array(st.size);
+ let offset = 0;
+ while (offset < out.byteLength) {
+ const n = fs.read(fd, out.subarray(offset), null, out.byteLength - offset);
+ if (n <= 0) break;
+ offset += n;
+ }
+ return out.subarray(0, offset);
+ } finally {
+ fs.close(fd);
+ }
+}
+
+function createFs(
+ MemoryFileSystemCtor: {
+ create(sab: SharedArrayBuffer, maxBytes?: number): MemoryFileSystem;
+ },
+ maxBytes: number,
+): MemoryFileSystem {
+ const SharedArrayBufferCtor = SharedArrayBuffer as new (
+ byteLength: number,
+ options?: { maxByteLength?: number },
+ ) => SharedArrayBuffer;
+ return MemoryFileSystemCtor.create(
+ new SharedArrayBufferCtor(maxBytes, { maxByteLength: maxBytes }),
+ maxBytes,
+ );
+}
+
+function parseArgs(args: string[]): CliOptions {
+ const defaultResultDir = join(
+ repoRoot,
+ "test-runs",
+ "homebrew-package-browser-smoke",
+ new Date().toISOString().replace(/[-:]/g, "").replace(/\..+$/, "Z"),
+ );
+ const options: CliOptions = {
+ resultDir: process.env.KANDELO_TEST_RESULT_DIR || defaultResultDir,
+ tapRoot: process.env.KANDELO_HOMEBREW_TAP_ROOT || "",
+ formulas: [],
+ arch: "wasm32",
+ bottleCache: "",
+ timeoutMs: 180_000,
+ maxBytes: 128 * 1024 * 1024,
+ beadId: process.env.KANDELO_BEAD_ID || "kd-1mr.2.1",
+ port: Number(process.env.KANDELO_PLAYWRIGHT_PORT ?? 5401),
+ runId: "",
+ browserChannel: process.env.KANDELO_PLAYWRIGHT_CHANNEL || "chromium",
+ };
+
+ for (let i = 0; i < args.length; i += 1) {
+ const arg = args[i];
+ switch (arg) {
+ case "--result-dir":
+ options.resultDir = requireValue(args, ++i, arg);
+ break;
+ case "--tap-root":
+ options.tapRoot = requireValue(args, ++i, arg);
+ break;
+ case "--formula":
+ options.formulas.push(parseFormula(requireValue(args, ++i, arg)));
+ break;
+ case "--arch":
+ options.arch = parseArch(requireValue(args, ++i, arg));
+ break;
+ case "--bottle-cache":
+ options.bottleCache = requireValue(args, ++i, arg);
+ break;
+ case "--timeout-ms":
+ options.timeoutMs = parsePositiveInt(requireValue(args, ++i, arg), arg);
+ break;
+ case "--max-bytes":
+ options.maxBytes = parseByteSize(requireValue(args, ++i, arg));
+ break;
+ case "--bead-id":
+ options.beadId = requireValue(args, ++i, arg);
+ break;
+ case "--port":
+ options.port = parsePositiveInt(requireValue(args, ++i, arg), arg);
+ break;
+ case "--run-id":
+ options.runId = sanitizeToken(requireValue(args, ++i, arg));
+ break;
+ case "--browser-channel":
+ options.browserChannel = requireValue(args, ++i, arg);
+ break;
+ case "--help":
+ case "-h":
+ usage(0);
+ break;
+ default:
+ usage(2, `unexpected argument ${arg}`);
+ }
+ }
+
+ if (!options.tapRoot) usage(2, "--tap-root is required");
+ if (options.formulas.length === 0) usage(2, "at least one --formula is required");
+ const seen = new Set();
+ for (const formula of options.formulas) {
+ if (seen.has(formula)) usage(2, `duplicate --formula ${formula}`);
+ seen.add(formula);
+ }
+ options.resultDir = resolve(options.resultDir);
+ options.tapRoot = resolve(options.tapRoot);
+ options.bottleCache = options.bottleCache
+ ? resolve(options.bottleCache)
+ : join(options.resultDir, "bottle-cache");
+ options.runId ||= `${sanitizeToken(options.beadId)}-${new Date().toISOString().replace(/[^0-9TZ]/g, "")}-${process.pid}`;
+ return options;
+}
+
+function parseFormula(value: string): HomebrewSmokeFormula {
+ try {
+ return parseHomebrewSmokeFormula(value);
+ } catch (err) {
+ usage(2, err instanceof Error ? err.message : String(err));
+ }
+}
+
+function parseArch(value: string): HomebrewBottleArch {
+ if (value === "wasm32" || value === "wasm64") return value;
+ usage(2, `--arch must be wasm32 or wasm64, got ${value}`);
+}
+
+function parsePositiveInt(value: string, flag: string): number {
+ const parsed = Number(value);
+ if (!Number.isInteger(parsed) || parsed <= 0) usage(2, `${flag} must be a positive integer`);
+ return parsed;
+}
+
+function parseByteSize(value: string): number {
+ const match = /^([1-9][0-9]*)([kKmMgG]i?[bB]?|[bB])?$/.exec(value);
+ if (!match) usage(2, `--max-bytes must be a positive byte size, got ${value}`);
+ const amount = Number(match[1]);
+ const suffix = (match[2] ?? "b").toLowerCase();
+ const multiplier = suffix.startsWith("g") ? 1024 ** 3
+ : suffix.startsWith("m") ? 1024 ** 2
+ : suffix.startsWith("k") ? 1024
+ : 1;
+ return amount * multiplier;
+}
+
+function requireValue(args: string[], index: number, flag: string): string {
+ const value = args[index];
+ if (!value || value.startsWith("--")) usage(2, `${flag} requires a value`);
+ return value;
+}
+
+function usage(code: number, message?: string): never {
+ if (message) console.error(`homebrew-package-browser-smoke: ${message}`);
+ console.error(`usage: npx tsx scripts/homebrew-package-browser-smoke.ts \\
+ --tap-root --formula [--formula ...] \\
+ [--arch ] [--result-dir ] [--bottle-cache ] \\
+ [--timeout-ms ] [--max-bytes ] [--port ]`);
+ process.exit(code);
+}
+
+function writeSummary(
+ options: CliOptions,
+ data: {
+ startedAt: Date;
+ completedAt: Date;
+ tapCommit: string;
+ outcomes: SmokeOutcome[];
+ builtByFormula: Map;
+ },
+): void {
+ const counts = countOutcomes(data.outcomes);
+ const packages = options.formulas.map((formula) =>
+ summarizePackage(formula, options, data.outcomes, data.builtByFormula.get(formula))
+ );
+ const summary = {
+ suite: "Homebrew package browser VFS smoke",
+ bead_id: options.beadId,
+ started_at: data.startedAt.toISOString(),
+ completed_at: data.completedAt.toISOString(),
+ duration_ms: data.completedAt.getTime() - data.startedAt.getTime(),
+ result_dir: options.resultDir,
+ tap_root: options.tapRoot,
+ tap_commit: data.tapCommit,
+ arch: options.arch,
+ formulas: options.formulas,
+ counts,
+ outcomes: data.outcomes,
+ packages,
+ artifacts: {
+ passed: join(options.resultDir, "outcome-lists", "passed-tests.tsv"),
+ failed: join(options.resultDir, "outcome-lists", "failed-tests.tsv"),
+ skipped: join(options.resultDir, "outcome-lists", "skipped-tests.tsv"),
+ failures: join(options.resultDir, "failures.json"),
+ current_run: join(options.resultDir, "current-run.json"),
+ },
+ };
+ writeFileSync(join(options.resultDir, "summary.json"), `${JSON.stringify(summary, null, 2)}\n`);
+ writeFileSync(join(options.resultDir, "summary.md"), [
+ "# Homebrew package browser VFS smoke",
+ "",
+ `Result dir: \`${options.resultDir}\``,
+ `Tap commit: \`${data.tapCommit}\``,
+ `Counts: ${counts.pass} pass, ${counts.fail} fail, ${counts.skip} skip`,
+ "",
+ "| Formula | Status | Browser URL | Details |",
+ "|---|---:|---|---|",
+ ...packages.map((pkg) =>
+ `| \`${pkg.formula}\` | ${pkg.status} | ${pkg.browser_url ? `\`${pkg.browser_url}\`` : ""} | ${[...pkg.failed, ...pkg.skipped].join("; ").replace(/\|/g, "\\|")} |`,
+ ),
+ "",
+ "| Test | Status | Details |",
+ "|---|---:|---|",
+ ...data.outcomes.map((outcome) =>
+ `| \`${outcome.name}\` | ${outcome.status} | ${(outcome.details ?? "").replace(/\|/g, "\\|")} |`,
+ ),
+ "",
+ ].join("\n"));
+}
+
+function summarizePackage(
+ formula: HomebrewSmokeFormula,
+ options: CliOptions,
+ outcomes: SmokeOutcome[],
+ built: BuiltBrowserVfs | undefined,
+): {
+ formula: HomebrewSmokeFormula;
+ arch: HomebrewBottleArch;
+ status: PackageStatus;
+ required_cases: string[];
+ browser_url?: string;
+ vfs_image?: string;
+ vfs_report?: string;
+ commands: string[];
+ argv: string[][];
+ passed: string[];
+ failed: string[];
+ skipped: string[];
+ skip_reason?: string;
+} {
+ const smokeCases = browserSmokeCasesForFormula(formula);
+ const formulaOutcomes = outcomes.filter((outcome) =>
+ outcome.name === `homebrew_browser_vfs_build_${formula}` ||
+ outcome.name.startsWith(`browser_smoke_${formula}_`)
+ );
+ const globalOutcomes = outcomes.filter((outcome) => outcome.name === "browser_server_start");
+ const relevant = [...globalOutcomes, ...formulaOutcomes];
+ const failed = relevant.filter((outcome) => outcome.status === "fail").map(formatOutcome);
+ const skipped = formulaOutcomes.filter((outcome) => outcome.status === "skip").map(formatOutcome);
+ const passed = relevant.filter((outcome) => outcome.status === "pass").map(formatOutcome);
+ const status: PackageStatus = failed.length > 0 ? "failed" : skipped.length > 0 ? "skipped" : "success";
+ const firstSkip = formulaOutcomes.find((outcome) => outcome.status === "skip");
+
+ return {
+ formula,
+ arch: options.arch,
+ status,
+ required_cases: smokeCases.filter((smokeCase) => smokeCase.required).map((smokeCase) => smokeCase.name),
+ browser_url: built?.publicUrl,
+ vfs_image: built?.imagePath,
+ vfs_report: built?.reportPath,
+ commands: smokeCases.map((smokeCase) => smokeCase.command),
+ argv: smokeCases.map((smokeCase) => smokeCase.argv),
+ passed,
+ failed,
+ skipped,
+ ...(status === "skipped" && firstSkip?.details ? { skip_reason: firstSkip.details } : {}),
+ };
+}
+
+function formatOutcome(outcome: SmokeOutcome): string {
+ const text = outcome.status === "fail"
+ ? outcome.error ?? outcome.details ?? ""
+ : outcome.details ?? "";
+ return `${outcome.name}: ${text}${outcome.artifactPath ? ` [${outcome.artifactPath}]` : ""}`;
+}
+
+function writeCurrentRun(
+ options: CliOptions,
+ data: {
+ status: "running" | "complete" | "failed";
+ startedAt?: Date;
+ tapCommit: string;
+ outcomes: SmokeOutcome[];
+ currentCase: string;
+ },
+): void {
+ const counts = countOutcomes(data.outcomes);
+ const currentRun = {
+ suite: "homebrew-package-browser-smoke",
+ bead_id: options.beadId,
+ worktree: repoRoot,
+ result_dir: options.resultDir,
+ status: data.status,
+ started_at: data.startedAt?.toISOString(),
+ updated_at: new Date().toISOString(),
+ current_case: data.currentCase,
+ progress: {
+ completed: data.outcomes.length,
+ total: options.arch === "wasm64"
+ ? options.formulas.length
+ : options.formulas.length * 2 + 1,
+ pass: counts.pass,
+ fail: counts.fail,
+ skip: counts.skip,
+ },
+ tap_root: options.tapRoot,
+ tap_commit: data.tapCommit,
+ command: {
+ cwd: repoRoot,
+ argv: process.argv,
+ },
+ outcome_lists: {
+ passed: join(options.resultDir, "outcome-lists", "passed-tests.tsv"),
+ failed: join(options.resultDir, "outcome-lists", "failed-tests.tsv"),
+ skipped: join(options.resultDir, "outcome-lists", "skipped-tests.tsv"),
+ },
+ stale_no_runner_threshold_seconds: 900,
+ expected_next: data.status === "running"
+ ? { deterministic: true, action: "continue current browser smoke case" }
+ : { deterministic: false, action: "suite terminal" },
+ };
+ const out = join(options.resultDir, "current-run.json");
+ const tmp = `${out}.tmp`;
+ writeFileSync(tmp, `${JSON.stringify(currentRun, null, 2)}\n`);
+ renameSync(tmp, out);
+}
+
+function formulaDir(options: CliOptions, formula: HomebrewSmokeFormula): string {
+ return join(options.resultDir, `${formula}-${options.arch}`);
+}
+
+function readJsonFile(path: string): T {
+ return JSON.parse(readFileSync(path, "utf8")) as T;
+}
+
+function tryGitRevParse(path: string): string | undefined {
+ try {
+ return execFileSync("git", ["-C", path, "rev-parse", "HEAD"], {
+ encoding: "utf8",
+ stdio: ["ignore", "pipe", "ignore"],
+ }).trim();
+ } catch {
+ return undefined;
+ }
+}
+
+function readProcessErrorStderr(err: unknown): string {
+ if (err && typeof err === "object" && "stderr" in err) {
+ const stderr = (err as { stderr?: unknown }).stderr;
+ if (stderr instanceof Buffer) return stderr.toString();
+ if (typeof stderr === "string") return stderr;
+ }
+ return "";
+}
+
+function sanitizeToken(value: string): string {
+ return value.replace(/[^A-Za-z0-9_.-]+/g, "_").replace(/^_+|_+$/g, "") || "run";
+}
+
+main().catch((err) => {
+ console.error(err);
+ process.exit(1);
+});
diff --git a/scripts/homebrew-package-framebuffer-smoke.ts b/scripts/homebrew-package-framebuffer-smoke.ts
new file mode 100644
index 000000000..e137379d6
--- /dev/null
+++ b/scripts/homebrew-package-framebuffer-smoke.ts
@@ -0,0 +1,440 @@
+/**
+ * Framebuffer/device browser smoke for Kandelo Homebrew package sidecars.
+ *
+ * Sibling to homebrew-package-browser-smoke.ts, but for graphical/device
+ * programs that render through /dev/fb0 (fbdoom) or /dev/dri/card0 (modeset)
+ * rather than a terminal. It pours the Homebrew VFS for the requested package
+ * (injecting the DOOM shareware IWAD for fbdoom), boots it through
+ * BrowserKernel in headless Chromium, and observes the FramebufferRegistry for
+ * bind + pixel-write activity. A program that binds a framebuffer and pushes
+ * writes has reached the browser display path.
+ */
+import { spawn, type ChildProcess } from "node:child_process";
+import {
+ appendFileSync,
+ copyFileSync,
+ existsSync,
+ mkdirSync,
+ readFileSync,
+ rmSync,
+ writeFileSync,
+} from "node:fs";
+import { basename, dirname, join, resolve } from "node:path";
+import { fileURLToPath } from "node:url";
+import type { Browser } from "playwright";
+import { ABI_VERSION } from "../host/src/generated/abi";
+import type {
+ HomebrewBottleArch,
+ HomebrewTapMetadata,
+ HomebrewVfsPackagePlan,
+} from "../host/src/homebrew-vfs-planner";
+import {
+ countOutcomes,
+ SkipCase,
+ writeOutcomeLists,
+ type SmokeOutcome,
+} from "./homebrew-smoke-outcomes";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const repoRoot = resolve(__dirname, "..");
+const browserDemoDir = join(repoRoot, "apps", "browser-demos");
+const publicSmokeRoot = join(browserDemoDir, "public", "__kandelo-homebrew-fb-smoke");
+const publicSmokePath = "/__kandelo-homebrew-fb-smoke";
+
+interface FbSpec {
+ argv: string[];
+ device: string;
+ mode: "fb" | "kms";
+ needsWad: boolean;
+ minWrites: number;
+ description: string;
+}
+
+const FB_SPECS: Record = {
+ fbdoom: {
+ argv: ["/home/linuxbrew/.linuxbrew/bin/fbdoom", "-iwad", "/doom1.wad"],
+ device: "/dev/fb0",
+ mode: "fb",
+ needsWad: true,
+ minWrites: 1,
+ description: "fbdoom renders DOOM to /dev/fb0 from the poured Homebrew keg + shareware IWAD.",
+ },
+ modeset: {
+ argv: ["/home/linuxbrew/.linuxbrew/bin/modeset"],
+ device: "/dev/dri/card0",
+ mode: "kms",
+ needsWad: false,
+ minWrites: 1,
+ description: "modeset drives an EGL/GLES fluid sim through /dev/dri/card0 page flips.",
+ },
+};
+
+interface CliOptions {
+ resultDir: string;
+ tapRoot: string;
+ formulas: string[];
+ arch: HomebrewBottleArch;
+ bottleCache: string;
+ wadFile: string;
+ observeMs: number;
+ maxBytes: number;
+ beadId: string;
+ port: number;
+ runId: string;
+ browserChannel: string;
+}
+
+interface FbSmokeResult {
+ mode: "fb" | "kms";
+ binds: number;
+ unbinds: number;
+ writes: number;
+ writeBytes: number;
+ kmsBlits: number;
+ kmsCommits: number;
+ boundPid: number | null;
+ width: number;
+ height: number;
+ fmt: string | null;
+ canvasNonBlankPixels: number;
+ exitedEarly: boolean;
+ exitCode: number | null;
+ durationMs: number;
+ stdoutTail: string;
+ stderrTail: string;
+}
+
+function requireValue(args: string[], index: number, flag: string): string {
+ const value = args[index];
+ if (value === undefined) {
+ usage(2, `${flag} requires a value`);
+ }
+ return value;
+}
+
+function usage(code: number, message?: string): never {
+ if (message) process.stderr.write(`homebrew-package-framebuffer-smoke: ${message}\n`);
+ process.stderr.write(
+ "usage: npx tsx scripts/homebrew-package-framebuffer-smoke.ts --tap-root " +
+ "--formula [--formula ...] --arch wasm32 --result-dir " +
+ "[--bottle-cache ] [--wad-file ] [--observe-ms N] [--port N] [--bead-id ID]\n",
+ );
+ process.exit(code);
+}
+
+function parseOptions(argv: string[]): CliOptions {
+ const options: CliOptions = {
+ resultDir: "",
+ tapRoot: "",
+ formulas: [],
+ arch: "wasm32",
+ bottleCache: "",
+ wadFile: "",
+ observeMs: 12_000,
+ maxBytes: 256 * 1024 * 1024,
+ beadId: process.env.KANDELO_BEAD_ID || "kd-k3l9",
+ port: Number(process.env.KANDELO_PLAYWRIGHT_PORT ?? 5411),
+ runId: "",
+ browserChannel: process.env.KANDELO_PLAYWRIGHT_CHANNEL || "chromium",
+ };
+ for (let i = 0; i < argv.length; i += 1) {
+ const arg = argv[i];
+ switch (arg) {
+ case "--result-dir": options.resultDir = requireValue(argv, ++i, arg); break;
+ case "--tap-root": options.tapRoot = requireValue(argv, ++i, arg); break;
+ case "--formula": options.formulas.push(requireValue(argv, ++i, arg)); break;
+ case "--arch": options.arch = requireValue(argv, ++i, arg) as HomebrewBottleArch; break;
+ case "--bottle-cache": options.bottleCache = requireValue(argv, ++i, arg); break;
+ case "--wad-file": options.wadFile = requireValue(argv, ++i, arg); break;
+ case "--observe-ms": options.observeMs = Number(requireValue(argv, ++i, arg)); break;
+ case "--bead-id": options.beadId = requireValue(argv, ++i, arg); break;
+ case "--port": options.port = Number(requireValue(argv, ++i, arg)); break;
+ case "--run-id": options.runId = requireValue(argv, ++i, arg); break;
+ case "--browser-channel": options.browserChannel = requireValue(argv, ++i, arg); break;
+ case "-h": case "--help": usage(0); break;
+ default: usage(2, `unexpected argument ${arg}`);
+ }
+ }
+ if (!options.tapRoot) usage(2, "--tap-root is required");
+ if (!options.resultDir) usage(2, "--result-dir is required");
+ if (options.formulas.length === 0) usage(2, "at least one --formula is required");
+ for (const f of options.formulas) {
+ if (!(f in FB_SPECS)) usage(2, `unsupported --formula ${f}; supported: ${Object.keys(FB_SPECS).join(", ")}`);
+ }
+ if (options.arch !== "wasm32") usage(2, "framebuffer smoke only supports --arch wasm32");
+ options.resultDir = resolve(options.resultDir);
+ options.tapRoot = resolve(options.tapRoot);
+ options.bottleCache = options.bottleCache ? resolve(options.bottleCache) : join(options.resultDir, "bottle-cache");
+ if (options.wadFile) options.wadFile = resolve(options.wadFile);
+ options.runId ||= `${options.beadId}-fb-${process.pid}`;
+ return options;
+}
+
+function readJsonFile(path: string): T {
+ return JSON.parse(readFileSync(path, "utf8")) as T;
+}
+
+function createFs(
+ MemoryFileSystemCtor: { create(sab: SharedArrayBuffer, maxBytes?: number): unknown },
+ maxBytes: number,
+): unknown {
+ const SharedArrayBufferCtor = SharedArrayBuffer as new (
+ byteLength: number,
+ options?: { maxByteLength?: number },
+ ) => SharedArrayBuffer;
+ return MemoryFileSystemCtor.create(new SharedArrayBufferCtor(maxBytes, { maxByteLength: maxBytes }), maxBytes);
+}
+
+async function loadBottleBytes(pkg: HomebrewVfsPackagePlan, options: CliOptions): Promise {
+ if (pkg.url.startsWith("file://")) {
+ return new Uint8Array(readFileSync(fileURLToPath(pkg.url)));
+ }
+ const cachePath = join(options.bottleCache, `${pkg.sha256}.tar.gz`);
+ if (existsSync(cachePath)) return new Uint8Array(readFileSync(cachePath));
+ if (!pkg.url.startsWith("https://")) {
+ throw new Error(`package ${pkg.name}@${pkg.version} bottle URL must be https:// or file://, got ${pkg.url}`);
+ }
+ const { fetchHomebrewBottleBytes } = await import("../host/src/homebrew-vfs-fetch");
+ const bytes = await fetchHomebrewBottleBytes(pkg.url);
+ mkdirSync(options.bottleCache, { recursive: true });
+ writeFileSync(cachePath, bytes);
+ return bytes;
+}
+
+interface BuiltFbVfs {
+ formula: string;
+ imagePath: string;
+ publicUrl: string;
+}
+
+async function buildFormulaVfs(
+ metadata: HomebrewTapMetadata,
+ formula: string,
+ options: CliOptions,
+): Promise {
+ const [{ buildHomebrewVfs }, { planHomebrewVfs }, { MemoryFileSystem }, helpers] = await Promise.all([
+ import("../host/src/homebrew-vfs-builder"),
+ import("../host/src/homebrew-vfs-planner"),
+ import("../host/src/vfs/memory-fs"),
+ import("../images/vfs/scripts/vfs-image-helpers"),
+ ]);
+ const plan = await planHomebrewVfs(metadata, {
+ packages: [formula],
+ arch: options.arch,
+ expectedAbi: ABI_VERSION,
+ loadLinkManifest: (relPath: string) => readJsonFile(join(options.tapRoot, relPath)),
+ });
+ const fs = createFs(MemoryFileSystem as unknown as { create(sab: SharedArrayBuffer, maxBytes?: number): unknown }, options.maxBytes);
+ const result = await buildHomebrewVfs(plan, {
+ fs: fs as never,
+ createdBy: "scripts/homebrew-package-framebuffer-smoke.ts",
+ loadBottleBytes: (pkg: HomebrewVfsPackagePlan) => loadBottleBytes(pkg, options),
+ });
+
+ const spec = FB_SPECS[formula];
+ if (spec.needsWad) {
+ if (!options.wadFile || !existsSync(options.wadFile)) {
+ throw new SkipCase(`${formula} requires the DOOM shareware IWAD; pass --wad-file (fetch ${"https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad"})`);
+ }
+ const wadBytes = new Uint8Array(readFileSync(options.wadFile));
+ helpers.writeVfsBinary(fs, "/doom1.wad", wadBytes, 0o644);
+ }
+
+ const dir = join(options.resultDir, `${formula}-${options.arch}`);
+ mkdirSync(dir, { recursive: true });
+ const reportPath = join(dir, `${formula}-${options.arch}-homebrew-vfs-report.json`);
+ const imagePath = join(dir, `${formula}-${options.arch}-homebrew.vfs.zst`);
+ writeFileSync(reportPath, `${JSON.stringify({ ...result.report, image: imagePath }, null, 2)}\n`);
+ await helpers.saveImage(fs, imagePath, {
+ metadata: {
+ version: 1,
+ kernelAbi: plan.kandeloAbi,
+ createdBy: "scripts/homebrew-package-framebuffer-smoke.ts",
+ },
+ });
+
+ const publicDir = join(publicSmokeRoot, options.runId);
+ mkdirSync(publicDir, { recursive: true });
+ copyFileSync(imagePath, join(publicDir, basename(imagePath)));
+ const publicUrl = `http://127.0.0.1:${options.port}${publicSmokePath}/${encodeURIComponent(options.runId)}/${encodeURIComponent(basename(imagePath))}`;
+ return { formula, imagePath, publicUrl };
+}
+
+async function startViteServer(options: CliOptions): Promise {
+ const logPath = join(options.resultDir, "vite.log");
+ writeFileSync(logPath, "");
+ return new Promise((resolvePromise, reject) => {
+ const proc = spawn("npx", [
+ "vite", "--config", join(browserDemoDir, "vite.config.ts"),
+ "--host", "127.0.0.1", "--port", String(options.port), "--strictPort",
+ ], {
+ cwd: browserDemoDir,
+ stdio: ["ignore", "pipe", "pipe"],
+ env: {
+ ...process.env,
+ KANDELO_BROWSER_TEST_NO_HMR: "1",
+ KANDELO_BROWSER_DEMO_INPUTS: "homebrew-fb-smoke",
+ KANDELO_PLAYWRIGHT_PORT: String(options.port),
+ },
+ });
+ let started = false;
+ const timeout = setTimeout(() => {
+ if (!started) { proc.kill(); reject(new Error(`Vite did not start within 30000ms; see ${logPath}`)); }
+ }, 30_000);
+ const onData = (data: Buffer) => {
+ const text = data.toString();
+ appendFileSync(logPath, text);
+ if (!started && /Local:\s+http:\/\/127\.0\.0\.1:/.test(text)) {
+ started = true; clearTimeout(timeout); setTimeout(() => resolvePromise(proc), 500);
+ }
+ };
+ proc.stdout?.on("data", onData);
+ proc.stderr?.on("data", onData);
+ proc.on("exit", (code) => { if (!started) { clearTimeout(timeout); reject(new Error(`Vite exited with code ${code}; see ${logPath}`)); } });
+ });
+}
+
+function evaluateOutcome(formula: string, result: FbSmokeResult, screenshotBytes: number): { ok: boolean; detail: string } {
+ const spec = FB_SPECS[formula];
+ if (spec.mode === "kms") {
+ const detail = `kmsCommits=${result.kmsCommits} kmsBlits=${result.kmsBlits} ` +
+ `dims=${result.width}x${result.height} screenshotBytes=${screenshotBytes} ` +
+ `exitedEarly=${result.exitedEarly} exit=${result.exitCode ?? "-"}`;
+ // A page-flip/commit through the CRTC + a non-trivial scanout means modeset
+ // reached the browser display path via /dev/dri/card0 + WebGL2.
+ const ok = (result.kmsCommits >= 1 || result.kmsBlits >= 1) && result.width > 0 && result.height > 0;
+ return { ok, detail };
+ }
+ const detail = `binds=${result.binds} writes=${result.writes} writeBytes=${result.writeBytes} ` +
+ `dims=${result.width}x${result.height} canvasNonBlank=${result.canvasNonBlankPixels} ` +
+ `screenshotBytes=${screenshotBytes} exitedEarly=${result.exitedEarly} exit=${result.exitCode ?? "-"}`;
+ const ok = result.binds >= 1 && result.writes >= spec.minWrites && result.canvasNonBlankPixels > 0;
+ return { ok, detail };
+}
+
+async function runCase(
+ outcomes: SmokeOutcome[],
+ name: string,
+ fn: () => Promise,
+ artifactPath: string,
+): Promise {
+ const started = Date.now();
+ try {
+ const details = await fn();
+ outcomes.push({ name, status: "pass", durationMs: Date.now() - started, details, artifactPath });
+ } catch (error) {
+ const skipped = error instanceof SkipCase;
+ const message = error instanceof Error ? error.message : String(error);
+ outcomes.push({
+ name,
+ status: skipped ? "skip" : "fail",
+ durationMs: Date.now() - started,
+ details: message,
+ ...(skipped ? {} : { error: error instanceof Error ? (error.stack ?? message) : message }),
+ artifactPath,
+ });
+ }
+}
+
+async function main(): Promise {
+ const options = parseOptions(process.argv.slice(2));
+ mkdirSync(options.resultDir, { recursive: true });
+ const publicRunDir = join(publicSmokeRoot, options.runId);
+ const metadataPath = join(options.tapRoot, "Kandelo", "metadata.json");
+ const metadata = readJsonFile(metadataPath);
+ const outcomes: SmokeOutcome[] = [];
+ const resultsByFormula: Record = {};
+ const built = new Map();
+
+ try {
+ for (const formula of options.formulas) {
+ await runCase(outcomes, `homebrew_fb_vfs_build_${formula}`, async () => {
+ const b = await buildFormulaVfs(metadata, formula, options);
+ built.set(formula, b);
+ return `image=${b.imagePath}; browser_url=${b.publicUrl}`;
+ }, join(options.resultDir, `${formula}-${options.arch}`));
+ }
+
+ let vite: ChildProcess | undefined;
+ let browser: Browser | undefined;
+ await runCase(outcomes, "browser_server_start", async () => {
+ vite = await startViteServer(options);
+ const { chromium } = await import("playwright");
+ browser = await chromium.launch({ channel: options.browserChannel, headless: true });
+ return `vite=http://127.0.0.1:${options.port}`;
+ }, join(options.resultDir, "vite.log"));
+
+ try {
+ for (const formula of options.formulas) {
+ const spec = FB_SPECS[formula];
+ await runCase(outcomes, `fb_smoke_${formula}`, async () => {
+ const b = built.get(formula);
+ if (!b) throw new SkipCase(`requires successful homebrew_fb_vfs_build_${formula}`);
+ if (!browser) throw new Error("browser did not start");
+ const context = await browser.newContext();
+ const page = await context.newPage();
+ const consoleErrors: string[] = [];
+ page.on("pageerror", (err) => consoleErrors.push(err.message));
+ page.on("console", (msg) => { if (msg.type() === "error") consoleErrors.push(msg.text()); });
+ try {
+ await page.goto(`http://127.0.0.1:${options.port}/pages/homebrew-fb-smoke/`, {
+ waitUntil: "domcontentloaded",
+ timeout: 60_000,
+ });
+ await page.waitForFunction(() => (window as unknown as { __homebrewFbSmokeReady?: boolean }).__homebrewFbSmokeReady === true, undefined, { timeout: 60_000 });
+ const dir = join(options.resultDir, `${formula}-${options.arch}`);
+ // Screenshot mid-run (page.evaluate blocks until the smoke ends and
+ // tears down the canvas), captured on a timer that fires during the
+ // observation window.
+ const shotPath = join(dir, `${formula}-fb.png`);
+ const shotTimer = setTimeout(() => {
+ page.screenshot({ path: shotPath }).catch(() => {});
+ }, Math.min(options.observeMs, 8_000));
+ const result = (await page.evaluate(
+ async ({ vfsUrl, argv, observeMs, mode, crtcId }) =>
+ (window as unknown as { __runHomebrewFbSmoke: (r: unknown) => Promise }).__runHomebrewFbSmoke({ vfsUrl, argv, observeMs, mode, crtcId }),
+ { vfsUrl: b.publicUrl, argv: spec.argv, observeMs: options.observeMs, mode: spec.mode, crtcId: 1 },
+ )) as FbSmokeResult;
+ clearTimeout(shotTimer);
+ resultsByFormula[formula] = result;
+ writeFileSync(join(dir, `${formula}-fb-result.json`), `${JSON.stringify({ ...result, consoleErrors }, null, 2)}\n`);
+ const screenshotBytes = existsSync(shotPath) ? readFileSync(shotPath).length : 0;
+ const { ok, detail } = evaluateOutcome(formula, result, screenshotBytes);
+ if (!ok) {
+ throw new Error(`${formula} did not demonstrate ${spec.device} activity (${detail}); consoleErrors=${JSON.stringify(consoleErrors.slice(0, 3))}`);
+ }
+ return `${detail}; device=${spec.device}`;
+ } finally {
+ await context.close().catch(() => {});
+ }
+ }, join(options.resultDir, `${formula}-${options.arch}`, `${formula}-fb-result.json`));
+ }
+ } finally {
+ await browser?.close().catch(() => {});
+ if (vite) { vite.kill("SIGTERM"); }
+ }
+ } finally {
+ rmSync(publicRunDir, { recursive: true, force: true });
+ }
+
+ const counts = countOutcomes(outcomes);
+ const summary = {
+ suite: "Homebrew package framebuffer/device browser smoke",
+ bead_id: options.beadId,
+ arch: options.arch,
+ tap_root: options.tapRoot,
+ formulas: options.formulas,
+ counts,
+ outcomes,
+ results: resultsByFormula,
+ };
+ writeFileSync(join(options.resultDir, "summary.json"), `${JSON.stringify(summary, null, 2)}\n`);
+ writeOutcomeLists(options.resultDir, outcomes, { includeArtifactPath: true });
+ process.stdout.write(`framebuffer smoke: ${counts.pass} pass, ${counts.fail} fail, ${counts.skip} skip\n`);
+ if (counts.fail > 0) process.exitCode = 1;
+}
+
+main().catch((err) => {
+ process.stderr.write(`${err instanceof Error ? (err.stack ?? err.message) : String(err)}\n`);
+ process.exit(1);
+});
diff --git a/scripts/homebrew-package-node-smoke.ts b/scripts/homebrew-package-node-smoke.ts
new file mode 100644
index 000000000..2495d8962
--- /dev/null
+++ b/scripts/homebrew-package-node-smoke.ts
@@ -0,0 +1,736 @@
+/**
+ * Node-side smoke coverage for Kandelo Homebrew package sidecars.
+ *
+ * The runner consumes generated Kandelo/Homebrew sidecars, materializes each
+ * requested package into a VFS, and runs a package-specific smoke through
+ * NodeKernelHost. Program packages execute their poured binary. SQLite
+ * compiles a test-only consumer from the poured headers and static library.
+ */
+import { execFileSync } from "node:child_process";
+import {
+ existsSync,
+ mkdirSync,
+ readFileSync,
+ renameSync,
+ rmSync,
+ writeFileSync,
+} from "node:fs";
+import { dirname, join, resolve } from "node:path";
+import { fileURLToPath } from "node:url";
+import { ABI_VERSION } from "../host/src/generated/abi";
+import { fetchHomebrewBottleBytes } from "../host/src/homebrew-vfs-fetch";
+import { buildHomebrewVfs } from "../host/src/homebrew-vfs-builder";
+import {
+ planHomebrewVfs,
+ type HomebrewBottleArch,
+ type HomebrewTapMetadata,
+ type HomebrewVfsPackagePlan,
+} from "../host/src/homebrew-vfs-planner";
+import { NodeKernelHost } from "../host/src/node-kernel-host";
+import { MemoryFileSystem } from "../host/src/vfs/memory-fs";
+import { saveImage } from "../images/vfs/scripts/vfs-image-helpers";
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const repoRoot = resolve(__dirname, "..");
+const PREFIX = "/home/linuxbrew/.linuxbrew";
+const CELLAR = `${PREFIX}/Cellar`;
+
+type OutcomeStatus = "pass" | "fail" | "skip";
+type FormulaName = string;
+
+interface ProgramSmokeSpec {
+ argv0: string;
+ guestPath: string;
+ args: string[];
+ expected: RegExp;
+ description?: string;
+}
+
+const PROGRAM_SMOKES: Record = {
+ bzip2: {
+ argv0: "bzip2",
+ guestPath: `${PREFIX}/bin/bzip2`,
+ args: ["--help"],
+ expected: /bzip2/i,
+ },
+ dash: {
+ argv0: "dash",
+ guestPath: `${PREFIX}/bin/dash`,
+ args: ["-c", "echo dash-homebrew-smoke"],
+ expected: /dash-homebrew-smoke/,
+ description: "dash -c executed a shell command",
+ },
+ git: {
+ argv0: "git",
+ guestPath: `${PREFIX}/bin/git`,
+ args: ["--version"],
+ expected: /git version/i,
+ },
+ less: {
+ argv0: "less",
+ guestPath: `${PREFIX}/bin/less`,
+ args: ["--version"],
+ expected: /less/i,
+ },
+ lsof: {
+ argv0: "lsof",
+ guestPath: `${PREFIX}/bin/lsof`,
+ args: [],
+ expected: /COMMAND|PID|lsof/i,
+ description: "lsof enumerated visible process file descriptors",
+ },
+ msmtpd: {
+ argv0: "msmtpd",
+ guestPath: `${PREFIX}/bin/msmtpd`,
+ args: ["--version"],
+ expected: /msmtp|msmtpd/i,
+ },
+ nano: {
+ argv0: "nano",
+ guestPath: `${PREFIX}/bin/nano`,
+ args: ["--version"],
+ expected: /GNU nano|nano/i,
+ },
+ netcat: {
+ argv0: "nc",
+ guestPath: `${PREFIX}/bin/nc`,
+ args: ["--help"],
+ expected: /netcat|listen|connect|usage/i,
+ description: "nc help path exercised the network CLI binary",
+ },
+ vim: {
+ argv0: "vim",
+ guestPath: `${PREFIX}/bin/vim`,
+ args: ["--version"],
+ expected: /VIM|Vi IMproved/i,
+ },
+ wget: {
+ argv0: "wget",
+ guestPath: `${PREFIX}/bin/wget`,
+ args: ["--version"],
+ expected: /GNU Wget|Wget/i,
+ },
+ xz: {
+ argv0: "xz",
+ guestPath: `${PREFIX}/bin/xz`,
+ args: ["--version"],
+ expected: /xz/i,
+ },
+};
+
+interface CliOptions {
+ resultDir: string;
+ tapRoot: string;
+ formulas: FormulaName[];
+ arch: HomebrewBottleArch;
+ bottleCache: string;
+ timeoutMs: number;
+ maxBytes: number;
+ beadId: string;
+}
+
+interface Outcome {
+ name: string;
+ status: OutcomeStatus;
+ durationMs: number;
+ details?: string;
+ error?: string;
+}
+
+interface BuiltVfs {
+ fs: MemoryFileSystem;
+ imageBytes: Uint8Array;
+ reportPath: string;
+}
+
+class SkipCase extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "SkipCase";
+ }
+}
+
+async function main(): Promise {
+ const options = parseArgs(process.argv.slice(2));
+ mkdirSync(options.resultDir, { recursive: true });
+ mkdirSync(join(options.resultDir, "outcome-lists"), { recursive: true });
+ mkdirSync(options.bottleCache, { recursive: true });
+
+ const metadataPath = join(options.tapRoot, "Kandelo", "metadata.json");
+ const metadata = readJsonFile(metadataPath);
+ const tapCommit = gitRevParse(options.tapRoot);
+ const startedAt = new Date();
+ const outcomes: Outcome[] = [];
+
+ writeCurrentRun(options, {
+ status: "running",
+ startedAt,
+ tapCommit,
+ outcomes,
+ currentCase: "startup",
+ });
+
+ const builtByFormula = new Map();
+ for (const formula of options.formulas) {
+ await runCase(outcomes, options, tapCommit, `homebrew_vfs_build_${formula}`, async () => {
+ const built = await buildFormulaVfs(metadata, formula, options);
+ builtByFormula.set(formula, built);
+ return `report=${built.reportPath}`;
+ });
+
+ await runCase(outcomes, options, tapCommit, `node_smoke_${formula}`, async () => {
+ const built = builtByFormula.get(formula);
+ if (!built) throw new SkipCase(`requires successful homebrew_vfs_build_${formula}`);
+ return await runFormulaSmoke(formula, built, options);
+ });
+ }
+
+ writeOutcomeLists(options.resultDir, outcomes);
+ writeSummary(options, {
+ startedAt,
+ completedAt: new Date(),
+ tapCommit,
+ outcomes,
+ });
+ writeCurrentRun(options, {
+ status: outcomes.some((outcome) => outcome.status === "fail") ? "failed" : "complete",
+ startedAt,
+ tapCommit,
+ outcomes,
+ currentCase: "complete",
+ });
+
+ process.exit(outcomes.some((outcome) => outcome.status === "fail") ? 1 : 0);
+}
+
+async function buildFormulaVfs(
+ metadata: HomebrewTapMetadata,
+ formula: FormulaName,
+ options: CliOptions,
+): Promise {
+ const plan = await planHomebrewVfs(metadata, {
+ packages: [formula],
+ arch: options.arch,
+ runtime: "node",
+ expectedAbi: ABI_VERSION,
+ loadLinkManifest: (relPath) => readJsonFile(join(options.tapRoot, relPath)),
+ });
+ const fs = createFs(options.maxBytes);
+ const result = await buildHomebrewVfs(plan, {
+ fs,
+ createdBy: "scripts/homebrew-package-node-smoke.ts",
+ loadBottleBytes: (pkg) => loadBottleBytes(pkg, options),
+ });
+
+ const reportPath = join(options.resultDir, `${formula}-${options.arch}-homebrew-vfs-report.json`);
+ writeFileSync(reportPath, `${JSON.stringify(result.report, null, 2)}\n`);
+ const imagePath = join(options.resultDir, `${formula}-${options.arch}-homebrew.vfs.zst`);
+ const imageBytes = await saveImage(fs, imagePath, {
+ metadata: {
+ version: 1,
+ kernelAbi: plan.kandeloAbi,
+ createdBy: "scripts/homebrew-package-node-smoke.ts",
+ homebrew: {
+ tapRepository: plan.tapRepository,
+ tapCommit: plan.tapCommit,
+ releaseTag: plan.releaseTag,
+ packages: plan.packages.map((pkg) => ({
+ name: pkg.name,
+ version: pkg.version,
+ arch: pkg.arch,
+ sourceStatus: pkg.sourceStatus,
+ cacheKeySha: pkg.cacheKeySha,
+ })),
+ },
+ },
+ });
+ return { fs, imageBytes, reportPath };
+}
+
+async function runFormulaSmoke(
+ formula: FormulaName,
+ built: BuiltVfs,
+ options: CliOptions,
+): Promise {
+ switch (formula) {
+ case "sqlite":
+ return runSqliteSmoke(built, options);
+ case "fbdoom":
+ throw new SkipCase(
+ "fbdoom requires IWAD data and framebuffer/audio device plumbing; record browser framebuffer smoke separately",
+ );
+ case "modeset":
+ throw new SkipCase(
+ "modeset requires DRI/GLES framebuffer device support; record browser/device smoke separately",
+ );
+ default: {
+ const spec = PROGRAM_SMOKES[formula];
+ if (!spec) throw new SkipCase(`no Node smoke is defined for formula ${formula}`);
+ return runProgramSmoke(spec, built, options);
+ }
+ }
+}
+
+async function runProgramSmoke(
+ spec: ProgramSmokeSpec,
+ built: BuiltVfs,
+ options: CliOptions,
+): Promise {
+ const programBytes = readVfsFile(built.fs, spec.guestPath);
+ const result = await runWasm(programBytes, [spec.argv0, ...spec.args], built.imageBytes, options);
+ if (result.exitCode !== 0) {
+ throw new Error(
+ `${spec.argv0} ${spec.args.join(" ")} exited ${result.exitCode}; stderr=${JSON.stringify(result.stderr)}`,
+ );
+ }
+ const combined = `${result.stdout}\n${result.stderr}`;
+ if (!spec.expected.test(combined)) {
+ throw new Error(
+ `unexpected ${spec.argv0} ${spec.args.join(" ")} output: ${JSON.stringify(combined)}`,
+ );
+ }
+ return spec.description
+ ?? combined.trim().split("\n").find((line) => line.trim() !== "")
+ ?? `${spec.argv0} ${spec.args.join(" ")} passed`;
+}
+
+async function runSqliteSmoke(built: BuiltVfs, options: CliOptions): Promise {
+ const stage = join(options.resultDir, "sqlite-consumer-build", options.arch);
+ rmSync(stage, { recursive: true, force: true });
+ mkdirSync(join(stage, "include"), { recursive: true });
+ mkdirSync(join(stage, "lib"), { recursive: true });
+
+ const version = findPackageVersion(built.fs, "sqlite");
+ writeFileSync(
+ join(stage, "include", "sqlite3.h"),
+ readVfsFile(built.fs, `${CELLAR}/sqlite/${version}/include/sqlite3.h`),
+ );
+ writeFileSync(
+ join(stage, "include", "sqlite3ext.h"),
+ readVfsFile(built.fs, `${CELLAR}/sqlite/${version}/include/sqlite3ext.h`),
+ );
+ writeFileSync(
+ join(stage, "lib", "libsqlite3.a"),
+ readVfsFile(built.fs, `${CELLAR}/sqlite/${version}/lib/libsqlite3.a`),
+ );
+
+ const testSrc = join(repoRoot, "packages", "registry", "sqlite", "test", "sqlite_basic.c");
+ const outWasm = join(stage, "sqlite_basic.wasm");
+ const cc = join(repoRoot, "sdk", "bin", `${options.arch}posix-cc`);
+ execFileSync(cc, [
+ `-I${join(stage, "include")}`,
+ testSrc,
+ join(stage, "lib", "libsqlite3.a"),
+ "-lm",
+ "-o",
+ outWasm,
+ ], {
+ cwd: repoRoot,
+ env: {
+ ...process.env,
+ PATH: `${join(repoRoot, "sdk", "bin")}:${process.env.PATH ?? ""}`,
+ WASM_POSIX_SYSROOT: join(repoRoot, options.arch === "wasm64" ? "sysroot64" : "sysroot"),
+ },
+ stdio: "pipe",
+ });
+
+ const consumerBytes = new Uint8Array(readFileSync(outWasm));
+ const result = await runWasm(consumerBytes, ["sqlite_basic"], built.imageBytes, options);
+ if (result.exitCode !== 0) {
+ throw new Error(`sqlite_basic exited ${result.exitCode}; stderr=${JSON.stringify(result.stderr)}`);
+ }
+ if (!result.stdout.includes("PASS")) {
+ throw new Error(`sqlite_basic did not report PASS: ${JSON.stringify(result.stdout)}`);
+ }
+ return "sqlite_basic linked against poured sqlite keg and reported PASS";
+}
+
+async function runWasm(
+ programBytes: Uint8Array,
+ argv: string[],
+ rootfsImage: Uint8Array,
+ options: CliOptions,
+): Promise<{ exitCode: number; stdout: string; stderr: string }> {
+ let stdout = "";
+ let stderr = "";
+ const host = new NodeKernelHost({
+ maxWorkers: 4,
+ rootfsImage,
+ onStdout: (_pid, data) => { stdout += new TextDecoder().decode(data); },
+ onStderr: (_pid, data) => { stderr += new TextDecoder().decode(data); },
+ });
+ await host.init();
+ let timeout: ReturnType | undefined;
+ try {
+ const exitPromise = host.spawn(toArrayBuffer(programBytes), argv, {
+ env: [
+ "PATH=/home/linuxbrew/.linuxbrew/bin:/usr/bin:/bin",
+ "HOME=/tmp",
+ "TMPDIR=/tmp",
+ ],
+ cwd: "/",
+ stdin: new Uint8Array(),
+ });
+ const timeoutPromise = new Promise((_, reject) => {
+ timeout = setTimeout(
+ () => reject(new Error(`${argv[0]} timed out after ${options.timeoutMs}ms`)),
+ options.timeoutMs,
+ );
+ });
+ const exitCode = await Promise.race([exitPromise, timeoutPromise]);
+ return { exitCode, stdout, stderr };
+ } finally {
+ if (timeout) clearTimeout(timeout);
+ await host.destroy().catch(() => {});
+ }
+}
+
+async function runCase(
+ outcomes: Outcome[],
+ options: CliOptions,
+ tapCommit: string,
+ name: string,
+ fn: () => Promise,
+): Promise {
+ writeCurrentRun(options, {
+ status: "running",
+ tapCommit,
+ outcomes,
+ currentCase: name,
+ });
+ const started = Date.now();
+ try {
+ const details = await fn();
+ outcomes.push({ name, status: "pass", durationMs: Date.now() - started, details });
+ } catch (err) {
+ const error = err instanceof Error ? err : new Error(String(err));
+ outcomes.push({
+ name,
+ status: error instanceof SkipCase ? "skip" : "fail",
+ durationMs: Date.now() - started,
+ details: error.message,
+ error: error.stack ?? error.message,
+ });
+ }
+ writeOutcomeLists(options.resultDir, outcomes);
+}
+
+async function loadBottleBytes(
+ pkg: HomebrewVfsPackagePlan,
+ options: CliOptions,
+): Promise {
+ if (pkg.url.startsWith("file://")) {
+ return new Uint8Array(readFileSync(fileURLToPath(pkg.url)));
+ }
+
+ const cachePath = join(options.bottleCache, `${pkg.sha256}.tar.gz`);
+ if (existsSync(cachePath)) return new Uint8Array(readFileSync(cachePath));
+ if (!pkg.url.startsWith("https://")) {
+ throw new Error(
+ `package ${pkg.name}@${pkg.version} bottle URL must be https:// or file://, got ${pkg.url}`,
+ );
+ }
+
+ const bytes = await fetchHomebrewBottleBytes(pkg.url);
+ writeFileSync(cachePath, bytes);
+ return bytes;
+}
+
+function findPackageVersion(fs: MemoryFileSystem, formula: string): string {
+ const info = JSON.parse(new TextDecoder().decode(readVfsFile(fs, "/etc/kandelo/homebrew-vfs.json")));
+ const pkg = info.packages?.find((candidate: { name?: string }) => candidate.name === formula);
+ if (!pkg) throw new Error(`package ${formula} missing from /etc/kandelo/homebrew-vfs.json`);
+ const keg = String(pkg.keg ?? "");
+ const prefix = `${CELLAR}/${formula}/`;
+ if (!keg.startsWith(prefix)) throw new Error(`unexpected sqlite keg path: ${keg}`);
+ return keg.slice(prefix.length);
+}
+
+function readVfsFile(fs: MemoryFileSystem, path: string): Uint8Array {
+ const st = fs.stat(path);
+ const fd = fs.open(path, 0, 0);
+ try {
+ const out = new Uint8Array(st.size);
+ let offset = 0;
+ while (offset < out.byteLength) {
+ const n = fs.read(fd, out.subarray(offset), null, out.byteLength - offset);
+ if (n <= 0) break;
+ offset += n;
+ }
+ return out.subarray(0, offset);
+ } finally {
+ fs.close(fd);
+ }
+}
+
+function createFs(maxBytes: number): MemoryFileSystem {
+ const SharedArrayBufferCtor = SharedArrayBuffer as new (
+ byteLength: number,
+ options?: { maxByteLength?: number },
+ ) => SharedArrayBuffer;
+ return MemoryFileSystem.create(
+ new SharedArrayBufferCtor(maxBytes, { maxByteLength: maxBytes }),
+ maxBytes,
+ );
+}
+
+function parseArgs(args: string[]): CliOptions {
+ const defaultResultDir = join(
+ repoRoot,
+ "test-runs",
+ "homebrew-package-node-smoke",
+ new Date().toISOString().replace(/[-:]/g, "").replace(/\..+$/, "Z"),
+ );
+ const options: CliOptions = {
+ resultDir: process.env.KANDELO_TEST_RESULT_DIR || defaultResultDir,
+ tapRoot: process.env.KANDELO_HOMEBREW_TAP_ROOT || "",
+ formulas: [],
+ arch: "wasm32",
+ bottleCache: "",
+ timeoutMs: 30_000,
+ maxBytes: 128 * 1024 * 1024,
+ beadId: process.env.KANDELO_BEAD_ID || "kd-1mr.2",
+ };
+
+ for (let i = 0; i < args.length; i += 1) {
+ const arg = args[i];
+ switch (arg) {
+ case "--result-dir":
+ options.resultDir = requireValue(args, ++i, arg);
+ break;
+ case "--tap-root":
+ options.tapRoot = requireValue(args, ++i, arg);
+ break;
+ case "--formula":
+ options.formulas.push(parseFormula(requireValue(args, ++i, arg)));
+ break;
+ case "--arch":
+ options.arch = parseArch(requireValue(args, ++i, arg));
+ break;
+ case "--bottle-cache":
+ options.bottleCache = requireValue(args, ++i, arg);
+ break;
+ case "--timeout-ms":
+ options.timeoutMs = parsePositiveInt(requireValue(args, ++i, arg), arg);
+ break;
+ case "--max-bytes":
+ options.maxBytes = parseByteSize(requireValue(args, ++i, arg));
+ break;
+ case "--bead-id":
+ options.beadId = requireValue(args, ++i, arg);
+ break;
+ case "--help":
+ case "-h":
+ usage(0);
+ break;
+ default:
+ usage(2, `unexpected argument ${arg}`);
+ }
+ }
+
+ if (!options.tapRoot) usage(2, "--tap-root is required");
+ if (options.formulas.length === 0) usage(2, "at least one --formula is required");
+ options.resultDir = resolve(options.resultDir);
+ options.tapRoot = resolve(options.tapRoot);
+ options.bottleCache = options.bottleCache
+ ? resolve(options.bottleCache)
+ : join(options.resultDir, "bottle-cache");
+ return options;
+}
+
+function parseFormula(value: string): FormulaName {
+ if (/^[a-z0-9][a-z0-9._-]*$/.test(value)) return value;
+ usage(2, `invalid --formula ${value}`);
+}
+
+function parseArch(value: string): HomebrewBottleArch {
+ if (value === "wasm32" || value === "wasm64") return value;
+ usage(2, `--arch must be wasm32 or wasm64, got ${value}`);
+}
+
+function parsePositiveInt(value: string, flag: string): number {
+ const parsed = Number(value);
+ if (!Number.isInteger(parsed) || parsed <= 0) usage(2, `${flag} must be a positive integer`);
+ return parsed;
+}
+
+function parseByteSize(value: string): number {
+ const match = /^([1-9][0-9]*)([kKmMgG]i?[bB]?|[bB])?$/.exec(value);
+ if (!match) usage(2, `--max-bytes must be a positive byte size, got ${value}`);
+ const amount = Number(match[1]);
+ const suffix = (match[2] ?? "b").toLowerCase();
+ const multiplier = suffix.startsWith("g") ? 1024 ** 3
+ : suffix.startsWith("m") ? 1024 ** 2
+ : suffix.startsWith("k") ? 1024
+ : 1;
+ return amount * multiplier;
+}
+
+function requireValue(args: string[], index: number, flag: string): string {
+ const value = args[index];
+ if (!value || value.startsWith("--")) usage(2, `${flag} requires a value`);
+ return value;
+}
+
+function usage(code: number, message?: string): never {
+ if (message) console.error(`homebrew-package-node-smoke: ${message}`);
+ console.error(`usage: npx tsx scripts/homebrew-package-node-smoke.ts \\
+ --tap-root --formula [--formula ...] \\
+ [--arch ] [--result-dir ] [--bottle-cache ]`);
+ process.exit(code);
+}
+
+function writeOutcomeLists(resultDir: string, outcomes: Outcome[]): void {
+ const listsDir = join(resultDir, "outcome-lists");
+ mkdirSync(listsDir, { recursive: true });
+ const passed = outcomes.filter((outcome) => outcome.status === "pass");
+ const failed = outcomes.filter((outcome) => outcome.status === "fail");
+ const skipped = outcomes.filter((outcome) => outcome.status === "skip");
+ writeFileSync(
+ join(listsDir, "passed-tests.tsv"),
+ ["test\tduration_ms\tdetails", ...passed.map((outcome) =>
+ `${outcome.name}\t${outcome.durationMs}\t${tsv(outcome.details ?? "")}`,
+ )].join("\n") + "\n",
+ );
+ writeFileSync(
+ join(listsDir, "failed-tests.tsv"),
+ ["test\tduration_ms\terror", ...failed.map((outcome) =>
+ `${outcome.name}\t${outcome.durationMs}\t${tsv(outcome.error ?? outcome.details ?? "")}`,
+ )].join("\n") + "\n",
+ );
+ writeFileSync(
+ join(listsDir, "skipped-tests.tsv"),
+ ["test\treason", ...skipped.map((outcome) =>
+ `${outcome.name}\t${tsv(outcome.details ?? "")}`,
+ )].join("\n") + "\n",
+ );
+ writeFileSync(join(resultDir, "failures.json"), `${JSON.stringify(failed, null, 2)}\n`);
+}
+
+function writeSummary(
+ options: CliOptions,
+ data: {
+ startedAt: Date;
+ completedAt: Date;
+ tapCommit: string;
+ outcomes: Outcome[];
+ },
+): void {
+ const counts = countOutcomes(data.outcomes);
+ const summary = {
+ suite: "Homebrew package Node VFS smoke",
+ bead_id: options.beadId,
+ started_at: data.startedAt.toISOString(),
+ completed_at: data.completedAt.toISOString(),
+ duration_ms: data.completedAt.getTime() - data.startedAt.getTime(),
+ result_dir: options.resultDir,
+ tap_root: options.tapRoot,
+ tap_commit: data.tapCommit,
+ arch: options.arch,
+ formulas: options.formulas,
+ counts,
+ outcomes: data.outcomes,
+ artifacts: {
+ passed: join(options.resultDir, "outcome-lists", "passed-tests.tsv"),
+ failed: join(options.resultDir, "outcome-lists", "failed-tests.tsv"),
+ skipped: join(options.resultDir, "outcome-lists", "skipped-tests.tsv"),
+ failures: join(options.resultDir, "failures.json"),
+ current_run: join(options.resultDir, "current-run.json"),
+ },
+ };
+ writeFileSync(join(options.resultDir, "summary.json"), `${JSON.stringify(summary, null, 2)}\n`);
+ writeFileSync(join(options.resultDir, "summary.md"), [
+ "# Homebrew package Node VFS smoke",
+ "",
+ `Result dir: \`${options.resultDir}\``,
+ `Tap commit: \`${data.tapCommit}\``,
+ `Counts: ${counts.pass} pass, ${counts.fail} fail, ${counts.skip} skip`,
+ "",
+ "| Test | Status | Details |",
+ "|---|---:|---|",
+ ...data.outcomes.map((outcome) =>
+ `| \`${outcome.name}\` | ${outcome.status} | ${outcome.details ? outcome.details.replace(/\|/g, "\\|") : ""} |`,
+ ),
+ "",
+ ].join("\n"));
+}
+
+function writeCurrentRun(
+ options: CliOptions,
+ data: {
+ status: "running" | "complete" | "failed";
+ startedAt?: Date;
+ tapCommit: string;
+ outcomes: Outcome[];
+ currentCase: string;
+ },
+): void {
+ const counts = countOutcomes(data.outcomes);
+ const currentRun = {
+ suite: "homebrew-package-node-smoke",
+ bead_id: options.beadId,
+ worktree: repoRoot,
+ result_dir: options.resultDir,
+ status: data.status,
+ started_at: data.startedAt?.toISOString(),
+ updated_at: new Date().toISOString(),
+ current_case: data.currentCase,
+ progress: {
+ completed: data.outcomes.length,
+ total: options.formulas.length * 2,
+ pass: counts.pass,
+ fail: counts.fail,
+ skip: counts.skip,
+ },
+ tap_root: options.tapRoot,
+ tap_commit: data.tapCommit,
+ command: {
+ cwd: repoRoot,
+ argv: process.argv,
+ },
+ outcome_lists: {
+ passed: join(options.resultDir, "outcome-lists", "passed-tests.tsv"),
+ failed: join(options.resultDir, "outcome-lists", "failed-tests.tsv"),
+ skipped: join(options.resultDir, "outcome-lists", "skipped-tests.tsv"),
+ },
+ stale_no_runner_threshold_seconds: 600,
+ expected_next: data.status === "running"
+ ? { deterministic: true, action: "continue current smoke case" }
+ : { deterministic: false, action: "suite terminal" },
+ };
+ const out = join(options.resultDir, "current-run.json");
+ const tmp = `${out}.tmp`;
+ writeFileSync(tmp, `${JSON.stringify(currentRun, null, 2)}\n`);
+ renameSync(tmp, out);
+}
+
+function countOutcomes(outcomes: Outcome[]): { pass: number; fail: number; skip: number } {
+ return {
+ pass: outcomes.filter((outcome) => outcome.status === "pass").length,
+ fail: outcomes.filter((outcome) => outcome.status === "fail").length,
+ skip: outcomes.filter((outcome) => outcome.status === "skip").length,
+ };
+}
+
+function readJsonFile(path: string): T {
+ return JSON.parse(readFileSync(path, "utf8")) as T;
+}
+
+function gitRevParse(path: string): string {
+ return execFileSync("git", ["-C", path, "rev-parse", "HEAD"], {
+ encoding: "utf8",
+ }).trim();
+}
+
+function toArrayBuffer(bytes: Uint8Array): ArrayBuffer {
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;
+}
+
+function tsv(value: string): string {
+ return value.replace(/\t/g, " ").replace(/\r?\n/g, "\\n");
+}
+
+main().catch((err) => {
+ console.error(err);
+ process.exit(1);
+});
diff --git a/scripts/homebrew-package-smoke-cases.ts b/scripts/homebrew-package-smoke-cases.ts
new file mode 100644
index 000000000..31442958a
--- /dev/null
+++ b/scripts/homebrew-package-smoke-cases.ts
@@ -0,0 +1,264 @@
+import type { HomebrewBottleArch } from "../host/src/homebrew-vfs-planner";
+
+export const HOMEBREW_PREFIX = "/home/linuxbrew/.linuxbrew";
+export const HOMEBREW_CELLAR = `${HOMEBREW_PREFIX}/Cellar`;
+export const SQLITE_BROWSER_CONSUMER_PATH = "/usr/local/kandelo-smoke/bin/sqlite_basic";
+
+export type HomebrewSmokeFormula = string;
+
+export interface BrowserSmokeCase {
+ name: string;
+ formula: HomebrewSmokeFormula;
+ required: boolean;
+ command: string;
+ argv: string[];
+ stdin?: string;
+ env?: string[];
+ expected: RegExp;
+ description: string;
+}
+
+export function parseHomebrewSmokeFormula(value: string): HomebrewSmokeFormula {
+ if (/^[a-z0-9][a-z0-9._-]*$/.test(value)) return value;
+ throw new Error(`formula must be a Homebrew package name, got ${value}`);
+}
+
+export function browserUnsupportedReason(arch: HomebrewBottleArch): string | undefined {
+ return arch === "wasm64"
+ ? "wasm64 browser compatibility is unsupported by the current Homebrew browser sidecar path"
+ : undefined;
+}
+
+/**
+ * Formulae that cannot be certified through the non-interactive terminal
+ * Homebrew browser smoke because they require framebuffer/DRI device plumbing
+ * and (for fbdoom) game data. These mirror the Node smoke's framebuffer skips
+ * (kd-v3fs vim-node-smoke) and should be certified via a dedicated browser
+ * framebuffer/device smoke harness, not this one.
+ */
+export function browserFormulaUnsupportedReason(
+ formula: HomebrewSmokeFormula,
+): string | undefined {
+ switch (formula) {
+ case "modeset":
+ return "modeset requires a DRI/GLES framebuffer device (/dev/dri) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer/device smoke";
+ case "fbdoom":
+ return "fbdoom requires IWAD game data and a framebuffer/audio device (/dev/fb0) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer smoke";
+ default:
+ return undefined;
+ }
+}
+
+export function browserSmokeCasesForFormula(formula: HomebrewSmokeFormula): BrowserSmokeCase[] {
+ switch (formula) {
+ case "hello":
+ return [programOutputCase({
+ formula,
+ name: "hello_version",
+ argv: [`${HOMEBREW_PREFIX}/bin/hello`, "--version"],
+ expected: /hello/i,
+ description: "Run hello --version from the poured Homebrew prefix.",
+ })];
+ case "bc":
+ return [programOutputCase({
+ formula,
+ name: "bc_expression",
+ argv: [`${HOMEBREW_PREFIX}/bin/bc`],
+ stdin: "2+3\nquit\n",
+ expected: /(^|\n)5(\n|$)/,
+ description: "Run a simple bc expression from the poured Homebrew prefix.",
+ })];
+ case "bzip2":
+ return [programOutputCase({
+ formula,
+ name: "bzip2_help",
+ argv: [`${HOMEBREW_PREFIX}/bin/bzip2`, "--help"],
+ expected: /bzip2/i,
+ description: "Run bzip2 --help from the poured Homebrew prefix.",
+ })];
+ case "coreutils":
+ return [programOutputCase({
+ formula,
+ name: "coreutils_printf",
+ argv: [`${HOMEBREW_PREFIX}/bin/coreutils`, "--coreutils-prog=printf", "ok\n"],
+ expected: /^ok$/m,
+ description: "Run coreutils printf through the multicall binary.",
+ })];
+ case "diffutils":
+ return [programVersionCase(formula, "diff", /diff/i)];
+ case "file":
+ return [programVersionCase(formula, "file", /file/i)];
+ case "findutils":
+ return [programVersionCase(formula, "find", /find/i)];
+ case "gawk":
+ return [programOutputCase({
+ formula,
+ name: "gawk_begin",
+ argv: [`${HOMEBREW_PREFIX}/bin/gawk`, "BEGIN { print 6 * 7 }"],
+ expected: /^42$/m,
+ description: "Run a BEGIN expression through gawk.",
+ })];
+ case "grep":
+ return [programOutputCase({
+ formula,
+ name: "grep_stdin",
+ argv: [`${HOMEBREW_PREFIX}/bin/grep`, "beta"],
+ stdin: "alpha\nbeta\n",
+ expected: /^beta$/m,
+ description: "Run grep against stdin.",
+ })];
+ case "gzip":
+ return [programVersionCase(formula, "gzip", /gzip/i)];
+ case "m4":
+ return [programOutputCase({
+ formula,
+ name: "m4_stdin",
+ argv: [`${HOMEBREW_PREFIX}/bin/m4`],
+ stdin: "define(`x',`ok')x\n",
+ expected: /ok/,
+ description: "Run an m4 definition against stdin.",
+ })];
+ case "make":
+ return [programVersionCase(formula, "make", /make/i)];
+ case "posix-utils-lite":
+ return [programOutputCase({
+ formula,
+ name: "patch_scan",
+ argv: [`${HOMEBREW_PREFIX}/bin/patch`, "patch"],
+ stdin: "--- a/file\n+++ b/file\n",
+ expected: /patching file file/,
+ description: "Run the posix-utils-lite patch applet against unified patch metadata.",
+ })];
+ case "sed":
+ return [programOutputCase({
+ formula,
+ name: "sed_substitute",
+ argv: [`${HOMEBREW_PREFIX}/bin/sed`, "s/a/b/"],
+ stdin: "a\n",
+ expected: /^b$/m,
+ description: "Run a sed substitution against stdin.",
+ })];
+ case "tar":
+ return [programVersionCase(formula, "tar", /tar/i)];
+ case "tcl":
+ return [programOutputCase({
+ formula,
+ name: "tcl_expr",
+ argv: [`${HOMEBREW_PREFIX}/bin/tcl`],
+ stdin: "puts [expr {2 + 5}]\n",
+ env: [`TCL_LIBRARY=${HOMEBREW_PREFIX}/lib/tcl8.6`],
+ expected: /^7$/m,
+ description: "Run a Tcl expression using the poured Tcl runtime library.",
+ })];
+ case "unzip":
+ return [programOutputCase({
+ formula,
+ name: "unzip_version",
+ argv: [`${HOMEBREW_PREFIX}/bin/unzip`, "-v"],
+ expected: /unzip/i,
+ description: "Run unzip -v from the poured Homebrew prefix.",
+ })];
+ case "xz":
+ return [programOutputCase({
+ formula,
+ name: "xz_version",
+ argv: [`${HOMEBREW_PREFIX}/bin/xz`, "--version"],
+ expected: /xz/i,
+ description: "Run xz --version from the poured Homebrew prefix.",
+ })];
+ case "zip":
+ return [programOutputCase({
+ formula,
+ name: "zip_version",
+ argv: [`${HOMEBREW_PREFIX}/bin/zip`, "-v"],
+ expected: /zip/i,
+ description: "Run zip -v from the poured Homebrew prefix.",
+ })];
+ case "zstd":
+ return [programVersionCase(formula, "zstd", /zstandard|zstd/i)];
+ case "sqlite":
+ return [{
+ name: "sqlite_basic_consumer",
+ formula,
+ required: true,
+ command: SQLITE_BROWSER_CONSUMER_PATH,
+ argv: [SQLITE_BROWSER_CONSUMER_PATH],
+ expected: /PASS/,
+ description: "Run sqlite_basic linked against the poured sqlite keg.",
+ }];
+ case "dash":
+ // dash is a POSIX shell; `--version` is an illegal option. Exercise the
+ // shell by running a command instead.
+ return [programOutputCase({
+ formula,
+ name: "dash_command",
+ argv: [`${HOMEBREW_PREFIX}/bin/dash`, "-c", "echo dash_browser_smoke_ok"],
+ expected: /dash_browser_smoke_ok/,
+ description: "Run a command through dash from the poured Homebrew prefix.",
+ })];
+ case "lsof":
+ // Kandelo's lsof (examples/lsof.c) has no version flag; `-h` prints usage and exits 0.
+ return [programOutputCase({
+ formula,
+ name: "lsof_help",
+ argv: [`${HOMEBREW_PREFIX}/bin/lsof`, "-h"],
+ expected: /usage:\s*lsof|lsof/i,
+ description: "Run lsof -h from the poured Homebrew prefix.",
+ })];
+ case "netcat":
+ // The poured prefix links `nc` (not `netcat`); `-h` prints the GNU netcat banner.
+ return [programOutputCase({
+ formula,
+ name: "netcat_help",
+ argv: [`${HOMEBREW_PREFIX}/bin/nc`, "-h"],
+ expected: /netcat|usage/i,
+ description: "Run nc -h from the poured Homebrew prefix.",
+ })];
+ default:
+ return [programVersionCase(formula, formula, new RegExp(escapeRegex(formula), "i"))];
+ }
+}
+
+export function browserCaseNamesForFormula(formula: HomebrewSmokeFormula): string[] {
+ return browserSmokeCasesForFormula(formula).map((smokeCase) => smokeCase.name);
+}
+
+function programOutputCase(options: {
+ formula: HomebrewSmokeFormula;
+ name: string;
+ argv: string[];
+ stdin?: string;
+ env?: string[];
+ expected: RegExp;
+ description: string;
+}): BrowserSmokeCase {
+ return {
+ name: options.name,
+ formula: options.formula,
+ required: true,
+ command: options.argv.join(" "),
+ argv: options.argv,
+ stdin: options.stdin,
+ env: options.env,
+ expected: options.expected,
+ description: options.description,
+ };
+}
+
+function programVersionCase(
+ formula: HomebrewSmokeFormula,
+ binName: string,
+ expected: RegExp,
+): BrowserSmokeCase {
+ return programOutputCase({
+ formula,
+ name: `${binName}_version`,
+ argv: [`${HOMEBREW_PREFIX}/bin/${binName}`, "--version"],
+ expected,
+ description: `Run ${binName} --version from the poured Homebrew prefix.`,
+ });
+}
+
+function escapeRegex(value: string): string {
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+}
diff --git a/scripts/homebrew-smoke-outcomes.ts b/scripts/homebrew-smoke-outcomes.ts
new file mode 100644
index 000000000..63a6c5974
--- /dev/null
+++ b/scripts/homebrew-smoke-outcomes.ts
@@ -0,0 +1,86 @@
+import { mkdirSync, writeFileSync } from "node:fs";
+import { join } from "node:path";
+
+export type SmokeOutcomeStatus = "pass" | "fail" | "skip";
+
+export interface SmokeOutcome {
+ name: string;
+ status: SmokeOutcomeStatus;
+ durationMs: number;
+ details?: string;
+ error?: string;
+ artifactPath?: string;
+}
+
+export class SkipCase extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = "SkipCase";
+ }
+}
+
+export function countOutcomes(outcomes: SmokeOutcome[]): {
+ pass: number;
+ fail: number;
+ skip: number;
+} {
+ return {
+ pass: outcomes.filter((outcome) => outcome.status === "pass").length,
+ fail: outcomes.filter((outcome) => outcome.status === "fail").length,
+ skip: outcomes.filter((outcome) => outcome.status === "skip").length,
+ };
+}
+
+export function writeOutcomeLists(
+ resultDir: string,
+ outcomes: SmokeOutcome[],
+ options: { includeArtifactPath?: boolean } = {},
+): void {
+ const listsDir = join(resultDir, "outcome-lists");
+ mkdirSync(listsDir, { recursive: true });
+ const passed = outcomes.filter((outcome) => outcome.status === "pass");
+ const failed = outcomes.filter((outcome) => outcome.status === "fail");
+ const skipped = outcomes.filter((outcome) => outcome.status === "skip");
+ const withArtifact = options.includeArtifactPath === true;
+
+ writeFileSync(
+ join(listsDir, "passed-tests.tsv"),
+ [
+ withArtifact ? "test\tduration_ms\tdetails\tartifact_path" : "test\tduration_ms\tdetails",
+ ...passed.map((outcome) => [
+ outcome.name,
+ String(outcome.durationMs),
+ tsv(outcome.details ?? ""),
+ ...(withArtifact ? [tsv(outcome.artifactPath ?? "")] : []),
+ ].join("\t")),
+ ].join("\n") + "\n",
+ );
+ writeFileSync(
+ join(listsDir, "failed-tests.tsv"),
+ [
+ withArtifact ? "test\tduration_ms\terror\tartifact_path" : "test\tduration_ms\terror",
+ ...failed.map((outcome) => [
+ outcome.name,
+ String(outcome.durationMs),
+ tsv(outcome.error ?? outcome.details ?? ""),
+ ...(withArtifact ? [tsv(outcome.artifactPath ?? "")] : []),
+ ].join("\t")),
+ ].join("\n") + "\n",
+ );
+ writeFileSync(
+ join(listsDir, "skipped-tests.tsv"),
+ [
+ withArtifact ? "test\treason\tartifact_path" : "test\treason",
+ ...skipped.map((outcome) => [
+ outcome.name,
+ tsv(outcome.details ?? ""),
+ ...(withArtifact ? [tsv(outcome.artifactPath ?? "")] : []),
+ ].join("\t")),
+ ].join("\n") + "\n",
+ );
+ writeFileSync(join(resultDir, "failures.json"), `${JSON.stringify(failed, null, 2)}\n`);
+}
+
+function tsv(value: string): string {
+ return value.replace(/\t/g, " ").replace(/\r?\n/g, "\\n");
+}
diff --git a/scripts/install-local-binary.sh b/scripts/install-local-binary.sh
index dfd7a9776..017217c80 100755
--- a/scripts/install-local-binary.sh
+++ b/scripts/install-local-binary.sh
@@ -67,7 +67,10 @@ install_local_binary() {
local src_basename
src_basename="$(basename "$src")"
local host_target
- host_target="$(rustc -vV 2>/dev/null | awk '/^host/ {print $2}')"
+ host_target=""
+ if command -v rustc >/dev/null 2>&1; then
+ host_target="$(rustc -vV 2>/dev/null | awk '/^host/ {print $2}' || true)"
+ fi
if ! wasm_require_no_legacy_asyncify "$src"; then
return 1
@@ -152,9 +155,11 @@ install_local_binary() {
dest="$repo_root/local-binaries/programs/$arch/$program$src_ext"
fi
- mkdir -p "$(dirname "$dest")"
- cp "$src" "$dest"
- echo " installed $dest"
+ if [ "${WASM_POSIX_SKIP_LOCAL_BINARY_INSTALL:-0}" != "1" ]; then
+ mkdir -p "$(dirname "$dest")"
+ cp "$src" "$dest"
+ echo " installed $dest"
+ fi
# When invoked under the package-system resolver (`xtask build-deps
# resolve`, `xtask archive-stage`), WASM_POSIX_DEP_OUT_DIR points at
@@ -172,8 +177,12 @@ install_local_binary() {
# path is a no-op.
if [ -n "${WASM_POSIX_DEP_OUT_DIR:-}" ]; then
local resolver_dest="$WASM_POSIX_DEP_OUT_DIR/$src_basename"
- mkdir -p "$(dirname "$resolver_dest")"
- cp "$src" "$resolver_dest"
- echo " installed $resolver_dest (resolver scratch)"
+ if [ "$src" -ef "$resolver_dest" ]; then
+ echo " installed $resolver_dest (resolver scratch)"
+ else
+ mkdir -p "$(dirname "$resolver_dest")"
+ cp "$src" "$resolver_dest"
+ echo " installed $resolver_dest (resolver scratch)"
+ fi
fi
}
diff --git a/sdk/src/bin/pkg-config.ts b/sdk/src/bin/pkg-config.ts
index 9576f834b..4f77b50f7 100755
--- a/sdk/src/bin/pkg-config.ts
+++ b/sdk/src/bin/pkg-config.ts
@@ -54,7 +54,8 @@ async function main(): Promise {
const arch = detectArch();
const sysroot = findSysroot(arch);
const env = buildPkgConfigEnv(process.env, sysroot);
- const exitCode = await runPassthrough('pkg-config', process.argv.slice(2), env);
+ const pkgConfig = process.env.PKG_CONFIG || 'pkg-config';
+ const exitCode = await runPassthrough(pkgConfig, process.argv.slice(2), env);
process.exit(exitCode);
}
diff --git a/test-runs/kd-0hns/DISPOSITION.md b/test-runs/kd-0hns/DISPOSITION.md
new file mode 100644
index 000000000..a8f6b09be
--- /dev/null
+++ b/test-runs/kd-0hns/DISPOSITION.md
@@ -0,0 +1,78 @@
+# kd-0hns — Rootfs/Shell Sidecar Disposition
+
+Repair of publishable Homebrew sidecars for the VFS-critical rootfs and shell
+input packages. Scope: bash, curl, bzip2, xz, nethack, dash, ncurses, less,
+netcat, wget, git, lsof, nano, vim, fbdoom, modeset.
+
+Base: `origin/main` (1ab41fe2a, PR #785 Homebrew tooling) merged with
+`gascity/kd-1mr/kd-bry6-interactive-network-device-cli` (interactive Formulae +
+generator). ABI 16 / `bottles-abi-v16`.
+
+## Two defects repaired
+
+1. `fork_instrumentation="auto"` — not a schema value. Root cause was
+ `package_fork_instrumentation()` in
+ `scripts/homebrew-generate-sidecars-from-env.sh` returning the literal
+ `"auto"` for any package that did not declare a policy (none did). Fixed the
+ generator to emit only `not-required|required|disabled|unknown` and declared
+ per-output `fork_instrumentation` in all 16 `package.toml` files.
+2. `file://` bottle urls — fail the sidecar `httpsUrl` schema and the
+ composite-status `HTTPS_URL_RE` check. Replaced with the canonical GHCR blob
+ destination `https://ghcr.io/v2/automattic/kandelo-homebrew//blobs/sha256:`.
+
+## Per-package disposition
+
+| Package | Formula | fork_instrumentation | url | sidecar validate | build/node_smoke | Disposition |
+|---------|---------|----------------------|-----|------------------|------------------|-------------|
+| dash | kd-bry6 | required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| git | kd-bry6 | required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| vim | kd-bry6 | required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| less | kd-bry6 | not-required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| lsof | kd-bry6 | not-required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| modeset | kd-bry6 | not-required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| nano | kd-bry6 | not-required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| netcat | kd-bry6 | not-required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| wget | kd-bry6 | not-required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| fbdoom | kd-bry6 | not-required (was auto) | GHCR https (was file://) | PASS | success/success | REPAIRED — publishable |
+| bzip2 | kd-0k6q/kd-1mr.2 | not-required | GHCR https | PASS (combined) | success (pilot) | ADOPTED — publishable |
+| xz | kd-0k6q/kd-1mr.2 | not-required | GHCR https | PASS (combined) | success (pilot) | ADOPTED — publishable |
+| bash | none | required (declared) | n/a | BLOCKED | — | BLOCKED — no Homebrew Formula; also needs ncurses |
+| ncurses | none | not-required (declared) | n/a | BLOCKED | — | BLOCKED — no Homebrew Formula (leaf dep of bash + nethack) |
+| curl | none | not-required (declared) | n/a | BLOCKED | — | BLOCKED — no Homebrew Formula; needs libcurl + zlib + openssl |
+| nethack | none | not-required (declared) | n/a | BLOCKED | — | BLOCKED — no Homebrew Formula; needs ncurses |
+
+Publishable = **12 of 16** (10 repaired + 2 adopted). Blocked = **4 of 16**
+(bash, ncurses, curl, nethack), each with a precise blocker and follow-up bead.
+
+## Publication caveat (applies to all publishable sidecars)
+
+The repaired/adopted sidecars are **structurally publishable**: they pass
+`homebrew-validate` and the composite-status planner's bottle checks (https url,
+sha256, cache_key, link manifest, valid fork_instrumentation). The bottles were
+built locally (real sha256/bytes/cache_key). The remaining publication step is
+uploading the bottle bytes to the recorded GHCR destinations via the trusted
+publish flow (`scripts/homebrew-ghcr-upload.sh`), which requires a
+`packages: write` `GH_TOKEN` and is an outward-facing push to
+`Automattic/kandelo-homebrew` — out of scope for this session without explicit
+`@brandon` authorization. This is the same structural bar the accepted kd-0k6q /
+kd-1mr.2 pilot sidecars already meet.
+
+## Verification
+
+- Individual: 10/10 kd-bry6 sidecars regenerated with corrected inputs →
+ `homebrew-validate: ok` each (see `homebrew-validate.log`).
+- Combined: `test-runs/kd-0hns/rootfs-shell-tap` (12 packages, closed
+ dependency set) → `homebrew-validate: ok (packages=12, bottles=12,
+ link_manifests=12, provenance_reports=12)`.
+- All 16 `package.toml` parse as valid TOML with policy-compliant
+ `fork_instrumentation`.
+- Generator python re-compiles after the fix.
+
+## kd-v3fs composite impact
+
+- rootfs/shell interactive inputs (dash, git, vim, less, nano, netcat, wget,
+ lsof, modeset, fbdoom) + bzip2/xz are now publishable; the combined tap is a
+ ready rootfs/shell input bundle.
+- Still blocking rootfs/shell: bash, ncurses, curl, nethack (missing Formulae).
+ rootfs can compose on `dash` today; `bash` remains optional/blocked on
+ ncurses.
diff --git a/test-runs/kd-0hns/homebrew-validate.log b/test-runs/kd-0hns/homebrew-validate.log
new file mode 100644
index 000000000..cfe15bc10
--- /dev/null
+++ b/test-runs/kd-0hns/homebrew-validate.log
@@ -0,0 +1,17 @@
+warning: Git tree '/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-0hns-vfs-rootfs-shell-sidecars' has uncommitted changes
+kandelo dev shell — LLVM 21.1.7, Rust (pinned via rust-toolchain.toml), Node 24, Erlang 28 (minimal), SDK on PATH
+== building xtask ==
+ Compiling ureq v2.12.1
+ Compiling xtask v0.1.0 (/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-0hns-vfs-rootfs-shell-sidecars/tools/xtask)
+ Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 43s
+PASS dash :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS git :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS vim :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS less :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS lsof :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS modeset :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS nano :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS netcat :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS wget :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+PASS fbdoom :: homebrew-validate: ok (packages=1, bottles=1, link_manifests=1, provenance_reports=1)
+SUMMARY pass=10 fail=0
diff --git a/test-runs/kd-0hns/outcome-lists/failed-tests.tsv b/test-runs/kd-0hns/outcome-lists/failed-tests.tsv
new file mode 100644
index 000000000..a0cdb004f
--- /dev/null
+++ b/test-runs/kd-0hns/outcome-lists/failed-tests.tsv
@@ -0,0 +1 @@
+test error
diff --git a/test-runs/kd-0hns/outcome-lists/passed-tests.tsv b/test-runs/kd-0hns/outcome-lists/passed-tests.tsv
new file mode 100644
index 000000000..4a3f077ae
--- /dev/null
+++ b/test-runs/kd-0hns/outcome-lists/passed-tests.tsv
@@ -0,0 +1,14 @@
+test result
+combined-rootfs-shell-tap homebrew-validate ok (packages=12 bottles=12 link_manifests=12 provenance_reports=12)
+dash homebrew-validate ok (repaired: fork+url)
+git homebrew-validate ok (repaired: fork+url)
+vim homebrew-validate ok (repaired: fork+url)
+less homebrew-validate ok (repaired: fork+url)
+lsof homebrew-validate ok (repaired: fork+url)
+modeset homebrew-validate ok (repaired: fork+url)
+nano homebrew-validate ok (repaired: fork+url)
+netcat homebrew-validate ok (repaired: fork+url)
+wget homebrew-validate ok (repaired: fork+url)
+fbdoom homebrew-validate ok (repaired: fork+url)
+bzip2 homebrew-validate ok (adopted pilot; in combined tap)
+xz homebrew-validate ok (adopted pilot; in combined tap)
diff --git a/test-runs/kd-0hns/outcome-lists/skipped-tests.tsv b/test-runs/kd-0hns/outcome-lists/skipped-tests.tsv
new file mode 100644
index 000000000..158787a9d
--- /dev/null
+++ b/test-runs/kd-0hns/outcome-lists/skipped-tests.tsv
@@ -0,0 +1,5 @@
+test reason
+bash no Homebrew Formula in any convoy branch; requires authoring Formula/bash.rb + brew bottle build; also depends on ncurses (also missing)
+ncurses no Homebrew Formula in any convoy branch; leaf dependency of bash and nethack; requires authoring Formula/ncurses.rb (10 outputs) + brew bottle build
+curl no Homebrew Formula in any convoy branch; depends on libcurl+zlib+openssl (dependent/language runtime wave kd-xhdd/kd-yuef)
+nethack no Homebrew Formula in any convoy branch; depends on ncurses (also missing); requires authoring Formula/nethack.rb + brew bottle build
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/bzip2.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/bzip2.rb
new file mode 100644
index 000000000..257fee342
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/bzip2.rb
@@ -0,0 +1,68 @@
+require "shellwords"
+
+class Bzip2 < Formula
+ desc "bzip2 compression tool for Kandelo"
+ homepage "https://sourceware.org/bzip2/"
+ url "https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz"
+ sha256 "ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269"
+ license "bzip2-1.0.6"
+
+ skip_clean "bin/bzip2"
+
+ def kandelo_root
+ root = ENV["HOMEBREW_KANDELO_ROOT"] || ENV["KANDELO_HOMEBREW_KANDELO_ROOT"]
+ odie "HOMEBREW_KANDELO_ROOT must point at a Kandelo checkout" if root.to_s.empty?
+ root
+ end
+
+ def configure_kandelo_environment(root)
+ %w[
+ CC CXX OBJC OBJCXX CFLAGS CPPFLAGS CXXFLAGS LDFLAGS CPATH
+ C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH SDKROOT
+ MACOSX_DEPLOYMENT_TARGET
+ ].each { |key| ENV.delete(key) }
+
+ ENV.prepend_path "PATH", "#{root}/sdk/bin"
+ if (node = ENV["HOMEBREW_KANDELO_NODE"]).to_s != ""
+ ENV.prepend_path "PATH", File.dirname(node)
+ end
+ if (llvm_bin = ENV["HOMEBREW_KANDELO_LLVM_BIN"]).to_s != ""
+ ENV["WASM_POSIX_LLVM_DIR"] = llvm_bin
+ ENV["LLVM_BIN"] = llvm_bin
+ ENV.prepend_path "PATH", llvm_bin
+ end
+ end
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+
+ out_dir = buildpath/"kandelo-package-out"
+ ENV["WASM_POSIX_DEP_VERSION"] = version.to_s
+ ENV["WASM_POSIX_DEP_SOURCE_URL"] = "https://sourceware.org/pub/bzip2/bzip2-#{version}.tar.gz"
+ ENV["WASM_POSIX_DEP_SOURCE_SHA256"] = "ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269"
+ ENV["WASM_POSIX_DEP_OUT_DIR"] = out_dir
+ ENV["WASM_POSIX_DEP_WORK_DIR"] = buildpath/"kandelo-package-work"
+ ENV["WASM_POSIX_DEP_TARGET_ARCH"] = ENV.fetch("HOMEBREW_KANDELO_ARCH", ENV.fetch("KANDELO_HOMEBREW_ARCH", "wasm32"))
+
+ system "bash", "#{root}/packages/registry/bzip2/build-bzip2.sh"
+ chmod 0755, out_dir/"bzip2.wasm"
+ bin.install out_dir/"bzip2.wasm" => "bzip2"
+ chmod 0755, bin/"bzip2"
+ end
+
+ test do
+ bzip2 = bin/"bzip2"
+ assert_equal "\0asm".b, File.binread(bzip2, 4)
+
+ root = kandelo_root
+ configure_kandelo_environment(root)
+
+ test_wasm = testpath/"bzip2.wasm"
+ File.binwrite(test_wasm, File.binread(bzip2))
+ output = shell_output(
+ "cd #{root.shellescape} && node --experimental-wasm-exnref --import tsx/esm examples/run-example.ts #{test_wasm.to_s.shellescape} --help 2>&1",
+ )
+ assert_match "bzip2", output.scrub
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/dash.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/dash.rb
new file mode 100644
index 000000000..bf2dd6847
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/dash.rb
@@ -0,0 +1,33 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Dash < Formula
+ include KandeloFormulaSupport
+
+ desc "POSIX shell for Kandelo"
+ homepage "http://gondor.apana.org.au/~herbert/dash/"
+ url "http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.12.tar.gz"
+ sha256 "6a474ac46e8b0b32916c4c60df694c82058d3297d8b385b74508030ca4a8f28a"
+ license all_of: ["BSD-3-Clause", "GPL-2.0-or-later"]
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8"
+ end
+
+ skip_clean "bin/dash"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["DASH_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.12.tar.gz", source_sha256: "6a474ac46e8b0b32916c4c60df694c82058d3297d8b385b74508030ca4a8f28a")
+ system "bash", "#{root}/packages/registry/dash/build-dash.sh"
+ install_kandelo_wasm(out_dir, "dash.wasm", "dash")
+ end
+
+ test do
+ assert_kandelo_wasm "dash"
+ assert_match "dash-homebrew-smoke", shell_output_kandelo_wasm("dash", ["-c", "echo dash-homebrew-smoke"])
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/fbdoom.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/fbdoom.rb
new file mode 100644
index 000000000..67de69781
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/fbdoom.rb
@@ -0,0 +1,31 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Fbdoom < Formula
+ include KandeloFormulaSupport
+
+ desc "fbDOOM framebuffer game port for Kandelo"
+ homepage "https://github.com/maximevince/fbDOOM"
+ url "https://github.com/maximevince/fbDOOM.git", branch: "master"
+ version "0.1.0"
+ license "GPL-2.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c"
+ end
+
+ skip_clean "bin/fbdoom"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/maximevince/fbDOOM", source_sha256: "0000000000000000000000000000000000000000000000000000000000000000")
+ system "bash", "#{root}/packages/registry/fbdoom/build-fbdoom.sh"
+ install_kandelo_wasm(out_dir, "fbdoom.wasm", "fbdoom")
+ end
+
+ test do
+ assert_kandelo_wasm "fbdoom"
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/git.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/git.rb
new file mode 100644
index 000000000..600a54894
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/git.rb
@@ -0,0 +1,39 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Git < Formula
+ include KandeloFormulaSupport
+
+ desc "Distributed revision control system for Kandelo"
+ homepage "https://git-scm.com/"
+ url "https://github.com/git/git/archive/refs/tags/v2.47.1.tar.gz"
+ sha256 "30654cc6c0142fa68050cc7b0ee6a2a65944288b907821781112efaf24293b23"
+ license "GPL-2.0-only"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f"
+ end
+
+ skip_clean "bin/git"
+ skip_clean "bin/git-remote-http"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["GIT_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/git/git/archive/refs/tags/v2.47.1.tar.gz", source_sha256: "30654cc6c0142fa68050cc7b0ee6a2a65944288b907821781112efaf24293b23")
+ system "bash", "#{root}/packages/registry/git/build-git.sh"
+ install_kandelo_wasm(out_dir, "git.wasm", "git")
+ install_kandelo_wasm(out_dir, "git-remote-http.wasm", "git-remote-http")
+ bin.install_symlink "git-remote-http" => "git-remote-https"
+ bin.install_symlink "git-remote-http" => "git-remote-ftp"
+ bin.install_symlink "git-remote-http" => "git-remote-ftps"
+ end
+
+ test do
+ assert_kandelo_wasm "git"
+ assert_kandelo_wasm "git-remote-http"
+ assert_match "git version", shell_output_kandelo_wasm("git", ["--version"])
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/less.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/less.rb
new file mode 100644
index 000000000..02a9a7f17
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/less.rb
@@ -0,0 +1,33 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Less < Formula
+ include KandeloFormulaSupport
+
+ desc "Terminal pager for Kandelo"
+ homepage "https://www.greenwoodsoftware.com/less/"
+ url "https://www.greenwoodsoftware.com/less/less-668.tar.gz"
+ sha256 "2819f55564d86d542abbecafd82ff61e819a3eec967faa36cd3e68f1596a44b8"
+ license "GPL-3.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061"
+ end
+
+ skip_clean "bin/less"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["LESS_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://www.greenwoodsoftware.com/less/less-668.tar.gz", source_sha256: "2819f55564d86d542abbecafd82ff61e819a3eec967faa36cd3e68f1596a44b8")
+ system "bash", "#{root}/packages/registry/less/build-less.sh"
+ install_kandelo_wasm(out_dir, "less.wasm", "less")
+ end
+
+ test do
+ assert_kandelo_wasm "less"
+ assert_match "less", shell_output_kandelo_wasm("less", ["--version"])
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/lsof.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/lsof.rb
new file mode 100644
index 000000000..c839f2f55
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/lsof.rb
@@ -0,0 +1,32 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Lsof < Formula
+ include KandeloFormulaSupport
+
+ desc "Kandelo /proc file descriptor lister"
+ homepage "https://github.com/brandonpayton/kandelo"
+ url "https://github.com/Automattic/kandelo/archive/1ab41fe2ad5553f4fa4bb0223f2d804b13149578.tar.gz"
+ sha256 "446dd26b6e3f909f25f21f77950a3b11a07c633721dbff698a85b4f05fbbc493"
+ version "0.1.0"
+ license "GPL-2.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b"
+ end
+
+ skip_clean "bin/lsof"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/Automattic/kandelo/archive/1ab41fe2ad5553f4fa4bb0223f2d804b13149578.tar.gz", source_sha256: "446dd26b6e3f909f25f21f77950a3b11a07c633721dbff698a85b4f05fbbc493")
+ system "bash", "#{root}/packages/registry/lsof/build-lsof.sh"
+ install_kandelo_wasm(out_dir, "lsof.wasm", "lsof")
+ end
+
+ test do
+ assert_kandelo_wasm "lsof"
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/modeset.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/modeset.rb
new file mode 100644
index 000000000..6e0fe049f
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/modeset.rb
@@ -0,0 +1,32 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Modeset < Formula
+ include KandeloFormulaSupport
+
+ desc "DRI/GLES framebuffer fluid simulation for Kandelo"
+ homepage "https://github.com/brandonpayton/kandelo"
+ url "https://github.com/Automattic/kandelo/archive/1ab41fe2ad5553f4fa4bb0223f2d804b13149578.tar.gz"
+ sha256 "446dd26b6e3f909f25f21f77950a3b11a07c633721dbff698a85b4f05fbbc493"
+ version "0.1.0"
+ license "GPL-2.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88"
+ end
+
+ skip_clean "bin/modeset"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/Automattic/kandelo/archive/1ab41fe2ad5553f4fa4bb0223f2d804b13149578.tar.gz", source_sha256: "446dd26b6e3f909f25f21f77950a3b11a07c633721dbff698a85b4f05fbbc493")
+ system "bash", "#{root}/packages/registry/modeset/build-modeset.sh"
+ install_kandelo_wasm(out_dir, "modeset.wasm", "modeset")
+ end
+
+ test do
+ assert_kandelo_wasm "modeset"
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/nano.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/nano.rb
new file mode 100644
index 000000000..cf2188889
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/nano.rb
@@ -0,0 +1,33 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Nano < Formula
+ include KandeloFormulaSupport
+
+ desc "Terminal text editor for Kandelo"
+ homepage "https://www.nano-editor.org/"
+ url "https://ftpmirror.gnu.org/gnu/nano/nano-8.0.tar.xz"
+ sha256 "c17f43fc0e37336b33ee50a209c701d5beb808adc2d9f089ca831b40539c9ac4"
+ license "GPL-3.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0"
+ end
+
+ skip_clean "bin/nano"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["NANO_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://ftpmirror.gnu.org/gnu/nano/nano-8.0.tar.xz", source_sha256: "c17f43fc0e37336b33ee50a209c701d5beb808adc2d9f089ca831b40539c9ac4")
+ system "bash", "#{root}/packages/registry/nano/build-nano.sh"
+ install_kandelo_wasm(out_dir, "nano.wasm", "nano")
+ end
+
+ test do
+ assert_kandelo_wasm "nano"
+ assert_match(/GNU nano|nano/i, shell_output_kandelo_wasm("nano", ["--version"]))
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/netcat.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/netcat.rb
new file mode 100644
index 000000000..b310390ee
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/netcat.rb
@@ -0,0 +1,34 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Netcat < Formula
+ include KandeloFormulaSupport
+
+ desc "GNU netcat network utility for Kandelo"
+ homepage "https://sourceforge.net/projects/netcat/"
+ url "https://downloads.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz"
+ sha256 "30719c9a4ffbcf15676b8f528233ccc54ee6cba96cb4590975f5fd60c68a066f"
+ license "GPL-2.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd"
+ end
+
+ skip_clean "bin/nc"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["NETCAT_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://downloads.sourceforge.net/project/netcat/netcat/0.7.1/netcat-0.7.1.tar.gz", source_sha256: "30719c9a4ffbcf15676b8f528233ccc54ee6cba96cb4590975f5fd60c68a066f")
+ system "bash", "#{root}/packages/registry/netcat/build-netcat.sh"
+ install_kandelo_wasm(out_dir, "nc.wasm", "nc")
+ bin.install_symlink "nc" => "netcat"
+ end
+
+ test do
+ assert_kandelo_wasm "nc"
+ assert_match(/netcat|listen|connect|usage/i, shell_output_kandelo_wasm("nc", ["--help"]))
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/vim.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/vim.rb
new file mode 100644
index 000000000..461cfcf70
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/vim.rb
@@ -0,0 +1,34 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Vim < Formula
+ include KandeloFormulaSupport
+
+ desc "Vim terminal editor for Kandelo"
+ homepage "https://www.vim.org/"
+ url "https://github.com/vim/vim/archive/refs/tags/v9.1.0900.tar.gz"
+ sha256 "30efb714ed82c5d7a1491f3e4aac6487d2c493d33c834d7ef043e6f45176772e"
+ license "Vim"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae"
+ end
+
+ skip_clean "bin/vim"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["VIM_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://github.com/vim/vim/archive/refs/tags/v9.1.0900.tar.gz", source_sha256: "30efb714ed82c5d7a1491f3e4aac6487d2c493d33c834d7ef043e6f45176772e")
+ system "bash", "#{root}/packages/registry/vim/build-vim.sh"
+ install_kandelo_wasm(out_dir, "vim.wasm", "vim")
+ (share/"vim").install out_dir/"runtime" if (out_dir/"runtime").directory?
+ end
+
+ test do
+ assert_kandelo_wasm "vim"
+ assert_match(/VIM|Vi IMproved/i, shell_output_kandelo_wasm("vim", ["--version"]))
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/wget.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/wget.rb
new file mode 100644
index 000000000..ade787e42
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/wget.rb
@@ -0,0 +1,33 @@
+require "shellwords"
+require_relative "../Kandelo/kandelo_formula_support"
+
+class Wget < Formula
+ include KandeloFormulaSupport
+
+ desc "GNU Wget network downloader for Kandelo"
+ homepage "https://www.gnu.org/software/wget/"
+ url "https://ftpmirror.gnu.org/gnu/wget/wget-1.25.0.tar.gz"
+ sha256 "766e48423e79359ea31e41db9e5c289675947a7fcf2efdcedb726ac9d0da3784"
+ license "GPL-3.0-or-later"
+
+ bottle do
+ root_url "https://ghcr.io/v2/automattic/kandelo-homebrew"
+ sha256 cellar: :any_skip_relocation, wasm32_kandelo: "7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad"
+ end
+
+ skip_clean "bin/wget"
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+ ENV["WGET_VERSION"] = version.to_s
+ out_dir = prepare_kandelo_package_env(source_url: "https://ftpmirror.gnu.org/gnu/wget/wget-1.25.0.tar.gz", source_sha256: "766e48423e79359ea31e41db9e5c289675947a7fcf2efdcedb726ac9d0da3784")
+ system "bash", "#{root}/packages/registry/wget/build-wget.sh"
+ install_kandelo_wasm(out_dir, "wget.wasm", "wget")
+ end
+
+ test do
+ assert_kandelo_wasm "wget"
+ assert_match(/GNU Wget|Wget/i, shell_output_kandelo_wasm("wget", ["--version"]))
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Formula/xz.rb b/test-runs/kd-0hns/rootfs-shell-tap/Formula/xz.rb
new file mode 100644
index 000000000..e9f1da378
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Formula/xz.rb
@@ -0,0 +1,68 @@
+require "shellwords"
+
+class Xz < Formula
+ desc "XZ Utils compression tool for Kandelo"
+ homepage "https://tukaani.org/xz/"
+ url "https://tukaani.org/xz/xz-5.6.2.tar.xz"
+ sha256 "a9db3bb3d64e248a0fae963f8fb6ba851a26ba1822e504dc0efd18a80c626caf"
+ license all_of: ["GPL-2.0-or-later", "LGPL-2.1-or-later", "0BSD"]
+
+ skip_clean "bin/xz"
+
+ def kandelo_root
+ root = ENV["HOMEBREW_KANDELO_ROOT"] || ENV["KANDELO_HOMEBREW_KANDELO_ROOT"]
+ odie "HOMEBREW_KANDELO_ROOT must point at a Kandelo checkout" if root.to_s.empty?
+ root
+ end
+
+ def configure_kandelo_environment(root)
+ %w[
+ CC CXX OBJC OBJCXX CFLAGS CPPFLAGS CXXFLAGS LDFLAGS CPATH
+ C_INCLUDE_PATH CPLUS_INCLUDE_PATH OBJC_INCLUDE_PATH SDKROOT
+ MACOSX_DEPLOYMENT_TARGET
+ ].each { |key| ENV.delete(key) }
+
+ ENV.prepend_path "PATH", "#{root}/sdk/bin"
+ if (node = ENV["HOMEBREW_KANDELO_NODE"]).to_s != ""
+ ENV.prepend_path "PATH", File.dirname(node)
+ end
+ if (llvm_bin = ENV["HOMEBREW_KANDELO_LLVM_BIN"]).to_s != ""
+ ENV["WASM_POSIX_LLVM_DIR"] = llvm_bin
+ ENV["LLVM_BIN"] = llvm_bin
+ ENV.prepend_path "PATH", llvm_bin
+ end
+ end
+
+ def install
+ root = kandelo_root
+ configure_kandelo_environment(root)
+
+ out_dir = buildpath/"kandelo-package-out"
+ ENV["WASM_POSIX_DEP_VERSION"] = version.to_s
+ ENV["WASM_POSIX_DEP_SOURCE_URL"] = "https://tukaani.org/xz/xz-#{version}.tar.xz"
+ ENV["WASM_POSIX_DEP_SOURCE_SHA256"] = "a9db3bb3d64e248a0fae963f8fb6ba851a26ba1822e504dc0efd18a80c626caf"
+ ENV["WASM_POSIX_DEP_OUT_DIR"] = out_dir
+ ENV["WASM_POSIX_DEP_WORK_DIR"] = buildpath/"kandelo-package-work"
+ ENV["WASM_POSIX_DEP_TARGET_ARCH"] = ENV.fetch("HOMEBREW_KANDELO_ARCH", ENV.fetch("KANDELO_HOMEBREW_ARCH", "wasm32"))
+
+ system "bash", "#{root}/packages/registry/xz/build-xz.sh"
+ chmod 0755, out_dir/"xz.wasm"
+ bin.install out_dir/"xz.wasm" => "xz"
+ chmod 0755, bin/"xz"
+ end
+
+ test do
+ xz = bin/"xz"
+ assert_equal "\0asm".b, File.binread(xz, 4)
+
+ root = kandelo_root
+ configure_kandelo_environment(root)
+
+ test_wasm = testpath/"xz.wasm"
+ File.binwrite(test_wasm, File.binread(xz))
+ output = shell_output(
+ "cd #{root.shellescape} && node --experimental-wasm-exnref --import tsx/esm examples/run-example.ts #{test_wasm.to_s.shellescape} --version",
+ )
+ assert_match "xz", output.scrub
+ end
+end
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/bzip2.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/bzip2.json
new file mode 100644
index 000000000..dcd5fd316
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/bzip2.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T03:05:02Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "f0785634aa730b9e9d31700fa9341fb6cc6637589bb7a47cf7b5e3d2c6181639",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 62564,
+ "cache_key_sha": "49c19e83209e7954c9f8399262cd76d7e23868e4a022e4502f8668d4e0c9cd5f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/bzip2/blobs/sha256:98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/bzip2.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/bzip2",
+ "kandelo_abi": 16,
+ "name": "bzip2",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "1.0.8"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/dash.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/dash.json
new file mode 100644
index 000000000..9b4051859
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/dash.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:12Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "10131b1f653fee7727b06b6c0feed3d16b9edab6d156c183be3a3ee19fc61f4a",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 144268,
+ "cache_key_sha": "f1cf217ac3c91d7dddf9acfa101b6ea0c090fbbbb7abe064f31f601de2e11772",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/dash-0.5.12-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/dash/blobs/sha256:b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/dash.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/dash",
+ "kandelo_abi": 16,
+ "name": "dash",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "0.5.12"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/fbdoom.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/fbdoom.json
new file mode 100644
index 000000000..3bfdbafd6
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/fbdoom.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:13Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "0481f1947e92f1e08e785b5d8034cf1cf88c5cede0ee3e282f984f6429f43c95",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 202079,
+ "cache_key_sha": "e74be0eac8237d4345eb1db5c0c6d59aa0a20a54d7a603affeaa76190c7effc3",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/fbdoom/blobs/sha256:51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/fbdoom.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/fbdoom",
+ "kandelo_abi": 16,
+ "name": "fbdoom",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "0.1.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/git.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/git.json
new file mode 100644
index 000000000..8e1178044
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/git.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:14Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "8c5b08ee978619bf49028174b88e65abd7e17a10bbc6a50aff7175600ce37a84",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 4718293,
+ "cache_key_sha": "4c43e2a22ab146ab7136937652d959824578d07927521a16329dbd8474e3e3b8",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/git-2.47.1-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/git/blobs/sha256:2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/git.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/git",
+ "kandelo_abi": 16,
+ "name": "git",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "2.47.1"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/less.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/less.json
new file mode 100644
index 000000000..93296409d
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/less.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:15Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "eaa31a9603fb0b69b2d1415334e6559bc78273b16c2ef9ef00daf0aaf9a4c0d6",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 176495,
+ "cache_key_sha": "3ec5d016d15c7b316c6643d57f66cc2f4db4ed5726c3f30356c72fa9e15d6425",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/less-668-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/less/blobs/sha256:ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/less.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/less",
+ "kandelo_abi": 16,
+ "name": "less",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "668"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/lsof.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/lsof.json
new file mode 100644
index 000000000..6788fa579
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/lsof.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:16Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "46e2a45ef848a41db565070c445991a8d1d0b3b64ea839e796b0b33b78554541",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 35464,
+ "cache_key_sha": "88e06177e2acd7d54b78e9673812a7124712052ddda3599341dc208910a83b4f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/lsof/blobs/sha256:104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/lsof.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/lsof",
+ "kandelo_abi": 16,
+ "name": "lsof",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "0.1.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/modeset.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/modeset.json
new file mode 100644
index 000000000..082aa8368
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/modeset.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:17Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "1747945d62ab174951721bc844fce55ffece7765ed123ed7ca3c449479d9d8a0",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 42724,
+ "cache_key_sha": "d3fc05bf7b73121ad1d49c447b755154ebff60f6e0baac959cf54107617aac66",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/modeset/blobs/sha256:48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/modeset.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/modeset",
+ "kandelo_abi": 16,
+ "name": "modeset",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "0.1.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/nano.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/nano.json
new file mode 100644
index 000000000..99df04801
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/nano.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:20Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "969f255d25e14def893341bc3043e5eea8c2d2a0dfd3cccc5e43cdd5848e25a2",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 505439,
+ "cache_key_sha": "4be127352be19f0d75448a83769107716757e545aa4f3790dca8069a093aab59",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/nano-8.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/nano/blobs/sha256:5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/nano.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/nano",
+ "kandelo_abi": 16,
+ "name": "nano",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "8.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/netcat.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/netcat.json
new file mode 100644
index 000000000..734e09453
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/netcat.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:21Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "ffb676fee1246fca4785c061448dc6f6be25de4d34a8ceac427a1713e562a0a9",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 71472,
+ "cache_key_sha": "ecfdca45ff958a00f498d460f57df18b9de2e66ecac5d95aa7c346b3686a9409",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/netcat/blobs/sha256:2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/netcat.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/netcat",
+ "kandelo_abi": 16,
+ "name": "netcat",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "0.7.1"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/vim.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/vim.json
new file mode 100644
index 000000000..4479ed450
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/vim.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "e0baeb2e530ebe112b576454901dca51d48bc862bf7ed2972b19821afe095c7b",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 7794122,
+ "cache_key_sha": "4a2a54d3a4c1052e2d484be6f8f25661bd233c49b9f0eecca5fd7040bcc222ba",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/vim/blobs/sha256:778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/vim.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/vim",
+ "kandelo_abi": 16,
+ "name": "vim",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "9.1.0900"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/wget.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/wget.json
new file mode 100644
index 000000000..5eb46d2d2
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/wget.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:23Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "9ef07777d42633279dfd1317e118ddd868ed96c7e564cf53c91bd453f2da98fb",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 2456339,
+ "cache_key_sha": "17d7408ea85bf3a5e4e8d1e1630c5a157df613b2313a5c407b6e7c7a466d1c31",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/wget-1.25.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/wget/blobs/sha256:7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/wget.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/wget",
+ "kandelo_abi": 16,
+ "name": "wget",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "1.25.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/xz.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/xz.json
new file mode 100644
index 000000000..ec3fbc3a0
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/formula/xz.json
@@ -0,0 +1,45 @@
+{
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T03:00:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "cb2d319d104ffc915cdc02d83fdc976849ae4a6bd33c195ba82cd4fd91645c96",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 379877,
+ "cache_key_sha": "6dcdd72b55ed0fbb6edc38c3854216da67579110efbaf56ee35803c7aec84027",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/xz-5.6.2-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/xz/blobs/sha256:887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca"
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/xz.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/xz",
+ "kandelo_abi": 16,
+ "name": "xz",
+ "schema": 1,
+ "source_metadata": "Kandelo/metadata.json",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew",
+ "version": "5.6.2"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json
new file mode 100644
index 000000000..2f65c33e8
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 62564,
+ "cache_key_sha": "49c19e83209e7954c9f8399262cd76d7e23868e4a022e4502f8668d4e0c9cd5f",
+ "payload_root": "bzip2/1.0.8",
+ "sha256": "98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/bzip2/blobs/sha256:98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/bzip2/1.0.8",
+ "links": [
+ {
+ "source": "bin/bzip2",
+ "target": "bin/bzip2",
+ "type": "symlink"
+ }
+ ],
+ "package": "bzip2",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/bzip2.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "1.0.8"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/dash-0.5.12-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/dash-0.5.12-rebuild0-wasm32.json
new file mode 100644
index 000000000..5161baaa9
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/dash-0.5.12-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 144268,
+ "cache_key_sha": "f1cf217ac3c91d7dddf9acfa101b6ea0c090fbbbb7abe064f31f601de2e11772",
+ "payload_root": "dash/0.5.12",
+ "sha256": "b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/dash/blobs/sha256:b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/dash/0.5.12",
+ "links": [
+ {
+ "source": "bin/dash",
+ "target": "bin/dash",
+ "type": "symlink"
+ }
+ ],
+ "package": "dash",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/dash.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "0.5.12"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json
new file mode 100644
index 000000000..f2b967c92
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 202079,
+ "cache_key_sha": "e74be0eac8237d4345eb1db5c0c6d59aa0a20a54d7a603affeaa76190c7effc3",
+ "payload_root": "fbdoom/0.1.0",
+ "sha256": "51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/fbdoom/blobs/sha256:51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/fbdoom/0.1.0",
+ "links": [
+ {
+ "source": "bin/fbdoom",
+ "target": "bin/fbdoom",
+ "type": "symlink"
+ }
+ ],
+ "package": "fbdoom",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/fbdoom.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "0.1.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/git-2.47.1-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/git-2.47.1-rebuild0-wasm32.json
new file mode 100644
index 000000000..c70f83844
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/git-2.47.1-rebuild0-wasm32.json
@@ -0,0 +1,38 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 4718293,
+ "cache_key_sha": "4c43e2a22ab146ab7136937652d959824578d07927521a16329dbd8474e3e3b8",
+ "payload_root": "git/2.47.1",
+ "sha256": "2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/git/blobs/sha256:2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/git/2.47.1",
+ "links": [
+ {
+ "source": "bin/git",
+ "target": "bin/git",
+ "type": "symlink"
+ },
+ {
+ "source": "bin/git-remote-http",
+ "target": "bin/git-remote-http",
+ "type": "symlink"
+ }
+ ],
+ "package": "git",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/git.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "2.47.1"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/less-668-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/less-668-rebuild0-wasm32.json
new file mode 100644
index 000000000..877dbc348
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/less-668-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 176495,
+ "cache_key_sha": "3ec5d016d15c7b316c6643d57f66cc2f4db4ed5726c3f30356c72fa9e15d6425",
+ "payload_root": "less/668",
+ "sha256": "ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/less/blobs/sha256:ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/less/668",
+ "links": [
+ {
+ "source": "bin/less",
+ "target": "bin/less",
+ "type": "symlink"
+ }
+ ],
+ "package": "less",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/less.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "668"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json
new file mode 100644
index 000000000..dea1d3800
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 35464,
+ "cache_key_sha": "88e06177e2acd7d54b78e9673812a7124712052ddda3599341dc208910a83b4f",
+ "payload_root": "lsof/0.1.0",
+ "sha256": "104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/lsof/blobs/sha256:104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/lsof/0.1.0",
+ "links": [
+ {
+ "source": "bin/lsof",
+ "target": "bin/lsof",
+ "type": "symlink"
+ }
+ ],
+ "package": "lsof",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/lsof.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "0.1.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json
new file mode 100644
index 000000000..f51d42450
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 42724,
+ "cache_key_sha": "d3fc05bf7b73121ad1d49c447b755154ebff60f6e0baac959cf54107617aac66",
+ "payload_root": "modeset/0.1.0",
+ "sha256": "48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/modeset/blobs/sha256:48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/modeset/0.1.0",
+ "links": [
+ {
+ "source": "bin/modeset",
+ "target": "bin/modeset",
+ "type": "symlink"
+ }
+ ],
+ "package": "modeset",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/modeset.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "0.1.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/nano-8.0-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/nano-8.0-rebuild0-wasm32.json
new file mode 100644
index 000000000..4f88883ce
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/nano-8.0-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 505439,
+ "cache_key_sha": "4be127352be19f0d75448a83769107716757e545aa4f3790dca8069a093aab59",
+ "payload_root": "nano/8.0",
+ "sha256": "5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/nano/blobs/sha256:5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/nano/8.0",
+ "links": [
+ {
+ "source": "bin/nano",
+ "target": "bin/nano",
+ "type": "symlink"
+ }
+ ],
+ "package": "nano",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/nano.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "8.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json
new file mode 100644
index 000000000..bad1b6a72
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 71472,
+ "cache_key_sha": "ecfdca45ff958a00f498d460f57df18b9de2e66ecac5d95aa7c346b3686a9409",
+ "payload_root": "netcat/0.7.1",
+ "sha256": "2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/netcat/blobs/sha256:2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/netcat/0.7.1",
+ "links": [
+ {
+ "source": "bin/nc",
+ "target": "bin/nc",
+ "type": "symlink"
+ }
+ ],
+ "package": "netcat",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/netcat.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "0.7.1"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json
new file mode 100644
index 000000000..77a01b2bf
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 7794122,
+ "cache_key_sha": "4a2a54d3a4c1052e2d484be6f8f25661bd233c49b9f0eecca5fd7040bcc222ba",
+ "payload_root": "vim/9.1.0900",
+ "sha256": "778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/vim/blobs/sha256:778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/vim/9.1.0900",
+ "links": [
+ {
+ "source": "bin/vim",
+ "target": "bin/vim",
+ "type": "symlink"
+ }
+ ],
+ "package": "vim",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/vim.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "9.1.0900"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/wget-1.25.0-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/wget-1.25.0-rebuild0-wasm32.json
new file mode 100644
index 000000000..d4fec3640
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/wget-1.25.0-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 2456339,
+ "cache_key_sha": "17d7408ea85bf3a5e4e8d1e1630c5a157df613b2313a5c407b6e7c7a466d1c31",
+ "payload_root": "wget/1.25.0",
+ "sha256": "7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/wget/blobs/sha256:7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/wget/1.25.0",
+ "links": [
+ {
+ "source": "bin/wget",
+ "target": "bin/wget",
+ "type": "symlink"
+ }
+ ],
+ "package": "wget",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/wget.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "1.25.0"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/xz-5.6.2-rebuild0-wasm32.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/xz-5.6.2-rebuild0-wasm32.json
new file mode 100644
index 000000000..76630c05e
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/link/xz-5.6.2-rebuild0-wasm32.json
@@ -0,0 +1,33 @@
+{
+ "arch": "wasm32",
+ "bottle": {
+ "bytes": 379877,
+ "cache_key_sha": "6dcdd72b55ed0fbb6edc38c3854216da67579110efbaf56ee35803c7aec84027",
+ "payload_root": "xz/5.6.2",
+ "sha256": "887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/xz/blobs/sha256:887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca"
+ },
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "kandelo_abi": 16,
+ "keg": "/home/linuxbrew/.linuxbrew/Cellar/xz/5.6.2",
+ "links": [
+ {
+ "source": "bin/xz",
+ "target": "bin/xz",
+ "type": "symlink"
+ }
+ ],
+ "package": "xz",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/xz.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "schema": 1,
+ "version": "5.6.2"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/metadata.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/metadata.json
new file mode 100644
index 000000000..30160c39a
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/metadata.json
@@ -0,0 +1,494 @@
+{
+ "generated_at": "2026-06-30T14:09:12Z",
+ "generator": "kandelo-homebrew-publish 1",
+ "kandelo_abi": 16,
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "packages": [
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T03:05:02Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "f0785634aa730b9e9d31700fa9341fb6cc6637589bb7a47cf7b5e3d2c6181639",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 62564,
+ "cache_key_sha": "49c19e83209e7954c9f8399262cd76d7e23868e4a022e4502f8668d4e0c9cd5f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/bzip2/blobs/sha256:98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/bzip2.json",
+ "formula_path": "Formula/bzip2.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/bzip2",
+ "name": "bzip2",
+ "version": "1.0.8"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:12Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "10131b1f653fee7727b06b6c0feed3d16b9edab6d156c183be3a3ee19fc61f4a",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 144268,
+ "cache_key_sha": "f1cf217ac3c91d7dddf9acfa101b6ea0c090fbbbb7abe064f31f601de2e11772",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/dash-0.5.12-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/dash/blobs/sha256:b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/dash.json",
+ "formula_path": "Formula/dash.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/dash",
+ "name": "dash",
+ "version": "0.5.12"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:13Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "0481f1947e92f1e08e785b5d8034cf1cf88c5cede0ee3e282f984f6429f43c95",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 202079,
+ "cache_key_sha": "e74be0eac8237d4345eb1db5c0c6d59aa0a20a54d7a603affeaa76190c7effc3",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/fbdoom/blobs/sha256:51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/fbdoom.json",
+ "formula_path": "Formula/fbdoom.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/fbdoom",
+ "name": "fbdoom",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:14Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "8c5b08ee978619bf49028174b88e65abd7e17a10bbc6a50aff7175600ce37a84",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 4718293,
+ "cache_key_sha": "4c43e2a22ab146ab7136937652d959824578d07927521a16329dbd8474e3e3b8",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/git-2.47.1-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/git/blobs/sha256:2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/git.json",
+ "formula_path": "Formula/git.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/git",
+ "name": "git",
+ "version": "2.47.1"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:15Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "eaa31a9603fb0b69b2d1415334e6559bc78273b16c2ef9ef00daf0aaf9a4c0d6",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 176495,
+ "cache_key_sha": "3ec5d016d15c7b316c6643d57f66cc2f4db4ed5726c3f30356c72fa9e15d6425",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/less-668-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/less/blobs/sha256:ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/less.json",
+ "formula_path": "Formula/less.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/less",
+ "name": "less",
+ "version": "668"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:16Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "46e2a45ef848a41db565070c445991a8d1d0b3b64ea839e796b0b33b78554541",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 35464,
+ "cache_key_sha": "88e06177e2acd7d54b78e9673812a7124712052ddda3599341dc208910a83b4f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/lsof/blobs/sha256:104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/lsof.json",
+ "formula_path": "Formula/lsof.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/lsof",
+ "name": "lsof",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:17Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "1747945d62ab174951721bc844fce55ffece7765ed123ed7ca3c449479d9d8a0",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 42724,
+ "cache_key_sha": "d3fc05bf7b73121ad1d49c447b755154ebff60f6e0baac959cf54107617aac66",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/modeset/blobs/sha256:48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/modeset.json",
+ "formula_path": "Formula/modeset.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/modeset",
+ "name": "modeset",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:20Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "969f255d25e14def893341bc3043e5eea8c2d2a0dfd3cccc5e43cdd5848e25a2",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 505439,
+ "cache_key_sha": "4be127352be19f0d75448a83769107716757e545aa4f3790dca8069a093aab59",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/nano-8.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/nano/blobs/sha256:5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/nano.json",
+ "formula_path": "Formula/nano.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/nano",
+ "name": "nano",
+ "version": "8.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:21Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "ffb676fee1246fca4785c061448dc6f6be25de4d34a8ceac427a1713e562a0a9",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 71472,
+ "cache_key_sha": "ecfdca45ff958a00f498d460f57df18b9de2e66ecac5d95aa7c346b3686a9409",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/netcat/blobs/sha256:2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/netcat.json",
+ "formula_path": "Formula/netcat.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/netcat",
+ "name": "netcat",
+ "version": "0.7.1"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "e0baeb2e530ebe112b576454901dca51d48bc862bf7ed2972b19821afe095c7b",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 7794122,
+ "cache_key_sha": "4a2a54d3a4c1052e2d484be6f8f25661bd233c49b9f0eecca5fd7040bcc222ba",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/vim/blobs/sha256:778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/vim.json",
+ "formula_path": "Formula/vim.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/vim",
+ "name": "vim",
+ "version": "9.1.0900"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T14:09:23Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "9ef07777d42633279dfd1317e118ddd868ed96c7e564cf53c91bd453f2da98fb",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 2456339,
+ "cache_key_sha": "17d7408ea85bf3a5e4e8d1e1630c5a157df613b2313a5c407b6e7c7a466d1c31",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/wget-1.25.0-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/wget/blobs/sha256:7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/wget.json",
+ "formula_path": "Formula/wget.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/wget",
+ "name": "wget",
+ "version": "1.25.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "built_at": "2026-06-30T03:00:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "built_from": {
+ "formula_sha256": "cb2d319d104ffc915cdc02d83fdc976849ae4a6bd33c195ba82cd4fd91645c96",
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "bytes": 379877,
+ "cache_key_sha": "6dcdd72b55ed0fbb6edc38c3854216da67579110efbaf56ee35803c7aec84027",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "fork_instrumentation": "not-required",
+ "kandelo_abi": 16,
+ "link_manifest": "Kandelo/link/xz-5.6.2-rebuild0-wasm32.json",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "sha256": "887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca",
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/xz/blobs/sha256:887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca"
+ }
+ ],
+ "dependencies": [],
+ "formula_metadata": "Kandelo/formula/xz.json",
+ "formula_path": "Formula/xz.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/xz",
+ "name": "xz",
+ "version": "5.6.2"
+ }
+ ],
+ "release_tag": "bottles-abi-v16",
+ "schema": 1,
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew"
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/bzip2-1.0.8-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/bzip2-1.0.8-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..5bc6b782d
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/bzip2-1.0.8-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 62564,
+ "cache_key_sha": "49c19e83209e7954c9f8399262cd76d7e23868e4a022e4502f8668d4e0c9cd5f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/bzip2/blobs/sha256:98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/bzip2.rb",
+ "sha256": "f0785634aa730b9e9d31700fa9341fb6cc6637589bb7a47cf7b5e3d2c6181639"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/bzip2.json",
+ "sha256": "2675f606bd2b0da1b8a6d51d58a308949c5e1177fb721c6388bc9091523dc97c"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json",
+ "sha256": "d6bf5e6292dc8e2c757e8acf71793f25675d0fe4fb25c9dfba0afe82a20d44eb"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/bzip2-1.0.8-rebuild0-wasm32.provenance.json",
+ "sha256": "8166fcdefb39e7248c0284a16e6edf50714b27eeb2f57806af33ac9b1840225f"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "bzip2",
+ "version": "1.0.8"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/bzip2.json",
+ "Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json",
+ "Kandelo/reports/bzip2-1.0.8-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran bzip2 --help through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "No successful browser VFS smoke was recorded for bzip2 wasm32.",
+ "skipped": [
+ "No successful browser VFS smoke was recorded for bzip2 wasm32."
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/dash-0.5.12-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/dash-0.5.12-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..2eb86d749
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/dash-0.5.12-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 144268,
+ "cache_key_sha": "f1cf217ac3c91d7dddf9acfa101b6ea0c090fbbbb7abe064f31f601de2e11772",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/dash/blobs/sha256:b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/dash.rb",
+ "sha256": "10131b1f653fee7727b06b6c0feed3d16b9edab6d156c183be3a3ee19fc61f4a"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/dash.json",
+ "sha256": "f518b7f65c41827e58dd2938409418db017005ebce8ed5a05f4fcaf40362a07b"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/dash-0.5.12-rebuild0-wasm32.json",
+ "sha256": "28de98099cba2d9786772805650501ea839491cc778fe55a6c96eb86f1f1e719"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/dash-0.5.12-rebuild0-wasm32.provenance.json",
+ "sha256": "441622942228d6fec1ebe1c3432dae916fb3cd9fe1994623851e5b4edf903611"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "dash",
+ "version": "0.5.12"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/dash.json",
+ "Kandelo/link/dash-0.5.12-rebuild0-wasm32.json",
+ "Kandelo/reports/dash-0.5.12-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran dash through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/fbdoom-0.1.0-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/fbdoom-0.1.0-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..89686b147
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/fbdoom-0.1.0-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 202079,
+ "cache_key_sha": "e74be0eac8237d4345eb1db5c0c6d59aa0a20a54d7a603affeaa76190c7effc3",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/fbdoom/blobs/sha256:51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/fbdoom.rb",
+ "sha256": "0481f1947e92f1e08e785b5d8034cf1cf88c5cede0ee3e282f984f6429f43c95"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/fbdoom.json",
+ "sha256": "5948f5ae1432784439a8bd644744a43f9a8683dafda34a3fb9866ec6017e80eb"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json",
+ "sha256": "638883c4808ab936c3bc491e9b4fd60338df42c81cee2dd2922f573d6089aa7c"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/fbdoom-0.1.0-rebuild0-wasm32.provenance.json",
+ "sha256": "b289977e36facc97ccf4d1c4cb07ff64acca406b1cd335e5a6b89f9050a93faf"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "fbdoom",
+ "version": "0.1.0"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/fbdoom.json",
+ "Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/fbdoom-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran fbdoom through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run locally: fbdoom requires IWAD data plus framebuffer/audio device validation",
+ "skipped": [
+ "browser smoke not run locally: fbdoom requires IWAD data plus framebuffer/audio device validation"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/git-2.47.1-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/git-2.47.1-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..61ca19d34
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/git-2.47.1-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 4718293,
+ "cache_key_sha": "4c43e2a22ab146ab7136937652d959824578d07927521a16329dbd8474e3e3b8",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/git/blobs/sha256:2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/git.rb",
+ "sha256": "8c5b08ee978619bf49028174b88e65abd7e17a10bbc6a50aff7175600ce37a84"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/git.json",
+ "sha256": "eb33fed5bd2a5699c91f7d471465687fa6b98df09d6c839a14698a07fb569d1f"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/git-2.47.1-rebuild0-wasm32.json",
+ "sha256": "1bfcd6157ac3f634bfb8be19af7c8c8cbfa4b1538e994002ef4cd70ea83ef1b0"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/git-2.47.1-rebuild0-wasm32.provenance.json",
+ "sha256": "bdc451c1a936bc49f3c26cf8bed75f4d9bca12b6def3cc2c825e5f761da35cef"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "git",
+ "version": "2.47.1"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/git.json",
+ "Kandelo/link/git-2.47.1-rebuild0-wasm32.json",
+ "Kandelo/reports/git-2.47.1-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran git through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/less-668-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/less-668-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..54d407e43
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/less-668-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 176495,
+ "cache_key_sha": "3ec5d016d15c7b316c6643d57f66cc2f4db4ed5726c3f30356c72fa9e15d6425",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/less/blobs/sha256:ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/less.rb",
+ "sha256": "eaa31a9603fb0b69b2d1415334e6559bc78273b16c2ef9ef00daf0aaf9a4c0d6"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/less.json",
+ "sha256": "912fe0bb071d14711d5d0197a1b12300e02c8d4982a2e25d87e83c79f5fdf716"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/less-668-rebuild0-wasm32.json",
+ "sha256": "e8a6fadc56f4c52250acad4befc6be27f0c6d6df2252a9276dd6b9abed2e2c1e"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/less-668-rebuild0-wasm32.provenance.json",
+ "sha256": "5182cac09e7d7fd6997efe5f3d58a43defab892247480553c338f79b36735081"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "less",
+ "version": "668"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/less.json",
+ "Kandelo/link/less-668-rebuild0-wasm32.json",
+ "Kandelo/reports/less-668-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran less through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/lsof-0.1.0-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/lsof-0.1.0-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..c5a3c8615
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/lsof-0.1.0-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 35464,
+ "cache_key_sha": "88e06177e2acd7d54b78e9673812a7124712052ddda3599341dc208910a83b4f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/lsof/blobs/sha256:104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/lsof.rb",
+ "sha256": "46e2a45ef848a41db565070c445991a8d1d0b3b64ea839e796b0b33b78554541"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/lsof.json",
+ "sha256": "7eaadb907c26ef704439979e31135ae9c7e07330c5c9271b73d513c13fcd321b"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json",
+ "sha256": "728bef278e609994fdef61d7ee6d48879225b01451dc68b3eb126a9ff68c2219"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/lsof-0.1.0-rebuild0-wasm32.provenance.json",
+ "sha256": "f5f406f76f358eb4c5444f0a880209dc770cbd3565380de2e6c9990dea390e9b"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "lsof",
+ "version": "0.1.0"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/lsof.json",
+ "Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/lsof-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran lsof through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/modeset-0.1.0-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/modeset-0.1.0-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..0b5e571e2
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/modeset-0.1.0-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 42724,
+ "cache_key_sha": "d3fc05bf7b73121ad1d49c447b755154ebff60f6e0baac959cf54107617aac66",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/modeset/blobs/sha256:48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/modeset.rb",
+ "sha256": "1747945d62ab174951721bc844fce55ffece7765ed123ed7ca3c449479d9d8a0"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/modeset.json",
+ "sha256": "37e060ca66457d3947c18f1c801f3efcedbab9f57756055e008d789e3f9f2edb"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json",
+ "sha256": "da475ddcb7bcfaec1c9ad88cb707ca0a95d18ee603215fe4aabf88b1aaa644c8"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/modeset-0.1.0-rebuild0-wasm32.provenance.json",
+ "sha256": "d1eb94bcbb400d35eec05a7c942898a6baee839ca1504c174f2feb32d9989c40"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "modeset",
+ "version": "0.1.0"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/modeset.json",
+ "Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/modeset-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran modeset through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run locally: modeset requires DRI/GLES framebuffer/device validation",
+ "skipped": [
+ "browser smoke not run locally: modeset requires DRI/GLES framebuffer/device validation"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/nano-8.0-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/nano-8.0-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..11c16337f
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/nano-8.0-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 505439,
+ "cache_key_sha": "4be127352be19f0d75448a83769107716757e545aa4f3790dca8069a093aab59",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/nano/blobs/sha256:5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/nano.rb",
+ "sha256": "969f255d25e14def893341bc3043e5eea8c2d2a0dfd3cccc5e43cdd5848e25a2"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/nano.json",
+ "sha256": "5320b50e32f7469886c9a66738f317b74c1d547fd5090a04665e74b6a708eb29"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/nano-8.0-rebuild0-wasm32.json",
+ "sha256": "123fe970d640a892b8ff526dd9d4f7ec6ed7865bb9fdf492433df2af334441c2"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/nano-8.0-rebuild0-wasm32.provenance.json",
+ "sha256": "c6a5425b54e0bcef0bae04dd47d2688ec3be7b43beab4201d95ce5954d675298"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "nano",
+ "version": "8.0"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/nano.json",
+ "Kandelo/link/nano-8.0-rebuild0-wasm32.json",
+ "Kandelo/reports/nano-8.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran nano through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/netcat-0.7.1-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/netcat-0.7.1-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..15bc0cd0f
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/netcat-0.7.1-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 71472,
+ "cache_key_sha": "ecfdca45ff958a00f498d460f57df18b9de2e66ecac5d95aa7c346b3686a9409",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/netcat/blobs/sha256:2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/netcat.rb",
+ "sha256": "ffb676fee1246fca4785c061448dc6f6be25de4d34a8ceac427a1713e562a0a9"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/netcat.json",
+ "sha256": "53fa6c7d3f18c17d04bf86eb8d7c7bbfde683c89ceeb011d1c8c4da494b1cac7"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json",
+ "sha256": "08e22da6626926b0339ca5e26ad7b4a253ed2ea1044ce936e056afad7f892758"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/netcat-0.7.1-rebuild0-wasm32.provenance.json",
+ "sha256": "87691824474390dff2a1485abf8aca15aad0c9123e5fc1c4a40182759c0b2272"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "netcat",
+ "version": "0.7.1"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/netcat.json",
+ "Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json",
+ "Kandelo/reports/netcat-0.7.1-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran nc through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/vim-9.1.0900-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/vim-9.1.0900-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..ff27cdb63
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/vim-9.1.0900-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 7794122,
+ "cache_key_sha": "4a2a54d3a4c1052e2d484be6f8f25661bd233c49b9f0eecca5fd7040bcc222ba",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/vim/blobs/sha256:778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/vim.rb",
+ "sha256": "e0baeb2e530ebe112b576454901dca51d48bc862bf7ed2972b19821afe095c7b"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/vim.json",
+ "sha256": "47d2e2a6229d1fd3c277f0151b49a0386b94aa93d6153c6f5fe2e60e4f241e47"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json",
+ "sha256": "89dfb3608c1ec96d07556269b4df48a6103934d2a876c1d6213f046690bc329d"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/vim-9.1.0900-rebuild0-wasm32.provenance.json",
+ "sha256": "5dd1de15effdca911f833944c142171fe73c2b0de7391e2704bb7b99ecd14f48"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "vim",
+ "version": "9.1.0900"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/vim.json",
+ "Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json",
+ "Kandelo/reports/vim-9.1.0900-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran vim through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/wget-1.25.0-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/wget-1.25.0-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..6536d9080
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/wget-1.25.0-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 2456339,
+ "cache_key_sha": "17d7408ea85bf3a5e4e8d1e1630c5a157df613b2313a5c407b6e7c7a466d1c31",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/wget/blobs/sha256:7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/wget.rb",
+ "sha256": "9ef07777d42633279dfd1317e118ddd868ed96c7e564cf53c91bd453f2da98fb"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/wget.json",
+ "sha256": "36149dc08a4c02933ddccce4ee1cc7fb19d08fe8fba6f879c0940acd4f62d027"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/wget-1.25.0-rebuild0-wasm32.json",
+ "sha256": "c232efd23bd33b8395c05ff2943a05b1ac330dc2f37314a0fd8f126e2beedd32"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/wget-1.25.0-rebuild0-wasm32.provenance.json",
+ "sha256": "800b02127fd2e655e1f75e37b8112fdb918f72d60f8bc8d0c5634df2ab07e0df"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "wget",
+ "version": "1.25.0"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/wget.json",
+ "Kandelo/link/wget-1.25.0-rebuild0-wasm32.json",
+ "Kandelo/reports/wget-1.25.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran wget through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/xz-5.6.2-rebuild0-wasm32.provenance.json b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/xz-5.6.2-rebuild0-wasm32.provenance.json
new file mode 100644
index 000000000..d76eab842
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/reports/xz-5.6.2-rebuild0-wasm32.provenance.json
@@ -0,0 +1,113 @@
+{
+ "bottle": {
+ "bottle_tag": "wasm32_kandelo",
+ "bytes": 379877,
+ "cache_key_sha": "6dcdd72b55ed0fbb6edc38c3854216da67579110efbaf56ee35803c7aec84027",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "sha256": "887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/xz/blobs/sha256:887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca"
+ },
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "formula": {
+ "path": "Formula/xz.rb",
+ "sha256": "cb2d319d104ffc915cdc02d83fdc976849ae4a6bd33c195ba82cd4fd91645c96"
+ },
+ "metadata": {
+ "formula_json": {
+ "path": "Kandelo/formula/xz.json",
+ "sha256": "30b34cc85afe5691967e9fcefbb654a98e1f26c44f859e204a0524faa0b15aa6"
+ },
+ "link_manifest_json": {
+ "path": "Kandelo/link/xz-5.6.2-rebuild0-wasm32.json",
+ "sha256": "3f4215c770eacbde736e56b19823017466c6174453beff421321df5ad9dc9f85"
+ },
+ "metadata_json": {
+ "path": "Kandelo/metadata.json",
+ "sha256": "09973d75c369f192036c606ed88ee777e5a82f1a7475d9edfd7fb14f49683e38"
+ },
+ "provenance_json": {
+ "path": "Kandelo/reports/xz-5.6.2-rebuild0-wasm32.provenance.json",
+ "sha256": "2245062545e2a59af5739ce298825d1a7d138e018411af435362fb359908dbc8"
+ }
+ },
+ "repositories": {
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_repository": "Automattic/kandelo-homebrew"
+ },
+ "schema": 1,
+ "subject": {
+ "arch": "wasm32",
+ "bottle_rebuild": 0,
+ "kandelo_abi": 16,
+ "package": "xz",
+ "version": "5.6.2"
+ },
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/xz.json",
+ "Kandelo/link/xz-5.6.2-rebuild0-wasm32.json",
+ "Kandelo/reports/xz-5.6.2-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran xz --version through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "No successful browser VFS smoke was recorded for xz wasm32.",
+ "skipped": [
+ "No successful browser VFS smoke was recorded for xz wasm32."
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+}
diff --git a/test-runs/kd-0hns/rootfs-shell-tap/sidecars-input.json b/test-runs/kd-0hns/rootfs-shell-tap/sidecars-input.json
new file mode 100644
index 000000000..9896754d6
--- /dev/null
+++ b/test-runs/kd-0hns/rootfs-shell-tap/sidecars-input.json
@@ -0,0 +1,1351 @@
+{
+ "generated_at": "2026-06-30T14:09:12Z",
+ "generator": "kandelo-homebrew-publish 1",
+ "kandelo_abi": 16,
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "packages": [
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/dash-wasm32/bottles/dash--0.5.12.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:12Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "f1cf217ac3c91d7dddf9acfa101b6ea0c090fbbbb7abe064f31f601de2e11772",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/dash",
+ "target": "bin/dash",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "dash/0.5.12",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/dash.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/dash/blobs/sha256:b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/dash.json",
+ "Kandelo/link/dash-0.5.12-rebuild0-wasm32.json",
+ "Kandelo/reports/dash-0.5.12-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran dash through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/dash.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/dash",
+ "name": "dash",
+ "version": "0.5.12"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/git-wasm32/bottles/git--2.47.1.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:14Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4c43e2a22ab146ab7136937652d959824578d07927521a16329dbd8474e3e3b8",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/git",
+ "target": "bin/git",
+ "type": "symlink"
+ },
+ {
+ "source": "bin/git-remote-http",
+ "target": "bin/git-remote-http",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "git/2.47.1",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/git.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/git/blobs/sha256:2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/git.json",
+ "Kandelo/link/git-2.47.1-rebuild0-wasm32.json",
+ "Kandelo/reports/git-2.47.1-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran git through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/git.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/git",
+ "name": "git",
+ "version": "2.47.1"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/vim-wasm32/bottles/vim--9.1.0900.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4a2a54d3a4c1052e2d484be6f8f25661bd233c49b9f0eecca5fd7040bcc222ba",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/vim",
+ "target": "bin/vim",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "vim/9.1.0900",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/vim.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/vim/blobs/sha256:778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/vim.json",
+ "Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json",
+ "Kandelo/reports/vim-9.1.0900-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran vim through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/vim.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/vim",
+ "name": "vim",
+ "version": "9.1.0900"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/less-wasm32/bottles/less--668.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:15Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "3ec5d016d15c7b316c6643d57f66cc2f4db4ed5726c3f30356c72fa9e15d6425",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/less",
+ "target": "bin/less",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "less/668",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/less.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/less/blobs/sha256:ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/less.json",
+ "Kandelo/link/less-668-rebuild0-wasm32.json",
+ "Kandelo/reports/less-668-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran less through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/less.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/less",
+ "name": "less",
+ "version": "668"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/lsof-wasm32/bottles/lsof--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:16Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "88e06177e2acd7d54b78e9673812a7124712052ddda3599341dc208910a83b4f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/lsof",
+ "target": "bin/lsof",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "lsof/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/lsof.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/lsof/blobs/sha256:104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/lsof.json",
+ "Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/lsof-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran lsof through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/lsof.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/lsof",
+ "name": "lsof",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/modeset-wasm32/bottles/modeset--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:17Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "d3fc05bf7b73121ad1d49c447b755154ebff60f6e0baac959cf54107617aac66",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/modeset",
+ "target": "bin/modeset",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "modeset/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/modeset.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/modeset/blobs/sha256:48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/modeset.json",
+ "Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/modeset-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran modeset through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run locally: modeset requires DRI/GLES framebuffer/device validation",
+ "skipped": [
+ "browser smoke not run locally: modeset requires DRI/GLES framebuffer/device validation"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/modeset.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/modeset",
+ "name": "modeset",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/nano-wasm32/bottles/nano--8.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:20Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4be127352be19f0d75448a83769107716757e545aa4f3790dca8069a093aab59",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/nano",
+ "target": "bin/nano",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "nano/8.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/nano.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/nano/blobs/sha256:5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/nano.json",
+ "Kandelo/link/nano-8.0-rebuild0-wasm32.json",
+ "Kandelo/reports/nano-8.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran nano through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/nano.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/nano",
+ "name": "nano",
+ "version": "8.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/netcat-wasm32/bottles/netcat--0.7.1.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:21Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "ecfdca45ff958a00f498d460f57df18b9de2e66ecac5d95aa7c346b3686a9409",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/nc",
+ "target": "bin/nc",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "netcat/0.7.1",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/netcat.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/netcat/blobs/sha256:2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/netcat.json",
+ "Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json",
+ "Kandelo/reports/netcat-0.7.1-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran nc through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/netcat.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/netcat",
+ "name": "netcat",
+ "version": "0.7.1"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/wget-wasm32/bottles/wget--1.25.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:23Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "17d7408ea85bf3a5e4e8d1e1630c5a157df613b2313a5c407b6e7c7a466d1c31",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/wget",
+ "target": "bin/wget",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "wget/1.25.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/wget.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/wget/blobs/sha256:7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/wget.json",
+ "Kandelo/link/wget-1.25.0-rebuild0-wasm32.json",
+ "Kandelo/reports/wget-1.25.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran wget through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/wget.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/wget",
+ "name": "wget",
+ "version": "1.25.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/fbdoom-wasm32/bottles/fbdoom--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:13Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "e74be0eac8237d4345eb1db5c0c6d59aa0a20a54d7a603affeaa76190c7effc3",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/fbdoom",
+ "target": "bin/fbdoom",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "fbdoom/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/fbdoom.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/fbdoom/blobs/sha256:51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/fbdoom.json",
+ "Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/fbdoom-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran fbdoom through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run locally: fbdoom requires IWAD data plus framebuffer/audio device validation",
+ "skipped": [
+ "browser smoke not run locally: fbdoom requires IWAD data plus framebuffer/audio device validation"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/fbdoom.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/fbdoom",
+ "name": "fbdoom",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.2-port-sqlite-bzip2-and-xz-homebrew-pilot/test-runs/kd-1mr.2/homebrew-bottles/bzip2-wasm32/bottles/bzip2--1.0.8.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T03:05:02Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "49c19e83209e7954c9f8399262cd76d7e23868e4a022e4502f8668d4e0c9cd5f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/bzip2",
+ "target": "bin/bzip2",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "bzip2/1.0.8",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/bzip2.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/bzip2/blobs/sha256:98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/bzip2.json",
+ "Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json",
+ "Kandelo/reports/bzip2-1.0.8-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran bzip2 --help through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "No successful browser VFS smoke was recorded for bzip2 wasm32.",
+ "skipped": [
+ "No successful browser VFS smoke was recorded for bzip2 wasm32."
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/bzip2.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/bzip2",
+ "name": "bzip2",
+ "version": "1.0.8"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.2-port-sqlite-bzip2-and-xz-homebrew-pilot/test-runs/kd-1mr.2/homebrew-bottles/xz-wasm32/bottles/xz--5.6.2.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T03:00:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "6dcdd72b55ed0fbb6edc38c3854216da67579110efbaf56ee35803c7aec84027",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/xz",
+ "target": "bin/xz",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "xz/5.6.2",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/xz.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/xz/blobs/sha256:887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/xz.json",
+ "Kandelo/link/xz-5.6.2-rebuild0-wasm32.json",
+ "Kandelo/reports/xz-5.6.2-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran xz --version through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "No successful browser VFS smoke was recorded for xz wasm32.",
+ "skipped": [
+ "No successful browser VFS smoke was recorded for xz wasm32."
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/xz.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/xz",
+ "name": "xz",
+ "version": "5.6.2"
+ }
+ ],
+ "release_tag": "bottles-abi-v16",
+ "schema": 1,
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew"
+}
diff --git a/test-runs/kd-1mr.5/DISPOSITION.md b/test-runs/kd-1mr.5/DISPOSITION.md
new file mode 100644
index 000000000..e00049b7f
--- /dev/null
+++ b/test-runs/kd-1mr.5/DISPOSITION.md
@@ -0,0 +1,137 @@
+# kd-1mr.5 -- Browser Runtime Certification for the rootfs/shell Homebrew package set
+
+Bead: kd-1mr.5 (umbrella kd-1mr / initiative homebrew-all)
+Session: kg-ydrd / porter-adhoc-49d9da88f8
+Generated: 2026-07-01T07:00Z
+Worktree: `/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell`
+Branch: `gascity/kd-1mr/kd-1mr.5-certify-browser-rootfs-shell` (stacks on kd-0hns tap @ 37bcd20d8 + kd-v3fs browser tooling)
+Tap under certification: `test-runs/kd-0hns/rootfs-shell-tap` (the kd-0hns repaired 12-package tap)
+
+## Summary
+
+Ran wasm32 in-browser smokes (Chromium via Playwright, BrowserKernel) for all 12
+rootfs/shell packages. **10 of 12 certified `browser_compatible=true`** with
+recorded smoke evidence; **2 skipped with reason_code** (framebuffer/device
+programs). The corrected sidecars pass `homebrew-validate`. Re-running
+`homebrew-composite-status` shows the `browser_compatible=false` blocker for
+these 12 is resolved and moves **vim-browser-bundle/browser from skip -> pass**.
+
+| Package | Bottle sha (recorded) | Browser smoke | Disposition |
+|---|---|---|---|
+| dash | b07b39e7 | `dash -c 'echo dash_browser_smoke_ok'` -> ok | CERTIFIED browser_compatible=true |
+| git | 2ba2c7ce | `git --version` -> "git version" | CERTIFIED |
+| vim | 778be8fe | `vim --version` -> "VIM - Vi IMproved" | CERTIFIED |
+| less | ee879901 | `less --version` -> "less" | CERTIFIED |
+| lsof | 104cc2d3 | `lsof -h` -> "Usage: lsof ..." | CERTIFIED |
+| nano | 5c9724ce | `nano --version` -> "GNU nano" | CERTIFIED |
+| netcat | 2eec1a03 | `nc -h` -> GNU netcat banner | CERTIFIED |
+| wget | 7d7b48ed | `wget --version` -> "GNU Wget" | CERTIFIED |
+| bzip2 | 98468e8b | `bzip2 --help` -> "bzip2" | CERTIFIED |
+| xz | 887c92f5 | `xz --version` -> "xz" | CERTIFIED |
+| modeset | 48002a33 | SKIP (reason_code: framebuffer-device-required) | browser_compatible=false |
+| fbdoom | 51f8e3d2 | SKIP (reason_code: framebuffer-and-iwad-required) | browser_compatible=false |
+
+## reason_codes (packages that genuinely cannot run in the terminal browser smoke)
+
+- **modeset** -- `framebuffer-device-required`: modeset requires a DRI/GLES
+ framebuffer device (`/dev/dri`) not provided by the non-interactive terminal
+ Homebrew browser smoke. Certify via a dedicated browser framebuffer/device smoke.
+- **fbdoom** -- `framebuffer-and-iwad-required`: fbdoom requires IWAD game data
+ and a framebuffer/audio device (`/dev/fb0`). Certify via a dedicated browser
+ framebuffer smoke.
+
+Both mirror the Node smoke's framebuffer skips (kd-v3fs `vim-node-smoke-20260701`:
+"22 pass / 0 fail / 2 framebuffer skip"). Encoded in code as
+`browserFormulaUnsupportedReason()` in `scripts/homebrew-package-smoke-cases.ts`,
+so the browser smoke records them as skip-with-reason rather than failures.
+NOTE: the reason_code is not stored in the sidecar bottle because this worktree's
+(kd-0hns-based) `formula.schema.json` does not permit `runtime_status` in formula
+bottles; the sidecar records `browser_compatible=false` and the reason_code lives
+in this artifact + the runner code + the smoke `summary.json`. Follow-up: when the
+kd-v3fs `formula.schema.json` (which permits `runtime_status`) is the tap schema,
+record `runtime_status.browser={status:"unsupported", reason_code, reason}` in-sidecar.
+
+## Method
+
+1. Toolchain: root/host/apps `npm ci`; `npx playwright install chromium`;
+ `./run.sh build kernel` -> `local-binaries/kernel.wasm` (ABI 16); a prebuilt
+ `rootfs.vfs` staged at `local-binaries/rootfs.vfs` (only needed to satisfy the
+ browser-kernel `@rootfs-vfs` import; the homebrew-smoke page pours its own VFS).
+2. Bottle bytes: the kd-0hns/kd-bry6 bottles were not persisted in a sha-named
+ cache. Located the originals in
+ `kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/-wasm32/bottles/`
+ and verified **all 10 match the recorded sidecar sha256** (+ bzip2/xz from the
+ kd-1mr.2 pilot cache). Staged into a sha-keyed `--bottle-cache`, so smokes run
+ against the exact recorded bottles (no sidecar sha/url changes).
+3. Browser smoke: `npx tsx scripts/homebrew-package-browser-smoke.ts --tap-root
+ test-runs/kd-0hns/rootfs-shell-tap --formula <...> --arch wasm32 --bottle-cache
+ --result-dir test-runs/kd-1mr.5/browser-smoke`. Each package: build a
+ candidate wasm32 VFS from the sidecar + bottle bytes, boot through BrowserKernel
+ in headless Chromium, run the package smoke command, assert exit 0 + expected output.
+4. Sidecar update: edited the generation input's per-bottle `browser_compatible` +
+ `runtime_support` for the 10 certified packages, then **regenerated the tap** via
+ `cargo xtask homebrew-sidecars` (recomputes provenance metadata/formula/link shas).
+ This is the sanctioned path (hand-editing breaks provenance shas).
+
+## Verification
+
+- Browser smoke (`test-runs/kd-1mr.5/browser-smoke/summary.json`): **23 pass / 0
+ fail / 2 skip** (12 VFS builds + browser_server_start + 10 exec pass + 2 skip).
+ Outcome lists under `browser-smoke/outcome-lists/`; per-package terminal captures
+ under `browser-smoke/-wasm32/`.
+- Sidecar validation: `cargo xtask homebrew-validate --tap-root
+ test-runs/kd-0hns/rootfs-shell-tap` -> **`homebrew-validate: ok (packages=12,
+ bottles=12, link_manifests=12, provenance_reports=12)`**.
+- Composite status (`test-runs/kd-1mr.5/composite-status[-enriched]/`):
+ - Single-tap (12 pkgs): 2 pass / 0 fail / 14 skip; **no browser_compatible
+ blocker cites any of the 12 packages** (browser support corrected).
+ - Enriched (kd-0hns + kd-0k6q core metadata), browser runtime: **vim-browser-bundle
+ /browser PASS**; rootfs/browser blocked only on `bash`,`ncurses`; shell/browser
+ blocked on `bash`,`ncurses`,`curl`,`nethack` (all kd-1mr.4) + `fbdoom`,`modeset`
+ (framebuffer reason_codes).
+
+## Effect on kd-v3fs browser tier
+
+- **vim-browser-bundle/browser: UNBLOCKED** (skip -> pass) by vim browser certification.
+- **rootfs/browser**: browser blocker for its rootfs/shell members resolved; now
+ gated only on `bash` + `ncurses` (kd-1mr.4, no Formula yet).
+- **shell/browser**: gated on `bash`,`ncurses`,`curl`,`nethack` (kd-1mr.4) plus
+ `fbdoom`,`modeset` (need a dedicated framebuffer browser smoke -- follow-up).
+- python-vfs/perl-vfs/erlang-vfs/browser: unchanged, still blocked on
+ cpython/perl/erlang (kd-yuef, parked on trusted GHCR bottle publish).
+
+## Artifacts (committed under test-runs/kd-1mr.5/, .vfs.zst images gitignored)
+
+- `browser-smoke/summary.json`, `summary.md`, `outcome-lists/{passed,failed,skipped}-tests.tsv`,
+ per-package `*-terminal.txt` / `*-vfs-report.json`.
+- `composite-status/` and `composite-status-enriched/` summary + outcome-lists.
+- `sidecars-input.json` (edited generation input used to regenerate the tap).
+- Updated tap: `test-runs/kd-0hns/rootfs-shell-tap/Kandelo/{metadata.json,formula/*,reports/*}`.
+
+## Code changes (mine)
+
+- `scripts/homebrew-package-smoke-cases.ts`: browser smoke cases for `dash` (shell
+ command), `lsof` (`-h`), `netcat` (`nc -h`); `browserFormulaUnsupportedReason()`
+ for modeset/fbdoom.
+- `scripts/homebrew-package-browser-smoke.ts`: skip device-dependent formulae with
+ the reason_code (mirrors the arch-unsupported skip path).
+
+## Stacking / provenance note
+
+This branch is based on kd-0hns (the rootfs-shell tap) and brings in the kd-v3fs
+browser tooling (`homebrew-package-browser-smoke.ts`, `homebrew-composite-status.ts`,
+`homebrew-package-smoke-cases.ts`, `homebrew-smoke-outcomes.ts`,
+`apps/browser-demos/pages/homebrew-smoke/*`, `homebrew-vfs-planner.ts`,
+`vite.config.ts`) so the smokes can run. Those tooling files are kd-v3fs's and
+will dedupe when kd-v3fs merges; the net kd-1mr.5 contribution is the browser
+certification (sidecar updates), the tailored smoke cases + framebuffer skip logic,
+and the evidence artifacts.
+
+## Follow-ups
+
+1. Dedicated **browser framebuffer/device smoke** for modeset + fbdoom (and a
+ node/browser framebuffer harness), to certify the graphical rootfs/shell members.
+2. Adopt the kd-v3fs `formula.schema.json` (permits `runtime_status`) as the tap
+ schema so browser reason_codes are recorded in-sidecar, not only in artifacts.
+3. shell/browser + rootfs/browser full pass depend on kd-1mr.4 landing
+ bash/ncurses/curl/nethack Formulae.
diff --git a/test-runs/kd-1mr.5/browser-smoke/current-run.json b/test-runs/kd-1mr.5/browser-smoke/current-run.json
new file mode 100644
index 000000000..7ba62df55
--- /dev/null
+++ b/test-runs/kd-1mr.5/browser-smoke/current-run.json
@@ -0,0 +1,74 @@
+{
+ "suite": "homebrew-package-browser-smoke",
+ "bead_id": "kd-1mr.5",
+ "worktree": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell",
+ "result_dir": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke",
+ "status": "complete",
+ "started_at": "2026-07-01T06:43:48.112Z",
+ "updated_at": "2026-07-01T06:44:46.536Z",
+ "current_case": "complete",
+ "progress": {
+ "completed": 25,
+ "total": 25,
+ "pass": 23,
+ "fail": 0,
+ "skip": 2
+ },
+ "tap_root": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-0hns/rootfs-shell-tap",
+ "tap_commit": "37bcd20d847101859641daf6e4583c70d634cfae",
+ "command": {
+ "cwd": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell",
+ "argv": [
+ "/Users/brandon/.nvm/versions/node/v24.15.0/bin/node",
+ "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/scripts/homebrew-package-browser-smoke.ts",
+ "--tap-root",
+ "test-runs/kd-0hns/rootfs-shell-tap",
+ "--formula",
+ "dash",
+ "--formula",
+ "git",
+ "--formula",
+ "vim",
+ "--formula",
+ "less",
+ "--formula",
+ "lsof",
+ "--formula",
+ "modeset",
+ "--formula",
+ "nano",
+ "--formula",
+ "netcat",
+ "--formula",
+ "wget",
+ "--formula",
+ "fbdoom",
+ "--formula",
+ "bzip2",
+ "--formula",
+ "xz",
+ "--arch",
+ "wasm32",
+ "--port",
+ "58172",
+ "--timeout-ms",
+ "45000",
+ "--result-dir",
+ "test-runs/kd-1mr.5/browser-smoke",
+ "--bottle-cache",
+ "test-runs/kd-1mr.5/bottle-cache",
+ "--bead-id",
+ "kd-1mr.5"
+ ]
+ },
+ "outcome_lists": {
+ "passed": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/outcome-lists/passed-tests.tsv",
+ "failed": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/outcome-lists/failed-tests.tsv",
+ "skipped": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/outcome-lists/skipped-tests.tsv"
+ },
+ "stale_no_runner_threshold_seconds": 900,
+ "expected_next": {
+ "deterministic": false,
+ "action": "suite terminal"
+ }
+}
diff --git a/test-runs/kd-1mr.5/browser-smoke/failures.json b/test-runs/kd-1mr.5/browser-smoke/failures.json
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/test-runs/kd-1mr.5/browser-smoke/failures.json
@@ -0,0 +1 @@
+[]
diff --git a/test-runs/kd-1mr.5/browser-smoke/outcome-lists/failed-tests.tsv b/test-runs/kd-1mr.5/browser-smoke/outcome-lists/failed-tests.tsv
new file mode 100644
index 000000000..f89d46ccc
--- /dev/null
+++ b/test-runs/kd-1mr.5/browser-smoke/outcome-lists/failed-tests.tsv
@@ -0,0 +1 @@
+test duration_ms error artifact_path
diff --git a/test-runs/kd-1mr.5/browser-smoke/outcome-lists/passed-tests.tsv b/test-runs/kd-1mr.5/browser-smoke/outcome-lists/passed-tests.tsv
new file mode 100644
index 000000000..4ac77a029
--- /dev/null
+++ b/test-runs/kd-1mr.5/browser-smoke/outcome-lists/passed-tests.tsv
@@ -0,0 +1,24 @@
+test duration_ms details artifact_path
+homebrew_browser_vfs_build_dash 491 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32
+homebrew_browser_vfs_build_git 10024 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32
+homebrew_browser_vfs_build_vim 21984 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32
+homebrew_browser_vfs_build_less 418 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32
+homebrew_browser_vfs_build_lsof 260 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32
+homebrew_browser_vfs_build_modeset 265 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/modeset-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32
+homebrew_browser_vfs_build_nano 873 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32
+homebrew_browser_vfs_build_netcat 280 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32
+homebrew_browser_vfs_build_wget 4733 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32
+homebrew_browser_vfs_build_fbdoom 387 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/fbdoom-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32
+homebrew_browser_vfs_build_bzip2 306 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32
+homebrew_browser_vfs_build_xz 614 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32
+browser_server_start 2868 vite=http://127.0.0.1:58172; channel=chromium /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log
+browser_smoke_dash_dash_command 1960 command=/home/linuxbrew/.linuxbrew/bin/dash -c echo dash_browser_smoke_ok; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash_command-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash_command-terminal.txt
+browser_smoke_git_git_version 1527 command=/home/linuxbrew/.linuxbrew/bin/git --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git_version-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git_version-terminal.txt
+browser_smoke_vim_vim_version 1956 command=/home/linuxbrew/.linuxbrew/bin/vim --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim_version-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim_version-terminal.txt
+browser_smoke_less_less_version 1369 command=/home/linuxbrew/.linuxbrew/bin/less --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less_version-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less_version-terminal.txt
+browser_smoke_lsof_lsof_help 1387 command=/home/linuxbrew/.linuxbrew/bin/lsof -h; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof_help-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof_help-terminal.txt
+browser_smoke_nano_nano_version 1292 command=/home/linuxbrew/.linuxbrew/bin/nano --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano_version-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano_version-terminal.txt
+browser_smoke_netcat_netcat_help 1306 command=/home/linuxbrew/.linuxbrew/bin/nc -h; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat_help-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat_help-terminal.txt
+browser_smoke_wget_wget_version 1426 command=/home/linuxbrew/.linuxbrew/bin/wget --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget_version-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget_version-terminal.txt
+browser_smoke_bzip2_bzip2_help 1269 command=/home/linuxbrew/.linuxbrew/bin/bzip2 --help; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2_help-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2_help-terminal.txt
+browser_smoke_xz_xz_version 1246 command=/home/linuxbrew/.linuxbrew/bin/xz --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz_version-terminal.txt /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz_version-terminal.txt
diff --git a/test-runs/kd-1mr.5/browser-smoke/outcome-lists/skipped-tests.tsv b/test-runs/kd-1mr.5/browser-smoke/outcome-lists/skipped-tests.tsv
new file mode 100644
index 000000000..bfc9fa477
--- /dev/null
+++ b/test-runs/kd-1mr.5/browser-smoke/outcome-lists/skipped-tests.tsv
@@ -0,0 +1,3 @@
+test reason artifact_path
+browser_smoke_modeset_unsupported modeset requires a DRI/GLES framebuffer device (/dev/dri) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer/device smoke /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-unsupported.txt
+browser_smoke_fbdoom_unsupported fbdoom requires IWAD game data and a framebuffer/audio device (/dev/fb0) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer smoke /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-unsupported.txt
diff --git a/test-runs/kd-1mr.5/browser-smoke/summary.json b/test-runs/kd-1mr.5/browser-smoke/summary.json
new file mode 100644
index 000000000..eced81e58
--- /dev/null
+++ b/test-runs/kd-1mr.5/browser-smoke/summary.json
@@ -0,0 +1,545 @@
+{
+ "suite": "Homebrew package browser VFS smoke",
+ "bead_id": "kd-1mr.5",
+ "started_at": "2026-07-01T06:43:48.112Z",
+ "completed_at": "2026-07-01T06:44:46.530Z",
+ "duration_ms": 58418,
+ "result_dir": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke",
+ "tap_root": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-0hns/rootfs-shell-tap",
+ "tap_commit": "37bcd20d847101859641daf6e4583c70d634cfae",
+ "arch": "wasm32",
+ "formulas": [
+ "dash",
+ "git",
+ "vim",
+ "less",
+ "lsof",
+ "modeset",
+ "nano",
+ "netcat",
+ "wget",
+ "fbdoom",
+ "bzip2",
+ "xz"
+ ],
+ "counts": {
+ "pass": 23,
+ "fail": 0,
+ "skip": 2
+ },
+ "outcomes": [
+ {
+ "name": "homebrew_browser_vfs_build_dash",
+ "status": "pass",
+ "durationMs": 491,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_git",
+ "status": "pass",
+ "durationMs": 10024,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_vim",
+ "status": "pass",
+ "durationMs": 21984,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_less",
+ "status": "pass",
+ "durationMs": 418,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_lsof",
+ "status": "pass",
+ "durationMs": 260,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_modeset",
+ "status": "pass",
+ "durationMs": 265,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/modeset-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_nano",
+ "status": "pass",
+ "durationMs": 873,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_netcat",
+ "status": "pass",
+ "durationMs": 280,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_wget",
+ "status": "pass",
+ "durationMs": 4733,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_fbdoom",
+ "status": "pass",
+ "durationMs": 387,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/fbdoom-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_bzip2",
+ "status": "pass",
+ "durationMs": 306,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32"
+ },
+ {
+ "name": "homebrew_browser_vfs_build_xz",
+ "status": "pass",
+ "durationMs": 614,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32"
+ },
+ {
+ "name": "browser_server_start",
+ "status": "pass",
+ "durationMs": 2868,
+ "details": "vite=http://127.0.0.1:58172; channel=chromium",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log"
+ },
+ {
+ "name": "browser_smoke_dash_dash_command",
+ "status": "pass",
+ "durationMs": 1960,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/dash -c echo dash_browser_smoke_ok; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash_command-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash_command-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_git_git_version",
+ "status": "pass",
+ "durationMs": 1527,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/git --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git_version-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git_version-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_vim_vim_version",
+ "status": "pass",
+ "durationMs": 1956,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/vim --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim_version-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim_version-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_less_less_version",
+ "status": "pass",
+ "durationMs": 1369,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/less --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less_version-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less_version-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_lsof_lsof_help",
+ "status": "pass",
+ "durationMs": 1387,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/lsof -h; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof_help-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof_help-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_modeset_unsupported",
+ "status": "skip",
+ "durationMs": 0,
+ "details": "modeset requires a DRI/GLES framebuffer device (/dev/dri) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer/device smoke",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-unsupported.txt"
+ },
+ {
+ "name": "browser_smoke_nano_nano_version",
+ "status": "pass",
+ "durationMs": 1292,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/nano --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano_version-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano_version-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_netcat_netcat_help",
+ "status": "pass",
+ "durationMs": 1306,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/nc -h; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat_help-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat_help-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_wget_wget_version",
+ "status": "pass",
+ "durationMs": 1426,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/wget --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget_version-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget_version-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_fbdoom_unsupported",
+ "status": "skip",
+ "durationMs": 0,
+ "details": "fbdoom requires IWAD game data and a framebuffer/audio device (/dev/fb0) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer smoke",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-unsupported.txt"
+ },
+ {
+ "name": "browser_smoke_bzip2_bzip2_help",
+ "status": "pass",
+ "durationMs": 1269,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/bzip2 --help; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2_help-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2_help-terminal.txt"
+ },
+ {
+ "name": "browser_smoke_xz_xz_version",
+ "status": "pass",
+ "durationMs": 1246,
+ "details": "command=/home/linuxbrew/.linuxbrew/bin/xz --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz_version-terminal.txt",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz_version-terminal.txt"
+ }
+ ],
+ "packages": [
+ {
+ "formula": "dash",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "dash_command"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/dash -c echo dash_browser_smoke_ok"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/dash",
+ "-c",
+ "echo dash_browser_smoke_ok"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_dash: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32]",
+ "browser_smoke_dash_dash_command: command=/home/linuxbrew/.linuxbrew/bin/dash -c echo dash_browser_smoke_ok; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash_command-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash_command-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "git",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "git_version"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/git --version"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/git",
+ "--version"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_git: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32]",
+ "browser_smoke_git_git_version: command=/home/linuxbrew/.linuxbrew/bin/git --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git_version-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git_version-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "vim",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "vim_version"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/vim --version"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/vim",
+ "--version"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_vim: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32]",
+ "browser_smoke_vim_vim_version: command=/home/linuxbrew/.linuxbrew/bin/vim --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim_version-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim_version-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "less",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "less_version"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/less --version"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/less",
+ "--version"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_less: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32]",
+ "browser_smoke_less_less_version: command=/home/linuxbrew/.linuxbrew/bin/less --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less_version-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less_version-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "lsof",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "lsof_help"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/lsof -h"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/lsof",
+ "-h"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_lsof: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32]",
+ "browser_smoke_lsof_lsof_help: command=/home/linuxbrew/.linuxbrew/bin/lsof -h; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof_help-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof_help-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "modeset",
+ "arch": "wasm32",
+ "status": "skipped",
+ "required_cases": [
+ "modeset_version"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/modeset-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/modeset --version"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/modeset",
+ "--version"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_modeset: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/modeset-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32]"
+ ],
+ "failed": [],
+ "skipped": [
+ "browser_smoke_modeset_unsupported: modeset requires a DRI/GLES framebuffer device (/dev/dri) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer/device smoke [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-unsupported.txt]"
+ ],
+ "skip_reason": "modeset requires a DRI/GLES framebuffer device (/dev/dri) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer/device smoke"
+ },
+ {
+ "formula": "nano",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "nano_version"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/nano --version"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/nano",
+ "--version"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_nano: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32]",
+ "browser_smoke_nano_nano_version: command=/home/linuxbrew/.linuxbrew/bin/nano --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano_version-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano_version-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "netcat",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "netcat_help"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/nc -h"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/nc",
+ "-h"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_netcat: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32]",
+ "browser_smoke_netcat_netcat_help: command=/home/linuxbrew/.linuxbrew/bin/nc -h; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat_help-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat_help-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "wget",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "wget_version"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/wget --version"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/wget",
+ "--version"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_wget: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32]",
+ "browser_smoke_wget_wget_version: command=/home/linuxbrew/.linuxbrew/bin/wget --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget_version-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget_version-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "fbdoom",
+ "arch": "wasm32",
+ "status": "skipped",
+ "required_cases": [
+ "fbdoom_version"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/fbdoom-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/fbdoom --version"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/fbdoom",
+ "--version"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_fbdoom: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/fbdoom-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32]"
+ ],
+ "failed": [],
+ "skipped": [
+ "browser_smoke_fbdoom_unsupported: fbdoom requires IWAD game data and a framebuffer/audio device (/dev/fb0) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer smoke [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-unsupported.txt]"
+ ],
+ "skip_reason": "fbdoom requires IWAD game data and a framebuffer/audio device (/dev/fb0) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer smoke"
+ },
+ {
+ "formula": "bzip2",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "bzip2_help"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/bzip2 --help"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/bzip2",
+ "--help"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_bzip2: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32]",
+ "browser_smoke_bzip2_bzip2_help: command=/home/linuxbrew/.linuxbrew/bin/bzip2 --help; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2_help-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2_help-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ },
+ {
+ "formula": "xz",
+ "arch": "wasm32",
+ "status": "success",
+ "required_cases": [
+ "xz_version"
+ ],
+ "browser_url": "http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst",
+ "vfs_image": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew.vfs.zst",
+ "vfs_report": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew-vfs-report.json",
+ "commands": [
+ "/home/linuxbrew/.linuxbrew/bin/xz --version"
+ ],
+ "argv": [
+ [
+ "/home/linuxbrew/.linuxbrew/bin/xz",
+ "--version"
+ ]
+ ],
+ "passed": [
+ "browser_server_start: vite=http://127.0.0.1:58172; channel=chromium [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vite.log]",
+ "homebrew_browser_vfs_build_xz: image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32]",
+ "browser_smoke_xz_xz_version: command=/home/linuxbrew/.linuxbrew/bin/xz --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz_version-terminal.txt [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz_version-terminal.txt]"
+ ],
+ "failed": [],
+ "skipped": []
+ }
+ ],
+ "artifacts": {
+ "passed": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/outcome-lists/passed-tests.tsv",
+ "failed": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/outcome-lists/failed-tests.tsv",
+ "skipped": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/outcome-lists/skipped-tests.tsv",
+ "failures": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/failures.json",
+ "current_run": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/current-run.json"
+ }
+}
diff --git a/test-runs/kd-1mr.5/browser-smoke/summary.md b/test-runs/kd-1mr.5/browser-smoke/summary.md
new file mode 100644
index 000000000..86012511b
--- /dev/null
+++ b/test-runs/kd-1mr.5/browser-smoke/summary.md
@@ -0,0 +1,48 @@
+# Homebrew package browser VFS smoke
+
+Result dir: `/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke`
+Tap commit: `37bcd20d847101859641daf6e4583c70d634cfae`
+Counts: 23 pass, 0 fail, 2 skip
+
+| Formula | Status | Browser URL | Details |
+|---|---:|---|---|
+| `dash` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst` | |
+| `git` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst` | |
+| `vim` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst` | |
+| `less` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst` | |
+| `lsof` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst` | |
+| `modeset` | skipped | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/modeset-wasm32-homebrew.vfs.zst` | browser_smoke_modeset_unsupported: modeset requires a DRI/GLES framebuffer device (/dev/dri) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer/device smoke [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-unsupported.txt] |
+| `nano` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst` | |
+| `netcat` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst` | |
+| `wget` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst` | |
+| `fbdoom` | skipped | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/fbdoom-wasm32-homebrew.vfs.zst` | browser_smoke_fbdoom_unsupported: fbdoom requires IWAD game data and a framebuffer/audio device (/dev/fb0) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer smoke [/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-unsupported.txt] |
+| `bzip2` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst` | |
+| `xz` | success | `http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst` | |
+
+| Test | Status | Details |
+|---|---:|---|
+| `homebrew_browser_vfs_build_dash` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_git` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_vim` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_less` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_lsof` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_modeset` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/modeset-wasm32/modeset-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/modeset-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_nano` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_netcat` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_wget` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_fbdoom` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/fbdoom-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_bzip2` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst |
+| `homebrew_browser_vfs_build_xz` | pass | image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew.vfs.zst; report=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz-wasm32-homebrew-vfs-report.json; browser_url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst |
+| `browser_server_start` | pass | vite=http://127.0.0.1:58172; channel=chromium |
+| `browser_smoke_dash_dash_command` | pass | command=/home/linuxbrew/.linuxbrew/bin/dash -c echo dash_browser_smoke_ok; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/dash-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/dash-wasm32/dash_command-terminal.txt |
+| `browser_smoke_git_git_version` | pass | command=/home/linuxbrew/.linuxbrew/bin/git --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/git-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/git-wasm32/git_version-terminal.txt |
+| `browser_smoke_vim_vim_version` | pass | command=/home/linuxbrew/.linuxbrew/bin/vim --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/vim-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/vim-wasm32/vim_version-terminal.txt |
+| `browser_smoke_less_less_version` | pass | command=/home/linuxbrew/.linuxbrew/bin/less --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/less-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/less-wasm32/less_version-terminal.txt |
+| `browser_smoke_lsof_lsof_help` | pass | command=/home/linuxbrew/.linuxbrew/bin/lsof -h; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/lsof-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/lsof-wasm32/lsof_help-terminal.txt |
+| `browser_smoke_modeset_unsupported` | skip | modeset requires a DRI/GLES framebuffer device (/dev/dri) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer/device smoke |
+| `browser_smoke_nano_nano_version` | pass | command=/home/linuxbrew/.linuxbrew/bin/nano --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/nano-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/nano-wasm32/nano_version-terminal.txt |
+| `browser_smoke_netcat_netcat_help` | pass | command=/home/linuxbrew/.linuxbrew/bin/nc -h; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/netcat-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/netcat-wasm32/netcat_help-terminal.txt |
+| `browser_smoke_wget_wget_version` | pass | command=/home/linuxbrew/.linuxbrew/bin/wget --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/wget-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/wget-wasm32/wget_version-terminal.txt |
+| `browser_smoke_fbdoom_unsupported` | skip | fbdoom requires IWAD game data and a framebuffer/audio device (/dev/fb0) not provided by the non-interactive terminal Homebrew browser smoke; certify via a dedicated browser framebuffer smoke |
+| `browser_smoke_bzip2_bzip2_help` | pass | command=/home/linuxbrew/.linuxbrew/bin/bzip2 --help; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/bzip2-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/bzip2-wasm32/bzip2_help-terminal.txt |
+| `browser_smoke_xz_xz_version` | pass | command=/home/linuxbrew/.linuxbrew/bin/xz --version; url=http://127.0.0.1:58172/__kandelo-homebrew-smoke/kd-1mr.5-20260701T064348095Z-55840/xz-wasm32-homebrew.vfs.zst; output=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/browser-smoke/xz-wasm32/xz_version-terminal.txt |
diff --git a/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/failed-tests.tsv b/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/failed-tests.tsv
new file mode 100644
index 000000000..f62fbc93d
--- /dev/null
+++ b/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/failed-tests.tsv
@@ -0,0 +1 @@
+test composite runtime error
diff --git a/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/passed-tests.tsv b/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/passed-tests.tsv
new file mode 100644
index 000000000..2375a6a7a
--- /dev/null
+++ b/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/passed-tests.tsv
@@ -0,0 +1,2 @@
+test composite runtime details
+vim-browser-bundle_browser_lazy_archive vim-browser-bundle browser vim-browser-bundle lazy_archive has 1 Homebrew package inputs ready for browser/wasm32
diff --git a/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/skipped-tests.tsv b/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/skipped-tests.tsv
new file mode 100644
index 000000000..b1d568afb
--- /dev/null
+++ b/test-runs/kd-1mr.5/composite-status-enriched/outcome-lists/skipped-tests.tsv
@@ -0,0 +1,8 @@
+test composite runtime reason
+rootfs_browser_vfs_image rootfs browser bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found
+shell_browser_vfs_image shell browser composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser)
+python-vfs_browser_vfs_image python-vfs browser cpython: no generated Homebrew sidecar metadata found
+perl-vfs_browser_vfs_image perl-vfs browser perl: no generated Homebrew sidecar metadata found
+erlang-vfs_browser_vfs_image erlang-vfs browser erlang: no generated Homebrew sidecar metadata found
+nethack-browser-bundle_browser_lazy_archive nethack-browser-bundle browser nethack: no generated Homebrew sidecar metadata found
+node-vfs_browser_vfs_image node-vfs browser composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser); node: no generated Homebrew sidecar metadata found
diff --git a/test-runs/kd-1mr.5/composite-status-enriched/summary.json b/test-runs/kd-1mr.5/composite-status-enriched/summary.json
new file mode 100644
index 000000000..883ad73ef
--- /dev/null
+++ b/test-runs/kd-1mr.5/composite-status-enriched/summary.json
@@ -0,0 +1,214 @@
+{
+ "suite": "Homebrew composite VFS status",
+ "bead_id": "kd-1mr.5",
+ "generated_at": "2026-07-01T06:58:12.607Z",
+ "result_dir": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/composite-status-enriched",
+ "arch": "wasm32",
+ "runtimes": [
+ "browser"
+ ],
+ "metadata": [
+ "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/metadata.json",
+ "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-0k6q-core-cli/test-runs/kd-0k6q/homebrew-sidecars/Kandelo/metadata.json"
+ ],
+ "package_count": 29,
+ "counts": {
+ "pass": 1,
+ "fail": 0,
+ "skip": 7
+ },
+ "outcomes": [
+ {
+ "name": "rootfs_browser_vfs_image",
+ "composite": "rootfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite"
+ ],
+ "closure_packages": [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite"
+ ],
+ "status": "skip",
+ "details": "bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "bash: no generated Homebrew sidecar metadata found",
+ "ncurses: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "shell_browser_vfs_image",
+ "composite": "shell",
+ "runtime": "browser",
+ "direct_packages": [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset"
+ ],
+ "closure_packages": [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset"
+ ],
+ "status": "skip",
+ "details": "composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser)",
+ "blockers": [
+ "composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found",
+ "curl: no generated Homebrew sidecar metadata found",
+ "nethack: no generated Homebrew sidecar metadata found",
+ "fbdoom: browser unsupported (runtime_support does not include browser)",
+ "modeset: browser unsupported (runtime_support does not include browser)"
+ ]
+ },
+ {
+ "name": "python-vfs_browser_vfs_image",
+ "composite": "python-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "cpython"
+ ],
+ "closure_packages": [
+ "cpython"
+ ],
+ "status": "skip",
+ "details": "cpython: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "cpython: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "perl-vfs_browser_vfs_image",
+ "composite": "perl-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "perl"
+ ],
+ "closure_packages": [
+ "perl"
+ ],
+ "status": "skip",
+ "details": "perl: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "perl: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "erlang-vfs_browser_vfs_image",
+ "composite": "erlang-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "erlang"
+ ],
+ "closure_packages": [
+ "erlang"
+ ],
+ "status": "skip",
+ "details": "erlang: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "erlang: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "vim-browser-bundle_browser_lazy_archive",
+ "composite": "vim-browser-bundle",
+ "runtime": "browser",
+ "direct_packages": [
+ "vim"
+ ],
+ "closure_packages": [
+ "vim"
+ ],
+ "status": "pass",
+ "details": "vim-browser-bundle lazy_archive has 1 Homebrew package inputs ready for browser/wasm32",
+ "blockers": []
+ },
+ {
+ "name": "nethack-browser-bundle_browser_lazy_archive",
+ "composite": "nethack-browser-bundle",
+ "runtime": "browser",
+ "direct_packages": [
+ "nethack"
+ ],
+ "closure_packages": [
+ "nethack"
+ ],
+ "status": "skip",
+ "details": "nethack: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "nethack: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "node-vfs_browser_vfs_image",
+ "composite": "node-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "node"
+ ],
+ "closure_packages": [
+ "node"
+ ],
+ "status": "skip",
+ "details": "composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser); node: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser)",
+ "node: no generated Homebrew sidecar metadata found"
+ ]
+ }
+ ]
+}
diff --git a/test-runs/kd-1mr.5/composite-status/outcome-lists/failed-tests.tsv b/test-runs/kd-1mr.5/composite-status/outcome-lists/failed-tests.tsv
new file mode 100644
index 000000000..f62fbc93d
--- /dev/null
+++ b/test-runs/kd-1mr.5/composite-status/outcome-lists/failed-tests.tsv
@@ -0,0 +1 @@
+test composite runtime error
diff --git a/test-runs/kd-1mr.5/composite-status/outcome-lists/passed-tests.tsv b/test-runs/kd-1mr.5/composite-status/outcome-lists/passed-tests.tsv
new file mode 100644
index 000000000..18619e5cf
--- /dev/null
+++ b/test-runs/kd-1mr.5/composite-status/outcome-lists/passed-tests.tsv
@@ -0,0 +1,3 @@
+test composite runtime details
+vim-browser-bundle_node_lazy_archive vim-browser-bundle node vim-browser-bundle lazy_archive has 1 Homebrew package inputs ready for node/wasm32
+vim-browser-bundle_browser_lazy_archive vim-browser-bundle browser vim-browser-bundle lazy_archive has 1 Homebrew package inputs ready for browser/wasm32
diff --git a/test-runs/kd-1mr.5/composite-status/outcome-lists/skipped-tests.tsv b/test-runs/kd-1mr.5/composite-status/outcome-lists/skipped-tests.tsv
new file mode 100644
index 000000000..4777add40
--- /dev/null
+++ b/test-runs/kd-1mr.5/composite-status/outcome-lists/skipped-tests.tsv
@@ -0,0 +1,15 @@
+test composite runtime reason
+rootfs_node_vfs_image rootfs node bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found
+shell_node_vfs_image shell node composite rootfs is not ready for node: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found
+python-vfs_node_vfs_image python-vfs node cpython: no generated Homebrew sidecar metadata found
+perl-vfs_node_vfs_image perl-vfs node perl: no generated Homebrew sidecar metadata found
+erlang-vfs_node_vfs_image erlang-vfs node erlang: no generated Homebrew sidecar metadata found
+nethack-browser-bundle_node_lazy_archive nethack-browser-bundle node nethack: no generated Homebrew sidecar metadata found
+node-vfs_node_vfs_image node-vfs node composite shell is not ready for node: composite rootfs is not ready for node: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; node: no generated Homebrew sidecar metadata found
+rootfs_browser_vfs_image rootfs browser bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found
+shell_browser_vfs_image shell browser composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser)
+python-vfs_browser_vfs_image python-vfs browser cpython: no generated Homebrew sidecar metadata found
+perl-vfs_browser_vfs_image perl-vfs browser perl: no generated Homebrew sidecar metadata found
+erlang-vfs_browser_vfs_image erlang-vfs browser erlang: no generated Homebrew sidecar metadata found
+nethack-browser-bundle_browser_lazy_archive nethack-browser-bundle browser nethack: no generated Homebrew sidecar metadata found
+node-vfs_browser_vfs_image node-vfs browser composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser); node: no generated Homebrew sidecar metadata found
diff --git a/test-runs/kd-1mr.5/composite-status/summary.json b/test-runs/kd-1mr.5/composite-status/summary.json
new file mode 100644
index 000000000..317e7e52a
--- /dev/null
+++ b/test-runs/kd-1mr.5/composite-status/summary.json
@@ -0,0 +1,436 @@
+{
+ "suite": "Homebrew composite VFS status",
+ "bead_id": "kd-1mr.5",
+ "generated_at": "2026-07-01T06:55:57.001Z",
+ "result_dir": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-1mr.5/composite-status",
+ "arch": "wasm32",
+ "runtimes": [
+ "node",
+ "browser"
+ ],
+ "metadata": [
+ "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.5-certify-browser-rootfs-shell/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/metadata.json"
+ ],
+ "package_count": 12,
+ "counts": {
+ "pass": 2,
+ "fail": 0,
+ "skip": 14
+ },
+ "outcomes": [
+ {
+ "name": "rootfs_node_vfs_image",
+ "composite": "rootfs",
+ "runtime": "node",
+ "direct_packages": [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite"
+ ],
+ "closure_packages": [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite"
+ ],
+ "status": "skip",
+ "details": "bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "bash: no generated Homebrew sidecar metadata found",
+ "ncurses: no generated Homebrew sidecar metadata found",
+ "coreutils: no generated Homebrew sidecar metadata found",
+ "gawk: no generated Homebrew sidecar metadata found",
+ "grep: no generated Homebrew sidecar metadata found",
+ "sed: no generated Homebrew sidecar metadata found",
+ "bc: no generated Homebrew sidecar metadata found",
+ "file: no generated Homebrew sidecar metadata found",
+ "m4: no generated Homebrew sidecar metadata found",
+ "make: no generated Homebrew sidecar metadata found",
+ "findutils: no generated Homebrew sidecar metadata found",
+ "diffutils: no generated Homebrew sidecar metadata found",
+ "posix-utils-lite: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "shell_node_vfs_image",
+ "composite": "shell",
+ "runtime": "node",
+ "direct_packages": [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset"
+ ],
+ "closure_packages": [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset"
+ ],
+ "status": "skip",
+ "details": "composite rootfs is not ready for node: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "composite rootfs is not ready for node: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found",
+ "tar: no generated Homebrew sidecar metadata found",
+ "curl: no generated Homebrew sidecar metadata found",
+ "gzip: no generated Homebrew sidecar metadata found",
+ "zstd: no generated Homebrew sidecar metadata found",
+ "zip: no generated Homebrew sidecar metadata found",
+ "unzip: no generated Homebrew sidecar metadata found",
+ "nethack: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "python-vfs_node_vfs_image",
+ "composite": "python-vfs",
+ "runtime": "node",
+ "direct_packages": [
+ "cpython"
+ ],
+ "closure_packages": [
+ "cpython"
+ ],
+ "status": "skip",
+ "details": "cpython: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "cpython: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "perl-vfs_node_vfs_image",
+ "composite": "perl-vfs",
+ "runtime": "node",
+ "direct_packages": [
+ "perl"
+ ],
+ "closure_packages": [
+ "perl"
+ ],
+ "status": "skip",
+ "details": "perl: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "perl: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "erlang-vfs_node_vfs_image",
+ "composite": "erlang-vfs",
+ "runtime": "node",
+ "direct_packages": [
+ "erlang"
+ ],
+ "closure_packages": [
+ "erlang"
+ ],
+ "status": "skip",
+ "details": "erlang: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "erlang: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "vim-browser-bundle_node_lazy_archive",
+ "composite": "vim-browser-bundle",
+ "runtime": "node",
+ "direct_packages": [
+ "vim"
+ ],
+ "closure_packages": [
+ "vim"
+ ],
+ "status": "pass",
+ "details": "vim-browser-bundle lazy_archive has 1 Homebrew package inputs ready for node/wasm32",
+ "blockers": []
+ },
+ {
+ "name": "nethack-browser-bundle_node_lazy_archive",
+ "composite": "nethack-browser-bundle",
+ "runtime": "node",
+ "direct_packages": [
+ "nethack"
+ ],
+ "closure_packages": [
+ "nethack"
+ ],
+ "status": "skip",
+ "details": "nethack: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "nethack: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "node-vfs_node_vfs_image",
+ "composite": "node-vfs",
+ "runtime": "node",
+ "direct_packages": [
+ "node"
+ ],
+ "closure_packages": [
+ "node"
+ ],
+ "status": "skip",
+ "details": "composite shell is not ready for node: composite rootfs is not ready for node: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; node: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "composite shell is not ready for node: composite rootfs is not ready for node: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found",
+ "node: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "rootfs_browser_vfs_image",
+ "composite": "rootfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite"
+ ],
+ "closure_packages": [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite"
+ ],
+ "status": "skip",
+ "details": "bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "bash: no generated Homebrew sidecar metadata found",
+ "ncurses: no generated Homebrew sidecar metadata found",
+ "coreutils: no generated Homebrew sidecar metadata found",
+ "gawk: no generated Homebrew sidecar metadata found",
+ "grep: no generated Homebrew sidecar metadata found",
+ "sed: no generated Homebrew sidecar metadata found",
+ "bc: no generated Homebrew sidecar metadata found",
+ "file: no generated Homebrew sidecar metadata found",
+ "m4: no generated Homebrew sidecar metadata found",
+ "make: no generated Homebrew sidecar metadata found",
+ "findutils: no generated Homebrew sidecar metadata found",
+ "diffutils: no generated Homebrew sidecar metadata found",
+ "posix-utils-lite: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "shell_browser_vfs_image",
+ "composite": "shell",
+ "runtime": "browser",
+ "direct_packages": [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset"
+ ],
+ "closure_packages": [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset"
+ ],
+ "status": "skip",
+ "details": "composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser)",
+ "blockers": [
+ "composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found",
+ "tar: no generated Homebrew sidecar metadata found",
+ "curl: no generated Homebrew sidecar metadata found",
+ "gzip: no generated Homebrew sidecar metadata found",
+ "zstd: no generated Homebrew sidecar metadata found",
+ "zip: no generated Homebrew sidecar metadata found",
+ "unzip: no generated Homebrew sidecar metadata found",
+ "nethack: no generated Homebrew sidecar metadata found",
+ "fbdoom: browser unsupported (runtime_support does not include browser)",
+ "modeset: browser unsupported (runtime_support does not include browser)"
+ ]
+ },
+ {
+ "name": "python-vfs_browser_vfs_image",
+ "composite": "python-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "cpython"
+ ],
+ "closure_packages": [
+ "cpython"
+ ],
+ "status": "skip",
+ "details": "cpython: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "cpython: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "perl-vfs_browser_vfs_image",
+ "composite": "perl-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "perl"
+ ],
+ "closure_packages": [
+ "perl"
+ ],
+ "status": "skip",
+ "details": "perl: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "perl: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "erlang-vfs_browser_vfs_image",
+ "composite": "erlang-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "erlang"
+ ],
+ "closure_packages": [
+ "erlang"
+ ],
+ "status": "skip",
+ "details": "erlang: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "erlang: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "vim-browser-bundle_browser_lazy_archive",
+ "composite": "vim-browser-bundle",
+ "runtime": "browser",
+ "direct_packages": [
+ "vim"
+ ],
+ "closure_packages": [
+ "vim"
+ ],
+ "status": "pass",
+ "details": "vim-browser-bundle lazy_archive has 1 Homebrew package inputs ready for browser/wasm32",
+ "blockers": []
+ },
+ {
+ "name": "nethack-browser-bundle_browser_lazy_archive",
+ "composite": "nethack-browser-bundle",
+ "runtime": "browser",
+ "direct_packages": [
+ "nethack"
+ ],
+ "closure_packages": [
+ "nethack"
+ ],
+ "status": "skip",
+ "details": "nethack: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "nethack: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "node-vfs_browser_vfs_image",
+ "composite": "node-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "node"
+ ],
+ "closure_packages": [
+ "node"
+ ],
+ "status": "skip",
+ "details": "composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser); node: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; coreutils: no generated Homebrew sidecar metadata found; gawk: no generated Homebrew sidecar metadata found; grep: no generated Homebrew sidecar metadata found; sed: no generated Homebrew sidecar metadata found; bc: no generated Homebrew sidecar metadata found; file: no generated Homebrew sidecar metadata found; m4: no generated Homebrew sidecar metadata found; make: no generated Homebrew sidecar metadata found; findutils: no generated Homebrew sidecar metadata found; diffutils: no generated Homebrew sidecar metadata found; posix-utils-lite: no generated Homebrew sidecar metadata found; tar: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; gzip: no generated Homebrew sidecar metadata found; zstd: no generated Homebrew sidecar metadata found; zip: no generated Homebrew sidecar metadata found; unzip: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; fbdoom: browser unsupported (runtime_support does not include browser); modeset: browser unsupported (runtime_support does not include browser)",
+ "node: no generated Homebrew sidecar metadata found"
+ ]
+ }
+ ]
+}
diff --git a/test-runs/kd-1mr.5/sidecars-input.json b/test-runs/kd-1mr.5/sidecars-input.json
new file mode 100644
index 000000000..6f9e432b5
--- /dev/null
+++ b/test-runs/kd-1mr.5/sidecars-input.json
@@ -0,0 +1,1361 @@
+{
+ "generated_at": "2026-06-30T14:09:12Z",
+ "generator": "kandelo-homebrew-publish 1",
+ "kandelo_abi": 16,
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "packages": [
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/dash-wasm32/bottles/dash--0.5.12.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:12Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "f1cf217ac3c91d7dddf9acfa101b6ea0c090fbbbb7abe064f31f601de2e11772",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/dash",
+ "target": "bin/dash",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "dash/0.5.12",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/dash.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/dash/blobs/sha256:b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/dash.json",
+ "Kandelo/link/dash-0.5.12-rebuild0-wasm32.json",
+ "Kandelo/reports/dash-0.5.12-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran dash through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/dash.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/dash",
+ "name": "dash",
+ "version": "0.5.12"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/git-wasm32/bottles/git--2.47.1.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:14Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4c43e2a22ab146ab7136937652d959824578d07927521a16329dbd8474e3e3b8",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/git",
+ "target": "bin/git",
+ "type": "symlink"
+ },
+ {
+ "source": "bin/git-remote-http",
+ "target": "bin/git-remote-http",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "git/2.47.1",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/git.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/git/blobs/sha256:2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/git.json",
+ "Kandelo/link/git-2.47.1-rebuild0-wasm32.json",
+ "Kandelo/reports/git-2.47.1-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran git through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/git.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/git",
+ "name": "git",
+ "version": "2.47.1"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/vim-wasm32/bottles/vim--9.1.0900.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4a2a54d3a4c1052e2d484be6f8f25661bd233c49b9f0eecca5fd7040bcc222ba",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/vim",
+ "target": "bin/vim",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "vim/9.1.0900",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/vim.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/vim/blobs/sha256:778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/vim.json",
+ "Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json",
+ "Kandelo/reports/vim-9.1.0900-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran vim through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/vim.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/vim",
+ "name": "vim",
+ "version": "9.1.0900"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/less-wasm32/bottles/less--668.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:15Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "3ec5d016d15c7b316c6643d57f66cc2f4db4ed5726c3f30356c72fa9e15d6425",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/less",
+ "target": "bin/less",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "less/668",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/less.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/less/blobs/sha256:ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/less.json",
+ "Kandelo/link/less-668-rebuild0-wasm32.json",
+ "Kandelo/reports/less-668-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran less through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/less.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/less",
+ "name": "less",
+ "version": "668"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/lsof-wasm32/bottles/lsof--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:16Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "88e06177e2acd7d54b78e9673812a7124712052ddda3599341dc208910a83b4f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/lsof",
+ "target": "bin/lsof",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "lsof/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/lsof.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/lsof/blobs/sha256:104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/lsof.json",
+ "Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/lsof-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran lsof through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/lsof.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/lsof",
+ "name": "lsof",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/modeset-wasm32/bottles/modeset--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:17Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "d3fc05bf7b73121ad1d49c447b755154ebff60f6e0baac959cf54107617aac66",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/modeset",
+ "target": "bin/modeset",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "modeset/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/modeset.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/modeset/blobs/sha256:48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/modeset.json",
+ "Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/modeset-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran modeset through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run locally: modeset requires DRI/GLES framebuffer/device validation",
+ "skipped": [
+ "browser smoke not run locally: modeset requires DRI/GLES framebuffer/device validation"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/modeset.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/modeset",
+ "name": "modeset",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/nano-wasm32/bottles/nano--8.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:20Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4be127352be19f0d75448a83769107716757e545aa4f3790dca8069a093aab59",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/nano",
+ "target": "bin/nano",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "nano/8.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/nano.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/nano/blobs/sha256:5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/nano.json",
+ "Kandelo/link/nano-8.0-rebuild0-wasm32.json",
+ "Kandelo/reports/nano-8.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran nano through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/nano.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/nano",
+ "name": "nano",
+ "version": "8.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/netcat-wasm32/bottles/netcat--0.7.1.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:21Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "ecfdca45ff958a00f498d460f57df18b9de2e66ecac5d95aa7c346b3686a9409",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/nc",
+ "target": "bin/nc",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "netcat/0.7.1",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/netcat.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/netcat/blobs/sha256:2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/netcat.json",
+ "Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json",
+ "Kandelo/reports/netcat-0.7.1-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran nc through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/netcat.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/netcat",
+ "name": "netcat",
+ "version": "0.7.1"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/wget-wasm32/bottles/wget--1.25.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:23Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "17d7408ea85bf3a5e4e8d1e1630c5a157df613b2313a5c407b6e7c7a466d1c31",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/wget",
+ "target": "bin/wget",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "wget/1.25.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/wget.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/wget/blobs/sha256:7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/wget.json",
+ "Kandelo/link/wget-1.25.0-rebuild0-wasm32.json",
+ "Kandelo/reports/wget-1.25.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran wget through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/wget.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/wget",
+ "name": "wget",
+ "version": "1.25.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/fbdoom-wasm32/bottles/fbdoom--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": false,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:13Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "e74be0eac8237d4345eb1db5c0c6d59aa0a20a54d7a603affeaa76190c7effc3",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/fbdoom",
+ "target": "bin/fbdoom",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "fbdoom/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/fbdoom.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/fbdoom/blobs/sha256:51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/fbdoom.json",
+ "Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/fbdoom-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran fbdoom through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run locally: fbdoom requires IWAD data plus framebuffer/audio device validation",
+ "skipped": [
+ "browser smoke not run locally: fbdoom requires IWAD data plus framebuffer/audio device validation"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/fbdoom.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/fbdoom",
+ "name": "fbdoom",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.2-port-sqlite-bzip2-and-xz-homebrew-pilot/test-runs/kd-1mr.2/homebrew-bottles/bzip2-wasm32/bottles/bzip2--1.0.8.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T03:05:02Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "49c19e83209e7954c9f8399262cd76d7e23868e4a022e4502f8668d4e0c9cd5f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/bzip2",
+ "target": "bin/bzip2",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "bzip2/1.0.8",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/bzip2.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/bzip2/blobs/sha256:98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/bzip2.json",
+ "Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json",
+ "Kandelo/reports/bzip2-1.0.8-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran bzip2 --help through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "No successful browser VFS smoke was recorded for bzip2 wasm32.",
+ "skipped": [
+ "No successful browser VFS smoke was recorded for bzip2 wasm32."
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/bzip2.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/bzip2",
+ "name": "bzip2",
+ "version": "1.0.8"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.2-port-sqlite-bzip2-and-xz-homebrew-pilot/test-runs/kd-1mr.2/homebrew-bottles/xz-wasm32/bottles/xz--5.6.2.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T03:00:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "6dcdd72b55ed0fbb6edc38c3854216da67579110efbaf56ee35803c7aec84027",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/xz",
+ "target": "bin/xz",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "xz/5.6.2",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/xz.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/xz/blobs/sha256:887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/xz.json",
+ "Kandelo/link/xz-5.6.2-rebuild0-wasm32.json",
+ "Kandelo/reports/xz-5.6.2-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran xz --version through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "No successful browser VFS smoke was recorded for xz wasm32.",
+ "skipped": [
+ "No successful browser VFS smoke was recorded for xz wasm32."
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/xz.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/xz",
+ "name": "xz",
+ "version": "5.6.2"
+ }
+ ],
+ "release_tag": "bottles-abi-v16",
+ "schema": 1,
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew"
+}
diff --git a/test-runs/kd-k3l9/DISPOSITION.md b/test-runs/kd-k3l9/DISPOSITION.md
new file mode 100644
index 000000000..69e3b89ce
--- /dev/null
+++ b/test-runs/kd-k3l9/DISPOSITION.md
@@ -0,0 +1,93 @@
+# kd-k3l9 -- Browser Framebuffer/Device Smoke Harness (modeset + fbdoom)
+
+Bead: kd-k3l9 (umbrella kd-1mr / initiative homebrew-all)
+Session: kg-ydrd / porter-adhoc-49d9da88f8
+Generated: 2026-07-01T07:40Z
+Worktree: `/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke`
+Branch: `gascity/kd-1mr/kd-k3l9-browser-framebuffer-smoke` (stacks on kd-1mr.5 -> kd-v3fs tooling -> kd-0hns tap)
+
+## Summary
+
+Built a browser framebuffer/device smoke harness and used it to certify the two
+rootfs/shell packages the terminal smoke (kd-1mr.5) could only skip. **Both are
+now `browser_compatible=true` with real in-browser rendering evidence**, so the
+whole 12-package kd-0hns rootfs/shell tap is browser-certified (`homebrew-validate: ok`).
+
+| Package | Device | In-browser evidence | Disposition |
+|---|---|---|---|
+| fbdoom | /dev/fb0 | bound fb 640x400; 1424 pixel-write frames (91 MB); canvas 249,072 non-blank px | CERTIFIED browser_compatible=true |
+| modeset | /dev/dri/card0 | 110 KMS page-flip commits at 1920x1080 via WebGL2 (CRTC 1) | CERTIFIED browser_compatible=true |
+
+## The harness
+
+New, sibling to the kd-1mr.5 terminal smoke:
+- `scripts/homebrew-package-framebuffer-smoke.ts` -- pours the Homebrew VFS for
+ the package (reusing planHomebrewVfs + buildHomebrewVfs), injects the DOOM
+ shareware IWAD for fbdoom, serves it, drives headless Chromium (new-headless
+ `chromium` channel for WebGL2-in-worker), runs the program, and asserts on
+ framebuffer/CRTC activity.
+- `apps/browser-demos/pages/homebrew-fb-smoke/{index.html,main.ts}` -- boots the
+ poured VFS through BrowserKernel with a PTY (framebuffer programs query
+ /dev/tty at keyboard init and exit without one), then:
+ - **fb mode** (fbdoom): subscribes to `kernel.framebuffers.onChange`/`onWrite`
+ and renders via `attachCanvas` (2D). Pass = fb bound + pixel writes + non-blank canvas.
+ - **kms mode** (modeset): transfers an OffscreenCanvas to the worker via
+ `kernel.kmsAttachCanvas(1, offscreen, statsSab, { mode: "webgl2" })` and reads
+ page-flip telemetry (`commit_count`, scanout w/h) from the stats SAB. Pass =
+ page-flip commits + a live scanout resolution.
+- `apps/browser-demos/vite.config.ts` -- registers the `homebrew-fb-smoke` page input.
+
+## Method notes (two real defects the harness had to solve)
+
+1. **PTY required.** fbdoom reached `I_InitGraphics` (framebuffer configured) but
+ then printed "Using keyboard on /dev/tty. Unable to query terminal settings."
+ and exited before the first frame. Booting with `pty: true` gives it a
+ queryable terminal so it proceeds into the render loop.
+2. **KMS attach after boot.** `kmsAttachCanvas` must run after `kernel.boot()`
+ (the worker does not exist before boot); attaching before boot throws
+ "Cannot read properties of undefined (reading 'postMessage')".
+
+## Bottle provenance
+
+The kd-bry6 fbdoom/modeset bottles (sha256 matching the kd-0hns sidecars) were
+staged into a sha-keyed `--bottle-cache`; the IWAD (`doom1.wad`, sha256
+`1d7d43be...`, freely-redistributable DOOM shareware) was fetched from
+`https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad` and injected at
+`/doom1.wad`. No sidecar sha/url changes -- only `browser_compatible` +
+`runtime_support` flipped, then the tap was regenerated via `cargo xtask
+homebrew-sidecars` (recomputes provenance shas).
+
+## Verification (durable artifacts under test-runs/kd-k3l9/)
+
+- Framebuffer smoke: **5 pass / 0 fail / 0 skip** (`fb-smoke/summary.json` +
+ `outcome-lists/`; per-package `*-fb-result.json`).
+- Sidecar validation: `cargo xtask homebrew-validate --tap-root
+ test-runs/kd-0hns/rootfs-shell-tap` -> **`homebrew-validate: ok (packages=12,
+ bottles=12, link_manifests=12, provenance_reports=12)`**; all 12 packages now
+ `browser_compatible=true`.
+- Composite status (`composite-status-enriched/`, browser runtime, kd-0hns +
+ kd-0k6q core metadata): `shell/browser` and `rootfs/browser` no longer list
+ modeset/fbdoom as blockers -- both now gated only on kd-1mr.4's
+ bash/ncurses/curl/nethack. `vim-browser-bundle/browser` PASS.
+
+## Effect on kd-v3fs browser tier
+
+- modeset + fbdoom removed as `shell/browser` blockers. shell/browser now depends
+ only on kd-1mr.4 (bash/ncurses/curl/nethack). rootfs/browser depends on bash+ncurses.
+- Combined with kd-1mr.5, the full 12-package rootfs/shell set is browser-certified;
+ the remaining browser-tier work is kd-1mr.4's four missing Formulae and the
+ language wave (kd-yuef).
+
+## Stacking / provenance note
+
+Branch stacks on kd-1mr.5 (which brought in the kd-v3fs browser tooling + certified
+the 10 terminal packages). Net kd-k3l9 contribution: the framebuffer smoke harness
+(runner + page + vite input), the modeset/fbdoom sidecar certification, and the
+evidence artifacts. Suggested merge order: kd-0hns -> kd-v3fs -> kd-1mr.5 -> kd-k3l9.
+
+## Follow-ups
+
+- A CI-gated variant of this harness (matching the existing kandelo-modeset.spec)
+ so the framebuffer certification is regression-guarded, not run-once evidence.
+- shell/browser + rootfs/browser full pass depend on kd-1mr.4 landing
+ bash/ncurses/curl/nethack.
diff --git a/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/failed-tests.tsv b/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/failed-tests.tsv
new file mode 100644
index 000000000..f62fbc93d
--- /dev/null
+++ b/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/failed-tests.tsv
@@ -0,0 +1 @@
+test composite runtime error
diff --git a/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/passed-tests.tsv b/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/passed-tests.tsv
new file mode 100644
index 000000000..2375a6a7a
--- /dev/null
+++ b/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/passed-tests.tsv
@@ -0,0 +1,2 @@
+test composite runtime details
+vim-browser-bundle_browser_lazy_archive vim-browser-bundle browser vim-browser-bundle lazy_archive has 1 Homebrew package inputs ready for browser/wasm32
diff --git a/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/skipped-tests.tsv b/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/skipped-tests.tsv
new file mode 100644
index 000000000..02ed2f7bd
--- /dev/null
+++ b/test-runs/kd-k3l9/composite-status-enriched/outcome-lists/skipped-tests.tsv
@@ -0,0 +1,8 @@
+test composite runtime reason
+rootfs_browser_vfs_image rootfs browser bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found
+shell_browser_vfs_image shell browser composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found
+python-vfs_browser_vfs_image python-vfs browser cpython: no generated Homebrew sidecar metadata found
+perl-vfs_browser_vfs_image perl-vfs browser perl: no generated Homebrew sidecar metadata found
+erlang-vfs_browser_vfs_image erlang-vfs browser erlang: no generated Homebrew sidecar metadata found
+nethack-browser-bundle_browser_lazy_archive nethack-browser-bundle browser nethack: no generated Homebrew sidecar metadata found
+node-vfs_browser_vfs_image node-vfs browser composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; node: no generated Homebrew sidecar metadata found
diff --git a/test-runs/kd-k3l9/composite-status-enriched/summary.json b/test-runs/kd-k3l9/composite-status-enriched/summary.json
new file mode 100644
index 000000000..9812e050f
--- /dev/null
+++ b/test-runs/kd-k3l9/composite-status-enriched/summary.json
@@ -0,0 +1,212 @@
+{
+ "suite": "Homebrew composite VFS status",
+ "bead_id": "kd-k3l9",
+ "generated_at": "2026-07-01T07:40:47.011Z",
+ "result_dir": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/composite-status-enriched",
+ "arch": "wasm32",
+ "runtimes": [
+ "browser"
+ ],
+ "metadata": [
+ "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-0hns/rootfs-shell-tap/Kandelo/metadata.json",
+ "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-0k6q-core-cli/test-runs/kd-0k6q/homebrew-sidecars/Kandelo/metadata.json"
+ ],
+ "package_count": 29,
+ "counts": {
+ "pass": 1,
+ "fail": 0,
+ "skip": 7
+ },
+ "outcomes": [
+ {
+ "name": "rootfs_browser_vfs_image",
+ "composite": "rootfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite"
+ ],
+ "closure_packages": [
+ "dash",
+ "bash",
+ "ncurses",
+ "coreutils",
+ "gawk",
+ "grep",
+ "sed",
+ "bc",
+ "file",
+ "m4",
+ "make",
+ "findutils",
+ "diffutils",
+ "posix-utils-lite"
+ ],
+ "status": "skip",
+ "details": "bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "bash: no generated Homebrew sidecar metadata found",
+ "ncurses: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "shell_browser_vfs_image",
+ "composite": "shell",
+ "runtime": "browser",
+ "direct_packages": [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset"
+ ],
+ "closure_packages": [
+ "less",
+ "tar",
+ "curl",
+ "netcat",
+ "wget",
+ "git",
+ "gzip",
+ "bzip2",
+ "xz",
+ "zstd",
+ "zip",
+ "unzip",
+ "lsof",
+ "nano",
+ "vim",
+ "nethack",
+ "fbdoom",
+ "modeset"
+ ],
+ "status": "skip",
+ "details": "composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found",
+ "curl: no generated Homebrew sidecar metadata found",
+ "nethack: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "python-vfs_browser_vfs_image",
+ "composite": "python-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "cpython"
+ ],
+ "closure_packages": [
+ "cpython"
+ ],
+ "status": "skip",
+ "details": "cpython: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "cpython: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "perl-vfs_browser_vfs_image",
+ "composite": "perl-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "perl"
+ ],
+ "closure_packages": [
+ "perl"
+ ],
+ "status": "skip",
+ "details": "perl: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "perl: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "erlang-vfs_browser_vfs_image",
+ "composite": "erlang-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "erlang"
+ ],
+ "closure_packages": [
+ "erlang"
+ ],
+ "status": "skip",
+ "details": "erlang: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "erlang: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "vim-browser-bundle_browser_lazy_archive",
+ "composite": "vim-browser-bundle",
+ "runtime": "browser",
+ "direct_packages": [
+ "vim"
+ ],
+ "closure_packages": [
+ "vim"
+ ],
+ "status": "pass",
+ "details": "vim-browser-bundle lazy_archive has 1 Homebrew package inputs ready for browser/wasm32",
+ "blockers": []
+ },
+ {
+ "name": "nethack-browser-bundle_browser_lazy_archive",
+ "composite": "nethack-browser-bundle",
+ "runtime": "browser",
+ "direct_packages": [
+ "nethack"
+ ],
+ "closure_packages": [
+ "nethack"
+ ],
+ "status": "skip",
+ "details": "nethack: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "nethack: no generated Homebrew sidecar metadata found"
+ ]
+ },
+ {
+ "name": "node-vfs_browser_vfs_image",
+ "composite": "node-vfs",
+ "runtime": "browser",
+ "direct_packages": [
+ "node"
+ ],
+ "closure_packages": [
+ "node"
+ ],
+ "status": "skip",
+ "details": "composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found; node: no generated Homebrew sidecar metadata found",
+ "blockers": [
+ "composite shell is not ready for browser: composite rootfs is not ready for browser: bash: no generated Homebrew sidecar metadata found; ncurses: no generated Homebrew sidecar metadata found; curl: no generated Homebrew sidecar metadata found; nethack: no generated Homebrew sidecar metadata found",
+ "node: no generated Homebrew sidecar metadata found"
+ ]
+ }
+ ]
+}
diff --git a/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32/fbdoom-fb-result.json b/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32/fbdoom-fb-result.json
new file mode 100644
index 000000000..cc92ee27c
--- /dev/null
+++ b/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32/fbdoom-fb-result.json
@@ -0,0 +1,22 @@
+{
+ "mode": "fb",
+ "binds": 1,
+ "unbinds": 0,
+ "writes": 1424,
+ "writeBytes": 91136000,
+ "kmsBlits": 0,
+ "kmsCommits": 0,
+ "boundPid": 100,
+ "width": 640,
+ "height": 400,
+ "fmt": "BGRA32",
+ "canvasNonBlankPixels": 249072,
+ "exitedEarly": false,
+ "exitCode": null,
+ "durationMs": 2472,
+ "stdoutTail": "",
+ "stderrTail": "",
+ "consoleErrors": [
+ "Failed to load resource: the server responded with a status of 404 (Not Found)"
+ ]
+}
diff --git a/test-runs/kd-k3l9/fb-smoke/modeset-wasm32/modeset-fb-result.json b/test-runs/kd-k3l9/fb-smoke/modeset-wasm32/modeset-fb-result.json
new file mode 100644
index 000000000..fa1d0a439
--- /dev/null
+++ b/test-runs/kd-k3l9/fb-smoke/modeset-wasm32/modeset-fb-result.json
@@ -0,0 +1,20 @@
+{
+ "mode": "kms",
+ "binds": 0,
+ "unbinds": 0,
+ "writes": 0,
+ "writeBytes": 0,
+ "kmsBlits": 0,
+ "kmsCommits": 110,
+ "boundPid": null,
+ "width": 1920,
+ "height": 1080,
+ "fmt": null,
+ "canvasNonBlankPixels": -1,
+ "exitedEarly": false,
+ "exitCode": null,
+ "durationMs": 2252,
+ "stdoutTail": "",
+ "stderrTail": "",
+ "consoleErrors": []
+}
diff --git a/test-runs/kd-k3l9/fb-smoke/outcome-lists/failed-tests.tsv b/test-runs/kd-k3l9/fb-smoke/outcome-lists/failed-tests.tsv
new file mode 100644
index 000000000..f89d46ccc
--- /dev/null
+++ b/test-runs/kd-k3l9/fb-smoke/outcome-lists/failed-tests.tsv
@@ -0,0 +1 @@
+test duration_ms error artifact_path
diff --git a/test-runs/kd-k3l9/fb-smoke/outcome-lists/passed-tests.tsv b/test-runs/kd-k3l9/fb-smoke/outcome-lists/passed-tests.tsv
new file mode 100644
index 000000000..a8ffd71a8
--- /dev/null
+++ b/test-runs/kd-k3l9/fb-smoke/outcome-lists/passed-tests.tsv
@@ -0,0 +1,6 @@
+test duration_ms details artifact_path
+homebrew_fb_vfs_build_fbdoom 1932 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew.vfs.zst; browser_url=http://127.0.0.1:65483/__kandelo-homebrew-fb-smoke/kd-k3l9-fb-72337/fbdoom-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32
+homebrew_fb_vfs_build_modeset 517 image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/modeset-wasm32/modeset-wasm32-homebrew.vfs.zst; browser_url=http://127.0.0.1:65483/__kandelo-homebrew-fb-smoke/kd-k3l9-fb-72337/modeset-wasm32-homebrew.vfs.zst /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/modeset-wasm32
+browser_server_start 2025 vite=http://127.0.0.1:65483 /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/vite.log
+fb_smoke_fbdoom 3021 binds=1 writes=1424 writeBytes=91136000 dims=640x400 canvasNonBlank=249072 screenshotBytes=0 exitedEarly=false exit=-; device=/dev/fb0 /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32/fbdoom-fb-result.json
+fb_smoke_modeset 2579 kmsCommits=110 kmsBlits=0 dims=1920x1080 screenshotBytes=0 exitedEarly=false exit=-; device=/dev/dri/card0 /Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/modeset-wasm32/modeset-fb-result.json
diff --git a/test-runs/kd-k3l9/fb-smoke/outcome-lists/skipped-tests.tsv b/test-runs/kd-k3l9/fb-smoke/outcome-lists/skipped-tests.tsv
new file mode 100644
index 000000000..622e3a6b1
--- /dev/null
+++ b/test-runs/kd-k3l9/fb-smoke/outcome-lists/skipped-tests.tsv
@@ -0,0 +1 @@
+test reason artifact_path
diff --git a/test-runs/kd-k3l9/fb-smoke/summary.json b/test-runs/kd-k3l9/fb-smoke/summary.json
new file mode 100644
index 000000000..8905ac009
--- /dev/null
+++ b/test-runs/kd-k3l9/fb-smoke/summary.json
@@ -0,0 +1,92 @@
+{
+ "suite": "Homebrew package framebuffer/device browser smoke",
+ "bead_id": "kd-k3l9",
+ "arch": "wasm32",
+ "tap_root": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-0hns/rootfs-shell-tap",
+ "formulas": [
+ "fbdoom",
+ "modeset"
+ ],
+ "counts": {
+ "pass": 5,
+ "fail": 0,
+ "skip": 0
+ },
+ "outcomes": [
+ {
+ "name": "homebrew_fb_vfs_build_fbdoom",
+ "status": "pass",
+ "durationMs": 1932,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32/fbdoom-wasm32-homebrew.vfs.zst; browser_url=http://127.0.0.1:65483/__kandelo-homebrew-fb-smoke/kd-k3l9-fb-72337/fbdoom-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32"
+ },
+ {
+ "name": "homebrew_fb_vfs_build_modeset",
+ "status": "pass",
+ "durationMs": 517,
+ "details": "image=/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/modeset-wasm32/modeset-wasm32-homebrew.vfs.zst; browser_url=http://127.0.0.1:65483/__kandelo-homebrew-fb-smoke/kd-k3l9-fb-72337/modeset-wasm32-homebrew.vfs.zst",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/modeset-wasm32"
+ },
+ {
+ "name": "browser_server_start",
+ "status": "pass",
+ "durationMs": 2025,
+ "details": "vite=http://127.0.0.1:65483",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/vite.log"
+ },
+ {
+ "name": "fb_smoke_fbdoom",
+ "status": "pass",
+ "durationMs": 3021,
+ "details": "binds=1 writes=1424 writeBytes=91136000 dims=640x400 canvasNonBlank=249072 screenshotBytes=0 exitedEarly=false exit=-; device=/dev/fb0",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/fbdoom-wasm32/fbdoom-fb-result.json"
+ },
+ {
+ "name": "fb_smoke_modeset",
+ "status": "pass",
+ "durationMs": 2579,
+ "details": "kmsCommits=110 kmsBlits=0 dims=1920x1080 screenshotBytes=0 exitedEarly=false exit=-; device=/dev/dri/card0",
+ "artifactPath": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-k3l9-browser-framebuffer-smoke/test-runs/kd-k3l9/fb-smoke/modeset-wasm32/modeset-fb-result.json"
+ }
+ ],
+ "results": {
+ "fbdoom": {
+ "mode": "fb",
+ "binds": 1,
+ "unbinds": 0,
+ "writes": 1424,
+ "writeBytes": 91136000,
+ "kmsBlits": 0,
+ "kmsCommits": 0,
+ "boundPid": 100,
+ "width": 640,
+ "height": 400,
+ "fmt": "BGRA32",
+ "canvasNonBlankPixels": 249072,
+ "exitedEarly": false,
+ "exitCode": null,
+ "durationMs": 2472,
+ "stdoutTail": "",
+ "stderrTail": ""
+ },
+ "modeset": {
+ "mode": "kms",
+ "binds": 0,
+ "unbinds": 0,
+ "writes": 0,
+ "writeBytes": 0,
+ "kmsBlits": 0,
+ "kmsCommits": 110,
+ "boundPid": null,
+ "width": 1920,
+ "height": 1080,
+ "fmt": null,
+ "canvasNonBlankPixels": -1,
+ "exitedEarly": false,
+ "exitCode": null,
+ "durationMs": 2252,
+ "stdoutTail": "",
+ "stderrTail": ""
+ }
+ }
+}
diff --git a/test-runs/kd-k3l9/sidecars-input.json b/test-runs/kd-k3l9/sidecars-input.json
new file mode 100644
index 000000000..81cfc1132
--- /dev/null
+++ b/test-runs/kd-k3l9/sidecars-input.json
@@ -0,0 +1,1363 @@
+{
+ "generated_at": "2026-06-30T14:09:12Z",
+ "generator": "kandelo-homebrew-publish 1",
+ "kandelo_abi": 16,
+ "kandelo_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "kandelo_repository": "Automattic/kandelo",
+ "packages": [
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/dash-wasm32/bottles/dash--0.5.12.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:12Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "f1cf217ac3c91d7dddf9acfa101b6ea0c090fbbbb7abe064f31f601de2e11772",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/dash",
+ "target": "bin/dash",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "dash/0.5.12",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/dash.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/dash/blobs/sha256:b07b39e7eb19324f49bd6ab23cad020354f4bcbf5602a6b6936a2633969888b8",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/dash.json",
+ "Kandelo/link/dash-0.5.12-rebuild0-wasm32.json",
+ "Kandelo/reports/dash-0.5.12-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran dash through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/dash.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/dash",
+ "name": "dash",
+ "version": "0.5.12"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/git-wasm32/bottles/git--2.47.1.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:14Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4c43e2a22ab146ab7136937652d959824578d07927521a16329dbd8474e3e3b8",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/git",
+ "target": "bin/git",
+ "type": "symlink"
+ },
+ {
+ "source": "bin/git-remote-http",
+ "target": "bin/git-remote-http",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "git/2.47.1",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/git.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/git/blobs/sha256:2ba2c7ce61393c99a06aff34744973b55bbd9e28ded2303e2f98d2363b39295f",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/git.json",
+ "Kandelo/link/git-2.47.1-rebuild0-wasm32.json",
+ "Kandelo/reports/git-2.47.1-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran git through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/git.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/git",
+ "name": "git",
+ "version": "2.47.1"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/vim-wasm32/bottles/vim--9.1.0900.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4a2a54d3a4c1052e2d484be6f8f25661bd233c49b9f0eecca5fd7040bcc222ba",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "required",
+ "links": [
+ {
+ "source": "bin/vim",
+ "target": "bin/vim",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "vim/9.1.0900",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/vim.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/vim/blobs/sha256:778be8fe04ce0439b260ed72c9bd81b163c60badd9e61c864864828198fee6ae",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/vim.json",
+ "Kandelo/link/vim-9.1.0900-rebuild0-wasm32.json",
+ "Kandelo/reports/vim-9.1.0900-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran vim through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/vim.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/vim",
+ "name": "vim",
+ "version": "9.1.0900"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/less-wasm32/bottles/less--668.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:15Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "3ec5d016d15c7b316c6643d57f66cc2f4db4ed5726c3f30356c72fa9e15d6425",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/less",
+ "target": "bin/less",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "less/668",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/less.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/less/blobs/sha256:ee8799015db23b073bb5f6f3c16953c07613f1c5dd16488cca16c9008da6c061",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/less.json",
+ "Kandelo/link/less-668-rebuild0-wasm32.json",
+ "Kandelo/reports/less-668-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran less through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/less.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/less",
+ "name": "less",
+ "version": "668"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/lsof-wasm32/bottles/lsof--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:16Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "88e06177e2acd7d54b78e9673812a7124712052ddda3599341dc208910a83b4f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/lsof",
+ "target": "bin/lsof",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "lsof/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/lsof.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/lsof/blobs/sha256:104cc2d3f485eb2da330996de062cde2574aa28d693c60d875b7af0c0d534a6b",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/lsof.json",
+ "Kandelo/link/lsof-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/lsof-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran lsof through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/lsof.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/lsof",
+ "name": "lsof",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/modeset-wasm32/bottles/modeset--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:17Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "d3fc05bf7b73121ad1d49c447b755154ebff60f6e0baac959cf54107617aac66",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/modeset",
+ "target": "bin/modeset",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "modeset/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/modeset.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/modeset/blobs/sha256:48002a330c17971fed6d7edf71872e0cce9552c8bfb3b18813092f936e14ca88",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/modeset.json",
+ "Kandelo/link/modeset-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/modeset-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran modeset through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run locally: modeset requires DRI/GLES framebuffer/device validation",
+ "skipped": [
+ "browser smoke not run locally: modeset requires DRI/GLES framebuffer/device validation"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/modeset.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/modeset",
+ "name": "modeset",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/nano-wasm32/bottles/nano--8.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:20Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "4be127352be19f0d75448a83769107716757e545aa4f3790dca8069a093aab59",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/nano",
+ "target": "bin/nano",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "nano/8.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/nano.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/nano/blobs/sha256:5c9724cea03f33dbf62b4c3edafdc797d37f2ce060a8456fee3c9f50406db2f0",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/nano.json",
+ "Kandelo/link/nano-8.0-rebuild0-wasm32.json",
+ "Kandelo/reports/nano-8.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran nano through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/nano.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/nano",
+ "name": "nano",
+ "version": "8.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/netcat-wasm32/bottles/netcat--0.7.1.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:21Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "ecfdca45ff958a00f498d460f57df18b9de2e66ecac5d95aa7c346b3686a9409",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/nc",
+ "target": "bin/nc",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "netcat/0.7.1",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/netcat.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/netcat/blobs/sha256:2eec1a038a610fca2ab8d2cc6b2feff048b009288f3fa249cbbd586107bb0efd",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/netcat.json",
+ "Kandelo/link/netcat-0.7.1-rebuild0-wasm32.json",
+ "Kandelo/reports/netcat-0.7.1-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran nc through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/netcat.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/netcat",
+ "name": "netcat",
+ "version": "0.7.1"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/wget-wasm32/bottles/wget--1.25.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:23Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "17d7408ea85bf3a5e4e8d1e1630c5a157df613b2313a5c407b6e7c7a466d1c31",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/wget",
+ "target": "bin/wget",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "wget/1.25.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/wget.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/wget/blobs/sha256:7d7b48ed79816e1c2e3812b68d4f0eb82d1178118a37d1b01cf0ee7e38f1a5ad",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/wget.json",
+ "Kandelo/link/wget-1.25.0-rebuild0-wasm32.json",
+ "Kandelo/reports/wget-1.25.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran wget through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run in this local bottle verification pass; Node formula smoke passed",
+ "skipped": [
+ "browser smoke not run in this local bottle verification pass; Node formula smoke passed"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/wget.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/wget",
+ "name": "wget",
+ "version": "1.25.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-bry6-interactive-network-device-cli/test-runs/kd-bry6/homebrew-bottles/fbdoom-wasm32/bottles/fbdoom--0.1.0.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T14:09:13Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "e74be0eac8237d4345eb1db5c0c6d59aa0a20a54d7a603affeaa76190c7effc3",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/fbdoom",
+ "target": "bin/fbdoom",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "fbdoom/0.1.0",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/fbdoom.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/fbdoom/blobs/sha256:51f8e3d28b47a182dbee12dd6eb25ab1a39c4c11cb6f78da51183d442796173c",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/fbdoom.json",
+ "Kandelo/link/fbdoom-0.1.0-rebuild0-wasm32.json",
+ "Kandelo/reports/fbdoom-0.1.0-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran fbdoom through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "browser smoke not run locally: fbdoom requires IWAD data plus framebuffer/audio device validation",
+ "skipped": [
+ "browser smoke not run locally: fbdoom requires IWAD data plus framebuffer/audio device validation"
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/fbdoom.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/fbdoom",
+ "name": "fbdoom",
+ "version": "0.1.0"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.2-port-sqlite-bzip2-and-xz-homebrew-pilot/test-runs/kd-1mr.2/homebrew-bottles/bzip2-wasm32/bottles/bzip2--1.0.8.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T03:05:02Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "49c19e83209e7954c9f8399262cd76d7e23868e4a022e4502f8668d4e0c9cd5f",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/bzip2",
+ "target": "bin/bzip2",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "bzip2/1.0.8",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/bzip2.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/bzip2/blobs/sha256:98468e8b210c247f40eb35e2c394bcdccbf18e1f9305fcc7946292327fe5167a",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/bzip2.json",
+ "Kandelo/link/bzip2-1.0.8-rebuild0-wasm32.json",
+ "Kandelo/reports/bzip2-1.0.8-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran bzip2 --help through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "No successful browser VFS smoke was recorded for bzip2 wasm32.",
+ "skipped": [
+ "No successful browser VFS smoke was recorded for bzip2 wasm32."
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/bzip2.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/bzip2",
+ "name": "bzip2",
+ "version": "1.0.8"
+ },
+ {
+ "bottle_rebuild": 0,
+ "bottles": [
+ {
+ "arch": "wasm32",
+ "bottle_file": "/Users/brandon/src/kandelo-gascity/worktrees/kandelo/kd-1mr.2-port-sqlite-bzip2-and-xz-homebrew-pilot/test-runs/kd-1mr.2/homebrew-bottles/xz-wasm32/bottles/xz--5.6.2.wasm32_kandelo.bottle.tar.gz",
+ "bottle_tag": "wasm32_kandelo",
+ "browser_compatible": true,
+ "build": {
+ "brew_version": "Homebrew 6.0.5",
+ "dev_shell": "scripts/dev-shell.sh",
+ "github_run": "https://github.com/local/kandelo/actions/runs/local",
+ "job": "local",
+ "runner_os": "local",
+ "sdk_fingerprint": "a7ef0c406359039ee25d54e4f8baee3afdc857cdbcac5df9a065ef875b3a3b48",
+ "sysroot_fingerprint": "d19b801e0da64ff3415019de982ee194ef093de68e1a08d25f41a82f07bcca98"
+ },
+ "built_at": "2026-06-30T03:00:22Z",
+ "built_by": "https://github.com/local/kandelo/actions/runs/local",
+ "cache_key_sha": "6dcdd72b55ed0fbb6edc38c3854216da67579110efbaf56ee35803c7aec84027",
+ "cellar": "/home/linuxbrew/.linuxbrew/Cellar",
+ "env": {
+ "PATH_prepend": [
+ "bin"
+ ]
+ },
+ "fork_instrumentation": "not-required",
+ "links": [
+ {
+ "source": "bin/xz",
+ "target": "bin/xz",
+ "type": "symlink"
+ }
+ ],
+ "payload_root": "xz/5.6.2",
+ "prefix": "/home/linuxbrew/.linuxbrew",
+ "receipts": [
+ ".brew/xz.rb",
+ "INSTALL_RECEIPT.json"
+ ],
+ "runtime_support": [
+ "browser",
+ "node"
+ ],
+ "status": "success",
+ "url": "https://ghcr.io/v2/automattic/kandelo-homebrew/xz/blobs/sha256:887c92f55f775a041503e670cd7a2d845839fa2167c89440ede0fb127a37a0ca",
+ "validation": {
+ "outcome_lists": [
+ {
+ "failed": [],
+ "name": "schema",
+ "passed": [
+ "Kandelo/metadata.json",
+ "Kandelo/formula/xz.json",
+ "Kandelo/link/xz-5.6.2-rebuild0-wasm32.json",
+ "Kandelo/reports/xz-5.6.2-rebuild0-wasm32.provenance.json"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "homebrew_audit",
+ "passed": [],
+ "skip_reason": "Tap audit can run in the trusted tap publication gate.",
+ "skipped": [
+ "brew audit was not part of this local dry-run verification"
+ ],
+ "status": "skipped"
+ },
+ {
+ "failed": [],
+ "name": "bottle_build",
+ "passed": [
+ "brew install --build-bottle",
+ "brew test",
+ "brew bottle --json --no-rebuild",
+ "brew bottle --merge --write --no-commit"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "node_smoke",
+ "passed": [
+ "Formula test ran xz --version through node --import tsx/esm examples/run-example.ts"
+ ],
+ "skipped": [],
+ "status": "success"
+ },
+ {
+ "failed": [],
+ "name": "browser_smoke",
+ "passed": [],
+ "skip_reason": "No successful browser VFS smoke was recorded for xz wasm32.",
+ "skipped": [
+ "No successful browser VFS smoke was recorded for xz wasm32."
+ ],
+ "status": "skipped"
+ }
+ ]
+ }
+ }
+ ],
+ "dependencies": [],
+ "formula_path": "Formula/xz.rb",
+ "formula_revision": 0,
+ "full_name": "automattic/kandelo-homebrew/xz",
+ "name": "xz",
+ "version": "5.6.2"
+ }
+ ],
+ "release_tag": "bottles-abi-v16",
+ "schema": 1,
+ "tap_commit": "1ab41fe2ad5553f4fa4bb0223f2d804b13149578",
+ "tap_name": "automattic/kandelo-homebrew",
+ "tap_repository": "Automattic/kandelo-homebrew"
+}