Repository navigation
iOS app: catch up with main and restyle as DebateOwl - #253
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes the Foundations rows of the 2026-10-09 design audit. - Delete the global toast keyframe that froze Sonner, so toasts stack, expand and leave again. - Rewire the colour tokens: muted text is a real lower tier, the ghost hover, popover, primary, destructive and input colours meet contrast, and dark shadows show. - Delete the global micro-interaction layer (tooltip, menu items, tab underline, icon hijacks, marching ants, switch bounce, progress width, .tabular-nums, input focus glow). Each overlay primitive now has one curve, exits faster than it enters, and scales from its trigger. - Gate hover on devices that hover, make press feedback 0.97 over 100ms, and give buttons, Select triggers, checkboxes and close buttons 44px hit areas on touch. - Reduced motion fades instead of freezing; reduced transparency and more contrast turn blurred surfaces solid; safe-area insets and the tap highlight are handled. - One focus outline, a single theme crossfade, and light and dark theme-color metas. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…overlapping Codex review r1 on #124: - Ask's Save and the Factoids link icon were opacity-0 until hover, which hoverOnlyWhenSupported made permanent on touch. They now rest at 60% and go full on hover or focus, as the audit's accessibility row asks. - The 44px checkbox hit area overlapped the next row in the debate context list. It is 36px, and those rows are at least 44px on touch, so each label stays the larger target. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…other Codex review r2 on #124: switching theme twice before the first transition was ready left its ready promise rejected and unhandled (AbortError: Transition was skipped). The final theme was already correct. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The audit replaced the blanket reduced-motion kill with one that keeps opacity and colour transitions. The spec asserted a 0s transition on the options panel; it now asserts the panel transitions nothing that moves (no transform, height, grid rows or 'all'). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes the Shell rows of the 2026-10-09 design audit. - Header: "Home" is now "Tools", and "Current debate" is a link that is active on the debate page and every tool route, with its own menu chevron. The brand is a span, Home's h1 describes the page, the nav pill and glow are gone, the edge appears only on scroll, and icon controls get tooltips. Language is a two-tap popover. - The mobile menu is a modal panel with a scrim and a 180ms fade. The theme toggle leaves the mobile header. On phones, side sheets become Vaul bottom sheets. - One delete rule: Undo when the app can put the item back exactly (Library sources); a destructive confirm otherwise; admin role changes confirm. - Library: the title is the row's button, labels are tied to their fields, errors are inline, the duplicate filters and stat tiles are gone, and the merge confirm is a dialog. History keeps its tab in the URL, and lists scroll with the page on phones. - Pending states for sign-out, delete-all, debate switch and delete, file import and announcement dismiss. The announcement renders from cache. - 404, legal pages, Sources, Login and the route error screen all have a way home. Shared items render as a readable view, and Import is gone. - Shared PageHeader and tool links, a text-xs floor, tinted tier badges, localized login errors, Escape continues past the inactivity gate, and the limit modal gets "Not now". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Tools rename, the Current debate link and the Library form changed what the recorded agent steps click. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rms on touch tailwindcss-animate's animate-in sets a 150ms default in the variant layer, which outranks a plain duration-* class. Measured after the change: mobile menu 180ms in and 120ms out; tooltip 120ms out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel was placed 4rem under the top, so the Current Debate row covered its first item. AppLayout now publishes the header's bottom edge as --app-header-bottom and the panel opens there (measured: header 118px, menu 118px on an iPhone 13). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y errors - navigation-performance waits for the Tools page h1. - The onboarding schedule check instruments the new target-first start. - Hungarian parity checks the inline required-field error, and the toast close label through a flowchart node delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nfirms - Library Undo re-inserts the same row (id and created_at), so a per-request source exclusion still applies and the source keeps its place. The library recipe now checks the restored row against the original. - The mobile menu closes when the window widens past lg, where it is hidden but would still hold the page modal. - Phone bottom sheets move focus inside on open, like the side sheet. - A refused announcement dismiss restores the session cache as well as the banner. - Folder merge and admin role changes keep their confirmation open while the write is pending and close only on success; a failed merge says so in the dialog. - Read-only results (a shared case) show no regenerate buttons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eader
Fixes the AI tools rows of the 2026-10-09 design audit (Ask and the four
form tools; the practice tools follow in the next commit).
- Ask: the stored reply keeps the streaming bubble's id, so it doesn't
remount mid-read. New text scrolls only a reader at the bottom, inside
the chat, never the window; otherwise "Jump to latest" appears. The box
stays editable while answering, Send becomes Stop (which keeps the
partial), and failures stay above the box with a Retry that doesn't
duplicate the question. The four switches and the model picker move into
an Options popover. The status is one true line ("Searching the web…",
"Working…") plus elapsed time, and the height uses dvh.
- Attack, Brainstorm, Factoids, Generate: requests take an AbortSignal and
show Cancel. One spinner and one status line replace five loops and a
fake progress bar. Errors are an inline panel with Retry. The success
toasts are gone, results scroll into view on phones, and the empty
states use the Lucide EmptyState.
- One ResultHeader: title, meta, actions, and the AI caveat. Generate marks
evidence "Unverified" when no web research backs it. Researched sources
sit in a disclosure under the header.
- "Discuss" prompts are built line by line through i18n and sent from Ask
on the streaming path. Markdown gets an inline mode and safe links.
- Deleted: StreamingIndicator, AnimatedSection, StaggeredContainer,
AutoSavedSourcesUndo and the unused showUndo prop, the stagger and
message keyframes, the typing dots, the streaming glow and token fade.
The caret blinks by opacity only. Error copy is localized, the form
cards drop their duplicate titles, and the no-debate notice appears once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes the Timer, Crossfire, Sparring and Flowchart rows of the 2026-10-09 design audit. - One RoundClock for Timer, Sparring and Crossfire: Inter tabular figures, amber in the last 30 seconds, red at zero (the Timer no longer goes calm at 0:00). A ClockAnnouncer speaks only at 1:00, 0:30 and 0:00 instead of every tick. - Timer: the ring sweeps linearly; the clock works in milliseconds, so a pause no longer gives up to a second back (unit test); a wake lock while running; sound and vibration together at 0:00; R and Escape reset only while paused, and the reset button offers Undo; keyboard hints are hidden on touch; solid card; no pulsing digits. - Crossfire: the clock ticks inside its own component instead of re-rendering the page twice a second; the header shows the resolution; the composer stays editable while the AI works (only Send waits); only turns that just arrived fade in. - Sparring: one spinner instead of a ping, a pulse and bouncing dots; the opponent's latest speech is pinned above the composer. - Flowchart: static edges, with rebuttals dashed; deleting a node or a saved flowchart acts at once with Undo; auto layout uses fitView with a 250ms glide; wheel scrolls the page; new nodes appear at the visible centre; touch-sized handles and controls; a real h1. - One ListeningIndicator for Ask, Generate and voice rounds, with no pulsing buttons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- sparring.spec reads the opponent's reply from the transcript and checks it is pinned above the composer. - The flow-edit recipe proves a node deletes at once and Undo restores it; the feature map says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inned copy Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
React Flow's stylesheet loads after ours and sizes the buttons content-box, so the coarse-pointer rule needs the extra class and border-box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude Opus 5 requests failed with "No endpoints found that can handle the requested parameters". The catalog marked Opus 5 as accepting temperature, but none of its 11 OpenRouter endpoints do, and require_parameters: true drops every endpoint that lacks a sent parameter. Temperature is now gone from every request: the catalog flag, the ai and ai-stream payloads, the research sub-calls, the JSON repair retry, and the client's saved feature settings. Saved settings that still carry a temperature get rewritten once through the existing canonical check. Older clients that still send temperature are ignored by the server. The routing test now fails if any catalog model's request carries temperature. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add Claude Haiku 5.5 (Basic), Claude Opus 5.5 and Claude Sonnet 5.5 (Pro) to the catalog and retire Claude Sonnet 5 and Claude Opus 5. Haiku 5.5 is the Basic default and Opus 5.5 the Pro default. Auto Fast now prefers and falls back to Haiku; Auto Pro prefers and falls back to Opus. Older clients that still send a retired ID resolve to Opus 5.5 on the server and in the settings store instead of getting a 400. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A form tool's request belongs to the tool, not one mount of its page, so Cancel still works after leaving and coming back (unit test). Every page checks the signal after the request returns, so a canceled run never publishes or saves. - Timer Undo returns to the paused remainder and stops the clock, instead of writing a paused clock under a running timer, which froze it. - Flowchart node Undo belongs to the chart it was deleted from: loading another chart dismisses it. A saved-chart delete writes first and throws on failure, so Undo is only offered once the row is gone. - Ask renders stored and streaming messages as one keyed list, so the finished reply keeps its bubble instead of remounting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dropping temperature makes every saved feature_configs non-canonical, so every existing user now takes the one-time rewrite path. That write sent the whole snapshot read at hydration, so a model choice saved in the meantime could be reverted on the server. The rewrite now applies only while updated_at still matches the read, and only if the user has not changed settings locally since hydration. A skipped cleanup retries on the next hydration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ranked report of 188 independently verified findings, grouped into 17 fix workstreams, plus per-area appendices with evidence and fixes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sr1aJw5ciMutxBnMzfiyS1
GPT-5.6 Luna becomes GPT-6 Luna, GPT-5.6 Sol becomes GPT-6.1 Sol, and DeepSeek V4 Flash becomes DeepSeek V4.1 Flash. GPT-6 has no Terra, so GPT-5.6 Terra retires into GPT-6.1 Sol. The catalog is back to ten models. Retired IDs resolve in the settings store and at both Edge Function boundaries. GPT-5.6 Luna, the old Basic default, moves to the new Basic default, Claude Haiku 5.5. A retired Basic ID never resolves to a Pro model. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Live verify rewrites every upstream call to the Muse Spark pin, so the provider call's model is the pin, not Opus 5.5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ell header is the banner Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Add a bottom tab bar on phone widths Phones below 768px navigate with Tools, Current debate, Library, and Settings. The header menu stays from 768px until the desktop nav, so iPad portrait still includes History. Co-authored-by: Gáborjáni-Szabó Ádám <Programcode@users.noreply.github.com> * Keep phone toasts, the keyboard, and Ask clear of the tab bar The toast offset now includes the bar up to 767px. The keyboard listener runs only below 768px, ignores pinch-zoom, and Ask sizes itself from the chrome above the page so a banner cannot push the composer under the bar. Co-authored-by: Gáborjáni-Szabó Ádám <Programcode@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Gáborjáni-Szabó Ádám <Programcode@users.noreply.github.com>
…ack.org links (#247) - /debatelab-pricing, -vs-chatgpt, -vs-debateclub and -vs-windebate are now /debateowl-*. One vercel.json rule 301s each old path, also under /hu/ or /es/ and with a trailing slash, to the new page in one hop; Vercel keeps the query. - Generator config, answers, guides, footer, landing guide hub, locales, llms.txt, humans.txt and the seo watch list use the new slugs; pages regenerated, CONTENT_DATE moved to 2026-10-27 because every guide links the new pricing page. - gsc_submit.py targets debateowl.com (URL-prefix or domain property) and inspects the live pages instead of the retired brand slugs. - Tests cover the new redirect with the path-to-regexp form Vercel compiles.
…arison tables (#249) * SEO/AEO: one DebateOwl entity, icons on every page, speech-times and comparison tables - Organization JSON-LD is DebateOwl (logo 512, sameAs, Pi-Stack as parentOrganization); meta author DebateOwl - WebSite/SoftwareApplication alternateName "Debate Owl"; WebSite inLanguage en/hu/es - Guide pages get favicon/192/apple-touch icon links, meta author, byline and a DebateOwl home link - /online-debate-timer: speech-times table generated from src/lib/free-tools/formats.ts - Tables on /debateowl-vs-chatgpt, vs-windebate, vs-debateclub and the case generator - Case generator and coach answers open with DebateOwl; definitions + DefinedTerm, new FAQs - 'Formerly DebateLab' in the footer and llms.txt; Bingbot in robots AI group - check-site enforces the entity and icon links; tests pin the timer table to the formats * Add Bing Webmaster Tools msvalidate.01 meta tag to the shared head and guide pages
On a phone the first screen now holds Ollie, the H1, one line, the Start trial button and three checked chips. The hero copy is the first sentence of the old subheadline; the announcement, second button and plan boxes are gone, and the product preview shows from lg up. What's new, Active Grounding and Use cases are removed: they repeated the feature list. Features are icon tiles, How it works and Pricing carry one short line per item, the short answer folds to three lines on phones, and the guide links become chip rows that scroll sideways on phones. Every link, anchor, heading level and JSON-LD source string stays. Unused keys leave all three catalogs; hu and es get the same shorter copy. At 390 px the English page goes from about 15,250 px to 5,120 px. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Titles follow "Page name | DebateOwl" on every indexable page in English, Hungarian and Spanish, and the home page is "DebateOwl: AI debate prep and practice". Each meta description is one sentence saying what the page does; the free tool pages lead with "Free" and no longer call DebateOwl a paid app. og: and twitter: tags carry the same strings, and the static guides gain the twitter title and description they lacked. The guides' heads now live only in PAGES in generate_seo_content.py. The logo and name link to the home page in the page's own language and are labelled "DebateOwl home". Terms, privacy and sources get a BreadcrumbList like the guides and tool pages already have. The favicon gets a simplified small-size owl (flat colours, bigger eyes, no tile) for the 16, 32 and 48 px frames; its source is src/assets/owl/owl-favicon.svg. Every landing trial button says "Start free trial" (hu "Ingyenes próba indítása", es "Comenzar prueba gratis"), matching the pricing card. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Brings feat/native-ios up to date with main (222 commits, through #251). Billing: main's resolveBillingState stays the one place that decides a plan, and it now also takes App Store rows (Pro ranks with Stripe Pro, Basic after legacy free and the payment grace). The server, the website and the app read the same user_settings, subscriptions and app_store_subscriptions rows, so effective_entitlement() is no longer called. Its App Store rules are pinned in billing-state.test.ts. Web files keep main's behaviour: client.ts, streaming.ts, the sparring store and page, and the settings store take main's versions, with the branch's account-switch guard kept in hydration. Tool defaults and the feature-config normalizer now live once in packages/core, and the app drops temperature as the website did. The lockfile is main's with the mobile workspace's resolved versions laid over it, so the Expo SDK 57 set is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The web preview swaps supabase.ts for supabase.web.ts, which had no billingQuery, so the You tab's plan never loaded there. The helper now lives in its own module on top of whichever client the platform gets. The screenshot script also shoots an 11-inch iPad Air (820 and 1180 points wide) and takes SHOTS_DIR to write a set elsewhere. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use core transforms, source retention, URL matching and SSE framing in both clients. Preserve web behavior and keep platform side effects in each app. Align mobile research autosave, Crossfire quota keys and Sparring clocks with the web. Co-Authored-By: Codex <noreply@openai.com>
The app takes the website's DebateOwl look: its colour tokens (plume blue, ink neutrals, gold, mint, coral) in light and dark, Fredoka for titles and button labels and Nunito for text, the tactile buttons that sink onto their ledge, 2px card and field edges, and Ollie in the places the website shows him: the app icon, splash and sign-in mark, empty states, tool progress, the Ask coach and the Sparring opponent. The owl PNGs are rendered from the website's SVGs by scripts/render-owls.ts. The app is named DebateOwl (slug debateowl) and links to debateowl.com. The bundle id stays com.adam.debatelab and the URL scheme debatelab. Labels follow main: the 40 strings main removed now point at the website's current keys (the one progress line per tool, the empty-state descriptions as form subtitles, counts with plurals), or live under mobile.* in all three languages where the website no longer has them. The You tab's plan card shows main's billing states, dates and wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The last colours from the old sky and slate palette move to the website's owl remap of the same family and step (src/index.css), and the timer ring keeps to plume blue, as the website has no gradients. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main (#201) charges Crossfire per round: the website sends the round's id beside every turn and the debrief, and the server's quota ledger charges the first. The app now sends the same id, so a student's round costs the same quota on the phone as on the website. Sparring already was, through its sessionId. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…app's guide Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The owl beside a progress line is decoration; only a labelled owl loader is a progress indicator itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The website's per-feature AI files now take their parsers from packages/core: the Generate, Brainstorm and Factoids transforms, source and assessment parsing, research retention and the autosave row, SSE framing, source URL matching, the Sparring round moves and the quota session key. The app follows main with them: research autosave runs one batch at a time and refreshes a page the debate already has, a Sparring turn's clock starts when the student starts, and Crossfire sends its round id through the shared key check. Both branches had added the Crossfire quota session; the merged request keeps one, which leaves signals out by operation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main fixed this on the website in #187: a reply cut off at its cap can send a newline before failing, and the page then kept an empty answer instead of asking the structured endpoint, which retries with a larger cap. The app had the same check and now follows main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the App Store rows cannot be read and the rest prove no access, Settings showed a definite Expired with nothing left today, which is wrong for an App Store subscriber and was cached without a retry. The query now fails, so the plan stays unknown and retries, as the AI functions refuse to decide in the same case. A missing App Store table still counts as no App Store rows. (Codex review r1, finding 1.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(Codex review r1, finding 2.) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
Button labels wrap to a second centred line instead of being cut off, and on the case screen "Attack this case" gets the wider button. The pinned bar now sits on a strip of the page colour with the page fading out above it, so text no longer shows between or behind the buttons, and the page and notices clear the bar's measured height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The You tab's badges take the website's outline badges: the state's colour at 15% behind, 30% as the edge and its darker text. Pro is gold, as on the website; mint is for extended access and legacy free, with a check mark. The website's Basic badge uses the trial blue instead of an unmapped teal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Like the website's Library, the list fills the width (in an 880pt column) with nothing open; opening a source splits the screen, with the list keeping 40% of it. Source titles wrap to two lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On iPad every option chip shows, wrapping as needed. On iPhone the row still scrolls sideways and now fades at its edge, as do the citation chips under an answer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Picker values, collapsed document items, recent work and source rows and flowchart edge labels take two lines instead of one. Switches use the brand fill with a white thumb, as on the website. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each shot lists the texts React Native Web draws cut off (an ellipsis or a line clamp that overflows) and the run writes them to clipped.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The citation chips under an Ask answer faded into the page colour over Ask's card colour, which drew a dark block in dark mode, and the fade showed even when every chip fit. The row now measures itself and fades only while it continues off screen, into the colour it sits on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
React Native Web draws a switched-on thumb in its own teal; iOS already takes the white thumbColor. A Library row's date line wraps instead of being cut off beside an open source on iPad. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings the iOS app up to date with main and restyles it as DebateOwl. Base is
feat/native-ios. Don't merge yet. The open questions for Adam are at the end.Catching up with main
origin/main(222 commits, through #251) is merged into the branch with a normal merge (baec2758). These 22 files conflicted._shared/entitlements.tsand its test,use-subscription.ts,settings-store.ts,SettingsPage.tsx). Main'sresolveBillingStatestays the one place that decides a plan. Main added payment grace, extended access andsubscription_ended; the branch'seffective_entitlement()SQL function predates them. Rather than let the SQL win,resolveBillingStatenow also takes App Store rows. App Store Pro ranks with Stripe Pro, and the later end shows. App Store Basic (20 a day) comes after legacy free and the payment grace, before a trial. Revoked, upgraded and expired rows grant nothing, and Apple's billing grace extends a row. The AI functions, the website and the app all readuser_settings,subscriptionsandapp_store_subscriptionsand resolve them the same way. A database without the App Store table answers PGRST205, which counts as no App Store rows, so web and functions keep working before that migration ships. I ported the pgTAP scenarios for the App Store rules tobilling-state.test.ts.client.ts,streaming.ts,sparring-store.ts,SparringPage.tsxtake main's versions, since main split the AI client into per-feature files. The branch's extractions come back on top in later commits (see "Moved to core").ai/index.tskeeps main's re-indented block plus the branch'ssparring_scoredpush.notifyScoredbecame optional so main's new judge tests run unchanged./rpc/effective_entitlementnow mock the table reads like main's; thetesting/entitlement.tshelper is gone.package.jsontest:edgetakes main's flags plus the branch's App Store and Expo env names.package-lock.jsonis main's lockfile with the mobile workspace's resolved versions laid over it, so the Expo SDK 57 set is unchanged. I restored two packages the Expo CLI got from Tailwind 3's hoisted tree (arg,micromatch).architecture.md,operations.md,supabase/README.md) keep main's text plus the branch's install-command, App Store and push sections, reworded for the TypeScript plan resolver.Other fixes the merge needed:
mobile.*in en/es/hu where the website no longer has them.temperatureis gone from the app's tool settings, as on the website.supabase.web.tslacked the new helper.3ee7cf9efixes it.Moved to core
packages/core/src/supabase/billing.tsis the plan reader web and app share. It sits oncontract/billing-state.ts, a re-export of the Deno resolver in the existingcontract/pattern.ai/feature-configs.tsholds the tool defaults, model normalisation and the canonical check, taken from the settings store.f79ace8a. They are the Generate, Brainstorm and Factoids transforms, discovered-source and assessment parsing, retention and the autosave row, SSE framing,source-url.ts(URL matching), Sparring round moves and timers, and the quota session key. The web imports them with no behaviour change. Tests moved with the code (packages/core/src/**/*.test.tsnow runs in vitest).Case structure v2 is not in this PR. #244 is still a draft, conflicts with main and has failing CI, so there is no v2 on main to move into core or render. Its schema and
case-view.tsalready live inpackages/core, so the app can pick them up once #244 lands. The case screenshots show the current (v1) format.App catch-up with main
SubscriptionStatus.tsx). Usage is the server's counter (ai_usage_today).quotaSession, so the server charges a round once (Charge Crossfire and Sparring per round, refund runs that produce nothing (batch T5) #201). A test covers it. Sparring already was, through itssessionId.DebateOwl restyle
debateowl, links to https://debateowl.com.@expo-google-fonts).icon-1024.png), the splash (pointing), the sign-in mark, empty states (reading, surprised, sleepy, point), tool progress, the Ask coach avatar and the Sparring opponent. The PNGs come from the website's SVGs viascripts/render-owls.ts.Review polish (second round)
From the review of this PR:
The full screenshot pass found and fixed more of the same kind: picker values, collapsed document items, recent work, source rows and flowchart edge labels that Hungarian or Spanish cut off now take two lines, and switches use the brand fill with a white thumb.
Tests
All results are local runs on Adam's VPS (Node 22.23.2), not CI.
npm run verifyat the final head1ef3b2e3passed. That covers docs, lint (eslint, knip, repo rules), typecheck (web, agentic, core and the app), vitest (121 files, 790 tests, includingapps/mobileandpackages/core), collaboration (30), Deno edge tests (543), build and site checks, the service worker check, and the Playwright desktop smoke set (47). An earliernpm ciplusverifyat6fb2664ealso passed../.superset/db-gate.sh --db-only) on the merged migration order passed 33 pgTAP files and 655 tests, includingapp_store_entitlements_test.sqlandpush_tokens_test.sql, plus the quota, Opus-default, admin-drift and workspace concurrency scripts.6fb2664eaddeduse-subscriptiontests (11 pass), and the Crossfire quota test fails when the round id is dropped.npm run -w @debatelab/mobile typecheckandexport:webpass, and the screenshot script exits 0 at every size (it fails on any page error or unexpected console error).6fb2664eraised two findings, both fixed. A failed App Store read on the website now leaves the plan unknown instead of "Expired" (3bb421db, with tests), and the owl loader stays still under Reduce Motion (a9f5a0ad). Round 2 ata9f5a0adraised one finding, which I dismissed. When the plan query fails, Settings falls back to an "Expired" card. Main already does this for every failed read, such as a failed settings read. The harm the indeterminate-read rule records (fix: finish UI cleanup and OpenRouter model catalog #47), a persisted downgrade of the model choice, can't happen: the settings store decides Pro throughreadProModelAccess, which returns unknown for a partial read. Showing an "unknown" plan in Settings needs a new card state and strings, so it's listed under gaps as a follow-up.verify-debatelab --live) and anything on a real iOS device or simulator.Screenshots
These come from the web export through
apps/mobile/scripts/screenshots.ts(staging, the seeded Pro account, nothing written), at 390, 820 and 1180 points.~/.t3/scratch/ios-reskin-shots/before/, light, English.~/.t3/scratch/ios-reskin-shots/after/, light and dark, English, Hungarian and Spanish. 648 shots from1ef3b2e3, all checked by eye.clipped.jsonthere lists every text a shot cuts off; only two remain, both by design: the motion as Ask's one-line header subtitle on iPhone, and the opponent's speech in Sparring, collapsed to four lines until tapped.The script gained an 11-inch iPad Air size (820×1180 and 1180×820), Spanish,
SHOTS_DIR, current sentence-case labels, a filter for the expected 404 from a project without the App Store table, and the clipped-text report: each shot lists the texts React Native Web draws with an overflowing ellipsis or line clamp.Known gaps and flags
com.adam.debatelab, and the URL scheme is stilldebatelab. A new id means a new App Store Connect app, so that's Adam's call.debateowl. Oneas initday this decides the Expo project name (@adamgaborjani/debateowl).20261014*migrations are older than main's 2026-10-16 to 2026-10-24 ones, so a project that already has main's needssupabase db push --include-all. The database gate passes on the merged order.effective_entitlement()is defined but no longer called. A follow-up migration can drop it.hasAppStoreSubscriptionis plumbed for when it is.useSubscriptionfalls back to an expired snapshot, so Settings says "Expired" instead of "couldn't load". This predates the branch and covers every failed read; a follow-up can add an unknown state to the Settings card.eas init), which is a build-day step, so it wasn't used.npx expo installis blocked by the repo'sallowScriptspolicy, so the two font packages were installed from the root withnpm install -w.Open questions for Adam
com.adam.debatelabfor the store, or move to a DebateOwl bundle id before the first TestFlight build?eas initrun (it creates@adamgaborjani/debateowl)? It also unlocks EAS Simulator for a native check of this restyle.🤖 Generated with Claude Code