Skip to content

Polish the prep modes (T8: MD-04, MD-06–12, MD-14, VS-04, AX-05, AX-06) - #211

Merged
Programcode merged 5 commits into
mainfrom
fix/t8-modes-polish
Oct 23, 2026
Merged

Programcode merged 5 commits into
mainfrom
fix/t8-modes-polish

Conversation

@Programcode

@Programcode Programcode commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Note

MD-10 is not in this PR any more. Commit 91a6a5c reverts e8fb46d (a normal revert commit; the tree matches 9f6c75b). MD-10 is Adam's design call, so it moves to follow-up draft PR #212 for him to decide on. The MD-10 notes below describe that follow-up, not this merge.

Ship gate re-run on 91a6a5c (main b0b2ae7), 23 Oct 2026 ~05:05 CEST: full npm run verify exit 0 (79 unit files, 30 collaboration, 457 edge, check-site 48 pages, test:sw, 43/43 e2e smoke). Recipes, desktop-chromium + mobile-chromium: practice 5+5, ai-tools (incl. Ask) 7+7, voice-rounds (spoken Sparring and Crossfire) 2+2, current-debate 3+3, case-generation 9+9, model-defaults 3+3, workspace-autosave (--collab) 2+2. axe 4.14 on /app/generate, /app/ask, /app/crossfire, /app/sparring: color-contrast only (1 node desktop, 0 at mobile), one <main>.

Then synced with main 5ea2275 (#210; only the locale files overlap, merged cleanly) as 4533132. Full npm run verify exit 0 again (80 unit files, 30 collaboration, 457 edge, check-site 48, 43/43 e2e).

Fixes the Low and Nit issues in the prep modes from the 22 Oct QA report (batch T8). Built on T5 (#201), T7 (#203), T2 (#202), #204, T9 (#206) and T4 (#207). Charging, refunds, quota pre-checks and the "This session uses 1 AI use" copy are unchanged.

Three commits. MD-10 is the last one on purpose: it is a design choice for Adam and reverts alone (git revert e8fb46d0; git show e8fb46d0 | git apply -R --check passes). VS-04 is its own commit too.

No migrations. No Edge Function changes, so nothing to deploy.

Issues

MD-06, Start debate's "Any role" turned into R1 in Generate. Generate now offers "Any role" (general, which the schema and the ai function already accept), and takes the debate's role when it fills in the debate's motion. Driving the real app found a bug in that path. Radix's hidden native select reported '' when the role was set on first render. That wiped the role, and Generate then silently refused to submit inside any debate. OptionSelect now ignores empty values. Test: src/test/generate/generate-form-role.test.tsx, which fails without the fix.

MD-07, "Using 7 sources" next to "7 items left out".

  • The context line now reads, for example, "Using 10 of 12 sources (2 didn't fit)". It counts only what reaches the model and uses i18next _one/_other keys in EN, ES and HU. Test in debate-context.test.tsx.
  • Generate, Brainstorm and Factoids show "Saved to History" once the result is there: recorded into the debate automatically, saved by hand, or reopened from History.

MD-08, the PDF repeated "Framework". The case PDF has one "Case Structure" heading, with Thesis, Framework and Burden of Proof labels under it. DOCX and the clipboard text are unchanged.

MD-09, motion cap. The QA build already had maxLength; the counter and the shared constant were missing.

  • MAX_MOTION_LENGTH (1,200) now lives in packages/core/src/validation/motion.ts. The debate store, the Sparring schema, Start debate, Sparring setup and Generate's motion field all use it.
  • Start debate shows a locale-formatted counter, like Sparring's.

MD-14, no feedback for 4–5 s on Start debate. The button is disabled and shows a spinner with "Creating…" (EN, ES, HU). That covers the header dialog, the inactive-debate gate and the motion dialog. A ref guard keeps one click to one create.

MD-11, Brainstorm and Factoids had no Copy or Save. Both now have Clipboard (a plain-text version of what the view shows) and Save to History, built from the same components as Generate. Export was already there.

MD-12, Sparring's clock started at once, and the word count had no label.

  • Each user turn opens with a stopped clock and a ready step. In typed rounds the button is "Start speaking"; the microphone or the first keystroke also start the turn.
  • Reset turn returns to the ready step and stops a listening microphone. Starting a turn ends the opponent's audio.
  • The page no longer resumes the clock when the opponent's audio ends, because the turn now waits for the student.
  • Word counts read "1,967 words so far" and "123 words", with locale number formatting and plurals.
  • T5's quota pre-check is untouched. Tests: src/test/sparring/sparring-round.test.tsx, plus the reworked voice-round tests.

MD-04, Attack kept the old critique after a blocked retry. When a rerun for changed text fails or is refused, the critique on screen gets the label "Critique of your previous argument". The label is tied to that exact critique. It goes away after a successful run, or after a later run on the critiqued text again.

VS-04, "No current debate" flashed on /app. I could not reproduce the flash on the local stack, on main or on this branch. A reload samples the persisted debate at once on both builds. So this is a safeguard, not a reproduced fix:

  • Home shows a loading card (which keeps the tour target) until the debate list has loaded from the server.
  • A failed load sets loadFailed, which brings back the empty state and Start debate instead of an endless skeleton. Test in debate-gates.test.tsx.

MD-10 (design choice: Adam to confirm), the first Generate interrupted with "Start a debate with this motion?".

  • With no Current Debate, once the debate list has loaded, Generate creates the debate for its motion and shows the toast "Started a debate for this motion".
  • The strip says "Your first result starts one for its motion" and offers Use once. One-off mode with no debate gets a "Turn off one-off mode" button.
  • If the create fails, or the list hasn't loaded yet, the dialog opens as before. Brainstorm, Sparring and Crossfire keep the dialog.
  • e2e specs, recipes, skill docs and the production canary are updated. The canary works against both the old and the new frontend.
  • Before/after screenshots are local at .verify/artifacts/20261023T022629Z-t8-manual/desktop-chromium/…/main-en-generate-first-submit.png (the dialog) and .verify/artifacts/20261023T022422Z-t8-manual/desktop-chromium/…/branch-en-generate-first-submit.png (the toast, with the case filed in the new debate). The CLI can't attach images to a PR, so they are in the thread instead.

AX-05, Ask message box. Already fixed on main: the input has aria-label="Message to your debate coach". It was present in QA build d749051 (added in #184). The Ask tests now find it by role and name, so they fail if the name is lost.

AX-06, Sparring nested <main>. It is now <section aria-label="Current round">, and nothing styles main inside the round. Crossfire already has its <h1> ("Crossfire", then h2 "Set up your crossfire"). Neither Crossfire nor Sparring skips a heading level, before or after.

axe 4.14 on the local stack (violation nodes, main b0b2ae7 → this branch)

The first number in each pair is desktop, the second is 375 px.

  • /app/generate: 1 → 1 and 0 → 0
  • /app/ask: 1 → 1 and 0 → 0
  • /app/crossfire: 1 → 1 and 0 → 0
  • /app/sparring (setup): 1 → 1 and 0 → 0
  • Sparring round in progress: 18 → 15 and 17 → 14. The removed violations are landmark-no-duplicate-main, landmark-main-is-top-level and landmark-unique; <main> count 2 → 1.
  • Everything left is color-contrast. It is the same on both builds and belongs to T10.

Verification

Full npm run verify at the final head e8fb46d (local; GitHub Actions minutes are used up): exit 0.

  • docs:check passed.
  • lint (eslint, knip, repo rules) passed.
  • typecheck passed.
  • Unit tests: 79 files, 574 tests.
  • Collaboration: 30 tests.
  • Edge: 457 passed, 0 failed.
  • Build with prerender and sitemap; check-site found no problems in 48 HTML files.
  • test:sw passed.
  • e2e smoke: 40 passed, 3 flaky (passed on retry). The flaky ones are all signed-out /tools pages in e2e/free-tools.spec.ts that timed out on their first heading while another worktree's stack was running. This branch doesn't touch them, and they passed in the four earlier verify runs on this branch.

Recipes with verify-debatelab (fake provider), desktop-chromium and mobile-chromium, all passing:

  • current-debate: 3 + 3
  • case-generation: 8 + 8
  • practice: 5 + 5
  • workspace-autosave (--collab): 2 + 2
  • model-defaults: 3 + 3
  • ai-tools: 7 + 7
  • e2e/full-stack/first-run: 4, desktop only

The recipes ran on 1924ba4a, and ai-tools on e8fb46d. Between those two heads, only T9 and T4 from main and one GeneratePage conflict resolution changed.

Real app at desktop and 375 px, checked in screenshots:

  • In EN and HU: the Start debate counter and Creating… state, Generate's first run, and the Sparring ready step ("Beszéd indítása", "Eddig 0 szó").
  • In EN: the Brainstorm toolbar, with Save turning into "Saved to History".

I did not get a Factoids toolbar screenshot (my temporary script's selector missed the claim field), though ai-tools ran Factoids itself on both projects.

Review rounds

Each round was one fresh-context Claude Opus subagent reading the full diff.

Round 1: 2 Medium, 5 Low, 3 Nit. Both Mediums are fixed and tested:

  • Reset turn left an untimed, stopped clock.
  • MD-10 could create a debate before the list loaded, moving the server's current-debate pointer.

Of the Lows and Nits:

  • Fixed: the one-off exit; Saved after Undo; double saves from History; typing during the opponent's audio; the Attack label after a reload; Generate's maxLength.
  • Left as is: state-based double-click guards in the gate's switch choice and in Brainstorm/Factoids Save (React 18 flushes discrete events synchronously); the Hungarian "X forrásból Y" wording, which is grammatical but worth a native check.

Round 2: no Medium or higher. Fixed:

  • the tour target on the loading card;
  • Reset turn stops a listening microphone;
  • the autostart tests wait for the debate list;
  • the stale label clears when the text matches again;
  • Save marks the object that was actually saved;
  • the Undo/regenerate overwrite, which T9 (Fix Flowchart QA issues (T9: FC-01–06, PF-03) #206) fixed on main at the same time. I kept T9's version on rebase.

Left as is: a critique opened from History is labelled "previous argument" if a later edited run fails. The description line under it stays accurate.

Needs a manual check

  • MD-10 is a product decision.
  • Voice rounds with real ElevenLabs audio. The fake stack proves only the browser voice path.
  • The PDF export on a real device.
  • The Factoids toolbar.
  • VS-04 on a slow network or a fresh device, which local runs can't reproduce.

🤖 Generated with Claude Code

Programcode and others added 3 commits October 23, 2026 02:31
…5, AX-06)

- Start debate: motion counter on the shared 1,200 limit, and a
  Creating… spinner that keeps one click to one create.
- Generate: offers Any role and takes the debate's role with its motion.
- Context line: "Using 7 of 14 sources (7 didn't fit)" instead of a
  separate left-out line; results show Saved to History once saved.
- PDF export: one Case Structure heading, no repeated Framework label.
- Brainstorm and Factoids: Clipboard and Save to History.
- Sparring: each turn waits on a ready step before the clock runs,
  labelled and locale-formatted word counts, no nested main.
- Attack: a critique left over from a failed or refused rerun is
  labelled as the previous argument's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Home rendered "No current debate" while the debate list was still on
its way from the server, so a debate just created elsewhere seemed to
vanish for a few seconds. It now shows a loading card until the list
arrives. A failed load sets loadFailed, which brings back the empty
state and its Start debate button instead of loading forever.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… choice)

With no Current Debate, Generate creates a debate for its motion and
says so in a toast, instead of opening "Start a debate with this
motion?". The strip offers Use once beside Start debate, so a one-off
run is still a choice. A second submit while the debate is being
created does nothing, and a failed create falls back to the dialog.
Other tools keep the dialog.

Adam to confirm. This commit holds the whole change, including tests,
recipes, docs and the production canary, so it reverts alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 23, 2026 02:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Next included review available in 9 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 5ea2275 and 4533132.

📒 Files selected for processing: 38
  • .claude/skills/verify-debatelab/features/practice.md
  • .claude/skills/verify-debatelab/features/workspace-autosave.md
  • .claude/skills/verify-debatelab/recipes/workspace-autosave.spec.ts
  • docs/architecture.md
  • packages/core/src/ai/schemas/sparring.ts
  • packages/core/src/validation/motion.ts
  • src/components/features/brainstorm/BrainstormResults.tsx
  • src/components/features/debate/DebateContextControl.tsx
  • src/components/features/debate/DebateDialogs.tsx
  • src/components/features/debate/DebateForm.tsx
  • src/components/features/debate/DebateMotionGate.tsx
  • src/components/features/factoids/FactoidsResults.tsx
  • src/components/features/generate/GenerateForm.tsx
  • src/components/features/generate/GenerateResults.tsx
  • src/components/features/sparring/SparringRound.tsx
  • src/components/features/sparring/SparringSetup.tsx
  • src/components/features/tools/result-actions.tsx
  • src/components/features/tools/result-text.ts
  • src/lib/pdf-export-utils.ts
  • src/lib/stores/debate-store.ts
  • src/lib/stores/sparring-store.ts
  • src/locales/en.json
  • src/locales/es.json
  • src/locales/hu.json
  • src/pages/AttackPage.tsx
  • src/pages/BrainstormPage.tsx
  • src/pages/FactoidsPage.tsx
  • src/pages/GeneratePage.tsx
  • src/pages/HomePage.tsx
  • src/pages/SparringPage.tsx
  • src/test/debate/debate-context.test.tsx
  • src/test/debate/debate-gates.test.tsx
  • src/test/generate/generate-form-role.test.tsx
  • src/test/helpers/debate.ts
  • src/test/pages/AskAccountSwitch.test.tsx
  • src/test/pages/AskStreamFallback.test.tsx
  • src/test/pages/SparringVoice.test.tsx
  • src/test/sparring/sparring-round.test.tsx
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing.

Comment @coderabbitai help to get the list of available commands.

MD-10 (start a debate on the first Generate instead of asking) is a
design choice for Adam. It moves to its own follow-up PR so the rest of
T8 can ship. The tree now matches 9f6c75b.
@Programcode
Programcode merged commit 7407139 into main Oct 23, 2026
3 of 13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants