docs: record dired Stage 1 (#165) as landed
#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
This commit is contained in:
parent
c8ec8f3718
commit
ea0632412e
21
COHERENCE.md
21
COHERENCE.md
|
|
@ -120,7 +120,7 @@ asymmetry**, and **per-arc coherence debt**.
|
|||
|
||||
Coherence-shaped work already in flight at audit time: find-file /
|
||||
dired Stage 0 (`C-x C-f`, merged #162, `docs/dired-framing.md`) and its
|
||||
Stage 1 directory view (PR #165), bottom panel Stage 1 (merged #155),
|
||||
Stage 1 directory view (merged #165), bottom panel Stage 1 (merged #155),
|
||||
multi-root LSP affinity (merged #161), the config registry foundation
|
||||
(merged #127).
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ working, unreachable capability:
|
|||
time; a complete 1,384-line dired existed only as a frozen test
|
||||
fixture (`tests/fixtures/pmacs-dired/init.lua`). **Fixed:** dired
|
||||
Stage 0 opens a path (`C-x C-f`, merged #162) and Stage 1 ships the
|
||||
browsing view as a builtin (`C-x d` / `C-x C-j`, PR #165). The fixture
|
||||
browsing view as a builtin (`C-x d` / `C-x C-j`, merged #165). The fixture
|
||||
stays frozen — its `install_local` + `require` routing *is* the M8
|
||||
package-universality proof (Q#DR1) — and shrinking it is scheduled
|
||||
after Stage 3.
|
||||
|
|
@ -363,11 +363,11 @@ Full verdict table:
|
|||
|---|---|---|---|
|
||||
| 1 | Install | **Partial** | Source build only: `cargo build --release --workspace --features pmacs/crdt` (`README.md`). No binaries, no packaging. Runtime deps (`/bin/sh`, git, tar, coreutils) documented, never checked at runtime |
|
||||
| 2 | Launch unconfigured | **Works** | `EditorState::new()` → empty `*scratch*`; missing config is not an error (`src/config.rs:7-9`); recentf/saveplace/autosave default-on |
|
||||
| 3 | Open real project | **Missing at the CLI** | `pmacs .` still exits 1 (above): `load_file` does `File::open` (which succeeds on a directory) then `read_to_end` → EISDIR, which is not `NotFound`, so `resolve_target_buffer`'s create-a-`[new file]` arm never fires. Dired Stage 1 (PR #165) supplies the buffer a directory should resolve *to*; routing `pmacs .` into it is Journey Stage 1's work, which must not invent a second directory surface |
|
||||
| 3 | Open real project | **Missing at the CLI** | `pmacs .` still exits 1 (above): `load_file` does `File::open` (which succeeds on a directory) then `read_to_end` → EISDIR, which is not `NotFound`, so `resolve_target_buffer`'s create-a-`[new file]` arm never fires. Dired Stage 1 (merged #165) supplies the buffer a directory should resolve *to*; routing `pmacs .` into it is Journey Stage 1's work, which must not invent a second directory surface |
|
||||
| 4 | Understand interface | **Partial** | Mode line gives name/modified/L:C/scroll + mode/LSP/terminal segments; but no welcome text (`EditorCore::new` sets `status: String::new()`), no cheat sheet, and `C-h` deletes a word (§18) |
|
||||
| 5 | Edit | **Works** | Full CUA + Emacs keymap in 161 lines (`builtin/keymaps/default.lua`); isearch, query-replace, kill ring, undo/redo, auto-indent/pair/comment, atomic save. Genuinely excellent zero-config |
|
||||
| 6 | Language intelligence | **Partial** | Rust grammar bundled and auto-attaches; rust-analyzer preconfigured (`builtin/runtime/lsp.lua:44-52`) — but a missing binary fails silently (§1.2) and highlighting masks it. No LSP status command exists to diagnose |
|
||||
| 7 | Find symbol / file | **File: fixed (open by path merged #162; browsing PR #165). Symbol: works but undiscoverable** | No find-file/dired/picker existed at audit. Now `C-x C-f` opens a known path and `C-x d` / `C-x C-j` browse (flat listing, `dired` mode keymap); `M-.`/`M-?`/`C-c o` still bound but advertised nowhere and server-gated; no workspace-symbol command; `pmacs.index.*` has no UI |
|
||||
| 7 | Find symbol / file | **File: fixed (open by path merged #162; browsing #165). Symbol: works but undiscoverable** | No find-file/dired/picker existed at audit. Now `C-x C-f` opens a known path and `C-x d` / `C-x C-j` browse (flat listing, `dired` mode keymap); `M-.`/`M-?`/`C-c o` still bound but advertised nowhere and server-gated; no workspace-symbol command; `pmacs.index.*` has no UI |
|
||||
| 8 | Open terminal | **Works but undiscoverable** | Full PTY with scrollback + modeline segment — reachable only as `M-x terminal`, no keybinding. *Was broken outright on the GPU frontend until the double terminal-layout sync was fixed: the child took a `SIGWINCH` storm at tick cadence, so typing into it was impossible while output still flowed.* |
|
||||
| 9 | Build / test | **Partial** | `M-x compile.run` works, defaults cwd to detected project root, parses Rust `-->` errors — but no keybinding, an **empty first prompt** (`initial = last and last.cmdline or ""`, `builtin/runtime/compile.lua:1134-1138`), and no `cargo build`/`cargo test` suggestion despite `ProjectKind::Cargo` existing (`src/project.rs:77`) |
|
||||
| 10 | Inspect error | **Partial (good once reached)** | `E:n W:n` modeline counts, underlines, `M-g n/p` + ``C-x ` `` walking a unified compile/grep/diag source, message echo, `RET` visits. Gated entirely on step 6 or 9 succeeding first |
|
||||
|
|
@ -460,7 +460,7 @@ level is the one missing. Audited level-by-level:
|
|||
**Beginner** (should see: files, buffers, search, diagnostics, terminal,
|
||||
build actions, menus, missing-tool guidance):
|
||||
|
||||
- files ✓ since #162 / PR #165 (`C-x C-f` opens a path, `C-x d` browses;
|
||||
- files ✓ since #162 / #165 (`C-x C-f` opens a path, `C-x d` browses;
|
||||
neither is advertised anywhere but the keymap) · buffers ✓ (`C-x
|
||||
b`, `*buffer-list*`) · search ✓ (`C-s`/`C-r`/`C-M-s`; project.search
|
||||
is M-x-only) · diagnostics ✓ once a server runs · terminal ✓ but
|
||||
|
|
@ -1183,7 +1183,7 @@ Primitive-by-primitive against the list above:
|
|||
hierarchy, package dependency graph, worker trees, git status) will
|
||||
each need it; building it once *before* dired's directory view and
|
||||
the workers tree harden their own conventions is exactly this
|
||||
section's point. Dired Stage 1 (PR #165) landed **without** inventing
|
||||
section's point. Dired Stage 1 (merged #165) landed **without** inventing
|
||||
one: its listing is flat (Emacs parity), and the recursive
|
||||
in-buffer case — `i` insert-subdirectory — is a named deferral in
|
||||
`docs/dired-framing.md` §13, which is where a shared tree primitive
|
||||
|
|
@ -1340,7 +1340,8 @@ greets a new user says nothing (`EditorCore::new` sets an empty
|
|||
status).
|
||||
|
||||
Note the dependency: five of the ten onboarding steps above currently
|
||||
lead somewhere broken or invisible (find a file — in flight; inspect a
|
||||
lead somewhere broken or invisible (find a file — the mechanism is fixed
|
||||
since #162/#165 but is advertised nowhere except the keymap; inspect a
|
||||
diagnostic — silent-failure risk; view workers — undiscoverable;
|
||||
setting provenance — unanswerable). Onboarding is correctly sequenced
|
||||
*after* the P1/P4 fixes, but the cheap floor — a welcome buffer in
|
||||
|
|
@ -1404,7 +1405,7 @@ Establish the end-to-end workflow; treat regressions as release
|
|||
blockers. **State: broken at step 3 (§2). Mostly wiring, and unusually
|
||||
cheap:** directory-argument handling (the remaining half of step 3 —
|
||||
dired Stage 1 landed the buffer it should resolve to); a find-file
|
||||
surface (**done**: #162 open-by-path, PR #165 browsing); surfacing the
|
||||
surface (**done**: #162 open-by-path, #165 browsing); surfacing the
|
||||
LSP spawn failure with guidance (§1.2); a
|
||||
compile keybinding + `cargo build`/`test` default from the existing
|
||||
`ProjectKind::Cargo`; a terminal keybinding; a welcome buffer. The
|
||||
|
|
@ -1474,7 +1475,9 @@ implementation — this list is direction, not commitment):
|
|||
|
||||
1. **Journey Stage 1** (P1): directory open + compile defaults +
|
||||
LSP-failure surfacing + bindings + welcome buffer + the first
|
||||
journey acceptance suite. Rides alongside the in-flight dired arc.
|
||||
journey acceptance suite. Dired Stage 1 has landed (#165), so the
|
||||
buffer a directory resolves *to* already exists; this arc routes
|
||||
`pmacs .` into it rather than growing a second directory surface.
|
||||
2. **Discovery surface** (P4): the describe/list/where-is command
|
||||
family, M-x rich rows, help unification, help prefix.
|
||||
3. **Transient keymap layer** (§6): the overlay scope + lifetime
|
||||
|
|
|
|||
|
|
@ -5,6 +5,14 @@ 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.
|
||||
|
||||
**Two lane headers below are stale on purpose**, pending the docs updates
|
||||
their own lanes owe: multi-root LSP affinity **#161 has merged** (the
|
||||
Lean 4 lane still says IN REVIEW; its continuation is PR #167) and GPU
|
||||
terminal input **#166 has merged** (its lane still says IN REVIEW; PR
|
||||
#168 records it). Trust the canonical-base line below over a lane header:
|
||||
if a PR number appears in `git log --first-parent githubsucks/main`, it
|
||||
has landed regardless of what its lane says.
|
||||
|
||||
## Repository authority
|
||||
|
||||
- Canonical development URL:
|
||||
|
|
@ -14,11 +22,14 @@ backlog.
|
|||
machine-local: `origin` may 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` @ `8c86d34` (the dired framing #164 atop find-file
|
||||
#162, COHERENCE.md #163, Lean 4 Stage 1 #160, the minimap blank-slab fix
|
||||
#159, bottom-panel Stage 1 #155, the inline-math re-scout #154, the vterm
|
||||
PTY-flake fix #153, and the GPU initial-target doc refresh #152; protocol
|
||||
v20).
|
||||
`githubsucks/main` @ `c8ec8f3` (dired Stage 1 #165 atop GPU terminal
|
||||
input #166, multi-root LSP affinity #161, the dired framing #164,
|
||||
find-file #162, COHERENCE.md #163, Lean 4 Stage 1 #160, the minimap
|
||||
blank-slab fix #159, bottom-panel Stage 1 #155, the inline-math re-scout
|
||||
#154, the vterm PTY-flake fix #153, and the GPU initial-target doc
|
||||
refresh #152; protocol v20). **Lanes below that name an older base have
|
||||
not been re-based; derive their integration surface from
|
||||
`git diff <their base>..main`.**
|
||||
- On the transfer source, `origin/main` named a release mirror at
|
||||
`d3fa632` and lagged badly. On the current destination, `origin` names
|
||||
the canonical URL. This difference is why all recovery begins by
|
||||
|
|
@ -189,154 +200,6 @@ If it does not, stop and repair the remote/fetch configuration.
|
|||
suites**; `git diff --check` clean. The sweep needs an isolated
|
||||
`XDG_CONFIG_HOME` and `-- --skip basedpyright`.
|
||||
|
||||
## Dired lane — Stage 0 MERGED; Stage 1 IN REVIEW (PR #165)
|
||||
|
||||
- Approved framing: `docs/dired-framing.md` **revision 6** — rev 5 is the
|
||||
approved text (merged as its own docs PR #164), rev 6 adds §0's Stage 1
|
||||
implementation notes (S1-1…S1-9). Stages 2 (marks and operations) and 3
|
||||
(wdired) each get their own detailed framing after the prior stage lands.
|
||||
- **Stage 0 (`C-x C-f` find-file) MERGED as #162** (`main` @ `2af1ab3`,
|
||||
2026-07-25, one review round, 12/12 CI green). Durable facts moved to
|
||||
`docs/agent-handoff.md` §1 per rule 3 below.
|
||||
- **Stage 1 branch: `githubsucks/dired-stage1`**, worktree
|
||||
`../pmacs-dired-stage1`, based on `githubsucks/main` @ `8c86d34` (the
|
||||
framing merge #164). **A fresh cut, not a rebase:** the older `dired`
|
||||
branch (`ffdd642`, worktree `../pmacs-dired-arc`) was based on the
|
||||
superseded `0827dd1` and carried only the framing content #164 already
|
||||
put on `main`, so merging it would have reconciled two histories of one
|
||||
document. It is left untouched and carries nothing unmerged.
|
||||
- **Stage 1 implemented; no wire change (protocol stays v20).** What
|
||||
landed on the branch:
|
||||
- `builtin/runtime/dired.lua`: one buffer per directory named
|
||||
`*dired:<canonical path>*` with the handle-table ownership check;
|
||||
read-only intercept + `set_round_trip_input`; the `dired` major mode
|
||||
and its mode-scoped keymap (`RET`/`f`, `^`, `n`/`p`, `g`, `q`, `s`);
|
||||
basename cursor re-seating across every wholesale repaint;
|
||||
`display_file` for file visits and same-window reuse for directory
|
||||
descent; `C-x d` / `C-x C-j`; the `dired.kill-when-opening` setting.
|
||||
Loaded after `window.lua`.
|
||||
- `src/fs.rs`: `ReadDirTolerance`, `FsDirEntryError`, `FsDirListing`,
|
||||
and one walk that either fails on a per-entry condition or records it
|
||||
(Q#DR6). `src/async_runtime.rs` carries the listing in
|
||||
`ReplyKind::ReadDir` / `JobResult::ReadDir`; `src/lua_bindings/mod.rs`
|
||||
keys the Lua result **shape** on `errors.is_some()`, so the bare array
|
||||
the frozen M8.2 fixture consumes with `ipairs` is untouched;
|
||||
`builtin/runtime/fs.lua` validates read-op opts and **rejects unknown
|
||||
keys** (a typo'd `tolerant` used to degrade silently to fatal).
|
||||
- `src/editor_core.rs` + `src/lua_bindings/mod.rs`:
|
||||
`normalize_buffer_path` is `pub` and exposed as
|
||||
`pmacs.path.canonicalize` — Q#DR2's preferred end state, so no Lua
|
||||
mirror exists and Stage 2 owes no mirror removal. This makes B2
|
||||
("tolerant `read_dir` is the only Rust change") false by one small
|
||||
binding, deliberately.
|
||||
- `tests/dired_acceptance.rs`: 22 tests over framing items 1–16,
|
||||
dispatch-driven; item 17 is the m8_1/m8_2/m8_3 additivity gate.
|
||||
- **The framing claim the substrate falsified (S1-2):** R2-3 expected a
|
||||
dedicated dired panel to carry its dedication across a descent.
|
||||
`display_buffer` never replaces the buffer in a slot dedicated to
|
||||
another one — it discards every side-specific parameter and falls back
|
||||
to the document window (Q#BP3 2.iii), and the exact-window arm errors.
|
||||
Dired does not unpin the user's panel; both arms are pinned.
|
||||
- **The vacuity the bites found (S1-3):** acceptance 3c cannot pin the
|
||||
descent *routing*. Dired holds focus in its own panel, so a raw
|
||||
`switch_buffer` lands in the same window and every 3c assertion holds
|
||||
either way. Dedication is the only discriminator, so the
|
||||
dedicated-panel test is the real pin — and the vacuity is documented at
|
||||
the assertion rather than relabelled.
|
||||
- **The pre-existing test dired's first mode-scoped binding broke
|
||||
(S1-4):** `describe_key_identifies_every_default_binding` asserted every
|
||||
binding in the stack resolves through `describe.key` context-free, which
|
||||
held only while the modes table was empty. It now sets the effective
|
||||
context per binding and explicitly *clears* the mode for global ones,
|
||||
because a leaked mode legitimately shadows a global chord of the same
|
||||
name (dired's `RET` shadows `edit.newline-and-indent`).
|
||||
- Durable substrate facts, independent of this arc:
|
||||
- `pmacs.buffer.kill` (not `remove`) redirects windows off a doomed
|
||||
buffer before removal, so `kill-when-opening` kills **after** the
|
||||
replacement is displayed.
|
||||
- Interactive origin does **not** survive an await: work resumed in
|
||||
`tick_async` sees no `InteractiveCommandOrigin`, so `pmacs.window.*`
|
||||
acts for the *ambient* active frontend (S1-9).
|
||||
- Kinds are lstat-based in both `read_dir` and `stat`, so nothing in an
|
||||
entry says whether a symlink points at a directory; `RET` probes by
|
||||
trying to list it (S1-8).
|
||||
- A path-backed buffer's *name* is its full path, not its basename —
|
||||
worth knowing before writing any name assertion.
|
||||
- `C-x d` takes **no** completion source on purpose (S1-5): with one,
|
||||
RET on an empty field opens whatever sorts first, and
|
||||
RET-on-where-you-are is the gesture the binding exists for. The field
|
||||
is prefilled instead.
|
||||
- **Bite verification:** 15 claims, each mutated in place and required to
|
||||
fail the test that names it. `dired.lua` is new, so `scripts/bite`'s
|
||||
file swap does not apply; every mutation was applied and reverted with
|
||||
`git checkout --`. One came back VACUOUS and is recorded above.
|
||||
- **Review round 1 addressed** (framing rev 7, S1-10…S1-12). Three
|
||||
behavioral fixes, each bite-verified: `dired.revert`'s re-seat is
|
||||
guarded on the active buffer (an ambient `move_to_line` after an await
|
||||
moved an unrelated buffer's cursor — the buffer-level instance of
|
||||
S1-9); `fmt_size` keeps the column width past ten digits, because
|
||||
`_layout` is a contract Stage 3 is planned against; and the symlink
|
||||
descent dropped its probe, since `open_directory`'s
|
||||
changed-nothing-on-failure invariant *is* the probe (it was listing the
|
||||
target directory twice). Plus a consecutive-`readdir`-error cap, because
|
||||
**nothing cancels a dired listing** — it carries no supersede key, so
|
||||
cancellation was never the backstop the tolerant loop implicitly relied
|
||||
on. Naming/comment findings taken as-is.
|
||||
- Durable process lesson, hit twice now: a mutation-bite helper restores
|
||||
with `git checkout --`, which reverts to **HEAD** — so a fix must be
|
||||
committed *before* it is bitten. Round 1's fixes were briefly wiped by
|
||||
exactly that.
|
||||
- **Canonical main integrated twice** — at `46a1b8f` (multi-root LSP
|
||||
affinity #161) and again at `b889873` (GPU terminal input #166), both
|
||||
merged rather than rebased per the #135/#137 precedent so the review
|
||||
anchors stay addressable. Each conflict was a single doc hunk resolved
|
||||
as the union: this lane owns COHERENCE's journey step 7 file half, #161
|
||||
owns the in-flight list, #166 owns step 8's GPU-terminal addendum.
|
||||
Three things worth carrying:
|
||||
- **A conflicting PR silently stops running CI.** GitHub builds
|
||||
`pull_request` runs against the merge ref, which does not exist while
|
||||
the PR conflicts, so no run is created and nothing reports a
|
||||
failure — the checks list simply stays as it was. Three pushes to
|
||||
this branch produced no CI at all before the cause was found. Watch
|
||||
`mergeable` on a long-lived lane, not just the check list.
|
||||
- #161's own COHERENCE finding **falsified a claim in this lane's
|
||||
module doc**: `pmacs.error` is never defined in production, so an
|
||||
uncaught raise inside a `pmacs.async` coroutine does not reach
|
||||
`*errors*` as the comment said. It reaches a bare `error()` inside
|
||||
`pmacs._async.tick()`, whose result `tick_async` discards with
|
||||
`let _ =` — i.e. nowhere. That makes dired's per-coroutine `pcall` +
|
||||
`set_status` load-bearing rather than tidy, and the comment now says
|
||||
so.
|
||||
- **A lane in review against a fast-moving `main` needs its gates rerun
|
||||
per integration, not per push.** Main advanced twice inside this
|
||||
review round, and the second time landed while the first
|
||||
integration's sweep was still running. The numbers below describe the
|
||||
twice-merged tree.
|
||||
- Verification on the twice-merged tree (`main` @ `b889873`):
|
||||
`cargo fmt --check` clean; strict workspace Clippy clean; **1,832
|
||||
default + 2,009 CRDT** library tests; dired acceptance **25 default +
|
||||
25 CRDT**; m8_1 10 / m8_2 15 / m8_3 32 unchanged; multi-root 13 and
|
||||
vterm Stage 3 5 (both suites main added, green under this lane's
|
||||
`mod.rs` and `editor.rs` changes); M4 121; required GPU 155;
|
||||
**isolated-`XDG_CONFIG_HOME` workspace sweep 3,205 passed across 93
|
||||
suites, zero failures**; `git diff --check` clean. The sweep needs the
|
||||
isolated config for the reason recorded in the bottom-panel lane
|
||||
below.
|
||||
- Coherence (framing §0.5, required since #163): serves `COHERENCE.md` §20
|
||||
Priority 1, which names this work explicitly; journey step 7's file half
|
||||
goes from no surface to a surface; **adds no interaction island** — keys
|
||||
are a mode-scoped keymap, and wdired will be a mode swap; adopts
|
||||
`pmacs.config` for `dired.kill-when-opening`; inherits §9's
|
||||
worker-attribution gap for its `read_dir` jobs without worsening it. The
|
||||
audited claims this changes are updated in `COHERENCE.md` itself, per its
|
||||
§25.
|
||||
- **Boundary with the Journey Stage 1 arc** (`COHERENCE.md` §20 arc-cut
|
||||
1): CLI directory-argument handling (`pmacs .` exits 1) belongs there,
|
||||
not here — Stage 1 does **not** fix it. The two meet at
|
||||
`resolve_target_buffer`; dired supplies the buffer a directory should
|
||||
resolve *to*, and `pmacs .` should route into it rather than growing a
|
||||
second directory surface.
|
||||
|
||||
## GPU terminal input lane — IN REVIEW
|
||||
|
||||
- Portable branch: `githubsucks/gpu-terminal-input`, worktree
|
||||
|
|
@ -593,6 +456,38 @@ git worktree add --track \
|
|||
|
||||
## Closed since the last snapshot
|
||||
|
||||
- **Dired Stage 1 (the directory view) — MERGED as #165** (`main` @
|
||||
`c8ec8f3`, 2026-07-25, after one review round). pmacs has a directory
|
||||
surface: `C-x d` / `C-x C-j`, one read-only buffer per directory named
|
||||
`*dired:<canonical path>*`, a `dired` major mode carrying
|
||||
`RET`/`f`, `^`, `n`/`p`, `g`, `q`, `s`. No wire change (v20). The Rust is
|
||||
two things — a per-entry-tolerant `read_dir` (Q#DR6), which had to be
|
||||
Rust because `read_dir_blocking` fails a whole listing on any of five
|
||||
per-entry conditions and a tolerant wrapper cannot be written in Lua at
|
||||
all, and `normalize_buffer_path` going `pub` as
|
||||
`pmacs.path.canonicalize` (Q#DR2's preferred end state, so no Lua mirror
|
||||
exists and Stage 2 owes no mirror removal). The frozen m8_1/m8_2/m8_3
|
||||
counts are unchanged, which is the additivity gate. 15 claims
|
||||
bite-verified; one came back VACUOUS (acceptance 3c cannot pin descent
|
||||
routing — dired holds focus in its own panel, so dedication is the only
|
||||
discriminator) and is documented at the assertion rather than
|
||||
relabelled. Its branch (`dired-stage1`) and worktree
|
||||
(`../pmacs-dired-stage1`) are done; the abandoned `dired` branch
|
||||
(`ffdd642`, `../pmacs-dired-arc`) was superseded by a fresh cut and
|
||||
carries nothing unmerged. **Stage 2 (marks and operations) and Stage 3
|
||||
(wdired) each still need their own framing**, and the frozen fixture
|
||||
shrinks after Stage 3. Durable substrate facts and both new ops lessons
|
||||
live in `docs/agent-handoff.md` §§1/5; the implementation notes are
|
||||
`docs/dired-framing.md` §0, S1-1…S1-12. Two named forward items for
|
||||
Stage 2: `apply_resource_op`'s rename rebind is exact-PathBuf-equality,
|
||||
first-match-only, looked up with the raw path while stored paths are
|
||||
normalized — so a directory rename strands every buffer under it, and
|
||||
`pmacs.fs.rename` has zero production callers, so it can be fixed at
|
||||
the primitive; and Q#DR5's seam is the main-thread drain
|
||||
`AsyncRuntime::tick`, not `_take_result`, where rename settles as an
|
||||
undifferentiated `ReplyKind::FsUnit` and so must be keyed on
|
||||
`JobKind::FsRename`.
|
||||
|
||||
- **GPU initial target — MERGED as #148** (`main` @ `0dd16a5`, 2026-07-24,
|
||||
after two review rounds). `pmacs --gpu [--socket …] FILE` opens a target
|
||||
before the GPU window appears. Protocol bumped 19 → 20: a semantic-session
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
# Agent handoff — cross-machine continuity
|
||||
|
||||
**Last updated: 2026-07-25, after find-file (#162) landed — the dired
|
||||
arc's Stage 0 — following COHERENCE.md (#163), Lean 4 Stage 1 (#160), the
|
||||
**Last updated: 2026-07-25, after dired Stage 1 (#165) landed — the
|
||||
directory view — following GPU terminal input (#166), multi-root LSP
|
||||
affinity (#161), the dired framing (#164), find-file (#162) — the dired
|
||||
arc's Stage 0 — COHERENCE.md (#163), Lean 4 Stage 1 (#160), the
|
||||
minimap blank-slab fix (#159), bottom-panel Stage 1 (#155), the
|
||||
inline-math re-scout (#154), the vterm PTY-flake fix (#153), and the
|
||||
GPU initial-target doc refresh (#152); and before that GPU
|
||||
|
|
@ -26,11 +28,13 @@ commands, read `docs/active-work.md` immediately after this file.
|
|||
|
||||
## 1. Where the project stands (2026-07-25)
|
||||
|
||||
- `main` @ `2af1ab3` (find-file #162 atop COHERENCE.md #163, Lean 4 Stage 1
|
||||
#160, minimap blank-slab #159, bottom-panel Stage 1 #155, inline-math
|
||||
re-scout #154, vterm PTY-flake #153, and doc refresh #152). Protocol
|
||||
unchanged at **v20**. The bullets below describe the arcs in their own
|
||||
terms; this line is the head-of-`main` anchor.
|
||||
- `main` @ `c8ec8f3` (dired Stage 1 #165 atop GPU terminal input #166,
|
||||
multi-root LSP affinity #161, the dired framing #164, find-file #162,
|
||||
COHERENCE.md #163, Lean 4 Stage 1 #160, minimap blank-slab #159,
|
||||
bottom-panel Stage 1 #155, inline-math re-scout #154, vterm PTY-flake
|
||||
#153, and doc refresh #152). Protocol unchanged at **v20**. The bullets
|
||||
below describe the arcs in their own terms; this line is the
|
||||
head-of-`main` anchor.
|
||||
- **`COHERENCE.md` is now required reading and a required framing input
|
||||
— #163.** It carries the product-coherence thesis, an audited
|
||||
scorecard, per-concern gaps, and §20's priority order, and it is the
|
||||
|
|
@ -70,11 +74,78 @@ commands, read `docs/active-work.md` immediately after this file.
|
|||
against an open buffer yet fails to load one that is not open —
|
||||
find-file expands the tilde Lua-side. Loading through the normalized
|
||||
path is a named deferral.
|
||||
- **Stage 1 (the directory view) is IN REVIEW as PR #165** — the
|
||||
builtin `dired.lua`, the per-entry-tolerant `read_dir` opt, and
|
||||
`pmacs.path.canonicalize`. Its branch state, substrate facts, and
|
||||
verification live in `docs/active-work.md`; this section absorbs them
|
||||
when it merges.
|
||||
- **dired Stage 1 — the directory view — LANDED — #165**
|
||||
(`docs/dired-framing.md` §0, S1-1…S1-12; merge `c8ec8f3`; one review
|
||||
round). pmacs now has a directory surface: `C-x d` / `C-x C-j` open a
|
||||
read-only listing, one buffer per directory named
|
||||
`*dired:<canonical path>*`, with a `dired` major mode whose
|
||||
mode-scoped keymap carries `RET`/`f`, `^`, `n`/`p`, `g`, `q`, `s`.
|
||||
Protocol unchanged at **v20**. **Stage 2 (marks and operations) and
|
||||
Stage 3 (wdired) each still need their own framing**; the frozen
|
||||
fixture shrinks after Stage 3.
|
||||
- **The Rust is confined to two things**: a per-entry-tolerant
|
||||
`read_dir` (`ReadDirTolerance {Fatal, PerEntry}` →
|
||||
`FsDirListing {entries, errors}`), because `read_dir_blocking` fails
|
||||
a whole 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** (one error value, no partial vec); and
|
||||
`editor_core::normalize_buffer_path` becoming `pub`, exposed as
|
||||
`pmacs.path.canonicalize`. Only non-UTF-8 **names** stay fatal —
|
||||
byte-preserving paths would be needed. The Lua result **shape** keys
|
||||
on `errors.is_some()`, so the bare array the frozen M8.2 fixture
|
||||
consumes with `ipairs` is untouched.
|
||||
- **Exposing a core normalizer beat mirroring it in Lua.** A Lua mirror
|
||||
would have been a second canonical form — the same class of bug as
|
||||
the five tab-width constants (#137). Applies to any future Lua-side
|
||||
path reckoning.
|
||||
- **A fixed-width column must be fixed-width for every input.** The
|
||||
exported `pmacs.dired._layout` (MARK 0, KIND 2, PERMS 3–12, SIZE 13,
|
||||
MTIME 24, NAME 41) is the contract Stage 3 reads offsets from, and
|
||||
`%10d` overflows at ≥10 GB, silently shifting every column right of
|
||||
it. Sizes now fall back to a width-clamped magnitude (K/M/G/T/P/E).
|
||||
- **An ambient action must be gated on the buffer it assumes.** A
|
||||
revert's cursor re-seat settles a tick or more later, by which time
|
||||
the user may have switched buffers; the paint names its buffer and is
|
||||
safe, but seating is ambient. This is the buffer-level instance of
|
||||
the rule below that interactive origin does not survive an await.
|
||||
- **A failure IS an answer — don't probe first.** Kinds are lstat-based
|
||||
in both `read_dir` and `stat`, so nothing in an entry says whether a
|
||||
symlink points at a directory. `RET` tries to list it and treats the
|
||||
failure as the answer; an explicit probe was a second full
|
||||
`read_dir`, so a descent listed twice.
|
||||
- **Unbounded per-entry error collection needs a cap when nothing
|
||||
cancels the work.** A dired listing carries no supersede key, so
|
||||
cancellation was never the backstop the tolerant loop implicitly
|
||||
relied on (`READDIR_MAX_CONSECUTIVE_ENTRY_ERRORS = 1024`).
|
||||
- **This is the first builtin with mode-scoped keys** (#129's first
|
||||
non-detection consumer), which broke the pre-existing
|
||||
`describe_key_identifies_every_default_binding`: it asserted every
|
||||
binding resolves through `describe.key` context-free, which held only
|
||||
while the modes table was empty. It now sets the effective context
|
||||
per binding and explicitly **clears** the mode for global ones,
|
||||
because a leaked mode legitimately shadows a global chord of the same
|
||||
name (dired's `RET` shadows `edit.newline-and-indent`), plus a floor
|
||||
assertion that at least one mode-scoped binding exists.
|
||||
- **A dedicated panel does not carry its dedication across a descent**
|
||||
— the framing expected it to. `display_buffer` never replaces the
|
||||
buffer in a slot dedicated to another one; it discards every
|
||||
side-specific parameter and falls back to the document window (Q#BP3
|
||||
2.iii), and the exact-window arm errors. Dired does not unpin the
|
||||
user's panel; both arms are pinned.
|
||||
- Smaller facts worth knowing before touching this code: a path-backed
|
||||
buffer's **name is its full path**, not its basename, which matters
|
||||
for any name assertion; `pmacs.buffer.kill` (not `remove`) redirects
|
||||
windows off a doomed buffer first, so `dired.kill-when-opening` kills
|
||||
**after** the replacement is displayed; ownership is checked against
|
||||
the handle table only, never the buffer name; and `C-x d` takes **no**
|
||||
completion source on purpose (with one, `RET` on an empty field opens
|
||||
whatever sorts first, and RET-where-you-are is the gesture the binding
|
||||
exists for — the field is prefilled instead).
|
||||
- Verification at merge: 1,832 default + 2,009 CRDT library tests;
|
||||
dired acceptance 25 + 25 CRDT; the frozen m8_1 10 / m8_2 15 / m8_3 32
|
||||
unchanged, which is the additivity gate for the `read_dir` change; M4
|
||||
121; required GPU 155; isolated-`XDG_CONFIG_HOME` workspace sweep
|
||||
3,205 across 93 suites. 15 claims bite-verified.
|
||||
- **GPU initial target LANDED — #148**
|
||||
(`docs/gpu-initial-target-framing.md` rev 3; merge `0dd16a5`; two review
|
||||
rounds). `pmacs --gpu [--socket NAME|PATH] FILE` transports exact Unix path
|
||||
|
|
@ -760,6 +831,24 @@ final variant — its own round-trip cannot detect a discriminant shift.
|
|||
trap-guarded one-file swap over read-only `git show`, with an
|
||||
inverted verdict (exit 0 iff the tests FAIL against the old
|
||||
version), making bite-verification machine-checkable.
|
||||
- **A fix must be COMMITTED before it is bitten.** `scripts/bite`
|
||||
restores by `git checkout --`, which reverts the file to **HEAD**, not
|
||||
to the state it found — so any uncommitted work in a bitten file is
|
||||
destroyed. A whole review round's fixes were wiped this way during
|
||||
#165. Corollary for a NEW file: the swap-over-`git show` mode does not
|
||||
apply at all, so its claims must be bitten by hand-editing, which makes
|
||||
the commit-first rule load-bearing rather than hygienic.
|
||||
- **A CONFLICTING PR silently runs no CI at all.** GitHub builds
|
||||
`pull_request` workflow runs against the PR's **merge ref**, which it
|
||||
does not create while the branch conflicts with its base. So pushes
|
||||
land, the branch updates, no run is ever queued, and **nothing reports
|
||||
the absence** — the checks list simply keeps showing the last
|
||||
successful run, which reads as current. Three pushes to #165 produced
|
||||
zero CI before the cause was found, and `gh pr checks` returns nothing
|
||||
usable here. On any lane that lives through a moving `main`, check
|
||||
`gh pr view <N> --json mergeable,mergeStateStatus,headRefOid` and
|
||||
confirm a run exists **for the current head sha**, not merely that a
|
||||
recent run was green.
|
||||
- **Stacked PRs**: retarget the child to main BEFORE merging the
|
||||
parent — GitHub auto-closes a PR whose base branch is deleted and
|
||||
cannot reopen it (#104 → re-opened as #105).
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
# Dired — framing
|
||||
|
||||
**Revision 7 — 2026-07-25. Status: APPROVED; Stage 0 MERGED as #162;
|
||||
Stage 1 IN REVIEW as PR #165, review round 1 addressed.**
|
||||
Stage 1 MERGED as #165 (`main` @ `c8ec8f3`, one review round). Stage 2
|
||||
(marks and operations) and Stage 3 (wdired) each still need their own
|
||||
framing before implementation; the frozen fixture shrinks after Stage 3.**
|
||||
Rev 1 passed a ground-truth review; rev 2 fixed round 1's seven findings;
|
||||
rev 3 fixed round 2's six and was approved; rev 4 recorded what Stage 0's
|
||||
implementation falsified in the approved text (§0); rev 5 adds the
|
||||
|
|
|
|||
Loading…
Reference in New Issue