Skip to content

Add JSON-for-UI output mode with published JSON Schema#2

Merged
aaronbrethorst merged 10 commits into
mainfrom
json-ui-output-mode
May 25, 2026
Merged

Add JSON-for-UI output mode with published JSON Schema#2
aaronbrethorst merged 10 commits into
mainfrom
json-ui-output-mode

Conversation

@aaronbrethorst
Copy link
Copy Markdown
Member

@aaronbrethorst aaronbrethorst commented May 25, 2026

Summary

  • Adds a structured JSON output mode for UI visualization: --json now emits a single document with meta (run inputs — never the apiKey), summary (verdict + status counts), and groups (a server group plus one per data source, each with its results and category/step-split check names). This replaces the previous flat Report.Results JSON.
  • Publishes a JSON Schema (draft 2020-12) at schema/oba-validator-report.schema.json describing both the report and error variants (oneOf), with a conformance test that validates generated output against it (so the schema can't rot).
  • Follows the api-key-service Render one-off-job convention: the job prints the document to stdout and the caller reads it; on failure before a report exists, a { "schemaVersion", "error" } object is emitted to stdout and the process exits 2.

Design + plan: docs/superpowers/specs/2026-05-25-json-ui-output-design.md, docs/superpowers/plans/2026-05-25-json-ui-output-mode.md.

Test plan

  • go build ./... && go vet ./... && go test ./... — all green
  • Unit: BuildDocument grouping/ordering, category/step split, counts/verdict/exitCode, meta echo + omitempty, apiKey never present (+ URL & message redaction), SKIP counting, leftover/unknown-source grouping, zero-data-sources ([] not null), determinism, unknown-status panic assertion
  • Schema conformance: success doc, error doc, and a rejects-malformed negative case
  • CLI: --json output shape; config-error → JSON error doc + exit 2; inline-apiKey redaction in both JSON and text error paths
  • Exercised the real binary end-to-end against the live Puget Sound server: valid 11KB document, validates against the published schema, total == sum(counts), no apiKey leak; and the config-error edge case

Review notes (multi-agent review; addressed)

  • Fixed an apiKey leak: a raw-JSON config arg not starting with { (e.g. a JSON array / BOM) is misread as a file path, and config.Load's read error echoed the raw input — including an inline apiKey — to stdout under --json. Now redacted via a key sniffed from the argument.
  • Hardened: Counts.add takes the typed validator.Status (panics on out-of-range instead of silently dropping); Summary.Total = len(results); WriteJSON marshals fully then writes once (no partial JSON on a broken pipe); result messages redacted at the report layer as defense-in-depth.

Non-blocking items surfaced for reviewer judgment

  • SKIP-only runs report verdict: "PASS" / exitCode: 0 (per the existing severity model — skips never affect exit code). A UI may want to distinguish "passed" from "nothing actually validated" using counts.skip.
  • Result Details pass through un-redacted by design (checks redact at source). If a future check puts a URL/secret in Details, the report layer won't catch it — could add deep redaction later.
  • Echoed feed URLs are shown verbatim (apiKey aside). If an operator ever uses a tokenized/signed feed URL, that token would appear in meta. OBA feed URLs are public in practice; flagging since it's a new disclosure surface.

Summary by CodeRabbit

  • New Features

    • JSON output mode (--json) now provides structured data including metadata, summary statistics, and grouped results for better machine readability
    • API keys are automatically redacted from error messages in both JSON and text output modes for improved security
  • Documentation

    • Updated README with detailed explanation of JSON output format and structure
    • Published JSON Schema specification for validator output validation

Review Change Stack

…rorJSON

Merges plan Tasks 2 and 3: the shared sampleReport test fixture changes shape,
so the BuildDocument transform and the report_test.go rewrite must land together
to keep the build green.
A raw-JSON config argument that does not start with '{' (e.g. a JSON array or a
BOM-prefixed object) is misread as a file path; config.Load's os.ReadFile error
then echoes the raw input verbatim, including an inline apiKey. The --json path
emitted this to stdout (text mode to stderr). Redact using a key sniffed from
the argument itself, since the parsed cfg is empty when Load fails this way.
- Counts.add takes typed validator.Status (compile-time enum coupling) and
  panics on an out-of-range value instead of silently dropping it; Summary.Total
  is now len(rep.Results) so it can't diverge from the source.
- WriteJSON/WriteErrorJSON marshal fully then write once, so a mid-stream write
  failure can't leave partial JSON on the consumer's stream.
- Redact result messages at the report layer (defense in depth; checks already
  redact upstream); redact the run-error text path for consistency.
- Cover the dark branches and contracts: SKIP counting, leftover/unknown-source
  grouping, details passthrough/omit, zero-data-sources ([] not null),
  determinism, message redaction, and the unknown-status panic.
- Comment/spec accuracy fixes.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

Warning

Review limit reached

@aaronbrethorst, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 40 minutes and 10 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3273faba-d507-427a-b7c7-52caa069821d

📥 Commits

Reviewing files that changed from the base of the PR and between 6a71083 and c8ee9d2.

📒 Files selected for processing (2)
  • README.md
  • docs/superpowers/specs/2026-05-25-json-ui-output-design.md
📝 Walkthrough

Walkthrough

This PR implements a comprehensive refactoring of the --json output mode for the OBA Validator, replacing flat output with a structured UI-oriented Document. The change includes new document data types, a pure BuildDocument transformation, API key redaction in error handling, JSON Schema validation, and updated CLI wiring to emit errors as JSON.

Changes

JSON-for-UI Output Mode

Layer / File(s) Summary
Design and implementation specifications
docs/superpowers/specs/2026-05-25-json-ui-output-design.md, docs/superpowers/plans/2026-05-25-json-ui-output-mode.md
Design spec locking the JSON document structure (meta, summary, groups, error variant), field rules, status/counts formatting, redaction behavior, and schema constraints. Implementation plan outlines tasks for document types, BuildDocument, API changes, and CLI wiring.
Document data model and BuildDocument transformation
report/document.go
Introduces Document, Meta, Summary, Group, Item, and ErrorDocument types with SchemaVersion constant. Implements BuildDocument to transform validator.Report and config into grouped JSON output with deterministic ordering, per-source grouping, category/step parsing, metadata echoing with redaction, and verdict/exit-code derivation.
Document generation and transformation tests
report/document_test.go
Comprehensive tests validating BuildDocument behavior: splitCheck/redactString helpers, grouping and group order, category/step parsing, per-group and summary counts, verdict/exit-code mapping, metadata formatting with URL/message redaction, skip and leftover-source handling, details field omission when nil, and byte-for-byte deterministic JSON output.
Report writing API: WriteJSON and WriteErrorJSON
report/report.go, report/report_test.go
WriteJSON signature updated to accept config and emit BuildDocument result with current UTC timestamp; new WriteErrorJSON emits error-document JSON with apiKey redaction; writeIndentedJSON helper marshals values with indentation. Tests validate Document structure, SchemaVersion, group count, verdict, indentation, and apiKey redaction in ErrorDocument.
CLI API key redaction and error handling
cmd/oba-validator/main.go
Adds redactionKey helper to extract apiKey from JSON config; refactors run to redact keys in config-load and validator-run errors before output; emits JSON errors via WriteErrorJSON under --json flag with exit code 2; updates successful JSON output call to pass config to WriteJSON.
CLI JSON output and redaction tests
cmd/oba-validator/main_test.go
Tests CLI in --json mode: config error emits valid JSON with schemaVersion and error fields; successful run against mocked OBA/feed servers produces Document with meta/summary/groups; inline apiKey values are redacted from both JSON error output (stdout) and text error output (stderr).
JSON Schema definition and conformance validation
schema/oba-validator-report.schema.json, report/schema_test.go, go.mod
Commits schema targeting draft 2020-12 with oneOf for reportDocument/errorDocument variants, strict additionalProperties, and open details. Adds jsonschema/v6 dependency. Tests validate success/error documents conform, reject malformed payloads, and compile schema correctly via jsonschema library.
Documentation updates
CLAUDE.md, README.md
CLAUDE.md describes Report rendering as WriteText or UI-oriented JSON Document via BuildDocument for deterministic tests. README.md adds "JSON output" section documenting meta/summary/groups structure, error-variant with exit code 2 on config/run failures, and published JSON Schema location.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.07% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a JSON-for-UI output mode with a published JSON Schema. It is specific and highlights the primary feature.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch json-ui-output-mode

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
docs/superpowers/plans/2026-05-25-json-ui-output-mode.md (1)

82-83: ⚡ Quick win

Prefer make targets in run instructions for repo consistency.

These steps currently instruct raw Go commands (go test, go build, go vet, go mod tidy, etc.). Please switch to repo-standard make targets where equivalents exist (make test, make build, make vet, make tidy) so contributors follow one consistent workflow.

Based on learnings: "Use make targets for common tasks (build, test, test-live, vet, fmt, run, tidy, install, clean) instead of running raw Go commands directly".

Also applies to: 200-201, 333-334, 437-438, 540-541, 616-617, 693-694, 731-732, 961-962, 1023-1024

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/superpowers/plans/2026-05-25-json-ui-output-mode.md` around lines 82 -
83, Update the documentation lines that run raw Go commands (e.g., the line
showing "Run: `go test ./report/ -run 'TestSplitCheck|TestRedactString' -v`") to
use the repository's make targets instead; replace `go test` with the equivalent
`make test` (and similarly swap `go build`, `go vet`, `go mod tidy`, etc. for
`make build`, `make vet`, `make tidy`) and adjust any test-specific flags to be
passed via the make target convention used in this repo; apply the same change
to the other occurrences called out (around the lines that currently show raw
`go` commands at the noted sections).
cmd/oba-validator/main.go (1)

89-104: 💤 Low value

Consider extracting the duplicated "output error:" literal to a constant.

The string "output error:" appears three times (lines 94, 111, 130). While functional, extracting it to a package-level constant improves maintainability.

♻️ Suggested refactor
+const outputErrPrefix = "output error:"
+
 func run(args []string, stdout, stderr io.Writer) int {
 	// ... 
 			if werr := report.WriteErrorJSON(stdout, err.Error(), key); werr != nil {
-				fmt.Fprintln(stderr, "output error:", werr)
+				fmt.Fprintln(stderr, outputErrPrefix, werr)
 			}
 	// ... (apply similarly to other occurrences)

Also applies to: 107-121, 129-132

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/oba-validator/main.go` around lines 89 - 104, The code duplicates the
literal "output error:" in main.go; introduce a package-level constant (e.g.,
outputErrorPrefix) and replace all literal occurrences used with fmt.Fprintln
and any similar log writes (locations around the cfg loading error block and the
other error-handling blocks that call fmt.Fprintln with stderr) to use that
constant instead; update references in the cfg load error handling (where cfg,
err, redactionKey, o.jsonOut, report.WriteErrorJSON, stdout, stderr are used)
and the other error branches (lines noted in the review) so all three places use
the single constant for maintainability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/superpowers/specs/2026-05-25-json-ui-output-design.md`:
- Around line 52-58: The fenced code block containing the flow diagram (starting
with "config.Load ──err──▶ (--json? WriteErrorJSON : text) ; exit 2" and ending
with "Report ──▶ (--json? WriteJSON=BuildDocument : WriteText) ; exit
rep.ExitCode()") needs a language tag to satisfy MD040; replace the opening
triple backticks with a tagged fence (e.g., change "```" to "```text") so the
block is fenced as text while leaving the block content unchanged.

In `@README.md`:
- Line 54: Update the malformed JSON example `{ "schemaVersion", "error" }` in
README.md to a valid JSON object: replace it with a proper key/value example
such as `{ "schemaVersion": "1.0", "error": "description" }` (or similar
concrete values) so the emitted error-object example is valid JSON; locate the
example text and perform the replacement in the documentation.

---

Nitpick comments:
In `@cmd/oba-validator/main.go`:
- Around line 89-104: The code duplicates the literal "output error:" in
main.go; introduce a package-level constant (e.g., outputErrorPrefix) and
replace all literal occurrences used with fmt.Fprintln and any similar log
writes (locations around the cfg loading error block and the other
error-handling blocks that call fmt.Fprintln with stderr) to use that constant
instead; update references in the cfg load error handling (where cfg, err,
redactionKey, o.jsonOut, report.WriteErrorJSON, stdout, stderr are used) and the
other error branches (lines noted in the review) so all three places use the
single constant for maintainability.

In `@docs/superpowers/plans/2026-05-25-json-ui-output-mode.md`:
- Around line 82-83: Update the documentation lines that run raw Go commands
(e.g., the line showing "Run: `go test ./report/ -run
'TestSplitCheck|TestRedactString' -v`") to use the repository's make targets
instead; replace `go test` with the equivalent `make test` (and similarly swap
`go build`, `go vet`, `go mod tidy`, etc. for `make build`, `make vet`, `make
tidy`) and adjust any test-specific flags to be passed via the make target
convention used in this repo; apply the same change to the other occurrences
called out (around the lines that currently show raw `go` commands at the noted
sections).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 11352a98-471f-4077-92ba-6e0007bb5225

📥 Commits

Reviewing files that changed from the base of the PR and between cec626b and 6a71083.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (13)
  • CLAUDE.md
  • README.md
  • cmd/oba-validator/main.go
  • cmd/oba-validator/main_test.go
  • docs/superpowers/plans/2026-05-25-json-ui-output-mode.md
  • docs/superpowers/specs/2026-05-25-json-ui-output-design.md
  • go.mod
  • report/document.go
  • report/document_test.go
  • report/report.go
  • report/report_test.go
  • report/schema_test.go
  • schema/oba-validator-report.schema.json

Comment thread docs/superpowers/specs/2026-05-25-json-ui-output-design.md Outdated
Comment thread README.md Outdated
Address CodeRabbit review nits on PR #2: the README error-object example was not
valid JSON syntax, and the spec's flow-diagram fence lacked a language tag (MD040).
@sonarqubecloud
Copy link
Copy Markdown

@aaronbrethorst aaronbrethorst merged commit 1c08c69 into main May 25, 2026
6 checks passed
@aaronbrethorst aaronbrethorst deleted the json-ui-output-mode branch May 25, 2026 21:25
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