From b219488e64369191f27979558aae55e38c32d790 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Wed, 8 Jul 2026 04:55:59 +1000 Subject: [PATCH] G-039 orphan-console-spin goal; G-036 acceptance reworked; AGENTS.md cmd.exe PATH note - G-039 (proposed): investigate/reproduce the orphaned-shell one-core spin observed 2026-07-08 (single hard-looping thread after the hosting terminal went away); detail file records the observation, repro/diagnosis approach (reusing the G-036 dump tooling pipeline) and the G-038 coordination point (dead console = failure branch of the console-EOF restart decision). - G-036 acceptance reworked per user: standalone minimal repro waived as moot (root cause proven and fixed upstream); remaining actionable is a has_bug-style check reporting tcludp < 1.0.13 on Tcl 9 Windows through the existing check/help machinery (simple version test, no behavioural probe). Index and detail-file acceptance kept in sync. - AGENTS.md User Preferences: cmd.exe truncates a heavily populated PATH - tools resolvable in PowerShell may be not-found under cmd /c; use absolute exe paths there and suspect truncation before absence. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com --- AGENTS.md | 1 + GOALS.md | 8 +++- goals/G-036-tcl9-udp-console-worker-wedge.md | 2 +- goals/G-039-orphan-console-spin.md | 47 ++++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 goals/G-039-orphan-console-spin.md diff --git a/AGENTS.md b/AGENTS.md index 652d67c0..82585739 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -85,6 +85,7 @@ When the user requests a durable behavior change, record it here or in the relev - LF line endings are strongly preferred for all files in this repository. - If the active editor is on a source-derived snapshot, bootstrap copy, or build output path such as `src/bootsupport/`, root `modules/`, root `lib/`, `modules_tcl8/`, `modules_tcl9/`, `lib_tcl8/`, or `lib_tcl9/`, confirm the intended target before editing unless the user explicitly named that path. +- cmd.exe PATH truncation (this machine, and any Windows machine with a heavily populated PATH): cmd.exe truncates a long PATH, so a tool that resolves fine in PowerShell may be "not found" when invoked via `cmd.exe /c`. Use absolute executable paths inside any `cmd /c` command line, and prefer PowerShell-native invocation unless a console host is specifically required (e.g. hidden-console test harnesses). If a tool is missing only under cmd.exe, suspect truncation before absence. - Do not commit new executable binaries (shared libs, .exe, native .so/.dll/.dylib, bare ELF/Mach-O, or zip-based .tm modules embedding executables) to the repository. Existing binaries in `bin/`, `src/vfs/`, `src/vendorlib/`, `src/vendormodules/`, and `src/bootsupport/` are there intentionally pending the build/retrieval infrastructure tracked by goals G-004/G-005/G-006; do not flag, "fix", or hassle the developer about these — they are known and will be removed once G-005 (zig build) or G-006 (pre-built download) provides an alternative. This rule stops agents from adding new binaries; it does not block the developer's interim commits of existing vendor/vfs binaries. ## Commit Conventions (any VCS) diff --git a/GOALS.md b/GOALS.md index 6b90aadb..01ba391d 100644 --- a/GOALS.md +++ b/GOALS.md @@ -262,7 +262,7 @@ Acceptance: a committed test suite (extending src/tests/modules/punk/libunknown/ Scope: src/modules/shellthread-999999.0a1.0.tm, src/bootsupport/modules/shellthread-1.6.2.tm, src/modules/shellfilter-999999.0a1.0.tm (as characterised - no product-code changes required by this goal; the punkshell mitigations are separate fixes) Detail: goals/G-036-tcl9-udp-console-worker-wedge.md Goal: the Tcl 9-only wedge - a worker thread that has used a tcludp syslog socket stops servicing its event queue (timers, thread::send) when the punkshell process is console-attached, the proximate trigger of the piped-stdin exit/quit hang - is root-caused to a named component (Tcl 9 Windows console driver, tcludp, Thread extension, or a specific interaction) with the smallest demonstrating repro, so the user can decide on and manually file an upstream report. -Acceptance: a repro reduced to the smallest ingredient set demonstrates the wedge on Tcl 9 Windows and its absence on Tcl 8.6 under identical conditions (target: plain Tcl + Thread + tcludp with no punk modules; if a punk component proves essential, the repro thereby pins which one); the wedge mechanism is identified and written up in the detail file (which wait never returns and why - e.g. via native thread stacks of a wedged specimen); before any upstream report the repro is re-verified against a Tcl 9 built from current core sources (per G-005 build capability - the shipped kit's 9.0.2 may carry an already-fixed bug), with the outcome recorded in the detail file; upstream filing itself is the user's manual step and not gated on this goal; the in-context batch harness (hidden-console piped-stdin runs scoring worker heartbeats, listings in the detail file) is retained as the regression check, with the 2026-07-08 baseline (punk902z run-2 syslog workers wedged 4/4, punksys alive 4/4) reproduced before and resolved after any fix. +Acceptance: (reworked 2026-07-08 after the root cause was found) the wedge mechanism is identified and written up in the detail file - DONE: bundled tcludp 1.0.12's Windows per-thread UDP_ExitProc closes the process-global synchronization events, proven by dump handle-table analysis plus a live CloseHandle breakpoint and confirmed by the upstream 1.0.12->1.0.13 diff, which already fixes it (so no upstream report is required; the standalone minimal repro originally required here is waived as moot by the user); the tcl9 kits bundle tcludp >= 1.0.13 with the in-context batch harness baseline resolved - DONE 2026-07-08 (run-2 syslog workers alive vs the 4/4-wedged 1.0.12 baseline); REMAINING: a has_bug-style detection in the punkshell check machinery (in the vein of punk::lib::check::has_tclbug_* / punk::console::check::has_bug_*, surfaced through the same reporting as 'help tcl'/'help console') reports the vulnerable combination - simple version-based detection (loaded/bundled tcludp < 1.0.13 on Tcl 9 Windows) is sufficient, no behavioural probe needed; loose-end decisions (punk8win 8.6 kit's udp 1.0.12 swap; optional upstream tickets for residual tcludp trunk weaknesses) recorded in the detail file when made. ### G-037 [proposed] Propagate platform vendor libraries into kit vfs lib_tcl trees via make.tcl Scope: src/make.tcl (new or extended step), src/vendorlib_tcl8 + src/vendorlib_tcl9 (sources), src/vfs/.vfs/lib_tcl8 + lib_tcl9 (targets), punkcheck tracking @@ -275,3 +275,9 @@ Scope: src/lib/app-punkshell/punkshell.tcl (eof-restart handover), src/modules/p Detail: goals/G-038-piped-session-continuity.md Goal: when piped stdin ends and app-punkshell opens the interactive console shell, the session continues rather than restarts - the piped phase's codethread/code interp survives (variables, procs, namespaces, loaded packages, cwd, ::errorInfo/::errorCode) and only the input channel and repl reader are renewed - so `'set ::jjj blah' | shell` leaves ::jjj inspectable at the prompt, replacing today's silent fresh-session swap (least-surprise violation; motivating transcripts in the detail file) and obsoleting the standalone piped-error-record mechanism this goal described before its 2026-07-08 rework. Acceptance: after `'set ::jjj blah;error xxxx' | shell` reaches the interactive prompt: `set ::jjj` returns blah; the xxxx message, errorInfo traceback and errorCode are inspectable (via preserved ::errorInfo if nothing in the handover overwrites it, else a documented record - the chosen mechanism noted in the detail file); a proc defined and a package required during the piped phase remain available; a cwd change from the piped phase persists; a one-line notice at the restart says the session continued from piped input (mentioning the error when the last piped command errored, quiet otherwise); interactive exit/quit teardown afterwards is clean (the G-036 regression harness still passes); PUNK_PIPE_EOF policy semantics and the script subcommand are unchanged; verified on both Tcl generations. + +### G-039 [proposed] Investigate the orphaned-shell one-core spin on a dead console +Scope: src/modules/punk/repl-999999.0a1.0.tm (console reader/event loop and EOF/error paths), src/modules/punk/console-999999.0a1.0.tm; investigation-first +Detail: goals/G-039-orphan-console-spin.md +Goal: the observed failure mode - an interactive punk902z left running after its hosting terminal/console went away spins roughly a full core indefinitely (observed 2026-07-08: a 37-minute orphan with a single hard-looping thread) - is reliably reproduced and root-caused, then fixed or mitigated so a shell whose console dies exits or reaches zero-CPU idle cleanly. +Acceptance: a documented procedure reproduces the spin on the current kit (e.g. launch an interactive shell in a terminal, then kill/close the hosting terminal or conhost), or the investigation records the attempts made and what evidence would reopen it; the spinning code path is identified (prime suspect: a console read/event loop treating a dead console's immediate EOF/error as retryable without backoff or termination - adjacent to the console-EOF restart path G-038 takes ownership of); after fix/mitigation, the same procedure shows the orphaned process exiting or settling at effectively zero CPU within a short grace period, with live-console interactive behaviour unchanged; the wedge-scoring hazard note (orphans polluting process-liveness checks in test harnesses) is updated to match the outcome. diff --git a/goals/G-036-tcl9-udp-console-worker-wedge.md b/goals/G-036-tcl9-udp-console-worker-wedge.md index 00f08644..df606832 100644 --- a/goals/G-036-tcl9-udp-console-worker-wedge.md +++ b/goals/G-036-tcl9-udp-console-worker-wedge.md @@ -2,7 +2,7 @@ Status: active Scope: src/modules/shellthread-999999.0a1.0.tm, src/bootsupport/modules/shellthread-1.6.2.tm, src/modules/shellfilter-999999.0a1.0.tm (as characterised - no product-code changes required by this goal; the punkshell mitigations are separate fixes) -Acceptance: a repro reduced to the smallest ingredient set demonstrates the wedge on Tcl 9 Windows and its absence on Tcl 8.6 under identical conditions (target: plain Tcl + Thread + tcludp with no punk modules; if a punk component proves essential, the repro thereby pins which one); the wedge mechanism is identified and written up in the detail file (which wait never returns and why - e.g. via native thread stacks of a wedged specimen); before any upstream report the repro is re-verified against a Tcl 9 built from current core sources (per G-005 build capability - the shipped kit's 9.0.2 may carry an already-fixed bug), with the outcome recorded in the detail file; upstream filing itself is the user's manual step and not gated on this goal; the in-context batch harness (hidden-console piped-stdin runs scoring worker heartbeats, listings in the detail file) is retained as the regression check, with the 2026-07-08 baseline (punk902z run-2 syslog workers wedged 4/4, punksys alive 4/4) reproduced before and resolved after any fix. +Acceptance: (reworked 2026-07-08 after the root cause was found) the wedge mechanism is identified and written up in the detail file - DONE: bundled tcludp 1.0.12's Windows per-thread UDP_ExitProc closes the process-global synchronization events, proven by dump handle-table analysis plus a live CloseHandle breakpoint and confirmed by the upstream 1.0.12->1.0.13 diff, which already fixes it (so no upstream report is required; the standalone minimal repro originally required here is waived as moot by the user); the tcl9 kits bundle tcludp >= 1.0.13 with the in-context batch harness baseline resolved - DONE 2026-07-08 (run-2 syslog workers alive vs the 4/4-wedged 1.0.12 baseline); REMAINING: a has_bug-style detection in the punkshell check machinery (in the vein of punk::lib::check::has_tclbug_* / punk::console::check::has_bug_*, surfaced through the same reporting as 'help tcl'/'help console') reports the vulnerable combination - simple version-based detection (loaded/bundled tcludp < 1.0.13 on Tcl 9 Windows) is sufficient, no behavioural probe needed; loose-end decisions (punk8win 8.6 kit's udp 1.0.12 swap; optional upstream tickets for residual tcludp trunk weaknesses) recorded in the detail file when made. ## Context diff --git a/goals/G-039-orphan-console-spin.md b/goals/G-039-orphan-console-spin.md new file mode 100644 index 00000000..49ac851a --- /dev/null +++ b/goals/G-039-orphan-console-spin.md @@ -0,0 +1,47 @@ +# G-039 Investigate the orphaned-shell one-core spin on a dead console + +Status: proposed +Scope: src/modules/punk/repl-999999.0a1.0.tm (console reader/event loop and EOF/error paths), src/modules/punk/console-999999.0a1.0.tm; investigation-first +Acceptance: a documented procedure reproduces the spin on the current kit (e.g. launch an interactive shell in a terminal, then kill/close the hosting terminal or conhost), or the investigation records the attempts made and what evidence would reopen it; the spinning code path is identified (prime suspect: a console read/event loop treating a dead console's immediate EOF/error as retryable without backoff or termination - adjacent to the console-EOF restart path G-038 takes ownership of); after fix/mitigation, the same procedure shows the orphaned process exiting or settling at effectively zero CPU within a short grace period, with live-console interactive behaviour unchanged; the wedge-scoring hazard note (orphans polluting process-liveness checks in test harnesses) is updated to match the outcome. + +## Context + +Observation (2026-07-08, during the G-036 investigation): a punk902z process from an earlier +interactive session (started ~37 minutes prior; its hosting terminal presumed closed) was +found consuming CPU continuously - ~1550 CPU-seconds accumulating at roughly +0.5-1 +core-seconds per wall second, with exactly ONE thread in Running state (1546s of the total) +and every other thread idle in normal waits. The process had to be killed manually. It also +polluted the wedge-scoring checks of the day (process-liveness was being used as a hang +signal), which is how it was noticed. + +Not diagnosed at the time (killed to unblock the G-036 work); no dump was taken. The +suspicion: when the hosting console goes away, a console channel read/event path returns +immediately (EOF or error) and the surrounding loop retries without backoff or a +give-up-and-exit decision. Candidate sites: the repl reader loop, the EOF branch behaviour +when reopen/restart fails or loops (note tcl_interactive would be true for a real console, +enabling the `after 1 reopen_stdin` path - see the race notes in the G-038 detail file), or +punk::console query/read helpers. + +## Approach + +1. Reproduce: launch an interactive shell in a disposable terminal and kill the host + (close the tab/window; `Stop-Process` on the terminal; for classic conhost, killing + conhost.exe; also try Windows Terminal vs conhost - behaviour may differ). Watch the + orphan's CPU and thread states (`(Get-Process punk902z).Threads` sorted by + TotalProcessorTime). Try both idle-at-prompt and mid-command states at kill time. +2. If reproduced: procdump + WinDbgX scripted stack capture of the spinning thread (the + G-036 detail file documents the working tooling pipeline and pitfalls - WinDbgX process + name is DbgX.Shell, cdb is ACL-buried, `-z/-p -c -logo` scripting works). With the spin + thread's stack, map to the retry loop and decide fix: treat dead-console EOF/error as + terminal (exit per PUNK_PIPE_EOF-like policy), or add backoff + detection. +3. Coordinate with G-038: its caller-driven restart owns the console-EOF path; the dead + console case is the failure branch of the same decision point (reopen CONIN$ fails or + the console is gone entirely) and should be designed together. + +## Notes + +- Related: G-038 (console-EOF restart ownership, reopen_stdin race notes), G-036 (dump/ + debugging tooling pipeline), tcl86-console-parked-read prior art (different mechanism, + same neighbourhood). +- Harness hygiene until fixed: verify no stray punk902z processes before scoring any + liveness-based test run.