Skip to content

attach: stop nudging a child that is already the right size; remove --no-resize - #109

Merged
myobie merged 4 commits into
mainfrom
schickling-assistant/skip-nudge-when-size-matches
Jul 20, 2026
Merged

attach: stop nudging a child that is already the right size; remove --no-resize#109
myobie merged 4 commits into
mainfrom
schickling-assistant/skip-nudge-when-size-matches

Conversation

@schickling-assistant

@schickling-assistant schickling-assistant commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Now carries #110 as well, so this is the whole thing against main: remove geometry-neutral attach, and stop nudging a child that is already the right size.

The nudge

nudgeRedraw() (resize to cols - 1 and back) fired on every attach. Its purpose is to paper over serialize-replay artifacts, but when a client attaches at exactly the size the session already has, the child is by definition already drawn for that geometry — so the nudge buys nothing and just delivers SIGWINCH to an otherwise idle process every time someone connects.

It now fires only when the attaching client's geometry differs from the session's. The comparison is read before negotiateSize(): a smaller client shrinks the session to its own size, which would otherwise look like it had matched by the time the decision is made. That case still nudges, as it should.

--no-resize goes away

You asked whether fractal's embedded pane was read-only-with-crop or typed-into-while-cropped, and noted that read-only is already geometry-neutral so the feature wouldn't be strictly needed in the first case. The honest answer turned out to be that it isn't needed in either.

Fractal reads the session's geometry from pty stats and opens its attach client at that size, cropping into the pane — it never reports the pane's dimensions. A client whose geometry equals the session's is inert in negotiateSize() by construction. So the geometry half of the neutral role was already a no-op for its only consumer.

The 80×24 justification in #95 was a fractal defect — it launched pty attach over pipes — not a pty gap, and it has since been fixed on our side by giving the attach client a real PTY. What genuinely remained was the nudge, which is fixed above for every client rather than through an opt-in role.

What that leaves

The ATTACH frame goes back to a plain 4-byte payload. ATTACH_FLAG_GEOMETRY_NEUTRAL, decodeAttachFlags, the geometryNeutral client field, capabilities.geometryNeutralAttach, clients.geometryNeutral, requireGeometryNeutralAttach(), and tests/neutral-attach-cli.test.ts are all gone. cmdAttach / doAttach return to their pre-#96 signatures.

Net against main: about 230 lines removed, ~10 added.

I did briefly add the --force-resize flag you offered — then took it out again. You said we can always add it, and nothing needs it today; shipping an unused opt-in flag into your protocol would have repeated exactly the mistake this PR is undoing. If skipping the nudge does regress a child's layout, it's a small change to add then, and I'd rather that be driven by a real case.

Verification

npm run typecheck clean. protocol, integration, completions suites pass. Integration coverage: an ordinary attach at the session's current size produces no SIGWINCH in a quiescent child, and a client attaching at a different size still nudges.

Unrelated pre-existing failures in my environment (all also present on main): shells.test.ts and screenshot.test.ts need zsh / vim, which aren't installed here, and help.test.ts reports the completions command from #106 as undocumented.

schickling-assistant and others added 2 commits July 20, 2026 20:59
…ght size

The attach-time nudge (resize to cols-1 and back) exists to paper over
serialize-replay artifacts. It fired on every attach, so connecting a
viewer delivered SIGWINCH to an otherwise idle child — including the
common case where the client attaches at exactly the size the session
already has, where the child is by definition already drawn correctly.

Nudge only when the attaching client's geometry differs from the
session's, read before negotiateSize() so a smaller client that shrinks
the session doesn't then look like it matched. `--force-resize` opts
back in for children whose replay needs the redraw regardless.

encodeAttach() now takes a flags bitmask rather than a geometryNeutral
boolean, and the attach CLI path passes an AttachModes object instead of
a fourth positional boolean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lw7FSfYArhebq26GUb1kHi
`pty attach --no-resize` (PR #96) let an interactive client receive the
live screen and send input while opting out of min-wins size negotiation
and the attach-time redraw SIGWINCH nudge. Its only consumer, fractal, is
switching off it.

The real problem fractal hit was the unconditional nudge on attach: every
connect woke an idle child and perturbed the shared session. The parent
commit fixes that directly — the nudge is now skipped when the client
attaches at the size the session already has, with `--force-resize` to opt
back in for children whose serialize replay needs the redraw regardless.
That covers fractal's case without a second attach mode, so fractal now
attaches ordinarily at the session's own geometry.

Removes the ATTACH_FLAG_GEOMETRY_NEUTRAL protocol flag, the per-client
`geometryNeutral` state and its stats counter, the
`capabilities.geometryNeutralAttach` advertisement and the CLI's
capability probe, and the `--no-resize` flag with its help and completion
entries. ATTACH_FLAG_FORCE_RESIZE keeps its released value of 0x02; 0x01
is retired rather than reused.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lw7FSfYArhebq26GUb1kHi
schickling and others added 2 commits July 20, 2026 22:23
…ove-geometry-neutral-attach

refactor(attach): remove geometry-neutral attach (--no-resize)
`--force-resize` was added alongside the conditional attach-time redraw
nudge as an escape hatch, but nothing ever asked for it: no caller, no
consumer, no reported child whose serialize replay actually needed the
unconditional nudge. It was speculative surface, and it dragged an
entire protocol mechanism along with it.

Removing it lets the ATTACH frame go back to a plain 4-byte payload --
no optional flag byte, no `decodeAttachFlags`, no flag constants, no
`AttachModes` plumbing through `cmdAttach`/`handleDeadSession`/
`doAttach`. `encodeAttach(rows, cols)` is once again exactly what it
looks like.

What remains is the branch's whole net effect: one behaviour fix. The
attach-time redraw nudge fires only when the attaching client's
geometry differs from the session's, so connecting a viewer at the
current size no longer delivers SIGWINCH to an idle child.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lw7FSfYArhebq26GUb1kHi
@schickling-assistant schickling-assistant changed the title perf(attach): skip the redraw nudge when the client is already the right size attach: stop nudging a child that is already the right size; remove --no-resize Jul 20, 2026
@schickling
schickling marked this pull request as ready for review July 20, 2026 21:29
@schickling
schickling requested a review from myobie July 20, 2026 21:29
@myobie
myobie merged commit 69ceabb into main Jul 20, 2026
1 check passed
@myobie
myobie deleted the schickling-assistant/skip-nudge-when-size-matches branch July 20, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants