fix(cli): reduce over-budget projected list pages instead of shortening values - #175
Merged
Conversation
…ng values When a projected list page (alert-event list, incident list, incident similar, channel escalate-rule-list) overflows the 16 KiB structured-output budget, the previous behavior fair-capped every shortenable string value across every row and marked the clipped ones with "...". A --json/--toon consumer filtering or exact-matching on those values (jq select, id comparisons) silently misses rows that really match, and an empty result is indistinguishable from a genuine non-match. boundProjectedList now reduces the page first: it emits the largest leading prefix of rows that fits the budget with every value byte-intact (largestFittingPrefix, a binary search over the monotone prefix size), and announces the emitted count on stderr. Value shortening is kept only for the case page reduction cannot solve — a single row that overflows the budget on its own — with identifier fields still exempt and the "..." marker still guaranteed; the irreducible case still fails with the error naming the largest fields. boundProjectedOutput returns the bounded data (same type) alongside the note; the four list call sites use the returned slice, and the two paginated ones pass the emitted count and effective limit to PrintList so its pagination note stays accurate. Flag help and the alert/incident skill cards describe the page-reduction semantics.
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.
Problem
fduty alert-event list --limit 100 --json(andincident list,incident similar,channel escalate-rule-list) bound their projected structured output to the 16 KiB budget by fair-capping every shortenable string value across every row, marking clipped ones with.... At a large--limitthe per-value cap collapses to a few bytes, so the page comes back as 100 rows ofx...stubs.For a
--json/--toonconsumer this is silent corruption: ajq select(.title | test(...))or an exact id match runs over the clipped values, misses rows that really match, and an empty result is indistinguishable from a genuine non-match. A stderr note announced the shortening, but the clipped page itself was still the output.Root cause
boundProjectedList(internal/cli/fieldproject.go) had exactly one tool for an over-budget page: shrink values until all rows fit. It never considered shrinking the page itself — the dimension that costs the consumer nothing, because these commands are already paginated (--limit/--page).Fix
largestFittingPrefix, a binary search — prefix encoded size is monotone), and announce the reduction on stderr:note: emitted N of M projected rows (every value intact) to stay below the 16384-byte structured-output limit; narrow --fields or lower --limit to fit more rows per page — the rows past the first N were not emitted...marker, and the irreducible case (nothing shortenable) still fails with the error naming the largest fields.boundProjectedOutputnow returns the bounded data (same type as its input) alongside the note; the four list call sites use the returned slice, and the two paginated ones (alert-event list,incident list) pass the emitted count and effective limit toPrintListso its pagination note stays accurate.--fieldsflag help and the alert/incident skill cards now describe the page-reduction semantics.Notes for reviewers
--json/--toonlist consumers: a large--limitnow yields a smaller, fully intact page instead of...-clipped rows (the point of this change). Scripts that count array length as the page size must heed the stderr notes.PrintList's genericraise --limit or use --pagenote is unchanged (shared helper, wider blast radius); the specific reduction note governs.alert list --fieldsnever bounds its projection at all — pre-existing gap, deliberately out of scope.Verification
The two new
AutoReducesPagetests stub 100 rows with ~600-byte mixed CJK titles via the httptest stub and runalert-event list --limit 100/incident list --limit 100in both json and toon: exit 0, stdout parses as an array of ≥1 and <100 rows forming the leading prefix of the fixture with every value byte-identical, no...anywhere, output under 16 KiB, and stderr carries the reduction note naming the emitted count.TestCommandListProjectionOverflowFailsand the end-to-endTestProjectionOverflowFailsHardpreviously pinned error-on-overflow with multi-row fixtures; those pages now reduce (covered above), so both were re-pointed at the case that still must fail: a single row whose projected non-string field alone exceeds the budget (non-zero exit, empty stdout, error naming the largest fields). Manual eyeball:alert-event list --helpshows the new--fieldssentence.