fix: address the Copilot review of the Ace editor

- `isProgressToken` used `Number.isInteger`, but zod 4's `.int()` rejects
  anything past `MAX_SAFE_INTEGER` — verified against the pinned zod — so an
  unsafe integer passed the guard and was left for the server to reject. Now
  `isSafeInteger`, with the boundary covered in both directions.

- `echoed` held only what this component last emitted, so it went stale the
  moment an external value was applied: A → B → A stranded the editor on B,
  because the second A matched the entry left from before B arrived and was
  dismissed as our own echo. It now advances to whatever is on screen.

- `Input.Wrapper` associates a *Mantine* input through context, and Ace is not
  one — it renders its own DOM. The wrapper's label and error node therefore
  pointed at nothing: the editor was never marked `aria-invalid`, never
  described by the error text, and its visible label did not focus it. Wired
  explicitly through the wrapper's id in an effect.

- Removed two leftover `[dbg]` logs an earlier regex cleanup missed.

- Documented the editor integration and the shared `cssVariablesResolver` in
  the web README, per the rule about new dependencies and patterns. Both
  footguns are recorded: the `?url` worker import, and the gutter override
  keying off Ace's cssClass rather than the theme module name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0177mPHAdECD18nLLCTwR5rh
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-08-23 17:36:43 -04:00
commit 7f10fa971c

View file

@ -387,11 +387,17 @@ function describeJsonType(value: unknown): string {
* a string or an **integer** — a float is as invalid as an object. Everything
* else in `_meta` may be any JSON (#1910), which is exactly why this one key
* needs its own check.
*
* `isSafeInteger`, not `isInteger`: zod 4's `.int()` rejects anything past
* `Number.MAX_SAFE_INTEGER`, where the float64 representation is no longer the
* integer it was written as. `Number.isInteger(2 ** 53)` is `true`, so the
* looser check would pass a token the server then rejects — verified against
* the pinned zod.
*/
function isProgressToken(value: unknown): value is ProgressToken {
return (
typeof value === "string" ||
(typeof value === "number" && Number.isInteger(value))
(typeof value === "number" && Number.isSafeInteger(value))
);
}