Three single-file HTML apps ported to Makepad 2.0 (dev b41e740) script_mod! DSL: - rider (ride.html): 21 unit + 9 integration + 9 headless UI tests - koboyo (koboyo.html): 29 + 14 + 8 - insurance (insurance.html): 28 + 14 + 8 All 140 tests green. Includes headless-Linux platform patch, full README, setup script, and three brutal codebase assessments with execution plans.
364 lines
24 KiB
Markdown
364 lines
24 KiB
Markdown
# Makepad 2.0 (dev @ `b41e740`) — Brutal Professional Assessment
|
||
|
||
**Scope & evidence base.** This reviews the dev branch as attached in the
|
||
workspace (sparse clone: `AGENTS.md`, `examples/splash`, `examples/uizoo`,
|
||
`libs/makepad_test`) **plus a full fresh clone used for metrics** and
|
||
compiler/test telemetry from building and testing three example apps against
|
||
the complete tree this week. It is *not* a line-by-line audit of all 5,548
|
||
files — where a claim is telemetry-based rather than line-read, it says so.
|
||
|
||
Hard numbers, all measured on `b41e740`:
|
||
|
||
| Metric | Value | Source |
|
||
|---|---|---|
|
||
| Tree size / files | 209 MB (excl. .git) / 5,548 files | fresh clone |
|
||
| Core Rust LOC (`platform+draw+widgets`) | ~283k lines in 505 `.rs` files | `wc -l` |
|
||
| `platform/script` (the DSL language) | 80 files / 52,822 lines (parser.rs alone: 4,291) | `wc -l` |
|
||
| `unsafe` in `platform/src` | **2,565** (~7.4 per file) | grep |
|
||
| `#[test]` across the entire core | **157, in only 27 files** | grep |
|
||
| `.unwrap()` in core sources | 1,562 | grep |
|
||
| Compiler warnings on stock toolchain | 14 (`makepad-widgets`) + ~40 more in `draw`, incl. `f64→f32` fallbacks that rustc flags as **future hard errors** (rust-lang issue #154024) | build logs from this session |
|
||
| CI configuration | **None. No `.github/`, no workflows anywhere in the tree** | `find` |
|
||
| Toolchain pin / committed lockfile | **Neither** (`rust-toolchain*` absent, `Cargo.lock` gitignored) | tree |
|
||
| Vendored code in `libs/` | **1.4M lines / 2,811 files** (rapier 18 MB, vulkan 13 MB, stitch 13 MB, CEF, CUDA, MLX, TTS, windows-bindgen…) | `du` |
|
||
| Root-directory clutter | 9 planning `.md` docs + 5 floating `download_*.sh` blobs at repo root | `ls` |
|
||
| Registration duplication | 161 `workspace.members` vs 20 `RunStudioRelease` lines in `makepad.splash` — both must be hand-edited per example | grep |
|
||
| Mega-files | `vulkan.rs` 7,120 lines, `widget_tree.rs` 3,917, `text_input.rs` 3,574, `portal_list.rs` 3,463 | `wc -l` |
|
||
|
||
Scorecard (0–10):
|
||
|
||
| Axis | Score | One-liner |
|
||
|---|---|---|
|
||
| Architecture | 6.5 | Ambitious, coherent layers — undermined by an interpreted DSL whose correctness lives in a markdown file |
|
||
| Code quality | 5.0 | Competent, idiomatic Rust in places; crushed by scale per file, warning debt, and test scarcity |
|
||
| Bugs / correctness | 4.0 | **dev head does not compile headless-Linux at all**; emulator-grade traps in the widget kit |
|
||
| Performance | 7.5 | Rendering engine is world-class; repo/tooling ergonomics (clone size, boot, build) are not |
|
||
| Design (API/DX) | 4.5 | Ten undocumented-or-markdown-documented sharp edges, several of them silent-failure |
|
||
| Security / safety | 3.5 | Documented memory-layout footgun for GPU buffers, floating multi-GB downloads without checksums, massive unaudited vendored surface |
|
||
| Tooling & CI | 2.0 | No CI, no pin, no lockfile, warning debt — the supply side of this project is running on vibes |
|
||
| **Overall** | **4.7** | **A research-grade engine with production-grade ambition and zero production guardrails** |
|
||
|
||
The good, stated once: the render stack (shader VM, retained areas,
|
||
batching, hot reload) is genuinely the most advanced in the Rust-UI space;
|
||
the cross-platform breadth (desktop, mobile, WASM, OpenXR, CEF) is real
|
||
code, not vaporware; `examples/splash`/`uizoo` contain zero `.unwrap()` (the
|
||
demos are cleaner than the framework); the new `makepad_test` studio-protocol
|
||
harness is a legitimately good idea; and publishing an `AGENTS.md` contract
|
||
for AI contributors is forward-thinking. None of that excuses what follows.
|
||
|
||
---
|
||
|
||
## 1. Architecture
|
||
|
||
**A1 — The framework's correctness is enforced by a Markdown file, not the
|
||
type system.** `script_mod!` waits until *app startup* to parse the UI: every
|
||
DSL mistake (`=` instead of `:`, wrong key name, missing scope) is a runtime
|
||
boot error. That's the deliberate hot-reload tradeoff, but the safety
|
||
fallback is **855 lines of rules for humans/agents** instead of compiler
|
||
guidance. Concretely, `AGENTS.md` rule 16 states that field order in
|
||
`#[repr(C)]` draw-shader structs is a **memory-safety contract**: the system
|
||
"uses an unsafe pointer trick in `DrawVars::as_slice()` that reads
|
||
contiguously past the end of `dyn_instances` into the subsequent `#[live]`
|
||
fields… [misordering] will **corrupt the GPU instance buffer**." A "Rust is
|
||
safe" framework whose GPU buffer integrity depends on developers reading a
|
||
rulebook is a documented footgun, full stop. The fix (derive-time layout
|
||
assertions) is a weekend of proc-macro work; it hasn't been done.
|
||
|
||
**A2 — A 53k-line bespoke language is the price of admission.**
|
||
`platform/script` (parser.rs 4,291 lines + VM + test app) is the core of
|
||
2.0: a whole scripting language whose tokenizer quirks are normalized as
|
||
usage rules — `#2ecc71` fails because `2e` parses as scientific notation
|
||
("write `#x2ecc71`"), and comments before the first token shift all error
|
||
columns because "Rust's proc macro token stream strips comments entirely."
|
||
These are *bugs documented as features*; every downstream team will
|
||
rediscover them one cryptic error at a time.
|
||
|
||
**A3 — Split-brain event architecture.** Two lanes: low-level
|
||
`event.hits_with_capture_overload(cx, area, …)` vs high-level widget
|
||
`finger_down(actions)` — and **`Event::FingerDown` doesn't exist at all** on
|
||
the enum; you must know to ask for `Hit::FingerDown`. Worse, a `View` only
|
||
*emits* `FingerDown` if a `cursor` is set: **cursor styling gates input
|
||
semantics**. A tooltip changed your clickability. This cost real debugging
|
||
time in two separate ports this week.
|
||
|
||
**A4 — Layering discipline inverts at the edges.** `libs/` — nominally
|
||
third-party vendored code — contains 1.4M lines including ML inference
|
||
(`diffusion`, `mlx`, `tts`, `cuda`), a physics engine (`rapier`), and a
|
||
browser (`cef`). These are *example-app dependencies living in the platform
|
||
repo*: every `cargo metadata`, clone, index, and audit pays for demo assets.
|
||
Meanwhile `studio/` (the design tool) is compiled into the same workspace as
|
||
`widgets`, so example apps that import widgets transitively configure the
|
||
studio protocol — which is also the test harness's control channel.
|
||
|
||
**A5 — Duplicated registries.** Example crates must be added to
|
||
`Cargo.toml workspace.members` **and** `makepad.splash` **and** use a
|
||
`#[makepad_test]` package convention; 161 members vs 20 splash items shows
|
||
the two lists already drift arbitrarily. One source of truth generated from
|
||
Cargo metadata is the obvious fix AGENTS.md already half-implements by
|
||
policy.
|
||
|
||
**A6 — Headless is a figurative platform, not a real one.** There *is* an
|
||
`os/headless` backend — and dev `@ b41e740` **does not compile it on Linux**:
|
||
`gl_render_bridge` un-gated, `can_play_type_impl` missing the headless arm,
|
||
`libc_sys`/`ipc`/`dma_buf` modules absent under headless, `shared_framebuf`
|
||
importing them unconditionally, `HeadlessLoadedModule` missing `symbol()`,
|
||
`Cx::is_draw_shader_window_ready` unimplemented. Five separate compile breaks
|
||
= nobody has built this configuration in CI. (See §3, B1.)
|
||
|
||
## 2. Code quality
|
||
|
||
- **Q1 — File-scale pathology.** `vulkan.rs` at 7,120 lines, a 4,626-line
|
||
*test* `main.rs` in script, 3.9k `widget_tree.rs`. These aren't modules,
|
||
they're walls. Review and blame archaeology are dead on arrival.
|
||
- **Q2 — Warning debt on the hot path.** 14 warnings in `makepad-widgets`
|
||
alone, including `#[live(4.0)]` picking up the deprecated `f64→f32`
|
||
fallback the compiler explicitly schedules as a future **hard error**
|
||
(chart.rs:383-385, per rust-lang#154024). When rustc flips that switch this
|
||
crate stops compiling. This is known, dated breakage sitting in tree.
|
||
- **Q3 — Panic-as-control-flow at scale.** 1,562 `.unwrap()` in core sources.
|
||
Not fatal in demo apps; in a rendering framework each is a potential
|
||
app-crash under user data — and with no fuzzing or property tests in tree,
|
||
they're uncharacterized.
|
||
- **Q4 — Tokenizer debt is user-facing.** The `#x` hex prefix rule has a
|
||
second edge nobody documents: it applies only when a *digit directly
|
||
precedes `e`* (`#2ecc71` fails, `#e8926a` passes — verified empirically
|
||
here). Developers will hit the unlucky combinations at random.
|
||
- **Q5 — Leaky core abstractions.** `PortalList::next_visible_item`
|
||
**over-requests one item past the declared range end**; index blindly and
|
||
panic (verified in the rider chat list — the crash is in *their* pattern,
|
||
not user code). `ids!(var)` in a loop silently hashes the *literal* string
|
||
`"var"` — compiles clean, returns the wrong widget, no error. Dynamic lookup
|
||
requires `&[var]`, discovered via "unused variable" warnings, not docs.
|
||
- **Q6 — Doc coverage is uneven by an order of magnitude.** `widgets` has
|
||
~1,846 doc lines for 1,079 `pub fn`s (fine); `platform/os/headless` and
|
||
the script VM's public surface are essentially uncommented. The README is
|
||
marketing + socials; the deep contract lives in a file addressed to
|
||
language models.
|
||
- **Q7 — Repo hygiene as quality signal.** Root hosts `aigame.md`,
|
||
`handoff.md`, `talk.md`, `splashgame.md` etc. — sprint notes shipped as
|
||
project surface, next to 5 floating download scripts. This is what
|
||
"no release process" looks like.
|
||
|
||
## 3. Bugs (ranked — upstream, verified this session unless noted)
|
||
|
||
- **B1 (Critical) — dev head does not build for headless Linux.** Six
|
||
independent failures (listed in `patches/makepad-dev-headless-linux.patch`,
|
||
which this workspace ships): missing `cfg` gate on `gl_render_bridge`;
|
||
missing headless arm in `cx_api::can_play_type_impl`; three missing module
|
||
shims (`libc_sys`, `ipc`, `dma_buf`) under `os/mod.rs`; unconditional
|
||
imports in `shared_framebuf.rs`; unimplemented `symbol()` on
|
||
`HeadlessLoadedModule`; unimplemented `Cx::is_draw_shader_window_ready()`.
|
||
Shipping a workspace where a documented platform doesn't compile means the
|
||
platform matrix isn't gated *at all*.
|
||
- **B2 (High) — Warning class scheduled to become fatal.** `f64→f32`
|
||
implicit fallback in `#[live]` defaults (≥2 sites in chart.rs, plus
|
||
draw-glyph/draw-pbr warnings). Silence today, hard error on a future
|
||
toolchain the project doesn't pin (and can't pin — no `rust-toolchain`).
|
||
- **B3 (High) — `PortalList` range overrun** (see Q5): core list widget
|
||
emits item ids outside the declared range; every consumer must defensively
|
||
`.get()` or panic. This belongs in the widget, not in 100 downstream
|
||
guards.
|
||
- **B4 (Medium) — Cursor-gated hit testing** (A3): a `View` with no `cursor`
|
||
and no animator is click-invisible. Undocumented in code; breaks the
|
||
mental model "drawn area == hittable area".
|
||
- **B5 (Medium) — Comment-stripping breaks diagnostics**: leading comments
|
||
or blank lines inside `script_mod!` desynchronize error spans (the fix
|
||
"start with real code" is legislated in AGENTS.md rule 18 instead of the
|
||
tokenizer tracking trivia).
|
||
- **B6 (Medium) — Hex/scientific-notation collision** (rule 19): tokenizer
|
||
wart preserved as permanent API surface via the `#x` escape.
|
||
- **B7 (Medium) — Boot-order fragility**: the widget tree builds lazily, so
|
||
boot-time `ui.widget(cx, …)`/`view(cx, …)` borrows return nothing and any
|
||
unconditional unwrapping crashes; consumers must poll/guard. Also:
|
||
`.view()` and `.widget()` return *different* sets (`ViewSet` vs
|
||
`WidgetSet`) — a custom widget queryable via one and silently absent via
|
||
the other.
|
||
- **B8 (Low) — Test-harness locator semantics**: `makepad_test` `click()`
|
||
always targets widget center, `wait_visible` doesn't check viewport
|
||
containment, no offset/click-at-point primitive; failure artifacts are
|
||
good (`failure.txt`/`widget-tree.txt`) but the panic line
|
||
(`runtime.rs:1374`) is the only stack context.
|
||
- **B9 (Low) — Floating example assets**: `download_tts.sh` pulls
|
||
`ggml-large-v3-turbo.bin` from a HF `resolve/main` URL — content changes
|
||
underneath you; reproducible example builds are impossible by construction.
|
||
|
||
## 4. Performance
|
||
|
||
- **P1 (Strength) — The render architecture earns its reputation.** Shader-
|
||
driven immediate-mode-over-retained-areas, draw-call batching, per-area
|
||
invalidation, hot reload, GL/Vulkan/DX/Metal backends, headless raster.
|
||
UI rendering performance is not the problem.
|
||
- **P2 — Everyone pays the ML tax.** `libs/` vendoring (`cuda`, `diffusion`,
|
||
`mlx`, `tts`, `rapier`, `cef`, `windows-bindgen`) inflates clone to 209 MB
|
||
and metadata/graph resolution for *every* consumer, including the phone-
|
||
sized demo apps that use none of it.
|
||
- **P3 — Boot cost discipline is absent.** Because the DSL is interpreted at
|
||
startup, app boot includes full script parse+link; in the headless harness
|
||
each app instance (with protocol handshake) costs **~10–20 s** cold. That
|
||
also defines the floor for any startup-time-sensitive product — and it's
|
||
unmeasured anywhere in tree (no startup benchmark exists).
|
||
- **P4 — Build-time is the real DX bottleneck.** From-scratch `cargo check`
|
||
of a two-example workspace on this sandbox ran into tens of minutes
|
||
(instrumented indirectly via long build phases this session); with no CI
|
||
caching artifacts and no sccache config committed, every contributor eats
|
||
it raw.
|
||
- **P5 — Test parallelism defeat**: `#[makepad_test]` boots one child app
|
||
per test, serially in practice — the 9-test rider suite needs ~3 minutes.
|
||
With ~zero pure unit tests upstream (§2), the only green/red loop is slow
|
||
by construction.
|
||
- **P6 — No perf guardrails**: no frame-time harness, no allocation
|
||
tracking, no per-commit renderer benchmarks. A framework that sells
|
||
performance should have a `benches/` that CI enforces; there isn't one.
|
||
|
||
## 5. Security & safety
|
||
|
||
- **S1 — GPU buffer integrity by convention** (A1, AGENTS.md rule 16).
|
||
`DrawVars::as_slice()` performs a documented out-of-slice contiguous read
|
||
into trailing fields; correctness depends on field *order* in user
|
||
structs. This is memory-unsafety reachable from perfectly ordinary app
|
||
code, mitigated only by "read the doc". Any safety-branded framework must
|
||
encode this invariant in the derive macro — compile error, not markdown.
|
||
- **S2 — Unsafe surface with no audit scaffolding.** 2,565 `unsafe`
|
||
occurrences in `platform`, no `#[deny(unsafe_op_in_unsafe_fn)]` policy, no
|
||
Miri/ASAN config in tree, no security.md, no audit comments linking to
|
||
invariants. For OS interop some of this is necessary — but there's no
|
||
evidence of a systematic review trail.
|
||
- **S3 — Supply chain: floating, unverified multi-GB fetches.**
|
||
`download_cef.sh` (spotify CDN), `download_map.sh` (geofabrik),
|
||
`download_tts.sh`/`download_voice.sh` (HuggingFace `resolve/main`) — no
|
||
pinned versions, no SHA-256, no signatures (verified in the scripts
|
||
themselves: straight `curl`/`wget`). One poisoned CDN account away from
|
||
shipping blobs into user apps.
|
||
- **S4 — Studio protocol exposure.** The studio hub and the test harness
|
||
speak a control protocol into the app process (stdin/stdout in
|
||
`makepad_test`, hub channels in `studio/`). There's no visible auth or
|
||
scoping in-tree; treating a design-time channel as implicitly-safe is how
|
||
debug endpoints end up in production builds (cf. every framework that
|
||
learned this the hard way).
|
||
- **S5 — Vendored 1.4M lines of third-party code without provenance
|
||
tracking.** No `vendor.lock`, no audit metadata, no automated `cargo
|
||
audit` equivalent that can even *see* these. Vulnerabilities in the
|
||
vendored `windows` bindgen / `rapier` / `stitch` snapshots are invisible
|
||
to the entire Rust security tooling ecosystem by construction.
|
||
- **S6 — No lockfile committed for a 161-member workspace** (`.gitignore`:
|
||
`Cargo.lock`). Consumers resolve fresh dependency graphs per build;
|
||
combined with no toolchain pin, "works on my machine" is the *designed*
|
||
state.
|
||
- **S7 (positive)** — Example app code (splash/uizoo) avoids `unwrap`
|
||
entirely and the script engine has its own dedicated test app
|
||
(`platform/script/test`, 4.6k lines): the language authors test their
|
||
language. The rest of the org does not test theirs.
|
||
|
||
## 6. Design (API & developer experience)
|
||
|
||
- **DX1 — The 855-line AGENTS.md is both the project's best document and its
|
||
worst smell.** It exists because the failure modes are real: it's a
|
||
catalog of every sharp edge formalized as user obligations (rules 16/18/19
|
||
quoted above, the `let X = #(X::register_widget(vm))` incantation,
|
||
`instance()`/`uniform()` shader-only, `theme.` prefixes, `+:` merge). Good
|
||
frameworks remove edges; this one documents them and continues.
|
||
- **DX2 — Silent-failure ergonomics.** `ids!(var)` (Q5), `.view()` vs
|
||
`.widget()` set difference (B7), mod.widgets assignment *not* bringing a
|
||
widget into scope (triageable only via "variable X not found in scope"
|
||
much later), cursor-gated actions (B4): a consistent pattern — the wrong
|
||
code compiles and runs, just misbehaves.
|
||
- **DX3 — Naming/macro ceremony.** `live_id!`, `ids!`, `id!`,
|
||
`live_id_unchecked`, `#[makepad_test]`, `app_main!`, `script_mod!`,
|
||
`script_shader!`, `register_widget(vm)`, `WidgetSet` vs `ViewSet` vs
|
||
`WidgetRef` — the conceptual surface per trivial app is far above
|
||
egui/dioxus-tier, and migration from 1.x `live_design!` is breaking with
|
||
no codemod in tree.
|
||
- **DX4 — Test authoring is the best DX in the repo** (once discovered):
|
||
`Selector::id(...).click(); app.press_key(...)` — but it needs
|
||
click-at-point, viewport checks, and faster boots to graduate from
|
||
"usable" to "good". Notably, the only real test culture visible on dev
|
||
lives in *example apps*, not the framework.
|
||
- **DX5 — 1.x→2.0 doc gap.** Search engines serve makepad 1.x `live_design!`
|
||
answers; 2.0 changed the shape of everything and the only authoritative
|
||
source is in-repo. Every external LLM, blog, or tutorial mis-teaches 2.0
|
||
users today.
|
||
- **DX6 — `makepad.splash`/`Cargo.toml` dual registration** (A5) and the
|
||
20-of-161 splash coverage: the example discovery story is itself
|
||
unenforced.
|
||
|
||
---
|
||
|
||
## 7. Execution plan — make this codebase actually improvable
|
||
|
||
Written to be actionable from two seats: **the Makepad team** (upstream) and
|
||
**a consumer running a private fork** (what this workspace can do today).
|
||
Rough effort assumes a small team.
|
||
|
||
### Phase 0 — Supply-side hygiene (2–3 days; fork can do all of it)
|
||
|
||
| # | Task | Acceptance |
|
||
|---|---|---|
|
||
| 0.1 | Commit `rust-toolchain.toml`, un-ignore `Cargo.lock` for workspace+examples, add `audit.toml`/`cargo-deny` | Reproducible builds; `cargo deny check` green |
|
||
| 0.2 | **Stand up CI** (GitHub Actions matrix: Linux/macOS/Windows × {x11, wayland, **headless**}): `cargo check --workspace`, run `platform/script/test`, run `makepad_test` suites for 3 example apps | dev head must compile every declared platform; B1 class of bug becomes impossible to merge |
|
||
| 0.3 | Zero-warning policy: fix the 54 warnings incl. `f64→f32` live defaults (B2); add `-D warnings` to CI | Tree compiles clean; future-hard-error class extinguished |
|
||
| 0.4 | Pin + checksum all `download_*.sh` assets (URL → version + SHA-256 manifest), move to `xtask` | Tamper-evident asset fetches (S3) |
|
||
| 0.5 | **Upstream the five headless-Linux fixes** from `patches/makepad-dev-headless-linux.patch` as one PR with a headless CI leg proving it | Patch deleted locally |
|
||
|
||
### Phase 1 — Kill the documented footguns (3–6 weeks)
|
||
|
||
| # | Task | Acceptance |
|
||
|---|---|---|
|
||
| 1.1 | Encode the draw-shader layout invariant **in the derive**: generated `const _: ()` asserting no non-instance data after `DrawVars`/instance fields; `DrawVars::as_slice` gets `unsafe_op_in_unsafe_fn` + SAFETY comments (S1) | Misordered struct = compile error; AGENTS.md rule 16 deleted as obsolete |
|
||
| 1.2 | Tokenizer fixes: treat trivia (comments) in span tracking (B5); disambiguate `e` in hex without `#x` — and make `#x` a warning-free alias for one release (B4/DX4) | `#2ecc71` parses; rule 19 removed |
|
||
| 1.3 | Compile-time DSL validation: parse `script_mod!` in the proc-macro as far as possible (head/token/`=` vs `:` checks) with rustc diagnostics; runtime errors only for true dynamic features | Common DSL mistakes fail at `cargo check`, citing file:line |
|
||
| 1.4 | Hard-error the silent failures: `ids!` of a non-literal when a same-named var is in scope = error suggesting `&[var]`; `View` without cursor that has finger handlers = warning; `.view()` vs `.widget()` hints in error text | Every trap from §2 produces a message at the point of mistake |
|
||
| 1.5 | `PortalList` contract: never yield out-of-range item ids (B3) + regression test in-tree | `.get()` guard no longer required downstream |
|
||
|
||
### Phase 2 — Test & quality architecture (4–8 weeks, overlapping)
|
||
|
||
| # | Task | Acceptance |
|
||
|---|---|
|
||
| 2.1 | Test-floor policy: every `widgets/src` widget gets at least smoke coverage; grow core `#[test]` count from 157 toward a per-file baseline; property tests for script parser/VM (corpus exists in `platform/script/test` — generalize) | CI reports coverage; trend enforced non-decreasing |
|
||
| 2.2 | `makepad_test` v2: click-at-point, viewport-visibility semantics for `wait_visible`, parallel app boots, boot-time budget alert (~>5 s/instance fails perf gate), richer failure diffing (current text artifact is fine, add tree diff vs expectation) | Rider-scale suite (9 tests) < 60 s wall |
|
||
| 2.3 | Renderer benchmark harness (`benches/`): frame time on canonical scenes, allocation regression gate, startup-time measurement (P3/P6) | Perf numbers on every PR |
|
||
| 2.4 | Unsafe audit program: categorize the 2,565 with `cargo geiger`, Miri on `platform/script` VM + `shared_framebuf` + draw-vars paths; SAFETY-comment lint | Audit report committed; Miri leg in CI |
|
||
| 2.5 | Clippy pedantic on changed code baseline; mega-file roadmap (split `vulkan.rs`, `widget_tree.rs`, `portal_list.rs` behind submodules — no behavior change) | Largest file < 2.5k lines |
|
||
|
||
### Phase 3 — Repo & ecosystem surgery (2–6 weeks)
|
||
|
||
| # | Task | Acceptance |
|
||
|---|---|
|
||
| 3.1 | Move `libs/` ML/CEF/demo stacks into a separate `makepad-extras` repo (or crates.io deps); core clone back to <60 MB | Clone time / `cargo metadata` drop visibly (P2) |
|
||
| 3.2 | Vendor manifest for what remains (`vendor.lock` with upstream commit + license), license audit of the whole tree | SBOM generated in CI (S5) |
|
||
| 3.3 | Root cleanup: planning docs → `docs/internal/` or wiki; single registration source (`xtask` generates splash run-items from workspace metadata) | A5 resolved; no dual entry (DX6) |
|
||
| 3.4 | Authoritative docs: rustdoc for `widgets` + `platform/script`, published per-commit; AGENTS.md content rendered into the human docs (it's currently agent-only); 1.x→2.0 migration guide + codemod script | DX5 closed; `docs.rs`-grade reference |
|
||
| 3.5 | Studio protocol: audit surface, default-off in release profiles, scoped loopback + token for test channel (S4) | Release builds ship no open control plane |
|
||
|
||
### Phase 4 — What the fork in this workspace should do *now* (days)
|
||
|
||
1. Carry the five headless patches until Phase 0.5 lands (already done).
|
||
2. Keep the three test-suffixed example crates as the project's accidental
|
||
"integration lab": they already exercise PageFlip, PortalList, custom
|
||
draw shaders, script_apply_eval, hit capture, and the test harness —
|
||
formalize them as the fork's regression suite for upstream bumps.
|
||
3. Gate any upstream re-sync on: clean `git apply` of patches, all 140
|
||
port tests green (currently: rider 21+9+9, koboyo 29+14+8, insurance
|
||
28+14+8), zero new warnings.
|
||
|
||
### Definition of done (framework-level)
|
||
|
||
1. `dev` compiles on every platform it names, in CI, with `-D warnings`.
|
||
2. No memory-safety invariant lives only in documentation (S1 closed).
|
||
3. A new example app can be built by reading rustdoc alone — 0 AGENTS.md
|
||
rules required to avoid silent traps (DX1/DX2).
|
||
4. Test culture shift measurable: core `#[test]` count ×10 at minimum and
|
||
CI-time <15 min with caching.
|
||
5. Clone-and-build to running `uizoo` from a cold machine <10 min.
|
||
|
||
---
|
||
|
||
### Bottom line
|
||
|
||
Makepad is **the best Rust-UI render stack wrapped in research-lab
|
||
engineering discipline**. The engine deserves the ambition; the repository
|
||
doesn't currently deserve users. The single highest-leverage change costs
|
||
almost nothing — CI + warnings + the headless fix (Phase 0) — and would have
|
||
prevented every upstream bug hit in this workspace. Everything durable
|
||
beyond that is one theme: convert obligations currently printed in
|
||
`AGENTS.md` into compiler-enforced invariants, and the framework grows from
|
||
"impressive demo platform" into something teams can bet on.
|