Skip to content

Document registered fonts and prove the CJK path on Windows CI #399

Document registered fonts and prove the CJK path on Windows CI

Document registered fonts and prove the CJK path on Windows CI #399

Workflow file for this run

name: CI
on:
pull_request:
push:
branches:
- main
permissions:
contents: read
jobs:
zig:
name: Zig Core
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- uses: actions/setup-node@v4
with:
node-version: 22
# The TypeScript core suites transpile at build/test time; without
# node they skip silently, so CI must provide it.
- run: npm ci --prefix packages/core
- run: zig build test
- run: zig build validate
macos-webview:
name: macOS WebView
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- run: zig build test-webview-system-link
- run: zig build test-webview-smoke
# Signed-package seal pin: an ad-hoc signed package must pass
# codesign --verify --strict (macOS runners are the only tier with
# codesign; the step skips loudly anywhere else).
- run: zig build test-package-signing
# Shared macos-14 runners are far noisier than a dev box (the second
# CI run measured a 576 ms automation-ready against the 500 ms local
# ceiling), so widen the smoke budgets here instead of weakening the
# local defaults. NATIVE_SDK_SMOKE_BUDGET_MS raises the first-frame latency
# budget and the automation-ready ceiling together; every correctness
# assertion in the smokes stays strict.
- run: zig build test-gpu-dashboard-smoke
env:
NATIVE_SDK_SMOKE_BUDGET_MS: "1500"
- run: zig build test-gpu-components-smoke
env:
NATIVE_SDK_SMOKE_BUDGET_MS: "1500"
macos-gpu-perf:
name: macOS GPU Perf
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
# Percentile perf check: 5 cold launches asserting p90
# first-frame latency under NATIVE_SDK_PERF_BUDGET_MS, then 5 steady-state
# widget clicks asserting p90 input latency under NATIVE_SDK_PERF_INPUT_BUDGET_MS.
# Its own job so a shared-runner slowdown is visible in isolation and
# never blocks the correctness smokes.
# Shared macos-14 runners are far noisier than a dev box (first CI run
# measured a 581 ms cold-start outlier against the 300 ms default), so
# widen the budgets here instead of weakening the local defaults: this
# job exists to catch step-function regressions, not runner noise.
- run: zig build test-gpu-dashboard-perf
env:
NATIVE_SDK_PERF_BUDGET_MS: "1500"
NATIVE_SDK_PERF_INPUT_BUDGET_MS: "500"
linux-webkitgtk:
name: Linux WebKitGTK
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- name: Install WebKitGTK dependencies
run: sudo apt-get update && sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev
- run: zig build test-webview-system-link -Dplatform=linux
# Declare-to-use, proven on real Linux executables WITH the
# WebKitGTK dev package installed — the seam, not the environment:
# the native-only ui-inbox binary must carry no libwebkitgtk
# DT_NEEDED entry and no webkit_/jsc_ dynamic symbol even though
# the headers were right there, while the webview example must
# keep them. (The environment half — building native-only on a
# runner with no WebKitGTK dev package at all — is the
# linux-canvas-smoke job.)
- run: zig build test-linux-web-layer-audit
windows-webview:
name: Windows WebView
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
# Builds the WebView example with the system engine, compiling the
# full embedded-WebView host against the vendored WebView2 SDK
# header (third_party/webview2). The host refuses to fall back to
# the stubbed layer, so a regression — a missing header, a broken
# include path, or a conformance error in the embedded layer — is a
# compile failure here, not a silent WebViewNotFound at runtime.
- run: zig build test-webview-system-link -Dplatform=windows
# The registered-font receipt, natively on Windows: runs the
# font-registry suite — registration validation, the glyph-budget
# gate, present/reference pixel parity, and the Chinese-receipt
# test that registers the committed subsetted Noto Sans SC through
# the app-fonts seam and proves the rendered string is real glyphs,
# not tofu — on real Windows, not under emulation. The font
# pipeline is platform-neutral Zig, so this lane pins that neutral
# truth on a Windows host (the Linux run lives in the Zig Core
# lane's `zig build test`).
- run: zig build test-canvas-fonts
cef-platform-tooling:
name: CEF Platform Tooling
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- uses: actions/setup-node@v4
with:
node-version: 22
# The TypeScript core suites transpile at build/test time; without
# node they skip silently, so CI must provide it.
- run: npm ci --prefix packages/core
- run: zig build test-tooling
npm-package:
name: npm Package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
- run: npm --prefix packages/native-sdk run version:check
- run: npm --prefix packages/native-sdk run scripts:check
native-examples:
name: Native Examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- uses: actions/setup-node@v4
with:
node-version: 22
# The TypeScript examples transpile at build time; the transpiler
# needs its installed dependency.
- run: npm ci --prefix packages/core
- name: Install GTK dependencies
run: sudo apt-get update && sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev
- run: zig build test-examples-native
# Declare-to-use, proven on real Windows executables: the
# canvas-only ui-inbox cross-compiles without the embedded WebView
# layer (no WebView2Loader.dll reference, no loader installed) and
# the webview example keeps it.
- run: zig build test-windows-web-layer-audit
linux-canvas-smoke:
name: Linux Canvas Smoke
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
# Deliberately NO libwebkitgtk-6.0-dev: ui-inbox declares no web
# use, so its host compiles with the WebKitGTK stub seam and this
# job doubles as the native-only Linux LINK test — the build can
# only succeed if nothing in a native-only app needs the WebKitGTK
# headers or pkg-config entry. (The seam under webkit-PRESENT
# conditions is the linux-webkitgtk job's ELF cross-audit.)
- name: Install GTK and Xvfb
run: sudo apt-get update && sudo apt-get install -y libgtk-4-dev xvfb
# The stub is the expected, configured state of every native-only
# Linux app, so compiling the GTK host with the stub define must be
# diagnostic-FREE, not merely successful: zig renders every clang
# diagnostic of a failing translation unit as `error:` (serialized
# clang diagnostics carry no severity into its error bundle), so
# even an informational #pragma message in this path masquerades as
# the build-killing error the moment any unrelated real error
# appears in the file. `zig cc` runs clang in passthrough mode,
# where warnings actually reach stderr — `zig build` only surfaces
# C diagnostics on failure, which is exactly the escalation this
# step pins against. The throwaway cache dir keeps the compile
# cold: on a cache hit zig replays nothing, stderr included, so a
# warm cache (setup-zig restores one) would hide the diagnostics
# this step exists to catch.
- name: WebKitGTK stub compile is diagnostic-free
run: |
export ZIG_GLOBAL_CACHE_DIR=$(mktemp -d) ZIG_LOCAL_CACHE_DIR=$(mktemp -d)
status=0
out=$(zig cc -c src/platform/linux/gtk_host.c -DNATIVE_SDK_ALLOW_WEBKITGTK_STUB $(pkg-config --cflags gtk4) -o /tmp/gtk_host_stub.o 2>&1) || status=$?
if [ "$status" -ne 0 ] || [ -n "$out" ]; then
echo "the WebKitGTK stub compile must succeed with zero diagnostics (exit $status):"
echo "$out"
exit 1
fi
# Drives the gpu_surface software path under Xvfb: snapshot ready,
# gpu_backend=software, gpu_nonblank=true, automation widget-click,
# a rendered screenshot, an ELF audit that the built binary carries
# no WebKitGTK reference, and ZERO WebKit helper processes (canvas
# apps never boot WebKit). A11y env, the widened cold-start
# readiness budget (shared runners stall ~27 s before the first
# runtime event), and failure forensics (dump snapshot + app log)
# all live in the script.
- name: Build and drive ui-inbox headless
run: .github/scripts/linux-canvas-smoke.sh
# Durable receipt for the GLib 2.72 fallback (the pre-2.74
# G_APPLICATION_DEFAULT_FLAGS shim in gtk_host.c): no stock image
# pairs an old glib with GTK >= 4.10 (only backport distros do),
# and ubuntu 22.04 ships GTK 4.6 — so a clean compile is
# impossible here by design. This pins the error SET instead:
# every diagnostic must match a GTK-age shape (the allowlist
# script holds the shapes, why cascades are allowed, and the
# positive-evidence floor) — a 2.74+ glib symbol, type, or
# member used without a version-checked fallback surfaces as a
# rejected diagnostic and fails this step, and so does a compile
# that produced no classifiable error set at all. If this compile ever succeeds outright, the premise
# changed (newer GTK in the image) and the receipt must be
# re-verified rather than trusted.
- name: GTK host GLib 2.72 fallback holds (error-set receipt)
run: |
docker run --rm -v "$PWD:/src" -v "$(dirname "$(which zig)"):/zig" ubuntu:22.04 bash -ec '
export DEBIAN_FRONTEND=noninteractive
apt-get update -q >/dev/null && apt-get install -y -q libgtk-4-dev pkg-config >/dev/null
export ZIG_GLOBAL_CACHE_DIR=$(mktemp -d) ZIG_LOCAL_CACHE_DIR=$(mktemp -d)
status=0
out=$(/zig/zig cc -c /src/src/platform/linux/gtk_host.c -DNATIVE_SDK_ALLOW_WEBKITGTK_STUB $(pkg-config --cflags gtk4) -ferror-limit=0 -o /tmp/gtk_host_2272.o 2>&1) || status=$?
if [ "$status" -eq 0 ]; then
echo "unexpected clean compile on ubuntu 22.04 - this receipt assumes GTK-age errors; re-verify what it proves now"
exit 1
fi
echo "$out" | python3 /src/.github/scripts/glib272_error_allowlist.py
'
linux-dev-smoke:
name: Linux Dev Smoke (Debug scaffold)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- uses: actions/setup-node@v4
with:
node-version: 22
# The scaffold default is the TypeScript core; its transpiler runs
# under node at build time from this checkout's packages/core.
- run: npm ci --prefix packages/core
# No WebKitGTK dev package, same as linux-canvas-smoke: the scaffold
# declares no web use, so its host compiles with the stub seam.
- name: Install GTK and Xvfb
run: sudo apt-get update && sudo apt-get install -y libgtk-4-dev xvfb
# The Debug half of the Linux runtime story: linux-canvas-smoke runs
# at the graph's release default, and Release always uses the LLVM
# backend — a Debug-only x86_64 codegen fault (self-hosted backend,
# the mode every fresh `native init` + `native dev` builds) stays
# invisible to it. This job scaffolds the default template with the
# CLI, builds it -Doptimize=Debug with automation, runs it under
# Xvfb, and requires the startup scene to come up (ready=true,
# gpu_nonblank=true, template widgets in the snapshot).
- name: Scaffold and drive the Debug template headless
run: .github/scripts/linux-dev-smoke.sh
windows-canvas-smoke:
name: Windows Canvas Smoke (Wine)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- name: Install Wine, Xvfb, and xdotool
run: sudo apt-get update && sudo apt-get install -y wine xvfb xdotool
# The Windows twin of the linux-canvas-smoke stub receipt: the
# WebView2 stub is the expected, configured state of every
# native-only Windows app, so cross-compiling the host with the
# stub define must be diagnostic-free (see that job's step comment
# for why even an informational #pragma message is dangerous, and
# why the compile must run against a cold cache).
- name: WebView2 stub cross-compile is diagnostic-free
run: |
export ZIG_GLOBAL_CACHE_DIR=$(mktemp -d) ZIG_LOCAL_CACHE_DIR=$(mktemp -d)
status=0
out=$(zig c++ -target x86_64-windows-gnu -std=c++17 -DNATIVE_SDK_ALLOW_WEBVIEW2_STUB -c src/platform/windows/webview2_host.cpp -o /tmp/webview2_host_stub.o 2>&1) || status=$?
if [ "$status" -ne 0 ] || [ -n "$out" ]; then
echo "the WebView2 stub cross-compile must succeed with zero diagnostics (exit $status):"
echo "$out"
exit 1
fi
# Cross-compiles ui-inbox for x86_64-windows-gnu and drives the
# gpu_surface software path (child HWND + WM_TIMER + SetDIBitsToDevice)
# under Wine: snapshot ready, gpu_backend=software, gpu_nonblank=true,
# automation widget-click, and real XTEST pointer/keyboard input.
# Wineprefix init happens inline in the script (measured 21s from
# scratch in an ubuntu-24.04 container, so no cache step).
- name: Build and drive ui-inbox.exe under Wine
run: .github/scripts/windows-canvas-smoke.sh
windows-effects-smoke:
name: Windows Effects Smoke (Wine)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- name: Install Wine and Xvfb
run: sudo apt-get update && sudo apt-get install -y wine xvfb
# Cross-compiles examples/effects-probe for x86_64-windows-gnu and
# proves the effect system's live Windows path under Wine: fx.spawn
# launches cmd.exe, streamed lines land in the model, the worker's
# PostMessageW wake shows up as effects_wake events in the trace
# log (frame ticks also drain, so the log is the wake's evidence),
# and fx.cancel terminates the child with the line count frozen.
- name: Build and drive effects-probe.exe under Wine
run: .github/scripts/windows-effects-smoke.sh
frontend-examples:
name: Frontend Examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- run: zig build test-examples-frontends
mobile-examples:
name: Mobile Examples
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- run: zig build test-examples-mobile
scaffold:
name: Generated App Scaffolds
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.16.0
- uses: actions/setup-node@v4
with:
node-version: 22
# The default scaffold is a TypeScript core: its build runs the
# @native-sdk/core transpiler from this checkout's own install.
- run: npm ci --prefix packages/core
- run: zig build
- name: Scaffold and test the zero-config native app
run: |
set -euo pipefail
app=".zig-cache/scaffold-native-slim"
rm -rf "$app"
./zig-out/bin/native init "$app"
# Slim scaffold: no build files — the CLI's generated graph drives it.
test ! -f "$app/build.zig"
test ! -f "$app/build.zig.zon"
# The editor surface landed: package.json + tsconfig.json + the
# materialized @native-sdk/core copy stock tsc resolves.
test -f "$app/package.json"
test -f "$app/tsconfig.json"
test -f "$app/node_modules/@native-sdk/core/sdk/core.ts"
# ...and none of it is build truth: every verb works without it.
rm -rf "$app/node_modules"
./zig-out/bin/native test "$app" -Dplatform=null
./zig-out/bin/native check "$app"
# check self-healed the editor copy back into place.
test -f "$app/node_modules/@native-sdk/core/sdk/core.ts"
./zig-out/bin/native eject "$app"
(cd "$app" && zig build test -Dplatform=null)
- name: Scaffold and test frontend templates
run: |
set -euo pipefail
for frontend in native next vite react svelte vue; do
app=".zig-cache/scaffold-${frontend}"
rm -rf "$app"
./zig-out/bin/native init "$app" --frontend "$frontend" --full
(cd "$app" && zig build test -Dplatform=null && ../../zig-out/bin/native validate app.zon)
# Every scaffold ships a CI workflow; parse it as real YAML.
test -s "$app/.github/workflows/ci.yml"
python3 -c 'import sys, yaml; yaml.safe_load(open(sys.argv[1]))' "$app/.github/workflows/ci.yml"
done
evals-typecheck:
name: Evals Typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- uses: pnpm/action-setup@v4
with:
version: 10.23.0
package_json_file: evals/package.json
- run: pnpm install --frozen-lockfile
working-directory: evals
- run: pnpm typecheck
working-directory: evals
docs:
name: Docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- uses: pnpm/action-setup@v4
with:
version: 10.23.0
package_json_file: docs/package.json
- run: pnpm install --frozen-lockfile
working-directory: docs
- run: pnpm check
working-directory: docs