Skip to content

feat: expose health score v2 sub-signal detail via new pipe chain (CM-IN-1212) - #4448

Open
gaspergrom wants to merge 1 commit into
mainfrom
feat/CM-IN-1212-healthscore-v2-thresholds
Open

feat: expose health score v2 sub-signal detail via new pipe chain (CM-IN-1212)#4448
gaspergrom wants to merge 1 commit into
mainfrom
feat/CM-IN-1212-healthscore-v2-thresholds

Conversation

@gaspergrom

Copy link
Copy Markdown
Contributor

Summary

Part of IN-1212 (Health Score v2 content spec implementation) — the crowd.dev/Tinybird half.

  • Promotes previously-computed-but-discarded sub-signal columns (per-signal scores, *Available coverage flags, raw counts) in the 3 category pipes (health_score_v2_maintainer, health_score_v2_security, health_score_v2_development) — no scoring/business logic changed, only column exposure.
  • Adds a new pipe chain rolling repo-level signal detail up to project level for the insights frontend's health-breakdown UI, mirroring the existing project_insights_impact_breakdown pattern:
    • health_score_v2_signal_detail (COPY) — LEFT JOINs the 3 widened category _ds tables on repoUrl
    • project_insights_health_breakdown_copy (COPY) — rolls repo-level rows up to project level
    • project_insights_health_breakdown (endpoint) — slug-filtered public endpoint, consumed by the insights server route

Deploy status

Already deployed to production — validated end-to-end via crowd-tinybird-manager (all 6 files pushed, all 5 copy backfill jobs confirmed done, project_insights_health_breakdown confirmed queryable by slug with real data + correct NULL-degradation behavior). Two real issues were found and fixed during the production push (not glossed over):

  • UInt8/UInt16 schema type mismatches on 5 expressions across the category pipes required explicit toUInt8(...) casts.
  • health_score_v2_maintainer_ds was missing a coveredWeight column the pipe needed.
  • The insights-app-token also needed a PIPES:READ grant added on the new endpoint pipe (a recurring gap worth flagging: tb push doesn't grant the consuming app token automatically).

Staging could not be meaningfully exercised (workspace was at datasource/copy-pipe quota caps, unrelated to this change) — production deploy and validation are solid regardless.

Consumer

linuxfoundation/insights PR (IN-1212) reads this endpoint via a new server/api/project/[slug]/overview/health-score-breakdown.get.ts route — that PR depends on this one already being deployed, which it is.

Test plan

  • tb check clean on all 11 touched files
  • All 5 copy backfill jobs confirmed done
  • project_insights_health_breakdown confirmed queryable by slug with real data in production
  • No scoring/business logic touched — verified via direct SQL read of the 3 category pipes' existing signal_coverage degradation logic (Layer 1 redistribution, Layer 2 category-drop) — already implemented, this PR only exposes it

…-IN-1212)

Promotes previously computed-but-discarded sub-signal scores and
availability flags in the 3 category pipes (health_score_v2_maintainer,
health_score_v2_security, health_score_v2_development), and adds a new
pipe chain (health_score_v2_signal_detail -> project_insights_health_breakdown_copy
-> project_insights_health_breakdown) rolling repo-level signal detail up
to project level for the insights frontend's health-breakdown UI.

No scoring/business logic changed, only column exposure and rollup.

Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Copilot AI balanced review requested due to automatic review settings August 6, 2026 12:41
@cursor

cursor Bot commented Aug 6, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Large schema and nightly COPY schedule changes affect insights health data surfaces; scoring math is mostly unchanged but widened category materializations must stay in sync with downstream joins.

Overview
IN-1212 extends Tinybird so the insights health-breakdown UI can show per-signal scores, coverage (*Available), and underlying metrics—not only category totals.

The three category copy pipes (health_score_v2_maintainer, _security, _development) and their _ds tables now persist sub-signal outputs that were already computed in SQL (plus explicit toUInt8 casts and maintainer coveredWeight). Scoring and rescaling logic are unchanged.

A new scheduled chain mirrors project_insights_impact_breakdown: health_score_v2_signal_detail joins the widened category tables per repo; project_insights_health_breakdown_copy rolls enabled, non-excluded repos up to project level (avg/max/min rules per column type); project_insights_health_breakdown is a cheap slug-filtered read of the materialized project_insights_health_breakdown_ds.

Reviewed by Cursor Bugbot for commit 82c1e49. Bugbot is set up for automated code reviews on this repo. Configure here.

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ 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 82c1e49. Configure here.

max(sd.opened12m) AS opened12m,
avg(sd.medianCloseS) AS medianCloseS,
avg(sd.prMergeScore) AS prMergeScore,
max(sd.prMergeAvailable) AS prMergeAvailable,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Blocked scores dilute project averages

High Severity

Project-level score columns use plain avg() over every repo row, while *Available uses max(). Blocked signals still carry placeholder scores (0, or 5 for dependencyHealthScore when the repo has no packages), so those placeholders are folded into the mean whenever any sibling repo is available. Raw nullable columns already skip gaps correctly via avg/max on NULLs; the UInt8 scores do not, so the breakdown UI can show Available while the averaged score is wrong.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 82c1e49. Configure here.

TYPE COPY
TARGET_DATASOURCE health_score_v2_signal_detail_ds
COPY_MODE replace
COPY_SCHEDULE 25 2 * * *

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

COPY schedules hit busy 2 AM window

Medium Severity

The new COPY pipes are scheduled at 25 2 and 35 2, inside the already dense 1–3 AM UTC window (leaderboards, health-score v2 chain, agentic/ai trackers, ossPackages_enriched, impact breakdown). That violates the Tinybird concurrent-copy quota rule: the account caps at 12 concurrent copy jobs, and overflow leaves pipes permanently queued, which can empty downstream data.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by learned rule: Tinybird COPY pipe schedules must not collide — account concurrent quota is 12

Reviewed by Cursor Bugbot for commit 82c1e49. Configure here.

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 a Tinybird pipeline exposing Health Score v2 sub-signal details for the Insights health-breakdown UI.

Changes:

  • Exposes existing category scores, availability flags, and raw metrics.
  • Materializes repository-level details and project-level rollups.
  • Adds a slug-filtered endpoint for Insights.

Reviewed changes

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

Show a summary per file
File Description
pipes/project_insights_health_breakdown.pipe Adds the public breakdown endpoint.
pipes/project_insights_health_breakdown_copy.pipe Aggregates repository signals by project.
pipes/health_score_v2_signal_detail.pipe Joins category details by repository.
pipes/health_score_v2_security.pipe Exposes security sub-signals.
pipes/health_score_v2_maintainer.pipe Exposes maintainer sub-signals.
pipes/health_score_v2_development.pipe Exposes development sub-signals.
datasources/project_insights_health_breakdown_ds.datasource Defines project-level breakdown storage.
datasources/health_score_v2_signal_detail_ds.datasource Defines repository-level detail storage.
datasources/health_score_v2_security_ds.datasource Extends the security schema.
datasources/health_score_v2_maintainer_ds.datasource Extends the maintainer schema.
datasources/health_score_v2_development_ds.datasource Extends the development schema.
Suppressed comments (8)

services/libs/tinybird/pipes/project_insights_health_breakdown_copy.pipe:58

  • orgDiversityScore is 0 for blocked repos, so averaging every row dilutes available scores with missing data while orgDiversityAvailable still becomes true. Average only rows whose availability flag is set.
        avg(sd.orgDiversityScore) AS orgDiversityScore,

services/libs/tinybird/pipes/project_insights_health_breakdown_copy.pipe:61

  • For unavailable Gerrit responsiveness data, the source emits score 0 with responsivenessAvailable = false. Including that row in avg converts a blocked signal into a penalty for mixed-coverage projects; filter the average by availability.
        avg(sd.responsivenessScore) AS responsivenessScore,

services/libs/tinybird/pipes/project_insights_health_breakdown_copy.pipe:71

  • The source emits scorecardScorePts = 0 when Scorecard data is unavailable. Averaging those blocked rows lowers projects that have valid Scorecard data on only some repos; gate the average with scorecardAvailable.
        avg(sd.scorecardScorePts) AS scorecardScorePts,

services/libs/tinybird/pipes/project_insights_health_breakdown_copy.pipe:74

  • Missing repo-details data produces a zero security-practices score with securityPracticesAvailable = false. This average therefore treats blocked repos as failures; exclude unavailable rows so the project score matches the exposed coverage state.
        avg(sd.securityPracticesScore) AS securityPracticesScore,

services/libs/tinybird/pipes/project_insights_health_breakdown_copy.pipe:81

  • When dependency data is unavailable, the source still computes a non-null fallback score while setting dependencyHealthAvailable = false. Averaging that value makes blocked repos affect the project score; only average available rows.
        avg(sd.dependencyHealthScore) AS dependencyHealthScore,

services/libs/tinybird/pipes/project_insights_health_breakdown_copy.pipe:84

  • Unavailable release data yields score 0, so this average penalizes projects for blocked repos even though releaseCadenceAvailable reports the signal as available when any repo has data. Gate the average on the availability flag.
        avg(sd.releaseCadenceScore) AS releaseCadenceScore,

services/libs/tinybird/pipes/project_insights_health_breakdown_copy.pipe:91

  • The source score is zero when issue-resolution data is blocked, so averaging all repos turns unavailable data into a negative score while issueResolutionAvailable may still be true. Average only available rows.
        avg(sd.issueResolutionScore) AS issueResolutionScore,

services/libs/tinybird/pipes/project_insights_health_breakdown_copy.pipe:96

  • The source score is zero when PR-merge data is blocked. Including those rows in the average penalizes mixed-coverage projects despite the availability flag; exclude unavailable rows from this aggregate.
        avg(sd.prMergeScore) AS prMergeScore,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

SELECT
ip.id AS projectId,
ip.slug AS slug,
avg(sd.busFactorScore) AS busFactorScore,
Comment on lines +86 to +87
max(sd.daysSinceLatest) AS daysSinceLatest,
max(sd.daysBetweenRecent) AS daysBetweenRecent,
d.merged12m AS merged12m,
d.closedUnmerged12m AS closedUnmerged12m,
d.medianMergeS AS medianMergeS
FROM (SELECT DISTINCT url AS repoUrl FROM repositories WHERE deletedAt IS NULL) AS base
`project_insights_impact_breakdown_ds`.
- Parameters: `slug` (single project).

TAGS "Insights, Widget", "Project", "Health"
@gaspergrom
gaspergrom requested a review from epipav August 6, 2026 15:17
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