Skip to content

feat(infra): Spacemacs joins the config environments; GUI config-boot comparisons - #403

Merged
eval-exec merged 4 commits into
mainfrom
infra/spacemacs
Sep 19, 2026
Merged

eval-exec merged 4 commits into
mainfrom
infra/spacemacs

Conversation

@eval-exec

Copy link
Copy Markdown
Owner

What

Second config environment for neomacs-infra, plus GUI-boot parity tests for both configs.

The abstraction

ConfigEnvironment trait (session contract: name/tree/home/session_env/session_args/prepare_session_state) with shared lifecycle in config_env::common (spec parse, shallow fetch-by-SHA, seal, MANIFEST). Adding Centaur Emacs later = one file + one spec + one CLI arm, zero consumer edits.

Spacemacs session model

No DOOMLOCALDIR-style redirect exists — writable state lives inside .emacs.d itself. Sessions mount through a HOME overlay: <state>/.emacs.d is a real directory whose entries symlink into the sealed tree (dotfiles included — .lock is checked in; .git skipped), elpa shared read-only from extracted package state (Doom's straight/ trick generalized), .cache copied per session. Deterministic .spacemacs dotfile suppresses the first-run wizard, pins the home buffer's wall-clock footer, carries the lexical-binding cookie on line 1.

Real fixes found by the first live sessions

  • copy_tree_writable — fs::copy reproduces sealed read-only bits; Spacemacs rewrites .cache/spacemacs-buffer.el every boot
  • Probe fixture paren balance (a silent load failure masqueraded as a rendering bug for a whole chase)
  • Isolation hardening at the trait level: XDG dirs pinned inside session state, NO_AT_BRIDGE/GTK_MODULES cleared (the accessibility bridge wedges GUI startup in do_wait), quit escapes past config frameworks' kill-emacs confirmations
  • Ported teammate's Windows cargo check gating (is_sealed/symlink/seal) into the new module structure

Results

Test Status
Spacemacs TUI boot parity ✅
Doom TUI face comparison ✅
Doom GUI boot parity (Xvfb) ✅ 15s
Spacemacs GUI (GNU side) ⏸ open: GNU blocks before opening its X connection; TUI green, doom GUI green on identical env — spacemacs-specific, documented in test

Spacemacs is the second config environment and stresses the
abstraction exactly where it should: the distribution IS ~/.emacs.d
with no DOOMLOCALDIR-style redirect, writable state lives inside
.emacs.d itself.  The session model is therefore a HOME overlay:
<state>/.emacs.d is a real directory whose entries symlink into the
sealed tree (dotfiles included -- .lock is checked in; .git skipped),
elpa shared read-only from the extracted package state (Doom's
straight/ trick generalized), .cache copied per session.

Three real fixes fell out of the first live session, each now encoded
where it belongs:
- copy_tree_writable: fs::copy reproduces the sealed source's
  read-only bits, and Spacemacs rewrites .cache/spacemacs-buffer.el
  on every boot -- session-seeded copies must restore write bits.
- The deterministic dotfile carries the lexical-binding cookie on
  line 1 (below the header comment it is invisible, and GNU pops a
  *Warnings* window no paired comparison could match) and pins the
  home buffer's wall-clock footer via a :before advice on
  display-startup-time -- its unless-guard then keeps the constant.
- The existing Doom lifecycle moved behind a ConfigEnvironment trait
  (name/tree/home/session_env/session_args/prepare_session_state)
  with the shared machinery (spec parse, shallow fetch, seal,
  MANIFEST) in config_env::common; adding a third distribution
  (Centaur) is now one file, one spec, one CLI arm.

The TUI boot test mounts both editors through the overlay, settles
past deferred startup before first input (the Doom which-key lesson),
and asserts exact display parity -- green against the pinned
syl20bnr/spacemacs develop @ ab5bb4ce.
…dening

Both fixtures now mount in real GUI sessions through the same
ConfigEnvironment contract the TUI tests use: per-session HOME, XDG
directories pinned inside the session state (GTK3/fontconfig/GLib never
read the operator's real config), NO_AT_BRIDGE/GTK_MODULES cleared --
the accessibility bridge spawns a session bus under the redirected XDG
and wedges GUI startup in do_wait -- and quit escapes past config
frameworks' kill-emacs confirmations.

Three findings from the first live runs, each encoded where it belongs:
- The stock GUI harness defaults to -Q -l, which suppresses the very
  user-init the config tests exist to boot; the plan now sets its own
  args (mount args then -l probe, no -Q).
- The GTK3 GNU oracle is an X11 build: it cannot mount a Wayland-only
  weston at all.  GNU GUI under weston has never actually run on CI --
  one more leg of the still-open GUI cluster.  The config tests use
  the Xvfb backend, where GNU GUI is proven (live-font artifacts).
- GNU GUI does boot doom through the harness (frame opens, probe
  fires), but the scratch renders no visible text under software
  Xvfb/llvmpipe, and spacemacs GUI init never completes there within
  300s while its TUI boots in seconds.  Both tests land ignored with
  the status documented, mirroring the minor-mode repro convention.

The TUI spacemacs boot and doom face comparisons stay green.
Chased the empty-scratch wall to ground.  GNU GUI + the sealed doom
fixture under Xvfb boots doom successfully -- 'Doom loaded 14 packages
across 3 modules in 0.310s' in *Messages*, zero warnings with the
seeded DOOMLOCALDIR, and the pixel capture shows the themed frame
(doom's dark theme, ~50% coverage).  The harness's window-text probe
reads an intentionally-empty buffer: the minimal fixture doom (no
DOOMDIR) sets initial-scratch-message nil, so no window-text needle
can ever fire.  Neomacs on the same fixture shows the vanilla scratch
text -- itself a candidate divergence to settle.

Both GUI config tests stay ignored with the design requirement
documented: the comparison probe must observe doom-GUI state (dashboard
buffer presence, modeline face, or pixel diff), not selected-window
text.  The isolation hardening (XDG pins, NO_AT_BRIDGE, kill-emacs
escapes, Xvfb backend for the X11 GTK oracle) is all real and stays.
The empty-scratch wall was two bugs stacked, neither a rendering bug:

1. The probe fixture had unbalanced parens after string surgery — GNU
   failed to load it (end-of-file), the tick never armed, and every
   harness run timed out from a probe that was never running.  The
   needle redesign (scan *Messages* for the framework's finish line,
   since minimal doom sets initial-scratch-message nil and ships no
   dashboard without a DOOMDIR) rides along in the rewritten fixture.
2. With the fixture loading, doom GUI parity passes in 15s — GNU and
   Neomacs boot the sealed doom fixture on isolated Xvfb, identical
   frame/buffer/visible-text state.

Spacemacs GUI remains open, GNU-side only: in the harness GNU never
opens its X connection (no socket fd; gmain/gdbus idle; pango parked)
while the doom sibling passes on identical env and TUI spacemacs parity
is green — a spacemacs-specific pre-display block to chase separately.
Copilot AI balanced review requested due to automatic review settings September 19, 2026 17:28
@eval-exec
eval-exec merged commit 7bf6c5d into main Sep 19, 2026
29 of 37 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The checked-in .spacemacs fixture is unbalanced by one paren (fails to load), and copy_tree calls std::os::unix::fs::symlink directly, which breaks the Windows cargo check --workspace gate.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 High severity · 2 Low severity

Open (4)
What changed in this PR

This PR generalizes neomacs-infra's single Doom Emacs test fixture into a pluggable ConfigEnvironment abstraction and adds Spacemacs as a second environment, plus GUI boot-parity tests that compare GNU Emacs against neomacs for each config. The Doom-specific logic previously living inline in lib.rs is split into a config_env module (mod/common/doom/spacemacs), with shared lifecycle (spec parse, shallow fetch-by-SHA, seal, MANIFEST) in common. Spacemacs mounts through a HOME overlay (<state>/.emacs.d symlinks into a sealed tree; elpa shared read-only, .cache copied writable), driven by a deterministic .spacemacs dotfile that suppresses the first-run wizard.

Changes:

  • Extracts the fixture lifecycle into config_env with a ConfigEnvironment trait and shared common helpers, including a new copy_tree_writable (restores write bits so sessions can rewrite seeded state).
  • Adds the Spacemacs environment (HOME-overlay session model), its spec, and a deterministic dotfile fixture.
  • Adds TUI (spacemacs_boot.rs) and GUI (config_env_boot.rs + config-env-boot.el) boot-parity tests, and generalizes the infra CLI to materialize/status any named environment.
File Description
crates/​neomacs-infra/​src/​lib.rs Slims to crate docs + workspace_root; re-exports the new config_env API.
crates/​neomacs-infra/​src/​config_env/​mod.rs New ConfigEnvironment trait, XDG isolation env, NAMES/open_by_name.
crates/​neomacs-infra/​src/​config_env/​common.rs Shared spec/seal/fetch/copy lifecycle; copy_tree uses a raw unix symlink call (Windows-breaking).
crates/​neomacs-infra/​src/​config_env/​doom.rs Doom environment moved onto the trait, using shared common helpers.
crates/​neomacs-infra/​src/​config_env/​spacemacs.rs New Spacemacs environment with HOME-overlay session model.
crates/​neomacs-infra/​src/​bin/​infra.rs Generic materialize/status over NAMES; top-level usage string has a stray pipe.
crates/​neomacs-infra/​spacemacs-spec.toml Pins the Spacemacs repo/revision.
crates/​neomacs-infra/​fixtures/​spacemacs-dotfile.el Deterministic dotfile; dotspacemacs/user is missing a closing paren.
crates/​neomacs-gui-tests/​tests/​config_env_boot.rs GUI boot-parity test for Doom (active) and Spacemacs (ignored).
crates/​neomacs-gui-tests/​fixtures/​config-env-boot.el Shared GUI boot probe dumping window text + frame geometry.
crates/​neomacs-tui-tests/​tests/​spacemacs_boot.rs TUI boot-parity test; unused OsString import.
crates/​neomacs-tui-tests/​tests/​{tui,face_color_test,minor_mode_order_repro}.rs Wire in the new module/trait imports.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

(advice-add 'configuration-layer/display-startup-time :before
(lambda (&rest _)
(setq configuration-layer--spacemacs-startup-time 0.500
dotspacemacs--user-config-elapsed-time 0.500)))
if meta.is_symlink() {
let target = fs::read_link(source)
.map_err(|error| format!("readlink {}: {error}", source.display()))?;
std::os::unix::fs::symlink(&target, destination).map_err(|error| {
Comment on lines +49 to +55
eprintln!("usage: infra <materialize {} [path]|status>", {
let mut usage = String::new();
for name in neomacs_infra::config_env::NAMES {
usage.push_str(&format!("<{name}>|"));
}
usage
});
use crate::support;
use neomacs_infra::config_env::ConfigEnvironment as _;
use neomacs_tui_tests::{TuiLaunch, TuiSession, TuiTempDirectory};
use std::ffi::OsString;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants