Skip to content

Feat: added Deployment Summary UX for the previous PR #114 - #115

Merged
Khanz9664 merged 2 commits into
mainfrom
feat/deployment-ux
Jun 1, 2026
Merged

Khanz9664 merged 2 commits into
mainfrom
feat/deployment-ux

Conversation

@Khanz9664

@Khanz9664 Khanz9664 commented Jun 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

The Deployment Summary has been successfully integrated natively into the core TrustReport user experience, drastically improving the discoverability of deployment recommendations without breaking any existing API surfaces or logic.

1. Architectural Changes

The deployment summary string (and its rich HTML equivalent) is now systematically embedded into the three primary report generation endpoints:

TrustReport.show()

The core CLI output now features the deployment summary printed immediately after the Score Summary / Penalty Explanation section and before Key Observations. This establishes a highly natural reading flow:

  1. Score
  2. Why the score happened (Penalties)
  3. Can I deploy? (Deployment Verdict & Recommendations)
  4. Detailed Observations

TrustReport._generate_text_report()

The plain-text export (used when saving to .txt files) mirrors the structure of show(), ensuring the deployment summary is persisted when sharing analysis logs in CI/CD pipelines or text archives.

TrustReport._repr_html_()

The Jupyter Notebook output now renders a visually distinct, rich HTML block. It utilizes the structured deployment_explanation dictionary rather than the plain text string, converting the reasons into a clean bulleted list with color-coded success/failure icons (✓/✗), and the recommendations into a formatted checklist.

Note

Backward Compatibility Maintained:
As intended, _format_score_explanation() was left completely intact. No existing trust score mechanics, blocking logic, or visualization endpoints were altered. This is a 100% additive UX enhancement.

2. Test Coverage

The test suite in tests/test_deployment_explanation.py was expanded to rigorously verify the UX changes:

  • test_show_contains_deployment_summary: Captures stdout using capsys to assert that report.show() successfully prints the "Deployment Verdict:" string and subsequent recommendations.
  • test_deployment_summary_in_text_report: Asserts the output of _generate_text_report().
  • test_deployment_summary_in_html_report: Mocks out the matplotlib summary plot to independently assert the presence of the new HTML deployment block in _repr_html_().

All 9 tests pass successfully.

3. Changelog Documentation

The CHANGELOG.md file was updated to formally record this UX improvement, explicitly stating:

Deployment recommendations are now surfaced directly in TrustReport.show(), text exports, and HTML report views. Users now receive deployment verdicts, primary risk identification, and actionable recommendations without needing to access deployment_summary manually.

Summary by CodeRabbit

  • New Features

    • Deployment recommendations now automatically surface in report outputs across all formats (interactive display, text exports, HTML reports).
    • Reports now include deployment verdicts, primary risk identification, and actionable recommendations without manual consultation.
  • Tests

    • Added test coverage for deployment recommendation rendering across output surfaces.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

More reviews will be available in 53 minutes and 8 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32810931-3a68-4827-947b-ffa36beeebd9

📥 Commits

Reviewing files that changed from the base of the PR and between ebffba0 and 7495282.

📒 Files selected for processing (2)
  • tests/test_deployment_explanation.py
  • trustlens/report.py
📝 Walkthrough

Walkthrough

Deployment recommendations are now automatically displayed across all TrustReport output surfaces: direct console output via show(), plain text exports, and Jupyter HTML representations. The implementation adds deployment summary rendering to each output method and includes comprehensive test coverage validating consistent display of verdicts, risk identification, and recommendations.

Changes

Deployment Recommendation Display

Layer / File(s) Summary
Console and text report output
trustlens/report.py
TrustReport.show() prints deployment summary after score explanation; _generate_text_report() appends deployment summary lines to text output.
HTML deployment verdict card
trustlens/report.py
_repr_html_() renders a new deployment verdict section containing verdict, primary risk, per-reason status, and recommendations using deployment_explanation.
Multi-surface output tests
tests/test_deployment_explanation.py
Three new tests verify deployment summary renders consistently in show() stdout, _generate_text_report() return value, and _repr_html_() HTML output, including verdict text and recommendation assertions.
Changelog documentation
CHANGELOG.md
Unreleased section documents deployment recommendations now surfaced automatically via all output methods without manual deployment_summary access.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A report unfolds in three clear views,
Show, text, and HTML—pick your muse!
Verdicts and risks now brightly gleam,
Deployment wisdom flows downstream. 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% 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
Title check ✅ Passed The title accurately describes the main change: adding Deployment Summary UX features as a follow-up to PR #114.
Description check ✅ Passed The description comprehensively covers all template sections with detailed explanations of architectural changes, test coverage, and changelog updates.
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 feat/deployment-ux

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.

@llamapreview llamapreview Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Auto Pull Request Review from LlamaPReview

Large PR Notification

Dear contributor,

Thank you for your substantial contribution to this project. LlamaPReview has detected that this Pull Request contains a large volume of changes, which exceeds our current processing capacity.

Details:

  • PR and related contents total size: Approximately 1,495,976 characters
  • Current limit: 256,000 characters

Next steps:

  1. Consider breaking this PR into smaller, more focused changes if possible.
  2. For manual review, please reach out to your team members or maintainers.

We appreciate your understanding and commitment to improving this project. Your contributions are valuable, and we want to ensure they receive the attention they deserve.

LlamaPReview is continuously evolving to better serve the community. Share your thoughts on handling large PRs in our GitHub Discussions - your feedback helps us improve and expand our capabilities.

If you have any questions or need assistance, our community and support team are here to help.

Best regards,
LlamaPReview Team

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/test_deployment_explanation.py (1)

155-157: ⚡ Quick win

Strengthen assertions to enforce placement contract, not just presence.

On Line 155 and Line 170 (and similarly in the HTML test on Line 189-191), these checks only verify substring existence. They can still pass if the deployment block moves to the wrong section or if "Fairness" appears elsewhere. Add relative-position assertions (and a more specific HTML marker) so tests enforce the intended UX sequence from the PR objective.

Suggested test hardening
 def test_show_contains_deployment_summary(mock_report, capsys):
@@
     mock_report.show()
     captured = capsys.readouterr()
-    assert "Deployment Verdict: CAUTION" in captured.out
-    assert "Primary Risk:" in captured.out
+    out = captured.out
+    assert "Deployment Verdict: CAUTION" in out
+    assert "Primary Risk:" in out
     assert "Investigate subgroup performance disparities" in captured.out
+    # Contract: deployment summary should appear before key observations
+    assert out.index("Deployment Verdict:") < out.index("Key Observations")
@@
 def test_deployment_summary_in_text_report(mock_report):
@@
-    assert "Deployment Verdict: CAUTION" in text
-    assert "Primary Risk:" in text
+    assert "Deployment Verdict: CAUTION" in text
+    assert "Primary Risk:" in text
     assert "Investigate subgroup performance disparities" in text
+    assert text.index("Deployment Verdict:") < text.index("Key Observations")
@@
 def test_deployment_summary_in_html_report(mock_report):
@@
     html = mock_report._repr_html_()
     assert "Deployment Verdict:" in html
-    assert "Fairness" in html
+    assert "Primary Risk" in html
+    assert "Fairness" in html
     assert "Investigate subgroup performance disparities" in html

Also applies to: 170-172, 189-191

🤖 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 `@tests/test_deployment_explanation.py` around lines 155 - 157, The current
assertions only check for substrings and can pass if the deployment block
appears in the wrong place; update the tests around the captured output checks
that reference "Deployment Verdict: CAUTION", "Primary Risk:", and "Investigate
subgroup performance disparities" to enforce relative ordering (e.g., assert
captured.out.index("Fairness") < captured.out.index("Deployment Verdict:
CAUTION") and that "Primary Risk:" and the specific investigation line appear
after the verdict) and in the HTML assertions replace generic substring checks
with a specific structural marker (for example assert the deployment block
occurs inside the intended container by checking an HTML id/class or the
relative index of "<div id=\"deployment-verdict\">" vs "<section
class=\"fairness\">") so the test validates placement, not just presence.
🤖 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 `@trustlens/report.py`:
- Around line 1511-1539: The deployment card interpolates unescaped dynamic
content from self.deployment_explanation (used in reasons_html, pr_html,
recs_html and the verdict line) which can lead to HTML/script injection; fix by
HTML-escaping all dynamic values before building the strings (escape
exp["verdict"], each r["message"] in reasons_html, exp["primary_risk"]["metric"]
in pr_html, and each recommendation in recs_html) — e.g., import and use a safe
escaper (html.escape or markupsafe.escape) when constructing reasons_html,
pr_html, recs_html and then concatenate into html.

---

Nitpick comments:
In `@tests/test_deployment_explanation.py`:
- Around line 155-157: The current assertions only check for substrings and can
pass if the deployment block appears in the wrong place; update the tests around
the captured output checks that reference "Deployment Verdict: CAUTION",
"Primary Risk:", and "Investigate subgroup performance disparities" to enforce
relative ordering (e.g., assert captured.out.index("Fairness") <
captured.out.index("Deployment Verdict: CAUTION") and that "Primary Risk:" and
the specific investigation line appear after the verdict) and in the HTML
assertions replace generic substring checks with a specific structural marker
(for example assert the deployment block occurs inside the intended container by
checking an HTML id/class or the relative index of "<div
id=\"deployment-verdict\">" vs "<section class=\"fairness\">") so the test
validates placement, not just presence.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e97448cd-5472-4bc8-ad87-db4e78202876

📥 Commits

Reviewing files that changed from the base of the PR and between cf2f9ce and ebffba0.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • examples/trustlens_demo.ipynb
  • tests/test_deployment_explanation.py
  • trustlens/report.py

Comment thread trustlens/report.py
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Autofix skipped. No unresolved CodeRabbit review comments with fix instructions found.

@Khanz9664
Khanz9664 merged commit 7691569 into main Jun 1, 2026
11 checks passed
@Khanz9664
Khanz9664 deleted the feat/deployment-ux branch June 1, 2026 03:44
komoike-oss28-ui added a commit to komoike-oss28-ui/TrustLens that referenced this pull request Jun 2, 2026
…COLORS

Merging upstream/main (Khanz9664#115, Deployment Summary UX) reintroduced references
to summary_plot._C in report.py, which was removed in this branch's style
migration. Repoint them to the canonical BRAND_COLORS so the merged tree
type-checks. Color values unchanged.

Refs Khanz9664#57
Khanz9664 added a commit that referenced this pull request Jun 3, 2026
… (#102)

* feat(visualization): add centralized style module

Introduce trustlens/visualization/style.py as the single source of truth
for visual constants across plotting functions:

- BRAND_COLORS dict for named colors (blue/orange/green/red/amber/...)
- PALETTE list for categorical plots, drawn from BRAND_COLORS
- SEMANTIC_COLORS for severity (acceptable/moderate/severe/unknown),
  verdict (deploy/caution/do_not_deploy), grade (A/B/C/D), direction,
  and neutral references
- TYPOGRAPHY, GRID, FIG_DEFAULTS, SPACING for non-color constants
- Frozen Theme dataclass with DEFAULT_THEME, leaving room for future
  named themes (dark, colorblind, publication) without API changes
- apply_style() context manager that scopes matplotlib.rcParams mutations
  to a `with` block, preventing global state leakage in notebooks and
  larger ML pipelines
- styled_figure() and get_categorical_colors() helpers

The module is internal (no __all__) - the surface may evolve before being
promoted to a supported public API.

Relates to #57

* test(visualization): add tests for centralized style module

Add tests/test_visualization_style.py covering:

- Hex validity and uniqueness of palette / brand / semantic colors
- Required keys for severity, verdict, and grade scales
- Theme dataclass frozen-ness and instance independence
- apply_style context manager: rcParams restoration on normal exit,
  on exception, and through nested usage
- styled_figure: default and custom figsize, multi-subplot support,
  facecolor application
- get_categorical_colors: cyclic behavior, empty / negative inputs
- Module surface completeness

Relates to #57

* refactor(calibration): use centralized style module

Replace inline styling in plot_reliability_diagram() with the centralized
style module introduced in the previous commits:

- Remove function-local BLUE / ORANGE / GRAY constants
- Replace plt.style.use("seaborn-v0_8-whitegrid") with apply_style()
  context manager - rcParams are now scoped and restored on exit
- Source colors from theme.brand and theme.semantic["neutral"]
- Source grid alpha and savefig DPI from theme

Visual output is preserved (same hex values, same figsize, same alpha
and linewidth values). No public API changes.

Update CHANGELOG.md with an entry under [Unreleased] / Added.

Closes #57 (calibration_plots only; remaining visualization modules to
follow in subsequent commits on this branch).

* fix(visualization): address review feedback from automated bots

Address feedback from CodeRabbit and LlamaPReview on PR #102:

- CHANGELOG.md: change `(closes #57)` to `(refs #57)` since this is an
  incremental migration; the issue should not auto-close until all
  visualization modules are migrated on this branch.
- style.py: guard `get_categorical_colors()` against an empty theme
  palette to fail fast with a ValueError instead of a ZeroDivisionError.
- tests: add a regression test for the empty palette guard.
- calibration_plots.py: remove the faulty `"agg" not in get_backend()`
  check that incorrectly skipped `plt.show()` on interactive backends
  whose names also contain "agg" (e.g. QtAgg, TkAgg). This bug pre-dated
  this PR but was surfaced by the review.

Relates to #57

* fix(visualization): add base-style warning and validate n_bins

Address remaining review feedback from PR #102:

- style.py: emit a UserWarning when apply_style() cannot load the
  theme's base_style sheet, instead of silently falling through to
  rcParams-only styling. Custom themes with typos or missing styles
  are now visible during debugging without becoming hard failures
  (per LlamaPReview and @Khanz9664).
- calibration_plots.py: validate n_bins >= 1 up front with a clear
  ValueError instead of letting an invalid value reach the bar width
  calculation (per CodeRabbit and @Khanz9664).
- tests: add coverage for the new warning path and the n_bins guard
  in a new tests/test_calibration_visualization.py file, following
  the repo's per-module visualization test convention.

Relates to #57

* refactor(failure): use centralized style module

Migrate failure_plots.py to use apply_style() context manager and
theme references from trustlens.visualization.style, removing the
inline GREEN/RED constants and direct plt.style.use() call.

Color values are preserved bit-for-bit:
- GREEN "#34C759"  -> theme.brand["green"]
- RED   "#FF3B30"  -> theme.brand["red"]
- edgecolor="white"   -> theme.semantic["neutral"]["edge"]
- edgecolor="#CCCCCC" -> theme.semantic["neutral"]["annotation_edge"]
- facecolor="white"   -> theme.semantic["neutral"]["annotation_face"]
- dpi=150 (savefig)   -> theme.fig_defaults["savefig_dpi"]

Magic numbers (alpha, figsize, fontsize, bar width factor) are
intentionally left as-is, per the migration plan agreed in PR #102.

Visual parity verified: full test suite (301 passed) runs unchanged.

Refs #57

* refactor(bias): use centralized style module

Migrate bias_plots.py to use apply_style() context manager and
theme references from trustlens.visualization.style, removing the
inline PALETTE definition (which exactly duplicated style.PALETTE)
and the direct plt.style.use() call.

Color values are preserved bit-for-bit:
- PALETTE (8 colors)   -> get_categorical_colors(n) from style module
                          (identical hex values, identical mod cycling)
- edgecolor="white"    -> theme.semantic["neutral"]["edge"]
- edgecolor="#CCCCCC"  -> theme.semantic["neutral"]["annotation_edge"]
- facecolor="white"    -> theme.semantic["neutral"]["annotation_face"]
- dpi=150 (savefig)    -> theme.fig_defaults["savefig_dpi"]

Magic numbers (linewidth, alpha, figsize, fontsize, percentage
offset factor) are intentionally left as-is, per the migration plan
agreed in PR #102.

Visual parity verified: full test suite (301 passed) runs unchanged.

Refs #57

* refactor(representation): use centralized style module

Migrate representation_plots.py to use apply_style() context manager and
theme references from trustlens.visualization.style, removing the inline
hex color literals and the direct plt.style.use() call.

Color values are preserved bit-for-bit:
- "#34C759" (silhouette / separability good)   -> theme.brand["green"]
- "#FF9F0A" (silhouette / separability warn)   -> theme.brand["amber"]
- "#FF3B30" (silhouette / separability bad)    -> theme.brand["red"]
- "#4B8BF5" (Within-Class card)                -> theme.brand["blue"]
- "#AF52DE" (Between-Class card)               -> theme.brand["purple"]
- "#666666" (subtitle text)                    -> theme.brand["text_muted"]
- "#444444" (card label / ratio label text)    -> theme.brand["text_dark"]
- "#888888" (guidance footer text)             -> theme.brand["text_subtle"]
- dpi=150  (savefig in both functions)         -> theme.fig_defaults["savefig_dpi"]

The matplotlib `tab10` cmap used in plot_embedding_2d() is intentionally
left untouched, since it is a separate color system from BRAND_COLORS and
substituting get_categorical_colors() would change the per-class scatter
colors (visual parity violation).

Magic numbers (alpha, figsize, fontsize, linewidth, marker size, ...) are
intentionally left as-is, per the migration plan agreed in PR #102.

Also restores the "Centralized Visualization Styling" CHANGELOG entry that
was inadvertently dropped during the recent merge from main (commit
53ea795), and extends its "so far:" list to include representation_plots.py.

Visual parity verified: full test suite (302 passed) runs unchanged.

Refs #57

* refactor(fairness): use centralized style module

Migrate fairness.py to use apply_style() context manager and theme
references from trustlens.visualization.style, removing the inline PALETTE
list, the violation_colors dict, and the direct plt.style.use() calls.

Color values are preserved bit-for-bit:
- PALETTE (8 colors)              -> get_categorical_colors() (mod-cycling)
- bar edgecolor "white"           -> theme.semantic["neutral"]["edge"]
- annotation facecolor "white"    -> theme.semantic["neutral"]["annotation_face"]
- annotation edgecolor "#CCCCCC"  -> theme.semantic["neutral"]["annotation_edge"]
- TPR/gap bar "#4B8BF5"           -> theme.brand["blue"]
- FPR/gap bar "#F5784B"           -> theme.brand["orange"]
- violation_colors {severe/moderate/acceptable} -> theme.semantic["severity"]
- violation fallback "#CCCCCC"    -> theme.semantic["severity"]["unknown"] (same hex)
- savefig dpi=150                 -> theme.fig_defaults["savefig_dpi"]

The grid alpha is left as the literal 0.35; it intentionally differs from
theme.grid["alpha"] (0.4), so theming it would change visual output. Other
magic numbers (alpha=0.85, figsize, fontsize) are left as-is per the
migration plan agreed in PR #102. The *_multi wrappers delegate to the
single-feature functions and are unchanged.

Also updates the CHANGELOG "so far" list to include fairness.py.

Visual parity verified: full test suite (312 passed) runs unchanged.

Refs #57

* refactor(summary): use centralized style module

Migrate summary_plot.py to source colors from the centralized
trustlens.visualization.style module and to scope its matplotlib.rcParams
mutations inside apply_style(), removing the inline _C palette and
_GRADE_COLORS dict and the global plt.rcParams.update() call.

Color values are preserved bit-for-bit:
- _C[...] (blue/orange/green/red/amber/purple/gray/light/white/dark)
                                  -> BRAND_COLORS[...]
- _GRADE_COLORS {A/B/C/D}         -> SEMANTIC_COLORS["grade"]
- class-distribution palette      -> built from BRAND_COLORS in the same
                                     order (NOT get_categorical_colors, which
                                     is a different 8-color palette)
- savefig dpi=150                 -> FIG_DEFAULTS["savefig_dpi"]

The previously global rcParams.update() leaked styling into the user's
matplotlib session; it is now scoped to the apply_style() context, which is
the core goal of #57. apply_style() already sets font, spines, and white
figure/axes facecolors via the base theme, so only "axes.grid": False is
re-applied inside the context (the base style seaborn-v0_8-whitegrid enables
the grid; the dashboard draws its own per-panel grids).

Left as literals (no brand equivalent, parity-preserving): the "#DDD"
annotation-box edges, the per-panel grid alphas (0.2/0.25) with dashed
linestyle, and the bar edgecolor "white". Magic numbers (alpha, figsize,
fontsize) are unchanged per the migration plan agreed in PR #102.

Also updates the CHANGELOG "so far" list to include summary_plot.py.

Visual parity verified: full test suite (312 passed) runs unchanged, and an
rcParams leak check confirms no global state leaks after rendering.
Also repoints the cross-module references to summary_plot._C in
trust_score.py and report.py (used in their _repr_html_ output) to the
canonical BRAND_COLORS via a top-level import, since _C was removed from
summary_plot. Color strings are unchanged (gray #8E8E93, dark #1C1C1E
both exist in BRAND_COLORS), so the rendered HTML is identical.
Refs #57

* ci: re-trigger checks for centralized style migration

* ci: re-trigger checks

* fix(report): repoint _C references introduced by main merge to BRAND_COLORS

Merging upstream/main (#115, Deployment Summary UX) reintroduced references
to summary_plot._C in report.py, which was removed in this branch's style
migration. Repoint them to the canonical BRAND_COLORS so the merged tree
type-checks. Color values unchanged.

Refs #57

---------

Co-authored-by: Shahid Ul Islam <65996596+Khanz9664@users.noreply.github.com>
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