mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Closing a tab must end the work the tab was doing. The child is a session leader (portable-pty calls setsid), so signalling its pid reaches the shell and leaves everything the shell started running, reparented to init and holding the pty slave. Signal the process group instead: SIGTERM, a bounded grace, then SIGKILL to the group whether or not the leader went quietly -- a polite leader does not imply an empty group. Three things this found that reading could not. waitpid(WNOHANG | WNOWAIT) returns EINVAL on Darwin. POSIX defines WNOWAIT only for waitid; Linux tolerates it, macOS does not. The failure was silent because `seen == pid` is false for -1 exactly as it is false for "still running" -- error and negative result collapsed into one branch. Every shutdown escalated to SIGKILL and the polite arm was dead code on the platform we develop on. Only an assertion on *which arm fired* could see it. A grandchild test that does not defeat the tty hangup proves nothing. Killing a session leader makes the kernel SIGHUP the foreground group, so the grandchild dies either way and a pid-only mutation survives. The fixture must ignore SIGHUP and busy-loop; then pid-only leaks and kill(-pgid) does not. A child blocked writing to an undrained master does not die promptly even on SIGKILL -- measured 606ms to reap, versus microseconds when drained. So the reader outlives termination and reap. shutdown_draining takes the reader by value, which makes the forbidden order a compile error rather than a comment: a joined reader has been consumed and cannot be passed. Mutation matrix, sources restored byte-identically after each: L1 delete SIGKILL escalation -> FAIL (orphan + grace arms) L2 kill(pid) not kill(-pgid) -> FAIL (orphan arm) L3 delete pre-reap try_wait -> FAIL (Killed, want AlreadyExited) L4 join reader before SIGTERM -> FAIL (10.01s, grace is 250ms) Fixtures built to ignore signals carry their own SIGKILL deadline. Without it a legitimate failure leaves a core spinning at PPID 1, and L1/L4 were detected by hanging -- a test that finds a bug by never finishing cannot be told from a broken one. The deadline sits far outside the observation window so it can never rescue a failing implementation. 2088 desktop + 3 mixer + 26 buzz-terminal + 5 fences + 4 resize green, clippy --workspace --all-targets -D warnings clean, fmt clean. Co-authored-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com> Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>
Buzz
Desktop chat shell with:
- Tauri + React + TypeScript + Vite
- Tailwind CSS
- shadcn/ui-ready shared components
- Biome (lint/format/check)
- Feature-driven frontend structure
Scripts
pnpm dev- run the web frontendpnpm tauri dev- run the desktop apppnpm build- typecheck and build frontendpnpm typecheck- TypeScript checkspnpm lint- Biome lintpnpm format- Biome format (write)pnpm check- Biome check
Structure
src/shared- reusable app-wide code (ui,lib,styles)src/features- feature modules (vertical slices)src/app- top-level app composition