chore(#520): flows-smoke + asset-streaming-smoke → null backend (agnostic fixtures) - #523
Conversation
…stic assembler fixtures) Both fixtures test assembler CODEGEN, not rendering, so the headless `.null` backend is the correct target — no display / GPU / GL context needed to generate or build them (labelle-assembler#520 remainder). - asset-streaming-smoke: `.backend = .null`. The streaming codegen (lazy-inference → `registerAtlasFromMemory`, `SceneAssetManifests`) is emitted identically; the generated main loop + ImageBackendAdapter also RUN headless (frame-capped, clean rc=0). CI repointed to `.labelle/null_desktop`, invokes the assembler binary directly (cli is pinned pre-`.null`), asserts the streaming codegen, builds, and runs. - flows-smoke: `.backend = .null`. All flow-codegen assertions hold and it builds clean on null; the CustomNode (#240) path actually executes. CI repointed to `.labelle/null_desktop`, stays build-only: a headless run trips a pre-existing, backend-INDEPENDENT crash in the generated `tick` flow-handler's runtime `game.getComponent` (faults in labelle-core ecs `alive.contains`) — the fixture never ran before (raylib build-only), so this latent runtime gap is out of scope here. Assembler `zig build` + `zig build test` still green (1233 pass / 8 skip). Claude-Session: https://claude.ai/code/session_01P7B7UzgrWEbBYLT3YBrAog https://claude.ai/code/session_01P7B7UzgrWEbBYLT3YBrAog
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughCI and example fixtures switch from ChangesHeadless .null backend migration
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request switches the backend for the asset-streaming-smoke and flows-smoke examples from .raylib to the headless .null backend. This change allows testing the assembler's codegen (asset-streaming and flow codegen) in headless environments, such as CI, without requiring a display or GPU. The corresponding README files, project configurations, and lockfiles have been updated to reflect this transition. There are no review comments, so I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c8f405e682
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # `.null` Backend variant, so `labelle generate` would fail at | ||
| # the project.labelle parse step. Same recipe as the null / | ||
| # flows-smoke / plugin-controllers steps below. | ||
| $GITHUB_WORKSPACE/labelle-assembler/zig-out/bin/labelle-assembler generate --project-root . |
There was a problem hiding this comment.
Run install before the first null-backend generate
In the examples-integration job on a fresh runner, this is now the first direct .null generation, but nothing before it populates the labelle package cache with the extracted labelle-null backend; the only labelle-assembler install --project-root . that fetches the null backend is in the later external-null step. Since the assembler binary's generate path only reads the local cache (the CLI/install path is what fetches dependencies), this step will fail before reaching the later install. Add an install for this project before generate, or move this step after a cache-populating install.
Useful? React with 👍 / 👎.
The lock's `.backend = .{ .name = "null" }` made the assembler resolve null as an EXTERNAL packaged backend (ExternalBackendNeedsManifest) at generate. The working null examples (examples/null, plugin-controllers) carry no lock — match that.
Claude-Session: https://claude.ai/code/session_01P7B7UzgrWEbBYLT3YBrAog
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)
216-229: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFourth copy of the fixFingerprint dance — consider extracting a shared script.
This ~12-line "capture invalid/use-this-value fingerprint from a first
zig build, sed-patchbuild.zig.zon, rebuild" block is now duplicated four times in this file (here, the null example at Lines 322-330, flows-smoke at Lines 413-422, plugin-controllers at Lines 462-471). A shared shell script (e.g.scripts/ci/fix-fingerprint-and-build.sh) invoked from each step would keep the four call sites in sync if the diagnostic format or patch logic ever needs to change.♻️ Example extraction
# scripts/ci/fix-fingerprint-and-build.sh #!/bin/bash set -e set +e ERR=$(zig build 2>&1) set -e BAD=$(printf '%s\n' "$ERR" | grep -oE 'invalid fingerprint: 0x[0-9a-f]+' | head -1 | awk '{print $3}') GOOD=$(printf '%s\n' "$ERR" | grep -oE 'use this value: 0x[0-9a-f]+' | head -1 | awk '{print $4}') if [ -n "$BAD" ] && [ -n "$GOOD" ]; then echo "labelle-cli-equivalent fixFingerprint: ${BAD} -> ${GOOD}" sed -i "s/${BAD}/${GOOD}/" build.zig.zon fi zig build- set +e - ERR=$(zig build 2>&1) - set -e - BAD=$(printf '%s\n' "$ERR" | grep -oE 'invalid fingerprint: 0x[0-9a-f]+' | head -1 | awk '{print $3}') - GOOD=$(printf '%s\n' "$ERR" | grep -oE 'use this value: 0x[0-9a-f]+' | head -1 | awk '{print $4}') - if [ -n "$BAD" ] && [ -n "$GOOD" ]; then - echo "labelle-cli-equivalent fixFingerprint: ${BAD} -> ${GOOD}" - sed -i "s/${BAD}/${GOOD}/" build.zig.zon - fi - zig build + $GITHUB_WORKSPACE/labelle-assembler/scripts/ci/fix-fingerprint-and-build.sh🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/ci.yml around lines 216 - 229, The fingerprint-capture-and-patch block is duplicated across several CI steps, so extract it into a shared script and call it from each site instead of keeping four copies in .github/workflows/ci.yml. Move the logic that runs zig build, parses BAD and GOOD, patches build.zig.zon, and rebuilds into a reusable script such as scripts/ci/fix-fingerprint-and-build.sh, then update the null_desktop, flows-smoke, and plugin-controllers steps to invoke that script so any future diagnostic or sed changes stay in sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/flows-smoke/README.md`:
- Around line 21-22: The README text is wrapped in a way that leaves “#520)” at
the start of a line, which markdownlint treats as an invalid heading. Reflow the
sentence in the affected fixture description so the `labelle-assembler `#520``
reference stays on the same line or is otherwise not line-initial, preserving
the meaning while avoiding MD018.
---
Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 216-229: The fingerprint-capture-and-patch block is duplicated
across several CI steps, so extract it into a shared script and call it from
each site instead of keeping four copies in .github/workflows/ci.yml. Move the
logic that runs zig build, parses BAD and GOOD, patches build.zig.zon, and
rebuilds into a reusable script such as scripts/ci/fix-fingerprint-and-build.sh,
then update the null_desktop, flows-smoke, and plugin-controllers steps to
invoke that script so any future diagnostic or sed changes stay in sync.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 564a52c7-848e-4757-9b2d-3bff011fb86f
⛔ Files ignored due to path filters (2)
examples/asset-streaming-smoke/labelle.lockis excluded by!**/*.lockexamples/flows-smoke/labelle.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
.github/workflows/ci.ymlexamples/asset-streaming-smoke/README.mdexamples/asset-streaming-smoke/project.labelleexamples/flows-smoke/README.mdexamples/flows-smoke/project.labelle
…n CI `.null` is an EXTRACTED external backend (#386 Phase 6c) — it resolves to the `labelle-null` package, not a bundled slot, so its `backend.manifest.zon` must be in the package cache before `generate` can splice the codegen (else: ExternalBackendNeedsManifest). The raw-assembler `generate` does NOT populate the cache; only `ensureCache` (via labelle-cli `generate` / `install`) does. The existing raw-assembler null example steps only pass because an earlier `labelle generate` step incidentally seeds null (ensureCache always fetches null for the tests target). Switching asset-streaming-smoke to the raw assembler removed that seed AND moved it to the first example step, so null was uncached when it ran → CI failed at generate. Fix: run `labelle-assembler install --project-root .` before `generate` in BOTH converted steps (mirrors the external-backend step), making each fixture self-sufficient and order-independent. Verified end-to-end on a FRESH package cache (remote labelle-null fetch, no sibling checkout — the CI condition): install → generate → build → run all green for both. Claude-Session: https://claude.ai/code/session_01P7B7UzgrWEbBYLT3YBrAog https://claude.ai/code/session_01P7B7UzgrWEbBYLT3YBrAog
…es (#525) These backend-coupled examples now live in their backend packages — the assembler is backend-agnostic and should not carry them: - gamepad → labelle-raylib#8 - gamepad-android → labelle-sokol#6 - sokol_imgui → labelle-sokol#6 Remove the three example dirs and the raylib-only "Generate + build the gamepad example" CI step. The gamepad-sim harness stays (it tests the shared backends/sdl_gamepad source, not the example); its comment is repointed to the gamepad example's new home in labelle-raylib. The remaining examples are all backend-agnostic: null / plugin-controllers (headless .null), asset-streaming-smoke + flows-smoke (.null, #523), and external-null (out-of-tree backend_package fixture). Completes the examples side of the agnosticism remainder. Verified: `zig build` + `zig build test` green. Claude-Session: https://claude.ai/code/session_01P7B7UzgrWEbBYLT3YBrAog
Makes the two remaining assembler smoke-test fixtures backend-agnostic by switching them from
raylibto the headlessnullbackend (refs #520 remainder). Both test assembler codegen, not rendering, so.null(no window / GPU / GL context) is the correct target.What changed
examples/asset-streaming-smoke— converted cleanly (build and run)project.labelle.backend = .raylib→.null(+labelle.lockbackend name).registerAtlasFromMemory(defer PNG decode) and emitsSceneAssetManifests— grep-asserted on the generatedmain.zig.ImageBackendAdapteralso run headless (frame-capped, cleanrc=0).Examples integration test) repointed to.labelle/null_desktop, invokes the assembler binary directly (labelle-cli is pinned pre-.null), asserts the streaming codegen, builds, and runs frame-capped. Real GPU upload / on-screen render is not asserted (null has no GPU) — never was; stays a local.raylibcheck.examples/flows-smoke— converted for build; CI stays build-onlyproject.labelle.backend = .raylib→.null..zig,PluginFlowNodesshim,script__loggernamed-module promotion,overrideImportwiring) and it builds clean; the CustomNode Game-script CustomNodes don't compile: shim missing PluginFlowNodes + named-module promotion needed (follows #238) #240 path even executes (logger.log_i32: 42)..labelle/null_desktop, build-only (its prior depth). A headless run trips a pre-existing, backend-INDEPENDENT crash: the generatedtickflow-handler's runtimegame.getComponenton theentity_createdpayload faults in labelle-core ecs (alive.contains). The fixture was raylib build-only and never ran, so it never surfaced this — unrelated to flow codegen/backend, out of scope. Reverting to raylib keeps the GPU dep for no benefit (raylib can't run headless in CI either). Flagged in README + CI comment.Verification
zig build+zig build test --summary all— 1233 pass / 8 skip, rc=0.null_desktop,rc=0.null_desktop,rc=0.Neither needs to migrate to a backend package — the null conversion still fully tests each feature's codegen.
Claude-Session: https://claude.ai/code/session_01P7B7UzgrWEbBYLT3YBrAog
https://claude.ai/code/session_01P7B7UzgrWEbBYLT3YBrAog
Summary by CodeRabbit
.nullbackend for display-free, faster codegen validation..nullbackend workflow, local commands, and revised CI expectations.