chatContextWindow (#189) is the first numeric provider field routed
through WorkspaceRepo.updateAiProviderSettings, whose patch builder cast
every value as `${v}::text`. The DTO validates it as @IsInt(), so a JS
number 200000 was stored as the JSON STRING "200000". The client guards
require `typeof === "number"` (ai-chat-window.tsx, context-badge.tsx),
so the `/ max` badge denominator never rendered and the whole feature
silently no-opped.
Branch the jsonb_build_object value cast by JS runtime type: numbers ->
::numeric (real JSON number), booleans -> ::boolean, everything else ->
::text (unchanged for the existing string fields). This is the root fix
(store as a real number) rather than coercing on read, so every reader
sees the correct type.
Add a DB round-trip int-spec asserting
jsonb_typeof(settings->'ai'->'provider'->'chatContextWindow') = 'number'
and that the value re-reads as the number 200000, including the
partial-merge path. CHANGELOG: Added entry for the chatContextWindow
setting and a Changed entry for the badge's new "used / max" meaning.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>