Repository navigation
chore: remove health score v1 fields and routes - #2375
gaspergrom wants to merge 15 commits into
Conversation
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
…N-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
There was a problem hiding this comment.
🔵 Needs a closer look
It removes externally consumed contracts while consumer sign-off remains pending, and the OpenAPI 3.1 null schema needs correction.
1 open finding
What changed in this PR
Removes legacy Health Score v1 API surfaces while retaining v2 scoring and benchmark functionality.
Changes:
- Removes v1 fields, route, query flag, calculations, and unused Tinybird calls.
- Preserves OSS Index tuple compatibility across upstream schema changes.
- Adds focused endpoint, benchmark, and tuple-mapping tests.
| File | Description |
|---|---|
api/src/lib/collections.ts |
Updates collection mapping comment. |
frontend/docs/openapi.json |
Removes v1 fields and documents nullable v2 score. |
frontend/server/api/project/[slug]/insights.get.ts |
Filters legacy fields and maps v2 score. |
frontend/server/api/project/[slug]/insights.get.test.ts |
Tests v2 and null score responses. |
frontend/server/api/project/[slug]/overview/health-score-overview.get.ts |
Removes the legacy route. |
frontend/server/api/project/index.ts |
Removes health-score enrichment flag. |
frontend/server/helpers/health-score.helpers.ts |
Retains only benchmark signals and response keys. |
frontend/server/helpers/health-score.helpers.test.ts |
Tests benchmark pipes and schema. |
frontend/server/api/ossindex/categories.ts |
Maps tuple fields relative to the tail. |
frontend/server/api/ossindex/collections.ts |
Supports both upstream tuple layouts. |
frontend/server/api/ossindex/groups.ts |
Preserves group tuple mapping. |
frontend/server/api/ossindex/ossindex.test.ts |
Tests both tuple layouts. |
frontend/types/overview/responses.types.ts |
Removes v1 health-score types. |
frontend/types/project.ts |
Removes legacy insight fields. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| "type": "number", | ||
| "nullable": true, |
…scores IN-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
dd4a4d0 to
973b6fe
Compare
| return { | ||
| ...project, | ||
| // External callers read healthScore, so it carries the raw v2 score. | ||
| healthScore: project.healthScoreV2, |
…s once IN-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
973b6fe to
d347c1e
Compare
…N-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
…-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
…ject list IN-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
… IN-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
d347c1e to
1f8e782
Compare
| return { | ||
| ...project, | ||
| // External callers read healthScore, so it carries the raw v2 score. | ||
| healthScore: project.healthScoreV2, |
| let projects = res.data.map((p: ProjectTinybird) => ({ | ||
| const projects = res.data.map((p: ProjectTinybird) => ({ | ||
| ...p, | ||
| healthScore: p.healthScoreV2 ?? null, |
…1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
| popularityHealthScore: number; | ||
| developmentHealthScore: number; | ||
| securityHealthScore: number; | ||
| healthScoreV2: number | null; |
… routes IN-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
…s IN-1222 Signed-off-by: Gašper Grom <gasper.grom@gmail.com>
There was a problem hiding this comment.
🟡 Changes recommended
Collection behavior contradicts the documented interim contract, response schemas remain inaccurate, and required consumer sign-off is pending.
7 open findings
Filter removes v1 sub-scores before documented #4922 transition · New Filter removes v1 sub-scores before documented #4922 transition · New Restore healthScore alias in ProjectInsights pagination response Add healthScore to the ProjectList item type Add healthScore to the Project response type Unexpectedly switches project API endpoint from v1 to v2 Use type arrays for nullability in OpenAPI 3.1
🧠 Review effort: Balanced
| ...Object.fromEntries( | ||
| Object.entries(item).filter(([key]) => !legacyScoreFields.includes(key)), | ||
| ), |
| ...Object.fromEntries( | ||
| Object.entries(project).filter(([key]) => !legacyScoreFields.includes(key)), | ||
| ), |
|
Closing for now: org-dashboard still reads the v1 health score ( |

Do not merge until Joana Maia confirms consumer sign-off (LFX One, Org Lens, OD, Self Serve, CNCF) and a deprecation date.
Summary
healthScore=trueflag on/api/project, and thehealth-score-overviewroute. Dead v1 types go with them.GET /api/project/{slug}/insightsdropscontributorHealthScore,popularityHealthScore,developmentHealthScoreandsecurityHealthScore.healthScorealready carries the v2 value in raw points. This PR documents it that way: out of 100 with all three categories, out of 60, 65 or 75 when one category is missing, and null for unscored or archived projects. CNCF needs notice before this merges.GET /api/project/{slug},GET /api/project(the list),GET /api/collection/{slug}/projectsandGET /api/collection/{slug}/project-reposreturnhealthScoreas each row's rawhealthScoreV2, or null, the same mapping as the insights route. The field survives the v1 column removal in crowd.dev PR 3 (#4922). On the list and both collection routes,sort=healthScore,healthScore_descandhealthScore_ascsort by raw v2. The Open Source Index sorts byhealthScoreV2Normalizedand does not change.GET /api/project/{slug}/overview/health-score-overview. Its Tinybird pipe served about 3,500 external requests in the last 30 days.GET /api/project/{slug}/overview/health-scorereturns only the 11 benchmark keys. It stops calling two signal pipes that no benchmark uses:health_score_securityandhealth_score_contributions_outside_work_hours. The Contribution Time Distribution widget reads a different pipe and is unaffected.healthScorevalue or a v1 sub-score, whether or not crowd.dev PR 3 (#4922) has deployed. Widget benchmark callouts stay.legacyScoreFieldsinhealth-score.helpers.ts).Contract change and sign-off gate
Joana's sign-off has to cover each of these.
linuxfoundation/org-dashboard). OD callsGET /api/project?healthScore=truein batches of 50 slugs (51 calls in 7 days) and reads the v1 breakdown that flag adds. This PR removes the flag, and OD's Key Projects page goes empty. Because list rows now carryhealthScore= raw v2, which is null for about 812 unscored projects, OD's unguarded unpacking ofproject.healthScorethrows on any batch that contains an unscored project. OD's project detail header also readshealthScorefromGET /api/project/{slug}and grades it on v1 bands (80/60/40/20); it now gets raw v2 points, so a partial project (max 60, 65 or 75) can never reach Excellent and unscored projects lose the badge. OD must migrate both the list and the detail reads before this merges, as an explicit sign-off item.healthScorefromGET /api/project/{slug}. After this PR it gets raw v2 points, and AAIF's v1 bands (80/60/40) no longer fit. Notify AAIF.GET /api/project,GET /api/collection/{slug}/projectsandGET /api/collection/{slug}/project-repos, each row'shealthScorechanges from the v1 score to raw v2 points, null when unscored (k8s goes from 86 to 71; about a third of repo rows have no v2 score). On all three routes,sort=healthScore, with or without_asc/_desc, orders by raw v2. The collection routes also stop returning the four v1 sub-scores. OD reads list rows, and AAIF's v1 bands misread raw v2 here as on/{slug}, so both notices must cover these routes too./overview/health-score-overview(829 calls in 7 days). That route returns 404 after this PR.Interim state (until the Tinybird removal)
GET /api/project,GET /api/project/{slug},GET /api/project/{slug}/insightsand the two collection routes return the raw v2 score underhealthScore. Tinybird keeps selecting the v1 columns until crowd.dev PR 3 deploys; the insights route and the collection routes drop the four v1 sub-scores before responding, so no response carries a v1 value in the meantime.Changes
api/src/lib/collections.tsfrontend/docs/openapi.jsonrequiredand properties; describeshealthScoreas nullable raw v2 points (max 100, or 60/65/75 with a missing category)frontend/server/api/project/[slug]/insights.get.tslegacyScoreFields;healthScorestays the v2 valuefrontend/server/api/project/[slug]/insights.get.test.tsfrontend/server/api/project/[slug]/overview/health-score-overview.get.tsfrontend/server/api/project/[slug]/index.tshealthScoreas the row's rawhealthScoreV2frontend/server/api/project/[slug]/index.test.tsfrontend/server/api/project/index.tshealthScore=trueflag and the enrichment branch that called the removed pipe; returns each row'shealthScoreas the rawhealthScoreV2or null; mapssort=healthScoreandhealthScore_*tohealthScoreV2frontend/server/api/project/index.test.tshealthScore, thehealthScoreandhealthScore_*sort mapping, and unchangedhealthScoreV2Normalizedsortsfrontend/server/api/collection/[slug]/projects.tshealthScoreas the rawhealthScoreV2or null; drops the four v1 sub-scores; mapssort=healthScoreandhealthScore_*tohealthScoreV2frontend/server/api/collection/[slug]/project-repos.tshealthScoreas the rawhealthScoreV2or null; drops the four v1 sub-scores; mapssort=healthScoreandhealthScore_*tohealthScoreV2frontend/server/api/collection/[slug]/project-routes.test.tshealthScoresort mapping with other sorts passing throughfrontend/server/helpers/health-score.helpers.tslegacyScoreFields, the four v1 sub-score names the routes dropfrontend/server/helpers/health-score.helpers.test.tsfrontend/server/api/ossindex/categories.tsfrontend/server/api/ossindex/collections.tsfrontend/server/api/ossindex/groups.tsfrontend/server/api/ossindex/ossindex.test.tsfrontend/types/overview/responses.types.tsHealthScoreBasetoHealthScoreTinybird; removes v1 fields andSecurityScore; trimsHealthScoreResultsto the 11 benchmark keysfrontend/types/project.tshealthScorefromProjectInsightsTinybirdandProjectInsights; addshealthScoreV2toProjectTinybirdJIRA
IN-1222: Deprecate v1 health score sinks and tables
Related PRs
Deploy order
mainonce that PR merges./overview/health-score-overviewand/api/project?healthScore=truereturn 500, and every project page loses its benchmark callouts through/overview/health-score.health_score_securitynorhealth_score_contributions_outside_work_hourshas served a request since this PR deployed.DB migrations
No DB migrations.
Test plan
Checked on the QA build of this branch (round 1, then round 2 after the partial-marker commit, both PASS):
GET /api/project/k8s/insightshas none of the four sub-scores.healthScoreequalshealthScoreV2, andhealthLabelis present. An unknown slug returns 404.GET /api/project/k8s/overview/health-scorereturns 11 keys, and the benchmark values equal production.GET /api/project/k8s/overview/health-score-overviewreturns 404.GET /api/project?healthScore=truereturns a plain list with the same rows as without the flag.GET /api/project/{slug}returnshealthScoreequal to the rawhealthScoreV2(52 for a 52/65 partial) and null for an unscored project.GET /api/projectreturns each row'shealthScoreas the rawhealthScoreV2or null, sendssort=healthScore,healthScore_descandhealthScore_ascashealthScoreV2, and leaveshealthScoreV2Normalizedsorts as they are.sort=healthScore,healthScore_descandhealthScore_ascorder by raw v2, every row'shealthScoreequalshealthScoreV2, andhealthScoreV2Normalized_descstill puts the 65/65 partials first.healthScoreequal to the rawhealthScoreV2(71 for k8s) and null for a repo row without a v2 score. They sendsort=healthScore,healthScore_descandhealthScore_ascashealthScoreV2and leavehealthScoreV2Normalized_descandcontributorCount_ascas they are./api/collection/cncf/projectsand/project-repos, k8s returnshealthScore71, equal tohealthScoreV2(it was the v1 86), with no mismatches across 100 rows.sort=healthScore_descon both routes returns the same order ashealthScoreV2_desc(88, 87, 87, 87, 86). No row on either route carries a v1 sub-score (0 of 100). The in-app callers of/project-reposread only identity and dependency fields, and nothing in the app calls/projects.frontend/serverroute andapi/handler for v1 health fields (the v1healthScorevalue, the four sub-scores,overallScore, health*Percentagefields). Only the two collection routes passed any through, and this PR drops them there. The public API (api/) builds its responses field by field and returns v2 only.healthScoreon list endpoints) no longer applies: the list now returns raw v2.To check after deploy and before the Tinybird removal:
/docsrenders the updated OpenAPI file. (The local/docsreturned 502, so this needs a deployed check.)health_score_securityorhealth_score_contributions_outside_work_hourssince this PR deployed.GET /api/project?healthScore=true.healthScoreonGET /api/project/{slug},GET /api/projectand the collection routes is raw v2 points.Pre-existing and not changed here: the OpenAPI document lists
type,repoUrlandmaturityfor the insights response, which the live response omits.Checklist
git commit --signoff -Son every commitmain