Skip to content

Monorepo dev-mode skew: launcher uses local templates with cached binary #195

@apotema

Description

@apotema

What's wrong

When developing inside the toolkit monorepo (sibling repos at ../labelle-engine/, ../labelle-assembler/, etc.), the launcher's findRepoRoot path in src/cli/cache.zig makes labelle build read framework deps + assembler templates from local source rather than fetching from remote. The cached assembler binary, however, still comes from ~/.labelle/assembler/<version>/labelle-assembler — and isn't rebuilt when local source moves.

When a feature branch on ../labelle-assembler/ adds a new template placeholder (e.g., {{preview_setup}}) that the cached binary doesn't yet know how to substitute, the launcher generates a project whose main.zig contains the literal placeholder string. The Zig compiler then chokes on expected ';' after statement and the build fails.

Reproduction

  1. Check out ../labelle-assembler/ on a branch that adds a new {{...}} placeholder in backends/*/templates/desktop.txt without bumping the assembler version.
  2. From labelle-gui, run zig build smoke, OR manually:
    cd /tmp && rm -rf repro && mkdir repro/proj && cd repro/proj
    cat > project.labelle <<'ZON'
    .{ .name = "x", .core_version="1.12.0", .engine_version="1.35.0", .gfx_version="1.10.0", .assembler_version="0.17.0", .labelle_version="1.36.0" }
    ZON
    labelle build
    
  3. Observe: main.zig:NN:NN: error: expected ';' after statement pointing at a literal {{...}} placeholder.
  4. Inspect the generated file at .labelle/raylib_desktop/main.zig — the placeholder is in the output unchanged.

Why this happens

src/cli/cache.zig:fetchAssemblerWithFallback copies templates from the local checkout into the project's .labelle/deps/labelle-assembler/ when the monorepo is detected. The launcher then spawns the cached assembler binary, which reads those templates but only knows how to substitute placeholders it shipped with. New placeholders pass through verbatim.

Why it usually doesn't bite users

  • Non-monorepo users fetch both templates and binary from the released tarball — they're in lock-step.
  • Within the monorepo, the cached binary is usually ahead of or aligned with what's in ../labelle-assembler/main. The skew only appears when a feature branch ships template-format changes ahead of a binary release.

Proposed fixes (pick one)

Option A — Rebuild from local source in monorepo mode

When findRepoRoot succeeds, rebuild the assembler binary from local source into a per-checkout scratch dir (<repo>/zig-out/dev-assembler/labelle-assembler) and use that binary instead of the cache. Guarantees template/binary coherence at the cost of a rebuild on first invocation per session. Cache the build by source mtime to avoid rebuilding every call.

Option B — Surface a warning + abort

Detect the skew at copy time by checking the templates for placeholders the cached binary's --help-placeholders (new flag) doesn't list. If skew is detected, abort with error: assembler templates use placeholders the cached binary 0.17.0 doesn't support. Rebuild the assembler or use a newer version.

Option C — Pin the assembler binary to local source's git rev

When in monorepo mode, refuse to use a cached binary and always rebuild from ../labelle-assembler/ HEAD. Treat the cache as remote-only. Most explicit but slowest.

I'd lean Option A — it preserves the convenience of monorepo dev mode while making it correct. Cache by mtime + branch ref so it only rebuilds when the source actually moves.

How this came up

Surfaced today (2026-05-12) during the labelle-toolkit/labelle-gui smoke harness on main. The harness creates a fresh project via ProjectManager.newProject, runs labelle build against it, and asserts success. Failed because (a) the gui's default assembler_version was 0.8.0 (separately fixed in labelle-gui#64) and (b) the local ../labelle-assembler/ was on a feature branch (labelle-assembler#95) adding new preview-mode placeholders.

Even after the gui's default-version fix, the underlying skew would resurface anytime someone is in dev mode on a branch that's ahead of the cached binary.

Acceptance

  • Pick an option (or propose a different one).
  • Implement; verify the repro above no longer fails when running with a monorepo + feature-branched assembler.
  • Document in CLAUDE.md (or wherever the launcher's behavior is described) that monorepo dev mode now rebuilds/validates the assembler.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions