feat: add covered-category-count and capped max-score fields for partial health scores (IN-1262) - #4548
Conversation
…ial health scores (IN-1262) Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
…262) Mirrors the existing healthScoreV2/healthLabel korg override (IN-1244) so a project with no displayable overall score never gets a populated partial-score denominator either. Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
…N-1262) Sum of three IS NOT NULL boolean checks infers as Nullable(UInt32) in ClickHouse, which Tinybird rejects against the Nullable(UInt8) schema column. Already validated and live in production; committing the fix to keep the branch in sync with the deployed pipe. Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
…endpoint (IN-1262) Insights frontend reads project detail data through this pipe, not project_insights_copy_ds directly, so the two new partial-health-score columns need to be forwarded here before the frontend can consume them. Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
PR SummaryMedium Risk Overview
The fields flow through Reviewed by Cursor Bugbot for commit e7c2e7c. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Pull request overview
Adds project-level Health Score v2 coverage counts and capped maximum scores for downstream consumers.
Changes:
- Computes and stores category coverage and maximum score.
- Exposes fields through project insights and Kafka sink output.
- Documents the scheduled Health Score v2 export.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
project_insights.pipe |
Exposes the new fields. |
project_insights_copy.pipe |
Computes project values and nulls unsupported records. |
health_score_v2_sink.pipe |
Updates export schedule documentation. |
health_score_sink.pipe |
Adds fields to Kafka output. |
project_insights_copy_ds.datasource |
Adds nullable storage columns. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7140994. Configure here.
project_repo_insights.pipe (serving the Collections page) was missing the two fields project_insights.pipe already exposes for the partial Health Score v2 treatment, so Collections never received the data needed to render the capped denominator or partial label suffix. Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Suppressed comments (1)
services/libs/tinybird/pipes/health_score_v2_sink.pipe:3
- The 00:35 export runs before both inputs it publishes:
project_insights_impact_breakdown_copy.piperefreshes at 02:40 andproject_insights_copy.piperefreshes at 03:00. This can emit the previous day's health and impact snapshot; the existing dependency documentation explicitly identifies 03:30 as the intended sink time. Please schedule this after 03:00 (for example,EXPORT_SCHEDULE 35 3 * * *). Also, because the cron directive itself is unchanged in this diff, this edit only updates the comment rather than activating the export as the PR description claims.
-- Live and scheduled: EXPORT_SCHEDULE below runs this daily at 00:35 UTC.
… (IN-1262) healthLabel now buckets healthScoreV2 * 100.0 / healthMaxScore against the 85/70/50/30 thresholds instead of the raw capped score, so partial scores benchmark on the same scale as full ones. Also reschedules the Kafka sink export to 03:35 UTC so it runs after project_insights_copy_ds's refresh and picks up the corrected labels. Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
… avgHealthScore (IN-1262) avgHealthScore now averages each project's healthScoreV2 * 100.0 / healthMaxScore instead of the raw capped score, so a partial score contributes its full-scale equivalent to the collection average rather than a disadvantaged raw value. Confirmed with product (Joana Maia) that partial scores should be treated as if they weren't partial. Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
services/libs/tinybird/pipes/health_score_v2_sink.pipe:42
- The diff reschedules an already-active export from 00:35 to 03:35; it does not activate an inert
@on-demandsink as the PR description states, and the test plan still expects 00:35. Align the documented rollout/test expectation with the intended cron before merge.
EXPORT_SCHEDULE 35 3 * * *
services/libs/tinybird/pipes/project_repo_insights.pipe:16
- This combined endpoint also returns repository records, but both new fields are hardcoded to
NULLfor repositories. State that these semantics apply only to project records so API consumers do not expect repository coverage values.
- `coveredCategoryCount` (0-3) and `healthMaxScore` (60/65/75/100, IN-1262) describe a partial Health Score v2: `healthMaxScore` is the capped denominator when exactly one category is missing (2 of 3 covered), 100 when all 3 are covered, and null when fewer than 2 are covered (same guard as `healthScoreV2`).
services/libs/tinybird/pipes/project_insights_copy.pipe:245
- This changes project
healthLabelsemantics for every two-category project (for example, 45/60 moves fromfairtohealthy), but the PR description says consumer behavior is unchanged and neither lists nor tests this relabeling. Please either remove this scope or document and validate the behavior before merge.
(hv2.healthScoreV2 * 100.0 / hv2.healthMaxScore) >= 85,
Adds coveredCategoryCount and healthMaxScore to health_score_v2_sink.pipe's SELECT, matching health_score_sink.pipe and the PR description. Fixes the healthMaxScore doc comment's denominator wording on project_insights_copy_ds and scopes the coveredCategoryCount/healthMaxScore doc on project_repo_insights.pipe to project records only. Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Suppressed comments (1)
services/libs/tinybird/pipes/health_score_v2_sink.pipe:26
EXPORT_FORMAT csvemits headerless positional rows, so inserting these fields here immediately shifts every existing impact/date column for the current Kafka consumer. This conflicts with the documented producer-first rollout: append the new fields after the existingdatecolumn (and coordinate the rollout if the consumer rejects extra fields) so existing positions retain their meaning.
p.coveredCategoryCount AS coveredCategoryCount,
p.healthMaxScore AS healthMaxScore,
| p.healthScoreV2 as overall_score_v2, | ||
| p.coveredCategoryCount as covered_category_count_v2, | ||
| p.healthMaxScore as health_max_score_v2, | ||
| toStartOfDay(now()) as date |
| -- Live and scheduled: EXPORT_SCHEDULE below runs this daily at 03:35 UTC, | ||
| -- after project_insights_copy_ds's 03:00 refresh and the impact breakdown's | ||
| -- 02:40 refresh (see project_insights_impact_breakdown_copy.pipe). |
| -- healthLabel buckets the score NORMALIZED to /100 (healthScoreV2 * 100 / healthMaxScore), | ||
| -- not the raw capped healthScoreV2 - so a partial score like 45/60 benchmarks as its | ||
| -- full-scale equivalent 75/100 ('healthy'), not the raw 45 ('fair') (IN-1262, per product | ||
| -- decision - see collection_insights_aggregate_projects_copy_pipe.pipe for the same rule | ||
| -- applied to the Collections average). healthMaxScore is 100 when all 3 categories are | ||
| -- covered, so this is a no-op for non-partial scores. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Suppressed comments (2)
services/libs/tinybird/pipes/project_insights_copy.pipe:239
- This six-line block narrates the expression immediately below it. Repository guidance prohibits comments that merely explain what code does and limits allowed comments to two lines; the
healthMaxScorename and pipeDESCRIPTIONalready capture this behavior, so remove this block.
-- healthLabel buckets the score NORMALIZED to /100 (healthScoreV2 * 100 / healthMaxScore),
-- not the raw capped healthScoreV2 - so a partial score like 45/60 benchmarks as its
-- full-scale equivalent 75/100 ('healthy'), not the raw 45 ('fair') (IN-1262, per product
-- decision - see collection_insights_aggregate_projects_copy_pipe.pipe for the same rule
-- applied to the Collections average). healthMaxScore is 100 when all 3 categories are
-- covered, so this is a no-op for non-partial scores.
services/libs/tinybird/pipes/health_score_v2_sink.pipe:5
- The scheduling-order invariant is a valid comment, but repository guidance limits allowed comments to two lines. Condense this three-line note while retaining the reason for the ordering.
-- Live and scheduled: EXPORT_SCHEDULE below runs this daily at 03:35 UTC,
-- after project_insights_copy_ds's 03:00 refresh and the impact breakdown's
-- 02:40 refresh (see project_insights_impact_breakdown_copy.pipe).
| - `coveredCategoryCount` column (0-3) is the count of the three health-v2 categories (maintainer, security, development) with a non-null score. Project records only; null for repo records. | ||
| - `healthMaxScore` column is the capped denominator for a partial `healthScoreV2` (e.g. 65, not 100, when Security & Supply Chain is the one missing category — `healthScoreV2` is then out of 65). Null when `coveredCategoryCount` < 2, 100 when all 3 categories are covered. Project records only; null for repo records. |
| EXPORT_SERVICE kafka | ||
| EXPORT_CONNECTION_NAME lfx-oracle-kafka-streaming | ||
| EXPORT_SCHEDULE 35 0 * * * | ||
| EXPORT_SCHEDULE 35 3 * * * |

Summary
coveredCategoryCount(0-3) andhealthMaxScore(60/65/75/100) to the Tinybird pipe chain —project_insights_copy_ds.datasource→project_insights_copy.pipe→project_insights.pipe, plus the two sink pipes — so a project missing exactly one Health Score v2 category (Maintainer 40 / Security & Supply Chain 35 / Development Activity 25) carries a single source-of-truth capped denominator and coverage count, instead of Insights, LFX One, and the Health Score Badge each recomputing the "- Partial" logic independently.healthMaxScoreis null when fewer than 2 categories are covered (mirrors the existinghealthScoreV2null guard), 100 when all 3 are covered, otherwise 100 minus the weight of the one missing category.korgproject override inproject_insights_copy.pipeexplicitly nulls both new fields, matching how it already nulls other v2 fields for that slug.project_insights_copy.pipeget both fields hardcoded toNULL— coverage/partial scoring is a project-level concept only.EXPORT_SCHEDULEcron onhealth_score_v2_sink.pipe(was@on-demand-only pending stakeholder sign-off, now runs daily at 03:35 UTC — afterproject_insights_copy_ds's 03:00 refresh — and threads the two new fields through bothhealth_score_sink.pipeandhealth_score_v2_sink.pipe.healthLabelinproject_insights_copy.pipeandavgHealthScoreincollection_insights_aggregate_projects_copy_pipe.pipeboth bucket/average the score normalized tohealthScoreV2 * 100.0 / healthMaxScorerather than the raw capped score, so a partial score (e.g. 45/60) benchmarks consistently as its full-scale equivalent (75/100) at both the project and collection level.healthScoreV2itself is computed, and does not touch the Insights/LFX One/Health Score Badge consumers — those are separate companion PRs.Changes
services/libs/tinybird/datasources/project_insights_copy_ds.datasourcecoveredCategoryCountandhealthMaxScoreNullable(UInt8) columns + doc commentsservices/libs/tinybird/pipes/project_insights_copy.pipehealthScoreV2guard uses; nulls them forkorgand for repo recordsservices/libs/tinybird/pipes/project_insights.pipeservices/libs/tinybird/pipes/health_score_sink.pipecovered_category_count_v2/health_max_score_v2to the sink outputservices/libs/tinybird/pipes/health_score_v2_sink.pipeEXPORT_SCHEDULEat 03:35 UTC (was on-demand only) and addscoveredCategoryCount/healthMaxScoreto the sink outputservices/libs/tinybird/pipes/collection_insights_aggregate_projects_copy_pipe.pipeavgHealthScoretohealthScoreV2 * 100.0 / healthMaxScorebefore averaging, to stay consistent with the project-levelhealthLabelnormalizationJIRA
IN-1262 — Implement Partial Health Score labels and capped totals for projects with 1 missing category
This is crowd.dev's slice of a cross-repo ticket. Companion PRs exist in insights, lfx-self-serve, and lf-dbt to consume these fields for the "- Partial" label and capped total display.
Deploy order
coveredCategoryCount/healthMaxScorefrom these pipes and are not testable end-to-end until this is live.Test plan
korgproject still returnsnullfor both new fields after deployproject_insights_copy.pipereturnnullfor both fieldshealth_score_v2_sink.pipedaily export runs at 03:35 UTC without error on its first scheduled fireChecklist
git commit --signoff -Son every commit