### Description
Scene formulas — the "Computed" value of **Set a variable**, **…Control a device**, **Wait** and **Condition on variables** — run on a deliberately restricted `mathjs` instance. Until now that namespace only contained the four arithmetic operators, `%`, `^`, the comparison operators and `round()` / `random()`, so a formula like `sqrt(400)` or `min(15, x)` aborted the scene with "value is not a number".
This PR extends the namespace with the functions asked for in the forum topic, and makes the whole supported surface discoverable directly in the scene editor.
**Functions added**
| Group | Functions |
|---|---|
| Rounding & sign | `abs`, `ceil`, `floor`, `fix`, `sign` |
| Powers & roots | `pow`, `sqrt`, `cbrt`, `square`, `cube`, `nthRoot`, `hypot` |
| Exponential & logarithm | `exp`, `log` (with optional base), `log2`, `log10` |
| Statistics | `min`, `max`, `mean`, `median`, `sum`, `prod` |
| Integer arithmetic | `gcd`, `lcm` |
| Random | `randomInt` |
| Trigonometry | `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2` |
| Constants | `pi`, `e`, `tau` |
`abs`, `ceil` and `floor` happened to work already because `mathjs` pulled them in transitively through `round`; they are now pinned explicitly like the rest, so a `mathjs` upgrade cannot silently remove them.
The use case from the forum topic now works as a single formula, no HTTP request needed:
```
round(min(15, exp({{tankLevel}} / 25)) * 60)
```
### Technical changes
- **`server/lib/scene/scene.formula.js`** (new): the restricted formula engine moves out of `scene.actions.js` into its own module, so the supported surface lives in one documented place. Every operator, function and constant is passed explicitly to `create()` — `mathjs` only guarantees the "math" namespace for what it is given, so anything only reachable transitively could disappear on an upgrade.
- **`server/lib/scene/scene.actions.js`**: imports the shared `evaluate`. The **Control a device** action now wraps the evaluation in a `try/catch` and aborts the scene with `ACTION_VALUE_NOT_A_NUMBER` when the formula cannot be evaluated — the three other formula actions already did this, and this action was the only one that let a `mathjs` parse error escape. A wider function surface means more ways to write an invalid call (`gcd(4)`, a typo'd name), so it now fails closed too.
- **Front**: new `FormulaFunctionsHelp` component rendered under every formula input (Set a variable, Control a device, Wait, Condition on variables). It lists the available operators, functions and constants, plus a short syntax reminder. Function names are not translatable, so they live in the component and mirror the server module; only the three labels and the example sentence go through i18n (`en`, `fr`, `de`).
- **Tests**: `scene.action.formula.test.js` grows one case per operator, function and constant (54 tests), so a `mathjs` upgrade that drops one fails CI instead of failing silently in production. Plus a fail-closed test for the new `try/catch`.
### Not included
`and` / `or` / `not` / `xor` / `equal` / `unequal` and `compareText` were mentioned in the forum thread but are left out on purpose:
- The formula string is whitespace-stripped before evaluation, so the operator form (`1 and 0` → `1and0`) cannot parse, and string arguments would be mangled.
- They return booleans rather than numbers, which does not fit a pipeline whose four call sites all expect a number — and Gladys already has dedicated "Condition on variables" boxes with AND / OR semantics for that job.
Every function added here returns a number, so it behaves identically in all four formula actions.
## Forum
Forum: https://community.gladysassistant.com/t/scenes-supporter-quelques-fonctions-supplementaires-de-math-js/9509
### Checklist
- [x] Tests pass: `cd server && npm run coverage` (Codecov requires 100% coverage on changed lines) and Cypress (`npm run cypress:run`) if the UI changed
- [x] Linter and prettier pass on both front and server (`npm run eslint`, `npm run prettier`)
- [x] No undocumented breaking change
Notes on the checklist: the full server suite passes locally and coverage on the two changed server files is 100% for `scene.formula.js` and leaves no new uncovered line in `scene.actions.js`. `front` passes `prettier-check`, `eslint`, `compare-translations` and `npm run build`. Cypress was not run locally (its binary is unavailable in this environment) — the change only adds a static help block under existing inputs and touches no route or form control.
---
_Generated by [Claude Code](https://claude.ai/code/session_01Twh2gVvdbLtoLLQRukvNvh)_
## Summary by CodeRabbit
* **New Features**
* Added formula assistance to scene action editors, documenting supported operators, functions, constants, syntax, and examples.
* Added English, French, and German translations for formula help.
* Expanded formula support for calculations, comparisons, rounding, powers, statistics, trigonometry, and constants.
* **Bug Fixes**
* Invalid or non-finite formulas now safely stop scenes without changing affected device values or causing execution to hang.
* Restricted unsupported formula operations to improve safety and reliability.