Fix mcp permissions render clipping (#1424)#1425
Merged
Aaronontheweb merged 9 commits intoJun 17, 2026
Merged
Conversation
ScrollableContainerNode.Render in Termina 0.12.1 ignores bounds.Y and writes relative to context (0,0). When hosted directly in a VerticalLayout the scroll container always writes starting at terminal row 0, overwriting the header and server-info rows above it. Fix: wrap the scroll container in a borderless PanelNode. PanelNode.Render calls context.CreateSubContext(bounds) before passing the context down, so the inner context is already offset to the correct screen position. Secondary fix: footer hint TextNodes now use .NoWrap() + .WidthAuto() on the status indicator so the hints line stays on one row instead of wrapping when the HorizontalLayout divides width equally. Regression test added: ToolGrid_ManyTools_HeaderRowsNotOverwrittenByScrollContent uses 15 tools on a 40-row VirtualTerminal — enough to reproduce the overwrite — and asserts MCP Permissions, Audience, and Server default are all visible simultaneously.
Code fixes from review: - EnsureToolCursorVisible: reset stale ScrollOffset to 0 when MaxScroll drops to 0 (e.g. after terminal resize or tool-list shrink). The old early return left a nonzero offset in place, clipping the top rows even though all tools fit in the viewport. - BuildFooter: apply .NoWrap() to all footer paths — the _confirmingSave branch and the non-ToolGrid fall-through at the end of the lambda were missing it. The first commit only applied NoWrap to the three ToolGrid status-indicator branches. - BuildFooter: extract BuildToolGridFooterWithStatus helper to eliminate the three near-identical Layouts.Horizontal() blocks. Any future footer layout change now only needs to happen in one place. Screenshot smoke test: - Add tests/smoke/tapes/screenshots/mcp-permissions.tape — captures the mcp-permissions page in whatever state the runner sees (Loading when no daemon, ServerList when one is present) as a PNG baseline. Registered in run-smoke.sh SHOT_TAPES/SHOT_FRAMES as 'mcp-permissions-loading'. The first CI screenshots run will generate the .approved.png baseline.
Generated from first CI screenshots run (no-daemon Loading state): header panel at row 0, connection-refused error body below it. Matches the deterministic frame described in mcp-permissions.tape.
Cold-cache runs (fresh Ollama install + 350 MB model pull + ffmpeg apt deps) consume ~25 min of setup before the VHS tapes even start. The previous 30-minute limit caused a cancellation on cache-cold runners. Native Smoke already uses 45 min; align Screenshot Regression to match.
The netclawd image build on a cold runner consistently takes ~19-20 min, leaving no margin under the previous 20-minute limit. The job was intermittently cancelled at exactly the timeout boundary. 30 minutes gives a 10-minute safety margin for cold-cache builds.
The previous screenshot tape captured only the no-daemon Loading state,
which showed a header and an error message but none of the actual
permissions UI. Replaced with two meaningful frames:
mcp-permissions-server-list — ServerList state with smoke-math shown
as Connected, 3 tools. Confirms the header renders at row 0 with real
daemon data beneath it.
mcp-permissions-tool-grid — ToolGrid with all header rows (Server,
Audience, Server enabled, Server default) and all three tool rows
(add, echo, record-tasks) visible simultaneously. This directly
exercises the render fix for issue netclaw-dev#1424: if ScrollableContainerNode
regresses and ignores bounds.Y, the tool rows will overwrite the header
rows in the screenshot.
The tape now starts the daemon and registers Netclaw.SmokeMcpServer
(smoke-math, 3 tools) before launching the TUI.
run-native-tape.sh: extend the sed substitution pass to cover both the
preamble and the body file, so tape bodies can use __TOKENS__ too (needed
here for __NETCLAW_SMOKE_MCP_SERVER__).
Baselines removed: the stale mcp-permissions-loading.approved.png is
deleted. CI will generate the two new baselines on the first screenshots
run.
ServerList frame: smoke-math appears as Connected, 3 tools. ToolGrid frame: Server/Audience/Server-enabled/Server-default header rows plus add/echo/record-tasks tool rows all visible simultaneously — the direct regression check for netclaw-dev#1424 (scroll container must not overwrite header rows).
This was referenced Jun 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
netclaw mcp permissionsrender bug on 0.24.0-beta.5 #1424):ScrollableContainerNode.Render()in Termina 0.12.1 ignoresbounds.Y, always writing at context(0,0). When the tool list was tall enough, the scroll container overwrote the page header rows._toolScrollNodein a borderlessPanelNode.PanelNode.Render()callscontext.CreateSubContext(bounds)before delegating to its content, so the scroll container now receives a properly-offset render context..NoWrap()+.WidthAuto()to footerTextNodes so they never expand to Fill-width, which caused hint text to wrap on narrower terminals.McpToolPermissionsPageTests.ToolGrid_ManyTools_HeaderRowsNotOverwrittenByScrollContent— 15 tools on a 40-rowVirtualTerminal, asserts header rows and tool rows are all visible simultaneously.ScrollOffsetreset whenMaxScrolldrops to 0;.NoWrap()applied to all footer paths; extractedBuildToolGridFooterWithStatushelper.tests/smoke/tapes/screenshots/mcp-permissions.tapeand registered it inrun-smoke.sh. The approved baseline will be committed after the first CI screenshots run.Test plan
dotnet test --filter McpToolPermissionsPageTests→ 13/13 passdotnet slopwatch analyze→ 0 violations./scripts/Add-FileHeaders.ps1 -Verify→ all files have headers./scripts/smoke/run-smoke.sh mcp-permissionspassesmcp-permissions-loading.actual.png→ human reviews → commits astests/smoke/screenshots/mcp-permissions-loading.approved.png