docs(features): document the Lua feature matrix; drop unreachable compile_error idea (F-002)

`--all-features` can't build pmacs — luajit and lua54 select mlua's
mutually-exclusive Lua backends. Document the model so generic tooling
(CI, cargo hack, distro packaging) doesn't trip over it:

- README §Build: a feature-matrix table (luajit default / lua54 fallback /
  orthogonal crdt), the supported build lines, and an explicit "don't use
  --all-features".
- src/lib.rs crate docs: a "Lua flavor features" section stating the
  exactly-one-flavor rule.
- Cargo.toml [features]: expanded comment on the mutual exclusivity.

CI already iterates the flavors explicitly (never --all-features), so no
CI change was needed.

The audit's suggested crate-local compile_error! for the wrong-flavor case
was investigated and rejected as unreachable: the flavor check lives in
the mlua-sys *build script*, which cargo compiles before the pmacs crate,
so a mis-set flavor (both or neither) fails there first and pmacs's own
compile_error! never evaluates — confirmed empirically for both cases. A
dependent crate can't preempt a dependency's build failure, so the docs
are the honest mitigation and they name mlua-sys as the actual error
surface.

Validated: fmt clean; clippy clean under both Lua flavors; both flavors
build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014TXbAwk27agwhrNNrhLi2U
This commit is contained in:
Levi Neuwirth 2026-07-03 19:54:35 -04:00
parent 2da504b6a0
commit 3b630bfee4
4 changed files with 75 additions and 4 deletions

View File

@ -61,9 +61,17 @@ similar_names = "allow"
multiple_crate_versions = "allow" multiple_crate_versions = "allow"
[features] [features]
# Pick exactly one Lua flavor at build time. v0.1 default is LuaJIT # Pick exactly ONE Lua flavor at build time. v0.1 default is LuaJIT
# (spec §3 Checkpoint 6); lua54 is a buildable fallback for environments # (spec §3 Checkpoint 6); lua54 is a buildable fallback for environments
# without LuaJIT support (e.g. some CI hosts, big-endian machines). # without LuaJIT support (e.g. some CI hosts, big-endian machines).
#
# `luajit` and `lua54` are MUTUALLY EXCLUSIVE — they select mlua's
# mutually-exclusive Lua backends. `--all-features` enables both and CANNOT
# build; the `mlua-sys` build script errors ("You can enable only one of
# the features: …") before this crate compiles, so pmacs can't preempt it
# with a friendlier message — the fix is to build one flavor. See the
# feature matrix in README.md; build a non-default flavor with
# `--no-default-features --features lua54` (audit F-002).
default = ["luajit"] default = ["luajit"]
luajit = ["mlua/luajit", "mlua/vendored"] luajit = ["mlua/luajit", "mlua/vendored"]
lua54 = ["mlua/lua54", "mlua/vendored"] lua54 = ["mlua/lua54", "mlua/vendored"]

View File

@ -31,17 +31,49 @@ and send pull requests.
## Build ## Build
Builds on the toolchain pinned in `rust-toolchain.toml` (Rust Builds on the toolchain pinned in `rust-toolchain.toml` (Rust
`1.95.0`, edition 2024); rustup selects it automatically. Lua flavor selectable `1.95.0`, edition 2024); rustup selects it automatically.
between `luajit` (default) and `lua54`; both pass the full test suite.
```sh ```sh
cargo build --release # produce target/release/pmacs cargo build --release # produce target/release/pmacs (LuaJIT)
cargo run --release -- <file> # build and run on a file cargo run --release -- <file> # build and run on a file
cargo test --workspace # unit + integration tests (all crates) cargo test --workspace # unit + integration tests (all crates)
cargo fmt --check cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings # incl. pmacs-gpu cargo clippy --workspace --all-targets -- -D warnings # incl. pmacs-gpu
``` ```
### Feature matrix
Cargo features fall into two independent axes. **Do not use
`--all-features`** — it enables both Lua flavors at once, which cannot
build (see below).
| Feature | Axis | Notes |
| -------- | ---------- | ---------------------------------------------------------- |
| `luajit` | Lua flavor | **Default.** LuaJIT backend via `mlua` (vendored). |
| `lua54` | Lua flavor | Lua 5.4 fallback for hosts without LuaJIT (big-endian, …). |
| `crdt` | Buffer | Opt-in CRDT-backed buffer mode (adds the `loro` dep). v1.0 builds enable it; orthogonal to the flavor. |
**Exactly one Lua flavor must be enabled** — `luajit` *or* `lua54`, never
both (and never neither). They map to `mlua`'s mutually-exclusive Lua
backends, so `--all-features` (or `--features luajit,lua54`, or
`--no-default-features` with no flavor) fails in the `mlua-sys` build
script with *"You can enable only one of the features: …"*. That check
lives in a dependency cargo builds first, so pmacs can't replace it with a
friendlier error — the fix is to build a specific flavor. Supported build
lines:
```sh
cargo build --release # luajit (default)
cargo build --release --no-default-features --features lua54
cargo build --release --features crdt # luajit + crdt
cargo build --release --no-default-features --features lua54,crdt
```
CI, `cargo hack`, and distro tooling should iterate the flavors
explicitly (`--no-default-features --features <flavor>[,crdt]`) rather
than reaching for `--all-features`. Both flavors pass the full test suite;
CI runs the matrix on every push.
Release-only perf gates (M5 keystroke-to-render, M6 ingest/RSS/cancel Release-only perf gates (M5 keystroke-to-render, M6 ingest/RSS/cancel
and scrollback navigation/search) are `#[ignore]`'d during normal and scrollback navigation/search) are `#[ignore]`'d during normal
test runs and exercised in CI under dedicated jobs. test runs and exercised in CI under dedicated jobs.

View File

@ -112,6 +112,22 @@ lua54`, and `--features crdt`. If possible, add a clearer crate-local compile
error for simultaneously enabled Lua flavors so users see a pmacs-specific error for simultaneously enabled Lua flavors so users see a pmacs-specific
message before the `mlua-sys` failure. message before the `mlua-sys` failure.
Resolution (PR TBD): documented the feature matrix explicitly — a table in
`README.md` §Build (the two Lua flavors + orthogonal `crdt`, the supported
build lines, and an explicit "don't use `--all-features`"), a `# Lua flavor
features` section in `src/lib.rs`'s crate docs, and an expanded `Cargo.toml`
`[features]` comment. CI already avoids `--all-features` (it iterates the
flavors explicitly), so no CI change was needed.
The suggested crate-local `compile_error!` was **investigated and rejected as
unreachable**: the flavor check lives in the `mlua-sys` *build script*, which
cargo compiles before the `pmacs` crate, so any mis-set flavor (both, or
neither) fails there first and `pmacs`'s own `compile_error!` never evaluates
— confirmed empirically for both cases. A dependent crate cannot preempt a
dependency's build failure, so the honest mitigation is the documented matrix
rather than a guard that can never fire. The docs state that the actual error
surface is the `mlua-sys` message.
### F-003 - Medium - `pmacs-gpu` can appear hung when attached to a non-CRDT daemon ### F-003 - Medium - `pmacs-gpu` can appear hung when attached to a non-CRDT daemon
Evidence: Evidence:

View File

@ -23,6 +23,21 @@
//! * [`worker`] --- work-stealing pool with cooperative cancellation (M3.1) //! * [`worker`] --- work-stealing pool with cooperative cancellation (M3.1)
//! * [`message_bus`] --- typed in-process bus with `MessagePack` codec (M3.2) //! * [`message_bus`] --- typed in-process bus with `MessagePack` codec (M3.2)
//! * [`async_runtime`] --- main-thread dispatcher + tick over the bus (M3.3) //! * [`async_runtime`] --- main-thread dispatcher + tick over the bus (M3.3)
//!
//! # Lua flavor features (audit F-002)
//!
//! Exactly **one** Lua flavor must be enabled: `luajit` (the default) **or**
//! `lua54`. They select `mlua`'s mutually-exclusive Lua backends, so
//! enabling both — most commonly via `--all-features` — or neither is a
//! hard build error. The `crdt` feature is orthogonal and composes with
//! either flavor. See the feature matrix in `README.md` / `Cargo.toml`.
//!
//! Note: a misconfigured flavor set surfaces as an **`mlua-sys` build-script
//! error** ("You can enable only one of the features: …"), not a
//! pmacs-labeled one. That check lives in a *dependency*, which cargo
//! compiles before this crate, so pmacs cannot intercept it with its own
//! `compile_error!` — the mitigation is the documented matrix (don't reach
//! for `--all-features`; build an explicit flavor).
pub mod ansi; pub mod ansi;
pub mod async_runtime; pub mod async_runtime;