Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/verify-debatelab/bin/verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ cmd_up() {
wait_url "$mailer_url/api/v1/messages"
wait_url "$APP_ORIGIN"
wait_url "http://127.0.0.1:$FAKE_PORT/__requests"
for fn in workspace-invites ai ai-stream demo-code-login admin announcements; do
for fn in workspace-invites ai ai-stream demo-code-login admin announcements voice account; do
wait_url "$api_url/functions/v1/$fn" 300 --request OPTIONS --header "Origin: $APP_ORIGIN"
done
if [ "$collab" = true ]; then
Expand Down
59 changes: 59 additions & 0 deletions e2e/results-overflow.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { expect, test } from '@playwright/test';
import { seedCurrentDebate, setLocale, stubSupabaseSession } from './helpers/auth';

// Models quote raw URLs in evidence. On 2026-10-02 a live run quoted this
// 135-character URL and the Generate results column grew past the viewport:
// a 1fr grid track grows to the min-content width of an unbreakable word.
const longUrl = 'https://admin.farefreelondon.org/wp-content/uploads/2026/04/20240320_GCC_Free_Public_Transport_Study_Summary_Report_v2.0.pdf';
const motion = 'This House would make public transport free';

const contention = (index: number) => ({
id: String(index + 1),
claim: `Contention ${index + 1}: fares block the riders who need transit most`,
reasoning: 'Fares are a regressive barrier concentrated on low-income riders.',
evidence: `The 2026 policy brief (${longUrl}) found fares covered 8 percent of operating costs.`,
needsSource: false,
impact: 'More people reach work, school, and healthcare.',
});

test('a long URL in generated evidence does not widen the page', async ({ page }) => {
await setLocale(page, 'en');
await stubSupabaseSession(page);
await seedCurrentDebate(page, motion);
await page.route('**/functions/v1/ai', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
output: {
caseStructure: {
thesis: 'Free transit is a net public good.',
framework: 'Net societal benefit, weighed on access and cost.',
keyDefinitions: ['Public transport: publicly funded scheduled transit.'],
burdenOfProof: 'We must show the policy produces a net gain in practice.',
},
contentions: [0, 1, 2].map(contention),
predictedOpponentCase: {
likelyArguments: ['The lost farebox revenue has to come from somewhere.'],
strategicWeaknesses: ['Assumes fare revenue is the only funding model.'],
keyClashes: ['Who actually bears the cost.'],
},
counters: [{ targetArgument: 'Funding gap', counterpoint: 'Fare collection has overhead.', rebuttal: 'Net cost is small.' }],
metadata: { side: 'pro', format: 'custom', generatedAt: new Date().toISOString() },
},
discoveredSources: [],
}),
});
});

await page.goto('/app/generate');
await page.getByRole('button', { name: 'Generate Debate Case' }).click();
await expect(page.getByText('Contention 3: fares block the riders who need transit most')).toBeVisible();

const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
expect(overflow, 'horizontal page overflow in px').toBeLessThanOrEqual(1);
// The column must also stay inside the page container, which ends before the viewport edge on desktop.
const results = await page.locator('#generate-results').boundingBox();
const container = await page.locator('#generate-results').locator('xpath=ancestor::div[contains(@class, "max-w-6xl")]').boundingBox();
expect(results && container && Math.round(results.x + results.width - (container.x + container.width))).toBeLessThanOrEqual(1);
});
2 changes: 1 addition & 1 deletion src/components/features/ask/AskChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ export function AskChat({ messages, isLoading, onSend, onClear, onSaveChat, save
</SheetContent>
</Sheet>

<div className={cn('grid gap-3', desktopSidebarOpen ? 'lg:grid-cols-[280px_1fr]' : 'lg:grid-cols-[auto_1fr]')}>
<div className={cn('grid gap-3', desktopSidebarOpen ? 'lg:grid-cols-[280px_minmax(0,1fr)]' : 'lg:grid-cols-[auto_minmax(0,1fr)]')}>
<aside className="hidden lg:block">
{desktopSidebarOpen ? (
<Card className="flex h-[calc(100vh-14rem)] min-h-[400px] max-h-[800px] flex-col border-primary/20">
Expand Down
2 changes: 1 addition & 1 deletion src/components/loading/RouteSkeleton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const HomeGridSkeleton = () => (
const ToolFormSkeleton = () => (
<PageFrame className="mx-auto max-w-6xl">
<Heading width="w-52" />
<div className="grid gap-8 lg:grid-cols-[400px_1fr]">
<div className="grid gap-8 lg:grid-cols-[400px_minmax(0,1fr)]">
<Surface className="min-h-[420px] space-y-6">
<Shape className="h-6 w-40" />
{[0, 1, 2].map((field) => (
Expand Down
2 changes: 1 addition & 1 deletion src/pages/AttackPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export default function AttackPage() {
</AnimatedSection>
<CurrentDebateStrip hidden={Boolean(workspace.context)} />

<div className="grid gap-8 lg:grid-cols-[400px_1fr]">
<div className="grid gap-8 lg:grid-cols-[400px_minmax(0,1fr)]">
{/* Form */}
<AnimatedSection delay={75} className="lg:sticky lg:top-24 lg:self-start">
<AttackForm onSubmit={handleSubmit} isLoading={attackLoading} debateContext={!workspace.context} />
Expand Down
2 changes: 1 addition & 1 deletion src/pages/BrainstormPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export default function BrainstormPage() {
</AnimatedSection>
<CurrentDebateStrip side={brainstormForm?.side} hidden={Boolean(workspace.context)} />

<div className="grid gap-8 lg:grid-cols-[400px_1fr]">
<div className="grid gap-8 lg:grid-cols-[400px_minmax(0,1fr)]">
{/* Form */}
<AnimatedSection delay={75} className="lg:sticky lg:top-24 lg:self-start">
<BrainstormForm onSubmit={handleSubmit} isLoading={brainstormLoading} debatePrefill={!workspace.context} />
Expand Down
2 changes: 1 addition & 1 deletion src/pages/FactoidsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export default function FactoidsPage() {
</AnimatedSection>
<CurrentDebateStrip hidden={Boolean(workspace.context)} />

<div className="grid gap-8 lg:grid-cols-[400px_1fr]">
<div className="grid gap-8 lg:grid-cols-[400px_minmax(0,1fr)]">
{/* Form */}
<AnimatedSection delay={75} className="lg:sticky lg:top-24 lg:self-start">
<FactoidsForm onSubmit={handleSubmit} isLoading={factoidsLoading} debateContext={!workspace.context} />
Expand Down
2 changes: 1 addition & 1 deletion src/pages/GeneratePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ export default function GeneratePage() {
</AnimatedSection>
<CurrentDebateStrip side={generateForm?.side} hidden={Boolean(workspace.context)} />

<div className="grid gap-8 grid-cols-1 lg:grid-cols-[440px_1fr]">
<div className="grid gap-8 grid-cols-1 lg:grid-cols-[440px_minmax(0,1fr)]">
{/* Form */}
<AnimatedSection delay={75} className="lg:sticky lg:top-24 lg:self-start">
<GenerateForm onSubmit={handleSubmit} isLoading={generateLoading || regeneratingSection !== null} debatePrefill={!workspace.context} />
Expand Down
Loading