42 KiB
Active work — cross-machine resume ledger
Snapshot: 2026-07-25. This file records volatile work that has not
landed on main. Read it after docs/agent-handoff.md. Remove completed
entries when their PR merges; do not let this become a second permanent
backlog.
Repository authority
- Canonical development URL:
https://github.com/levineuwirth/pmacs.git. This ledger uses the normalized local aliasgithubsucksso its refs and recovery commands are identical on every machine. Remote names are otherwise machine-local:originmay name this canonical URL, a release mirror, or something else, and therefore has no authority by name alone. - Canonical base at this snapshot:
githubsucks/main@0dd16a5(GPU initial-target #148 atop folding Stage 2 landed-doc refresh #150, folding Stage 2 #149, the ledger refresh #147, web grammars HTML+CSS #146, and the LaTeX Stage 1 #144 / inline-math framing #145 pair; protocol v20). - On the transfer source,
origin/mainnamed a release mirror atd3fa632and lagged badly. On the current destination,originnames the canonical URL. This difference is why all recovery begins by verifying URLs and normalizinggithubsucksrather than trustingorigin/main. - The shared desktop checkout contained unrelated uncommitted work. The branches below were prepared in isolated worktrees; never clean or overwrite the shared checkout to recover them.
Start on another machine by inspecting its remotes:
git remote -v
git remote get-url githubsucks
If the second command says the alias is absent, add it; if it prints a different URL, stop and resolve that collision rather than overwriting an unknown remote:
git remote add githubsucks https://github.com/levineuwirth/pmacs.git
Then recover current refs:
git fetch githubsucks --prune
git log -1 --oneline githubsucks/main
git worktree list
git status --short --branch
The git log command must expose 0dd16a5 or a newer intentional main.
If it does not, stop and repair the remote/fetch configuration.
Inline-math slice lane — PR #158 OPEN, main integrated
- Portable branch:
githubsucks/inline-math-slice; worktree../pmacs-math-slice. PR #158, basemain. - Canonical
mainmerged into the lane twice on 2026-07-25, both times merged rather than rebased, per the #135/#137 precedent: the PR is awaiting review rounds and a rebase would break every review anchor.- First at
8c86d34(28 commits behind). The conflict was pre-existing, not introduced by the dired (#164) or Lean 4 ledger commits; it already conflicted againstmain@e745068. - Then at
46a1b8f, after Lean 4 Stage 2 (#161) landed while this branch's CI was still running. Same single conflict, same shape, same resolution.
- First at
- Both conflicts were this ledger and nothing else — both sides'
lanes kept verbatim each time. That is the standing cost of a
long-lived PR here: every merge to
mainedits this file, so a branch awaiting review re-conflicts on it and only on it. It is a docs collision, never a code one, and it says nothing about integration risk — do not read aCONFLICTINGbadge on this PR as a code signal without checking which filegit merge-treenames. - First integration's surface (derived from
git diff <merge-base>..main, not from another PR's file list):pmacs-gpu/src/main.rsgained 72 lines on main frome547a90— the minimap all-blank-slab divide-by-zero fix — and this lane rewrites large parts of the same file. Git auto-merged it textually; a clean auto-merge is not evidence the tree compiles (the folding-arc lesson), so the full gate suite below is what actually discharges it. - Second integration's surface is code-disjoint. #161 touched
COHERENCE.md,builtin/runtime/lsp.lua,src/lua_bindings/mod.rs, and a newtests/lsp_multi_root_acceptance.rs; intersecting that against this lane's own changed-file set leaves exactly one entry,docs/active-work.md. No source file is touched by both sides, so this one carries none of the first integration's semantic risk. - CI ran on this branch for the first time on 2026-07-25 and passed
all twelve (Format, both Lints, GPU Render headless, all four Test
matrix jobs, M1/M4/M5/M6 gates) at
8b457de— the first-integration tip. Before that there were zero workflow runs since the PR opened on 2026-07-24, while every other open PR had a full run; not a fork and not a trigger-config issue (the workflow fires on allpull_requestevents), cause never identified. So the green run validates the first integration, including thepmacs-gpu/src/main.rsauto-merge, on macOS and Linux both — the platforms local gating could not cover. The second integration is not yet CI-covered, but its surface is the ledger alone. - Framing:
docs/inline-math-slice-framing.mdrev 3, approved after two review rounds; parent arc framing merged as #154. - State: parser, font bundle (GUST licence), MATH-table layout with the
measured height budget, currency-guarded detection, and the
ChunkSource::MathBoxspacer substrate are implemented and round-3-reviewed (review fixes atcbf7782: the exclusive-endmapping bug its own test had pinned, script-marker whitespace, fallible layout viaUncoverableGlyph, real fraction gap-min constants — flagship scale 0.867, fallback depth 5). - Caret-driven suppression (the Q#MS5 gate over the effective caret and
Q#MS11 selection endpoints, chunk substitution before tab expansion,
the line-reuse predicate's third input, and the CursorByte /
optimistic-edit / Decorations refresh triggers), the draw pass
(per-glyph mini-buffers positioned by each shaped line's real
baseline, fraction-rule quads over the washes, the F8b family pin),
the Q#MS11 whole-rectangle wash widening, and the pixel acceptance
battery (criteria 5–11, 14–16; 17 discharged by the differential
cargo tree -e featurescheck — byte-identical with and without the dependency line) are implemented on the branch tip. - Clippy is CLEAN on the whole workspace at
-D warnings— the draw pass consumed every formerly-dead item. - Verification pre-integration (at
14c1c01, against the old base): 199pmacs-gputests underPMACS_REQUIRE_GPU=1; 1,815 default + 1,992 CRDT library tests; M4 121; full workspace sweep green (isolatedXDG_CONFIG_HOME). Superseded by the post-integration run below — those numbers describe a tree 28 commits behind. - Verification post-integration (the merge commit; this is the set
that describes what the PR now proposes):
cargo fmt --checkclean; strict workspace Clippy clean; 1,826 default + 2,003 CRDT library tests; 202pmacs-gputests underPMACS_REQUIRE_GPU=1; M4 121; isolated-XDG_CONFIG_HOME--no-fail-fastworkspace sweep 3,208 across 91 suites, zero failures;git diff --checkclean. - The GPU count is the integration proof, not just a pass. It went
199 → 202, and
e547a90added exactly 3 tests topmacs-gpu— the whole delta on main since the merge base. So both sides' tests are present and running; neither was dropped by the auto-merge. Spot-checked structurally too: main's fix survives as(count > 0).then(|| MinimapLineShape {(the deferred closure, not the eagerthen_some) with its regression test, alongside this lane's 37 math references in the same file. - Remaining: the user's review pass.
Named v0 approximations: the peer-caret half of acceptance 14 is
pinned at the mapping level (unit tests), not pixels; a soft-wrapped
spacer draws its box whole at the first run's origin; the fit budget
reads the bundled code face even under a custom
set_fontfamily (the draw anchors to the real shaped baseline either way).
Lean 4 lane (Arc 8) — Stage 1 MERGED; Stage 2 IN REVIEW (PR #161)
- Stage 1 merged as #160 (
main@0827dd1, 2026-07-25, one review round, all twelve checks green). Branchgithubsucks/lean4-stage1retained; it was worked in the shared checkout (no sibling worktree). - Approved framing:
docs/lean4-mode-framing.mdrevision 4, committed as the branch's first commit (a382965) after three review rounds. Seven stages, 19 decisions (Q#LN1–19), 64 acceptance criteria. North star: match or exceed VS Code's Lean support. - Stage 1 implemented; no wire change (protocol stays v20), no LSP, no
frontend change. Four commits: framing, grammar, theme captures,
editing surface + acceptance.
Cargo.toml+src/syntax.rs:arborium-lean2.18 and oneBUILTIN_LANGUAGESentry namedlean4(Q#LN2 — the name becomes thedidOpenlanguage_id), claiming.leanonly.src/highlight.rs: four capture entries —constructor,character,keyword.conditional,warning.builtin/runtime/{comment,pair,syntax}.lua:--comments, the⟨⟩ ⦃⦄ ⟮⟯pair set, thelean→lean4modeline alias.tests/lean4_stage1_acceptance.rsplus unit tests insyntax.rs/highlight.rs: 12 criteria, 17 tests.
- Q#LN1's open obligation is discharged.
tree-sitter-lean4is unusable (depends ontree-sitter ^0.25directly against our 0.26, exports noLANGUAGEconst despite its README, packages no queries);arborium-leanridestree-sitter-language 0.1with a pre-generated ABI-15 parser.cargo tree -dshows no duplicate core. The parse smoke pins the failure mode that matters:→/∀/≥must produce(arrow)/(forall)/(comparison), since a mismatched-core build degrades silently on exactly those characters rather than failing loudly. - Q#LN4 is a deliberate retro-paint of seven language entries, not
four:
tree_sitter_javascript::HIGHLIGHT_QUERYis concatenated base-first into javascriptreact/typescript/typescriptreact. Its shape is "every capitalized identifier" (#match? "^[A-Z]") plus every Lua table brace — not "constructors". Pinned in both directions per #146. - Implementation findings not in the framing:
warninghad to move from bold red to bold bright red:numberis plainfg(1), sosorryand an adjacent numeric literal were the same colour. Found by writing the test.Some(1)is not@constructor— in call position a narrower@functionpattern wins. Only bare or pattern-position capitalized identifiers reach it. Pinned so the blast-radius claim stays honest.- Lean node kinds nest:
module > declaration > def|theorem. pmacs.parse.injection_aliasesis a documented write-only Lua proxy (canonical map is Rust-side), so fence tests must drive_parse_nowand inspect layer languages, never read the table back.
- Review round 1 addressed. The finding: acc12's server-list assertion
could not fail for the regression it named — the shared
editor()helper wipespmacs.lsp.configbefore any buffer opens, so#pmacs.lsp.list() == 0holds for every language regardless of what Stage 1 ships. It now asserts against a pristineEditorStatethatpmacs.lsp.config.lean4is nil, with a non-vacuity check that the same lookup findsrust; bite-verified by adding alean4config tolsp.luaand watching it fail. Also fixed a stale column in ahighlight.rscomment. - Verification on this branch:
cargo fmt --checkclean; strict workspace Clippy clean; 1,826 default + 2,003 CRDT library tests; lean4 Stage 1 9/9; comment toggle 14; auto-pair 45; injection 4; M4 121; required GPU 152; isolated-config workspace sweep 3,150 across 90 suites;git diff --checkclean. The sweep needs an isolatedXDG_CONFIG_HOMEfor the reason recorded in the bottom-panel lane below.
Stage 2 — multi-root LSP server affinity (Q#LN15)
- Portable branch:
githubsucks/lsp-multi-root-affinity, shared checkout, based ongithubsucks/main@0827dd1. Named for the substrate, not for Lean: the diff contains no Lean content, becauseensure_serveris the one server-affinity function every LSP language shares and a cross-cutting change to it must not be reviewable only as a Lean feature. - Three files, no protocol change:
src/lua_bindings/mod.rs(thelsp.list()row builder gainsroot_uri+cwd),builtin/runtime/lsp.lua(project_root_forreturnsroot, source;ensure_serverhoists it above the reuse loop and matches on it),tests/lsp_multi_root_acceptance.rs(9 tests, acceptance 13–21). - The rule that keeps this from regressing every other language: the
affinity key is the root only when a root was actually FOUND.
project_root_fornever returns nil for a file with a path — its last resort is the file's own directory — so a naive(language_id, root)key gives every directory of loose scratch files its own server, for every language.sourceis"config" | "detected" | "fallback"and only the first two become a key. - Wire-identical for the fallback case, and that is provable rather
than hoped. Matching is on the spawned spec's
root_uri(nil matching nil), so the fallback spawn passesroot_uri = nil;cwdstill carries the directory andbuild_initializederives the identicalrootUrifromcwdwhen the field is None, using a percent-encoder with the same allowed set as Lua'sfile_uri_for.build_initialize(src/lsp.rs) is the only reader ofspec.root_uriin the tree. - Deliberate behavior change, asserted not discovered: a server
hand-spawned from
init.luawith onlycwdset also reads back nil, so a root-bearing attach will not adopt it. config[language].rootmay now be afunction(path) -> string|nil, memoized per directory — needed because the hoist puts root resolution on every attach rather than every spawn. The memo is keyed weakly by the resolver function itself, so replacingconfig[lang].rootcannot serve a root the previous resolver computed. This is Q#LN8's generalization landing early; the Lean resolver that uses it is Stage 3.- Bite-verified three ways: 5/9 fail against the pre-change
lsp.lua, 8/9 against the pre-changemod.rs, and — the one that matters most — installing the naive always-key-on-root variant fails acceptance 20 and 21 exactly as Q#LN15 part 2 predicts. The four that survive the first bite (13, 15, 16, 19) are the regression pins; passing on both sides is their job. - Every fixture sets
pmacs.project.set_search_boundaryat its own tempdir root. Without it the marker walk climbs to the filesystem root and a stray.gitabove the temp directory turns the markerless cases into detected ones — the assertions would still pass while testing nothing. - Found but not fixed here (pre-existing, own lane):
ensure_servernever forwardscfg.restarttopmacs.lsp.spawn, so arestart = "never"inpmacs.lsp.config[lang]is silently dropped on the auto-attach path. At least one existing test sets it believing it takes effect. Out of scope for a PR whose acceptance 16 pins existing attach behavior as unchanged. - Review round 1 addressed. The blocker was process, not design: the
test file was committed before
cargo fmtran, so the fix sat uncommitted in the working tree and the branch as pushed failed the first gate. The reported "fmt clean" described the worktree, not the branch — gate results are only meaningful when run against the pushed tree. Also added the two pins review asked for (a stringconfig .rootas an affinity key — acc17 only covered the function form; androot = falsereading as unset), each bite-verified against exactly the mutation it targets and neither against the other. And documented the canonicalization obligation: the"detected"arm is canonicalized for free, a configured root is not, so on macOS a resolver returning/var/…and a detected/private/var/…are different keys for one directory. Stage 3's Lean resolver is the first real consumer, so the obligation is written at the point of use. - Verification on this branch:
cargo fmt --checkclean; strict workspace Clippy clean; 1,826 default + 2,003 CRDT library tests; multi-root 11/11; M4 121; statusline 7; completion popup 9; auto-pair 45; required GPU 155; isolated-config workspace sweep 3,164 across 91 suites;git diff --checkclean. The sweep needs an isolatedXDG_CONFIG_HOMEand-- --skip basedpyright.
Dired lane — framing APPROVED; Stage 0 MERGED, Stage 1 next
- Approved framing:
docs/dired-framing.md(revision 5), landing as its own docs PR offgithubsucks/main@2af1ab3, branchgithubsucks/dired-framing, worktree../pmacs-dired-framing. The repo's-framing-branch convention (vterm-framing,gpu-initial-target-framing,tab-width-parity-framing). - Stage 0 (
C-x C-ffind-file) MERGED as #162 (main@2af1ab3, 2026-07-25, one review round, 12/12 CI green). Durable facts moved todocs/agent-handoff.md§1 per rule 3 below. - Stage 1 (the dired view) is next and unstarted. Branch
dired(worktree../pmacs-dired-arc) carries the framing commits only and is based on the now-superseded0827dd1; rebase it onto themainresulting from the framing PR before implementing, or cut a fresh branch — its framing commits become redundant once the docs PR lands. - Stage 1's scope, from the framing §10:
builtin/runtime/dired.lua; thediredmajor mode + mode keymap; buffer-per-directory with lexical canonicalization and the ownership check; read-only intercept +set_round_trip_input; visit routing throughwindow.display_file; parent/sort/revert/quit;C-x d(with thedisplayopt) /C-x C-j; cursor preservation by basename; thedired.kill-when-openingconfig key; and the tolerantread_diropt — the only Rust in the stage. - The one Rust change is load-bearing and is why Stage 1 is not
pure-Lua:
read_dir_blocking(src/fs.rs:201) fails the entire listing on any of five per-entry conditions, and the tolerant wrapper its own module doc delegates to package authors cannot be written in Lua — the primitive returns one error and no partial vec. - Coherence (framing §0.5, required since #163): serves
COHERENCE.md§20 Priority 1, which names this work explicitly; journey steps 7 and (partially) 3; adds no interaction island — keys are a mode-scoped keymap, and wdired is a mode swap; adoptspmacs.configfordired.kill-when-opening; inherits §9's worker-attribution gap for itsread_dirjobs without worsening it. - Boundary with the Journey Stage 1 arc (
COHERENCE.md§20 arc-cut 1): CLI directory-argument handling (pmacs .exits 1) belongs there, not here. The two meet atresolve_target_buffer; dired supplies the buffer a directory should resolve to, andpmacs .should route into it rather than growing a second directory surface.
GPU terminal input lane — IN REVIEW
-
Portable branch:
githubsucks/gpu-terminal-input, worktree../pmacs-gui-term-input, based ongithubsucks/main@46a1b8f. -
Approved framing:
docs/gpu-terminal-input-framing.mdrevision 2, committed as the branch's first commit (9a0df21). Bug fix, not a feature; no protocol change (stays v20). -
Reported as "text input within the terminal doesn't work on GUI, this is fine in TUI". Root cause: the dispatcher applied both terminal-layout syncs to every attached frontend, and a semantic session satisfies both conditions (a
term_sizesentry fromAttachRequestand a terminal declaration). Its PTY was resized twice per tick forever — grid arm installs the TUI placement size, semantic arm installs the declared content rectangle, each arm's idempotence guard seeing only what the other just wrote — so the child took aSIGWINCHstorm at tick cadence. -
The fix is a split, not a guard. The grid arm is also the only per-tick controller-liveness release a semantic frontend gets, and
sync_semantic_terminal_layoutcannot take that over: the buffer-follow snapshot clears the viewport declaration (on_buffer_snapshot_sent), so that arm stops running in exactly the switch-away case that needs the release.sync_terminal_layoutis therefore split into a frontend-kind-neutral half (panel reconcile + liveness) and a grid-only geometry half, with the loop body extracted tosync_terminal_layouts_for_tickso the exclusivity is structural and tests drive the real thing. -
Trap for anyone touching this again: the release at the "no
window_placementsentry" arm reads like liveness and is grid geometry. A semantic frontend has no placement entry at all, so moving it into the neutral half releases a GPU controller every tick. -
Bite-verified against two pre-images, because the naive guard fixes the storm and introduces the leak:
pin mainnaive guard the split settle (acc 2+3) FAIL pass pass controller release (acc 6) pass FAIL pass grid still resizes (acc 5) pass pass pass -
Real-path evidence: a quiet child trapping
SIGWINCHreports 144 frames in 4 s andWINCH 1..12on screen against the pre-fix tree, versus a settled screen with the fix. -
Deliberately out of scope, named: interactive-shell echo on a raw-mode PTY (Q#GT5 — reproduces in-process too, so it is not the GUI/TUI asymmetry), and a geometry change appearing to clear the visible screen (reproduces pre-fix; why acceptance 4 latches its observation across frames).
-
Verification on this branch:
cargo fmt --checkclean; strict workspace Clippy clean; 1,829 default + 2,006 CRDT library tests; vterm Stage 1/2/3 10 / 6 / 9 CRDT; bottom-panel Stage 1 46; M4 121; required GPU 155; isolated-config workspace sweep 3,177 across 92 suites, zero failures;git diff --checkclean. Gates were run against the committed tree.
Bottom-panel lane (window placement + side windows) — Stage 1 IN REVIEW
- Portable branch:
githubsucks/bottom-panel, worktree../pmacs-bottom-panel, based ongithubsucks/main@ddaa80d. - Approved framing:
docs/bottom-panel-framing.mdrevision 4, committed as the branch's first commit (c27f75a). - Stage 1 implemented; no wire change (protocol stays v20). What
landed on the branch:
src/window.rs:WindowParams(side/fixed_rows/dedicated- implementation-owned
quit_actionandorigin_document),Side, a depth-boundedQuitAction,MIN_WINDOW_OUTER_ROWS = 2,Layout::compute(area, fixed), thesubtree_min_rows/interactive_min_rowsrecursions,boundary_below, and the three newFrontendViewfields (panel_capable,frame_geometry,panel_hidden).
- implementation-owned
src/editor_core.rs:primary_document_window, the non-side target rule,display_buffer+ the Q#BP3 placement policy,quit_window,reconcile_panel_layout_core,resize_boundary, per-frontendJumpEntrys, and the sharedresolve_target_bufferseam that the #148 initial-target bootstrap now routes through as well.src/editor.rs: the reconciliation transaction, geometry declaration, the side-windowdispatch_idle_forgate, the divider paint, and the divider drag.src/lua_bindings/window_panel.rs: the wholepmacs.windowpanel surface plus the shared adopter-placement helpers;builtin/runtime/window.luaownswindow.panel-height/window.min-heightand the resize commands.- Adopters:
listview.open,compile.run,pmacs.terminal.openall takedisplay = "current" | "panel"(Stage 1 default"current"); LSP/compile visits route throughdisplay_file.
- Review round 1 addressed. The load-bearing finding: the Q#BP6
side-window split guard (
try_split_active) had no production caller —pmacs.window.split_horizontal/split_vertical, and soC-x 2/C-x 3, still went through plainsplit_active. Splitting a focused panel made the root wrapper's final child a split rather thanLeaf(side), which bothLayout::compute's fixed pass anddocument_subtreekey on. It survived the first round because the acceptance test called the core method directly; it now goes through the real Lua binding. This is the folding-arc round-2 lesson repeating exactly: after wiring a guard into a production hook, pin it through the real path — a direct-call test misses the wiring. Also fixed: the armed divider drag was not scoped to its arming frontend (it could cancel and swallow a peer's mouse events); a recompile carries nodisplayand duplicated a panel-placed*compilation*into the document window; andpaint_mode_line_graphemeshad lost its doc block to an insertion. Five bite-verified fixes (three viascripts/bite, two by manual revert since their tests sharesrc/daemon.rswith the production code). - Two Stage-2 hazard pins now exist in
src/daemon.rs, closing the gap the review named: a fresh attach whileLOCALis focused in a panel inheritsLOCAL's document buffer, and an initial-target bootstrap whoseafter-loadhook creates and selects a panel still reasserts into a document window. - Review round 2 addressed. The load-bearing finding: Q#BP7 item 1
— "growth reaching the live tail re-arms follow" — was never
implemented.
at_bottomis the instantaneous geometric readoutscroll_offset == 0, which a still-anchored view satisfies whenever it is momentarily tall enough to reach the tail, so the round-1 assertion could not see the gap: the next rows the child printed pushed the anchored view back into history.src/terminal/view.rsnow hasrearm_follow_on_growth, reached by one shareddeclare_view_sizehelper from every size-declaring path (snapshot_for_view,record_view_size,view_status_for_size) so grid and semantic declarations cannot disagree. Also fixed: the PTY fixtures emitted LF-only output, which staircases until every row clips to blanks — so the anchor assertions compared""with""and could not fail (now CRLF, each guarded byassert!(!top_before.is_empty())); acc33's contrast case asserted nothing;start_runletalready_in_paneloverride an explicitdisplay = "current", which is the documented opt-out from the Stage 3 flip (now gated on omission); andwindow_dragwas a daemon-global slot that a peer's mode-line press could clear. - Durable test lessons from this round, both the same class:
- A geometric readout is not a state predicate.
at_bottomsays "the viewport currently reaches the tail", not "this view follows the tail". Pinning follow requires feeding MORE output and asserting the view moved (acc32b uses a filesystem gate between two bursts). - A PTY in the default mode does not translate LF to CRLF. An
echo-driven fixture staircases rightward and clips to blanks past the viewport width, so any text equality over it is vacuously true. Emit\r\n, and guard text comparisons with a non-empty assertion the way the daemon pin guards on!panel_hidden.
- A geometric readout is not a state predicate.
- Round-2 self-review caught a regression the round-2 commit
introduced, in the change it labelled "minor": routing
pmacs.window.buffer()'s no-argument arm through the fid-scopedselected_windowvalidator made it fallible, andacting_frontendcan name a frontend with no registered view (a baredispatch_keyfrom an unattached peer does exactly that). The runtime calls that function on ordinary edits fromkillring,syntax,autosave,pair,indentandcommentwithoutpcall, so the raise never surfaced as an error — it silently dropped the operation.kill_ring_acceptancewent 30/30 → 25/5 (frontend_detached_drops_per_frontend_state: "B has kill state"). The no-arg arm is back on ambientactive_buffer_id()and documented as deliberately infallible; the explicit-window arm keeps its Q#BP11 validation. New acc19c pins it through the real path (abuffer.after-editsubscriber during a viewless peer'sdispatch_key) and bites against the regressing commit. Generalizes: a "uniformity" cleanup that changes a function's fallibility is not minor — check every caller's error discipline first, and remember that an ambient resolver's fallback IS its contract. - Verification on this branch:
cargo fmt --checkclean; strict workspace Clippy clean; 1,817 default + 1,994 CRDT library tests;bottom_panel_stage1_acceptance46/46; kill ring 30 default + 30 CRDT; vterm Stage 1 9 default + 10 CRDT; M4 121; required GPU 152; compile 67; vterm Stage 2 4 / Stage 3 5 (7 CRDT); folding Stage 2 48; statusline 7; listview 6; isolated-config workspace sweep 3,130 passed across 89 suites, zero failures;git diff --checkclean.- Run the sweep with an isolated
XDG_CONFIG_HOME. The real~/.config/pmacs/init.luaon this desktop callspmacs.packages.install_local(...), so every editor the sweep builds races on one shared install root; a losing race sets a status message that leaks into the mode line and breaksfolding_stage2_acceptance::unfolded_frame_is_identical_to_the_pre_folding_baseline, which compares whole painted frames. Standalone it is 48/48. This generalizes the knowncompile_mode_acceptancereal-config trap: any suite that paints the status area inherits it. - A latent pre-existing
mainbug surfaced while gating and is NOT this branch's:buffer::tests::proptests::rope_matches_crdt_projection_after_arbitrary_editsfails onmain@352bf0bwithops = [Insert(0,"a"), Insert(0,"aaa"), Replace(0,1,"a"), Undo]— undo of a textually-nullReplacereturns a no-op edit result still carryingcrdt_op = Some, violating the suite's own shape invariant.src/buffer.rsis byte-identical here, and the seed was deliberately not committed (it would make an unrelated failure deterministically red on this PR). Needs its own lane. - Durable test lesson from this round:
TerminalViewStatus.scroll_offsetis documented as the retained rows between this viewport and the live tail, so it necessarily tracks the viewport height. Asserting it constant across a panel height change is either vacuous or wrong — the invariant Q#BP7 actually states is that the anchor is frozen, which the acceptance now pins by comparing the first visible row's text, plusat_bottomfor the follow re-arm. compile_mode_acceptanceneeds--test-threads=1locally; it is 67/67 there. Under default parallelism it fails roughly 1 run in 3, with a different test each time (acc14/acc25a, then acc24) — verified pre-existing by swapping ingithubsucks/main'sbuiltin/runtime/compile.luaand reproducing the same rate. Thepmacs-gpubin tests have historically gone red under a loaded sweep (wgpu device contention). Rerun isolated before treating either as a regression.
- Run the sweep with an isolated
- Stage 2 (the GPU panel band, next available protocol version) has its own re-framing obligation before implementation; Stage 3 is the default placement flip.
Folding lane (Arc 6) — Stages 1 and 2 MERGED; Stage 3 (GPU) is next
Both shipped stages are on main; nothing in this arc is in flight. Stage 3
has no branch and no framing yet.
- Stage 1 (headless fold engine) merged as #142, Stage 2 (grid/daemon collapse) as #149 — both under "Closed since the last snapshot".
- Retained, carrying nothing unmerged: branches
folding/folding-tuiand worktrees../pmacs-folding/../pmacs-folding-tui. The framingsdocs/folding-framing.md(rev 5) anddocs/folding-stage2-framing.md(rev 4) are the approved artifacts Stage 3 re-scouts against. - Stage 3 (GPU) obligations, already named by the framings — the
starting point for its own framing doc: GPU collapse at TUI parity;
caret/hit-test fold-awareness; the
BufferSnapshotfold-mirror clear (parent R2-4 — without it, empty-after-revert diff suppression leaves stale folds on the GPU, the same trap class as #120); CRDT-origin and GPU-optimistic interactive unfold (parent R2-3); and flippingFrontendView.fold_projectiontotruefor semantic frontends, which Stage 2 deliberately leftfalse(Q#FD21).
Parked lane: kill-ring browser + persistence
- Portable branch:
githubsucks/kill-ring-browser - Parked framing head:
503c489 - State: framing only, revision 2; no implementation and no PR.
- Status: explicitly parked by the user on 2026-07-20.
- Its original scout was based on
0efb5cd. The preserved framing marks this ground truth stale and requires a complete re-scout against the then-currentgithubsucks/mainbefore implementation. - Compile-mode has merged since the original scout, so old “compile-mode in flight” keybinding/touch-set assumptions are not authoritative.
Recovery worktree, only when the user un-parks it:
git worktree add --track \
-b kill-ring-browser \
../pmacs-kill-ring-browser \
githubsucks/kill-ring-browser
Documentation lane
- Portable branch:
githubsucks/handoff-2026-07-20 - Carries synchronized
AGENTS.md/CLAUDE.md, this ledger, the durable handoff refresh, and the keybinding reference correction. - It changes no runtime code.
- Review and merge this documentation branch separately; it must not be folded into a feature framing branch.
- Now also absorbs both landed arcs: Vterm Stage 1 (#126) and the config
registry (#127). Canonical
mainis merged into it up to2e37c04, so its diff againstmainis documentation only.
Closed since the last snapshot
-
GPU initial target — MERGED as #148 (
main@0dd16a5, 2026-07-24, after two review rounds).pmacs --gpu [--socket …] FILEopens a target before the GPU window appears. Protocol bumped 19 → 20: a semantic-sessionSessionBootstrapRequestafterAttachRequest, plus an appendedInstanceMessage::InitialTargetResultpre-window readiness barrier; v6–v19 wire encodings are unchanged. Root owns launcher tilde/cwd resolution and exact raw-byte path transport; the daemon resolves/dedups/loads the target and runs load/switch hooks inside one dispatcher transaction, then publishes CRDT-upgraded targets to existing grid replicas (gated onupgraded_to_crdt, independent of the load/create outcome, so a dedup onto a hidden not-yet-backed buffer still reaches pre-attached replicas — round 2 finding). Semantic replicas receive a publication only when displaying that buffer, so a second target launch cannot switch an existing GPU window. Round 2 also closed a failure-containment gap: every dispatcher-side bootstrap failure now shuts down the socket (a dropped write-half clone does not close a shared FD), and the dispatcher drops any event from a session that was never installed, rather than reaching absent render/size state. Integrated cleanly with Folding Stage 2 (#149): fold projection at attach is selected from the same negotiatedsemantic_renderbit the target bootstrap uses. Its lane, worktree (../pmacs-gpu-initial-target), and branch (gpu-initial-target) are done; the-framingbranch is kept. Durable substrate facts and both review-round lessons live indocs/agent-handoff.md§§1/5 anddocs/gpu-initial-target-framing.mdrev 3. -
Folding Stage 2 (grid/daemon collapse) — MERGED as #149 (
main@6ed4fe9, 2026-07-24, after five review rounds). The grid TUI now renders collapses. Spine (Q#FD12):src/fold_view.rs'sVisibleLineMap, derived from the fold store plus a window's line offsets and never stored, threaded asOption<&'a VisibleLineMap>on a lifetime-bearingViewport<'a>that staysCopy. No wire schema or protocol change; the GPU path is Stage 3. 48 acceptance tests on the realpaint_framegrid, every behavioral claim bite-verified. Durable design points, each a trap Stage 3 inherits:- the map's unit is a merged hidden component (overlapping or adjacent intervals unioned, keeping the earliest visible head), not a fold — folds may cross, and a later fold's own head can be hidden;
- instances are per rendered window and per command/event operation, never per frame; a command's map follows the operation's target window, since a wheel event names a pane without activating it;
- fold projection is per-frontend (
FrontendView.fold_projection) — sharedEditorCoremotion would otherwise make a simultaneous unfolded GPU session's cursor skip lines it still displays; - a hidden cursor normalizes by position, not row, and
set_view_topclamps in the setter rather than being repaired at render time; - the interactive-Lua unfold keys on the post-intercept edit site — a managed buffer intercept may legally relocate the op.
Process notes worth keeping:
mainmoved under the arc, and the merge was textually clean but not semantically clean (#146 addedViewportliterals the newfoldsfield invalidated) — a cleangit merge-treedoes not mean the merged tree compiles. CI was red at review on the macOS/luajitoutline_5_level_100_entry_renders_within_100msbudget flake and went green on rerun. -
Documentation ledger refresh — MERGED as #147 (
main@0a479ae, 2026-07-24). The #142 housekeeping, expanded after review found the ledger stale through four merges rather than one. Its own macOS/luajit red was the vtermVTERM_ALT_READYPTY timeout; green on rerun. -
Web grammars HTML + CSS — MERGED as #146 (
main@47581f4, 2026-07-23)..html/.htm/.xhtmland.csshighlight off the officialtree-sitter-html0.23 /tree-sitter-css0.25 crate query constants (no in-repo overlay), and HTML'sINJECTIONS_QUERYlights up<script>→ js and<style>→ css. Durable lesson recorded indocs/web-grammars-html-css-framing.md: thehighlight.rscapture table is global, so adding a capture name retro-paints every other language — check the reverse direction and pin it. -
LaTeX Stage 1 — MERGED as #144, with its parent inline-math framing committed as #145 (
main@f09b0a1, 2026-07-23)..tex/.latex/.sty/.clshighlight viacodebook-tree-sitter-latex0.6 plus the first in-repo query overlay (builtin/queries/latex/highlights.scm,include_str!) — the reusable pattern for grammars whose crate ships no usable queries. The crates.iotree-sitter-latexis provably broken (noscanner.c). The math parser and Tiers 3–4 are deferred to the inline-math arc. -
Folding Stage 1 (headless fold engine) — MERGED as #142 (
main@c49a8c7, 2026-07-23, after three review rounds; round 3 clean). The instance-side fold store + translating/droppingView, the structural source (derived head line, closer-aware tail), the Lua data API + interactiveC-c @commands, the command-path pre-edit unfold, and authoritative-emptyFoldStateproduction landed with no protocol bump. Thefoldingbranch and worktree (../pmacs-folding) are retained but carry nothing unmerged; thefolding-framing.mdframing is preserved. CI red at merge was an unrelated environmental perf flake (outline_5_level_100_entry_renders_within_100ms, macOS/luajit only), green on rerun. Stage 2 has since merged as #149 (above); durable substrate seams live indocs/agent-handoff.md§1. -
Vterm Stage 3 (protocol v19 + GPU terminal) — MERGED as #135 (
main@cac4961, 2026-07-22, after two review rounds). Arc 5's terminal stage is complete (compile mode #113, Stage 1 #126, Stage 2 #130, Stage 3 #135). Its lane, worktree (../pmacs-vterm-gpu), and branch are done; durable substrate facts live indocs/agent-handoff.mdanddocs/vterm-framing.md. -
Branches deleted 2026-07-22 (authorized):
vterm-stage3-framing(Revision 8 framing; its content is carried onvterm-gpu, verified as a superset before deletion — the branch was NOT an ancestor ofvterm-gpubecause the framing was copied rather than merged, so it needed a forced local delete) andtab-width-parity(a clean ancestor ofmainvia #137). Both removed as worktree + local ref +githubsucksref; theorigintracking refs were pruned. The-framingbranches for each are deliberately kept. -
Tab-width rendering parity — MERGED as #137 (
main@2625ec7, 2026-07-22). One fixed 8-columnTAB_STOP_COLUMNSinpmacs-protocolnow drives core/TUI columns, GPU code projection, and minimap width; source bytes and protocol ranges are unchanged. Its lane, worktree, andtab-width-paritybranch (local +githubsucks) are deleted; thetab-width-parity-framingbranch is kept. This closes the long-standing "tab width is a rendering-parity bug, NOT a config gap" deferral recorded indocs/agent-handoff.md§5. -
Locals-query processing — MERGED as #134 (with handoff #136), and modeline detection handoff #133. Both landed between this lane's base and its canonical-main integration.
-
Config registry — MERGED as #127 (
main@2e37c04). Its lane (config-registry, worktree../pmacs-config-registry) is done; the branch is kept but carries nothing unmerged. Durable substrate facts moved todocs/agent-handoff.md§1 per rule 3 below. -
Both this and Vterm Stage 1 ran as concurrent lanes in sibling worktrees off
main, with the shared files (src/editor.rs,src/lua_bindings/mod.rs,src/lib.rs) assigned to one lane each in advance. The rebase of the second lane onto the first had zero conflicts — worth repeating for future parallel work, along with its precondition: agree the file split before either lane starts, and keep each lane's footprint in the other's files to a single line.
Update protocol
Whenever a listed lane changes materially:
- update its public branch and head/state here;
- record new verification and remove superseded caveats;
- keep durable architecture in
docs/agent-handoff.md, not here; - remove the lane after merge or abandonment;
- verify every recovery command from a clean worktree before calling the transfer complete.