Both conflicts were competing rewrites of the same anchor lines: #172
refreshed the canonical base and the handoff header while this branch
did the same for #165. Resolved by taking main's list, which is the more
accurate of the two (it names Lean 4 Stage 2 #161 properly), refreshing
it to the current tip `ccf29e3`, and keeping this branch's note that
lanes naming an older base have not been re-based.
#172 also removed the inline-math lane, so the stale-header note drops
from three back to two and now says who owes the remaining updates.
Both conflicts were docs-only and resolved as unions, with one repair
taken from main: #156 fixed a pre-existing corrupted duplicate of the
"GPU initial target LANDED — #148" bullet in the handoff, whose tail ran
into the protocol-version text. This branch still carried the broken
copy, so the resolution keeps main's repaired `- Protocol **v20**` bullet
and drops the stub, along with main's now-superseded "Stage 1 IN REVIEW
as PR #165" sub-bullet.
Refreshed the canonical base to `d152120` and widened the stale-header
note from two lanes to three: #158 merged but its lane still reads
"PR #158 OPEN".
Brings the three required docs current after #158 merged, and discharges
the follow-up that framing named for itself.
COHERENCE.md section 16 audits the claim that the GPU frontend exceeds
the TUI "under real divergence pressure" without a privileged frontend
emerging. Inline math is the sharpest instance of that so far -- the GPU
typesets $...$ while the TUI shows LaTeX source, and the TUI fallback is
a named deferral. Section 25 makes that update ride the PR, so the
enumerated list gains the case along with what keeps it inside the rule:
the slice reserves no protocol version and adds no wire surface, so the
divergence is presentational and both frontends read the same model.
docs/inline-math-framing.md carried a licence error the slice framing
flagged in its own section 9 and deliberately did not fix in-branch,
since the parent is a merged document. Latin Modern Math is under the
GUST Font License, not the OFL; the row now says so and records the
~717 KiB bundled size.
docs/agent-handoff.md records the landing and re-anchors section 1 to
d152120. The bullet leads with the facts a fresh agent would otherwise
have to rediscover: the whole slice lives in pmacs-gpu because pmacs-gpu
depends only on pmacs-protocol and never on pmacs; the v0 subset is 34
Greek symbols, sub/superscript and \frac; an unsupported command fails
the WHOLE span back to source, so most inline spans in a real paper
still show LaTeX by design; and math is suppressed while the caret is
inside its span.
docs/active-work.md removes the merged lane per its own update protocol
and adds a Closed entry. Four things there are reusable beyond this arc:
a stale frontend binary is invisible from the source tree, so diagnose
with strings on the binary rather than by re-reading a checkout that is
already current; the dangerous integration was the one that did NOT
conflict, so decide from the shared-file set rather than from whether
git complained; integration is proved by predicting the other side's
test-count delta and checking it; and m4_5_basedpyright has no timeout,
hangs forever, and is intermittent, so an earlier clean sweep proves
nothing. It also corrects a claim I recorded on main: the branch's
missing CI was not an unidentified cause -- a conflicting PR builds no
merge ref, so no pull_request run is created.
Docs only; no code changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZjWMjwPXhPbt9upku9mCk
The inline-math slice landed while this PR was open. Its own merge
removed its ledger lane, so the stale-header note above still names
exactly two; only the base anchor needed moving.
`main` moved through #158-#166 (Lean 4 Stage 2, COHERENCE.md, find-file,
the dired framing and Stage 1, the GPU terminal input fix) while this
documentation branch waited. Both required docs conflicted; neither
conflict was a code signal.
Resolution:
- `docs/active-work.md`: main's ledger is the base — every lane it has
gained since this branch was cut is kept verbatim. Only the
bottom-panel lane is replaced with this branch's "Stage 1 MERGED;
Stage 2 (GPU band) is next" section, and only the bottom-panel entry
is added to "Closed since the last snapshot".
- `docs/agent-handoff.md`: main's version is the base. This branch's §1
bottom-panel bullet, its §1 roadmap Arc 7 entry (which also records
that DAP is now unblocked), and its four §5 ops lessons are inserted
at their anchors.
One repair rides along. Main's `docs/agent-handoff.md` carried a
garbled fragment at §1: a duplicated, truncated "GPU initial target
LANDED — #148" bullet whose body was the tail of the old head-of-`main`
anchor bullet, leaving the `SUPPORTED=[6..=20]` protocol enumeration
orphaned mid-sentence. The fragment is removed and the enumeration is
restored as its own bullet.
No code changes; the merged tree's non-doc content is main's.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#165's own commits could not update the handoff snapshot to name the
merge that contains them, so the protocol obligation lands here.
- `docs/agent-handoff.md`: absorb the dired lane into §1, replacing the
placeholder that promised exactly this. The bullet carries Stage 1's
durable substrate facts — why the tolerant `read_dir` had to be Rust,
why exposing the core normalizer beat mirroring it in Lua, the
fixed-width `_layout` contract Stage 3 reads offsets from, the
ambient-action buffer guard, treating a failure as the answer instead
of probing, the per-entry error cap, the first mode-scoped keymap and
the pre-existing test it broke, and the dedication a descent does not
carry. Refresh the head-of-`main` anchor and the last-updated line.
- `docs/agent-handoff.md` §5: two ops lessons that cost real time. A fix
must be committed before it is bitten, because `scripts/bite` restores
by `git checkout --` and reverts to HEAD; a CONFLICTING PR runs no CI
at all, because `pull_request` workflows build a merge ref GitHub does
not create while the branch conflicts, and nothing reports the absence.
- `docs/active-work.md`: remove the merged lane per update-protocol rule
4 and summarize it under "Closed since the last snapshot", keeping the
two forward items Stage 2 needs (the rename rebind is first-match-only
over a raw path, and Q#DR5's seam is the main-thread drain). Refresh
the canonical base. Flag the two lane headers that still call a merged
PR "IN REVIEW" — #161 and #166 — rather than editing lanes another
thread owns.
- `COHERENCE.md`: #165 is no longer a PR. Per §25 the audited claims this
work changed were updated when it landed; this corrects their tense in
seven places and the two prose lines that still asserted dired was in
flight.
- `docs/dired-framing.md`: status line to MERGED, and state plainly that
Stages 2 and 3 each still need their own framing.
Docs only; no code, no gate-relevant change.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126d2sikA6jZpFin3rtLCSK
Third merge of main into the lane, at b889873 (GPU terminal input #166).
Unlike the first two this one produced NO conflict -- and it is the case
that shows why a clean git merge-tree is not a reason to skip
integrating. #166 lands 41 lines in pmacs-gpu/src/main.rs, the same
heavily-rewritten file as the first integration; the two edits merged
silently only because they sit in different regions of it (#166 is
entirely in the headless probe, this lane rewrites the render path).
Merging the PR on that clean auto-merge would have shipped a combination
no gate had run.
Reconciliation, run against what #166 actually added rather than against
a pass/fail: it adds 3 library tests, 2 to vterm_stage3_acceptance, and
0 to pmacs-gpu. Predicted lib 1,826 -> 1,829, CRDT 2,003 -> 2,006, GPU
unchanged at 202; that is exactly what ran. Suite count 91 -> 92 is
#161's new lsp_multi_root_acceptance binary. All three sides' markers
verified live in the shared file.
Also records an ops trap that cost hours this session:
m4_5_basedpyright_initializes_and_negotiates_encoding does not time out,
it hangs forever, parking a --workspace sweep at 38 of 92 suites with a
live basedpyright langserver child. The per-suite M4 gate already skips
it; the workspace sweep needs the same flag.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZjWMjwPXhPbt9upku9mCk
Main advanced twice inside one review round (#161, then #166), the
second landing while the first integration's sweep was still running.
The ledger now names both integrations, how each doc conflict was
resolved, and the verification numbers for the twice-merged tree -- plus
the lesson that a lane in review against a fast-moving main reruns its
gates per integration, not per push.
Main moved again while this lane was gating: the GPU terminal-input fix
merged as #166. One conflict, in COHERENCE.md's journey table, resolved
as the union -- this lane owns step 7's file half, #166 owns step 8's
GPU-terminal addendum.
The module doc said an uncaught raise inside a `pmacs.async` coroutine
"goes to *errors*, not the status line". #161's COHERENCE finding shows
that is wrong, and in the worse direction: `pmacs.error` is never
defined in production, so `step()`'s guarded report is dead and the raise
falls through to a bare `error()` inside `pmacs._async.tick()` -- whose
result `EditorState::tick_async` discards with `let _ =`. The failure
reaches nowhere at all, and dired would look like it silently did
nothing.
So the per-coroutine `pcall` plus `pmacs.editor.set_status` is
load-bearing, not tidy, and the doc now says which channel is dead, which
is live, and that the acceptance suite observes the live one -- the
corollary COHERENCE draws from that finding.
The ledger records the integration, the reruns on the merged tree, and
the ops lesson that cost three CI runs: a conflicting PR has no merge
ref, so GitHub creates no `pull_request` run and nothing reports the
absence.
Multi-root LSP affinity merged as #161 (`main` @ `46a1b8f`) while this
lane was in review, which made the PR conflict -- and a conflicting PR
has no merge ref, so GitHub silently stopped running CI on it after the
first push. Integrating rather than rebasing, per the #135/#137
precedent: the review anchors stay addressable and every gate is rerun
against the merged tree.
One conflict, in COHERENCE.md's in-flight list, resolved as the union of
both truths -- and #161 is now merged, which its own text still called a
PR.
The overlap to watch is `src/lua_bindings/mod.rs`: #161 widened the
`lsp.list()` row builder while this lane added `pmacs.path` and the
read_dir listing conversion. The merge was textually clean, which the
folding arc's lesson says is not the same as compiling, so the full gate
suite reruns from here.
COHERENCE.md section 25 and the handoff/ledger update protocols make
these ride the PR.
COHERENCE.md:
- Section 6 named one optimistic key classifier and attributed it to the
GPU. There are two, one per replica frontend:
crate::optimistic::classify_key belongs to the pmacs --attach TUI
replica, and pmacs-gpu has its own unrelated optimistic_insert_text /
optimistic_crdt_insert. The section's "kept honest by
dispatch_idle_for" claim is confirmed for both, which this
investigation verified rather than assumed.
- Section 16 graded per-frontend degradation strong on the evidence of
per-frontend fold projection. That grade stands, but the practice is
enforced by convention rather than structure, and this defect is the
counter-example; the note says so and points at what is now structural.
- Section 2 step 8 records that the terminal was broken outright on the
GPU frontend, not merely undiscoverable.
docs/agent-handoff.md section 5 gains four lessons: adjacency does not
make two operations alternatives (and two individually sound idempotence
guards can be jointly useless); bite against every pre-image the fix
could have taken, since the obvious guard here fixes the storm and
introduces a controller leak; a quiet child is an instrument, because a
frame storm hides inside a chatty fixture and a geometric readout is
satisfied by an oscillating geometry; and TerminalMode::Raw makes
sh-based input fixtures useless because there is no ICRNL.
docs/active-work.md gains the lane entry with the branch, the bite
matrix, the named out-of-scope items, and the gate results.
Framing rev 7 adds S1-10..S1-12 -- the three findings that changed
behavior, each stated as the durable lesson rather than as a diff:
painting takes a buffer and seating takes the world, so any post-await
cursor operation needs an active-buffer guard; the rendered columns are
a contract Stage 3 is planned against, so precision yields to width; and
`open_directory`'s changed-nothing-on-failure invariant is itself a
probe, which is why the symlink descent no longer lists the target
twice. Plus the tolerant-channel note: cancellation was never a backstop
for a dired listing, because nothing cancels one.
The ledger records the round, the updated counts (dired 25 + 25 CRDT,
sweep 3,189 across 92), and the process lesson that cost me the fixes
once: a mutation-bite helper restores with `git checkout --`, so a fix
must be committed before it is bitten.
docs/dired-framing.md rev 6: §0 gains the Stage 1 implementation notes
(S1-1..S1-9) -- the normalizer is exposed rather than mirrored (so B2 is
false by one small binding, in the direction Q#DR2 preferred); R2-3's
dedication claim is falsified by the display policy; acceptance 3c
cannot pin the descent routing and now says so; dired is the first
builtin to bind a mode-scoped key, which one pre-existing lib test
assumed impossible; `C-x d` takes no completion source on purpose;
ownership is the handle table alone; the mark column ships blank; a
symlinked directory needs a probe; and interactive origin does not
survive an await.
COHERENCE.md, per its §25 (an audited claim this PR changes updates
here, riding the PR): §1.1's interactive-file-opening fact, §2's journey
step 7, §4's beginner-level `files`, §14's tree bullet (Stage 1 landed a
flat listing and did NOT invent a tree convention), and §15's Priority 1
list. Step 3 stays **Missing at the CLI** with the mechanism spelled
out: `pmacs .` still exits 1, and this arc deliberately does not claim
the CLI path -- it supplies the buffer a directory should resolve to.
docs/active-work.md: the dired lane rewritten for Stage 1, including why
the branch is a fresh cut rather than a rebase of `dired`, the durable
substrate facts, the bite results (one VACUOUS, recorded rather than
relabelled), and the verification. Its canonical-base line was four
merges stale and now names 8c86d34.
docs/agent-handoff.md: one forward pointer only. The handoff describes
merged state, so it absorbs the substance when this merges.
Lean 4 Stage 2 (#161) landed while this branch's first-ever CI run was
in flight, which put the PR back to CONFLICTING at an unmoved head.
Merged rather than rebased, same as the 8c86d34 integration and for the
same reason: the PR is awaiting review rounds and a rebase would break
every review anchor.
The sole conflict was docs/active-work.md, as it was last time and for
the same structural reason -- every merge to main edits the lane ledger,
so a long-lived PR re-conflicts there and only there. Both sides' lanes
kept verbatim; main's updated Lean 4 heading taken over the stale one.
This integration is code-disjoint from the lane. Intersecting main's
changed files (COHERENCE.md, builtin/runtime/lsp.lua,
src/lua_bindings/mod.rs, tests/lsp_multi_root_acceptance.rs) against the
lane's own changed-file set leaves exactly docs/active-work.md, so none
of the first integration's pmacs-gpu/src/main.rs auto-merge risk recurs
here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZjWMjwPXhPbt9upku9mCk
Separates the pre-integration numbers, which described a tree 28 commits
behind, from the ones that describe what the PR now proposes.
The GPU test count is the integration proof rather than merely a pass: it
went 199 to 202, and e547a90 added exactly three tests to pmacs-gpu,
which is the entire delta on main since the merge base. Both sides' tests
are therefore present and running, and neither was dropped by the
auto-merge. Confirmed structurally as well -- main's fix survives as the
deferred closure form rather than the eager one that panicked, with its
regression test, alongside this lane's math work in the same file.
The lane was 28 commits behind. Merged rather than rebased, per the
#135/#137 precedent: the PR is awaiting review rounds and a rebase would
break every review anchor.
The only conflict was docs/active-work.md, where both sides add lanes.
Kept both: main's lanes verbatim, with this lane leading since it is the
one in flight. The conflict was pre-existing rather than introduced by
the dired or Lean 4 ledger commits -- it already conflicted against main
at e745068.
The integration surface, derived from git diff merge-base..main rather
than from another PR's file list, is pmacs-gpu/src/main.rs: main gained
72 lines there from e547a90, 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, so
the full gate suite is what discharges it; the ledger records the
post-integration numbers separately from the pre-integration ones, which
described a tree 28 commits behind.
Lands the approved dired framing on main as its own docs PR, and brings
the two required docs current after find-file merged as #162.
The framing was approved after two review rounds (seven findings, then
six) and revised twice more since: revision 4 recorded what implementing
Stage 0 falsified in the approved text, and revision 5 adds the coherence
impact statement that #163 made mandatory for every framing.
The coherence statement is new work, not a restatement. COHERENCE.md
section 20 Priority 1 already names this arc -- a find-file surface and
directory-argument handling -- so the framing now states which journey
steps it touches (7, and partially 3), that it adds no interaction island
because its keys are a mode-scoped keymap through the ordinary registry
and wdired is a mode swap rather than a modal layer, that it adopts the
config registry for dired.kill-when-opening, and that it inherits the
worker-attribution gap for its read_dir jobs without worsening it. It
also draws the boundary against the adjacent Journey Stage 1 arc: CLI
directory handling belongs there, the two meet at resolve_target_buffer,
and dired supplies the buffer a directory should resolve to rather than
growing a second directory surface.
One convergence worth recording: section 2 grades the golden journey
broken at step 3 because pmacs on a directory exits 1, and the mechanism
it cites -- File::open succeeding on a directory, then read_to_end
returning EISDIR -- is the same one Stage 0 pinned in its
accepting-a-directory test, where the pcall turns it into a status
message instead.
The handoff snapshot was stale through eight merges. It now anchors on
main at 2af1ab3, records COHERENCE.md as required reading and a required
framing input, and carries the two minibuffer facts find-file
established: a custom completion source cannot descend directories, and
a selected candidate shadows typed text -- both of which apply to M-x and
switch-buffer, not just find-file.
The ledger gains the dired lane with Stage 1's scope, the reason its one
Rust change cannot be done in Lua, and the rebase note for the dired
branch, whose framing commits become redundant when this lands.
The blocker was process, not design. The test file was committed before
`cargo fmt` ran, so the reflow of five over-width assertions sat
uncommitted in the working tree while the branch as pushed failed the
first gate in CLAUDE.md. The "fmt clean" reported on the PR described
the worktree, not the branch. Gate results are only meaningful run
against the pushed tree, so this commit lands the formatting first and
the gates are re-run against it.
Two pins review asked for, each covering a branch the nine acceptance
tests left untested:
- A **string** `config.root` as an affinity key. acc17 covers only the
function form, so `return configured, "config"` had no test. The bite
puts both files in their own marked project: drop the config arm and
they key on their own detected roots and spawn two servers, so one
server on the configured root is only reachable if the override wins.
- `root = false` reads as unset. Defended by a truthiness check rather
than `~= nil`, previously by comment alone. Under `~= nil` the config
arm returns `false, "config"` and `file_uri_for(false)` returns nil, so
the file lands on a rootless server instead of its detected project.
Each was falsified against exactly the mutation it targets and neither
against the other.
Also documents an asymmetry review caught: `project_root_for`'s
"detected" arm is canonicalized for free because `pmacs.project.detect`
canonicalizes before walking, but a **configured** root — string or
resolver return — is fed to `file_uri_for` exactly as written, and the
affinity key is that URI. On macOS a resolver returning `/var/…` and a
detected `/private/var/…` are therefore different keys for one
directory, silently yielding two servers for one project. There is no
Lua-side canonicalizer to normalize it, and Stage 3's Lean resolver is
the first real consumer, so the obligation is stated in the
`config.root` doc comment where that resolver's author will read it.
Stage 1 merged as #160 (`main` @ `0827dd1`); the Lean lane header and
branch line now say so, and Stage 2 gets its own subsection.
Edits stay inside the Lean lane. PR #156 is still open against both this
file and `docs/agent-handoff.md`, and it rewrites the snapshot header,
the canonical-base line, and the whole bottom-panel lane — so those are
left alone rather than merged twice. `agent-handoff.md` is untouched for
the same reason plus its own: §1 describes what is on `main`, so it
updates at merge, not during review.
Records the one finding this stage turned up but did not fix:
`ensure_server` never forwards `cfg.restart` to `pmacs.lsp.spawn`, so a
`restart` in `pmacs.lsp.config[lang]` is silently dropped on the
auto-attach path. Pre-existing, and out of scope for a PR whose
acceptance 16 pins existing attach behavior as unchanged.
Review round 1 flagged that neither ledger knew about this branch, and
`docs/active-work.md`'s stated job is exactly the volatile open lanes.
Records the branch, base, framing revision, what Stage 1 ships, the
discharged Q#LN1 obligation, the Q#LN4 blast radius, and the four
implementation findings that are not in the framing (the `warning`
colour collision with `number`, `Some(1)` resolving to `@function`
rather than `@constructor`, the `module > declaration > def` nesting,
and `injection_aliases` being a write-only proxy). Also carries forward
the two Stage 2 corrections the framing already holds, since that lane
starts next.
Deliberately ADDITIVE ONLY -- one new section, zero deleted lines. PR
#156 is open against both this file and `docs/agent-handoff.md` and owns
the snapshot header, the canonical-base line, and the bottom-panel
lane's status. Touching those here would collide with a PR already in
review, which is the "frozen reviewed PRs do not absorb moving
overlapping work" lesson from #135/#137.
`docs/agent-handoff.md` is deliberately untouched: its §1 snapshot
describes what is ON `main`, so it gets updated when this merges, not
while it is in review.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The two halves that touch live rendering, landed together because the
acceptance criteria that make either honest need both.
Suppression (Q#MS3/MS4/MS5/MS11). Detection runs in the per-line chunk
builder — the chunk-build path, never the edit path — and substitutes
each suppressed span's source bytes with ONE spacer chunk BEFORE tab
expansion, so a literal tab inside a span vanishes with it while tabs
outside keep their SourceTab provenance. The gate reads the EFFECTIVE
caret (own_cursor, which optimistic edits predict forward — F4's
no-flap requirement holds by construction) plus both own-selection
endpoints. Three motion paths can flip a gate without a content
change, and each now re-runs the per-line chunk compare, gated on a
one-scan "does the visible slice hold a $" check: the CursorByte arm,
finish_optimistic_edit (the text re-chunks under the OLD caret there;
without the hook a typed char rendered one keystroke stale), and the
Decorations arm — whose "no decoration change needs a reshape" premise
acquires exactly one exception, the Selection endpoints Q#MS11 made
suppression inputs.
The line-reuse predicate (acceptance 11, the #120 edge). Per-line
math state is cached in lockstep with line_chunk_cache: every detected
span with the gate bit it was built under. The scroll-reuse path
refuses a retained line whose cached bits disagree with the CURRENT
caret/selection — content is unchanged on every reuse path, so the
cached span set is authoritative and the gate bits are the only
variable. The acceptance test drives the stale-gate case through
rebuild_lines_reusing_scroll directly and fails if the gate is removed
from the predicate.
The hit map (B1'). hit_test_source_byte rebuilds its runs from a
whole-slice chunk walk, so it now reads the substitutions BACK from
the per-line caches — never re-planned under a possibly-newer caret —
keeping the map and the shaped glyphs one source of truth.
The draw pass (Q#MS6/MS7). Every MathItem::Glyph draws from its own
mini-buffer with Attrs pinned to the bundled math family (F8b), placed
at layout's exact x and the shaped line's REAL baseline; the
mini-buffer itself is positioned by the line_y cosmic-text actually
produced for it, so no font-metric rederivation can drift. Fraction
rules ride the bg quad batch after the decoration washes and under the
glyphs. Wash geometry gains Q#MS11's intersection rule: a wash
touching a suppressed span widens to the box's whole reserved
rectangle (a match strictly inside the span produced a zero-width
interval before), while the round-3 exclusive-end fix keeps a
non-intersecting wash off the box.
Acceptance (framing §5). Criteria 5-11 and 14-16 run on real pixels
through render_to_view: drawn ink where a literal-spacer control
renders none, with the before-region pixel-identical; the fraction
rule as a full-width run with operand ink both sides; caret-inside
rendering EXACTLY as math-disabled (driven through the real
CursorByte arm, which owns the refresh — a direct helper call would
not have pinned the wiring); every failure mode (unbalanced, unknown
command, $$, uncoverable glyph) pixel-equal to disabled; box clicks
snapping to the span start with the trailing edge landing after the
span; the scroll-reuse stale-gate bite; reflow confined to the
affected line with the after-text shifted by exactly the quantized
projection difference; selection gating and the whole-rectangle wash;
and the licence provenance pair. Criterion 17 is discharged
differentially: cargo tree -e features output for ttf-parser is
byte-identical with and without this crate's dependency line.
Also folded in, per the round-3 close-out: the F6 documenting test
($a$$b$ is eaten by the $$-opaque rule; one separating character
restores both spans), the depth-search bound raised 6 -> 8 so a
metric shift cannot make the "floor is dead code" expect fire with a
misleading message, the MathBox { end, .. } pattern nit, and the
active-work.md lane entry.
Named v0 approximations, deliberate: 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 one-rectangle model); the fit budget reads the bundled
code face even under a custom set_font family — the draw anchors to
the real shaped baseline either way, so only the fit margin is
approximate.
Clippy is CLEAN across the workspace at -D warnings for the first
time on this branch: the draw pass consumed every formerly-dead item,
and the three lints it could not fix (a test-only accessor, one doc
string, one manual midpoint) are fixed here.
Gates: cargo fmt --check; cargo clippy --workspace --all-targets
-- -D warnings; 1,815 default + 1,992 CRDT library tests; M4 121
(basedpyright skipped); 199 pmacs-gpu tests under PMACS_REQUIRE_GPU=1;
workspace sweep 3,131 across 88 suites (isolated XDG_CONFIG_HOME);
git diff --check.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Handoff §1 gains the arc entry: the window-parameter substrate, the two
production `Layout::compute` callers, the recursive minima, hiding as a
durable transition, per-window input gating, the per-frontend jump
origins, and the shared initial-target load seam. §5 gains four durable
lessons, three of them the same class:
- a guard with no production caller passes every direct-call test;
- a geometric readout (`at_bottom`) is not a state predicate;
- a PTY does not translate LF to CRLF, so text equality over clipped
output is vacuous;
- widening an ambient resolver into a scoped one can make a total
function partial — which is what took CI red on all four Test jobs.
The roadmap position, the arc's named deferrals, and DAP's unblocking
are recorded too.
active-work closes the lane, refreshes the canonical base to `e745068`,
and keeps Stage 2's named obligations plus the two gating facts found on
the way (the sweep needs an isolated XDG_CONFIG_HOME; compile_mode
acceptance is load-sensitive, verified pre-existing).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PR #155 review round 2, self-review of the round-2 commit.
The round-2 change labelled "minor" — resolving both arms of
pmacs.window.buffer() through the acting frontend for uniformity — made
the NO-ARGUMENT arm fallible. `acting_frontend` follows the interactive
origin, which can name a frontend that has no registered view: a bare
`dispatch_key` from an unattached peer does exactly that. `selected_window`
then raises "acting frontend has no layout" instead of answering.
Nothing surfaced that error, because the runtime callers do not pcall it.
killring, syntax, autosave, pair, indent and comment all read
pmacs.window.buffer() on ordinary edits, so the raise silently dropped
the operation: kill_ring_acceptance went 30/30 to 25/5, with
frontend_detached_drops_per_frontend_state reporting only "B has kill
state". main is 30/30, and reverting this one file restored it.
The no-arg arm is back on ambient active_buffer_id() and now documents
why that is deliberate rather than an oversight: dispatch sets
active_frontend to the acting frontend before running a command, so the
two agree on every real path, while only the ambient resolver has the
fallback that makes it total. The explicit-window arm keeps its Q#BP11
layout validation, which is what the arc actually needed.
acc19c pins it through the real path — a buffer.after-edit subscriber
reading pmacs.window.buffer() during a viewless peer's dispatch_key —
rather than by calling the binding directly. Bite-verified:
scripts/bite bbe4152 src/lua_bindings/mod.rs --test
bottom_panel_stage1_acceptance -- acc19c goes red with the exact
"acting frontend has no layout" traceback.
The ledger also records two gating facts found on the way: the workspace
sweep must run with an isolated XDG_CONFIG_HOME, because the real user
init.lua installs a local package and the losing race leaks a status
message into painted-frame comparisons; and a latent pre-existing main
bug in the buffer CRDT undo path, which is not this branch's and whose
proptest seed is deliberately not committed here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012j4omtTMn9v1UfmHQb9ap6
`TerminalViewStatus.scroll_offset` is the retained rows between the
VIEWPORT and the live tail, so it necessarily tracks viewport height: an
assertion that it survives a panel height change unchanged is either
vacuous or wrong, and it went red once under a loaded sweep for exactly
that reason. Q#BP7's invariant is that the ANCHOR is frozen, so acc32
and acc33 now compare the first visible row's text across the change,
and additionally pin the follow behavior that distinguishes them: a
shrink never re-arms follow, growth reaching the tail does, and growth
with a frozen selection does not.
Both also wait for the child's last line before sampling, so neither
races further output.
Also records the round in docs/active-work.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds the lane to docs/active-work.md: branch, base, what Stage 1
implemented, the verification run, and the two known local-only test
caveats (the parallel-load GPU flake and compile_mode_acceptance's
single-thread requirement).
The durable handoff snapshot stays untouched until the PR merges, per
its own update protocol.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Move the lane from active-work.md into its Closed section, retire the
protocol v20 / main-hash references to LANDED form in agent-handoff.md, and
record both review-round lessons (failure-socket containment, upgrade-gated
replica publication) in the ops-lessons ledger.
Integrate folding Stage 2 and its landed-state documentation with the
protocol-v20 GPU initial-target branch. Preserve per-session fold projection
selection in the target bootstrap transaction and retain v19 compatibility
coverage after the later protocol bump.
Shut down bootstrap sockets on every dispatcher-side failure and reject
frontend events whose session state was never installed. This prevents a
lingering failed client from reaching absent render/size state.
Track target-side CRDT upgrades independently from load/create status so a
deduplicated hidden buffer is published to every existing grid replica. Add
real-daemon regressions for both failure containment and replica publication.
Post-merge housekeeping owed from #149, kept as its own docs-only PR per
the #138-#140 / #147 convention. No runtime code.
- active-work.md: base snapshot and the recovery check bump 47581f4 ->
6ed4fe9. The Stage 2 lane is retired and replaced by a folding lane that
records both stages as merged with nothing in flight, and states Stage 3
(GPU) has no branch and no framing yet — carrying its named obligations
(GPU collapse at TUI parity, caret/hit-test fold-awareness, the
BufferSnapshot fold-mirror clear, CRDT-origin unfold, and flipping
FrontendView.fold_projection true for semantic frontends) as that
framing's starting point. "Closed since the last snapshot" gains #149
and #147.
- agent-handoff.md §1: main @ 6ed4fe9, the "Last updated" line and section
date, the Stage 2 bullet flipped from IMPLEMENTED/PR-OPEN to LANDED with
the Stage 3 obligations attached, and the roadmap entry (remaining arcs
now read "6 folding Stage 3").
Both stages' design points are recorded as traps Stage 3 inherits rather
than as history: the merged-hidden-component unit, per-window/per-target
map instances, per-frontend projection, position-not-row normalization,
and the post-intercept edit site.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5BkezMppbpCgGAYk2ftxV
PR #149 review round 5 flagged this PR as stale: it still claimed `main`
@ `c49a8c7`, Stage 2 framing "rev 2, under review; no implementation, no
PR", while `main` is `47581f4` and Stage 2 is implemented and open.
- Base snapshot and the recovery check bump `c49a8c7` -> `47581f4`.
- The folding Stage 2 lane becomes IMPLEMENTED / PR #149 OPEN: framing
rev 4 approved, the `VisibleLineMap` spine, the base-moved merge (and
why it was merged rather than rebased), and the five review rounds'
design-changing findings — each of which is a trap Stage 3 inherits.
- `main`'s ledger had gone unrefreshed through four merges, not one, so
"Closed since the last snapshot" now also records web grammars HTML +
CSS (#146) and LaTeX Stage 1 (#144) with its inline-math framing
(#145), including their durable lessons.
- agent-handoff §1: `main` @ `47581f4`, the "Last updated" line, the
Stage 2 substrate bullet, and the roadmap entry.
Rebased onto `47581f4` so it stays one documentation-only commit
directly off canonical main.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5BkezMppbpCgGAYk2ftxV
Post-merge housekeeping owed from #142, kept as its own docs PR (no
runtime code).
- agent-handoff.md §1: bump main to c49a8c7, add the folding Stage 1
substrate bullet (store/View, structural source, C-c @ surface,
command-path unfold, FoldState production; no protocol bump), refresh
the "Last updated" line and the roadmap Arc 6 entry, and note Stage 2
is in framing on folding-tui (the visible-line-map reframe).
- active-work.md: retire the Stage 1 folding lane (PR #142 was OPEN),
add a "Closed since the last snapshot" entry for #142, open the
Stage 2 (grid/daemon collapse) framing lane on folding-tui, and
refresh the canonical base snapshot to c49a8c7.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5BkezMppbpCgGAYk2ftxV
Keep foreign BufferSnapshot publications out of existing semantic GPU
sessions while retaining grid-replica coherence. Treat dead peer writes as
peer-local failures, restore active-frontend cleanup, deterministic probe
readiness, GPU logging, shared tilde expansion, and accurate docs.
Add focused publication and cleanup coverage and record the two-window
Wayland/Vulkan smoke plus the complete post-review gate results.
Update the framing, durable handoff, and active-work ledger after integrating
current canonical main and completing the required gates and real GPU smoke.
Add protocol-v20 semantic bootstrap and readiness result framing so
`pmacs --gpu FILE` opens the requested path before the GPU window becomes
ready. Keep target identity scoped to the authenticated frontend, preserve
legacy/no-target attach behavior, and publish fresh buffers coherently to
existing replicas.
Carry Unix path bytes and launcher cwd through the root broker, resolve paths
lexically in the daemon, reuse or create buffers without ambient-view state,
and preserve the managed daemon lifecycle from #141. Add focused parser,
wire, lifecycle, hook, isolation, and real-connector acceptance coverage.
Advance the active lane to Revision 2 and record closure of all four
non-structural framing findings. Keep implementation gated on explicit user
approval.
Advance the volatile ledger to the current canonical base and record the
portable Revision 1 framing checkpoint, scope, recovery command, and approval
boundary.
Round 2 correctly found the Finding-2/3 fixes were unpinned (reverting
them left the suite green). Both are now bite-verified:
- **Kill-path purge (Finding 2).** Replaced the direct
`forget_buffer(id)` unit test with
`killing_a_buffer_through_the_real_path_purges_its_fold_store`, which
drives `pmacs.buffer.remove` — the production route through
`after_buffer_removed` — and asserts the store is gone via the dead id
(BufferIds never recycle). Mirrors config_registry's real-kill-path
test. Bite-verified: reverting the `after_buffer_removed` fold branch
turns it red.
- **close-all point move (Finding 3).** Added
`close_all_command_moves_point_to_enclosing_head`, which invokes the
`fold.close-all` command with the point inside the second of two
top-level fns and asserts the cursor landed on that fn's head-line
content end (and both folds exist). Bite-verified: reverting close_all's
`maybe_move_point` loop turns it red.
- Ledger: `docs/active-work.md` folding lane now records PR #142 OPEN +
the two landed review rounds (was "opens once the gate suite is green").
Correction to the round-1 gate report: the acceptance suite is **21**
tests (round 1 was 20, not 24 — a tally slip), green under default and
`--features crdt`. Full gate suite otherwise green (fmt, clippy
--workspace --all-targets, git diff --check).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5BkezMppbpCgGAYk2ftxV