Repository navigation
fix(web): follow a new thread when the first send's reply is lost - #503
Merged
Merged
Conversation
When the connection dropped after the server received a new thread's first send but before it replied, the draft reserved a fresh thread id and restored the prompt. The client could no longer match the thread the server created, so after reconnecting it stayed on the draft with the sent prompt still in the composer. The draft now reserves a fresh id only when the server rejected the bootstrap. After a transport failure it keeps its id, follows the thread once its turn syncs, and clears the restored prompt if it was not edited. Written by an agent (Claude Code, claude-opus-5-5).
Upstream `pingdotgg#11372` keeps a new thread's bootstrap running after the requesting client disconnects. Written by an agent (Claude Code, claude-opus-5-5).
incognitojam
added a commit
that referenced
this pull request
Sep 29, 2026
Release notes listed every commit since the previous release, so docs, CI, and intake bookkeeping commits such as #527 appeared next to app changes. The desktop update popover renders the same notes, so users saw them there too. ## Change `render_release_notes` now lists a commit only when it changes shipped code: a file under `apps/web`, `apps/desktop`, `apps/mobile`, `apps/server`, `packages/`, or `patches/`, excluding tests, test fixtures and helpers, `scripts/` folders, integration suites, and Markdown. The remaining commits are counted on the Full Changelog line: ``` **Full Changelog**: https://github.com/incognitojam/styal/compare/…430...…431 (includes 6 docs, CI, test, and tooling changes not listed above) ``` The desktop updater already skips the Full Changelog line, so the count does not appear as a change in the popover. Nightly and stable releases share the renderer, so both get the filter. The rule uses changed paths rather than the commit subject. #38 removed an earlier subject-based filter because it could hide user-facing changes made in `ci` or release commits; with paths, a `ci(release)` commit that changes desktop code is still listed. Relay changes are not listed because the relay deploys from `main` through `deploy-relay.yml`, not with releases. ## Validation - Rendered notes with the new function against the real tags for three published nightlies and compared them with the published bodies: - `v0.1.0-nightly.20260928.430`: only the web fix (#503) remains; `docs(agents)` #505 and `chore(upstream)` #506 are counted instead. - `v0.1.0-nightly.20260928.431`: 6 commits dropped, all `ci` and `chore(upstream)`, including #527. - `v0.1.0-nightly.20260926.422`: 15 dropped. Apart from docs, CI, tests, and intake bookkeeping, these are three `infra/relay` fixes and two upstream macOS installer artwork cherry-picks that are empty in the fork (their intake notes say "Not applied"), so the published notes listed changes that were not in the build. - Ran the rendered notes for nightly 430 through `normalizeDesktopUpdateReleaseNotes`, as Markdown and as GitHub-rendered HTML. Both produce the single listed change and no count item. - `vp test run scripts/release-changelog.test.ts` (36 passed): path classification cases, a mixed fork and upstream render with the omitted count, and a release where every commit is internal. - Not verified: a full nightly or stable workflow run with this change. Still listed: version bump commits (`chore(release): prepare …`, `chore(mobile): bump app version`) and refactors, because they change app files. Commits that change only the lockfile are not listed. --- Written by an agent (Claude Code, claude-opus-5-5).
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.
Note
If the connection drops after the server receives a new thread's first message but before it replies, the web client stayed on the draft with the sent prompt still in the composer. It now follows the thread once it reconnects and clears the restored prompt.
Problem
When the first send from a new-thread draft fails, the web client restores the prompt. Since #195 it also gives the draft a fresh thread id after any failure that is not an interrupt, including a dropped socket. #195 meant to do this only after a definitive bootstrap failure. After a transport failure the server may have created the thread, turn and worktree already. The draft then pointed at a different id, so after reconnecting the client could not match the thread the server created and stayed on the draft with the sent prompt in its composer. The error was set on the discarded id and transport errors are hidden, so nothing explained it.
This was seen with a Mac client dispatching a new thread to a remote host: the host's database shows the thread created and its turn started within two seconds, while the client showed a reconnecting banner and never cleared the composer or switched to the thread.
Fix
OrchestrationDispatchCommandError), which is the case fix(web): preserve drafts after thread bootstrap failure #195 handled and matches upstream. After a transport failure the draft keeps its id, so the existing draft promotion follows the thread once its turn syncs.The server can still abandon a bootstrap partway when it notices the disconnect before finishing, leaving a thread with no turn. In that case the client keeps the prompt and stays on the draft. Upstream pingdotgg#11372 makes the bootstrap outlive the requesting connection, so it is added to the tracked upstream PRs. Mobile's outbox already waits for the shell to resync and checks whether the thread exists; desktop inherits the web client.
Validation
A headless browser used a worktree dev server through a TCP proxy that can stop server-to-client traffic on the app WebSocket. From a new-thread draft in New worktree mode: stop replies, send, wait for the server to create the thread and start the turn, cut the socket, and let the client reconnect.
apps/web/src/composerDraftStore.test.tscovers clearing the restored prompt after an unrelated store write replaces the draft object, and keeping it when the user edited it. The first test fails without the fix.Not tested: a desktop client connected to a remote host through styal Link; the browser run exercises the same client code.
Written by an agent (Claude Code, claude-opus-5-5).