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
68 changes: 68 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,19 @@ jobs:
shell: pwsh
run: python tools/ci/fixed_step_smoke.py

- name: Native and WASM scalar math contract
shell: pwsh
run: python tools/ci/scalar_math_smoke.py

- name: Retain scalar math evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: scalar-math
path: target/ci/scalar-math
if-no-files-found: error
retention-days: 1

- name: Retain fixed lifecycle evidence
if: always()
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -346,6 +359,32 @@ jobs:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
rustup target add wasm32-unknown-unknown

- name: Compile unchanged browser examples
shell: pwsh
run: python tools/ci/compile_web_examples.py

- name: Retain compiled browser examples
if: always()
uses: actions/upload-artifact@v4
with:
name: bloom-web-examples-${{ github.run_id }}
path: target/ci/web-examples
if-no-files-found: error
retention-days: 1

- name: Native and WASM public constant contract
shell: pwsh
run: python tools/ci/palette_smoke.py

- name: Retain public constant evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: public-constants
path: target/ci/palette
if-no-files-found: error
retention-days: 1

- name: Windows / installed starter web run
shell: pwsh
env:
Expand Down Expand Up @@ -384,6 +423,21 @@ jobs:
CARGO_BUILD_JOBS: '2'
run: ./scripts/ci-check.sh --full --component example-compile

- name: Windows / portable example startup
shell: pwsh
env:
CARGO_BUILD_JOBS: '2'
run: python tools/ci/native_example_smoke.py

- name: Retain portable example startup evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: windows-native-examples
path: target/ci/native-examples
if-no-files-found: error
retention-days: 1

- name: Retain executed example-check summary
if: always()
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -527,6 +581,9 @@ jobs:
# a working hosted WebGPU presentation path.
browser-smoke:
needs: [build-web, build-windows]
# A later Windows native failure must not hide browser evidence for pages
# already compiled/uploaded. Missing or failed artifacts still fail here.
if: ${{ !cancelled() && needs.build-web.result == 'success' }}
runs-on: macos-14
steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -556,6 +613,17 @@ jobs:
- name: web / browser-smoke
run: ./scripts/ci-check.sh --web --component browser-smoke

- name: Download compiled browser examples
if: ${{ !cancelled() }}
uses: actions/download-artifact@v4
with:
name: bloom-web-examples-${{ github.run_id }}
path: target/ci/web-examples

- name: web / portable example runtime
if: ${{ !cancelled() }}
run: python tools/ci/web_example_smoke.py

- name: Upload browser quality evidence
if: always()
uses: actions/upload-artifact@v4
Expand Down
90 changes: 90 additions & 0 deletions docs/evidence/example-browser-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Public constants and portable example browser acceptance

The six shared-loop examples compile for WASM, but executing their original
game code found undefined RGBA arguments in every example. Reading the palette
implementation directly returns the correct values; importing it through the
public `bloom/core` barrel returns undefined bindings in Perry 0.5.1220 WASM.
The same probe finds undefined public `Key` and `MouseButton` values. Package-root
imports also lose palette, input, platform, cursor, texture-kind/filter and
material-slot constants. Native and WASM compilation alone do not prove those
public bindings are usable.

Explicit initialized exports in the two barrels preserve the original names,
values, TypeScript types and shared object identities. The palette definitions
and numeric key values do not change. Actual native/WASM execution now verifies
all 24 colors through both naming styles and both public entry points, shared
color mutation/restoration, 102 input/platform/cursor values through each entry
point, and the ten package-root texture/material constants. Its console runner
can admit unused FFI imports only with guards that reject every engine call.
A separately compiled control calls `getPlatform()` and must fail at that guard.
Default pure timing/scalar fixtures still reject FFI imports entirely.

The expanded browser preparer copies each original example byte-for-byte into
an explicit local dependency project, compiles it with the pinned Perry binary,
verifies the real WASM imports and splices the production bootstrap. Source and
page hashes survive the artifact transfer. Hosted Chrome uses the qualified
engine WASM package, normal physics bootstrap and the original game pages.

The monitor observes actual FFI and Perry callback dispatch, then requests normal
engine stop after eight updates. It requires one completed cleanup, the intended
viewport and drawing in every frame. Undefined/non-finite drawing arguments and
missing key/mouse codes are failures. Space-blaster must initialize and close
audio; voxel-sandbox must restore cursor intent. Captures must satisfy the same
game-content checks as the native examples. The monitor does not replace game
draws, supply input values or inject a fake physics factory. Browser evidence runs
even if a later Windows native check fails; absent or invalid compiled artifacts
still fail, and the native job remains required.

Local recording-FFI execution of the actual compiled games rejects all six
earlier pages and accepts all six after the shared binding correction. This
diagnostic uses the production scheduler, but does not load a browser, renderer,
GPU, audio device or network. The first local probe selected the wrong boot
script and failed before game execution; that setup failure is retained. The
audio observer was also corrected to use the actual `bloom_init_audio` and
`bloom_close_audio` names before hosted qualification.

With the shared bindings corrected, all six native content/capture/cleanup
checks pass on Radeon 760M / DX12, and all 20 canonical examples compile/link.
The unchanged six WASM pages pass the final recording-FFI state verifier,
including audio and cursor cleanup. Actual fixed lifecycle and scalar math
contracts still pass in native/WASM execution. Fourteen Python acceptance
controls, four monitor tests and the repository contracts pass. The first
repository contract attempt failed because the new worktree had no initialized
Jolt submodule; it passes after checking out the existing pinned submodule.

The initial #174 hosted run, 34576806162, passes the scalar contract and all
20 example links. All six native executions then fail with `TypeError: Expected
number for native f64 parameter`, after WARP adapter initialization and before
capture/cleanup. Its logs and reports remain retained. Local native success does
not replace this failed hosted requirement; the expanded public binding
correction and runtime gates require a fresh hosted run.

Hosted run 34580890147 at `da31009` passes all six browser compilations and
actual browser content/cleanup for five games. Voxel-sandbox stops after two
frames because an initial pointer-lock request rejects with `WrongDocumentError`.
The bridge now handles both synchronous denial and promise rejection, preserves
intent for a later canvas click, and releases a late grant after cursor cleanup.
Three production-bridge unit controls cover rejection/retry, legacy behavior
and a grant arriving after cleanup.

The same run's native public-constant fixture fails before output. Its retained
linker log shows multiple `perry_global_index_ts__*` and `index_ts__init` symbols
merged by MSVC despite a zero compiler exit. The fixture is on `C:` while its
linked engine is on `D:`. Perry's common-project-root calculation cannot find
a shared ancestor across drives and its module-name fallback collapses distinct
`index.ts` paths. Replaying the hosted executable locally reproduces the failure;
locally rebuilding with MSVC succeeds, so changing the linker alone is not a
demonstrated remedy. Test projects now live under the checkout's `target/ci`,
and native compilation rejects duplicate Perry module globals. The new check
rejects the actual hosted log while accepting both earlier local linker logs.
Both linker formats also have zero-exit failure controls.
The same duplicate-global pattern is present in all six compile logs from the
initial native failure. The revised local native/WASM constant contract and
all six native content/cleanup checks pass with the new project location.

The same-drive and pointer-lock corrections require a fresh hosted run.
Eight startup frames do not qualify full gameplay or input interaction, pause/
focus policy, resize/device loss, quality goldens or performance. The missing
test3d grid lines, broad generated API/export audit and general compiler
qualification remain open. No discrete-GPU acceptance is inferred from hosted
Metal or Windows software rendering.
73 changes: 73 additions & 0 deletions docs/evidence/example-loops-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Shared example loops and scalar interpolation

Six portable examples used blocking source loops, preventing the browser from
scheduling their frames. They now use the shared `runGame` callback and cleanup:
test3d, dungeon-crawl, isometric-rpg, kart-racer, space-blaster and voxel-sandbox.
The 3D test now closes its window, the space game closes audio during cleanup,
and the voxel game restores the cursor before closing.

## Runtime findings and corrections

Actual native execution exposed failures that compilation did not detect.

- Perry 0.5.1220's integer specialization truncates fractional inputs in
arithmetic-only number functions. For example, native `lerp(10, 20, 0.25)`
returned 10, while WASM returned 12.5. Five quadratic/cubic easing functions
also returned incorrect values. An identity division keeps these public
functions on the compiler's floating-point path. The generated native trace
and earlier failed observations are retained. The division preserves the
mathematical operation and can be removed by LLVM after correct lowering.
- The same specialization loses globals inside arithmetic expressions. The
native voxel index returned 32 for both `(32, 0, 32)` and `(32, 5, 32)`,
overwriting unrelated terrain cells. LLVM showed multiplication by zero
instead of the captured dimension. Passing width/depth explicitly preserves
the intended packed layout and restores visible terrain.
- Combined interpolation calls and nested camera writes produced undefined
fields in the native isometric game. Local result variables preserve the
camera values in both camera examples. Isometric entities now retain map
coordinates only; screen coordinates are derived when drawing. This avoids
a separate observed failure where stored derived coordinates became undefined
during intervening draw loops, hiding the player and NPCs.

The compiler binary and source remain unchanged. These corrections qualify
the stated engine/example paths; general numeric specialization and object
assignment behavior in arbitrary user programs remain compiler limitations.

## Required checks and local observations

`tools/ci/scalar_math_smoke.py` compiles and executes the public math code with
Perry as a native executable and as actual WASM. Eight sample points cover
fractional interpolation, both easing branches, endpoints and extrapolation,
with independent host expectations. NaN, infinity and signed-zero behavior also
pass. The WASM runner uses the production void-return compatibility and no
engine FFI, renderer, browser or network. CI retains this contract separately
from the existing fixed-step lifecycle check.

`tools/ci/native_example_smoke.py` compiles bounded diagnostic copies of all six
examples against the actual checkout. It preserves their update/draw and cleanup
bodies, captures frame eight and stops after readback. All six pass locally on
Radeon 760M DX12 with nine frames and one completed cleanup each. The six
unchanged source entries also compile and splice to WASM with resolved engine
imports; that is compilation evidence, not browser execution.

The native gate requires recognizable game content at the requested viewport,
including the isometric player and terrain, the space game's player, the dungeon
player/floor, a kart and track, the 3D cube and voxel terrain. Applying these
checks to the actual earlier voxel HUD-only and isometric missing-player images
rejects them; all six corrected native captures pass. Synthetic controls also
reject a nonblank HUD, missing player, incomplete readback and duplicate cleanup.
These checks do not replace approved renderer image goldens or prove gameplay.
The all-20 canonical native compile/link gate remains required.

The first diagnostic native runs failed before rendering because DXC/DXIL was
not available to the process. Running the same binaries with the existing SDK
shader-runtime directory succeeded. Logs retain the failure and DLL hashes.
Automatic distribution of shader runtimes remains packaging work; diagnostic
crash dumps are private and excluded from publication.

Full browser execution of these six examples, other canonical runtime entries,
input/gameplay coverage and visible native presentation remain open. Visual
inspection also found missing grid lines in test3d; the cube/content smoke does
not qualify that separate renderer defect. Current-source full strict graphics
qualification remains required before integration. Hosted results for this
candidate are pending; no issue is closed by the local checks.
Loading
Loading