22 KiB
Active work — cross-machine resume ledger
Snapshot: 2026-07-24. 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.
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.