How to record matching-host evidence for ADR 0006 and eventually flip
NativeGpuPlatform::gpu_promoted so auto selects SkiaGpuNative.
This is Wave A tooling: scaffold manifests, gate inventory, macOS short-path hooks, and validators. It does not promote any platform by itself.
- Source paths, package tests, offscreen GPU smoke, and
PictureRecordedare not promotion. - Each platform promotes independently.
- Flip
gpu_promotedin source only after a manifest passesnode scripts/validate-gpu-promotion-manifest.mjs <file> --require-passed(mobile: runtime manifest withgpuPromotionEvidenceunder--require-passed). - Do not commit generated files under
artifacts/(gitignored). Link CI artifacts or smoke logs from ADR 0006 / release notes.
| Gate | Requirement |
|---|---|
readbackEliminated |
Production present path: no full-frame CPU readback / image intermediates |
rendererThread |
Worker owns GPU context/surface |
mailboxOk |
Latest-wins frames; lifecycle controls never dropped |
performance |
≥ 600s; p95 ≤ 16.7ms@60 / 8.3ms@120; dropped < 1%; input→present ≤ 2 VSync |
memory |
Bounded; ≥ 100 surface recreations; ≥ 100 fg/bg cycles |
contextLoss |
Recover ≤ 3 VSyncs; raster fallback keeps AppRuntime |
rasterFallback |
Automatic after repeated recovery failure |
Schema example: gpu-promotion-manifest.example.json.
moon run tools/moui/gpu_promotion_scaffold --target native -- \
--platform macos --out-dir artifacts/gpu-promotion/macos/manualNode scripts/record-gpu-promotion-smoke.mjs is a thin orchestrator over this tool
(and optional macOS short-smoke).
node scripts/validate-gpu-worker-no-readback.mjsnode scripts/record-gpu-promotion-smoke.mjs --platform macosWrites under artifacts/gpu-promotion/<platform>/<timestamp>/:
gpu-promotion-manifest.json— alwaysgpuPromoted: falsefor Wave Agap-report.md— what still blocksauto→ GPUgate-inventory.json— tooling coverage per gaterecorder.log
node scripts/record-gpu-promotion-smoke.mjs --platform macos --mode short-smokeRuns scripts/macos-skia-renderer-smoke.sh --run-gpu-smoke --run-showcase-smoke,
parses Metal markers, and fills partial diagnostics. Still not
promotion.
Direct smoke (without recorder):
scripts/macos-skia-renderer-smoke.sh --run-gpu-smoke --run-showcase-smoke# Schema / structural checks (pending manifests OK)
node scripts/validate-gpu-promotion-manifest.mjs \
artifacts/gpu-promotion/macos/<ts>/gpu-promotion-manifest.json
# Promotion bar (must fail until gates are real)
node scripts/validate-gpu-promotion-manifest.mjs \
artifacts/gpu-promotion/macos/<ts>/gpu-promotion-manifest.json \
--require-passed# 15s measured window after warm-up (dev)
node scripts/run-macos-gpu-performance-smoke.mjs --duration-ms 15000 --prepare
# ADR performance gate length
node scripts/run-macos-gpu-performance-smoke.mjs --duration-ms 600000 --prepare
# or via recorder
node scripts/record-gpu-promotion-smoke.mjs --platform macos --mode performance --duration-seconds 15Success log must include surface_route=metal-gpu; surface_gpu=true; gpu_context=worker-owned; present_kind=host-gpu-surface. If you see Ganesh Metal runtime is unavailable; falling back to raster, numbers are not GPU-present evidence. Ordinary runs use moon run ... --target native; Skia/Metal flags come from moui_skia prebuild.
Writes metrics.json with p95/drop%/duration. Still leaves mailbox/memory/context-loss gates incomplete and never sets gpuPromoted=true.
node scripts/record-gpu-promotion-smoke.mjs --platform macos --dry-run| Mode | Status | Meaning |
|---|---|---|
scaffold |
implemented | Pending manifest + inventory |
short-smoke |
macOS only | Metal first-frame / GPU smoke markers |
full |
skeleton only | Writes full-plan.json + metrics-template.json, can merge --metrics-json, exits 3 |
full still exits 3 so automation cannot treat it as promotion success. Measured values may be merged through:
moon run tools/moui/gpu_promotion_scaffold --target native -- \
--platform macos --out-dir artifacts/gpu-promotion/macos/manual \
--mode full --metrics-json path/to/metrics.jsonEven with metrics merged, the tool never sets gpuPromoted=true.
Local macOS short-path recording example (partial evidence only):
node scripts/record-gpu-promotion-smoke.mjs --platform macos --mode short-smoke
# expect shortPathOk=true, gpuPromoted=false, schema validate okAs of 2026-07-14, all NativeGpuPlatform::gpu_promoted arms return true.
Product auto selects GPU whenever the host surface is available. This runbook
still records matching-host seven-gate evidence for quality claims; it no longer
gates the product default.
Keep working:
- explicit
skia-raster/MOUI_SKIA_RENDERER=skia-raster - sticky raster recovery after terminal GPU failure
- fallback-Skia packaging (
gpuPromoted: false, selected raster)
- macOS Metal (claim already recorded)
- Web WebGPU (optional promotion record; already product GPU mainline)
- iOS Metal (device)
- Android Vulkan (+ API 23 GLES fallback evidence)
- HarmonyOS EGL (signed device)
- Windows D3D12 (MSVC host)
- Linux Wayland Vulkan
- ADR:
decisions/0005-mobile-host-and-gpu.md - Embedded-runtime route:
window-hosted-moui.md - Capability notes:
renderer-capability-report.md - Session: see
docs/ai-sessions/for the all-platform native GPU workers session log.