You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
--fields should project each object inside the budgets wrapper while preserving rowCount; it must not return {}. --exclude should remove requested fields, and --full should restore long values. Unit fixtures cover the same real wrapper shape for folders, labels, annotations, and anomalies.
Could this break things?
Risk: medium. API requests and human-mode tables are unchanged. Agent-mode consumers may notice long strings becoming truncated by default, and scripts can intentionally request fewer fields. Consumers that require the complete original response should use --full or --no-truncate.
Re-reviewed at 0abaebb. Built the branch and tested against the live API.
The --fields blocker is fixed. Adding rowCount to hasListMetadata (output_contract.go:149) resolves it. Before the fix, list-budgets --fields id,budgetName returned {} with exit 0 against a tenant that has 4 budgets. Now verified working on list-budgets, list-labels, list-anomalies, and returning proper {"folders":[],"rowCount":0} for genuinely empty ones. Human-mode table renders correctly too (it was a row of <nil>).
Three things still open.
1. --exclude strips wrapper metadata and applies at every depth
transformResponseObjects (output_contract.go:196) applies the exclusion set to every object at every nesting level, so the "preserve pagination and wrapper metadata" claim in the PR description doesn't hold yet. Verified live:
rowCount is gone from the wrapper, and alertThresholds[].amount is gone from a nested object the user didn't ask about. --exclude pageToken or --exclude cursor would break pagination the same way.
2. Unknown field names are a silent no-op
projectObject (output_contract.go:166) keeps exact matches and returns whatever it found, with no diagnostic:
Same result for a case mismatch (--fields ID) or the wrong field name (--fields name — budgets use budgetName). An agent can't distinguish "no data" from "wrong field name," which is the failure mode the original {} bug had. Worth a usage error, or at minimum a stderr warning, when zero requested fields exist in the response.
3. I'd still cut the truncation half
No commit in this PR has touched it, so this stands from the first pass:
It changes the value's type.string → {value, _truncated} (output_contract.go:224) breaks every non-LLM consumer: jq -r .description yields null, JSON-schema validation on type: string fails, typed unmarshal fails. The CLI stops conforming to the OpenAPI schema it ships.
It costs more tokens than it saves on the default format. In toon (the agent-mode default) the map serializes as an escaped JSON string inside the cell, so the retained 2000 runes come back backslash-escaped and brace-wrapped — strictly more tokens than the original string, plus the row is no longer scalar.
It silently deletes table columns.filterObjectColumns hides map-valued columns, so one long row turns the field into a map and the whole column disappears for every row, with a footer that says "Hidden columns (object values)" about a string field.
It buys nothing on real DCI data. The longest string in any list endpoint I sampled is 125 chars (anomalies[].resourceData[].resource_id), well under the 2000 default at output_contract.go:10. Where long strings do occur — report filter/attribution expressions, presigned invoice URLs, pagination cursors — they're exactly the values an agent has to round-trip verbatim.
If truncation stays, I'd make it opt-in (--truncate[=N]), keep the field a string, and put the marker in a sibling key rather than changing the type.
One design question worth settling before this grows
Field projection is a query concern. Doing it client-side means paying full transfer cost and then discarding — it saves agent tokens but nothing else. The PR description already concedes the terse-field-name half is API-owned. Worth a conversation with the API team about ?fields= before we build more of this in the CLI. Related: restish already has -f/--filter which does nested projection, so we should decide whether --fields is a friendlier alias for that or a parallel mechanism.
Also worth deciding: --fields a,b is top-level exact-match only. Agents will want --fields id,scope.name. Dotted paths or don't ship the flag.
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
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.
Summary
--fieldsand--excludeprojection for list and get responsesrowCountlist wrappers used by budgets, folders, labels, annotations, and anomalies--fulland--no-truncateescape hatches{count: 0, results: []}shape for an empty top-level list in agent modePart of #9 and #12. Terse field renames and endpoint-specific minimal schemas remain API-owned because the CLI passes through OpenAPI response fields.
Test methods
Automated validation run on this branch:
go test ./... go vet ./...Manual validation with an authenticated CLI:
go build -o /tmp/dci-pr33 . /tmp/dci-pr33 --no-agent list-budgets --output table DCI_AGENT_MODE=1 /tmp/dci-pr33 list-budgets --fields id,name --output json DCI_AGENT_MODE=1 /tmp/dci-pr33 list-budgets --exclude description --output json DCI_AGENT_MODE=1 /tmp/dci-pr33 list-budgets --full --output json--fieldsshould project each object inside thebudgetswrapper while preservingrowCount; it must not return{}.--excludeshould remove requested fields, and--fullshould restore long values. Unit fixtures cover the same real wrapper shape for folders, labels, annotations, and anomalies.Could this break things?
Risk: medium. API requests and human-mode tables are unchanged. Agent-mode consumers may notice long strings becoming truncated by default, and scripts can intentionally request fewer fields. Consumers that require the complete original response should use
--fullor--no-truncate.Example truncation marker:
{"description":{"value":"first 2000 characters...","_truncated":4821}}