SOW-0122: fast --list-invocations and stock IDX alignment; track remaining CLI gaps

KT
6h ago
+832-307

Stacked on #20. Completes SOW-0122 (.agents/sow/done/SOW-0122-20260621-journalctl-performance-followups.md) and opens SOW-0166, SOW-0167 and SOW-0168 for the remaining measured gaps.

Decisions for review (agent-chosen, pending your review)

  1. --list-invocations prefilter limited to 32 IDs.
    • SOW-0121 added a prefilter, an OR of every invocation-ID value, to keep sparse-ID journals cheap.
    • Every step evaluates every term, so with ~10,000 IDs the command was 240-590x slower than stock.
    • It now applies only up to 32 IDs (ELIGIBILITY_MAX_TERMS / invocationEligibilityMaxTerms). Above that, the walk matches stock's unit/boot walk.
    • Rows without an ID are skipped either way, so output is unchanged.
  2. IDX column sized like stock: the column is as wide as the widest index, at least 3 when the header shows. Previously, at 100+ rows stock printed IDX / -99 and we printed IDX / -99.

Measurements

Fixtures: 1.5M entries, as one 931 MB file and as 300 files. Full table: .local/sow0122/report.md (local, not committed), summarized in the SOW.

--list-invocations -ubeforeafterstock v262
Rust, file / dir27.7 s / 13.0 s0.23 s / 0.67 s0.06 s / 1.03 s
Go, file / dir14.5 s / 15.4 s0.66 s / 1.81 s

Output is byte-identical to stock for --list-invocations (with and without -q) and --list-boots, in both languages.

Rust is otherwise at or faster than stock: full output is 2-4x faster. The new pending SOWs:

SOWGapMeasured
SOW-0166Directory --since seek17x slower than stock
SOW-0167Every Go open loads the whole entry array0.27 s / 160 MB floor per file
SOW-0168--follow polls and reopens instead of waitingidle CPU and latency far above stock; needs your decision (inotify vs cheaper polling)

Validation

  • Query matrix vs v262 oracle: 3587/3587 PASS.
  • Parser parity: 134/134 in each language.
  • go test ./cmd/journalctl and cargo test -p journalctl: pass.
  • New paired tests for the IDX width rule.

Summary by cubic

Completes SOW-0122 by fixing --list-invocations performance and IDX column alignment in both CLIs, and opens SOW-0166, SOW-0167, and SOW-0168 for the remaining measured gaps. Output is now byte-identical to stock for --list-invocations and --list-boots; Rust is otherwise at or faster than stock. Carries the sow-0160/xz-dictionary base via merges, with its SOWs recorded in the ledger.

Two agent-chosen decisions, both approved by the user on 2026-11-03:

  • The valid-ID prefilter (an OR of every invocation ID) is now bounded to 32 IDs. Above that, the walk matches stock's unit/boot walk; rows without a valid ID are skipped either way, so output is unchanged. This takes --list-invocations -u from 240-590x slower than stock to near parity (Rust 0.23 s file / 0.67 s dir vs stock 0.06 s / 1.03 s).
  • The IDX column is sized to the widest index, at least 3 when the header is shown, matching stock's table formatting.

Residual gaps tracked as new SOWs

  • SOW-0166: directory --since seek at 17x slower than stock; the SOW records the reproduction procedure.
  • SOW-0167: every Go open loads the full entry array (0.27 s and 160 MB floor per file).
  • SOW-0168: --follow polls and reopens instead of waiting; decided 2026-11-03 to make portable polling cheap (reuse readers, check header counters per poll, back off while idle) — inotify needs a separate policy decision.

Validation: 3587/3587 query matrix PASS against the v262 oracle, 134/134 parser parity in each language, paired IDX-width tests added, and both go test ./cmd/journalctl and cargo test -p journalctl pass.