Skip to content

fix(app): snapshot the session before spawning background goroutines - #4230

Merged
aheritier merged 1 commit into
mainfrom
fix/app-session-snapshot
Sep 11, 2026
Merged

fix(app): snapshot the session before spawning background goroutines#4230
aheritier merged 1 commit into
mainfrom
fix/app-session-snapshot

Conversation

@aheritier

Copy link
Copy Markdown
Collaborator

Fixes #4229.

Why

go test -race -shuffle=on ./pkg/tui (the test-race job from #4221) still fails about one run in five on TestLoadSessionThenClickEditLabel after #4228. The race detector points at pkg/app: App.ReplaceSession writes a.session from the bubbletea update loop while the goroutine started by App.Start reads it to call EmitStartupInfo. reEmitStartupInfo and RunSkillFork hand a.session to their goroutines the same way. This is a production race, not a test artifact.

What

  • Start, reEmitStartupInfo and RunSkillFork now read a.session on the caller's goroutine and pass the value to the background work, the way Run / RunWithMessage already do. ReplaceSession re-emits startup info for the new session itself, so emitting for the snapshotted session is the intended behavior.
  • New TestAppBackgroundWorkSnapshotsSessionBeforeReplace drives each of the three entry points, calls ReplaceSession right after, and asserts both sessions reach the runtime. Without the fix it fails deterministically under -race (7 race reports across the three subtests).

Verification

  • go test -race -count=3 ./pkg/app: clean.
  • go test -race -count=10 -run TestLoadSessionThenClickEditLabel ./pkg/tui: clean (was ~1 in 5 failing).
  • task lint passes.

Independent of #4228; the two together make test-race green.

Start, reEmitStartupInfo and RunSkillFork read a.session from inside
the goroutines they spawn, which races with ReplaceSession writing the
field from the bubbletea loop. The race detector caught it about one run
in five in TestLoadSessionThenClickEditLabel, failing the test-race CI
job. Read the field on the caller's goroutine and hand the value to the
background work, as Run already does; ReplaceSession re-emits startup
info for the new session itself. Adds a regression test that covers all
three entry points and fails deterministically under -race without the
fix.

Fixes #4229
@aheritier
aheritier requested a review from a team as a code owner September 10, 2026 16:30
@aheritier aheritier added kind/fix PR fixes a bug (maps to fix:). Use on PRs only. status/needs-triage For issues that need to be triaged labels Sep 10, 2026
@aheritier
aheritier enabled auto-merge September 10, 2026 16:32
@aheritier aheritier added the area/core Core agent runtime, session management label Sep 10, 2026
@aheritier
aheritier added this pull request to the merge queue Sep 11, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 11, 2026
@aheritier
aheritier added this pull request to the merge queue Sep 11, 2026
Merged via the queue into main with commit e853b6e Sep 11, 2026
16 checks passed
@aheritier
aheritier deleted the fix/app-session-snapshot branch September 11, 2026 08:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Core agent runtime, session management kind/fix PR fixes a bug (maps to fix:). Use on PRs only. status/needs-triage For issues that need to be triaged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Data race on App.session between Start's startup-info goroutine and ReplaceSession

2 participants