Seven commits on the JefeOS C++ kernel spanning a hard-won sigtest end-to-end PASS, a post-sigtest network wedge that survived two dedicated agent sessions, five new POSIX userspace utilities, a POSIX regex engine in libc, and a coverage audit that found 94% of deployed ELFs have zero automated tests. One race fixed. One mystery documented and defense-in-depth shipped around it.
Sigtest PASS: the RAX that Wasn't
The ring-3 signal trampoline had already landed — SigFrame on the user stack, sigtramp page at 0x7FFFFFFFF000, sys_sigreturn restore — but sigtest kept returning non-zero from raise(SIGUSR1) even though the handler visibly ran in ring 3. Root cause was a timing race: the INT 0x80 asm stub writes the syscall return value into the saved RAX slot after syscall_handler returns, but deliver_pending() — called from inside the handler — snapshots the frame right then. The SigFrame captured RAX=62 (the kill(2) syscall number) instead of 0, sigreturn restored that, and raise() got back garbage. Fixed with a pre-deliver_pending publish of ret into g_current_syscall_frame->rax. sigtest now prints PASS handler ran, signo=10 and returns 0 cleanly.
Paging: Splitting Limine's 2MB Entries
Adjacent fix that unblocked the same test: when the kernel walked a huge-page PD entry and tried to install a 4KB PTE underneath it, get_next_level() treated the 2MB entry's data bits as a child-table pointer. Result: user ELF .text bytes overwritten with PTE values, user code triple-faulted before main(). The walker now detects the HugePage bit on a present entry, allocates a fresh 4KB PT, splits the 2MB into 512 leaf entries preserving flags, and swaps in the new PT with a CR3 flush. It also promotes intermediate User/Writable bits monotonically so ring-3 faults don't regress into supervisor-only pages mid-walk.
Observability: yield-poll wait
Both cmd_sigtest and cmd_elftest used to fork and return, leaving the shell blind to the child's exit status. Replaced with a yield-poll loop: 2s timeout, drains net::process_packets() and ssh::process() on every tick so the NIC and SSH server don't starve, watches the child's state slot directly, reaps via waitpid() when it hits Zombie. The shell gets a self-explaining PASS/FAIL readout without re-introducing the “blocking wait starves SSH” problem we spent sprints fixing earlier.
Network Wedge: Two Agent Sessions, No Fix
After sigtest passes, JefeOS's NIC and timer IRQ both stop firing on the next SSH attempt. Total investigation: two dedicated agent sessions (~2.5hrs, 8-9 VM bounces, 4+ builds) plus a canned 10s-timeout repro harness at scripts/wedge-test.ps1. Going in, the leading hypothesis was stale tss.rsp0 from elf::exec_elf. Agent B ruled that out (TSS RSP0 was correct at wedge time) and shipped a defense-in-depth per-schedule TSS RSP0 update anyway — the standard Linux __switch_to pattern, architecturally correct regardless of the wedge. Current leading suspect: PIC EOI accounting, where the ring-3 sigreturn IRETQ leaves the 8259 ISR half-acked and blocks IRQ0 thereafter. Next step is dumping inb(0x20/0x21/0xA0/0xA1) at the wedge moment — with one landmine already flagged: you cannot do it from inside the timer ISR, because serial::puts in an ISR holds IF off long enough for NIC RX to fall behind and cause a different, self-inflicted wedge. Ring-buffer logging only.
POSIX Userspace: Five More Utilities
Shipped printf (format strings, %s/%d/%i/%u/%x/%X/%o/%c/%%/%b, backslash escapes, \c suppression), expr (integer arithmetic and comparison, logical, string functions length/substr/index/match, : regex-lite, parentheses), id (uid/gid/euid/egid with -u/-g/-r), nl (-b a|t|n, -w, -s, -i), and od (-b/-c/-x, -A x|d|n|o). expr is the linchpin: once it's real, POSIX shell math stops being a lie.
POSIX regex in libc
New regex.h plus regex.c (697 LOC): recursive-descent backtracking matcher, BRE and ERE, 16 capture groups, all 12 POSIX character classes ([[:alpha:]] through [[:xdigit:]]), the expected cflags (REG_EXTENDED, REG_ICASE, REG_NOSUB, REG_NEWLINE), and eflags (REG_NOTBOL, REG_NOTEOL). Unblocks anything that calls regcomp/regexec — expr : REGEX immediately, and any future sed or awk we pick up. 24-case test program shipped; runtime PASS verification pending VM access.
TEST_PLAN: We Don't Test Our Stuff
While we were here: docs/TEST_PLAN.md landed. Coverage tables for 35 userspace programs, 36 shell builtins, 107 native INT 0x80 syscalls, and ~80 Linux compat syscalls. Headline finding: 94% of deployed ELFs have zero automated tests. Two smoke-test scripts proposed (tests/posix-smoke.sh, tests/syscall-coverage.sh) to get the number moving in the right direction.
What's Next
- Dump PIC IMR/ISR registers at the wedge moment (outside the timer ISR) to confirm or kill the EOI hypothesis.
- Wire the two proposed smoke-test scripts and start closing coverage gaps.
- Verify the regextest 24-case suite on VM.
- Resume the POSIX climb:
WIFEXITED/WEXITSTATUSmacros, file locking (flock/fcntlF_SETLK),getrandom. - VFS layer (long-deferred — kernel abstraction over NTFS/JefeFS/sockets).