Browse Source
Motivating transcript: piped `error xxxx` then interactive `set errorInfo` shows tcllib virtchannel boot noise (caught `unset timer`) instead - the restart boundary discards run-1's code interp, and bare ::errorInfo is clobbered by internal caught errors anyway. Detail file records the two mechanisms and design points (capture at the repl error-reporting site, tsv/exitinfo handover, punk-owned record + one-line first-prompt notice, quiet on clean pipes). Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.commaster
2 changed files with 62 additions and 0 deletions
@ -0,0 +1,56 @@
|
||||
# G-038 Piped-phase errors inspectable in the restarted interactive shell |
||||
|
||||
Status: proposed |
||||
Scope: src/lib/app-punkshell/punkshell.tcl (eof-restart handover), src/modules/punk/repl-999999.0a1.0.tm (error capture at the reporting site and/or teardown), src/modules/punk/repl/codethread-999999.0a1.0.tm (as needed for code-interp access) |
||||
Acceptance: `'puts test;error xxxx' | <punkexe> shell` then, at the first interactive prompt, a documented command or variable yields the xxxx message, its errorInfo traceback and errorCode from the piped phase, and the first prompt is preceded by a one-line notice that a piped-phase error was retained; the retained record survives boot-time caught-error noise (proven against the motivating transcript, where plain `set errorInfo` showed virtchannel's `can't unset "timer"` instead); an error-free piped phase produces no notice and an explicitly-empty record; plain ::errorInfo semantics are otherwise unchanged; verified on both Tcl generations. |
||||
|
||||
## Context |
||||
|
||||
Motivating transcript (user, 2026-07-08): `'puts test;error xxxx' | punk902z shell` - the |
||||
piped phase prints `test` then the xxxx error, EOF triggers app-punkshell's CONIN$ restart, |
||||
and at the interactive prompt `set errorInfo` shows an unrelated |
||||
`can't unset "timer": no such variable ... "unset timer"` instead of the xxxx traceback. |
||||
The user had hoped the piped error would be retained for interactive inspection. |
||||
|
||||
Two mechanisms defeat the natural expectation: |
||||
|
||||
1. **Restart boundary**: the restarted shell is a fresh `repl::init`/`repl::start` with a new |
||||
codethread and code interp (app-punkshell do_shell). The piped phase's ::errorInfo lives in |
||||
run-1's code interp, which is torn down with its codethread. Nothing carries it across. |
||||
2. **::errorInfo is boot-noise-prone anyway**: a *caught* error still stamps ::errorInfo. |
||||
tcllib's `virtchannel_core/events.tcl` (`tcl::chan::events`) runs `catch { unset timer }` |
||||
as ordinary control flow, and the repl-exec log tee construction (fifo2 stacks during |
||||
repl::init) triggers it in the fresh code interp - so a brand-new shell's resident |
||||
::errorInfo is whatever internal caught error happened last during boot. Restoring the |
||||
retained error into plain ::errorInfo would be clobbered by the same noise, hence the |
||||
punk-owned record in the goal statement (or injection strictly after boot completes - |
||||
but a dedicated record is robust and self-describing). |
||||
|
||||
## Approach (design points) |
||||
|
||||
- **Capture at the reporting site, not by scraping ::errorInfo at teardown**: the repl already |
||||
distinguishes command errors when it renders the tcl-err (lowercase `p%`) prompt path - that |
||||
is the natural place to record {message errorInfo errorCode command-string timestamp} for |
||||
the most recent errored command. Teardown-time capture of the code interp's ::errorInfo is |
||||
the fallback but inherits the noise problem above. |
||||
- **Handover**: the record must cross thread/interp teardown - candidates: tsv (already used |
||||
by the repl for runchunks), or app-punkshell capturing it from the run-1 exitinfo/donevalue |
||||
plumbing and seeding the run-2 code interp after init. |
||||
- **Surface**: a documented variable in the code interp (e.g. ::punk::last_pipeline_error) or |
||||
a small command; the first-prompt notice should be one line and only appear when a retained |
||||
error exists (piped runs that end cleanly stay quiet - agents/CI pipe scripts constantly). |
||||
- **Scope question to settle**: retain only across the piped->interactive restart, or also |
||||
expose "last error of the previous run" generally (subshell exits, `repl::start` restarts)? |
||||
The goal commits only to the piped->interactive case; wider retention can be recorded here |
||||
if it falls out naturally. |
||||
- Note the errorInfo-noise observation stands alone too: even without retention, |
||||
`set errorInfo` in a fresh punk shell reports internals' caught errors. Out of scope to |
||||
"fix" tcllib, but the dedicated-record design sidesteps it and the doc/help for the new |
||||
record can mention the caveat. |
||||
|
||||
## Notes |
||||
|
||||
- Related: G-036 detail (same eof-restart machinery, where the codethread/interp lifecycle is |
||||
mapped); G-015 (script subcommand is the agent-facing piped path and already reports errors |
||||
on stderr with honest exit codes - this goal is about the *shell* subcommand's interactive |
||||
restart, a human-facing convenience). |
||||
Loading…
Reference in new issue