unbridled-41 opened a new pull request, #5071:
URL: https://github.com/apache/rocketmq-dashboard/pull/5071
## Problem
A native ratio alert rule that has no stored `thresholdUnit` shows a
nonsense threshold in the console, and the edit form writes that nonsense back
into the rule.
`formatThresholdCondition` converts the stored ratio to a percentage with a
raw multiply (`web/src/pages/ops/alerts.tsx:133`):
```ts
if (nativeRatioMetrics.has(rule.metric) && !rule.thresholdUnit) {
return `${rule.operator} ${rule.threshold * 100}%`;
}
```
In binary floating point `0.55 * 100` is `55.00000000000001` and `0.29 *
100` is `28.999999999999996`, so the 阈值 column of `/ops/alerts` renders `>
55.00000000000001%` for a rule whose threshold is 0.55. The same multiply is
used to seed the edit form (`:485`), so opening the rule and saving it stores
`55.00000000000001` with `thresholdUnit: '%'` — a value nobody typed, in the
field the evaluator compares against.
The existing test for this branch (AlertsPage.test.tsx:272-281) uses 0.85,
the one value in the fixture set where `0.85 * 100` happens to land on exactly
85, so the defect is invisible in the suite.
Which rules are in that state:
- the legacy ratio representation the branch exists for (the conversion is
also applied when the edit form loads such a rule, `:485`);
- a rule created through the API without `thresholdUnit` — nothing couples
the metric to a unit: `AlertRuleRequestDTO.java:38` has no constraint on it and
`NativeAlertMetricCatalogService.validate` (`:70-85`) only checks that the
metric is supported by the instance;
- a rule imported through the YAML transfer, which copies the source rule's
`thresholdUnit` verbatim (`AlertRuleTransferService.java:71`).
Rules created from the console form are not affected: `handleSubmit` always
forces `thresholdUnit: '%'` for a ratio metric.
## Evidence
Pre-fix, on base `a562601d`, with the three new tests in place and only
`alerts.tsx` at its base revision:
```
$ cd web && npx vitest run src/pages/ops/__tests__/AlertsPage.test.tsx
× renders a legacy native ratio threshold without the binary-float tail
× shows a unitless ratio rule threshold as a round percentage in the table
× saves a legacy ratio rule with the rounded percent the form showed
Test Files 1 failed (1)
Tests 3 failed | 28 passed (31)
AssertionError: expected '> 55.00000000000001%' to be '> 55%'
TestingLibraryElementError: Unable to find an element with the text: > 55%.
AssertionError: expected { id: 99, …(18) } to match object { threshold: 55,
thresholdUnit: '%' }
```
The three failures are the three faces of the defect: the formatter, the
rendered table cell, and the payload the edit form saves. The third is what
makes this more than a display bug — the rounded number never reaches the
database today.
## Root cause
`rule.threshold * 100` (display, `:133`) and
`Number(form.getFieldValue('threshold')) * 100` (edit prefill, `:485`) convert
a ratio to a percent without rounding, so the binary representation error of
the multiply is rendered and persisted.
## Fix
One module-level helper, used by both sites:
```ts
const ratioToPercent = (ratio: number): number => Number((ratio *
100).toFixed(6));
```
Six decimals is three orders of magnitude below where a double's noise
starts (the tail appears at the 16th significant digit), so every threshold an
operator can type survives the conversion exactly while the tail disappears.
The display, the form seed and the saved value now agree.
## Score
`PRIORITY = 60` (impact 18: the alerting console prints and then stores a
threshold that is not the one the operator set, on a value the evaluator
compares against; scope 10: the three native ratio metrics, and only rules
without a stored unit; reproducibility 20: three deterministic assertions, one
of them on the saved payload; maintenance value 12: the branch is documented as
supported, and this is the number the feature is about).
`FIX_CONFIDENCE = 88`.
## Tests
```
$ cd web && npx vitest run src/pages/ops/__tests__/AlertsPage.test.tsx #
post-fix
Test Files 1 passed (1)
Tests 31 passed (31)
$ cd web && npx tsc --noEmit -p tsconfig.json #
exit 0
$ cd web && npx eslint src/pages/ops/alerts.tsx \
src/pages/ops/__tests__/AlertsPage.test.tsx # 0
errors (5 pre-existing warnings)
```
The pre-fix run of the same file (only `alerts.tsx` reverted to `a562601d`,
tests kept) is the failure quoted under Evidence. Both conversion sites are
asserted, not one representative: the table cell (page render) and the save
payload (edit → OK), plus a direct unit assertion on both a downward (`0.29`)
and an upward (`0.55`) rounding case.
## Risk
Very low. The change only affects rules whose stored `thresholdUnit` is
empty — a console-created rule always carries `'%'` and never reaches either
conversion. For those rules the displayed and saved percent changes from the
float tail to the round number, which is the intent of the conversion. No API
shape, no rounding of user-entered values (`precision={2}` on the input is
unchanged), and no evaluation semantics change: the stored threshold for a
percent rule is the percent, and the server divides by 100 for ratio metrics
with a `%` unit (`AlertRuleSemanticFingerprint.normalizedThreshold`), which is
unaffected by the low-order bits.
## Dedup
- `gh search prs/issues --repo apache/rocketmq-dashboard "ratio threshold
percent"`, `"threshold"`, `"thresholdUnit"` → no PR or issue about the
conversion (the hits are the `nativeRatioMetrics` unit work and rule-asset
transfer).
- `/tmp/open_pr_files.txt` lists `web/src/pages/ops/alerts.tsx` for PRs
#4832/#4826/#4641/#5067 (counts, UTC stat, leftovers, other surfaces) — none
touches `formatThresholdCondition` or the edit prefill.
- `git log --oneline a562601d -- web/src/pages/ops/alerts.tsx` → the recent
commits are localization and test-result fixes; the multiply is unchanged since
the native-alerting feature.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]