Commit Graph

5 Commits

Author SHA1 Message Date
Levi Neuwirth 6b4d52a5bc
review round 1: the crdt suite Stage 3 missed, and two stale explanations
P1 — compile_mode_crdt_acceptance was never revised. Its three
`compile.run` fixtures still omitted `display`, so the flip placed
output in the panel with `select = false`, the source buffer stayed
active, and `adopt_next_buffer` timed out waiting for a snapshot that
only arrives via the ACTIVE-BUFFER-FOLLOW path. Its subject is CRDT
convergence of a generated buffer, not placement, so it takes the
explicit opt-out — and the reason is recorded at `adopt_next_buffer`,
the helper that actually depends on it, rather than at each call site.

WHY MY OWN VERIFICATION MISSED IT, which matters more than the fix: the
Stage 3 census and every sweep I ran used `--features luajit` WITHOUT
`crdt`, so no crdt-gated suite was ever exercised. The census was
therefore blind to an entire configuration by construction, in exactly
the way #209 exists to prevent. The CI crdt job — added by that lane —
is what caught this, three days after it landed.

Baselined rather than assumed. A worktree at the branch base 21de0b2
sweeps 3715 passed / 0 failed under `luajit,crdt` with
PMACS_REQUIRE_GPU=1; the branch with this fix sweeps 3715 / 0. Identical.

An earlier branch sweep, taken before this fix, reported SEVENTY
failures across THIRTEEN suites. Twelve of those suites — m5_5,
gpu_invocation, gpu_initial_target, m10_11, vterm_stage3 and the rest —
are daemon, socket or GPU suites, and all of them recovered by fixing
three compile tests. The likeliest reading is that the failing
compile-crdt runs leaked daemon or PTY processes that poisoned every
subsequent socket-based suite; what is ESTABLISHED is narrower and
still useful: baseline green, branch green with the fix, and the
collateral confined to process-spawning suites. Count failures, not
causes — the same lesson this stage already learned once, at a
different layer.

Also of note: CI reported only 3 failures because `cargo test` halts
after a failing binary. The workflow does not pass `--no-fail-fast`, so
CI under-reports a multi-suite break exactly as my first census did.

P2 — builtin/runtime/compile.lua's recompile comment still said `_last`
stores only cmdline/cwd. This PR deliberately stores `display` too, so
an explicit opt-out survives replay. Corrected, with the
`display_omitted` arm's remaining purpose stated rather than implied.

P2 — the framing's §7 step 2 still called the resolver extraction
"provably behaviour-preserving", contradicting §1.6b's own record of the
intentional non-string normalization. It is DEFAULT-PRESERVING WITH ONE
INTENTIONAL NORMALIZATION, and now says so where a reader following the
branch plan will hit it.

Verified: fmt, diff-check, compile_mode_crdt 3/3, compile_mode 73/73,
and the full crdt sweep at 3715/0 against a measured baseline of 3715/0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 12:08:28 +02:00
Levi Neuwirth 6793edcfc7 fix(compile): PR #113 round 4 — column-counted CR rewrites, alt-screen style resync
Finding-by-finding (framing revision 10; bites via scripts/bite
against b5bbce8):

1. CR rewrites are COLUMN-counted and newline-segmented, not
   byte-counted. Each newline-free segment of a text event consumes
   one existing codepoint per incoming codepoint (codepoints
   approximate columns; double-width and combining characters count
   as one — the documented stance), and LF is not an overwrite
   column: a newline arriving mid-line drops the cursor to a fresh
   line and the stale remainder survives in place (terminal
   semantics). Pre-fix, abcdef\rX\n wrote "X\n" over "ab" — splitting
   the line and leaving "cdef" as a ghost line the parser saw again
   at EOF — and abc\ré ate two ASCII columns because é is two bytes.
   Round-3's UTF-8 invariant holds per-segment: every edit's range
   ends sit on codepoint boundaries, so the rope is valid after each
   step and byte-native CRDT edits never reject. Bites: single-batch
   (shorter rewrite, multibyte-over-ASCII, CRLF), split-feed with the
   é split across batches, and a CRDT twin covering the segmented
   multi-edit replication.
2. Alternate-screen exits resynchronize the effective style. The
   parser now tracks the style the consumer LAST RECEIVED
   (emitted_style; outside alt-screen it always equals
   current_style). An ordinary ?1049l exit emits the resync SetStyle
   whenever suppressed SGR changes drifted the two apart, and
   finish() balances against emitted_style rather than
   current_style — a suppressed SGR reset inside the alt screen left
   the internal style default, so the old comparison saw nothing to
   balance while the consumer stayed red. Consumer-mirror units for
   both drift directions plus the no-drift no-event case; Lua twin
   (r4f2) bites via the ansi.rs swap.

Gates: fmt; clippy workspace all-targets; lib 1528; crdt lib 1702;
compile acceptance 56; crdt acceptance 3; m4 101; m6.4 15; m6.8 8;
GPU 59; workspace sweep 2510/0; git diff --check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoiEyuPjoBhvwACf8HAnLB
2026-07-13 17:55:08 +01:00
Levi Neuwirth b76c46603a fix(compile): PR #113 round 3 — UTF-8-safe renderer, observable parser reset, raw spec reads
Finding-by-finding (framing revision 9; bites via scripts/bite):

1. The CR/backspace renderer is UTF-8-safe: overwrite ranges consume
   WHOLE existing codepoints (range end aligned forward past
   continuation bytes) in ONE atomic replace of the complete text
   event — never a split of either side — and backspace steps to the
   previous codepoint boundary; out_pos stays on boundaries by
   induction. Pre-fix, byte-counted splits left malformed bytes on
   the plain rope, and under CRDT the byte-native edit rejected the
   mid-codepoint range, aborting the pump after events_take had
   consumed the batch (terminal event lost, record leaked). Bites:
   default acceptance (é\rX, X\ré, é\bX with exact-content, marker,
   clean-*errors*, baseline asserts) and a CRDT twin that pre-fix
   times out never reaching its exit marker.
2. parser:finish()'s reset is observable: balancing events —
   AlternateScreenExit for an unclosed enter, a default SetStyle for
   a non-default running style (now also cleared; reset() preserved
   it) — let consumers unwind mirrored state from the event stream
   alone. New Rust unit applies events to consumer state; Lua twin
   (r3f2) bites via the ansi.rs swap.
3. stdin/group spec fields are RAW reads: spec tables are plain
   data, metatable-provided fields are deliberately not honored (the
   compile.lua rawget posture), and a raising __index can no longer
   be silently absorbed as group=false, quietly disabling
   process-group isolation. Regression test pins both shapes:
   metatable-provided group=true is ignored (pgid != pid), and a
   hostile raising metatable spawns cleanly.

Gates: fmt, clippy workspace all-targets, lib 1526, crdt lib 1700,
compile acceptance 53, crdt acceptance 2, m4 101, GPU 59, workspace
sweep 2505/0, git diff --check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoiEyuPjoBhvwACf8HAnLB
2026-07-13 17:17:02 +01:00
Levi Neuwirth a2b12dc9d6 docs+test: gate fixes and handoff snapshot (compile-mode in flight)
cargo fmt over the new files; doc-markdown backticks; is_ok_and in
the recompile counter wait; m4_6's M-g n/p pin updated to the Q#CM5
takeover contract (error.next/error.previous with the diag commands
as the dispatchers' fallback — the test's no-attachment status
behavior is unchanged). Handoff §1: main @ 0efb5cd, compile-mode
branch in flight at framing revision 6, themes named as the
standing runner-up.

Gate results on this machine (laptop, basedpyright live): fmt,
clippy --workspace --all-targets, lib 1522, crdt lib 1696,
compile_mode_acceptance 34, compile_mode_crdt_acceptance 1,
m4_acceptance 101 (no skip), PMACS_REQUIRE_GPU gpu 59, workspace
sweep 2482/0, git diff --check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoiEyuPjoBhvwACf8HAnLB
2026-07-13 15:23:20 +01:00
Levi Neuwirth 53854ed803 test(compile): acceptance suites — framing items 1-33 dispatch-driven, 35 two-replica
tests/compile_mode_acceptance.rs (34 tests): spawn shape + header +
exit markers; read-only under dispatch; child-boundary stderr merge
in emission order; stdin EOF; group kill/leader-exit/escalation/
ledger bites incl. the redirected TERM-ignoring survivor and the
pipe-holding-descendant tick-latency bound; starter-rule parsing
with 0-based normalization and severity posture; sub-1 fail-closed;
severity override + malformed-rule containers; unterminated final
line; RET/n-p/M-g n/M-g p/C-x ` navigation pins with the diag
fallback; recompile + q-target discipline; supersede baseline; all
seven undo/redo chords table-driven; M-x undo after a completed run
recovering via buffer.after-edit; no-hook shrink and same-length
newline-moving replace with anchor epochs; ANSI SGR/CR with
rendered-cell attachment proof surviving RET-then-M-,; killed-buffer
teardown; grep locations panel, kill-mid-search + masking
prevention, root retention; shell-command M-!; round-trip pins.

tests/compile_mode_crdt_acceptance.rs: a chord-triggered full run
converges byte-identically on two replicas (mid-session generated-
buffer snapshot adoption), and a synthetic accepted replica edit
triggers the immediate recovery marker, converging across the
causal-reorder seam.

Fixes found by the suite: compile.lua's CR handling now scans the
current line start from the buffer (the REPL discipline) instead of
using the per-batch parse position — a same-batch CR previously let
a progress line overwrite earlier output; malformed Lua patterns
are rejected (and counted) at validation time via a probe match.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VoiEyuPjoBhvwACf8HAnLB
2026-07-13 15:11:43 +01:00