fix(uxcat): bias descriptions, modal scrolling, Apple Calendar .ics, pill offset - #165
Conversation
uxCoreData was hardcoded to null in the UX Core context value, so every consumer of the shared bias list saw an empty array. On the ongoing test the bias name comes from the test API and rendered fine, but the description came from context and sat on a skeleton forever. Reported as a geo/VPN issue; it affected everyone. Populate it client-side from a slim Strapi query gated to /uxcat routes. The full bias payload is ~1.4 MB and those screens only read number, title, description, slug and mentionedQuestionsIds, so select just those and cache per module. mentionedQuestionsIds is required: test-result JSON.parses it to pick recommended reading and would throw on null. Also fixes QuestionAnalyse, which built its list in an effect with an empty dependency array and so never saw the data arrive. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The wrapper had no height ceiling, so on short viewports it grew past the screen and the centred overlay clipped it at both ends — the header and the footer buttons were unreachable. Reported against the "Our projects" modal on /ru, but it is the shared UX Core modal, so every consumer had it. Cap the wrapper, stop the header shrinking, and give the body min-height:0 — without that the flex child cannot shrink below its content height and overflow:auto never engages. The mobile fullHeightMobile override still wins by source order. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The downloaded file was missing PRODID, UID and DTSTAMP — all required
by RFC 5545 — used LF instead of CRLF, and wrote NaN for the dates:
nextTestTime arrives as an epoch string and new Date('1758...') is an
Invalid Date, so the timestamps never rendered. Apple Calendar rejects
the file outright; more lenient clients had been hiding it.
Replace react-icalendar-link with a small local builder that emits the
required properties, escapes TEXT per 3.3.11, leaves URL unescaped since
it is a URI value, and folds lines at 75 octets rather than characters
(Cyrillic copy overruns a character-based fold). The UID is derived from
the start time so re-downloading updates the event instead of stacking
duplicates.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Those pages keep their own controls in the bottom-right corner, where the pill sits. Add clearance via a --ks-aux-lift custom property, set from the uxcorePage body class that _app.tsx already applies to /uxcore, /uxcg, /uxcp, /uxcat and /uxcore-api. The margin goes on the root rather than the pill: the panel is positioned against the root, so raising the pill alone would leave the panel anchored low and overlapping it. On mobile the panel height comes from --ks-aux-panel-h, and a JS-set custom property overrides the CSS fallback entirely, so the lift has to be subtracted there too — otherwise the panel keeps its full height and runs off the top of short screens. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Claude finished @MaryWylde's task in 4m 21s —— View job Review completeTodo list
AssessmentWell-diagnosed set of fixes — each commit correctly traces the bug to its root cause rather than papering over symptoms, and the PR description's reasoning checks out against the code. Highlights:
No violations of AGENTS.md conventions found — import order, barrel files, SCSS modules, no App Router/Tailwind/new state libs, no hydration hazards (all Two minor, non-blocking suggestions left as inline comments (a defensive bound on |
|
|
||
| for (const locale of SLIM_LOCALES) { | ||
| let page = 1; | ||
| while (true) { |
There was a problem hiding this comment.
Minor robustness nit: this while (true) only terminates on an empty page or a short page (json.data.length < PAGE_SIZE). getStrapiBiases below guards the same kind of loop with fetched < TOTAL_ITEMS_EXPECTED so a Strapi pagination bug (e.g. always returning exactly 100 items) can't spin forever. Worth adding an equivalent upper bound here too, since this runs client-side on every /uxcat page load.
| const CRLF = '\r\n'; | ||
| const PRODID = '-//KeepSimple//UXCAT//EN'; | ||
| const DEFAULT_DURATION_MS = 30 * 60 * 1000; | ||
| const MAX_LINE_OCTETS = 74; |
There was a problem hiding this comment.
Small mismatch: the comment on foldLine (and the PR description) says folding happens "at 75 octets," but MAX_LINE_OCTETS is 74. Not a bug — it's on the conservative side (first physical line could actually hold 75 per RFC 5545 §3.1, only continuation lines need the -1 for the leading space) — but worth a one-line comment explaining the off-by-one is intentional, or bumping the first line to 75, so a future reader doesn't "fix" it into a real bug.
Four user-reported bugs on UXCAT / UX Core. One commit per fix, each reviewable on its own.
1. Bias explanation never loads during the test (
d4171fa)Reported as a geo/VPN issue (tested from RU, and via NL and DE VPNs) — it wasn't.
uxCoreDatawas hardcoded tonullin the UX Core context value, so every consumer of the shared bias list got an empty array, for everyone, on every network.On the ongoing test the bias name comes from the test API and rendered fine; the description comes from context and sat on a skeleton forever, which is what made it look like a slow/blocked fetch.
Populated client-side from a slim Strapi query gated to
/uxcatroutes. The full bias payload is ~1.4 MB and these screens read onlynumber,title,description,slugandmentionedQuestionsIds, so we select just those (~38 KB/page) and cache per module.mentionedQuestionsIdsis not optional —test-resultJSON.parses it to pick recommended reading and throws onnull.Same fix repairs
QuestionAnalyse, which built its list in an effect with an empty dependency array and so never saw the data land.2. "Our projects" modal doesn't scroll (
1166ea1)Reported on
/ru; it's the shared UX Core modal, soenandhyhad it too. The wrapper had no height ceiling, so on short viewports it grew past the screen and the centred overlay clipped it at both ends — header and footer buttons unreachable.Capped the wrapper, stopped the header shrinking, and gave the body
min-height: 0— without that a flex child can't shrink below its content height andoverflow: autonever engages. The mobilefullHeightMobileoverride still wins by source order.3. Apple Calendar rejects the .ics (
8b2cf72)The file was missing
PRODID,UIDandDTSTAMP(all required by RFC 5545), used LF instead of CRLF, and wroteNaNfor both dates —nextTestTimearrives as an epoch string andnew Date('1758…')is an Invalid Date. Apple Calendar rejects it outright; more lenient clients were masking it.Replaced
react-icalendar-linkwith a small local builder: required properties, TEXT escaping per §3.3.11,URLleft unescaped as a URI value, and folding at 75 octets rather than characters (Cyrillic copy overruns a character-based fold). UID derives from the start time, so re-downloading updates the event instead of stacking duplicates.4. Copilot pill overlaps UX Core page chrome (
1873535)Lifted 70px on
/uxcore(incl. bias pages),/uxcg,/uxcp,/uxcatand/uxcore-api, via a--ks-aux-liftcustom property driven off theuxcorePagebody class_app.tsxalready sets for exactly those routes.The margin goes on the widget root, not the pill: the chat panel is positioned against the root, so raising the pill alone would leave the panel anchored low and overlapping it. On mobile the panel height comes from
--ks-aux-panel-h, and a JS-set custom property overrides a CSS fallback entirely — so the lift is subtracted there too, otherwise the panel keeps full height and runs off the top of short screens (measuredpanelTop: -39at 360×640 before the fix).Test plan
tsc --noEmitclean; ESLint clean on touched files (remaining warnings pre-date this branch)en/ru, zero index misalignment between locales (mergeBiasesLocalizationpairsen[i]withru[i], so this matters), no null descriptionsru/en/hy. Before: wrapper spanned −110→731, 0 scroll, footer off-screen. After: 20→600, body scrolls, footer reachableNaN, every line ≤75 octets, commas/semicolons/newlines escaped, URL unescaped;parseEventDatecorrect for epoch number, numeric string and ISO string,nullfor garbageNote for the reviewer
react-icalendar-linkis now unused but still inpackage.json. Left in deliberately: removing it needsnpx --yes yarn@1.22.22 remove, because the systemyarnis Berry 4 and rewrites the v1 lockfile into Berry format. Happy to drop it here or in a follow-up.🤖 Generated with Claude Code