feat(config): deprecate list.task-timeout-ms - #3615
Merged
Merged
Conversation
The per-task timeout killed any git command that outlived the budget, on every collect worker, through a thread-local that `Cmd::run` consulted on each invocation and clamped an explicit `.timeout()` against. Progressive rendering removed the reason for it: `wt list` and the picker paint from local data and stream results in behind the frame, so no single git command can hold up the first paint. What it bounded instead was completion, which `[list] timeout-ms` already bounds directly, and the drain falls back to a hardcoded 120s when that is unset. A config carrying the key loads and warns; `wt config update` strips it. Sibling keys, including `timeout-ms`, are untouched. The env and `--config-set` layers migrate through the same rule, silently, as they have no file to materialize. With the thread-local gone, `Cmd::run` reads only the command's own `self.timeout`, so every explicit `.timeout()` caller (remote detection, fsmonitor teardown, the version check) keeps its bound unclamped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
worktrunk-bot
approved these changes
Jul 26, 2026
Merged
max-sixty
added a commit
that referenced
this pull request
Jul 29, 2026
Cuts 0.70.0 — version bump plus the changelog for the 45 commits since v0.69.2. **Minor bump, not patch.** `cargo semver-checks` reports 6 breaking library changes (`set_command_timeout` and `ListConfig::task_timeout_ms` removed, `WorkingTree::stage` arity changed, three enum variants added to exhaustive enums). Worktrunk ships breaking library changes freely, but semver still puts a break at minor while pre-1.0. ## Release validation - Local gate green on the release commit: 4631 tests, lints, doctests. - `nightly` dispatched on the cut-from tip (`a27cbd42`) for the full cross-platform suite — `full-tests` green on linux, macOS, and Windows, plus minimal-versions, nix-flake, crate-build, and the release targets. ## Data-loss surface review The cumulative diff was audited against the deletion surface. One deliberate widening, signed off for this release with follow-ups to file: - **#3602** removes the content check from `wt config shell install`'s legacy cleanup, so `conf.d/{cmd}.fish` and the stranded nushell `{cmd}.nu` are now deleted by path, unread. Only that exact filename is touched and each removal is reported, but the deletion is absent from both `--dry-run` and the confirmation prompt, and the already-configured path skips the prompt entirely. Also noted, none blocking: - The `!path.exists()` check precedes the lock guard on the `Path`/`Current` removal arm, so a locked worktree whose directory is absent loses its branch. This already governed the branch-targeted route in v0.69.2; #3533 unified the other arms onto it. The FAQ's "Neither `git worktree remove` nor `wt remove` (even with `--force`) will delete them" is absolute where the behavior isn't. - On the default background removal path, `ensure_clean` and `stop_fsmonitor_daemon` swapped order, so the safety gate is now answered by the live fsmonitor daemon rather than a full re-stat. Bounded by trash staging with 24-hour retention, and the foreground and picker paths were already daemon-served. Net *improvements* to the same surface: shared-branch retention across remove/prune/merge (#3533), outcome-accurate removal reporting (#3633, #3637), and the removal of the thread-local command timeout that could kill in-flight git commands on worker threads (#3615). ## Changelog accuracy Entries were verified against the actual diffs rather than commit messages, which corrected several drafts: the prune figures were one PR stale (~2.9 s → the real ~0.6 s), `wt merge` takes no worktree argument so it only gained the retention half of #3533, the Azure DevOps report is behind `--full`, #3608 never touched `nightly.yaml`, and #3601 inverted what the FAQ change actually said. Two omissions were added — the `install-statusline` foreign-statusline fix (#3595) and the shipped `/wt-switch-create` skill change (#3636). > _This was written by Claude Code on behalf of Maximilian_
1 task
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.
Removes the
[list] task-timeout-msper-task command timeout and the thread-local machinery behind it. The key stops having any effect immediately; a config that still carries it loads, warns, and is stripped bywt config update.The timeout killed any git command that outlived its budget, on every collect worker, through a thread-local that
Cmd::runconsulted on each invocation and clamped an explicit.timeout()against. Progressive rendering removed the reason for it:wt listand the picker paint from local data and stream results in behind the frame, so no single git command can hold up the first paint. What it bounded instead was completion, which[list] timeout-msalready bounds directly, and the drain falls back to a hardcoded 120sDRAIN_TIMEOUTwhenever that is unset (collect/mod.rsdrain_deadline), so removing this cannot introduce an unbounded wait. Both keys default to unset, so the default path never had a per-task timeout at all.[list] timeout-ms, the wall-clock budget for the whole collect phase, stays. It is the surviving knob and the more direct expression of the same goal.With the thread-local gone, the two-source
min()inCmd::runcollapses to the command's ownself.timeout, so every explicit.timeout()caller keeps its bound unclamped:PROBE_TIMEOUTingit/reap.rs, the fsmonitor stop/lsof bounds ingit/remove.rs, the version check inconfig/show.rs, andREMOTE_DETECTION_TIMEOUT.Deprecation
A
Structuralrow inDEPRECATION_RULESstrips the key from[list]in both the section and inline forms, top-level and per-project, following the[switch.picker] timeout-msprecedent (also a strip with no equivalent key to migrate into):The env overlay (
WORKTRUNK__LIST__TASK_TIMEOUT_MS) and--config-setroute through the same rule and migrate silently, since neither layer has a file forwt config updateto materialize. Neither errors.Testing
New unit tests cover detection and migration for the section, inline, and per-project forms plus the warning text, and two cases join the
test_warning_fires_iff_update_changesbattery that pins the warn-iff-update-changes invariant. The three integration tests that exercised the feature are gone;Cmd::timeoutkeeps its own coverage inshell_exec.rs, so dropping the four thread-local unit tests loses nothing for the surviving path. Verified end to end that a config carrying the key loads, warns, and has it stripped bywt config updatewith sibling keys intact.