Repository navigation
Fix Library and History QA issues (T7: LB-01, LB-03–07, HI-01, MD-05, VS-07) - #203
Conversation
LB-01: the source switch moves at once and goes back with a toast when the write fails; offline, it does not move and says the change was not saved. LB-03/LB-05: one row per normalized URL per debate, checked in memory and against the server before insert; URL import warns before fetching. LB-04: on phones the row controls get their own line, the meta line and folder chips wrap, and the open-in-new link is a 44px target. LB-07: a new source shows at once while it saves, with a toast after, and the Library shows a loading line instead of 0 sources before first load. HI-01/VS-07: History gets a Crossfire tab with open (transcript and debrief) and delete; tabs wrap with 44px targets on phones. MD-05: research says how many sources it added, and the debate summary shows the active count Ask and the other tools use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… layout in verify recipes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A row still saving is found again by its id, so a folder switch that copies it no longer leaves a second copy behind. - Switch writes for one source run in click order; only the newest decides what shows, and a failure falls back to the last value the server took. - A server reload that read before a switch write keeps the new value. - An Undo row is pending until its insert lands, so it cannot be deleted or changed mid-restore. - The Crossfire delete dialog stays open while the delete runs and shows a failure in place. - Offline toast wording no longer repeats itself. - Vite ignores .verify/ and .ci-failures/, where Playwright's trace pages were reloading the app in the middle of recipes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ounts (MD-05) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The switch, a folder's Activate/Deactivate and the editor's Save all join each source's write queue, and a server reload keeps the newest of them, so a folder activation is no longer overwritten by an older toggle. - updateSource writes and undoes only the fields an edit changes, so a research metadata refresh cannot save a switch value that is still being written or about to fail. - Each Crossfire Open button names its round. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A reload keeps the value of any switch write already running when it started, not only writes that began after it. - A folder's Activate/Deactivate updates only the rows the Library shows, so a row still saving cannot take the folder's value on the server alone. - A failed switch write that a newer click already replaced is not reported; the newer write's outcome is what shows. - Debate counts leave out rows still saving, matching what tools send. - The identity test now copies a saving row through a folder rename. - docs/architecture.md describes the shared dedupe and the write queue. - lib-add waits for the pause to reach the server before leaving the page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Folder Activate/Deactivate and the source editor's Save did not catch a failed write, so a refused change rolled back with no message. Both now show a toast, offline-aware like the switch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The draft reloaded whenever the source object changed, so a rolled-back save or a background refresh replaced what the student had typed. It now loads once per opened source. lib-offline covers a failed offline save. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The editor sent every field on Save, so values loaded when the sheet opened could overwrite a switch or research change that landed while it was open. It now sends only what differs from what it loaded, and Save is disabled while a save runs. lib-offline retries the kept text online. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Save sent the fields that differed from what the sheet loaded, which went stale when the stored source rolled back and could be overwritten by a save that finished after the sheet moved to another source. The sheet now records which fields the student edited: those keep what was typed and are all Save sends; the rest follow the stored source while it is open. A finished save clears its marks only if the same source is still open. New recipe lib-edit-while-switching covers a switch that fails while the editor is open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A finished save cleared the edit mark of every field it sent, even one the student changed again while it ran, so that text was never sent and could be replaced by the stored copy. Each field now carries an edit count and each sheet opening a number; a save clears a mark only when neither changed. lib-edit-while-switching types on during a slow save and checks the next Save sends it, and first checks the editor opened mid-write. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedEnable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Next included review available in 37 minutes. View limit details
ℹ️ Recent review info
📝 Walkthrough
Note 🎁 Summarized by CodeRabbit Free
Comment |
Batch T7 from the 22 Oct 2026 QA report on prod: nine Library and History issues. Nothing here needs a migration, an Edge Function deploy or a production change. Merging ships only the frontend.
Issues
LB-01 (High): the Library switch reverted silently offline
lib-offline(switch and editor save offline, then a retry online) andlib-edit-while-switchingon desktop and mobile Chromium.LB-03 (Medium): research saved the same page again and again
src/lib/source-url.tsholds the URL normalizer: host lower-cased withoutwww., no scheme, fragment, tracking parameters (utm_*, fbclid, gclid and similar) or trailing slash.addSourcerefuses a page the debate already has (DuplicateSourceError). It checks the in-memory Library first, then the debate's rows on the server, so another tab or a list that failed to load can't add a second copy. Research auto-save refreshes the existing row's metadata instead of adding one. Undo is exempt.lib-dedupe.LB-04 (Medium): titles shrank to a few letters on phones
sm, the row's controls (open link, delete, switch) take their own line, so the title gets the row's width and two lines. The date/URL line wraps to two lines, folder chips wrap, and the open-in-new link is a 44px target on touch. The list card has less side padding on phones, and the search placeholder is shorter. OnlyLibraryPage.tsxchanged; no sharedui/primitives.lib-layoutat 360px with a long Spanish title. The title is wider than 200px and the page doesn't scroll sideways.HI-01 (Medium): Crossfire sessions couldn't be found again
CrossfirePage.tsxis untouched because T5 is changing it. The read-only view insrc/components/features/crossfire/SavedCrossfireView.tsxrepeats the debrief markup; once T5 lands, CrossfirePage can reuse it.cross-history(finish a round, leave, reopen from History, delete) on desktop and mobile Chromium.LB-05 (Low): a duplicate URL import was caught only after the fetch
import-source.lib-dedupeasserts noimport-sourcerequest is made.LB-06 (Low): deleting a source has no confirmation
MD-05 (Low): Attack added sources silently, and counts disagreed
/app, the Current Debate page and the header menu show "N sources (M active)" from one hook (useDebateCounts). M counts the same switched-on sources Ask's "Using M sources" counts.lib-counts(7 seeded sources, 5 on:/appshows "7 sources (5 active)", Ask shows "Using 5 sources") on desktop and mobile. Fake mode has no Exa, so the toast after a real Attack run is not verified end to end; that needs a live run.VS-07 (Low): History's tab bar scrolled sideways with ~30px tabs
LB-07 (Nit): no feedback after saving a source
lib-offlinerecipe checks the "Saved <title> to the Library" toast.Also in this PR
vite.config.ts: the dev server ignores.verify/and.ci-failures/. Playwright writes trace pages under.verify/during recipes, and Vite reloaded the app mid-test ("Unable to load DebateLab"). This caused three mobile recipe failures before the change and none after.lib-offline,lib-edit-while-switching,lib-dedupe,lib-layout,lib-countsandcross-history, with recipes and feature docs.docs/architecture.mddescribes the shared dedupe and the switch write queue.Not fixed here: two recipe failures that come from main
lib-import(#195)lib-importfails on both projects since main's #195 (batch C2, LB-02). The newstripHtmlreturns 0 characters for https://en.wikipedia.org/wiki/Free_public_transport; the old one returned 92,543. The cause is insupabase/functions/import-source/html-text.ts:WIKI_CHROMEtreats-as a word boundary, and Wikipedia's<html>element has the classvector-feature-toc-pinned-clientpref-1, which matchestoc.shouldStripapplies that check to every tag,<html>included, so the whole document is stripped. Out of scope for T7; C2 owns it.lib-add(on main since before #196; #196 uncovered it)The failing read is the recipe's
response.text()on the streamedairesponse. The trace shows that request ending innet::ERR_ABORTED. There is no navigation, no reload and no service worker; the page aborted it.src/lib/ai/live.tsstops reading at theresultSSE event and callsreader.cancel()infinally.supabase/functions/ai/stream.tswritesresultand closes the stream right after. The client's cancel races that close; when the cancel wins, Chrome drops the body.fetchwrapper read the whole response, which hid this. Delay Jam and align cache, CSP, and robots #196 loads Jam on the first click, and Keep Jam out of the full-stack e2e harness #198 stubs it in the harness, so the race shows. On this stack: pure main b79f858 fails 2/2, c5f3ad1 passes 2/2, and c5f3ad1 with Jam stubbed fails 2/2.live.ts, afterresult, keep reading to the end of the stream (bounded by the abort signal and a ~2 s cap) and cancel only if it hasn't ended. With that patch applied temporarily,lib-addpasses 2/2. For users, it also stops every live request from ending as aborted and from firing the Edge Function'scancel()after the answer. Not changed in this PR.Review rounds
r1 and r2 ran on Codex. From r3 on, Codex returned 429 (plan limit), so each round ran as a fresh-context Claude Opus review with the same scope and the repo's CODING_STANDARDS.md.
docs/architecture.mdwas stale.The same review agreed that the
lib-addnetwork-body failure comes from main and that nothing in this branch touches that path.lib-offlinenow edits offline and checks the typed text stays; it fails without the fix ("Fares and ridership.").lib-edit-while-switchingrecipe fails a switch write while the editor is open.Verification
Local only; GitHub Actions minutes are used up, so there's no CI run. Local passes at the final head:
npm run verifyat 70e5dd7 (the full ladder) exits 0:verify-debatelab recipes (fake provider, local Supabase) at 70e5dd7:
practice(includescross-history): 5/5 on desktop-chromium and 5/5 on mobile-chromium.library:lib-offline,lib-edit-while-switching,lib-dedupe/lib-layoutandlib-countspass on both projects.lib-addandlib-importfail on both, for the two main issues described under "Not fixed here". Neither comes from this branch: both fail the same way on main's own app code..verify/artifacts/on the VPS worktree; not attached.Not verified: real Chrome DevTools offline (the pill), a live Attack run's toast, staging and production.
Proposed cleanup for existing duplicates (not run)
Prod still has the duplicate rows from before this fix. This is a proposal for Adam to review; deleting them is a mass delete and needs a separate OK. The preview only reads. The delete keeps one row per user, debate and page: the switched-on one if any, otherwise the oldest. Its normalization approximates the app's (host lower-cased without
www., path without trailing slash, utm_*/fbclid/gclid dropped). Run the preview first and spot-check the groups. I checked the preview on a local database with seeded rows inside a rolled-back transaction: it groupedhttps://www.Motherly.com/homework/?utm_source=x#topwith a row whose metadata URL ishttp://motherly.com/homework, kept the switched-on copy, and left?id=2alone.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes