Skip to content
Merged
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
25 changes: 13 additions & 12 deletions .github/workflows/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@

**Read `REVIEW_COMMON.md` (repo root) first - its contract binds this checklist.**
Architecture doc: `skills/internal/preflight.md` (repo root). A per-PR check is a step, a
matrix cell, or a workflow trigger whose failure turns a branch or a published artifact red
before a human merges or ships it - a `pull_request` lane's step and a branch-push lane's
smoke alike.
matrix cell, or a workflow trigger whose failure means the tree or a published artifact is
wrong, and that turns the lane red before a human merges or ships it - a `pull_request` lane's
step and a branch-push lane's smoke alike. A provisioning step - a toolchain install, a version
pin - is not itself a per-PR check.

**A diff that weakens a per-PR check is a defect: deleting it while no per-PR lane still
runs its cases, stopping its failure from failing the lane (`continue-on-error`, a trailing
`|| true`, a swallowed exit code), shrinking what it checks, or narrowing its condition to
anything but a `matrix.role` condition that still runs it on every pull request or the
nightly cron.**
**A diff that weakens a per-PR check is a defect: deleting it, or a step it depends on, while
no per-PR lane still runs its cases, stopping its failure from failing the lane
(`continue-on-error`, a trailing `|| true`, a swallowed exit code), shrinking what it checks, or
narrowing its condition to anything but a `matrix.role` condition that still runs it on every
pull request.**

**A per-PR check the diff adds fails the lane when it finds a defect.**

Expand All @@ -29,10 +30,10 @@ preflight gate - a check `preflight` runs locally before a push - that keeps it
(`skills/internal/preflight.md` sec."extended_checks.yml") or states the platform no per-PR
cell has.** A per-PR job fits 35 minutes; what does not fit moves.

**A diff that adds or changes a per-PR check states a run of that check's command, on the
lane's platform, in its PR body or commit message; a green run of that lane on the PR's head
commit is that evidence.** A check that fails for a non-defect turns a green branch red for
everyone.
**A diff that adds or changes a per-PR check, or adds, changes, or removes a step a per-PR
check depends on, states a run of that check's command, on the lane's platform, in its PR body
or commit message; a green run of that lane on the PR's head commit is that evidence.** A check
that fails for a non-defect turns a green branch red for everyone.

**A step in `pages.yml` that names more than one id under `examples/games/` spells them as a
`for g in <ids>; do` loop, never inline.** `examples/games/REVIEW.das` (repo root) reads the
Expand Down
32 changes: 12 additions & 20 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,6 @@ jobs:
- name: "Install CMake and Ninja"
uses: lukka/get-cmake@latest

# The wasm64 (MEMORY64) modules emscripten emits refuse to load under a node older than 23
# ("This emscripten-generated code requires node v23.0.0"); ubuntu-latest ships 22, and the
# DlimConfiguration probe below runs one of those modules under the runner's node.
- name: "Install node 24 (the wasm64 probe runs under it)"
uses: actions/setup-node@v4
with:
node-version: 24

# The host daslang now builds with dasGlfw/dasOpenGL ON so it can drive the
# /examples game cross-compile (daspkg release wasm). dasGlfw's
# find_package(OpenGL REQUIRED) needs the GL + X11 dev headers.
Expand Down Expand Up @@ -213,9 +205,9 @@ jobs:
# WASM build: the wasm32 interpreter playground (daslang_static) + the wasm64
# compiled path (runtime/module archives, compute samples, and the /examples
# games). Skipped on a cache hit — the cached web/output + web/output64 are
# reused. wasm32 is the universal interpreter fallback; everything COMPILED
# is wasm64 (the cross-compile is layout-correct only when host ptr width ==
# target ptr width).
# reused. Everything COMPILED is cross-compiled as wasm64 (layout-correct only
# when host ptr width == target ptr width) and lowered to a 32-bit memory at
# link (-sMEMORY64=2), so it runs on every engine, WebKit included.
- name: "Build WASM (Emscripten): playground + wasm64 examples"
if: steps.wasm-cache.outputs.cache-hit != 'true'
run: |
Expand All @@ -241,7 +233,7 @@ jobs:
# 1. wasm32 interpreter playground (daslang_static) + vendored UI + the example .das
# sources staged into site/playground. THREADED build (-pthread + the imgui family),
# so new_thread / JobQue map to Web Workers and every playground sample runs
# cross-origin-isolated (coi-serviceworker drops the memory64 gate for /playground).
# cross-origin-isolated (coi-serviceworker).
# stage_site_playground also generates the furier + path_tracer_lab samples from the
# canonical examples/graphics sources. If the imgui-family build breaks (an external's
# master regressed), degrade rather than blocking every deploy: drop the clones and
Expand Down Expand Up @@ -298,8 +290,8 @@ jobs:
# drives its .das_package release_wasm_build to produce the 3 wasm64
# archives on demand — no daspkg install step (the example declares
# no deps). Non-fatal — a wasm-build hiccup must not red the whole
# deploy; the furier card is skipped at stage time below (examples.js
# shows a "needs memory64" note when the iframe is unavailable).
# deploy; the furier card is skipped at stage time below (a placeholder
# page stands in for the iframe).
if ./bin/daslang utils/daspkg/main.das -- \
release wasm --root examples/graphics/furier --out "$REPO/web/output64/examples"; then
echo "furier wasm build OK"
Expand Down Expand Up @@ -545,9 +537,9 @@ jobs:
fi
# /examples/ runtime: the interpreted runner harness + per-game artifacts.
# Each game dir holds BOTH the compiled wasm64 build (loaded in an iframe on
# memory64 engines) AND the .das sources + HUD font the interpreted fallback
# (_interp.html) mounts on Safari/iOS. The page UI (examples.html, posters,
# Each game dir holds BOTH the compiled build (loaded in an iframe on every
# engine) AND the .das sources + HUD font the interpreted runner
# (_interp.html) mounts under ?force=interp. The page UI (examples.html, posters,
# files/examples.js) was already staged above via cp site/examples.html +
# cp -r site/files.
mkdir -p _site/examples
Expand All @@ -568,11 +560,11 @@ jobs:
cp modules/dasStbImage/fonts/droidsansmono.ttf "_site/examples/$g/"
done
# furier — the ImGui-in-wasm showcase. wasm64-only: it bundles the compiled
# furier — the ImGui-in-wasm showcase. Compiled-only: it bundles the compiled
# dasImgui module, which the universal interpreter can't bind, so there is NO
# interpreted fallback (no .das sources to stage). The card is always listed
# interpreted form (no .das sources to stage). The card is always listed
# in examples.js, so stage the compiled build only when ALL THREE outputs are
# present; otherwise stage a small placeholder furier.html so a memory64 engine
# present; otherwise stage a small placeholder furier.html so the player
# loads a friendly "being rebuilt" note instead of 404-ing the iframe (and
# flipping the player to a bogus "running" on the 404 page's load event).
mkdir -p _site/examples/furier
Expand Down
1 change: 1 addition & 0 deletions CHANGELIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ A public site and service for the `[tune]` ecosystem: upload a tuned box's sidec
- **On-demand wasm compilation** (#3628, #3630, #3633) - a fresh pre-warmed throwaway runtime per run, a content-addressed build queue behind a rootless-podman network-none sandboxed builder (`dasweb-buildd`), and standalone graphics/audio pages served from `run.daslang.io`
- **The sample verifiers** (#3645, #3649, #3679) - a tier-1 batch compile gate over all 39 curated samples per PR, and a nightly playwright leg that drives the live playground per sample per engine (first sweep 70/77, zero false positives)
- **Stability round** (#3635, #3648, #3650, #3652, #3667, #3714) - canvas size reconciled to the CSS box every frame (retiring three workarounds), wasm memory growth to 2 GB with reported OOM, channel `gather` outside the lock (the "dead window" wedge), the runtime wasm compiled once per page (the browser-tab OOM cliff), and a scripted fail-closed toolchain-bump protocol
- **Every browser** (#4051) - the compiled web builds link `-sMEMORY64=2` (wasm64 pointers over a memory lowered to 32-bit) and drop `+relaxed-simd`, so the example cards, the playground's wasm engine and the dasllama.io examples run on Safari and iOS; the memory64 gates are gone from both sites, and dasllama.io serves its examples under COEP `require-corp`

#### The Fast Dev Loop: Module Cache + Split JIT (#3683, #3687, #3692, #3693, #3701, #3707, #3936)

Expand Down
3 changes: 2 additions & 1 deletion doc/source/reference/utils/daspkg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ Options:
- ``--quick`` -- on ``release``, accept a complete existing ``[tune]``
sidecar instead of re-minting (``--paranoid`` is accepted for
compatibility; the tuner runs one margin-decided protocol).
- ``--wasm`` -- on ``build``, target wasm64 (memory64).
- ``--wasm`` -- on ``build``, target wasm64 (memory64, lowered to a 32-bit
memory at link so every browser runs the artifact).
- ``--wasm-lib-dir <path>`` -- directory holding the wasm64 archives;
default ``<das_root>/web/output64/lib``.

Expand Down
4 changes: 2 additions & 2 deletions examples/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
**A `.das` in this folder tree that a game's `main.das` requires, directly or through another
required file, answers to `games/REVIEW.md` too - wherever the diff puts it.**

**A folder with a `web_shell.html`, and every `.das` and `models.json` in it, answers to
`dasLLAMA/REVIEW.md` too, wherever the diff puts it.**
**Every file in a folder that holds a `web_shell.html` answers to `dasLLAMA/REVIEW.md` (beside
this file) too - wherever in this tree that folder sits.**

**A diff that drops `require live/audio_live` from a program states, in the PR body, why that
program's audio is meant to die with a reload** - `audio_live` is what carries the audio
Expand Down
27 changes: 17 additions & 10 deletions examples/dasLLAMA/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,27 @@ A browser example is a subfolder here with a `web_shell.html` (`ARCHITECTURE.md`
rules below bind browser examples; a rule naming `library/` binds that folder instead.

**A browser example reads its input inside its own frame - a `glfwSet*Callback` written in
`.das` is a defect; an example that draws its own text polls each input every frame and
edge-detects it (`glfwGetKey`, `glfwGetMouseButton`), and one on the imgui harness reads ImGui's
state.** In the browser build a callback lambda fires outside any frame of the program and the
program traps (`ARCHITECTURE.md` sec. 3.3).

**A browser example's `web_shell.html` gives the canvas element `max-width` / `max-height` so the
element's box is exactly the rendered image - never `object-fit` on a canvas stretched to fill the
page area around it.** A click maps through the element's box with one ratio per axis, so a
stretched box mis-maps every click (`ARCHITECTURE.md` sec. 3.3).
`.das` is a defect; an example that draws its own text polls each input every frame and acts
when it goes down, never on every frame it stays down - a repeat comes from the example's own
hold timer (`glfwGetKey`, `glfwGetMouseButton`) - and one on the imgui harness reads ImGui's
state.** In the browser build a callback lambda fires outside any frame
of the program and the program traps (`ARCHITECTURE.md` sec. 3.3).

**A browser example whose `main.das` reads the mouse - `glfwGetMouseButton`, or ImGui's mouse
state through the imgui harness - gives the canvas element `max-width` / `max-height` in its
`web_shell.html` - never `object-fit` on a canvas stretched to fill the page area around it.** A
click maps through the element's box with one ratio per axis, so a stretched box mis-maps every
click (`ARCHITECTURE.md` sec. 3.3).

**A browser example's `web_shell.html` must reload a page the browser restored from its
back-forward cache - a `pageshow` handler that reloads when `persisted` is set.** Such a page
comes back with its workers and audio output frozen out of step (`ARCHITECTURE.md` sec. 3.1).

**A browser example's `web_shell.html` never refuses a browser on a WebAssembly feature probe -
it gates on the page's cross-origin isolation (`crossOriginIsolated`, `SharedArrayBuffer`)
alone.** The build runs on every engine, so a feature gate only refuses browsers that would have
run it.

**A diff that plays a second sound creates a new status box (`set_status_update`) for it and
releases the first when its sound ends - never reuse a box across sounds.** The mixer's last
report for the first sound lands after the second attaches, and reads as the second's stop
Expand All @@ -43,6 +50,6 @@ writes nothing (`ARCHITECTURE.md` sec. 3.8).

**A diff that adds an entry point to `library/dasllama_lib.das` gives it `[export_c]` and a
result `daslib/c_api_header.das` can spell in C - a scalar, a string, a pointer, an enum, a
vector or a POD struct, never an array, a fixed array, a table or a tuple.** An `[export_c]`
vector, a POD struct, or nothing at all, never an array, a fixed array, a table or a tuple.** An `[export_c]`
whose signature that describer refuses is a hard emit error, not a skipped export
(`ARCHITECTURE.md` sec. 3.8).
33 changes: 9 additions & 24 deletions examples/dasLLAMA/parrot/web_shell.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<link rel="stylesheet" href="/files/dasllama-io.css">
<script src="/files/github-star.js" defer></script>
<!-- Analytics — site code "dasllama" under the borisbat goatcounter account -->
<script data-goatcounter="https://dasllama.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
<script data-goatcounter="https://dasllama.goatcounter.com/count" async crossorigin="anonymous" src="//gc.zgo.at/count.js"></script>
<style>
html, body { margin: 0; height: 100%; background: #12101a; overflow: hidden; }
body {
Expand Down Expand Up @@ -51,10 +51,9 @@
</head>
<body>
<!-- The parrot shell: the dasllama.io nav on top (its css and script come from the site
root, /files/), then the stage. The shell checks the browser first - the build is wasm64
(memory64) with real Web Workers, so it needs an engine with memory64 (Chrome or Edge 133+,
Firefox 134+; Safari has none yet, and every iPhone and iPad browser is Safari's engine) on a
cross-origin-isolated page; a browser without either gets the note below and never fetches a
root, /files/), then the stage. The shell checks the page first - the build runs its real
Web Workers on SharedArrayBuffer, so it needs a cross-origin-isolated page; a page without
it gets the note below and never fetches a
byte. Then it reads models/manifest.json - the list the deploy minted, stamped with the
IMAGE_VERSION it minted at - and refuses a set minted for another version before fetching a
megabyte of it: the program would decline the images anyway, this way the reason is on the
Expand Down Expand Up @@ -96,18 +95,11 @@ <h1>parrot</h1>
// modules/dasLLAMA/dasllama/dasllama_image.das); 0 means "not stamped" (a local rig), no check
var PAGE_IMAGE_VERSION = /* @image-version */ 0;

// wasm64 (memory64): validate a minimal module whose memory section carries the memory64
// flag (0x04) - true only where the engine parses it, unlike a Memory descriptor probe an
// engine can silently downgrade. Same probe as daslang.io's examples page.
var HAS_WASM64 = (function () {
try { return WebAssembly.validate(new Uint8Array([0, 0x61, 0x73, 0x6d, 1, 0, 0, 0, 5, 3, 1, 4, 1])); }
catch (e) { return false; }
})();
// the -pthread build runs its workers on SharedArrayBuffer, which a page gets only when the
// server sent the cross-origin isolation headers
var HAS_ISOLATION = !!(self.crossOriginIsolated && typeof SharedArrayBuffer !== 'undefined');
var FORCE = new URLSearchParams(location.search).get('force');
var SUPPORTED = FORCE === 'unsupported' ? false : (HAS_WASM64 && HAS_ISOLATION);
var SUPPORTED = FORCE === 'unsupported' ? false : HAS_ISOLATION;

function setStatus(text) { document.getElementById('status').textContent = text; }
function showNote(status, html) {
Expand All @@ -131,17 +123,10 @@ <h1>parrot</h1>
window.addEventListener('pageshow', function (e) { if (e.persisted) location.reload(); });

if (!SUPPORTED) {
if (FORCE === 'unsupported' || !HAS_WASM64) {
showNote('needs a memory64 browser',
'<b>This browser cannot run parrot.</b><br>The example is dasLLAMA compiled to ' +
'WebAssembly memory64, which needs Chrome or Edge 133+ or Firefox 134+ on a desktop. Safari ' +
'does not support memory64 yet, and on iPhone and iPad every browser runs on Safari\'s engine.');
} else {
showNote('needs SharedArrayBuffer',
'<b>SharedArrayBuffer is not available on this page.</b><br>The build runs on Web Workers ' +
'over it, and a browser grants it only to a cross-origin-isolated page - one the server ' +
'sends the Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers for.');
}
showNote('needs SharedArrayBuffer',
'<b>SharedArrayBuffer is not available on this page.</b><br>The build runs on Web Workers ' +
'over it, and a browser grants it only to a cross-origin-isolated page - one the server ' +
'sends the Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy headers for.');
} else {
// the probes passed but the program refuses the browser anyway (emcc's own user-agent check
// throws "compiled without support for <browser>" at the top of its script): the error
Expand Down
Loading
Loading