Skip to content

Offer explicit fresh-shell recovery after session loss - #74

Merged
R055LE merged 2 commits into
mainfrom
fresh-shell-recovery
Oct 2, 2026
Merged

R055LE merged 2 commits into
mainfrom
fresh-shell-recovery

Conversation

@R055LE

@R055LE R055LE commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Changes

  • Distinguish a reported shell exit or unreported channel end from transport loss. Keep the
    available transcript visible with copy-only command actions and an explicit Start fresh shell.
  • Keep the original endpoint, username, identity, selected key or key URI, and ephemeral choice
    as credential-free connection metadata. Recovery opens sign-in again and uses current host-key
    verification. It never reconnects or replays a command automatically.
  • Say that directory, exports, aliases, functions, and remote processes are not restored. A remote
    process may still be running; recovery does not claim it was killed or resumed.
  • Finish old output/monitor/connection cleanup before resetting the terminal and opening a new
    session/archive. Discard abandoned queued input so it cannot fill the fresh bootstrap slot.
    Guard stale input, resize, and disconnect events against the current session.
  • Preserve raw-terminal access when shell integration alone fails.

Transport-loss finding

The new real Android/OpenSSH regression crashed the app with sshlib 0.4.2: a Broken pipe escaped
the receive-window delivery coroutine at SessionChannel.deliverData / sendWindowAdjust.
That separate library coroutine bypasses the application's output-reader error handling (#73).

Use the released sshlib 0.5.0 writer/teardown path. Keep the previous 64 KiB receive-window bound
explicitly. All 31 added SHA-256 pins match fresh Maven Central downloads and their published
checksums; existing pins and verification configuration are preserved. Strict verification passed.

Validation

  • Before the lifecycle change, the new ended shell releases its transport before another connection regression timed out waiting for transport cleanup.
  • ./gradlew --no-daemon test lint assembleDebug assembleRelease assembleDebugAndroidTest passed:
    114 local JVM tests, zero failures. The three opt-in SSH JVM tests skip without fixture credentials.
  • ./scripts/verify-release-shrinker-contracts.sh passed.
  • ./fixtures/openssh/test-adapter.sh: all three real JVM adapter tests passed with 0.5.0.
  • ./fixtures/openssh/test-android-structured.sh: all five real Android SSH tests passed, including
    encrypted imported-key authentication, existing structured/raw command behavior, replies,
    bootstrap downgrade, exit, exec, strict failure, and transport loss. Recovery exercised nine
    failure/reconnect cycles, including five 128 KiB output bursts followed by an abrupt drop.
    Each cycle retained its own archive, started in a fresh shell, and sent only bootstrap on reconnect.
  • All seven SessionRecoveryTest Compose tests passed: read-only context and explicit action at
    200% font scale, distinct network state, raw downgrade, original key/username selection even
    after identity edits, permission recovery, fresh saved-password unlock, and cleared manual password.
  • Unit tests also prove changed-key blocking on a new connection, new archive IDs, waiting through
    an overlapping failed service preparation, stale-event isolation, and no command replay. The new
    full-input-queue regression first timed out waiting for the fresh bootstrap; discarding abandoned
    queued input makes it pass.
  • Full local connectedDebugAndroidTest: 139 test cases, zero failures, nine prerequisite or
    opt-in skips. The five real SSH fixture tests were run separately with their prerequisites.

The first CI attempt on final head 522baa9 passed the JVM, lint, debug/release build, and release
shrinker checks, then timed out in four existing Android IME-visibility tests. The preceding revision
passed CI with the same UI/test sources, and both full local Android suites passed. The four methods
also passed together on a restarted local emulator with the hardware-keyboard IME policy disabled;
that hypothesis did not reproduce the failure. The cause remains unconfirmed and is tracked in #75.
The same-commit CI rerun
passed the complete verification job on 522baa9, including the Android suite. The
first failed attempt
remains linked in #75; the green retry does not establish why its keyboard was missing.
Signed physical-phone acceptance has not been run.

Closes #50.
Closes #73.

@R055LE
R055LE merged commit 8b24e1b into main Oct 2, 2026
1 of 2 checks passed
@R055LE
R055LE deleted the fresh-shell-recovery branch October 2, 2026 03:09
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.

Handle abrupt SSH transport loss without a window-update crash Offer explicit fresh-shell recovery after shell exit or network loss

1 participant