Skip to content

test: pin automation target resolution at base-index 1; document duration flag units - #178

Open
edwinhu wants to merge 1 commit into
Helvesec:mainfrom
edwinhu:fix/automation-target-docs-and-base-index-regression
Open

test: pin automation target resolution at base-index 1; document duration flag units#178
edwinhu wants to merge 1 commit into
Helvesec:mainfrom
edwinhu:fix/automation-target-docs-and-base-index-regression

Conversation

@edwinhu

@edwinhu edwinhu commented Jul 28, 2026

Copy link
Copy Markdown

Summary

Adds a regression test pinning pane-target resolution for the rmux-specific automation commands at base-index 1 + pane-base-index 1, and documents the unit requirement on the duration flags.

The bug this pins

Reported against 0.8.0 (current nixpkgs). With base-index 1 set, every rmux extension subcommand failed while the tmux-compatible surface worked:

$ rmux new-session -d -s rt -x 90 -y 20 "somecommand"
$ rmux list-panes -a -F '#{session_name}:#{window_index}.#{pane_index} #{pane_id}'
rt:1.1 %0

$ rmux capture-pane -p -t rt          # tmux-compatible surface
<pane contents>                       # works

$ rmux pane-snapshot -t rt            -> unable to resolve pane id for target rt:1.0
$ rmux pane-snapshot -t rt:1.1        -> unable to resolve pane id for target rt:1.0
$ rmux pane-snapshot -t %0            -> unable to resolve pane id for target rt:1.0
$ rmux stream-pane   -t rt            -> unable to resolve pane id for target rt:1.0
$ rmux wait-pane     -t rt --visible-text foo --timeout 8s
                                      -> unable to resolve pane id for target rt:1.0

Root cause in 0.8.0 was pane_id_for_slot, which listed the window's panes with #{pane_index}\t#{pane_id} and compared the internal target.pane_index() directly against the display-space #{pane_index}. Under a non-zero base index those spaces differ by one, no row matched, and the command bailed. capture-pane resolves server-side and was unaffected, so the break was invisible on the default zero-based indices.

The error text naming rt:1.0 regardless of the target passed made this look like the target was being discarded; it is not — it is Display for PaneTarget rendering the already-normalized internal indices.

This is already fixed on main. 270dd546 added #{pane-base-index} to the format string and routed the comparison through listed_pane_index_matches_target, which applies the offset. I verified main at 9f007bf6 resolves all three target spellings correctly.

What this PR adds

1. A regression test for the reported configuration. The existing nonzero_pane_base_index_preserves_targeted_automation_and_percent_resize pins pane-base-index alone, with base-index still 0 and only slot-shaped targets — so the reported setup was never exercised. The new base_index_one_resolves_every_automation_target_spelling sets both indices to 1, asserts the layout really is shifted (so it can't pass vacuously), and drives pane-snapshot, wait-pane, locator and expect-pane against:

  • alpha:1.1 and alpha:1.2 — explicit slots
  • %<id> for each pane — stable ids
  • bare alpha — which must land on the active pane, not display index 0 (which does not exist under pane-base-index 1)

Reverting the saturating_add(pane_base_index) in listed_pane_index_matches_target fails the test, so it guards the actual fix rather than the surrounding scaffolding.

2. --timeout / --stable-for / --ttl document their required unit. parse_duration rejects bare integers on purpose — --timeout 8000 must not be silently read as either 8s or 8000s — but --help rendered the flag as a bare --timeout <TIMEOUT> with no help text, so the requirement was discoverable only by triggering the error. I kept the strict parse and fixed the discoverability:

Before:  --timeout <TIMEOUT>
After:   --timeout <DURATION>    Duration with an explicit unit: ms, s, or m (for example 500ms, 8s, 2m)

Before:  error: invalid value '8000' for '--timeout <TIMEOUT>': duration requires an explicit unit: ms, s, or m
After:   error: invalid value '8000' for '--timeout <DURATION>': duration requires an explicit unit: ms, s, or m (for example 500ms, 8s, 2m)

duration_flags_document_their_required_unit pins both the help text and the example in the rejection.

Verification

  • cargo test --test automation_cli — 25 passed
  • cargo test --test cli_surface — 145 passed; manpage_surface — 1 passed
  • cargo test --bin rmux — 530 passed
  • cargo fmt --all -- --check clean; cargo clippy --all-targets adds no new warnings
  • Every command from the original report re-run against a base-index 1 daemon built from this branch: pane-snapshot, stream-pane and wait-pane all return pane content for -t rt, -t rt:1.1 and -t %0

Note on an unrelated pre-existing failure

cargo test --test acceptance_cli_matrix fails 2 of 22 on unmodified main at 9f007bf6 in my environment — cli_acceptance_matrix_exercises_real_daemon_state and detached_window_spawns_without_c_use_non_attached_caller_cwd, both with can't find window: 0. It reproduces with the working tree stashed, so it is not caused by this change, but the failure mode looks like the same display-vs-internal index confusion and may be worth a separate look.

Adds a regression guard for the pane-target resolution shared by the
rmux-specific automation commands, and documents the unit requirement on
the duration flags.

Under `base-index 1` + `pane-base-index 1`, rmux 0.8.0 failed every
extension command with

    unable to resolve pane id for target <session>:<window>.0

even when the caller passed a fully explicit `session:window.pane` slot
or a `%id`. The tmux-compatible surface (`capture-pane`, `list-panes`)
resolves server-side and was unaffected, so the break was invisible to
anyone on the default zero-based indices.

The resolution itself is already fixed on main: `pane_id_for_slot` now
selects `#{pane-base-index}` and `listed_pane_index_matches_target`
adds it before comparing against the display-space `#{pane_index}`.
What was missing is a test that pins it. `nonzero_pane_base_index_*`
covers `pane-base-index` alone, with `base-index` still 0 and only
slot-shaped targets, so the reported configuration was not exercised.

The new test sets both indices to 1 and drives pane-snapshot, wait-pane,
locator and expect-pane against all three target spellings, including a
bare session target, which must land on the ACTIVE pane rather than on
display index 0 (which does not exist when pane-base-index is 1).
Reverting the `saturating_add(pane_base_index)` in
`listed_pane_index_matches_target` fails it.

Separately, `parse_duration` rejects bare integers so that `--timeout
8000` can never be read ambiguously, but `--help` rendered the flag as a
bare `--timeout <TIMEOUT>` with no help text, leaving the requirement
discoverable only by hitting the error. The duration flags now carry a
`<DURATION>` value name and state the accepted units, and the rejection
message carries an example.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L9BMBLf4cXLCZfxCPRvctZ
@edwinhu
edwinhu requested a review from shideneyu as a code owner July 28, 2026 19:17
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.

1 participant