Spaces:
Running
Running
Commit History
Today
-
docs: record reader and search analytics and how queries are kept Running
siddhm11 +1: Claude Opus 5.5CURRENT-STATE gains a reader and search analytics row and lists the three new replicated tables. Doc 06 logs the decision: searches logged, query text kept 90 days and never stored against a reader, the owner's own use flagged and left out, with the production numbers that made it necessary (321 of 335 saves from search, no search ever recorded; 7 of 131 readers came back). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>c89cdb2 -
feat(admin): readers, searches and AI history dashboards
siddhm11 +1: Claude Opus 5.5Three owner-only pages next to AI usage, with tabs across all four: /admin/readers readers today, this week and month, the share who came back, what they did, new and returning readers per day, and readers per month since launch with where saves came from /admin/searches searches per day with and without results, the share that led to an opened or saved paper, the most searched queries, queries that found nothing, and the latest searches with their AI rewrite and overview /admin/ai/history every AI call by paper (title, plain summary, briefing outcome, tokens) and by search (rewrite, overview) The owner's own use is left out unless 'Include my own use' is chosen. Model-written text is shown as text, never markup. Every chart now comes from one builder with one tooltip script: whole-number ticks for small counts, about seven l…e8530b8 -
feat(analytics): reports on readers, searches and AI history
siddhm11 +1: Claude Opus 5.5readers_report: readers per day, new against returning (a reader's first day is the earlier of their first action and first counted day, so readers from before counting began aren't new), readers today and over 7 and 30 days, what share searched, opened, saved and asked, and the long view from every recorded action since launch: readers per month, how many days they came back, where saves and opens came from. The owner's browsers, known from reader_days, are left out unless asked for. searches_report: searches per day, the share that found nothing, fell back to keyword search, were rewritten, or led to an opened or saved paper (through the query_id their results carry), the most searched queries, queries that found nothing, and the latest searches with their rewrite and overview. ai_history: every AI call grouped by its paper (title, calls per feature, failures, tokens, the latest plain summary and briefing outcome) or its search (rewrite and overview). Co-Authored-By: Claude Opus 5…a7c16d8 -
feat(analytics): count what each reader does, per day
siddhm11 +1: Claude Opus 5.5There are no accounts, so a reader is the anonymous cookie. Interactions recorded saves and passes, but not visits, searches, feed pages, papers opened or questions asked, and the owner's own testing was mixed in with everyone else's (October's three active readers were the owner). reader_days keeps one replicated row per reader per UTC day: pages, searches, feed pages, papers opened, saves, passes and questions, with owner = 1 for a browser holding the preview token. analytics.observe(), called from the HTTP middleware for every finished request, classifies it by route, so no handler has to remember; failed requests, first visits, static files, figures, health and admin pages don't count. Counts live in memory and are written every minute and on shutdown, rows rewritten whole so turso_sync pushes them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>ae5214c -
feat(analytics): log searches, and keep and reuse their AI overviews
siddhm11 +1: Claude Opus 5.5Searches weren't recorded at all: 321 of 335 saves came from search results, but not how many searches there were or what was asked. search_log now keeps one row per search: the query (collapsed, at most 200 characters), its query_id (which the results' clicks and saves carry), the result count, retrieval mode, the AI rewrite when it changed the query, the time taken, and whether it was the owner. It is not stored against the reader. search_overviews keeps the AI overview shown for a query over its top five papers, and is also its cache: the same search reuses it for a week instead of a new model call (counted as search_overview cache hits). What people typed is kept 90 days: a daily housekeeping run clears query text, rewrites, overviews and search subjects in llm_calls, locally and in Turso, which only ever receives new rows and so must be told. Counts stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>bc1e7b6 -
feat(ai-usage): record the paper or query each AI call was for
siddhm11 +1: Claude Opus 5.5llm_calls gains a replicated subject column: the arXiv id for plain summaries, briefings and Ask, and the search query (whitespace collapsed, at most 200 characters) for the search rewrite and overview. A call that failed or found every model busy now says which paper or search it was for. Search queries are cleared after 90 days by the next commit's housekeeping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>600f214 -
docs(current-state): the AI usage dashboard at /admin/ai
siddhm11 +1: Claude Opus 5.5Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>3fce785 -
feat(admin): an AI usage dashboard at /admin/ai
siddhm11 +1: Claude Opus 5.5/healthz/ai is data for machines; this is the same data for a person, visible only with the preview token (404 for everyone else, noindex): today model calls, tokens, share answered by a backup model, share served from the cache, failed or busy calls stands out plain sentences with a status icon and word: the feature using most tokens (and whether it is cached), a model near its daily tokens or its minute, backup answers over a tenth, busy or failed calls, cache hit rates, declined briefings, reports models each model's tokens today against 200,000, and the requests and minute-tokens Groq last reported, as meters labelled when close features per feature: calls, answered, backup, cut off, failed, tokens and time per call, cache hit rate, every outcome count history tokens per day for 14 days, stacked by feature, one tooltip per day listing every feature, and th…61a86da -
fix(ai-usage): give a rate-limit window's age, not its raw timestamp
siddhm11 +1: Claude Opus 5.5/healthz/ai listed both the raw 'at' timestamp and age_s for each model's window: the timestamp was removed from the original after the copy was made. Seen on the live page after the first real call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>279a374
Yesterday
-
docs: record AI usage measurement and the caching flaws it found
siddhm11 +1: Claude Opus 5.5CURRENT-STATE gains an AI usage row (llm_calls columns, ai_daily, /healthz/ai, Groq's limits) and lists ai_daily as replicated; the LLM row no longer says the Groq chain is undeployed. Doc 06 logs the decision with the token arithmetic behind it and three findings from production: the briefing cache key thrown away by an unrelated parser bump (one good briefing replaced by a decline), uncached search AI, and plain summaries written twice. A schema comment still said 8 figures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>5af37f8 -
feat(health): /healthz/ai shows where the AI goes today
siddhm11 +1: Claude Opus 5.5Per feature: calls, ok, fallback (a model other than the primary answered), truncated, failed, unavailable, unparsable and over-budget calls, tokens in and out, average time, and the day's counts (cache hits, outcomes, drops, reports), including counts not yet written. Per model: calls, tokens and their share of the day's 200,000-token limit, and the newest rate-limit window Groq reported. Plus the briefing budget and 14 days of history. Groq's limits per model are now config (GROQ_REQUESTS_PER_DAY, GROQ_TOKENS_PER_DAY, GROQ_TOKENS_PER_MINUTE): no header reports tokens per day, so that limit has to be known to be compared against. Counts only: never a prompt, an answer or a reader. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>359b725 -
feat(ai-usage): count cache use and answer quality per feature, per day
siddhm11 +1: Claude Opus 5.5Calls alone don't say how well the AI did. ai_daily keeps one number per UTC day, feature and metric, replicated: explain cache_hit, cache_miss, written, trimmed, declined search_rewrite skipped (already academic), rewritten, unchanged, discarded search_overview shown, trimmed, empty briefing cache_hit, cache_miss, ok, insufficient, failed, busy, points_dropped (by the number and anchor checks) ask cache_hit, cache_miss (suggested questions), answer, unanswerable, nosupport, cap, busy, error, quotes_kept, quotes_dropped, cites_dropped any feature reported (Report a problem) ai_usage.count() only adds to a dict; a loop owned by the app lifespan writes the counts every minute and on shutdown, each row rewritten whole so turso_sync pushes it, and keeps them if a write fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>94b838e -
feat(ai-usage): log search rewrites, search overviews and plain summaries
siddhm11 +1: Claude Opus 5.5These three call Groq directly and logged nothing: no tokens, no failures, no sign of which model answered. groq_svc._run_logged now runs each one off the event loop and writes its llm_calls row, as search_rewrite, search_overview or explain, including calls that failed or found every model benched (status unavailable). Each feature still degrades exactly as before; a search that already looks academic makes no call and logs none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>134608d -
feat(ai-usage): log each model call's tokens, fallback and rate-limit window
siddhm11 +1: Claude Opus 5.5llm_calls held characters and a status. Each row now also has tokens in and out from Groq's usage, the answering model's place in GROQ_MODELS (0 is the primary), whether the reply hit the token cap (still status failed, which the briefing and Ask already handle), and the requests left today and tokens left this minute that Groq reported. app/ai_usage.py writes every row; app/llm.py now goes through it. The six columns replicate; turso_sync adds them to the remote table with the duplicate-tolerant ALTER (trap T8). LLM_DAILY_CALLS keeps covering only the briefing and Ask, so search calls, logged next, can't switch them off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>037c6f0 -
feat(groq): record tokens, the answering model's place and rate-limit headers
siddhm11 +1: Claude Opus 5.5groq_svc._complete, which every model call goes through, now returns Groq's token usage and the answering model's place in GROQ_MODELS (0 is the primary, anything else a fallback), and keeps the newest rate-limit headers per model, from answers and from 429s alike, through with_raw_response. Groq's headers report requests left today and tokens left this minute; no header reports tokens used today, which is why usage is kept per call. Groq's documented limits per model are 30 requests and 8,000 tokens a minute, 1,000 requests and 200,000 tokens a day. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>5aa36b6 -
fix(config): one helper for the test-only arXiv addresses, tested without a reload
siddhm11 +1: Claude Opus 5.5The previous commit's test reloaded app.config, which reset every setting for the tests that ran after it (two feed tests lost their database). Both arXiv addresses now go through _test_override(), honoured only when RESEARCHIT_ENV=test, and the test calls it directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>cb02b51 -
docs: record arXiv's access rules, the background lane and search thumbnails
siddhm11 +1: Claude Opus 5.5Doc 06 logs the split between the readers' pacer and a 15 s background lane, with the sources: arxiv.org/robots.txt (Crawl-delay: 15), arXiv's bulk-data page (interactive use first) and its API terms, which also leave figure redistribution to the copyright holder; that licence risk is recorded as the owner's open call. CURRENT-STATE gains the search thumbnail row and the warm-up's shown-papers queue, lane, cap and batch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>d0e4419 -
feat(search): a small figure beside each search result (SEARCH_FIGURES)
siddhm11 +1: Claude Opus 5.5Search is for scanning titles, so its figure is a small thumbnail to the right of the text (7.5rem, 4.75rem on a phone), not the feed card's large figure. It appears only for papers with a figure already saved (card_data, local reads only); the warm-up reads the top five results for next time. Without a figure the classic card's markup is unchanged, and it is shared by every page. The thumbnail repeats the title's link with #sec-fig, so it is out of the tab order and hidden from screen readers, with its credit in the title attribute. A thumbnail that fails to load is hidden. Eye-tracking (Google) and a 2025 IJHCI study found result thumbnails make the wanted result faster to find without changing how people scan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>7f2981f -
test(e2e): keep the test world's searches off the real arXiv API
siddhm11 +1: Claude Opus 5.5The seeded sidecar had no word index, so a search in the test world found nothing and fell back to export.arxiv.org: browser tests would have reached the real arXiv. The seed now builds papers_fts like the real sidecar, and ARXIV_API_URL, like ARXIV_HTML_BASE, can be pointed at the stand-in site only when RESEARCHIT_ENV=test; a test checks it cannot be redirected otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>92f723d -
feat(figures): read the papers people are shown, in the background
siddhm11 +1: Claude Opus 5.5Feed cards (and now search thumbnails) only show figures already saved, so a paper nobody had opened never showed one. Every feed page and the top 5 search results now call figure_prewarm.enqueue(); the warm-up reads queued papers one at a time through the 15 s background lane and prepares each one's first figure, so it shows the next time the paper appears. The queue holds 300 and drops the oldest; reading stops at 800 papers a day and while the breaker is open. The date-based run also takes the background lane, in batches of 300 rather than 1500 (about 2.5 hours a batch). /healthz/sources reports the queue, reads today and the cap. Still behind FIGURE_PREWARM, which is off until switched on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>f2a6efe -
fix(sources): background requests wait 15 s, as arXiv's robots.txt asks
siddhm11 +1: Claude Opus 5.5arXiv's robots.txt sets Crawl-delay: 15 for automated clients, and its bulk-data page puts interactive use by people first. Fetches a reader triggers stand in for that reader's browser and keep the shared pacer (one every 2 s, bursts of 3); work nobody is waiting for now also waits 15 s after the previous background request, so it can never use more than one request in 15 seconds however much is queued. ensure(background=True) and figures.prepare(background=True) take their slot before claiming a paper or figure, and give way if a reader is already fetching it, so a reader never waits behind background work. A paper or figure already saved costs no slot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>cbfe172 -
docs: record vector figures, the 24-figure cap and the figure rate limit
siddhm11 +1: Claude Opus 5.5CURRENT-STATE's figure row now covers SVG files and inline drawings, how they are cleaned and served, reduced-scale JPEG decoding, the 24-figure cap, the 600-a-minute limit and the hidden broken figure. Doc 06 logs serving cleaned SVG instead of rasterising (no native dependency, three layers keep script out) with the 50-paper measurement behind it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>7c5c922 -
test(e2e): vector figures render on the page and in the lightbox
siddhm11 +1: Claude Opus 5.5The seeded world now serves a small SVG chart at each SVG figure's path, so TRACE, whose two figures are both SVG files and showed nothing before, gets a browser test: the key figure is an .svg that loads, is served as image/svg+xml under a sandboxing policy, and opens in the lightbox. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>7c261e8 -
fix(limits): allow 600 figure requests a minute per address
siddhm11 +1: Claude Opus 5.5A paper page now shows up to 24 figures rather than 8, and one campus or office network can be many readers behind one address; two browser test runs back to back already hit the old 240. A cached figure is a file read, and fetches from arXiv keep their own pacer of one every 2 seconds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>bffdd34 -
feat(figures): serve vector figures as cleaned SVG
siddhm11 +1: Claude Opus 5.5/fig/<id>/<n>-<h8>.svg serves a figure's SVG after app/svg_clean.py has rebuilt it. An SVG file is fetched from its path; a drawing inline in the page is lifted out of the page, one fetch filling the cache for all of a paper's drawings, with concurrent requests sharing that fetch. Responses carry Content-Security-Policy default-src 'none' with sandbox, so a file opened directly runs nothing; pages show figures only through <img>. Picture URLs are unchanged, so cached thumbnails stay valid. A figure asked for in the wrong format is a 404, and a figure's path must stay under its own paper. The warm-up prepares any kind through figures.prepare(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>71b2d8b -
feat(sources): keep up to 24 figures and record each one's kind
siddhm11 +1: Claude Opus 5.5Pages showed at most 8 figures (SatNav: 8 of 16). A paper averages about 7, so 24 covers nearly all while a replicated row stays small. Each saved figure now carries its kind when it is not a picture: "svg" with the file's path, or "svg-inline" with the page's path (2201.11903v6) and its anchor. n_figures counts only figures with an image, so "X of Y" no longer counts figures that are only text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>318ba14 -
feat(arxiv-html): collect SVG figures, as files and drawn inline
siddhm11 +1: Claude Opus 5.5The parser took only <img> figures. It now also records an SVG file that an <object> (or an <img>) points to as kind "svg", and the first <svg> drawn inside a figure as kind "svg-inline", with no path: inline_svgs() lifts the drawing out of the page as an element tree when it is wanted. It builds the tree from html.parser events, since labels are HTML and may hold an unclosed <br>, and gives up on a drawing over 100,000 elements. On 2201.11903 every one of its 11 figures now has an image (1 picture, 3 SVG files, 7 drawings), against 1 before; on 2508.12461, 7 of 7 against 1. In the fixtures, TRACE's two figures and AlphaEarth's Figure 2 gain their SVG files. PARSER_VERSION is 2, so saved papers are read again on next open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>361cfb4 -
feat(svg): clean vector figures down to drawing elements
siddhm11 +1: Claude Opus 5.5In 50 papers from September 2026, 118 of 333 figure images were SVG: files an <object> points to (matplotlib, Inkscape) or drawings inline in the page (LaTeXML's TikZ and pgfplots). None of them showed. SVG is code, so app/svg_clean.py rebuilds each one from an allow-list of SVG, HTML and MathML elements, drops on* attributes, links outside the document, url(...) that is not url(#...), CSS escapes and non-image data, refuses entity declarations and internal DTD subsets, and caps size and element count. Inline SVG arrives lowercased from html.parser, so SVG's camelCase names and the namespaces of HTML and MathML labels are restored. Checked on 2508.12461's radar chart: 138 KB cleaned in 9 ms, rendering identical to the original. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>c952499 -
fix(figures): hide a figure whose thumbnail cannot be made
siddhm11 +1: Claude Opus 5.5/fig/ answers 404 when no thumbnail can be made, and the page showed a broken image box in its place. app.js now hides that figure: the card's figure, the key-figure section, or its tile in All figures, and that section once no tile is left. It catches failures before it loaded too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>e10f732 -
fix(figures): decode huge JPEGs at reduced scale instead of refusing them
siddhm11 +1: Claude Opus 5.5Authors export print-resolution figures: both JPEGs in 2607.28156 are about 15,600 x 6,400 (100M pixels), over the 50M-pixel limit, so no thumbnail was made and the page showed broken images. A JPEG is now decoded at 1/2, 1/4 or 1/8 scale (Image.draft), the smallest still 800 px wide once upright, and the 50M limit applies to what is actually decoded. Those two figures now decode at 1,950 x 801 and come out 800 px wide, 39 KB, in under 0.1 s with 55 MB peak memory. Other formats keep the 50M limit; JPEGs claiming over 400M pixels are refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>5cff7af -
docs(feed): record the two-column feed, layout logging and figure warm-up
siddhm11 +1: Claude Opus 5.5CURRENT-STATE gains rows for the v2 card, the wide feed, the layout column and ui_events, and the figure warm-up worker. Doc 06 logs the decision that the two columns keep served order (grid, auto-flow row, never dense) and that interactions record their layout, so position analysis can be split by it. CLAUDE.md §3.1 and §3.11 carry both as guards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>a0b3515 -
docs(ask): first Ask evaluation over 20 papers (2026-10-19)
siddhm11 +1: Claude Opus 5.580 questions: 55 answered, 23 declined as unanswerable (all 20 off-topic questions among them), 2 declined for lack of support, none busy or failed. 84 quotes shown, 24 dropped by the verbatim check. Median 0.72 s, p95 1.41 s. ratings.csv is left for a person to fill in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>a3f20c2 -
test(e2e): browser checks for the v2 card and the two-column feed
siddhm11 +1: Claude Opus 5.5Against the seeded world: two columns at 1440 px with every card at or below the one served before it and no overlaps, one column at 1179 px and on a phone, no sideways scrolling, Save and title clicks carrying layout=grid2 with the §3.11 fields intact, the rail's counts and interest filter (labels rendered as text), card text tabs and the rail preference surviving a reload, and figures loading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>860f9e0 -
fix(feed): pin the card menu to the corner when a card has no interest label
siddhm11 +1: Claude Opus 5.5Cards from the category and popularity tiers have no interest label, so the top row held only the menu button and left a blank band above every title. The menu now sits in the card's corner on those cards and the title keeps clear of it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>f3db993 -
feat(figures): prepare new papers' figures in the background
siddhm11 +1: Claude Opus 5.5app/figure_prewarm.py (FIGURE_PREWARM) asks Turso every 6 hours for papers dated in the last two days, skips ones already read, and reads each page and makes its first figure's thumbnail through the shared pacer, stopping when the breaker opens and at FIGURE_PREWARM_BATCH papers. It runs inside the Space because turso_sync only pushes after boot (trap T2), holds a file lock so there's one runner, and reports in /healthz/sources. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>db5a2cd -
feat(feed): two-column wide feed with an interest rail (FEED_WIDE)
siddhm11 +1: Claude Opus 5.5From 1180 px the feed is a grid of small rows with each card spanning rows to its height, set by a ResizeObserver, so two columns pack without moving anything: it stays one list in served order (§3.1), auto-flow row and never dense, and the loader still swaps in place. A sticky rail holds the issue line, Discover more, the interests on the page with counts (built from the cards with textContent), a client-side filter that hides cards and says "Showing N of M", and the Plain terms / Abstract preference. Filter use is recorded as a UI event, since hidden cards were still served. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>260969f -
feat(log): record which layout each interaction happened in
siddhm11 +1: Claude Opus 5.5A two-column feed changes how position relates to attention, so Save, Pass, Remove and click-throughs now carry layout (list or grid2) into a new interactions column. It replicates following trap T8: the local migration, an ALTER on the remote run once in ensure_remote_schema with only the duplicate-column error ignored (any other error stops replication start rather than pushing rows the remote can't take), then the column in the pushed and restored list. Old fake remote rows in the restore tests gain the new trailing column. Also adds POST /api/ui-event for the wide feed's controls, stored locally in ui_events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>edcddb5 -
style(feed): card v2 layout, per-card text tabs and Why this paper
siddhm11 +1: Claude Opus 5.5Card tabs and the menu's Why this paper are delegated, so appended pages need no binding; cards open on the reader's remembered text preference. The action row's own Why button, which a Save response re-renders, stays hidden on these cards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>f1da4df -
feat(feed): the redesigned card behind FEED_CARD_V2
siddhm11 +1: Claude Opus 5.5Interest label and a "⋯" menu (Why this paper, 3D, arXiv, Copy ID), the title with exactly today's link and §3.11 query string, authors, year and Code chip, a figure that opens the paper at its key figure, and per-card In plain terms / Abstract tabs. At most eight things to click. The match meter and foot line are gone. Tests prove the Save values and links equal today's card's, the hooks app.js needs are kept, and the feed never asks for a summary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>e11a6d0 -
feat(feed): enrich feed cards with figures, code and cached summaries
siddhm11 +1: Claude Opus 5.5app/card_data.py adds what the redesigned card shows to copies of a served page: the first saved figure the licence policy allows, the saved GitHub repo, "In plain terms" only if one is cached for the abstract shown, and the full abstract when one is saved. Local reads only, never a model or an outside request, and order, ids and §3.11 fields are untouched. The router calls it after the page is built and logged, when FEED_CARD_V2 is visible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>5723366 -
chore(eval): briefings for the 50 evaluation papers, ready to rate
siddhm11 +1: Claude Opus 5.548 of 50 produced a briefing that passed every check; the other two are the model declining on short maths papers. Rate each in ratings.csv; the gate for switching BRIEFING on is 45 good. Generated with the GROQ_MODELS chain (qwen/qwen3.8-27b) on 2026-10-19. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>dfa3298 -
fix(llm): repair TeX backslashes before parsing a model's JSON
siddhm11 +1: Claude Opus 5.5From the 50-paper evaluation: models copy TeX (\mathcal{O}) into JSON strings, which makes the reply invalid JSON, and the parser then returned the first inner object (one briefing point) as if it were the reply. Stray backslashes are now escaped before an object is given up on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>a85f8e6 -
test(e2e): briefing and Ask in the browser; fix an outline race
siddhm11 +1: Claude Opus 5.5The seeded world gains a cached briefing and two cached answers for SatNav. New browser tests: the briefing's links and outline entries, a suggested question echoed then answered with a cite, Enter sends while Shift+Enter doesn't, a missing model says busy, the phone sheet opens and closes on Escape with focus back on its button, and the lightbox asks about its figure. Fixed on the way: the section observer could override the last outline entry at the bottom of the page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>0cb3a12 -
fix(paper): background fragments fail quietly; limits sized for shared networks
siddhm11 +1: Claude Opus 5.5The browser tests opened paper pages faster than /briefing's 20-a-minute limit, and each 429 raised a "Something went wrong" toast for a fragment the reader never asked for. Fragments that load after paint now carry data-quiet and fail silently. The per-paper limits also assumed one reader per address, which a university network breaks; the cache-backed fragments now allow 60 a minute and Ask 20. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>0ef8102 -
fix(briefing): check multipliers and TeX-written numbers properly
siddhm11 +1: Claude Opus 5.5From the 50-paper evaluation: "2.3x" was skipped as a name because a letter followed the digits, so a multiplier went unchecked; and numbers the paper writes in TeX ($125$\,K) didn't match the same number in plain text, so correct points were dropped. Multipliers (x, ×) now count as quantities, and TeX wrapping, thin spaces and \times are ignored when comparing. A briefing that isn't shown keeps up to 2,000 characters of the model's reply, so the evaluation can say why. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>1452c66
2 days ago
-
feat(ask): an evaluation script, and log Ask in doc 06 and CURRENT-STATE
siddhm11 +1: Claude Opus 5.5scripts/eval_ask.py asks each paper the three suggested questions and one it almost surely doesn't cover, plus any owner-written ones, and writes a page to rate the answers with the gate's numbers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>1a6bc6f -
feat(ask): the chat panel, phone bottom sheet and figure questions
siddhm11 +1: Claude Opus 5.5A panel beside the text from 900 px and a bottom sheet from a floating button on a phone, with focus kept inside it until Escape. The question is echoed into the log as it's sent, Enter sends and Shift+Enter starts a new line, suggested questions disappear once asked, and the lightbox's Ask about this figure opens the panel and asks. Styles ported from the preview. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>a571e6c -
feat(ask): answer questions from the paper's own paragraphs
siddhm11 +1: Claude Opus 5.5POST /api/papers/<id>/ask picks passages with no model: the abstract, any figure or table the question names with the paragraphs citing it, and the top 8 paragraphs by BM25 in plain Python, with word hints for the suggested questions. The model drafts JSON; code keeps only quotes that match a cited paragraph word for word (NFKC, plain punctuation, whitespace and TeX dollars ignored) and shows the paper's own words for them, only cites that were sent, and swaps in a no-support message for any answer with an unfound number or no valid cite. Suggested questions are cached per paper and their text is always the server's own; free-form ones are not cached. A daily cap per reader, rate limit and the model budget each have their own message. Logs keep counts, never question text, and Ask never writes interactions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>b627658 -
docs: log the paper briefing in doc 06 and CURRENT-STATE
siddhm11 +1: Claude Opus 5.5Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>2300f36 -
feat(briefing): pace model calls and retry when Groq is saturated
siddhm11 +1: Claude Opus 5.5Measured live: four ~24,000-character briefing prompts in a row benched every model in the Groq chain, whose free tier is shared with search rewriting and In plain terms. Briefing calls now run one at a time at least BRIEFING_MIN_INTERVAL_S (8 s) apart, prompts are capped at 16,000 characters, and a call that finds no model available is reported as unavailable and not cached, so a later visit retries instead of waiting a day. scripts/eval_briefings.py generates briefings for the 50 papers in scripts/eval_papers.txt into a scratch database and writes a page to rate them, waiting out rate limits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>90ab33a