Skip to content

feat(scorecard): return threshold config, threholdEvaluation per point - #4685

Open
djanickova wants to merge 3 commits into
redhat-developer:mainfrom
djanickova:timeseries-entity-thresholds
Open

feat(scorecard): return threshold config, threholdEvaluation per point#4685
djanickova wants to merge 3 commits into
redhat-developer:mainfrom
djanickova:timeseries-entity-thresholds

Conversation

@djanickova

@djanickova djanickova commented Sep 10, 2026

Copy link
Copy Markdown
Member

Hey, I just made a Pull Request!

Entity time-series API (GET /metrics/catalog/:kind/:namespace/:name/time-series) now returns entity-resolved thresholds and per-point thresholdEvaluation, so the frontend can render sparkline legends and chart colors without calling the snapshot metrics endpoint.

Current types:

export type MetricTimeSeriesResponse = {
  metricId: string;
  entityRef: string;
  points: MetricTimeSeriesPoint[];
  metadata: {
    title: string;
    description: string;
    type: MetricType;
    unit?: string;
    history?: boolean;
    defaultVisualization?: ScorecardVisualizationType;
    collectorIds?: string[];
  };
  thresholds: ThresholdConfig;           <-- new
};
export type MetricTimeSeriesPoint = {
  value: MetricValue | null;
  timestamp: string;
  error?: string;
  thresholdEvaluation?: string | null;           <-- new
};

How to test

Start Postgres locally and point app-config.local.yaml at it, e.g.:

backend:
  database:
    client: pg
    connection:
      host: 127.0.0.1
      port: 5432
      user: postgres
      password: postgres

From workspaces/scorecard:

yarn start

Sign in as Guest, copy a Bearer token from a successful localhost:7007 request, then:
export TOKEN=<token>

Default github.openPRs thresholds are:

success: <10
warning: 10-50
error: >50

thresholdEvaluation is computed at read time from each point’s value against those current rules — the DB status column is ignored for this field.

Seed data

docker exec -it backstage-psql psql -U postgres -d backstage_plugin_scorecard

DELETE FROM metric_values
WHERE metric_id = 'github.openPRs'
  AND catalog_entity_ref = 'component:default/all-scorecards'
  AND timestamp >= '2026-04-27'
  AND timestamp < '2026-05-02';

INSERT INTO metric_values
  (metric_id, catalog_entity_ref, value, timestamp, error_message, status, entity_kind, entity_owner, entity_namespace)
VALUES
  -- Apr 27: value 9 → read-time success (<10)
  ('github.openPRs', 'component:default/all-scorecards', '9',  '2026-04-27 20:00:00', NULL, 'success', 'Component', 'user:development/guest', 'default'),
  -- Apr 28: error-only → no thresholdEvaluation
  ('github.openPRs', 'component:default/all-scorecards', NULL, '2026-04-28 16:00:00', 'timeout', NULL, 'Component', 'user:development/guest', 'default'),
  -- Apr 29: value 25 → read-time warning (10-50); stale DB status must be ignored
  ('github.openPRs', 'component:default/all-scorecards', '25', '2026-04-29 12:00:00', NULL, 'success', 'Component', 'user:development/guest', 'default'),
  -- Apr 30: value 60 → read-time error (>50)
  ('github.openPRs', 'component:default/all-scorecards', '60', '2026-04-30 12:00:00', NULL, 'warning', 'Component', 'user:development/guest', 'default'),
  -- May 1: value 3, null status → still read-time success
  ('github.openPRs', 'component:default/all-scorecards', '3',  '2026-05-01 12:00:00', NULL, NULL, 'Component', 'user:development/guest', 'default');

Scenarios

  1. Happy path — thresholds + read-time thresholdEvaluation:
curl -s "http://localhost:7007/api/scorecard/metrics/catalog/component/default/all-scorecards/time-series?metricId=github.openPRs&from=2026-04-27T00:00:00.000Z&to=2026-04-30T23:59:59.999Z" \
  -H "Authorization: Bearer $TOKEN" | jq .

Expected:

Top-level thresholds.rules: success / warning / error (or app-config / entity overrides if set)
Points:
Apr 27: { "value": 9, "thresholdEvaluation": "success", ... }
Apr 28: { "value": null, "error": "timeout", ... } — no thresholdEvaluation
Apr 29: { "value": 25, "thresholdEvaluation": "warning", ... } (not "success" from DB)
Apr 30: { "value": 60, "thresholdEvaluation": "error", ... } (not "warning" from DB)

  1. Stale DB status ignored (Apr 29):
curl -s "http://localhost:7007/api/scorecard/metrics/catalog/component/default/all-scorecards/time-series?metricId=github.openPRs&from=2026-04-29T00:00:00.000Z&to=2026-04-29T23:59:59.999Z" \
  -H "Authorization: Bearer $TOKEN" | jq '.points'

Expected: value: 25, thresholdEvaluation: "warning" (DB status was success).

  1. Error-only day — thresholdEvaluation omitted:
curl -s "http://localhost:7007/api/scorecard/metrics/catalog/component/default/all-scorecards/time-series?metricId=github.openPRs&from=2026-04-28T00:00:00.000Z&to=2026-04-28T23:59:59.999Z" \
  -H "Authorization: Bearer $TOKEN" | jq .

Expected: one point with value: null, error: "timeout", no thresholdEvaluation. Response still has thresholds.

  1. Empty range — still returns thresholds:
curl -s "http://localhost:7007/api/scorecard/metrics/catalog/component/default/all-scorecards/time-series?metricId=github.openPRs&from=2025-01-01T00:00:00.000Z&to=2025-01-31T23:59:59.999Z" \
  -H "Authorization: Bearer $TOKEN" | jq .

Expected: "points": [], metadata present, thresholds present.

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

Signed-off-by: Diana Janickova <djanicko@redhat.com>
@rhdh-gh-app

rhdh-gh-app Bot commented Sep 10, 2026

Copy link
Copy Markdown

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-scorecard-backend workspaces/scorecard/plugins/scorecard-backend minor v4.2.0
@red-hat-developer-hub/backstage-plugin-scorecard-common workspaces/scorecard/plugins/scorecard-common minor v4.2.0

@rhdh-qodo-merge

Copy link
Copy Markdown

PR Summary by Qodo

Expose thresholds and evaluations in metric time series

✨ Enhancement 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Enriches entity time-series responses with resolved thresholds for client-side legends.
• Exposes stored threshold evaluations without requiring an additional snapshot request.
• Documents and tests errors, null statuses, and threshold-resolution fallback behavior.
Diagram

sequenceDiagram
  actor Client
  participant Router
  participant Service
  participant Catalog
  participant Store as Metric Store
  participant Resolver
  Client->>Router: GET time series
  Router->>Service: Request metric history
  Service->>Catalog: Load entity
  Catalog-->>Service: Catalog entity
  Service->>Store: Read daily points
  Store-->>Service: Values and statuses
  Service->>Resolver: Resolve thresholds
  alt Resolution succeeds
    Resolver-->>Service: Entity thresholds
  else Resolution fails
    Service->>Service: Use metric defaults
  end
  Service-->>Router: Enriched time series
  Router-->>Client: Points and thresholds
Loading
High-Level Assessment

The chosen approach is appropriate: returning stored pull-time evaluations preserves historical classification, while resolving thresholds once supplies the legend and color mapping in the same request. Re-evaluating historical points could change prior results when configuration changes, and retaining a separate snapshot request would add client complexity and network overhead.

Files changed (7) +142 / -12

Enhancement (2) +22 / -0
CatalogMetricService.tsEnrich time-series results with thresholds and evaluations +12/-0

Enrich time-series results with thresholds and evaluations

• Maps each successful database row's stored status to 'thresholdEvaluation' while leaving calculation-error points unchanged. Resolves entity-specific thresholds and falls back to metric defaults if resolution fails.

workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts

Metric.tsAdd thresholds to shared time-series types +10/-0

Add thresholds to shared time-series types

• Adds optional 'thresholdEvaluation' to metric points and required 'thresholds' to time-series responses. Documents null, absent, and entity-resolution semantics for API consumers.

workspaces/scorecard/plugins/scorecard-common/src/types/Metric.ts

Tests (2) +92 / -9
CatalogMetricService.test.tsTest threshold enrichment and fallback semantics +75/-7

Test threshold enrichment and fallback semantics

• Updates time-series expectations to include stored threshold evaluations and resolved configuration. Adds coverage for calculation errors, null statuses, resolver invocation, and fallback to metric defaults.

workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.test.ts

router.test.tsUpdate endpoint fixture for enriched time-series responses +17/-2

Update endpoint fixture for enriched time-series responses

• Extends the router's mocked time-series response with point evaluations and resolved threshold rules, validating the expanded endpoint contract.

workspaces/scorecard/plugins/scorecard-backend/src/service/router.test.ts

Documentation (1) +20 / -3
README.mdDocument threshold-aware time-series responses +20/-3

Document threshold-aware time-series responses

• Explains threshold resolution precedence and per-point evaluation behavior. Expands the response example with successful evaluations, an error point, and threshold rules.

workspaces/scorecard/plugins/scorecard-backend/README.md

Other (2) +8 / -0
breezy-numbers-hide.mdDeclare minor releases for the enriched time-series API +6/-0

Declare minor releases for the enriched time-series API

• Adds release notes and minor version bumps for the backend and common packages. Describes the new resolved thresholds and per-point evaluations.

workspaces/scorecard/.changeset/breezy-numbers-hide.md

report.api.mdPublish the expanded time-series API contract +2/-0

Publish the expanded time-series API contract

• Updates the generated public API report with optional point-level threshold evaluations and required response-level threshold configuration.

workspaces/scorecard/plugins/scorecard-common/report.api.md

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 12:11 PM UTC · Completed 12:31 PM UTC

Commit: 1cd8364 · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $6.67

@rhdh-qodo-merge

rhdh-qodo-merge Bot commented Sep 10, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Invalid overrides return wrong rules ✓ Resolved 🐞 Bug ≡ Correctness
Description
getEntityMetricTimeSeries catches every resolveEntityThresholds failure and assigns
metric.thresholds, bypassing both the entity override and any app-config thresholds held by
resolveMetricThresholds. When an entity has an invalid threshold annotation, the endpoint silently
returns provider defaults even though collection used the resolver and recorded an evaluation error,
so clients receive a definition that did not classify the point.
Code

workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts[R257-258]

+    } catch {
+      thresholds = metric.thresholds;
Relevance

●● Moderate

The fallback intentionally has test coverage, but invalid overrides returning provider defaults
conflicts with resolver semantics and stored errors.

PR-#4393

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The resolver applies app-config thresholds before entity annotations, while invalid annotation keys
or expressions throw during merging. Metric collection uses this same resolver and stores the
failure, but the newly added catch suppresses it and returns metric.thresholds; the existing
snapshot path instead exposes the resolution error.

workspaces/scorecard/plugins/scorecard-backend/src/threshold/ThresholdResolver.ts[40-52]
workspaces/scorecard/plugins/scorecard-backend/src/utils/mergeEntityAndMetricThresholds.ts[69-97]
workspaces/scorecard/plugins/scorecard-backend/src/scheduler/tasks/PullMetricsByProviderTask.ts[177-215]
workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts[137-153]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The time-series service suppresses entity threshold resolution errors and substitutes raw provider defaults, which can also discard valid app-config thresholds and misrepresent how stored points were evaluated.

## Fix Focus Areas
- workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts[251-259]
- workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.test.ts[678-691]

## Recommended Fix
Remove the provider-default fallback and preserve the threshold resolution failure, either by propagating it or by returning an explicit threshold error consistent with the snapshot endpoint. Update the fallback test to assert the selected error behavior rather than a successful default definition.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Historical points use the wrong legend ✓ Resolved 🐞 Bug ≡ Correctness
Description
thresholdEvaluation copies the status saved at collection time, while thresholds is freshly
resolved from current app config and entity annotations for every request. After threshold keys,
colors, or expressions change, old points retain evaluations against prior rules but are paired with
the new definition, including keys that may no longer exist for client color mapping.
Code

workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts[247]

+        thresholdEvaluation: row.status ?? null,
Relevance

●●● Strong

Feature contract requires evaluation keys to map to returned colors; mutable current thresholds can
invalidate historical statuses.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The scheduler resolves thresholds and stores their matching rule key during collection, whereas the
new endpoint reads that stored key and independently resolves the current entity configuration.
Threshold rules contain mutable keys, expressions, and colors, and the public contract says the
returned definition maps evaluation keys to colors, proving that configuration changes can break the
advertised relationship.

workspaces/scorecard/plugins/scorecard-backend/src/scheduler/tasks/PullMetricsByProviderTask.ts[177-203]
workspaces/scorecard/plugins/scorecard-backend/src/threshold/ThresholdResolver.ts[40-52]
workspaces/scorecard/plugins/scorecard-common/src/types/threshold.ts[21-43]
workspaces/scorecard/plugins/scorecard-common/src/types/Metric.ts[141-169]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Historical statuses were computed from the threshold configuration active during collection, but the response pairs them with one current threshold definition, so configuration changes make the two fields inconsistent.

## Fix Focus Areas
- workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts[236-274]
- workspaces/scorecard/plugins/scorecard-common/src/types/Metric.ts[141-169]

## Recommended Fix
Make the response use one coherent threshold version. Recompute each non-error point's evaluation from its stored value using the returned current thresholds, or persist and return the pull-time threshold definition or version for each point if historical evaluation semantics must be retained.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 11 rules
✅ Cross-repo context — repo relationships
  Explored: repo: redhat-developer/rhdh (sha: 065822e2)
Review mode: ⚖️ Balanced: This changes a public time-series API contract and threshold-resolution behavior across backend logic, routing, and shared types, creating meaningful compatibility and correctness risk but not enough independent logic for extended review.

Grey Divider

Tip of the day
💡 Did you know, you can turn these tips off under Display preferences

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@rhdh-qodo-merge rhdh-qodo-merge Bot added documentation Improvements or additions to documentation enhancement New feature or request Tests labels Sep 10, 2026
@rhdh-qodo-merge

Copy link
Copy Markdown

Important

The /generate_labels command by Qodo is sunsetting on the 1st of October 2026 and will no longer be available. We recommend switching to the latest Qodo review capabilities. Learn more

@codecov

codecov Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.33333% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.58%. Comparing base (485fadb) to head (b18c0dd).
⚠️ Report is 24 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4685   +/-   ##
=======================================
  Coverage   62.58%   62.58%           
=======================================
  Files        2634     2634           
  Lines      105187   105199   +12     
  Branches    29528    29525    -3     
=======================================
+ Hits        65833    65843   +10     
- Misses      37543    37545    +2     
  Partials     1811     1811           
Flag Coverage Δ *Carryforward flag
adoption-insights 84.77% <ø> (ø) Carriedforward from e8c7efa
ai-integrations 78.80% <ø> (ø) Carriedforward from e8c7efa
app-defaults 53.07% <ø> (ø) Carriedforward from e8c7efa
augment 46.67% <ø> (ø) Carriedforward from e8c7efa
boost 82.94% <ø> (ø) Carriedforward from e8c7efa
bulk-import 73.12% <ø> (ø) Carriedforward from e8c7efa
cost-management 13.35% <ø> (ø) Carriedforward from e8c7efa
dcm 73.47% <ø> (ø) Carriedforward from e8c7efa
e2e-adoption-insights 60.00% <ø> (ø) Carriedforward from e8c7efa
e2e-extensions 62.31% <ø> (ø) Carriedforward from e8c7efa
e2e-global-header 50.35% <ø> (ø) Carriedforward from e8c7efa
e2e-homepage 61.11% <ø> (ø) Carriedforward from e8c7efa
e2e-intelligent-assistant 46.74% <ø> (ø) Carriedforward from e8c7efa
e2e-orchestrator 49.52% <ø> (ø) Carriedforward from e8c7efa
e2e-orchestrator-plugin 49.51% <ø> (ø) Carriedforward from e8c7efa
e2e-quickstart 55.21% <ø> (ø) Carriedforward from e8c7efa
e2e-scorecard 50.16% <ø> (ø) Carriedforward from e8c7efa
e2e-theme 16.36% <ø> (ø) Carriedforward from e8c7efa
extensions 57.37% <ø> (ø) Carriedforward from e8c7efa
global-floating-action-button 71.18% <ø> (ø) Carriedforward from e8c7efa
global-header 68.09% <ø> (ø) Carriedforward from e8c7efa
homepage 48.39% <ø> (ø) Carriedforward from e8c7efa
install-dynamic-plugins 71.94% <ø> (ø) Carriedforward from e8c7efa
intelligent-assistant 76.51% <ø> (ø) Carriedforward from e8c7efa
konflux 91.98% <ø> (ø) Carriedforward from e8c7efa
lightspeed 69.02% <ø> (ø) Carriedforward from e8c7efa
mcp-integrations 84.46% <ø> (ø) Carriedforward from e8c7efa
orchestrator 71.13% <ø> (ø) Carriedforward from e8c7efa
quickstart 63.74% <ø> (ø) Carriedforward from e8c7efa
sandbox 79.56% <ø> (ø) Carriedforward from e8c7efa
scorecard 88.25% <83.33%> (-0.02%) ⬇️
theme 87.91% <ø> (ø) Carriedforward from e8c7efa
translations 5.12% <ø> (ø) Carriedforward from e8c7efa
x2a 77.18% <ø> (ø) Carriedforward from e8c7efa

*This pull request uses carry forward flags. Click here to find out more.


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 485fadb...b18c0dd. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 10, 2026

Copy link
Copy Markdown

Review — approve

Summary

This PR extends the entity time-series API (GET /metrics/catalog/:kind/:namespace/:name/time-series) to return entity-resolved thresholds and per-point thresholdEvaluation. The change enables the frontend to render sparkline legends and chart colors directly from the time-series response without a separate snapshot call.

Changes reviewed

File What changed
scorecard-common/.../Metric.ts Added thresholdEvaluation?: string | null to MetricTimeSeriesPoint and required thresholds: ThresholdConfig to MetricTimeSeriesResponse
scorecard-common/report.api.md API report updated to reflect the new fields
scorecard-backend/.../CatalogMetricService.ts Core logic: resolves entity thresholds (with fallback to metric-level), evaluates each non-error point at read time via ThresholdEvaluator, includes both in the response
scorecard-backend/.../CatalogMetricService.test.ts Updated existing tests to assert new fields; added tests for null DB status, entity-threshold resolution failure fallback
scorecard-backend/.../router.test.ts Updated mock response to include thresholdEvaluation and thresholds
scorecard-backend/README.md Documented the new fields, updated the JSON example response
.changeset/breezy-numbers-hide.md Minor bump for backend and common packages

Analysis

Correctness

  • Threshold resolution correctly follows the existing layered approach: entity annotation overrides → app-config → provider defaults. The try/catch fallback from resolveEntityThresholds to resolveMetricThresholds handles malformed annotations gracefully.
  • thresholdEvaluation is correctly omitted on calculation-error points (isMetricCalculationError returns early before the evaluation block) and always present on success points (either as a matched rule key or null).
  • The ?? null coercion from getFirstMatchingThreshold's string | undefined return to the type's string | null is correct.
  • Per-row evaluation errors are caught, logged as warnings, and default to null — the service never crashes on a bad threshold expression for a single row.
  • Threshold resolution is performed once per request (not per row), keeping the hot loop efficient.

Security

  • No new API endpoints, no authentication changes.
  • Threshold data is derived from trusted sources (provider config, app-config, entity annotations).
  • No user-controlled input reaches the threshold evaluation path unsafely.

API contract

  • MetricTimeSeriesResponse.thresholds is required (not optional), but since this is a server→client response type, this is purely additive for API consumers. The minor version bump is appropriate.
  • MetricTimeSeriesPoint.thresholdEvaluation is optional, preserving backward compatibility for existing consumers.

Test coverage

  • Updated all existing time-series tests to include the new fields in assertions.
  • New test: DB status is null but read-time evaluation still produces a result — verifies the stale-status-ignored design.
  • New test: resolveEntityThresholds throws → falls back to resolveMetricThresholds — verifies the defensive catch block.
  • Existing ThresholdEvaluator.test.ts provides comprehensive coverage of the evaluation engine itself.

Documentation

  • README updated with a clear explanation of the new behavior and an updated JSON example.
  • JSDoc added for both new type fields with precise descriptions of semantics (when present, when absent, when null).

Style & conventions

  • Follows the existing patterns in CatalogMetricService (compare the threshold resolution in getLatestEntityMetrics).
  • ThresholdEvaluator instantiation as a class property is consistent with the service's stateless-dependency style.

Verdict

Clean, well-scoped feature addition with good test coverage and documentation. The implementation correctly follows the existing threshold resolution patterns already established in getLatestEntityMetrics. No blocking findings.

Previous run

Review

Findings

Medium

  • [error-handling-gap] workspaces/scorecard/plugins/scorecard-backend/src/service/CatalogMetricService.ts:253 — When resolveEntityThresholds throws (e.g., due to a malformed entity threshold annotation), the catch block falls back to metric.thresholds (raw provider defaults), skipping any admin-configured app-config threshold overrides. resolveMetricThresholds(metric) returns app-config-resolved thresholds via a simple Map lookup that cannot throw — a more accurate fallback. Additionally, the bare catch block silently swallows the error without logging, inconsistent with the existing error-handling patterns in the same class: getLatestEntityMetrics captures errors via stringifyError, and getEntityMetricDetails logs via this.logger.error.
    Remediation: Change fallback from metric.thresholds to this.thresholdResolver.resolveMetricThresholds(metric), capture the error variable, and add this.logger.warn(...).

  • [backward-compatibility] workspaces/scorecard/plugins/scorecard-common/src/types/Metric.ts:165 — Adding a required field thresholds: ThresholdConfig to the public exported type MetricTimeSeriesResponse is a breaking change for TypeScript consumers that construct objects of this type (e.g., test mocks). The PR's own router.test.ts demonstrates this: the existing mock literal had to be updated. The changeset marks scorecard-common as minor, but under strict semver adding a required property to a public type is a major change. Practical breakage is limited since this is a server-produced response shape.
    Remediation: Either make the field optional (thresholds?: ThresholdConfig) or upgrade the changeset bump to major for scorecard-common.

Low

  • [title-typo] PR title contains a typo: "threholdEvaluation" should be "thresholdEvaluation" (missing 's').

  • [naming-convention] workspaces/scorecard/plugins/scorecard-common/src/types/Metric.ts:143 — The new field thresholdEvaluation introduces a third name for the same domain concept. The existing codebase uses evaluation in ThresholdResult and status in EntityMetricDetail/DbMetricValue. The current name is arguably more self-documenting in the flat time-series point context, but worth noting for API consistency.

  • [api-shape-consistency] workspaces/scorecard/plugins/scorecard-common/src/types/Metric.ts:167thresholds is required on MetricTimeSeriesResponse but ThresholdConfig | undefined on MetricResult.result.thresholdResult.definition. This follows from the different error-handling strategies of the two endpoints (time-series always falls back; snapshot reports the error), so it is by design rather than accidental.


Labels: PR enriches scorecard time-series API with threshold data; enhancement label fits the feature addition.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added the requires-manual-review Review requires human judgment label Sep 10, 2026
Signed-off-by: Diana Janickova <djanicko@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 10, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 2:19 PM UTC · Ended 2:27 PM UTC

Commit: e8c7efa · View workflow run →

Signed-off-by: Diana Janickova <djanicko@redhat.com>
@sonarqubecloud

Copy link
Copy Markdown

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 10, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 2:28 PM UTC · Completed 2:35 PM UTC

Commit: b18c0dd · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Cost: $1.12

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed requires-manual-review Review requires human judgment labels Sep 10, 2026

let thresholds: ThresholdConfig;
try {
thresholds = this.thresholdResolver.resolveEntityThresholds(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't know if we want to silently switch what thresholds are used if there is error with them?
For snapshot, frontend shows there was error with evaluating entity thresholds because thresholds are malformed.

let thresholdEvaluation: string | null = null;
if (row.value !== null) {
try {
thresholdEvaluation =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we need to also let frontend know there were evaluation problems.

We will need to fix error handling in backend for next release I think.
Right now everywhere we use:
error?: string
We might deprecate it and use something like:
errors?: [{code: string, message: string}]

This way with codes, frontend can also do translation and it is secure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

(Almost everywhere, aggregated time-series returns: errors?: [{message: string, count: num}]) so we can follow this pattern here as well, without count, so errors?: [{message: string}])

@Eswaraiahsapram Eswaraiahsapram left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @djanickova , tested the changes on top of UI branch. Looks good to me. 🎉

/lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request lgtm ready-for-merge All reviewers approved — ready to merge Tests workspace/scorecard

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants