Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,47 @@ jobs:
path: target/ci/full-host-build.json
if-no-files-found: error

- uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Cache matching Perry source build
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/bloom-perry
key: windows-perry-${{ hashFiles('tools/ci/setup_windows_perry.py') }}

- name: Prepare pinned Windows example toolchain
shell: pwsh
env:
CARGO_BUILD_JOBS: '2'
run: python tools/ci/setup_windows_perry.py --out "$env:RUNNER_TEMP/bloom-perry" --github-env

- name: full / example-compile
env:
CARGO_BUILD_JOBS: '2'
run: ./scripts/ci-check.sh --full --component example-compile

- name: Retain executed example-check summary
if: always()
uses: actions/upload-artifact@v4
with:
name: windows-example-summary
path: target/ci/full-example-compile.json
if-no-files-found: error

- name: Retain native example build evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: windows-example-builds
path: |
target/ci/examples/result.json
target/ci/examples/logs/
${{ runner.temp }}/bloom-perry/toolchain.json
${{ runner.temp }}/bloom-perry/runtime-build.log
if-no-files-found: error

- name: Upload failure evidence
if: failure()
uses: ./.github/actions/upload-ci-failure
Expand Down
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,34 @@ dependencies listed in `.github/workflows/test.yml` (CMake and a C++ compiler
everywhere, X11/audio development packages on Linux, and the MSVC developer
environment on Windows).

Run the platform-independent PR gates while iterating:
Example checks require Perry on `PATH`. Windows CI pins Perry 0.5.1220 and its
matching source because the release's prebuilt standard library has unresolved
HTTP extension symbols. Prepare that same toolchain from PowerShell:

```powershell
python tools/ci/setup_windows_perry.py --out "$env:LOCALAPPDATA/Bloom/perry-ci-0.5.1220"
$env:PATH = "$env:LOCALAPPDATA/Bloom/perry-ci-0.5.1220/bin;$env:PATH"
$env:PERRY_WORKSPACE_ROOT = "$env:LOCALAPPDATA/Bloom/perry-ci-0.5.1220/source"
$env:PERRY_RUNTIME_DIR = "$env:LOCALAPPDATA/Bloom/perry-ci-0.5.1220/runtime-build/release"
$env:PERRY_NO_AUTO_OPTIMIZE = '1'
```

Setup builds matching runtime libraries once, with the feature set used by the
examples and the same unwind profile as Bloom's Rust library. Reusing that
profile avoids Windows linker collisions with per-app panic-abort libraries.
Other hosts also need a compiler supporting `bloomViewGetNativeHandle` for the
embedded-view example; the complete Windows matrix uses the pinned toolchain
above. Native compilation does not establish browser or rendered-frame startup.

Run the quick gates while iterating, including a native compile and link of Pong:

```bash
./scripts/ci-check.sh --quick
```

Before handing off a change, run the complete suite for the current host,
including its native crate and the packaged WebAssembly build:
including its native crate, all 20 canonical example links, and the packaged
WebAssembly build:

```bash
./scripts/ci-check.sh --full
Expand Down
53 changes: 53 additions & 0 deletions docs/evidence/windows-example-gate-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Native example build gate

All 20 canonical examples compile and link on Windows with the same Perry
0.5.1220 compiler and matching source-built runtime profile. This includes
`perry-embed`, whose native-view API is absent from the earlier 0.5.1182 release.
The gate retains a fresh executable's byte count and SHA-256, compiler command,
environment, and logs for every example. This establishes native linking;
startup and rendered-frame acceptance remain separate.

## Toolchain findings

The 0.5.1219 and 0.5.1220 Windows bundles have unresolved HTTP-extension symbols
in their prebuilt full standard library. Rebuilding the exact 0.5.1220 source
at `06137858dc8c6f80975238377138f2f948d6ef88` resolves the embedded-view link.
Perry's automatic per-app profile then exposes five different link failures:
Dungeon Crawl, Isometric RPG, Pong, Space Blaster, and Test Scene Watch fail
with relocations into discarded Rust COMDAT sections when linking Bloom's
unwind library with panic-abort runtime archives. All other 15 examples link.

Using one unwind profile with the union of required runtime features resolves
those failures. The profile enables runtime `full` and `regex-engine`, and
stdlib `async-runtime` and `crypto`. The setup tool verifies the official ZIP
SHA-256, exact source commit, unchanged source, and Cargo lockfile; builds the
libraries with `--locked`; and records their hashes and Rust compiler identity.
It uses Perry's supported runtime-directory and auto-optimization overrides.
The compiler and its source are unmodified.

The initial all-example invocation with this profile passes 20/20 native links
in 157.672 seconds on this host. Build time is an observation, not a performance
budget. Earlier failed profiles and their logs are retained.

## Required checks

The quick lane links Pong. The full and hardware lanes link every canonical
example. Windows PR CI runs the same full-lane component after building the
engine, with a pinned source/toolchain cache and required execution summary.
The compiler gate rejects zero exit status without a new native binary, so an
old output or object-only compilation cannot count as success. Failures and
timeouts do not hide later example results.

Three orchestration regressions, the full quality-contract component, and
repository contracts pass locally. Hosted example execution is pending.

The preceding [Windows CI correction](windows-example-ci-v1.md) now proves an
actual hosted native build at `636b69a`. Its shared suite exposes two DX12 GPU
failures and a process crash. Both focused GPU failures also reproduce on the
Radeon and the Microsoft software adapter with explicit DX12 selection; Vulkan
passes. Those failures remain required and are under separate investigation.
No broader CI, startup, packaging, or hardware issue is closed by this report.

Commands, failed profiles, successful executable hashes, setup receipts, and
logs are retained under
`tools/quality/out/windows-engine-plan/all-examples/`.
18 changes: 10 additions & 8 deletions docs/windows-engine-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,18 @@ audit are saved in `tools/quality/out/windows-engine-plan/plan-requirements.json

## Current next steps

1. Verify actual hosted Windows test and build execution. The
1. Complete hosted Windows test and build execution. The
[CI and example correction](evidence/windows-example-ci-v1.md) explicitly
selects Bash and requires execution-summary artifacts. Its hosted run must
show Cargo output and successful summary contents before this gap is closed.
selects Bash, restores the MSVC linker ahead of Git's tools, and requires
execution-summary artifacts. The hosted native build passes at `636b69a`.
The shared suite exposes two DX12 GPU failures and a process crash; both
focused GPU failures also reproduce locally under DX12 and remain open.
2. Finish all-example native linking, real starter/example startup, and clean
Windows installation. Six palette corrections bring the local link audit
from 13 to 19 successful examples out of 20. The embedded-view example needs
a newer Perry API, and both available newer Windows bundles have an
independent standard-library link failure that still needs resolution.
All-example compilation must become a required PR check.
Windows installation. The [native example gate](evidence/windows-example-gate-v1.md)
passes all 20 links locally using Perry 0.5.1220 and one matching source-built
runtime profile. It adds required full-lane Windows PR compilation and
rejects missing or stale executable outputs. Hosted example validation,
actual startup, and clean package installation remain required.
3. Complete the wider temporal/geometry, performance, memory, resize, and
capability corpus. The
[HD surface correction](evidence/windows-ssgi-surface-v1.md) and two valid
Expand Down
43 changes: 29 additions & 14 deletions scripts/ci-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ done

lane_components() {
case "$1" in
quick) printf '%s\n' "contracts lint shared-tests wasm-check quality-contract example-inventory" ;;
full) printf '%s\n' "contracts lint shared-tests wasm-check quality-contract example-inventory host-build wasm-build" ;;
quick) printf '%s\n' "contracts lint shared-tests wasm-check quality-contract example-inventory example-compile" ;;
full) printf '%s\n' "contracts lint shared-tests wasm-check quality-contract example-inventory host-build example-compile wasm-build" ;;
web) printf '%s\n' "wasm-check wasm-build browser-smoke" ;;
cross) printf '%s\n' "target-check" ;;
hardware) printf '%s\n' "example-compile quality-check quality-faults quality-run fractional-native-throughput virtual-geometry-stress" ;;
Expand Down Expand Up @@ -113,6 +113,12 @@ case "$host_os" in
*) host_crate="" ;;
esac

python_cmd="python3"
if [ "$host_crate" = "windows" ]; then
# Windows installers expose python.exe; python3 may be a Store alias.
python_cmd="python"
fi

ALLOWED_COMPONENTS="$(lane_components "$LANE")"
if [ -n "$COMPONENT" ]; then
case " $ALLOWED_COMPONENTS " in
Expand Down Expand Up @@ -260,7 +266,7 @@ run_component() {
;;
quality-contract)
hr "quality orchestration syntax and governance tests"
python3 -m py_compile \
"$python_cmd" -m py_compile \
tools/quality/run.py \
tools/quality/build_example.py \
tools/quality/khronos_materials.py \
Expand All @@ -272,8 +278,11 @@ run_component() {
tools/quality/vsm_motion_corpus.py \
tools/quality/prepare_bistro.py \
tools/ci/web_smoke.py \
tools/ci/test_web_smoke.py
python3 -m unittest \
tools/ci/test_web_smoke.py \
tools/ci/compile_examples.py \
tools/ci/setup_windows_perry.py \
tools/ci/test_compile_examples.py
"$python_cmd" -m unittest \
tools/quality/test_run.py \
tools/quality/test_khronos_materials.py \
tools/quality/test_shadow_detail.py \
Expand All @@ -283,6 +292,7 @@ run_component() {
tools/quality/test_vsm_debug_views.py \
tools/quality/test_vsm_motion_corpus.py \
tools/ci/test_web_smoke.py \
tools/ci/test_compile_examples.py \
-v
hr "visual metric and fault-engine tests"
cargo test --release --manifest-path tools/bloom-diff/Cargo.toml
Expand All @@ -297,7 +307,7 @@ run_component() {
;;
example-inventory)
hr "canonical TypeScript example inventory"
python3 tools/ci/compile_examples.py --check
"$python_cmd" tools/ci/compile_examples.py --check
;;
host-build)
if [ -z "$host_crate" ]; then
Expand All @@ -317,7 +327,7 @@ run_component() {
;;
browser-smoke)
hr "Bloom WebGPU real-browser known-frame smoke"
python3 tools/ci/web_smoke.py
"$python_cmd" tools/ci/web_smoke.py
;;
target-check)
cross_crate="${BLOOM_CROSS_CRATE:-}"
Expand Down Expand Up @@ -382,16 +392,21 @@ run_component() {
( cd "native/$cross_crate" && cargo "${cargo_args[@]}" )
;;
example-compile)
hr "compile every canonical TypeScript example"
python3 tools/ci/compile_examples.py
if [ "$LANE" = "quick" ]; then
hr "compile and link the representative Pong example"
"$python_cmd" tools/ci/compile_examples.py --example examples/pong
else
hr "compile and link every canonical TypeScript example"
"$python_cmd" tools/ci/compile_examples.py
fi
;;
quality-check)
hr "validate quality manifest, assets, and approved baselines"
python3 tools/quality/run.py check
"$python_cmd" tools/quality/run.py check
;;
quality-faults)
hr "prove seeded quality regressions are detected"
python3 tools/quality/run.py faults \
"$python_cmd" tools/quality/run.py faults \
--out "${BLOOM_QUALITY_FAULTS_OUT:-tools/quality/out/ci-faults}" \
--timeout "${BLOOM_QUALITY_TIMEOUT:-900}"
;;
Expand All @@ -404,14 +419,14 @@ run_component() {
quality_out="${BLOOM_QUALITY_OUT:-tools/quality/out/ci-hardware}"
hr "run '$quality_suite' quality suite on $BLOOM_QUALITY_MACHINE_CLASS"
if [ -n "${BLOOM_QUALITY_CASE:-}" ]; then
python3 tools/quality/run.py run "$quality_suite" \
"$python_cmd" tools/quality/run.py run "$quality_suite" \
--case "$BLOOM_QUALITY_CASE" \
--machine-class "$BLOOM_QUALITY_MACHINE_CLASS" \
--out "$quality_out" \
--host-idle-timeout "${BLOOM_QUALITY_HOST_IDLE_TIMEOUT:-120}" \
--timeout "${BLOOM_QUALITY_TIMEOUT:-1800}"
else
python3 tools/quality/run.py run "$quality_suite" \
"$python_cmd" tools/quality/run.py run "$quality_suite" \
--machine-class "$BLOOM_QUALITY_MACHINE_CLASS" \
--out "$quality_out" \
--host-idle-timeout "${BLOOM_QUALITY_HOST_IDLE_TIMEOUT:-120}" \
Expand Down Expand Up @@ -444,7 +459,7 @@ run_component() {
vg_stress_out="${BLOOM_VIRTUAL_STRESS_OUT:-tools/quality/out/ci-virtual-geometry}"
vg_stress_work="${BLOOM_VIRTUAL_STRESS_WORK:-${RUNNER_TEMP:-/tmp}/bloom-virtual-geometry-stress}"
hr "run 10M virtual-geometry stress on $BLOOM_VIRTUAL_STRESS_BACKEND"
python3 tools/quality/virtual_geometry_stress.py \
"$python_cmd" tools/quality/virtual_geometry_stress.py \
--platform "$BLOOM_VIRTUAL_STRESS_PLATFORM" \
--backend "$BLOOM_VIRTUAL_STRESS_BACKEND" \
--work "$vg_stress_work" \
Expand Down
7 changes: 4 additions & 3 deletions tools/check-ci-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ const read = (relative) =>
fs.readFileSync(path.join(root, relative), "utf8").replace(/\r\n/g, "\n");

const expectedLanes = new Map([
["quick", ["contracts", "lint", "shared-tests", "wasm-check", "quality-contract", "example-inventory"]],
["full", ["contracts", "lint", "shared-tests", "wasm-check", "quality-contract", "example-inventory", "host-build", "wasm-build"]],
["quick", ["contracts", "lint", "shared-tests", "wasm-check", "quality-contract", "example-inventory", "example-compile"]],
["full", ["contracts", "lint", "shared-tests", "wasm-check", "quality-contract", "example-inventory", "host-build", "example-compile", "wasm-build"]],
["web", ["wasm-check", "wasm-build", "browser-smoke"]],
["cross", ["target-check"]],
["hardware", ["example-compile", "quality-check", "quality-faults", "quality-run", "fractional-native-throughput", "virtual-geometry-stress"]],
Expand Down Expand Up @@ -50,7 +50,7 @@ if (!/^defaults:\n run:\n(?: #[^\n]*\n)* shell: bash$/m.test(testWorkflow
console.error("FAIL Tests must execute the shared Bash entry point with an explicit Bash shell on Windows");
failures += 1;
}
for (const summary of ["target/ci/quick-shared-tests.json", "target/ci/full-host-build.json"]) {
for (const summary of ["target/ci/quick-shared-tests.json", "target/ci/full-host-build.json", "target/ci/full-example-compile.json"]) {
if (!testWorkflow.includes(`path: ${summary}\n if-no-files-found: error`)) {
console.error(`FAIL Tests must reject missing execution evidence: ${summary}`);
failures += 1;
Expand All @@ -61,6 +61,7 @@ const workflowCommands = [
"./scripts/ci-check.sh --quick --component contracts",
"./scripts/ci-check.sh --quick --component lint",
"./scripts/ci-check.sh --full --component host-build",
"./scripts/ci-check.sh --full --component example-compile",
"./scripts/ci-check.sh --web --component wasm-check",
"./scripts/ci-check.sh --web --component wasm-build",
"./scripts/ci-check.sh --web --component browser-smoke",
Expand Down
Loading
Loading