Skip to content

fix(frontend/settings): keep a stored default_coverage of 0 on load - #510

Merged
cristim merged 1 commit into
mainfrom
fix/settings-default-coverage-zero
Oct 5, 2026
Merged

cristim merged 1 commit into
mainfrom
fix/settings-default-coverage-zero

Conversation

@cristim

@cristim cristim commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

What

loadGlobalSettings read the global target coverage with ||:

coverageInput.value = String(data.global.default_coverage || 80);
...
coverage: data.global.default_coverage || 80,   // cachedGlobalDefaults

A stored default_coverage of 0 therefore rendered as 80 in the Target coverage input and in the cache behind the account-override modal's "Inherit (currently: X%)" placeholder. Both sites now use ?? 80, so only an absent (undefined/null) value falls back to 80. This matches the per-service coverage inputs in the same function (svc?.coverage ?? data.global?.default_coverage ?? 80).

Why

An operator with global coverage 0 who opened Settings to change something else (e.g. the notification email) and clicked Save silently PUT default_coverage: 80. Since #500 a changed global default is also copied to the service_configs.coverage rows in the same transaction. The Settings page then PUTs each service again with its own stored value, so services that already had a stored row end up with their stored coverage; the services affected were the ones without a stored row, such as the RI cards (no per-card coverage input), which sent coverage: 80 because their save path falls back to settings.default_coverage. Review also found that the Settings Save never propagates a changed global coverage to services that have a stored row; that is tracked separately.

0 is a valid value end to end: the save path accepts 0-100 (settings.ts validation), config.validateCoverage uses MinCoverage = 0, the openapi schema documents 0-100, and updateConfig json-unmarshals the body over the stored row, so a sent 0 is stored as 0.

How verified

New tests in frontend/src/__tests__/settings.test.ts (issue #135 block) drive loadGlobalSettings then an unedited saveGlobalSettings:

  • stored 0: input shows 0, SP coverage input shows 0, updateConfig gets default_coverage: 0, the compute SP and EC2 RI service saves get coverage: 0
  • absent default_coverage: input shows 80 and Save sends 80 (existing default kept)
  • per-service coverage 0 under global 50: card shows 0, saves 0; sibling card inherits 50
  • override modal placeholder reads Inherit (currently: 0%)

Before the fix (origin/main source, new tests):

    Expected: "0"
    Received: "80"
    Expected: "Inherit (currently: 0%)"
    Received: "Inherit (currently: 80%)"
Tests:       2 failed, 77 skipped, 2 passed, 81 total

After: Tests: 77 skipped, 4 passed, 81 total. Mutation: reverting only the cache line to || fails the override-label test (Received: "Inherit (currently: 80%)").

Full frontend: npm run typecheck clean; npx jest --watchman=false 92 suites, 3040 passed, 1 skipped; npx eslint on both touched files clean; npm run build compiles (only the existing entrypoint-size warning). These are jsdom/mocked-API tests, not a run against the real stack.

Left alone (zero-vs-absent sites seen, out of scope; #151 tracks the sweep)

  • settings.ts same block: default_term || 3, default_payment || 'all-upfront' (load and cache), notification_days_before || 3. 0 is not a valid term or notify-days value, so these are harmless today.
  • internal/api/handler_dashboard.go resolveTargetCoverage: DefaultCoverage > 0 else 80.0, so the dashboard shows an 80% target when the configured global is 0. Backend half of the same field; left for an owner call on whether the dashboard should show 0%.
  • settings.ts save path: per-card coverage keeps the base value when the input is empty (rawCov !== ''), which is presence-based and fine.

Closes #135

loadGlobalSettings read default_coverage with `|| 80`, so a stored 0
rendered as 80 in the Target coverage input and in the cached global
default behind the override modal's "Inherit (currently: X%)" label.
An unedited Save then PUT default_coverage 80, and since #500 the
changed global also propagates 80 to every service config's coverage.

Use `?? 80` at both sites so only an absent value falls back to 80,
matching the per-service coverage inputs. The backend accepts 0-100.

Closes #135
@cristim cristim added priority/p2 Backlog-worthy urgency/this-sprint Within the current sprint triaged Item has been triaged severity/high Significant harm impact/few Limited audience effort/xs Trivial / one-liner type/bug Defect labels Oct 5, 2026
@coderabbitai

coderabbitai Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 2 billable files and costs up to $0.50.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 14 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available. Your 51 included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 622dfef1-e486-4c35-9555-0217b8f7a285
📥 Commits

Reviewing files that changed from the base of the PR and between e65a8a3 and 31bc66a.

📒 Files selected for processing (2)
  • frontend/src/__tests__/settings.test.ts
  • frontend/src/settings.ts
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

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

Labels

effort/xs Trivial / one-liner impact/few Limited audience priority/p2 Backlog-worthy severity/high Significant harm triaged Item has been triaged type/bug Defect urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(frontend/settings): stop rewriting a configured default_coverage of 0 to 80 on Save

1 participant