Skip to content

fix(chat): deregister sessions on session end instead of p.Wait() (#4515) - #4521

Open
dezren39 wants to merge 1 commit into
mainfrom
queue/6430-4515-chat-waiter-ordering
Open

dezren39 wants to merge 1 commit into
mainfrom
queue/6430-4515-chat-waiter-ordering

Conversation

@dezren39

@dezren39 dezren39 commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Closes #4515.

Problem

ProgramHandler spawned go func(){ p.Wait(); a.remove(p) }() before wish runs the program, but Bubble Tea v0.25.0 initializes the finished channel in Run, not NewProgram — an early waiter receives from a nil channel forever, leaking the goroutine and the registry entry (plus a data race on concurrent init). Codex raised this as P2 on #4384 (r4443380736); the PR merged as-is.

Verified empirically: Wait() on a never-run NewProgram program stays blocked past a 300ms grace window (throwaway test, not committed).

Fix

Tie removal to session-context cancellation (watchSession): s.Context() is valid at handler time and the session always outlives the program (wish runs p.Run() synchronously in the session handler per wish@v1.2.0/bubbletea/tea.go), so session-end pruning covers every session with guaranteed startup ordering and zero contact with p.finished.

Tests

  • New TestWatchSessionRemovesOnSessionEnd: watcher started pre-Run deregisters on context cancel, stays registered while live.
  • go test -race -count=1 ./... in pkgs/chat: 4/4 pass. go vet + gofmt clean.

Task: queue task 6430.


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

)

ProgramHandler spawned go func(){ p.Wait(); a.remove(p) }() before wish
runs the program, but Bubble Tea v0.25.0 initializes the finished channel
in Run, not NewProgram — an early waiter receives from a nil channel
forever, leaking the goroutine and the registry entry (plus a data race
on concurrent initialization).

Tie removal to session-context cancellation instead: s.Context() is valid
at handler time and the session always outlives the program (wish runs
p.Run() synchronously in the session handler), so session-end pruning
covers every session with guaranteed startup ordering.

Adds TestWatchSessionRemovesOnSessionEnd.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T18:26:07.687943Z 251d562 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Nov 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 53 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fd087914-7312-4e14-91bd-cf015d45c5a6
Commits

Reviewing files that changed from the base of the PR and between a3a15ba and 251d562.

Files selected for processing: 2
  • pkgs/chat/main.go
  • pkgs/chat/main_test.go
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 251d562bd1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pkgs/chat/main.go
// channel forever (and race with Run's initialization). The session
// always outlives the program (wish runs p.Run() synchronously in
// the session handler), so session-end pruning covers every session.
go a.watchSession(s.Context(), p)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Tie deregistration to the session rather than the connection

When a client keeps its SSH connection open across sessions (for example, with ControlPersist or multiple channels on one Go SSH client), exiting the chat never triggers this cleanup. In the pinned SSH dependency, Session.Context() returns the connection's context, and closing a session only closes its channel. Wish v1.2.0 cancels its own child context after p.Run(), not s.Context(). Consequently, every ended chat on that connection retains its program and watcher and continues receiving broadcast attempts until the entire connection closes. Tie removal to program/session completion instead, and cover a closed session whose underlying connection remains live.

Useful? React with 👍 / 👎.

This branch has not been deployed

No deployments
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.

chat: completion waiter can block forever on p.Wait() before program startup — session never deregistered

1 participant