Repository navigation
iOS parity round 1: prepare tools match the web - #254
Conversation
… core The website's live generation reader, its ai_run_results recovery and the live draft sections move to packages/core so the iOS app streams tools the same way. The website keeps its modules as thin adapters with the same exports, so its tests run unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The four tools ask the ai function to stream, as the website does, and show the answer as it is written: the phase line and elapsed time first, then the result's sections filling in with a caret. A stream that drops before its answer reads it back from ai_run_results under the request's own id. A refusal inside the stream keeps its limit details for the limit sheets. The screenshot script streams part of each answer from inside the page for new "-live" shots, and matches the sentence-case Brainstorm and Factoids buttons. 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
|
The case and attack documents gain the website's "Open in Crossfire", which fills the next Crossfire form with the case, or with the attacked case and its cross-examination questions, and says where it came from. A case can be built into an unsaved Flowchart map in its own debate. flowchartFromCase moves to packages/core so the website and the app build the same map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each tool's header says how many AI uses are left today, read again after every request. Crossfire and Sparring say what a round costs before it starts and check it first, as the website does. A limit or model refusal opens the website's dialog as a sheet with its words: a paid plan's daily cap and the weekly allowance say when access returns, other limits lead to the plan in You (purchases wait for in-app purchase), and a model refusal can switch the tool to low reasoning. The screenshot script shoots both sheets and the cost notes, answers the quota check in its Crossfire and Sparring fakes, and sends a debrief that fits the current schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A case's menu can regenerate one part (the opening, the arguments, the case structure, the predicted opposition or the counters) from a new generation, as the website's section cards do, with the website's merge now shared through packages/core. Undo goes back to the version before, and writes it back to the saved row so History matches the screen. Save opens a sheet with the website's title prompt, and a saved case is confirmed in mint with a check mark. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ask gains the website's Stop, which keeps the answer so far marked as stopped, and its General and Clarify modes. Answers the stream cannot serve now stream live from the ai function, as on the website. Each answer can be saved to the Current Debate's Ask folder in the Library. Up to five text or code files can be attached with expo-document-picker (in Expo Go); they are read on the phone and sent with the question in the website's format, now shared through packages/core. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every tool form, Crossfire, Sparring and Ask now show the website's line: "Using 3 sources and 2 saved results", with the results named. Review opens a sheet that turns sources and saved results off for the next request only (for the whole round in Crossfire), and pins up to three results for every request in the debate, in debate_context_pins as on the website. The line, the sheet and the request read one plan: the website's planner, moved to packages/core. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gth from the site config Hermes has no Intl.ListFormat, so the debate context line fell back to a comma; the formatjs polyfill joins it as the website does in all three languages. The limit sheet's trial length now comes from the website's site config instead of a copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The case menu now starts with Regenerate, and a wide iPad's outline rail is a menu too, so the script finds the action menu and its items by their labels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s fake Crossfire, opened from a case or an attack, asks what a round costs; the results fake aborted that call, which the browser logged as an error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shared live reader rejected with a plain Error named AbortError, which callSupabaseAI did not recognise as its own deadline, so a stalled stream on the website became an unexpected error reported to Sentry. The reader now throws a DOMException where one exists, and both clients tell an abort by its name, since a DOMException is not always an Error. A test covers the website's timeout on a live stream that goes quiet. The app's usage line no longer reloads after a round's cost check, which spends nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- "Use low reasoning instead" also moves the tool off a Pro-only model, so the retry is not refused again. - The debate context reads a list of titles and dates on each form, and the text only of what a request sends, kept for the session. A list read that ends after a newer one is dropped, and one that started before a pin change keeps the newer pins. - Crossfire and Sparring show Start as busy while the round's cost is checked, and ignore a second tap. - The case document confirms a save outside its state update. - A regenerated case keeps its new sources even if the student leaves, and a failure there no longer reads as a failed regeneration. - Opening a case or an attack in Crossfire while a round runs says why it was not brought in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The text the context plan keeps for the session never expired, so after a Regenerate or an Undo the plan judged the old case, a chat kept its old messages, and edits from the website went unseen. Kept text now carries the version the list read reports for its row: a case's generatedAt, which Regenerate and Undo change; a chat's message count; a Sparring round's updated_at. Attacks, brainstorms, factoids and Crossfire rounds are never edited. No source column says when it changed, so source text is read again after each list read. updateResult and saveChat also forget what they wrote. A row deleted between the list read and the text read is left out of the plan instead of failing the request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Round 1 of the iOS/iPadOS parity plan (
~/.t3/scratch/ios-parity/PARITY.md, section 3). The app's prepare tools now work the way the website's do, in Expo Go, with no backend change. Where the website already had the logic, it moved topackages/core, and both clients use it from there.Items
1. Live streaming for Generate, Attack, Brainstorm and Factoids: done.
stream: truewith aresultKey. The screen shows the phase (researching, writing, checking), the elapsed time from 5 s, and then the result's sections filling in with a caret.ai_run_results, as the website does.src/topackages/core/src/ai/{live,run-recovery,live-sections}.ts. The website's modules are now thin adapters with the same exports, and its tests run unchanged.ai-request.test.tscovers a streamed answer, a refusal inside the stream, a dropped stream recovered fromai_run_results, and a dropped stream with no stored answer.anthropic/claude-sonnet-5.5. Adam approved resetting the seeded account's weekly allowance for them.text/event-stream). The screen showed researching, writing, writing live and checking, the elapsed time, and the first section after 12 s; the case finished at 44 s.resultevent. The app readai_run_resultsand opened the finished case at 43 s.weekly_budget_reached, and the app opened the weekly-allowance sheet with only OK, as the website does.typesafe/jev-1.13through OpenRouter to rank sources and check which ones the case used.2. Generate: Regenerate one part, Undo, Save with a title: done, with one deliberate difference.
mergeRegeneratedSection, now in core and used byGeneratePage).3. Open in Crossfire and Build flowchart from case: done.
flowchartFromCasemoved to core, and the website uses it from there.4. Debate context control: done, with two gaps.
debate_context_pins.planDebateContext, which moved topackages/core/src/debate/context-plan.ts.5. Daily-use line, round cost and limit sheets: done, with the purchase step changed.
6. Ask: Stop, General/Clarify, Save to Library, text attachments: done.
ai-streamrefuses, stream live through theaifunction, as on the website.Askfolder.expo-document-picker, which Expo Go includes (npx expo configis unchanged). The phone reads them and sends them in the website's format, now shared from core.mobile.ask.*strings in en, hu and es.Not in this round: case structure v2 (waits for #244), Library folders and import, debate edit or delete, haptics and context menus (round 2).
Also changed
@formatjs/intl-listformat, because Hermes has noIntl.ListFormatand the context line joins its parts with it.case-edits,contextandlimitsgroups, the new Ask shots, and quota answers in its fakes. It also fixes two stale fakes: the sentence-case Brainstorm and Factoids buttons, and a Crossfire debrief that no longer fit its schema.Review fixes (Cody)
mobile.crossfire.prefillHeldin en, hu and es).output.metadata.generatedAt(Regenerate and Undo change it), a chat's message count, a Sparring round'supdated_at. Attacks, brainstorms, factoids and Crossfire rounds are never edited. Onlysparring_sessionshas anupdated_at, and adding one elsewhere would need a migration, so source text is read again after each list read instead.updateResultandsaveChatalso forget what they wrote. A row deleted between the list read and the text read is left out of the plan instead of failing the request.context-plan.test.tscovers a regenerated case, a chat with a new message, an unchanged row that is not read again, and a deleted row.packages/core.src/config/site.jsonis the website's one source for pricing facts (its i18n, prerender and pages read it), and the app reads it the same way.Verification
I ran
npm run verifylocally at 112ad07, with both rounds of review fixes. GitHub Actions is billing-blocked, so this is a local pass, not CI.Screenshots are in
~/.t3/scratch/ios-parity/r1-shots/: 761 shots for iPhone, iPad Air portrait and landscape, light and dark, English and Hungarian, plus iPhone light Spanish. Every AI answer in them is a fixed fake, and the runs save nothing. Contact sheets per screen are inr1-shots/contact/. After the review fixes I retook the limit, Crossfire and Sparring screens on iPhone in English and Hungarian (r1-shots/review-fixes/); they are unchanged apart from the fixes. The 40 shots inclipped.jsonall show text that was already shortened by design before this round: Ask's one-line motion under its title and the motion on Sparring's your-turn screen.🤖 Generated with Claude Code