summaryrefslogtreecommitdiff
path: root/test/fs.py
Commit message (Collapse)AuthorAge
* Forwarding pardes @pN for a pane the session has not is refused, "this ↵Gabriel Schneider5 days
| | | | | | | | | | | | session has no such pane", exit 1 and no pane made; one it has is looked at @p999:1 was taken as a new file's name, so a pane named <cwd>/@p999 was made and the launch succeeded; an @pN the session did have was the same stray pane. A pane address is now checked against the session: one it has is a look at it, one it has not is refused with the reason and exit 1, as a refused name is. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Forwarding to a running pardes says why in words: a name with a newline is ↵Gabriel Schneider5 days
| | | | | | | | | | | "a file name is one line", never NotOneLine The forwarding refusal printed the error's name for anything the session itself did not answer: NotOneLine, NotAFileName, NoWorkingDirectory. Those are now sentences, a dial failure is said as the message row says one, and any other error is its name's words. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* diff -u in a command pane names its files though the terminal turned the tab ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | before each timestamp into blanks A `---`/`+++` path was cut at the tab before diff -u's timestamp. Run in a command pane, the terminal had turned that tab into blanks, so the name took the timestamp with it and a look at a changed line opened nothing. The name is now also cut where blanks run up to a timestamp, either GNU diff's `2026-09-30 10:00:00...` or ctime's `Wed Sep 30 10:00:00 2026`. One blank is enough, since a tab can expand to a single blank, and the stamp is strict, so a name with blanks and no stamp after them stays whole. Tested on the parsed text and, in fs.py, on real `diff -u` output in a command pane, where a look at `+TWO` opens the new file. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Release Pardes 0.8Gabriel Schneider5 days
|\ | | | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]>
| * pardes --wait for a new name waits on the pane it made, by serial, and a ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | pane closed before it looks is done, not a failure fs.py's `pardes --wait 'wait new.txt'` failed two runs in three on the 0.0.8 merge. The stress case repeats the test's steps: 4 of 50 failed under load, each with "pardes: --wait: no pane shows that file". A new name's launch makes its pane, names it, then found it again by path in /index. The script had already seen the name, saved and removed the pane by then, so the lookup missed and --wait exited 1. Now the launch hands --wait the serial pane/new gave it. After a look, finding no pane on the file means that pane is already closed, which is the end --wait waits for: exit 0. The follow with its /index recheck covers a close in between, as before. Under the same load the stress case went 0 of 100. The same load showed a test race too, at fs.py's second Restore. The exec write is answered before the hang-up, but the client's clunk after it can meet the connection already cut. The test now requires the answer and tolerates the reset. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A path typed with a leading ~ is the home directory, at every entry point ↵Gabriel Schneider5 days
|/ | | | | | | | | | | | | | | | | | | | | | | | | | | | that takes one, through one helper Only DumpDir (dump.zig) and ShaderBuild expanded `~/`, each its own way. So a look at `~/notes.txt`, `name ~/x`, `Save ~/x`, ThemeFile, Restore and a quoted `pardes '~/x'` all took `~` as a directory of that name under the pane's. There is now one rule, filesystem.expandHome. A leading `~`, alone or before `/` or `:`, is $HOME, else the passwd entry's home; `~user` is that user's (getpwnam). As in a shell, it applies even beside a file named `~`, and `./~` names that file. Every entry point runs its typed path through it: - look, B3 and 9P, before any parsing, so `~/x:12`, `~/x:12:3` and `~/x:/re/` all work; - name, and a tag's rename; - Save <path>; - ThemeFile, DumpDir, Restore and ShaderBuild's shader files; - the forwarding launch. Recent rows are not shown with `~` and need nothing. How names are shown is unchanged. Tests: expandHome's cases, and HOME unset (passwd), with HOME passed in rather than set, since setenv moves the environ a spawned child reads. fs.py covers Save into missing directories under `~`, `name ~/x`, a look at `~/x:3`, and a forwarded `pardes '~/x'`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Save makes the directories its file goes in, always: for the pane's own name ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | and Save path alike Whether a Save made missing directories depended on how the name had come about. Config's pane did, a name written into a missing directory did (since kkrqxtsp), and `Save path` and every other name did not, failing ENOENT instead. There is now one rule: a Save makes the parent directories of the file it writes, a pane's own or a terminal's scrollback included, and the make_dirs flag is gone. A directory it cannot make still fails the write with why, as fs.py's /nonexistent-pardes-dir case shows. fs.py now also saves into missing directories by Save path and by a written name. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* winsize refuses fewer than 2 rows, saying so, and its range reads 1x2 to ↵Gabriel Schneider5 days
| | | | | | | | | | | | | 4096x4096 as the docs say `winsize 20 1` was taken and quietly raised to 2 rows, so the write succeeded with a size other than the one asked for. The range refusal also said "1x1 to 4096x4096", although fs.md says at least 2 rows. One row is now refused with "invalid winsize: at least 2 rows", and the range text starts at 1x2. size already refused anything under 20x6 with a text that names it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A tty editor killed with SIGTERM or SIGHUP puts its terminal back before it diesGabriel Schneider5 days
| | | | | | | | | | | | | | A nested pardes killed in a pane died with the default action. That left the pane's terminal on the alternate screen, in raw mode, with mouse and paste reporting on, so the shell under it was unusable until a reset. The tty frontend now handles both signals: it writes the resets a clean exit writes (keyboard protocol, mouse modes, focus, bracketed paste, SGR, cursor, main screen) and restores the cooked termios, all async-signal-safe. Then it dies of the same signal, since SA_RESETHAND put the default back. fs.py kills a tty session with each signal and checks for the main-screen switch and cooked mode; it fails without the handler. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pardes FILE in a pane whose session answers never falls back to a nested ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | | editor: the refusal is printed, exit 1, and no stray pane is left When the environment named a live session that answered, several failures broke out of forwarding and started a whole editor inside the pane that asked: a refused name, a pane the session has not, a failed look write. Its screen was drawn over the shell. Now, once the session answers (Client.probe), every refusal is printed as `pardes: <file>: <why>`, in the session's own words (the Rerror, now kept by the client), and the launch exits 1, as acme's B does. A new name the session refuses deletes the pane made for it, so no empty +New is left. A missing environment or a session that does not answer still starts a separate editor. fs.py checks a refused name and a stale PARDES_PANE. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pardes NEWFILE in a pane forwards even when its directory is missing, and ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | Save makes the directories fs.md said FILE must already exist, while `pardes new.txt` in fact forwarded, making a pane named for it that Save creates. With a missing directory (`pardes notes/new.txt`) the launch gave up forwarding and started a nested editor inside the pane. Now the name is made absolute as written and forwarded the same way. A name written to a pane's name file that goes into a directory not there has its Save make the directories, as Config's pane does. A Save <path> into a missing directory still fails ENOENT. The Forwarding section now says what a new FILE does. fs.py launches one into a missing directory and saves it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Zig files go to zls as a child process through the protocol client, as every ↵Gabriel Schneider5 days
| | | | | | | | other language does: the in-process ZLS backend goes lsp_zls.zig (1,522 lines), the zls dependency, build.zig's zls wiring and the import graph it baked into the options only for it, and main.zig's reference go. lsp_client's table gains a zls row (PARDES_LSP_ZIG overrides it); Hover, Rename, Diagnostics, WsSymbols, Lspinfo and gd answer through it (checked with lspprobe and the snapshots against zls 0.16.1-dev). What changes for a user: zls must be on PATH; a completion's rows are zls's candidates at the cursor, where the linked analyser gave each one's declaration; document symbols carry no signature. The Zig snapshots (lsp, lspcomplete, lspcompletemoved, lspdebug, lsprelpath) run the real zls now: lspdebug reads the client's explain and report, lsprelpath spells gr's rows where it spelled a completion's, and their goldens are recorded again (stable over three runs). Lspinfo still opens with its backend line. The ReleaseFast tty binary is 105.35 MB to 96.28 MB, the Debug one 296.5 MB to 245.9 MB. docs/lsp.md, web.md, design.typ and the README say so. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fs.py waits for a new file's pane to be named, not only madeGabriel Schneider5 days
| | | | | | pardes --wait NEWFILE reads pane/new and then writes the pane's name, two requests; the test checked /index for the name as soon as the pane showed, and a gate run caught it between them. It waits for the name now. Co-Authored-By: Claude Opus 5.5 <[email protected]>
*---. Merge: loose end + msize 64K + docs slimming + docs-audit fixes + monkey-gui ↵Gabriel Schneider5 days
|\ \ \ | | | | | | | | | | | | + tty ssh acked frames
| * | | The 9P server offers 64 KiB frames, not 8 KiBGabriel Schneider5 days
| |/ / | | | | | | | | | | | | | | | 8192 was kept for round 24 because 64 KiB seemed to hang fs-test's restore detached space; that was the batch-wake overflow fixed in kmqtwqsm, which any msize could hit, and fs.py passes at 64 KiB with it. A client asking for more now gets it, so a write up to 64 KiB less 24 is one Twrite, and round 24's no-newline cutoff (write_room, the negotiated msize less 24) follows: fs.py checks a 20000-byte ctl line from a 64 KiB client is taken whole. Each of the 16 connection slots holds its buffers at the larger size. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* / / pardes NEWFILE in a pane opens a pane named it in the session, as acme's B ↵Gabriel Schneider5 days
|/ / | | | | | | | | | | | | | | does, and a start with no terminal says so A name that did not exist yet failed resolveOs, so the launch fell through to starting an editor of its own, which on a pty with no controlling terminal (a detached session's) ended in a NoDevice error trace. A new name's directory is now resolved and the name kept: the launch reads pane/new and writes that path to the pane's name, so Save creates the file, and --wait waits on that pane (the git commit case). A standalone start whose /dev/tty will not open prints why and exits 1. fs.py covers both; the known-wrong line in docs/divergences.md goes. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | pardes --wait (-w) in a pane returns only once the pane its file landed in ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | is deleted, so it can be $EDITOR A launch inside a pane forwards its file to the session's look and returned at once, so fish's Ctrl-O (edit_command_buffer), git commit and crontab -e read their still-unedited file back and went on. With --wait, as acme's E against B and read the way plan9port's E reads acme's log, it finds the pane /index names the file by (the one already showing it, if open), follows /log on one connection with 'follow new', reads /index once more to catch a Del that came first, and then blocks with no deadline until that pane's del record: exit 0, or 1 when the connection ends with the session. The 9P client's one-shot requests keep their 2 s deadline; its new follow takes it for the setup only. Outside pardes nothing changes. --help, docs/fs.md, the README and the 9P skill say to set EDITOR='pardes --wait', which GIT_EDITOR follows. Tested in fs.py (it returns within 50 ms of the Del, a second -w waits on the same pane, one whose session is killed exits 1) and end to end: fish 4.8 in a detached session, echo hi, Ctrl-O, the waiting launch idle in poll, the line edited over 9P, Save, Del, and fish ran echo edited. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | Mini with no argument is wrong #args, EINVAL; Find, Grep and Mini say their ↵Gabriel Schneider5 days
|/ | | | | | | | names capitalised Mini needs a file but did not say so, so a bare Mini ran and failed EIO. It now requires its argument, refused wrong #args (EINVAL) as every such word is. Its failures, Find's and Grep's start with the builtin's own name (Mini:, Find:, Grep:), as the others' do. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Delcol on the last column leaves the window, empty but for its workspace ↵Gabriel Schneider5 days
| | | | | | | | tag, as acme's does The last column's Delcol ended the session. The window now stays, with only the workspace tag; Newcol, and New (which makes the column it goes in), start it again. A word run with no pane at all runs with a stand-in that is no pane, the root ctl takes session words, and pane/new makes its scratch in the session's directory. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Not-found failures say it once, in plain words: grep: pattern not found, ↵Gabriel Schneider5 days
| | | | | | | | callers not found The ENOENT that 9ns reads from a failure's words came from a tacked-on suffix, grep: no match, not found, definition: nothing found, not found, no shell "x", not found. They now say it once: grep: pattern not found, find: name not found, Callers: callers not found, definition: not found, shell "x" not found (...). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A ThemeFile that cannot be read or is no theme fails its write, and a bad ↵Gabriel Schneider5 days
| | | | | | | | path says why The theme is read when the host performs the request, after the write had been answered, so a missing file or a bad theme only showed a message; and a path not ending .zon said only invalid theme path. Load failures are now the waiting write's (late, as a Save's), and the path refusal says a theme file is a .zon. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A path with a part over 255 bytes is refused, never a panicGabriel Schneider5 days
| | | | | | std's statFile takes the kernel's ENAMETOOLONG for a bug (errnoBug), so a name, look, DumpDir or Save path with a part over 255 bytes panicked the editor (exec.kindOf via writeName, recentKeeps, dumpFailed). Every non-test statFile now goes through fs.statPath, which refuses such a name as NameTooLong first; fs.py drives long, looping, not-a-directory and not-ours paths through name, look, DumpDir, Dump and Save. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Recent goes on across a Restore, and is kept after itGabriel Schneider5 days
| | | | | | A Restore makes a new session, which never loaded the kept list, and saveRecent gives up until it has: Recent was empty after a Restore and nothing opened afterwards was kept. The new session now takes the old one's list (a boot from a dump reads the kept file). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pty/ctl exec that cannot start its shell keeps the one runningGabriel Schneider5 days
| | | | | | Each host closed the running shell before it forked the new one, so an exec whose shell failed left the pane with none and later runs answered error shell gone. A shell not there is now refused up front, and every host starts the new shell first, replacing the old only once the close-on-exec pipe says it ran; a failure there is only said (restartFailed). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Recent lists the files opened lately, closed ones too, and a jump back to a ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | | | closed file reopens it A file closed by accident, its path forgotten, could not be found again: the jumplist dropped closed panes. Every file opened (a look, a Save of a scratch, a Restore, a rename) goes first in a list of 200, kept once, its dot noted when it closes, kept across sessions in $XDG_STATE_HOME/pardes/ recent. `Recent` (SPC f r) shows it in a reused +Recent, each row `path:line:col open|closed` a look reopens; /recent reads `open|closed <path>`. The jumplist keeps a closed file's entries, +Jumps marks them `(closed)`, and Back to one opens the file at its place. acme has no such thing; its dump and Load are the nearest. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A shell that cannot start fails Tty and pty/ctl exec with why, before either ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | answers A shell whose exec failed (a script's missing interpreter) was reported started: Tty and pty/ctl exec succeeded, then the pane died. The child now reports a failed chdir or exec through a close-on-exec pipe the parent reads before acknowledging the shell; the host's spawn fails with the reason (`shell not found`, ENOENT), which fails the waiting write. A Tty whose first shell never ran leaves no pane; a terminal restarted by pty/ctl exec keeps its pane. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A shell started again by pty/ctl exec is guarded against the rename flap as ↵Gabriel Schneider5 days
| | | | | | | | | | | a new one is The guard that keeps a shell from taking this process's directory before its chdir lasted only until the first shell spoke; a shell started again in the same pane (pty/ctl exec) was asked with the old shell's word still standing. A spawn resets it. fs.py's naming test restarts one too. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* fs.py's workflow canary: one session driven as the dogfood agents drive itGabriel Schneider5 days
| | | | | | | | | | | The round-18 Grep that found nothing slipped past every narrower test. One broad run now looks files, runs Grep and Find hits and misses, looks a plain word, Edits two files and Saves them, gets one back from disk, runs pty/run failing then passing, Kills a command pane, sends to a REPL, makes and removes a column, answers an ask, and Dumps and Restores, checking the log and the read-backs at each step, in under 30 s. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A Save into a directory that is not there says no such directory, ENOENTGabriel Schneider5 days
| | | | | | | | It failed EIO with `file not found`, which named no file that was missing. It says `Save <path>: no such directory`, and a late failure saying `no such` answers ENOENT, as a builtin's does. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A shell given a directory is not taken to be in this process's before it has ↵Gabriel Schneider5 days
| | | | | | | | | | | | | spoken, so it logs no rename to the session's and back Each host read /proc/<pid>/cwd right after forking the shell and at every frame after; before the shell's chdir that says this process's directory, a rename to it, then the real one a frame later, a rename back. A shell given a directory is named by it already (newShell) and is no longer asked at fork; and until it has printed anything, an answer naming this process's directory is not taken. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A detached session no frontend has sized is 160x50, not 80x24Gabriel Schneider5 days
| | | | | | | At 80x24 a script's third or fourth pane/new was refused for want of rows. `size` still sets any other size, and a frontend attaching its own. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A pty/ctl winsize gives a terminal two rows at least, so it no longer reads ↵Gabriel Schneider5 days
| | | | | | | | | | | | busy for ever A one-row pty loses the prompt's input mark as soon as the prompt wraps, and busy detection never sees the shell idle again. Placement already keeps a new terminal at tag + 2 rows; a winsize write now keeps the pty at two. A pane dragged down to one body row keeps a one-row pty, since a taller pty than the pane shows would put its cursor below the pane. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* One rule for failing builtins: the write fails, one err, no msgGabriel Schneider5 days
| | | | | | | | | | | | | | | | A builtin that failed through a ctl failed the write and logged its err, but through look, exec, tagexec or a column's exec it only said so on the message row, logged as a msg, and the write succeeded. Now every click write runs its builtin as a ctl line does (ctl.captured): a failure fails the write, with its words (EINVAL for malformed input, else EIO or what the words name), logs one err and no msg or announcement. get's Modified and a look miss are shown but logged once, as their err. A control character's refusal names its reason, a failed click reads back nothing, and look never reads back a pane closed since. The special case for a cut-short Edit through exec goes (the rule covers it); fs.md's table of exceptions becomes the one rule, as does the skill. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* /commands takes each word's own doc comment, whole, without citationsGabriel Schneider5 days
| | | | | | | | | | | Repl showed Joincol's first line and Joincol another's, because a comment had drifted above the wrong declaration in builtins.zig; Kill's was cut mid-sentence and Exit's cited exec.c:892. The drifted line is back on Joincol, a parenthesis citing source (.c, .zig) is dropped, and the first sentence is kept whole up to 240 bytes, then cut between words with an ellipsis. A test checks every description opens its own word's comment. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* /commands says what each word does, and that the root's ctl takes EditGabriel Schneider5 days
| | | | | | | | | | | A /commands line gave a word, its argument and root or pane, but not what it does, and called Edit a pane's word though the root's ctl takes it too. Each line now ends with -- and the first sentence of the word's doc comment (read from builtins.zig itself, so there is one copy), and Edit is both. fs.md says a pane's word such as Undo or Msg is refused at the root. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A multi-line paste into Python's REPL runs whole, back at its promptGabriel Schneider5 days
| | | | | | | | | | | | The Enter went on Python's first output after the paste, before it had taken in the whole paste, and one Enter leaves a multi-line input at ... anyway. Python's output now only restarts a 100 ms quiet wait (the 250 ms fallback stays), and a paste of more than one line gets the second Enter a block gets. fs.py runs print(11)\nprint(22), the same with a trailing newline, and a for block followed by a statement in a real python3, each back at >>>. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* pty/run's busy names the program holding the terminalGabriel Schneider5 days
| | | | | | | | | busy said only that something ran. Where the host can tell (Linux, the tty's foreground group's /proc comm, a new fg_name host call), it says busy: <program> is running; elsewhere, busy as before. The GUI's host gains the one small callback (render agent's file: gui.zig, fgName). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A REPL paste's Enter waits on the clock, not on stale core timeGabriel Schneider5 days
| | | | | | | | | | | | sendToRepl timed the Enter's fallback from stepped_ns, which in an idle detached session is as old as the last frame: the wait was over before it began and the \r went out with the paste, which 3.13's REPL then reads as part of it (4 of 5 sends lost their Enter). The wait now starts from the host's clock and is checked against now_ns; the REPL's echo of the paste still sends it sooner, and the wake is scheduled for the deadline. fs.py sends five times after two idle seconds each in a real pty. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A detached session with no frontend takes its size from the root ctlGabriel Schneider5 days
| | | | | | | | | | A --detach session nobody is attached to stayed 80x24, too small for an agent's panes, and nothing could change it. The root ctl takes size <cols> <rows> while no frontend is attached (refused while one owns the size), and a client that attaches later still sets its own (the server compares with the core's size). Documented with the 80x24 default. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* No placement leaves a pane shorter than its tag and two rowsGabriel Schneider5 days
| | | | | | | | | | | | | | | | Placement could split a pane down to a tag and one row, or give a new one less. Every placement now checks the pane it made and each pane it shrank against its tag (wrapped at its width) plus two rows: where they lack the room, the column's tallest pane is halved instead, and where none can give it the new pane is refused with "no space for a pane in that column" (ENOSPC over 9P) and closed at the step's end, once its maker is done with it. splitBelow and splitParent leave two body rows (a boot layout, split before any row exists, is as before). Re-recorded by name: lookpanes (panes one or two rows lower) and splitparent (the 6-row squeeze now refuses); fs.py closes the scratches and long-named panes it no longer needs, since its 24-row session filled. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A command line cut across writes runs once whole, and look/exec answer per openGabriel Schneider5 days
| | | | | | | | | | | | | | | | A mount cuts a write at its message size, and each piece ran on its own: a line cut at the boundary ran as shell commands and a 50 KB Edit block broke. An open of look, exec, tagexec, any ctl or a column's exec now keeps an unfinished last line, or an Edit block still open, until its next write or its release, and never runs a fragment. The same open record holds what its last write touched, which a read on it answers (as /net/tcp/clone does); an open that never wrote reads the session's last as of its open. A release that runs a held line waits for quiet and counts as a change; a clicked line with a control character is still refused at its write. Tested in unit tests, fs.py (python client, 8 KiB) and selfmount.py (the kernel mount, a 1000-line seq burst and a 50 KB Edit block). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The workspace tag has /tagexec, every exec file reads back what it touched, ↵Gabriel Schneider5 days
| | | | | | | | | | | | | | and a tag's words log as the session's /tagexec runs a word as a click in the workspace tag, as col/<serial>/exec does in a column's. A column's exec was write-only; it and /tagexec now read back the serials the last write touched, as /exec does. A click in a tag no longer goes to the focused pane's event reader, and what a word run from a column's ctl or exec or /tagexec says is logged msg -, not against the focused pane. The README, fs.md and the skill say so, and document the answer record. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The tree's README fits its 45 lines again, and fs-discovery-test knows the ↵Gabriel Schneider5 days
| | | | | | | | | | | | new entries /README had grown to 51 lines with the layout files and the round 8 notes, past the 45 the discovery test holds it to. It is condensed (the log's record names on one line, the column files on one, two examples fs.md covers), and fs-discovery-test lists layout, tag and col, reads /index's new last field, and reads /commands' setting values. Co-Authored-By: Claude Opus 5.5 <[email protected]>
*-. Merge: 9P rounds 7-8 + layout files + loose ends + G3 cursorGabriel Schneider5 days
|\ \
| * | The QUIC listener tests are deterministic, and fs-test --quic passesGabriel Schneider5 days
| |/ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | "Unix TCP and QUIC share one listener" failed 17 of 360 runs under load (12 parallel copies), always at p.fs.opens: the client had hung up but its connection's task had not yet seen it, reset() then cut the connection, and the releases the hangup owes were refused as the old editor's. The test's replacement editor is the same editor, so those opens stayed. It now waits (resting, with its own deadline) for the runner to empty before reset: 0 of 360 after. fs-test -Dquic=true failed too, at two points. A session Looking at its own tree through a QUIC mount is features.txt's documented "left as they are" case (QUIC is answered on the editor's thread); that check is dropped with a note. The /screen check asserted body text that the view may have scrolled past (2 of 7 runs); it now asserts the pane's tag. 10 of 10 after. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A column has a ctl, an exec and an rmdir over 9P, and Restore maps its serialGabriel Schneider5 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | A script could read and write a column's tag but not act on the column. col/<serial>/ctl takes Delcol, Joincol, New and Tty, each acting on that column as from its tag; col/<serial>/exec runs a word as a middle click in the tag; rmdir col/<serial> closes an empty column and refuses one with panes (ENOTEMPTY, an err record saying why). The root ctl's refusal of Delcol and Joincol points at col/<serial>/ctl. A dump keeps each column's serial and Restore logs restoredcol <old> <new>; the dump golden gains them. Documented: Joincol's survivor, the column on the right, keeps its serial and tag. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | A send to Python's REPL runs once, the Enter after the paste, not in itGabriel Schneider5 days
| | | | | | | | | | | | | | | | | | | | | | | | A one-line send (print(1)) to Python 3.14 stopped at ... and needed another Enter: its REPL takes a bracketed paste, and an Enter read in the same read as the paste is part of the paste, one line or not (checked in a real pty). Into a REPL that asked for bracketed paste, the Enters (two for an open block) now wait for its next output, its answer to the paste, or 250 ms with nothing. fs-test runs python3 in a real pty and checks a one-line exec prints at once; the docs' pty/data recipe says to send the Enter apart. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* | fs-test checks an unattended detached session expires its messages on its ownGabriel Schneider5 days
|/ | | | | | | | | | | Round 7 saw messages linger for minutes in a detached session. With nothing attached they do expire, on the session's own clock (nextWake schedules the look, expireUnattended drops them); the merge did not regress it, and a session driven only over 9P now has a test that it does, with no request in between. With a frontend attached a message stays until its next key or click, as config.md and detached.md say; the lingering the agent saw is that. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A Restore logs restored <old> <new> for each paneGabriel Schneider5 days
| | | | | | | | | A script holding serials from before a Restore could not find its panes: the replacement numbers them afresh. The dump now keeps each pane's serial (0 in older dumps), and the replacement's log says `restored <old> <new>` for each after its `restore <path>`. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Sixteen 9P connections, and the next one is told there is no room instead of ↵Gabriel Schneider5 days
| | | | | | | | being reset Four slots ran out under scripts plus a mount, and the fifth client was closed without a word, which through a mount looks exactly like a dead session. pardes now serves sixteen, and builds against cloud9 09b77cf, whose runner answers the Tversion of a client it cannot seat with an Rerror "too many connections" and tells pardes, which logs `err - 9p: too many connections`. QUIC keeps its own sixteen and still just closes. Co-Authored-By: Claude Opus 5.5 <[email protected]>