Skip to content

feat: show partial Health Score label and capped total IN-1262 - #2145

Open
gaspergrom wants to merge 3 commits into
mainfrom
feat/IN-1262-partial-health-score
Open

feat: show partial Health Score label and capped total IN-1262#2145
gaspergrom wants to merge 3 commits into
mainfrom
feat/IN-1262-partial-health-score

Conversation

@gaspergrom

Copy link
Copy Markdown
Collaborator

Summary

  • Consumes the two new project_insights fields (coveredCategoryCount, healthMaxScore) added in crowd.dev#4548 to show a "- Partial" suffix on the Health Score label and cap the displayed total at the reduced max (e.g. "45 out of 65" instead of "out of 100") when exactly one of the three v2 categories is missing data.
  • isPartialHealthScore() treats any healthMaxScore other than null or 100 as partial, so the UI never recomputes category coverage itself — Tinybird is the single source of truth for whether a score is partial and what its denominator is.
  • Adds a tooltip explaining the partial score and updates the public health-score docs to describe the new labeling behavior.
  • Does not touch repo_health_score_v2_breakdown (repo-scoped queries): that pipe has no coveredCategoryCount/healthMaxScore fields, so a repo-filtered selection always renders as non-partial (healthMaxScore: null) by design — this PR does not add partial support at the repo level.
  • Cross-repo: this PR only reads the two new fields; it ships no schema or pipe changes of its own. Companion PRs exist for lfx-self-serve and lf-dbt (not yet opened).

Changes

File What changed
frontend/config/trust-score.ts getHealthScoreV2Config() takes an isPartial flag and appends "- Partial" to the label; adds isPartialHealthScore(healthMaxScore)
frontend/config/trust-score.test.ts Tests for the new partial-label and partial-detection logic
frontend/server/api/badge/health-score.ts Badge endpoint reads healthMaxScore and passes it through isPartialHealthScore() to getHealthScoreV2Config()
frontend/server/api/project/[slug]/overview/health-score-v2.get.ts Passes coveredCategoryCount/healthMaxScore through from project_insights; hardcodes both to null on the repo-filtered branch, which reads from repo_health_score_v2_breakdown
frontend/types/project.ts Adds coveredCategoryCount, healthMaxScore to ProjectInsightsTinybird and ProjectInsights
frontend/types/overview/responses.types.ts Adds the same two fields to HealthScoreV2Results
frontend/app/components/modules/project/components/details/collection-health-score-pill.vue Renders the partial label suffix on the collection pill
frontend/app/components/modules/project/components/details/collection-project-item.vue Passes partial state through to the pill
frontend/app/components/modules/project/components/overview/health-breakdown-section.vue Displays the capped total instead of a fixed "out of 100"
frontend/app/components/modules/project/components/overview/trust-score-v2.vue Wires coveredCategoryCount/healthMaxScore into the score display and adds the partial tooltip
frontend/app/components/modules/project/components/overview/trust-score/health-score-ring.vue Uses the capped max as the ring's denominator
frontend/app/components/modules/project/views/overview.vue Passes the two new fields down from the overview query result
frontend/app/components/uikit/chart/configs/gauge.chart.ts Gauge chart config accepts a configurable max instead of assuming 100
frontend/docs/metrics/health-score/index.md Documents the partial-score label and capped-total behavior for public readers

JIRA

IN-1262 — Implement Partial Health Score labels and capped totals for projects with 1 missing category

Deploy order

  1. crowd.dev PR #4548: deploy first — already merged to prod, adds coveredCategoryCount/healthMaxScore to the project_insights Tinybird pipe that this PR reads.
  2. This PR: safe to deploy independently of step 1's timing — if it lands first, healthMaxScore is absent/undefined from the pipe response, isPartialHealthScore() treats that as non-partial, and the UI falls back to the legacy "out of 100" display with no suffix. Once step 1 is live, real partial data renders without a further insights deploy.
  3. lfx-self-serve and lf-dbt companion PRs: not yet opened; no ordering dependency on this PR.

DB migrations

No DB migrations.

Test plan

  • pnpm test --run in frontend/: 249/249 tests passed across 42/42 files. The process itself exits non-zero only from a pre-existing Cannot find dependency 'vitest-environment-nuxt' warning in the local dev environment, confirmed via git-stash isolation to predate this branch.
  • pnpm run tsc-check passes clean.
  • Manually verify a project with exactly one missing v2 category shows "- Partial" on both the overview trust score and the collection pill, with the ring/breakdown denominator capped (60/65/75, matching which category is missing).
  • Manually verify a project with all three categories covered still shows the plain label and "out of 100" — no regression to the non-partial path.
  • Manually verify a repo-filtered health score view (not project-level) never shows "- Partial", since repo_health_score_v2_breakdown doesn't carry the two new fields.
  • Verify the GitHub badge endpoint (/api/badge/health-score) reflects "- Partial" in its label text for a partial project.

Known issue (not fixed in this PR)

QA surfaced a pre-existing bug in frontend/server/api/badge/health-score.ts while exercising this feature's badge code path: the handler never validates that the project query param is present before calling fetchFromTinybird({ slug: project }). An omitted project param currently falls through to a 302 redirect built from fallback/undefined-slug data instead of a 404 or 400. This predates and is unrelated to this ticket's changes — reporting it here, not fixing it under IN-1262.

Checklist

  • git commit --signoff -S on every commit — single commit 1bb517ddf, signed off.
  • MIT license header on every new source file — no new files in this diff; all touched files already carry the header.
  • PR diff < 1000 lines — 140 insertions / 23 deletions across 14 files.
  • No unrelated changes bundled.
  • Cross-repo impact documented above (deploy order, companion PRs).

Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Copilot AI balanced review requested due to automatic review settings September 1, 2026 16:11

Copilot AI 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.

Pull request overview

Adds project-level partial Health Score labels and capped denominators using Tinybird-provided metadata.

Changes:

  • Propagates partial-score fields through API responses and components.
  • Updates gauges, pills, breakdowns, badges, tests, and documentation.
  • Leaves repository-filtered scores non-partial by design.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
frontend/types/project.ts Adds partial-score fields.
frontend/types/overview/responses.types.ts Extends overview response types.
frontend/server/api/project/[slug]/overview/health-score-v2.get.ts Returns partial-score metadata.
frontend/server/api/badge/health-score.ts Adds partial badge labels.
frontend/config/trust-score.ts Adds partial detection and labeling.
frontend/config/trust-score.test.ts Tests partial-score helpers.
frontend/app/components/uikit/chart/configs/gauge.chart.ts Supports configurable gauge maxima.
frontend/app/components/modules/project/views/overview.vue Passes capped maximum downstream.
frontend/app/components/modules/project/components/overview/trust-score/health-score-ring.vue Displays capped ring totals.
frontend/app/components/modules/project/components/overview/trust-score-v2.vue Adds partial labels and tooltip.
frontend/app/components/modules/project/components/overview/health-breakdown-section.vue Shows capped breakdown totals.
frontend/app/components/modules/collection/components/details/collection-project-item.vue Passes maximum to the desktop pill.
frontend/app/components/modules/collection/components/details/collection-health-score-pill.vue Scales capped totals and progress.
frontend/docs/metrics/health-score/index.md Documents partial scores.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

maintainerHealthScoreV2?: number | null;
securitySupplyChainScoreV2?: number | null;
developmentActivityScoreV2?: number | null;
healthMaxScore?: number | null;
:maintainer-health-score-v2="project.maintainerHealthScoreV2"
:security-supply-chain-score-v2="project.securitySupplyChainScoreV2"
:development-activity-score-v2="project.developmentActivityScoreV2"
:health-max-score="project.healthMaxScore"
Comment thread frontend/config/trust-score.ts Outdated
- If **all 3 categories** are available, the Health Score is computed normally.
- If **exactly 1 category** is unavailable, the score is computed from the 2 available categories and shown with a **partial** indicator to signal that not all signals were observed.
- If **all 3 categories** are available, the Health Score is computed normally, out of a maximum of 100.
- If **exactly 1 category** is unavailable, the score is computed from the 2 available categories and shown out of a reduced maximum: 60 if Maintainer Health (40 pts) is missing, 65 if Security and Supply Chain (35 pts) is missing, or 75 if Development Activity (25 pts) is missing. The rating label carries a **" - Partial"** suffix (for example, "Healthy - Partial") to signal that not all categories were observed, and a tooltip next to the score explains which category is missing.
Collections page pill sourced only healthMaxScore for progress-bar
rescaling but rendered the bare band label, unlike the Health
Breakdown section already patched for IN-1262. Reuse
getHealthScoreV2Config/isPartialHealthScore, and pass healthMaxScore
through the mobile card view that was missing it.

Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Copilot AI review requested due to automatic review settings September 1, 2026 18:15

Copilot AI 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.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

frontend/config/trust-score.ts:51

  • undefined is treated as partial because it differs from both null and 100. The badge caller passes the Tinybird field directly, so when the upstream response omits this newly added field—as the documented independent deploy path allows—the badge incorrectly renders "... - Partial". Treat a missing value the same as null and add an undefined regression case.
export const isPartialHealthScore = (healthMaxScore: number | null): boolean =>
  healthMaxScore !== null && healthMaxScore !== 100;

frontend/docs/metrics/health-score/index.md:228

  • The documentation says the tooltip identifies which category is missing, but the implemented tooltip only lists all three possibilities and never identifies one. Update this claim to match the UI (or derive the missing category from healthMaxScore).
- If **exactly 1 category** is unavailable, the score is computed from the 2 available categories and shown out of a reduced maximum: 60 if Maintainer Health (40 pts) is missing, 65 if Security and Supply Chain (35 pts) is missing, or 75 if Development Activity (25 pts) is missing. The rating label carries a **" - Partial"** suffix (for example, "Healthy - Partial") to signal that not all categories were observed, and a tooltip next to the score explains which category is missing.

Comment on lines +44 to +48
<lfx-tooltip
v-if="isPartial"
placement="top"
>
<lfx-icon
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Copilot AI review requested due to automatic review settings September 2, 2026 09:28

Copilot AI 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.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (2)

frontend/app/components/modules/collection/components/details/collection-health-score-pill.vue:130

  • This component has an existing regression suite in frontend/test/collection-detail-components.test.ts, but the new partial path is not covered. Please add a case with a capped healthMaxScore that asserts the - Partial label, reduced denominator, and rescaled progress value, plus the null/100 fallback, so these coupled display calculations cannot regress independently.
const progressBarValue = computed(() => (props.score / (props.healthMaxScore ?? 100)) * 100);

frontend/app/components/modules/project/components/overview/trust-score-v2.vue:48

  • The new explanation is only reachable through LfxTooltip, which hardcodes a hover trigger, and its slotted LfxIcon renders a non-focusable <i>. Keyboard and touch users therefore cannot discover which category is missing. Please expose this text through a focus/click-capable, labelled control (or render it inline) so the partial-score explanation is available without hover.
                    <lfx-tooltip
                      v-if="isPartial"
                      placement="top"
                    >
                      <lfx-icon

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