fix(formatters): surface every GraphResponse field in goon output
Summary
Audit follow-up to !1289 (merged). The encoder was silently dropping four pieces of GraphResponse data. This MR routes each one to the wire so a goon consumer has the same information a raw consumer does.
| Field | Before | After |
|---|---|---|
ColumnDescriptor.target / .property |
count / max (target and property dropped) |
count(count:v) / max(max:v.updated_at) |
GroupColumnDescriptor.property (alias differs from property) |
severity_bucket(property) |
severity_bucket(property:severity) |
GraphEdge.depth (variable-length traversals) |
sort key only, depth dropped from output | User:1 --> Group:200 depth=2 |
Value::Null group / metric cell |
dropped — severity=null, count=5 rendered as count=5 |
bare null token preserves the dimension |
The null rendering is unambiguous because the string "null" already gets quoted as "null" by the existing token-collision guard.
Test plan
- 57 unit tests in
goon::tests(6 new for the data-loss fixes) - 7 insta snapshots (two updated for the richer aggregation header)
- 4 proptest invariants
- 8 integration subtests against ClickHouse
cargo test -p formatters --tests --all-features
cargo test -p integration-tests --test containers goon_formatter
cargo clippy -p formatters --all-features --all-targets -- -D warnings[skip goon-format-version-check]