Skip to content

feat(cli): add --fields projection to incident/alert list#58

Merged
ysyneu merged 2 commits into
feat/ai-srefrom
audit-fix/audit-2026-06-23-audit-cli-list-fields-projecti
Jun 23, 2026
Merged

feat(cli): add --fields projection to incident/alert list#58
ysyneu merged 2 commits into
feat/ai-srefrom
audit-fix/audit-2026-06-23-audit-cli-list-fields-projecti

Conversation

@ysyneu

@ysyneu ysyneu commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

What

Add an additive --fields flag to the curated incident list and alert list commands. In structured (--output-format json|toon / --json) mode, --fields a,b,c projects each row to only the named JSON-tagged fields via one shared reflection helper (internal/cli/fieldproject.go::projectFields), so the first list call is already compact.

  • Default behavior (no --fields) is byte-identical to today — the full nested record still dumps. Regression-tested.
  • --fields is a no-op in table mode (documented in flag help).
  • Unknown field names fail fast, listing the valid tag names for the row type.
  • Projected values keep their original typed value (e.g. flashduty.Timestamp), so per-field encoding stays byte-consistent with the full dump.

Examples:

  • fduty alert list --fields alert_id,title,alert_severity,created_at --output-format toon
  • fduty incident list --fields incident_id,title,incident_severity,progress,start_time --json

Root cause

In structured mode the curated compact column set (cols []output.Column) passed to ctx.PrintList is completely ignoredTOONPrinter/JSONPrinter marshal the whole nested SDK struct (IncidentInfo/AlertItem with responders, alerts, labels, incident, events blobs). So the agent's first incident list/alert list dump is huge and pure waste: it spills to a file and is then immediately re-queried with a narrower jq projection (which even failed in one session because jq isn't installed in the sandbox). --fields lets the FIRST call be compact: no spill, no jq.

Evidence (audit run audit-2026-06-23)

All 6 cited oversized findings are the first full dump being waste:

  • sess_CAikSKGN2GFsHh6nYsXQw6 — 83.7KB / 2593 lines for 66 alerts; re-queried with jq (jq absent in sandbox).
  • sess_7BvVWNcaRcCmw8DykPSaki — 69.7KB for 20 incidents.
  • sess_H3xYYtxVpEpXNFUgDAMem9 — 52KB + 67KB dumps.
  • sess_8mJca7nB7gCcsGUHLQgwQz — 60.4KB never used.

Scope

Deliberately out of scope (per the design's "do not stretch" rule): the proposal's --count/group-by summary mode (a mini query engine with unsettled design surface), nested/dotted field paths, and any change to the generated command layer or the internal/output printers. The default path is untouched end-to-end.

Verification

$ env -u GOROOT go build ./...        # exit 0
$ env -u GOROOT go test ./...         # all packages ok
ok  github.com/flashcatcloud/flashduty-cli/cmd/flashduty
ok  github.com/flashcatcloud/flashduty-cli/internal/cli
ok  github.com/flashcatcloud/flashduty-cli/internal/output
... (all green)
$ env -u GOROOT go vet ./internal/cli/   # clean

New tests in internal/cli/fieldproject_test.go drive the real command via the newGFStub harness:

  • Default-unchanged regression (conductor constraint): no --fields under toon and json still emits the full nested keys (responders/labels for incident, events/incident for alert).
  • Projection: toon + json emit exactly the requested keys and drop the rest (json asserted structurally via json.Unmarshal — exactly N keys).
  • Table-mode ignore: --fields is a no-op; normal headers still print.
  • Unknown field: errors with the offending name.

Note: make lint fails in this environment due to a pre-existing toolchain mismatch (installed golangci-lint v2.2.1 built with go1.24 refuses a module targeting go1.25.1) — unrelated to this change; gofmt -s and gci are clean on the touched files.

ysyneu added 2 commits June 23, 2026 16:27
In structured (json/toon) mode the curated `incident list` / `alert list`
commands ignore the compact column set and marshal the full nested SDK
record (IncidentInfo/AlertItem with responders/labels/alerts and
events/incident blobs). That makes the first list call huge — 20 incidents
~60-70KB, 66 alerts ~83KB — which spills to file and is then re-queried with
a narrower jq projection. The first dump is pure waste.

Add an additive --fields flag to both list commands: in json/toon mode it
projects each row to only the named JSON-tagged fields via one shared
reflection helper (projectFields), so the first call is already compact and
no jq round-trip is needed. Default behavior (no --fields) is byte-identical
to today; --fields is a no-op in table mode. Unknown field names fail fast
listing the valid tag names.

Out of scope by design: --count/group-by aggregation, nested/dotted paths.
The --fields projection flag added to `incident list` / `alert list`
changed the cobra command tree, leaving the generated card fences stale.
CI 'Check skill command-cards' (go run ./internal/cmd/skilldoc check)
failed on reference/{alert,incident}.md. Regenerated via make gen-cards.
@ysyneu ysyneu merged commit ce5428f into feat/ai-sre Jun 23, 2026
12 checks passed
@ysyneu ysyneu deleted the audit-fix/audit-2026-06-23-audit-cli-list-fields-projecti branch June 23, 2026 09: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