Skip to content

Commit 642a90b

Browse files
committed
Fix(abctl): keep the innermost exchange's corners in deeply-nested spans
A request/response pair nested three or more levels deep — e.g. a tools/list pair inside an a2a message/stream span inside a long-lived $transport/stream span — rendered "││" on both rows instead of "│┌" / "│└", so the pair didn't read as connected. computeSpanGlyphs caps the PHASE prefix at two levels and was picking the two WIDEST enclosing spans, whose middle bars masked the row's own corner. Pick the inner glyph from the row's NARROWEST containing span (its own tightest exchange) instead of the second-widest, so an endpoint of a deeply-nested pair always shows its ┌/└ corner. The outer glyph still shows the broadest enclosing span for context. Adds a triple-nested test case covering exactly this shape. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
1 parent 6cc58fe commit 642a90b

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

authbridge/cmd/abctl/tui/events_pane.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -615,15 +615,24 @@ func computeSpanGlyphs(pairs map[int]int, n int) []spanLevels {
615615
if len(participating) == 0 {
616616
continue
617617
}
618-
// Sort by width descending — outer (widest) first, then inner. Stable
619-
// so equal-width spans keep declaration order (deterministic tests).
618+
// Sort by width descending — widest first, narrowest last. Stable so
619+
// equal-width spans keep declaration order (deterministic tests).
620620
sort.SliceStable(participating, func(p, q int) bool {
621621
return (participating[p].b - participating[p].a) >
622622
(participating[q].b - participating[q].a)
623623
})
624+
// outer = the widest containing span (the broadest context). inner =
625+
// the NARROWEST containing span — the row's own tightest exchange —
626+
// NOT the second-widest. A row that is an endpoint of a deeply-nested
627+
// pair must still show its ┌/└ corner so its request and response
628+
// connect visually; picking the second-widest would let an
629+
// intermediate enclosing span's middle bar mask it. Example: a
630+
// tools/list pair nested inside both an a2a message/stream span and a
631+
// long-lived $transport/stream span would otherwise render "││" on
632+
// both rows instead of "│┌" / "│└".
624633
out[i].outer = glyphAt(participating[0], i)
625634
if len(participating) > 1 {
626-
out[i].inner = glyphAt(participating[1], i)
635+
out[i].inner = glyphAt(participating[len(participating)-1], i)
627636
}
628637
}
629638
return out

authbridge/cmd/abctl/tui/events_pane_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,28 @@ func TestComputeSpanGlyphs(t *testing.T) {
685685
outer(glyphEnd),
686686
},
687687
},
688+
{
689+
// The #52 case: a pair (2,3) nested THREE deep — inside a middle
690+
// span (1,4) inside an outer span (0,5). The innermost pair's
691+
// endpoints must still show their ┌/└ corners (so its req/resp
692+
// connect) rather than the middle span's bar masking them. inner =
693+
// the row's narrowest containing span, not the second-widest.
694+
name: "triple-nested innermost pair keeps its corners",
695+
pairs: map[int]int{
696+
0: 5, 5: 0,
697+
1: 4, 4: 1,
698+
2: 3, 3: 2,
699+
},
700+
n: 6,
701+
want: []spanLevels{
702+
outer(glyphStart), // 0: outer starts
703+
both(glyphMiddle, glyphStart), // 1: outer mid, middle-span starts
704+
both(glyphMiddle, glyphStart), // 2: outer mid, innermost STARTS (was masked to middle)
705+
both(glyphMiddle, glyphEnd), // 3: outer mid, innermost ENDS (was masked to middle)
706+
both(glyphMiddle, glyphEnd), // 4: outer mid, middle-span ends
707+
outer(glyphEnd), // 5: outer ends
708+
},
709+
},
688710
}
689711
for _, tc := range cases {
690712
t.Run(tc.name, func(t *testing.T) {

0 commit comments

Comments
 (0)