Browse Source

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
master
Julian Noble 2 weeks ago
parent
commit
b219488e64
  1. 1
      AGENTS.md
  2. 8
      GOALS.md
  3. 2
      goals/G-036-tcl9-udp-console-worker-wedge.md
  4. 47
      goals/G-039-orphan-console-spin.md

1
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)

8
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/<kit>.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' | <punkexe> 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' | <punkexe> 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.

2
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

47
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.
Loading…
Cancel
Save