Re-vendor the browser bundle: resize-aware summary clamp, and no stranded skeleton - #49
Merged
Merged
Conversation
…nded skeleton Picks up scolta-php#269, two follow-ups to the layout reservation. The clamp decision is a measurement, and it ran only on resolve and on a toggle click, so it froze at the width the summary landed in. Narrow the column afterwards and a summary that fitted reflows past the reserved height: still clipped, but with no fade and no control, so a sighted reader saw text cut off with no way to open it. A feature-detected ResizeObserver on the text region now recomputes it, one live at a time, disconnected on release and on expand, re-established on collapse, and never installed when the summary is off. The box measures the same at every width, so the reveal moves nothing. Separately, the un-awaited summarizeResults() call had nothing chained onto it, so a throw before its fetch became a rejected promise the expansion chain's catch never saw, stranding the reserved skeleton. It now carries its own version-guarded catch. No Python-side change. Copied byte-identically with scripts/vendor_assets.py, verified with cmp.
SummaryRe-vendors the browser bundle Type: bugfix Walkthrough
Related Issues & PRs
AI Review Summary — generated by ai-pr-review |
There was a problem hiding this comment.
AI Review: Approved
No findings above the confidence threshold. The changes look good.
🔵 Out-of-diff analyzer findings (2) — pre-existing issues on unchanged lines, capped to Low
- 🔵 [Low] [F1] [semgrep] javascript.lang.security.audit.detect-non-literal-regexp.detect-non-literal-regexp: RegExp() called with a
queryfunction argument, this might allow an attacker to cause a Regular Expression Denial-of-Service (ReDoS) within your application as RegExP blocks the main thread. For this reason, it is recommended to use hardcoded regexes instead. If your regex is run on user-controlled input, consider performing input validation or use a regex checking/sanitization library such as https://www.npmjs.com/package/recheck to verify that the regex does not appear vulnerable to ReDoS. (atsrc/scolta/assets/js/scolta.js:1025(line not in diff)) - 🔵 [Low] [F2] [semgrep] javascript.lang.security.audit.detect-non-literal-regexp.detect-non-literal-regexp: RegExp() called with a
queryfunction argument, this might allow an attacker to cause a Regular Expression Denial-of-Service (ReDoS) within your application as RegExP blocks the main thread. For this reason, it is recommended to use hardcoded regexes instead. If your regex is run on user-controlled input, consider performing input validation or use a regex checking/sanitization library such as https://www.npmjs.com/package/recheck to verify that the regex does not appear vulnerable to ReDoS. (atsrc/scolta/assets/js/scolta.js:1044(line not in diff))
Token usage by agent
| Agent | Model | Input | Output | Cache Write | Cache Read | Total | Est. Cost |
|---|---|---|---|---|---|---|---|
| code-reviewer | Sonnet 5 | 1 | 18 / 16384 | 20522 | 1195 | 21736 | $0.0775 |
| silent-failure-hunter | Sonnet 5 | 1 | 693 / 16384 | 20488 | 0 | 21182 | $0.0872 |
| judge-pass | Sonnet 5 | 1646 | 119 | 0 | 0 | 1765 | $0.0067 |
| Total | 1648 | 830 | 41010 | 1195 | 44683 | $0.1714 | |
| Context enrichment | (context) | 8195 | — | — | — | — | — |
| Language profiles | (profile) | 857 | — | — | — | — | — |
AI Review — generated by ai-pr-review
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-vendors
src/scolta/assets/js/scolta.jsfrom canonical to pick up tag1consulting/scolta-php#269, two follow-ups to the AI-summary layout reservation.scolta.cssis unchanged; that fix was JS only.1. The clamp decision was frozen at resolve-time width
Whether to clamp the summary and offer Show more is a measurement (
scrollHeightagainstclientHeight), and it ran only on resolve and on a toggle click. There was no resize listener in the bundle at all, so the decision was fixed at the width the summary happened to land in.Rotate a phone to portrait, or shrink a responsive column, and a summary that fitted reflows to more lines and overflows the reserved height. The text is still clipped, but with no clamped class there is no fade and the control stays hidden, so a sighted reader saw text cut off at the box edge with no on-screen way to open it. The full text is in the DOM throughout, so find-in-page and assistive tech were never affected; the visible affordance was. Widening had the mirror problem, leaving a pointless control on a summary that now fits.
A feature-detected
ResizeObserveron the summary text region now recomputes it: exactly one live at a time, disconnected when the slot is released and when the user expands the summary (not fighting that choice), re-established on collapse, and never installed when the AI summary is off.The recompute moves nothing. It toggles a mask class and the control's
hiddenflag inside the fixed-heightoverflow: hiddenpanel, and the reserved height derives from a line count and a font size rather than the width, so the box measures the same at every width: 297.03px at 1280px wide and at 420px wide, control hidden at the first and visible at the second.2. A pre-request throw stranded the loading skeleton
The search flow's expansion chain ends with an un-awaited
summarizeResults(...), which is correct in itself, but nothing was chained onto the promise it returns. That function handles its own fetch failures; the work before the fetch does not, andbuildLLMContext()dereferencesr.data.metaunguarded. Because the function isasync, such a throw becomes a rejected promise rather than a synchronous error, so the chain's own trailing.catchnever saw it. With the slot reserved from the frame the results paint, the consequence was a skeleton shimmering permanently with no way back. The call now carries its own.catch, guarded on the search version so an abandoned cycle cannot collapse a newer search's slot.Python side
Nothing changed. Both fixes are browser-side behaviour with no config key, no schema, no serialized setting, no indexer involvement and no index rebuild. Django and Wagtail inherit this through their
scoltadependency and need no change of their own.No new tests were mirrored into
tests/js/. That suite is a 14-file subset rather than a strict mirror of scolta-php's 26, and it carries none of the summary, SAYT or render-seam suites; the new coverage lives with the code it tests, upstream.Verification
python scripts/vendor_assets.pycmp src/scolta/assets/js/scolta.js ../scolta-php/assets/js/scolta.js— identicalcmp src/scolta/assets/css/scolta.css ../scolta-php/assets/css/scolta.css— identical (unchanged this round)python scripts/validate-dist.py— passed (wheel 770,590 bytes; sdist 4,343,094 bytes)pytest— 808 passedtests/jsJest subset — 283 passed, 1 skipped, across 14 suitesVendored from scolta-php
mainat07fddae, canonicalscolta.jsSHA-256240d3b9c….