Skip to content

feat(dashboard): consume the FP-judge triage overlay - #33

Merged
PhysShell merged 2 commits into
mainfrom
claude/fp-judge-dashboard-consume
Jul 2, 2026
Merged

feat(dashboard): consume the FP-judge triage overlay#33
PhysShell merged 2 commits into
mainfrom
claude/fp-judge-dashboard-consume

Conversation

@PhysShell

@PhysShell PhysShell commented Jul 2, 2026

Copy link
Copy Markdown
Owner

What & why

Closes the gap deferred from #31 (the original Codex P2): build_dashboard.py rendered the raw audit and ignored triage_class, so apply_verdicts' judged_fp findings were never retired — the FP-judge overlay had no effect on the dashboard. Per the roadmap (docs/fp-judge/STATUS.md, Phase 2 step 2: apply_verdicts --out findings-triaged.jsonbuild_dashboard.py), the dashboard now actually consumes the triage.

The real o7 judge run itself is stand-only (007's private harness); this PR is the domain-side consumer that makes its output render.

Changes

viz/build_dashboard.py

  • collect() auto-prefers <DATA_DIR>/findings-triaged.json when present (else raw findings.json), reads each finding's triage_class/verdict, and adds a triage dimension + interned verdict reason to the per-finding rows.
  • UI (all gated on the input being triaged — raw audits render exactly as before):
    • KPIs lead with the real / uncertain / unjudged / judged-FP split.
    • A triage chip filter (visibility toggles) and a Triage table column with the verdict reason on hover.
    • judged_fp is retired from every aggregate by default — counted in a KPI, revealable via its chip — per verdict-contract.md §3 ("counted, not hidden").

CI / fixtures

  • viz/fixtures/fp-verdicts.json — a committed synthetic overlay (its generated_from pins the fixture digest) exercising every triage class.
  • .github/workflows/ci.yml — the smoke now renders the raw path, then runs apply_verdicts (also smoking its staleness guard + merge) and re-renders the triaged path.
  • .gitignore — the derived viz/fixtures/findings-triaged.json (overlay is committed; this is generated).

Docs

  • docs/fp-judge/STATUS.md — mark dashboard consumption done.

Design decisions (confirmed with maintainer)

  • judged_fp: hidden by default, revealable via its chip + counted in a KPI (contract §3).
  • Input: auto-prefer findings-triaged.json, fall back to findings.json — no change to the roadmap/CI invocation shape.

How verified

Locally, reproducing the CI job:

  • Raw path (build_dashboard.py viz/fixtures, no overlay) → no triage UI; identical to prior behavior.
  • Triaged path (apply_verdicts --out … then re-render) → triaged=true, counts {real:2, uncertain:2, unjudged:9, judged_fp:1}, Triage column + chips present, verdict_summary.run_id carried through.
  • apply_verdicts --selftest green; a drifted fixture correctly rejected by the staleness guard (exit 2).

🤖 Generated with Claude Code

https://claude.ai/code/session_01DFSpD9yXgXePrFFX62XZ53


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Dashboard now supports triage-aware views when processed findings are available.
    • Added a triage filter and a new table column for verdict details.
    • KPIs now split results into clearer status categories for triaged data.
  • Bug Fixes

    • Hidden resolved false positives by default while still allowing them to be reviewed.
    • Improved handling of triaged results so dashboard totals stay consistent.

Closes the deferred gap from #31: build_dashboard.py rendered the raw audit and
ignored triage_class, so apply_verdicts' judged_fp findings were never retired.

- collect() auto-prefers <DATA_DIR>/findings-triaged.json (else raw findings.json),
  reads each finding's triage_class/verdict, and emits a triage dimension + reason.
- UI: KPIs lead with the real/uncertain/unjudged/judged-FP split; a triage chip
  filter (visibility toggles) and a Triage table column with the verdict reason on
  hover; judged_fp is retired from every aggregate by default (counted in a KPI,
  revealable via its chip) per verdict-contract.md §3.
- Backward compatible: with no overlay, renders exactly as before.
- CI smokes both paths: raw render, then apply_verdicts merge + triaged render,
  via a committed synthetic overlay viz/fixtures/fp-verdicts.json (its
  generated_from pins the fixture digest; the derived findings-triaged.json is
  gitignored).
- STATUS.md: mark dashboard-consumption done.

Verified locally: raw path shows no triage UI; triaged path -> triaged=true,
counts {real:2,uncertain:2,unjudged:9,judged_fp:1}, Triage column + chips present,
run_id provenance carried; apply_verdicts --selftest green; stale overlay rejected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFSpD9yXgXePrFFX62XZ53
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@PhysShell, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 10 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5bcae986-a6a6-4960-a143-6dc73e5db042

📥 Commits

Reviewing files that changed from the base of the PR and between 581a437 and dd54336.

📒 Files selected for processing (5)
  • .github/workflows/ci.yml
  • .gitignore
  • docs/fp-judge/STATUS.md
  • viz/build_dashboard.py
  • viz/fixtures/fp-verdicts.json
📝 Walkthrough

Walkthrough

Adds a CI-driven FP-judge triage overlay: a synthetic verdicts fixture, an apply_verdicts.py invocation in CI producing a triaged findings file, and dashboard backend/frontend changes to detect triaged data, embed triage fields per finding, and render triage KPIs, filter chips, and a table column.

Changes

FP-judge triage overlay

Layer / File(s) Summary
Verdict overlay fixture and CI wiring
viz/fixtures/fp-verdicts.json, .github/workflows/ci.yml, .gitignore, docs/fp-judge/STATUS.md
New synthetic FP-judge verdicts fixture; CI now applies apply_verdicts.py to generate findings-triaged.json before rebuilding the dashboard; the generated file is gitignored; STATUS.md documents the triage consumption contract.
Backend detection and embedding of triage data
viz/build_dashboard.py (lines 42-212)
Adds TRIAGE class constants, prefers findings-triaged.json when present, detects triaged input, extends per-finding row schema with triage/verdict-reason indexes, computes triage_counts, and adds triaged/verdict_summary/triage dims to the payload.
Frontend triage filter chips and table column
viz/build_dashboard.py (lines 342-644)
Adds a triage chip UI container and metadata, verdict-split KPIs, filter logic hiding judged_fp by default, renderTriageChips(), and a conditional Triage table column with reason tooltip.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI as CI Workflow
  participant AV as apply_verdicts.py
  participant BD as build_dashboard.py
  participant Data as findings-triaged.json
  participant UI as Dashboard UI

  CI->>BD: build_dashboard.py viz/fixtures (raw findings)
  CI->>AV: apply_verdicts.py findings.json fp-verdicts.json
  AV->>Data: write findings-triaged.json
  CI->>BD: build_dashboard.py viz/fixtures (rerender)
  BD->>Data: detect and load triaged findings
  BD->>BD: compute triage_counts, verdict_summary
  BD->>UI: embed triage fields, dims, KPIs
  UI->>UI: renderTriageChips(), filteredRows() hides judged_fp
Loading

Possibly related PRs

  • PhysShell/OwnAudit#6: Both PRs modify viz/build_dashboard.py's dashboard data ingestion and row schema generation that this PR extends with triage fields.
  • PhysShell/OwnAudit#7: Both PRs extend viz/build_dashboard.py's filtering/table UI that this PR builds on with triage chips and columns.
  • PhysShell/OwnAudit#9: This PR extends the "dashboard smoke" CI step introduced in that PR by adding a triage-overlay generation/merge step.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: the dashboard now consumes the FP-judge triage overlay.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/fp-judge-dashboard-consume

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d66cb0be5f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread viz/build_dashboard.py Outdated
# present: it carries per-finding `triage_class`/`verdict`, so the dashboard can retire
# confident false positives. Fall back to the raw findings.json otherwise.
triaged_path = os.path.join(STS, "findings-triaged.json")
src_path = triaged_path if os.path.isfile(triaged_path) else os.path.join(STS, "findings.json")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Validate triaged input before preferring it

When artifacts/findings-triaged.json is left over from an earlier judge run and Run-Audit.ps1 refreshes only artifacts/findings.json, this unconditional auto-preference bypasses the staleness guard in apply_verdicts and renders the old triage as current truth. In that state judged_fp rows from the previous audit are still retired from the dashboard even though verdict_summary.generated_from no longer matches the current raw findings, which is exactly the stale-overlay case the contract says must be refused.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Real hole — fixed in dd54336. The consumer now re-applies the FP-judge staleness rule: findings-triaged.json is preferred only when its verdict_summary.generated_from equals sha256(findings.json) (same check apply_verdicts.verify_fresh enforces). A leftover/stale overlay (e.g. Run-Audit.ps1 refreshed findings.json but not the overlay) is ignored — it falls back to raw findings.json and prints a warning — so an old triage is never rendered as current truth.

Verified: fresh overlay → preferred; mutate findings.json after judging → overlay ignored + warning.


Generated by Claude Code

Comment thread viz/build_dashboard.py Outdated
Comment on lines 136 to 138
raw = open(src_path, encoding="utf-8").read()
# content digest = the audit run's identity for the trend series (below).
digest = hashlib.sha256(raw.encode("utf-8")).hexdigest()[:16]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Base the trend digest on raw findings

When a triaged file exists, raw now contains findings-triaged.json, so the history digest includes judge metadata, verdict reasons, output ordering, and threshold changes rather than just the audit findings. Running the documented raw render followed by apply_verdicts and a triaged render for the same audit will add a second trend point, and rerunning the judge with different overlay content will look like a new audit run even if findings.json did not change.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Agreed — fixed in dd54336. The trend digest is now always sha256 of the raw findings.json bytes, independent of which file is rendered. So the documented raw-then-triaged render of one audit collapses to a single trend point (identical digest), and re-running the judge with different overlay content no longer looks like a new audit run. The digest is the audit's identity, not the overlay's.

Verified: raw render + triaged render of the same audit → one history point (no double-count).


Generated by Claude Code

… on raw findings

Addresses Codex review on #33:

- P1 (staleness): auto-preferring findings-triaged.json bypassed the FP-judge
  staleness guard — a leftover overlay (Run-Audit refreshed findings.json but not
  the overlay) would render an old triage as current truth. Now the consumer
  re-checks verdict_summary.generated_from == sha256(findings.json) and ignores a
  stale overlay (falls back to raw findings + a warning), same rule as apply_verdicts.
- P2 (trend identity): the history digest was taken from the rendered file, so a
  triaged render (judge metadata/reasons/threshold) diverged from the raw render of
  the same audit and double-counted trend points. Digest is now always sha256 of the
  raw findings.json bytes — the audit run's identity, independent of the overlay.

Verified: fresh overlay -> preferred; raw+triaged render of one audit -> single
trend point; stale overlay -> ignored with warning; CI triaged render still shows
the Triage view.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFSpD9yXgXePrFFX62XZ53

Copy link
Copy Markdown
Owner Author

@coderabbitai review


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

@PhysShell I'll review the changes now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@PhysShell
PhysShell merged commit 540aa06 into main Jul 2, 2026
3 checks passed
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.

2 participants