Go to file
Levi Neuwirth 05fbbd9919 M10.10: complete optimistic-apply keystroke path + Day-5 corrections
Post-ship-gate completion of M10.10 (optimistic local edit
application, Path β). The milestone core landed in 45be65b
"M10.10 ship gate"; this commit completes the frontend keystroke
path and absorbs Day-5 corrections.

Completes:
- optimistic::frontend_event_for_keystroke — keystroke orchestrator
  (classify_key predicate → mirror-ready check → CrdtOp or Key
  fallback per Refinement 4 graceful degradation).
- BufferMirror cursor tracking (active_buffer, cursor_byte_pos via
  CursorByte) + char-boundary-aware delete helpers (prev/next_char_len)
  so multibyte backspace/delete don't trip loro's mid-codepoint
  rejection.
- buffer.rs: crdt_state accessor (was test-only) now production —
  daemon's BufferSnapshot export path uses it.

Day-5 corrections:
- packages/manifest.rs: fix pre-existing M8-era proptest generator
  that produced ".."-containing entry paths the parser correctly
  rejects (segment-structured regex; stale regression seed removed).
  Out of M10.10 scope; absorbed so future milestone sweeps see clean
  output instead of a known-failing test requiring prose.
- tests: extract inline PTY/daemon helpers to shared tests/common/
  module (m5_5, m5_8 now import; no coverage change — m5_5 retains
  19 m10_10 tests). tests/common/ added (required for compilation).

Audit history (M10.10-AUDIT.md is gitignored internal-only; this
message is the sole version-controlled record):

M10.10 PASSES within Path β scope (end-of-line optimistic visual
paint; mid-line/delete-forward round-trip; full CRDT-op exchange
across the text-input scope). The initial audit verdict was WRONG —
optimistic-apply was structurally unreachable in the production
binary (build_capabilities advertised crdt_replica: false). Six
post-audit review rounds surfaced 28 findings (F5–F32) beyond the
framing pass's original 4. Six M10-era discipline additions emerged,
each empirically grounded: end-to-end-exercise check (bidirectional
scope), composition-consistency check, verification-milestone premise
check, library-API verification check, forward-pointer-comment
hygiene, methodology-composition check.

Scorecard adopts Option C dual methodology: layer (a) framing-pass
accuracy is 7/8 milestones-not-findings AND 2/8 findings-as-failures
— the 5/8 spread is the density diagnostic (M10.10's defining
characteristic; neither number alone is honest). Layer (c): 7/8 and
6/8 (M10.8 inherited-gap cluster). Budget honesty: 5-day
pre-authorization covered anticipated implementation surprises (K1,
Risk #6 a); Finding 3 was a third surprise absorbed via compression,
not structural slack; the six post-audit rounds were entirely
unbudgeted and are the milestone's dominant cost. M10.10's density
is partly forecastable — it is the only M10 milestone with all three
of: architectural reversal, multi-milestone integration, and
verification depending on incomplete cross-milestone wiring.

Ship-gate clean on clean checkout (cargo clean + rebuild): luajit+crdt
1364/1364, luajit 1211/1211, lua54+crdt 1364/1364, lua54 1211/1211,
m5_5 daemon-e2e 36/36, perf 1MB=1.1ms vs 10ms gate, clippy 0 across
feature combos, fmt clean. One transient flake observed
(async_runtime::supersede_cancels_in_flight_job_within_50ms — timing
test starved under concurrent compile load, non-reproducible in
isolation, known infra pattern, not an M10.10 regression).

Next: M10.11 (two-laptop acceptance) inherits all six discipline
additions; v1.0 ships after M10.11.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 16:40:46 -04:00
.github/workflows Initial commit: v0.1.0 2026-05-03 19:51:06 -04:00
audit M7 tail: package system, audit lint, lockfile, resolver 2026-05-07 16:50:37 -04:00
builtin M9 ship gate 2026-05-09 15:04:23 -04:00
docs M9 ship gate 2026-05-09 15:04:23 -04:00
proptest-regressions M10.10 ship gate 2026-05-13 16:28:46 -04:00
src M10.10: complete optimistic-apply keystroke path + Day-5 corrections 2026-05-15 16:40:46 -04:00
tests M10.10: complete optimistic-apply keystroke path + Day-5 corrections 2026-05-15 16:40:46 -04:00
.gitignore gitignore: add /M*-API-SURVEY.md to internal-only patterns 2026-05-09 17:38:48 -04:00
CHANGELOG.md Initial commit: v0.1.0 2026-05-03 19:51:06 -04:00
Cargo.lock M10.10 ship gate 2026-05-13 16:28:46 -04:00
Cargo.toml M10.10 ship gate 2026-05-13 16:28:46 -04:00
LICENSE-APACHE Initial commit: v0.1.0 2026-05-03 19:51:06 -04:00
LICENSE-MIT Initial commit: v0.1.0 2026-05-03 19:51:06 -04:00
README.md Fix PTY final-output drain race 2026-05-04 09:44:30 -04:00
build.rs Initial commit: v0.1.0 2026-05-03 19:51:06 -04:00
rustfmt.toml Initial commit: v0.1.0 2026-05-03 19:51:06 -04:00

README.md

Pmacs

Parallel Emacs --- a Rust-cored, Lua-scripted editor in the Emacs tradition.

Pmacs runs the editor's hot path (rope, buffers, views, async runtime, process supervision) in Rust, and exposes the rest --- commands, keymaps, hooks, packages --- through an embedded Lua VM. The design follows Emacs in shape (configurable, introspectable, programmable from inside) but discards the single-threaded substrate; workers, message bus, and a coroutine-based async surface are core primitives, not bolt-ons.

The editor is partitioned into a long-lived instance (the daemon that owns buffers, processes, and language services) and a thin frontend that attaches over a typed protocol. Frontends can run locally over a Unix socket or remotely over SSH; reconnect-on-drop modeled on mosh keeps remote sessions alive across laptop suspends.

The first-class package is a REPL package written entirely against the public Lua API: PTY-spawned shells (bash, zsh, fish, lua), an ECMA-48 ANSI parser, multi-REPL coexistence, and scrollback management with line/byte retention. Successful completion of an audit verifying the package uses zero direct Rust core access was the v0.1 ship gate.

Status

v0.1.0 --- preview. The design described above is implemented and working. Solo development through 1.0; public contributions are deferred until then. Use, evaluate, and file issues; pull requests will get a friendly "thanks, see you at 1.0" until that gate.

Build

Requires Rust 1.85 or newer (edition 2024). Lua flavor selectable between luajit (default) and lua54; both pass the full test suite.

cargo build --release             # produce target/release/pmacs
cargo run --release -- <file>     # build and run on a file
cargo test                        # unit + integration tests
cargo fmt --check
cargo clippy --all-targets -- -D warnings

Release-only perf gates (M5 keystroke-to-render, M6 ingest/RSS/cancel and scrollback navigation/search) are #[ignore]'d during normal test runs and exercised in CI under dedicated jobs.

Runtime requirements

The pmacs binary depends on a small set of POSIX command-line tools at runtime. The dependency exists because the project enforces #![forbid(unsafe_code)] everywhere, including in tests; calls that would otherwise need unsafe (PTY raw-mode setup, signal name translation) are routed through trampolines that exec these tools.

  • /bin/sh (POSIX shell). Used for the PTY raw-mode trampoline: /bin/sh -c 'stty raw -echo </dev/tty 2>/dev/null; exec "$@"' -- configures the controlling TTY's line discipline before exec'ing the actual subprocess. Required by the REPL package and any other caller that spawns a process in raw PTY mode.
  • stty (coreutils). The line-discipline configurator invoked by the trampoline above.
  • coreutils more broadly. The M6 process-supervisor tests spawn cat, yes, and which; absent these the test suite (not the editor itself) degrades. which is also used by the M6.5 shell-locator helper to find bash / zsh / fish for per-shell integration tests. The M7.2 fetcher's timeout test uses sleep.
  • git (added in M7.2). Required for any package operation: the package fetcher shells out to git to clone, fetch, and resolve refs, with a deterministic environment (GIT_TERMINAL_PROMPT=0, GIT_CONFIG_NOSYSTEM=1, LC_ALL=C, inherited GIT_* variables stripped). Authentication for private repositories rides the user's existing git configuration (credential helpers, SSH agent), so packagers do not need a separate auth story. Pre-M7 builds without package operations do not need git.
  • tar (added in M7.3). Required for pmacs.packages.install: the installer materializes a snapshot via git archive --format=tar piped into tar -x -C <dest>, which keeps the on-disk install directory self-contained (no .git linkage back to the bare cache, no working-tree state). GNU tar and bsdtar both work. Pre-M7 builds and any path that doesn't call pmacs.packages.install{...} do not need tar.

Distribution packagers should ensure these are runtime dependencies of the pmacs package. On a typical Linux distribution, busybox or GNU coreutils plus a shell of any kind satisfies the requirement; on macOS the system shell and /usr/bin/stty are both standard.

The Lua VM (LuaJIT or Lua 5.4) is statically vendored via mlua's vendored feature, so there is no external Lua dependency at runtime.

What v0.1 ships with

  • Editor core. Persistent rope with O(log N) edits and snapshots; buffers with chained intercept-views; undo/redo; atomic file I/O; crossterm-driven TUI.
  • Lua surface. Embedded LuaJIT (or Lua 5.4) with pmacs.command, pmacs.keymap (global / mode / buffer scopes), pmacs.hook (typed kinds: all-must-succeed, first-non-nil, last-write-wins), pmacs.buffer, pmacs.window, pmacs.editor. Minibuffer is itself a buffer. describe-key and describe-command for self-introspection.
  • Async runtime. Worker pool + message bus + coroutine-based Lua async surface (pmacs.async). Cancellation is provably correct under load.
  • Language services. Tree-sitter highlighting and LSP integration ride the worker/message infrastructure. Project indexing as a third service. Symbol search across 1M+ symbols completes under a second.
  • Frontend partition. Daemon mode with local Unix-socket transport; cell-delta diffing on the instance side; SSH transport variant for remote attach; reconnect-on-drop preserves session state across laptop suspend / network drop.
  • REPL package. A 691-line Lua package that wires the M6 ANSI parser to PTY-spawned shells with raw-mode line discipline. Three- region buffer (history / prompt / input) with read-only enforcement; RET / C-c / C-d bindings; multi-REPL coexistence; scrollback retention with line- and byte-bounded truncation. Published alongside an audit verifying zero direct Rust core access.

Layout

src/                 Rust core
  rope.rs              persistent byte-sequence backing every buffer
  buffer.rs            buffer + view chain + undo/redo
  editor_core.rs       cursor + commands + edit dispatch
  async_runtime.rs     worker pool + message bus
  process.rs           PTY-aware process supervisor
  ansi.rs              ECMA-48 parser
  daemon.rs            instance side of the frontend partition
  attach.rs            frontend side; protocol + reconnect
  lsp.rs               language-server client
  syntax.rs            tree-sitter integration
  project_index.rs     symbol / file indexing
  text_view.rs         cell-grid renderer
  frontend.rs          crossterm TUI
  lua_bindings.rs      pmacs.* Lua surface installers
  main.rs              entry point (TUI + daemon modes)

builtin/             Lua runtime shipped with the binary
  commands/default.lua  named commands for every editor primitive
  keymaps/default.lua   default key bindings
  hooks/default.lua     built-in hook definitions
  runtime/              packages (async, lsp, repl, syntax)

tests/               integration tests (acceptance gates per milestone)

License

Dual-licensed under either of:

at your option.