fix(cli): preserve target identity in default output #107

Merged
Lochnair merged 1 commits from fix/client-target-output into main 2026-08-15 13:25:56 +00:00
Lochnair commented 2026-08-15 13:21:37 +00:00 (Migrated from github.com)

Summary

  • default client event output now includes the logical target field for both
    single-target and multi-target runs;
  • explicit --target LABEL=TARGET labels are therefore preserved in default
    table/CSV/TSV/JSONL output even for a single target;
  • positional targets use their existing generated logical labels;
  • machine-readable default schemas no longer vary with target count.

Before

Single target: target was omitted from default output.
Multiple targets: target was included.

A single explicit label such as --target eu=... was therefore lost from
default CSV/table presentation, even though the user had gone out of their
way to name it.

After

Default event schema always includes target.

Table:

target event seq ...

CSV/TSV/JSONL:

target remains part of ALL_COLUMNS for any target count.

Target semantics

  • target = logical CLI target identity (from ManagedEvent::Client.target.id)
  • remote = resolved socket endpoint

No label reconstruction from remote addresses; identity always comes from the
existing TargetId.

Custom columns

Explicit --columns remains authoritative and no target is forcibly inserted.
--columns default behaves exactly like omitting --columns.

Timestamp note

event_wall_ns already provides the event Unix timestamp in nanoseconds;
this PR adds no duplicate timestamp field.

Summary scope

Final aggregate-summary formatting (the target: LABEL heading for
multi-target runs) is unchanged — this PR only affects per-event/per-probe
stream output.

Compatibility

  • no irtt-client API change;
  • no protocol change;
  • no target parsing change;
  • no stats change;
  • no Cargo/dependency change.

Tests

  • single_target_default_table_includes_target_and_accepts_pacing
  • single_labeled_target_default_table_includes_target
  • single_labeled_target_default_csv_includes_target_and_event_wall_ns
  • single_positional_target_default_csv_includes_target_as_positional_label
  • multi_target_default_table_includes_both_labels
  • multi_target_csv_emits_rows_for_both_labels (existing, still passing)
  • custom_columns_remain_authoritative_and_omit_target
  • columns_default_keyword_includes_target_for_single_target
  • single_labeled_target_default_jsonl_includes_target
  • unit tests in output.rs: default_table_columns_always_include_target_first,
    default_structured_columns_always_include_target_first,
    columns_default_keyword_matches_omitted_columns,
    custom_columns_do_not_insert_target, custom_target_column_renders_label,
    default_csv_renders_target_label_in_row, default_jsonl_renders_target_key_first

Verification

  • cargo test -p irtt-cli --all-features --locked
  • cargo fmt --all -- --check
  • cargo check --workspace --all-targets --all-features --locked
  • cargo test --workspace --all-targets --all-features --locked
  • cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
  • RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --locked
  • cargo check -p irtt-cli --no-default-features --features client --all-targets --locked
  • cargo check -p irtt-cli --no-default-features --features tui --all-targets --locked
  • cargo check -p irtt-cli --no-default-features --features server --all-targets --locked
  • git diff --check

All passed.

## Summary - default client event output now includes the logical `target` field for both single-target and multi-target runs; - explicit `--target LABEL=TARGET` labels are therefore preserved in default table/CSV/TSV/JSONL output even for a single target; - positional targets use their existing generated logical labels; - machine-readable default schemas no longer vary with target count. ## Before Single target: `target` was omitted from default output. Multiple targets: `target` was included. A single explicit label such as `--target eu=...` was therefore lost from default CSV/table presentation, even though the user had gone out of their way to name it. ## After Default event schema always includes target. Table: target event seq ... CSV/TSV/JSONL: target remains part of ALL_COLUMNS for any target count. ## Target semantics - `target` = logical CLI target identity (from `ManagedEvent::Client.target.id`) - `remote` = resolved socket endpoint No label reconstruction from remote addresses; identity always comes from the existing `TargetId`. ## Custom columns Explicit `--columns` remains authoritative and no target is forcibly inserted. `--columns default` behaves exactly like omitting `--columns`. ## Timestamp note `event_wall_ns` already provides the event Unix timestamp in nanoseconds; this PR adds no duplicate timestamp field. ## Summary scope Final aggregate-summary formatting (the `target: LABEL` heading for multi-target runs) is unchanged — this PR only affects per-event/per-probe stream output. ## Compatibility - no irtt-client API change; - no protocol change; - no target parsing change; - no stats change; - no Cargo/dependency change. ## Tests - `single_target_default_table_includes_target_and_accepts_pacing` - `single_labeled_target_default_table_includes_target` - `single_labeled_target_default_csv_includes_target_and_event_wall_ns` - `single_positional_target_default_csv_includes_target_as_positional_label` - `multi_target_default_table_includes_both_labels` - `multi_target_csv_emits_rows_for_both_labels` (existing, still passing) - `custom_columns_remain_authoritative_and_omit_target` - `columns_default_keyword_includes_target_for_single_target` - `single_labeled_target_default_jsonl_includes_target` - unit tests in `output.rs`: `default_table_columns_always_include_target_first`, `default_structured_columns_always_include_target_first`, `columns_default_keyword_matches_omitted_columns`, `custom_columns_do_not_insert_target`, `custom_target_column_renders_label`, `default_csv_renders_target_label_in_row`, `default_jsonl_renders_target_key_first` ## Verification - `cargo test -p irtt-cli --all-features --locked` - `cargo fmt --all -- --check` - `cargo check --workspace --all-targets --all-features --locked` - `cargo test --workspace --all-targets --all-features --locked` - `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings` - `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --locked` - `cargo check -p irtt-cli --no-default-features --features client --all-targets --locked` - `cargo check -p irtt-cli --no-default-features --features tui --all-targets --locked` - `cargo check -p irtt-cli --no-default-features --features server --all-targets --locked` - `git diff --check` All passed.
Sign in to join this conversation.