debugger: test names on closure frames #44

Closed
opened 2026-10-05 21:07:13 +00:00 by orion · 5 comments
Collaborator

Context

A test body runs as a closure the test runner calls back, so its frame in stackTrace is named closure (the chunk's
label), and the body of a group is closure too. A client sees double / closure / closure / math.test.trb
(the session tests/debug/tests.dap) and cannot tell which test it stopped in.

Source

Acceptance criteria

  • A test body's frame is named test "<name>" with the name the test was given at run time, so a test created in a
    loop (test "case {n}" { ... }, one chunk, many names) shows its own name. Proof: tests/debug/tests.expected
    (session tests.dap, stops in the body of Math > doubles) shows test "doubles" where it showed closure; the
    frame after a step out shows it too. sh tools/debug.sh.
  • The frame of a group body is named group "<name>" the same way (group "Math" in that session), nested
    groups each with their own name. Proof: the same session.
  • A closure that is not a test or group body keeps its name (closure), and so does a frame whose call site cannot
    be resolved (fallback to the chunk name, never ? or a crash). Proof: a case in compiler/tests/debugger.test.trb
    that stops in an ordinary closure and in a test body whose name is computed.
  • docs/design/DEBUGGER.md section 20 drops the point, section 10 says how frames are named, and
    docs/tooling/torb-debug.md (stackTrace row) mentions the names; torb docs skill --check stays clean.

Design (decided by the loop, see the comment)

  • Where: compiler/src/debugger/debuggee.trb. frameNameOf is computed once per chunk in sessionOf, which cannot
    know a run-time name. stackTraceOf resolves the name per frame instead: a frame that is the outermost frame of a
    call-back loop (vm/debug.trb framesOf) and whose chunk is a closure gets the name read from the frame below it,
    whose statement holds the kernel call of the native torb_test_case / torb_test_group (operand 1 is the name
    text, read through the same value reader variables uses). Anything else keeps frameNames.
  • No runtime C change, no new native, no new kernel operation, no change to the instruction set or the IR.

Seed

Does not touch the seed: no syntax, no new native, no driver flag, no std name the compiler looks up by string (the
debugger reads the existing natives torb_test_case and torb_test_group by their position in the natives table).

Size and model

One PR, one commit, feat(debugger): name the frames of test and group bodies, with the session update and the docs.
Tier A only (no ir, backend or runtime file). Implementer: opus/high (it reads VM frames and registers).

Dependencies

None.

Moved from the planning lists of the docs; the design record stays the specification.

## Context A test body runs as a closure the test runner calls back, so its frame in `stackTrace` is named `closure` (the chunk's label), and the body of a `group` is `closure` too. A client sees `double` / `closure` / `closure` / `math.test.trb` (the session `tests/debug/tests.dap`) and cannot tell which test it stopped in. ## Source - [DEBUGGER.md section 20](https://git.torb.dev/torbscript/language/src/commit/393ef2608e4a60b8ff76d8b6b408951b822d887d/docs/design/DEBUGGER.md#L420) (the open point "Test names on closure frames"); frames and locals are section 10. ## Acceptance criteria - [ ] A test body's frame is named `test "<name>"` with the name the test was given at run time, so a test created in a loop (`test "case {n}" { ... }`, one chunk, many names) shows its own name. Proof: `tests/debug/tests.expected` (session `tests.dap`, stops in the body of `Math > doubles`) shows `test "doubles"` where it showed `closure`; the frame after a step out shows it too. `sh tools/debug.sh`. - [ ] The frame of a `group` body is named `group "<name>"` the same way (`group "Math"` in that session), nested groups each with their own name. Proof: the same session. - [ ] A closure that is not a test or group body keeps its name (`closure`), and so does a frame whose call site cannot be resolved (fallback to the chunk name, never `?` or a crash). Proof: a case in `compiler/tests/debugger.test.trb` that stops in an ordinary closure and in a test body whose name is computed. - [ ] `docs/design/DEBUGGER.md` section 20 drops the point, section 10 says how frames are named, and `docs/tooling/torb-debug.md` (`stackTrace` row) mentions the names; `torb docs skill --check` stays clean. ## Design (decided by the loop, see the comment) - Where: `compiler/src/debugger/debuggee.trb`. `frameNameOf` is computed once per chunk in `sessionOf`, which cannot know a run-time name. `stackTraceOf` resolves the name per frame instead: a frame that is the outermost frame of a call-back loop (`vm/debug.trb` `framesOf`) and whose chunk is a closure gets the name read from the frame below it, whose statement holds the `kernel` call of the native `torb_test_case` / `torb_test_group` (operand 1 is the name text, read through the same value reader `variables` uses). Anything else keeps `frameNames`. - No runtime C change, no new native, no new kernel operation, no change to the instruction set or the IR. ## Seed Does not touch the seed: no syntax, no new native, no driver flag, no std name the compiler looks up by string (the debugger reads the existing natives `torb_test_case` and `torb_test_group` by their position in the natives table). ## Size and model One PR, one commit, `feat(debugger): name the frames of test and group bodies`, with the session update and the docs. Tier A only (no `ir`, `backend` or `runtime` file). Implementer: opus/high (it reads VM frames and registers). ## Dependencies None. _Moved from the planning lists of the docs; the design record stays the specification._
Author
Collaborator

[loop:torbscript] intake: in scope (author orion, label loop), source DEBUGGER.md section 20, not a duplicate, no collision with a design record. Small debugger fix (frame naming of a test body); likely sonnet/medium. next: refine, waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z

[loop:torbscript] intake: in scope (author orion, label loop), source DEBUGGER.md section 20, not a duplicate, no collision with a design record. Small debugger fix (frame naming of a test body); likely sonnet/medium. next: refine, waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z
Author
Collaborator

[loop:torbscript] claim refine by session:loop-torbscript-20261010 until 2026-10-10T00:20Z (the earlier 'ready buffer full' wait named #4, #163 and #223, which are closed; the ready issues still open are all in flight or blocked on a seed or on PR #282)

[loop:torbscript] claim refine by session:loop-torbscript-20261010 until 2026-10-10T00:20Z (the earlier 'ready buffer full' wait named #4, #163 and #223, which are closed; the ready issues still open are all in flight or blocked on a seed or on PR #282)
Author
Collaborator

[loop:torbscript] refine: ready, a test body's frame shows test "<name>" and a group body's group "<name>" (names read at run time, ordinary closures keep closure), next: implement

Acceptance criteria and design are in the issue body: (1) test frame named by its run-time name, proved by tests/debug/tests.expected (sh tools/debug.sh); (2) group frame likewise; (3) ordinary closure and unresolvable call site keep the chunk name, proved in compiler/tests/debugger.test.trb; (4) DEBUGGER.md section 20/10 and torb-debug.md updated, skills check clean.

Seed: not touched. Size: one PR, one commit feat(debugger): name the frames of test and group bodies, tier A. Model: opus/high.

[loop:torbscript] decided by the loop: the name is read per frame at stop time and not per chunk at session start. Today frameNameOf (debuggee.trb) runs once per chunk and a test body is an anonymous closure chunk labelled closure; the name is a run-time argument of the native test, so a test made in a loop shares one chunk across many names. A static lookup of string literals at the call site was rejected for that reason (wrong or empty for computed names). The call-back runs the body from torb_machine_test_case, so in framesOf the frame below the body's loop is the one whose statement holds the torb_test_case / torb_test_group kernel call; its text operand is the name. This needs no C runtime change, no new native and no kernel operation, so no seed work. The test "..." / group "..." form (not the bare name) is chosen so a test named like a function is not mistaken for one in the call stack.

[loop:torbscript] refine: ready, a test body's frame shows `test "<name>"` and a group body's `group "<name>"` (names read at run time, ordinary closures keep `closure`), next: implement Acceptance criteria and design are in the issue body: (1) test frame named by its run-time name, proved by `tests/debug/tests.expected` (`sh tools/debug.sh`); (2) group frame likewise; (3) ordinary closure and unresolvable call site keep the chunk name, proved in `compiler/tests/debugger.test.trb`; (4) DEBUGGER.md section 20/10 and torb-debug.md updated, skills check clean. Seed: not touched. Size: one PR, one commit `feat(debugger): name the frames of test and group bodies`, tier A. Model: opus/high. [loop:torbscript] decided by the loop: the name is read per frame at stop time and not per chunk at session start. Today `frameNameOf` (debuggee.trb) runs once per chunk and a test body is an anonymous closure chunk labelled `closure`; the name is a run-time argument of the native `test`, so a test made in a loop shares one chunk across many names. A static lookup of string literals at the call site was rejected for that reason (wrong or empty for computed names). The call-back runs the body from `torb_machine_test_case`, so in `framesOf` the frame below the body's loop is the one whose statement holds the `torb_test_case` / `torb_test_group` kernel call; its text operand is the name. This needs no C runtime change, no new native and no kernel operation, so no seed work. The `test "..."` / `group "..."` form (not the bare name) is chosen so a test named like a function is not mistaken for one in the call stack.
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261010 until 2026-10-10T04:24Z

[loop:torbscript] claim implement by session:loop-torbscript-20261010 until 2026-10-10T04:24Z
argus closed this issue 2026-10-10 00:18:25 +00:00
Author
Collaborator

[loop:torbscript] implement: PR #289, CI green (08e2eac6; the first run's tier B failed only in the unrelated runtime IO test test_io_a_cancelled_wait_releases_its_registration, the rerun passed), worker usage unknown, next: waiting (review by the merge gate argus)

[loop:torbscript] implement: PR https://git.torb.dev/torbscript/language/pulls/289, CI green (08e2eac6; the first run's tier B failed only in the unrelated runtime IO test test_io_a_cancelled_wait_releases_its_registration, the rerun passed), worker usage unknown, next: waiting (review by the merge gate argus)
Sign in to join this conversation.
No labels
loop
ready
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#44
No description provided.