Skip to content

fix(list): keep [list] columns out of the --format json plan - #3812

Merged
max-sixty merged 4 commits into
mainfrom
fix/issue-3787-json-ignores-columns
Aug 15, 2026
Merged

max-sixty merged 4 commits into
mainfrom
fix/issue-3787-json-ignores-columns

Conversation

@worktrunk-bot

@worktrunk-bot worktrunk-bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Collaborator

Closes the [list] columns half of #3787, per the call in this comment: JSON always emits the same shape, and list.columns only affects the actual columns.

Before, --format json planned all_columns (source Default) unioned with the selection's forced-on columns, so the selection reached JSON in one direction only — it couldn't narrow the emitted fields, but a listed ci did force the forge fetch on without --full. That made a presentation setting decide whether a machine-readable call talks to GitHub, which is the thing the Neovim plugin in #3787 had to pin --config-set 'list.columns=[…]' against. Now the JSON branch plans all_columns alone; --full is the only switch for the gated data, and it's the one a caller controls.

The table and the wt switch picker are untouched — a listed ci still renders the CI column without --full, and the picker still unions the selection in so its table matches wt list's.

Only ci and summary are affected: every other column is ungated, so full_plan() already covered them, and custom columns require no background task.

For the release note — this changes schema 1 too. A caller with [list] columns = […, "ci"] and no --full used to get the ci object in schema-1 JSON and now won't; schema 1 has no collected envelope to say why. The schema-1 ci row already documented `--full` only, so the docs get more accurate, but the observable output changes for anyone who was relying on the forcing path. Schema 2 reports the same narrowing through collected.ci.

Docs updated in after_long_help (the [list] columns section plus the schema-2 pr, summary, and checks rows — summary now names --full alongside [list] summary = true, and checks names the --full gate it shares with pr), with the generated mirrors, dev/config.example.toml, and the --help snapshots regenerated. The CLAUDE.md network inventory and the collect planning comment now record the exemption too.

Test

test_list_json_columns_selection_does_not_force_ci in tests/integration_tests/list_config.rs asserts schema 2's collected.ci across three configs: unset (false), columns = ["branch", "ci"] without --full (false — the regression this fixes), and the same with --full (true). collected records what the plan requested rather than what a fetch returned, so the test needs no forge and no gh on PATH. It sits next to test_list_json_ignores_columns_selection, which owns the narrowing direction, and test_list_config_listed_column_overrides_full_gate, which owns the table's forcing behaviour and still passes unchanged.

Ran locally: full cargo test --test integration and cargo test --lib --bins, plus cargo clippy --all-targets and cargo fmt --check. One unrelated failure, test_copy_ignored_preserves_file_executable_permissions, is a umask artifact of this sandbox (expects 0644, the runner's umask 002 produces 0664); it touches no code in this diff.

The docs-row follow-up in df5c238 re-ran cargo test --test integration -- test_help test_docs_are_in_sync (48 passed) and cargo fmt --check.

`wt list --format json` planned `all_columns` unioned with the selection's
forced-on columns, so a user's `[list] columns = […, "ci"]` turned a
machine-readable call into a forge fetch — `--full` is meant to be the switch
for that, and it's the one a caller controls. JSON now plans `all_columns`
alone; the table and the picker are unchanged.

Reported in #3787 by a Neovim plugin shelling out to `wt`, where the user's
display config decided whether the editor talked to GitHub.

@worktrunk-bot worktrunk-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The planning change itself is tight — the new three-way fork is behaviour-identical to the old prune_to_selection boolean everywhere except the JSON-with-a-selection case it means to change, required_tasks_for_render returns a HashSet so the picker's extend still dedups, and the layout (which is still computed with selected: Some(...) while tasks is now the unnarrowed full_plan()) is only read behind progressive_table/progressive_handler guards, so JSON can't observe the mismatch. wt list statusline builds its own plan through CollectOptions::for_columns, so it's untouched.

One doc gap left in the table this PR is tightening, plus a note below.

Worth calling out for the release note: this also changes schema 1. A caller with [list] columns = [..., "ci"] and no --full used to get the ci object in schema-1 JSON and now won't, and schema 1 has no collected envelope to say so. The schema-1 ci row already documented `--full` only, so the docs get more accurate — but the observable output changes for anyone who was relying on the forcing path.

Comment thread src/cli/mod.rs Outdated
Both rows described a gate the JSON plan no longer honours in full. With
`[list] columns` out of the JSON plan, `summary` resolves under
`ColumnSource::Default`, so it needs `--full` *and* `[list] summary = true`
(plus a `[commit.generation]` command) — the listed-column escape hatch that
made `[list] summary = true` alone sufficient is what this PR removes.
`checks` rides the same `CiStatus` task as `pr` and stated no gate at all.
Comment thread docs/content/config.md Outdated
json` always emits every field, but a listed gated column (`ci`, `summary`)
still forces its data collection on, so the JSON carries the same data the
table shows.
The selection drives the table and the `wt switch` picker; `wt list --format

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

this could we 50% as long

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Cut it entirely in 51c8121 — the scope now lives in the columns definition at the top of the section: "columns selects and orders the columns the wt list table and the wt switch picker render; --format json ignores it and always emits every field."

Net against the PR base, this section is 4 lines shorter than it was before the PR.

Comment thread docs/content/list.md Outdated
| `upstream` | Tracking branch: `{remote, branch, ahead, behind}`; absent when none is configured |
| `pr` | Open PR/MR: `{number, url, review, mergeable, repo}`; collected with `--full` or a listed `ci` column. `review` uses the schema 1 `ci.review_state` vocabulary; `mergeable` is false when the forge reports conflicts, null otherwise |
| `checks` | CI pipeline: `{status, source, stale}`; `status` is `passed`, `running`, or `failed` — null when a conflicts report masks it |
| `pr` | Open PR/MR: `{number, url, review, mergeable, repo}`; collected with `--full` (`[list] columns` doesn't reach JSON). `review` uses the schema 1 `ci.review_state` vocabulary; `mergeable` is false when the forge reports conflicts, null otherwise |

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

way way too verbose, all this section

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Trimmed in 51c8121. The [list] columns annotations are gone from every row — the rows now only name --full, which is the gate a JSON caller actually controls:

row now
pr collected with --full
checks collected with --full
summary needs --full, [list] summary = true, and a [commit.generation] command

pr is shorter than it was before the PR; summary gains the two gates it was missing (a caller who set only [list] summary = true got no field).

@max-sixty

Copy link
Copy Markdown
Owner

there is no need to list this everywhere, just say in the columns defn that it's for the wt list output; the docs should get simpler

The JSON caveat was repeated across the `columns` prose, three item-field
rows, and two code comments. Say it once where `columns` is defined — the
selection drives the `wt list` table and the picker, `--format json`
ignores it — and drop the per-row annotations, which now just name
`--full` as the gate.
@worktrunk-bot

worktrunk-bot commented Aug 13, 2026 •

Copy link
Copy Markdown
Collaborator Author

Done in 51c8121 — the caveat is stated once, in the columns definition, and removed from everywhere else it had spread to.

The definition now opens with the scope:

columns selects and orders the columns the wt list table and the wt switch picker render; --format json ignores it and always emits every field.

Removed: the six-line paragraph at the end of the columns section, the "[list] columns doesn't reach JSON" parentheticals on the pr and summary rows, and the trailing sentences in CLAUDE.md and the two module comments. Net −40 lines against the previous push, and both doc sections are now shorter than they were before this PR.

The code change is unchanged; test_docs_are_in_sync, test_help, list_config, and clippy pass locally.

CI on 51c81211: test (linux), test (macos), fast-checks, check-docs, lint, code-coverage, and codecov/patch all pass. test (windows) (required) was still running when my poll budget ran out — unverified.

@worktrunk-bot worktrunk-bot left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

One gap left, in the doc this PR is most about.

Collected's doc comment in src/commands/list/model/item.rs still names the gate this PR removes — "Fact families whose collection is gated (--full, [list] summary, a listed ci/summary column)". Collected is built only from tasks (collect/mod.rs), and the JSON plan is now full_plan() alone, which passes ColumnSource::Default — so listed is always false there and a listed column can no longer set collected.ci/collected.summary.

That comment isn't internal: schemars ships it verbatim into docs/static/schema/list-v2.json, which test_docs_are_in_sync regenerates from wt list --print-schema and which after_long_help points JSON consumers at ("A JSON Schema for the envelope is published at worktrunk.dev/schema/list-v2.json"). So the published machine-readable contract currently advertises the exact forcing path #3787 asked to remove — to the same audience the PR is for.

The fix is to drop the clause rather than explain it, which is also a line shorter. Pushing that now, with the schema mirror.

Everything else checks out: the three-way fork is behaviour-identical to the old prune_to_selection boolean in all three unchanged cases (empty selection still lands on full_plan(), since listed_plan() over an empty selection is the empty set), CiStatus and Summary really are the only gated columns (Url's gate is data-source, identical under either source), and JSON's display.columns comes from columns_map(custom_columns, …) rather than the layout, so the "always emits every field" claim holds for custom columns too.

`Collected`'s doc comment ships verbatim into
docs/static/schema/list-v2.json, and it still named "a listed
`ci`/`summary` column" as a gate on `collected`. The JSON plan is now
`full_plan()` alone, which passes `ColumnSource::Default`, so a listed
column can never set `collected.ci`/`collected.summary` — the published
schema was advertising the exact forcing path this PR removes, to the
machine consumers it removes it for.

Schema regenerated by `test_docs_are_in_sync`.
@max-sixty
max-sixty merged commit 246c6bd into main Aug 15, 2026
38 checks passed
@max-sixty
max-sixty deleted the fix/issue-3787-json-ignores-columns branch August 15, 2026 15:00
social4hyq pushed a commit to social4hyq/homebrew-core that referenced this pull request Sep 20, 2026
worktrunk 0.75.0

Created-by: HarmonybrewBot
Commit-by: HarmonybrewBot
Merged-by: HarmonybrewBot
Description: Created by `brew bump`

---

Created with `brew bump-formula-pr`.<details>
  <summary>release notes</summary>
  <pre>## Release Notes

### Improved

- **The `wt switch` picker opens on one unified diff**: local rows combine committed, staged, unstaged, and untracked changes. Tab skips empty subsidiary views, while `Alt-1` through `Alt-8` retain direct access. [Docs](https://worktrunk.dev/switch/#interactive-picker) ([#3865](max-sixty/worktrunk#3865))

- **Git 2.43 is now the minimum supported version**: older Git exits with an upgrade message before Git-dependent commands run; `wt config shell` remains available so shell startup continues. (Breaking.) ([#3895](max-sixty/worktrunk#3895))

### Fixed

- **`wt list` no longer grows `.git/objects` during advisory conflict checks**: untracked content stays visible but is excluded from synthetic trees, and all probe-only objects use temporary storage. ([#3906](max-sixty/worktrunk#3906), fixes [#3883](max-sixty/worktrunk#3883), thanks @srobroek for reporting and the original fix)

- **`HEAD±` counts untracked files without inflating moves**: `wt list`, the picker, and statusline include untracked lines. Tracked deletions paired with untracked destinations count as renames, so pure moves are line-neutral and edited moves show only their edits. `HEAD±` now always detects renames, regardless of `diff.renames`. ([#3925](max-sixty/worktrunk#3925))

- **Timed child processes no longer abort `wt` in restricted sandboxes**: `wt switch --create`, picker pagers, and other bounded commands survive denied signal-handler wakes. TERM→KILL cleanup also returns promptly once the process group is gone. ([#3857](max-sixty/worktrunk#3857), [#3887](max-sixty/worktrunk#3887), fixes [#3856](max-sixty/worktrunk#3856), thanks @tomascamargo for reporting)

- **JSON list output ignores display-column gates**: `[list] columns` no longer makes `wt list --format json` contact a forge or generate summaries. CI requires `--full`; summaries also require `[list] summary = true` and a configured generator. (Breaking: schema 1 loses config-driven `ci` and `summary` fields.) ([#3812](max-sixty/worktrunk#3812), thanks @emeren for the request)

- **Long Windows paths compare consistently**: paths beyond 260 characters could retain a `\\?\` prefix and appear to be on another drive. `copy-ignored` then refused them, while switch, remove, merge, and relocate landed at the worktree root instead of the original subdirectory. ([#3899](max-sixty/worktrunk#3899), fixes [#3898](max-sixty/worktrunk#3898), thanks @Persedes for reporting and verifying the fix)

- **Shell configuration rechecks before it writes**: overlapping installs lock and reread rc files; Fish completion installs preserve files created after preview; uninstall applies only previewed rc removals and rejects changed Worktrunk-owned files. ([#3853](max-sixty/worktrunk#3853), [#3924](max-sixty/worktrunk#3924))

- **`-vv` profiles exclude their own collector commands**: command counts and cache summaries no longer include duplicate-looking work performed only to assemble the diagnostic report; raw traces still retain it. ([#3900](max-sixty/worktrunk#3900))

- **Fenced HTML comments survive picker Markdown rendering**: PR descriptions and comments now preserve fenced `<!-- … -->` lines; fenced `<!-- wt list … -->` markers also no longer affect the following block. ([#3908](max-sixty/worktrunk#3908))

### Documentation

- **Agent CLIs without a plugin can publish activity markers**: the integration guide now specifies the session-start, turn-end, and session-end calls, working-directory requirement, error guard, and cleanup contract. [Docs](https://worktrunk.dev/claude-code/#agent-clis-without-a-plugin) ([#3848](max-sixty/worktrunk#3848), thanks @AsafMah for requesting generic-agent guidance and @ortonomy for the related Pi use case)

- **Agent guidance explains worktree selection**: commands that name a branch already select its worktree; `-C` changes repository context and is needed only for commands without a worktree selector or callers outside the repository. ([#3890](max-sixty/worktrunk#3890))

- **The `wt up` recipe safely updates dirty worktrees**: it fetches all remotes, fast-forwards dirty branches without autostash, rebases clean branches, and continues past an ordinary refusal or a failed remote. [Docs](https://worktrunk.dev/extending/#recipe-rebase-every-worktree-onto-its-upstream) ([#3882](max-sixty/worktrunk#3882))

- **The docs site has a new responsive design**: rebuilt on Astro and Starlight while preserving public routes, anchors, and crawler URLs; generated reference pages remain synchronized. ([#3866](max-sixty/worktrunk#3866))

### Internal

- **Library API rework** (Breaking library API): `BranchDiffSpec` gained `working_base`, while remote-URL, shell-path, branch-push, approval, temporary-index, and repository helpers were removed. ([#3833](max-sixty/worktrunk#3833), [#3853](max-sixty/worktrunk#3853), [#3865](max-sixty/worktrunk#3865), [#3866](max-sixty/worktrunk#3866), [#3875](max-sixty/worktrunk#3875))

- **Codex loads repository maintainer skills**: `.agents/skills` now exposes the canonical `.claude/skills` tree; checkouts without symlink support keep the existing limitation. ([#3903](max-sixty/worktrunk#3903))

## Install worktrunk 0.75.0

### Install prebuilt binaries via shell script

```sh
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-installer.sh | sh && wt config shell install
```

### Install prebuilt binaries via powershell script

```sh
powershell -ExecutionPolicy Bypass -c "irm https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-installer.ps1 | iex"; git-wt config shell install
```

### Install prebuilt binaries via Homebrew

```sh
brew install worktrunk && wt config shell install
```

## Download worktrunk 0.75.0

|  File  | Platform | Checksum |
|--------|----------|----------|
| [worktrunk-aarch64-apple-darwin.tar.xz](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-aarch64-apple-darwin.tar.xz) | Apple Silicon macOS | [checksum](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-aarch64-apple-darwin.tar.xz.sha256) |
| [worktrunk-x86_64-apple-darwin.tar.xz](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-x86_64-apple-darwin.tar.xz) | Intel macOS | [checksum](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-x86_64-apple-darwin.tar.xz.sha256) |
| [worktrunk-x86_64-pc-windows-msvc.zip](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-x86_64-pc-windows-msvc.zip) | x64 Windows | [checksum](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-x86_64-pc-windows-msvc.zip.sha256) |
| [worktrunk-aarch64-unknown-linux-musl.tar.xz](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-aarch64-unknown-linux-musl.tar.xz) | ARM64 MUSL Linux | [checksum](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-aarch64-unknown-linux-musl.tar.xz.sha256) |
| [worktrunk-x86_64-unknown-linux-musl.tar.xz](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-x86_64-unknown-linux-musl.tar.xz) | x64 MUSL Linux | [checksum](https://github.com/max-sixty/worktrunk/releases/download/v0.75.0/worktrunk-x86_64-unknown-linux-musl.tar.xz.sha256) |



### Install via Cargo

```sh
cargo install worktrunk && wt config shell install
```

### Install via Winget (Windows)

```sh
winget install max-sixty.worktrunk && git-wt config shell install
```

### Install via AUR (Arch Linux)

```sh
paru worktrunk-bin && wt config shell install
```
</pre>
  <p>View the full release notes at <a href="https://github.com/max-sixty/worktrunk/releases/tag/v0.75.0">https://github.com/max-sixty/worktrunk/releases/tag/v0.75.0</a>.</p>
</details>
<hr>

See merge request: Harmonybrew/homebrew-core!17938
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.

2 participants