Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
242 commits
Select commit Hold shift + click to select a range
2fca7bc
Add design audit against Emil Kowalski's Apple-design and motion skills
Programcode Oct 9, 2026
21dc4c6
Design foundations: tokens, one motion system, touch and reduced motion
Programcode Oct 9, 2026
073e566
Keep hover-only actions visible on touch and stop checkbox hit areas …
Programcode Oct 9, 2026
9bccae8
Tick the hover-only icon row in the design audit plan
Programcode Oct 9, 2026
33b14e4
Swallow the skipped view transition when a theme switch interrupts an…
Programcode Oct 9, 2026
41e7384
Reduced-motion spec: allow fades, forbid movement
Programcode Oct 9, 2026
2dc73ff
Design shell: wayfinding, one delete rule, pending states, page headers
Programcode Oct 9, 2026
497ec8c
Re-record agentic replays for the new header and Library
Programcode Oct 9, 2026
e8a7c30
Scope the mobile menu and tooltip durations to their states; widen Te…
Programcode Oct 9, 2026
840542a
Open the mobile menu below the whole two-row header
Programcode Oct 9, 2026
b6c222f
Wait for the Tools page heading in the offline service-worker check
Programcode Oct 9, 2026
7921744
Point the navigation specs at the Tools heading and the inline Librar…
Programcode Oct 9, 2026
21a2607
Shell review fixes: exact Undo, modal edge cases, close-on-success co…
Programcode Oct 9, 2026
4fa6e74
AI tools: Stop and Cancel, honest status, inline errors, one result h…
Programcode Oct 9, 2026
862bd8e
Practice tools: one round clock, honest waits, undoable flowchart edits
Programcode Oct 9, 2026
eecca59
Specs and recipes for the practice tools: pinned speech, flowchart Undo
Programcode Oct 9, 2026
60e89ee
voice-rounds spec: read the live reply from the transcript, not the p…
Programcode Oct 9, 2026
7f35277
Tick the AI tools and practice rows in the design audit plan
Programcode Oct 9, 2026
a168d14
Re-record agentic replays for the AI tools changes
Programcode Oct 9, 2026
4fee6f5
Flowchart controls reach 44px on touch
Programcode Oct 9, 2026
558b410
Stop sending temperature to OpenRouter
Programcode Oct 9, 2026
6dee075
Make Claude the default models and add the 5.5 family
Programcode Oct 9, 2026
bac0f45
AI tools review fixes: Cancel ownership, Undo scope, one reply bubble
Programcode Oct 9, 2026
8db4a3b
Timer: Reset has a real accessible name, not the keyboard hint
Programcode Oct 9, 2026
6f556bb
Add a verify recipe for the model defaults
Programcode Oct 9, 2026
2f3f2c8
Skip the settings cleanup when the row changed since hydration read it
Programcode Oct 9, 2026
44a6bb5
Add the 2026-10-08 ultracode review report
Programcode Oct 9, 2026
3b04533
Move the rest of the catalog to each family's newest model
Programcode Oct 9, 2026
30e9ccf
Read the requested model in the model-defaults recipe
Programcode Oct 9, 2026
37224a2
navigation-performance spec: the flowchart title is an h1, and the sh…
Programcode Oct 9, 2026
781d603
Merge pull request #134 from Programcode/t3/fix-openrouter-no-endpoin…
Programcode Oct 9, 2026
d0894e3
Limit Basic to Haiku, Luna and Muse Spark contributor
Programcode Oct 9, 2026
825ed19
Merge remote-tracking branch 'origin/main' into t3/anthropic-default-…
Programcode Oct 9, 2026
45c9cff
Use current catalog models in the settings cleanup test
Programcode Oct 9, 2026
a41e963
Flowchart delete: one at a time per chart, and fail closed on auth er…
Programcode Oct 9, 2026
920154b
Correct the live-verify note now that Muse Spark contributor is a Bas…
Programcode Oct 9, 2026
cca52c1
Flowchart delete: a failed session read fails the delete; Delete stay…
Programcode Oct 9, 2026
0770b94
Saved flowcharts: Load and Delete are sibling buttons
Programcode Oct 10, 2026
a3abda9
Landing: static backgrounds, one reveal, press states, self-hosted Inter
Programcode Oct 9, 2026
6811cd9
Sentence case in Spanish and Hungarian
Programcode Oct 9, 2026
da7d13b
Design audit plan: tick the landing rows and mark it Shipped
Programcode Oct 9, 2026
1d1953f
Spanish landing badge: no English 'Prep'
Programcode Oct 9, 2026
2b8c2df
Landing logo links reach 44px on touch
Programcode Oct 9, 2026
3450e4c
first-run spec: Hungarian tour step in sentence case
Programcode Oct 9, 2026
fba56f7
Re-record agentic replays for the landing and sentence-case changes
Programcode Oct 9, 2026
808c8be
New pages open at the top after in-app navigation
Programcode Oct 10, 2026
547d279
Scroll reset only for a new page, not query-only updates
Programcode Oct 10, 2026
1552103
Restore an agentic replay the final run recorded again
Programcode Oct 10, 2026
bb1b7f8
Merge pull request #135 from Programcode/t3/anthropic-default-model-c…
Programcode Oct 11, 2026
80f9490
Merge remote-tracking branch 'origin/main' into design-audit/fixes
Programcode Oct 11, 2026
f08cdad
Merge branch 'design-audit/fixes' into design-audit/shell
Programcode Oct 11, 2026
116c859
Merge branch 'design-audit/ai-tools' into design-audit/landing-v2
Programcode Oct 11, 2026
80dc67b
Merge branch 'design-audit/shell' into design-audit/ai-tools
Programcode Oct 11, 2026
b9e64c4
Design audit plan: the dark-mode logo row is done as is
Programcode Oct 11, 2026
bba0666
Design audit 1/4: Foundations (#124)
Programcode Oct 11, 2026
fbbb8da
Design audit 2/4: Shell (#126)
Programcode Oct 11, 2026
287ac36
Design audit 3/4: AI tools and practice tools (#128)
Programcode Oct 11, 2026
5af8a46
Design audit 4/4: Landing (#136)
Programcode Oct 11, 2026
d733459
Split the client AI module into per-feature files (#145)
Programcode Oct 16, 2026
3f4f22f
SEO: prerender public pages, real 404s, 301 brand pages, built sitema…
Programcode Oct 16, 2026
df25e98
Document sign-in email DNS and the new DMARC policy (#147)
Programcode Oct 16, 2026
0b3e9f0
Stream every AI answer live, token by token (#149)
Programcode Oct 17, 2026
f16e8a4
Pre-ship security pass: 25-item audit and fixes (#148)
Programcode Oct 17, 2026
80771f6
Open Ask's Options popover in the staging suite (#150)
Programcode Oct 17, 2026
c928589
Record that the security pass fixes shipped (#151)
Programcode Oct 17, 2026
588b132
Give five guide pages their own content and one brand config (#152)
Programcode Oct 18, 2026
33704ec
Run the production canary after debate-navigator deploys (#153)
Programcode Oct 18, 2026
0e21055
Give six more guide pages their own content (#154)
Programcode Oct 20, 2026
4f9e0a0
Merge 13 overlapping guide pages into 10 survivors (#155)
Programcode Oct 20, 2026
e5850ee
Run research helper calls on a fixed cheap model (#163)
Programcode Oct 22, 2026
6364102
Trim AI prompts and cache Anthropic system prompts (#177)
Programcode Oct 22, 2026
aab301b
Refuse Checkout when a subscription can still bill (#161)
Programcode Oct 22, 2026
b8b41c9
Cancel a subscription that completes after the account is gone (#162)
Programcode Oct 22, 2026
135f4de
Report a failed Google Doc update instead of an empty success. (#165)
Programcode Oct 22, 2026
e8c4579
Let ordinary debate sentences through the prompt check. (#166)
Programcode Oct 22, 2026
1204521
Restore a saved case when deleting it fails (#159)
Programcode Oct 22, 2026
4f76712
Regenerate a loaded case with its own motion and debate (#160)
Programcode Oct 22, 2026
95861df
Bind device drafts to the signed-in account (#158)
Programcode Oct 22, 2026
cc25074
Stop treating an Auth outage as a successful local save. (#171)
Programcode Oct 22, 2026
bc9a8de
Keep a full local save from crashing the page. (#174)
Programcode Oct 22, 2026
2f320ec
Clear Ask when you leave while it is still answering. (#170)
Programcode Oct 22, 2026
0f50644
Keep timer shortcuts away from buttons and open menus. (#172)
Programcode Oct 22, 2026
f08e1f0
Stop offering Pro again when a paid plan hits the daily cap. (#173)
Programcode Oct 22, 2026
a69e96f
Keep checking the plan after Stripe sends the student back. (#169)
Programcode Oct 22, 2026
34fb585
Reload once when a deploy leaves a tab holding an old chunk (#175)
Programcode Oct 22, 2026
1ad9329
Keep URL import working on hostile HTML (#168)
Programcode Oct 22, 2026
988b870
Make Claude Sonnet 5.5 the Pro default and Opus opt-in only (#164)
Programcode Oct 22, 2026
bf4c34e
Move saved Opus 5.5 settings to Sonnet 5.5 (data migration, after #16…
Programcode Oct 22, 2026
6260da2
Cap each AI feature's reply length instead of 32,768 tokens (#182)
Programcode Oct 22, 2026
b23b5d7
Fix the 11 bugs from today's QA pass (H1, M1–M5, L1–L5) (#184)
Programcode Oct 22, 2026
da7473e
Free no-login debate tools: timer, motion generator, flow sheet, spee…
Programcode Oct 22, 2026
b8471e4
Repair model JSON locally and enforce schemas before paying for a ret…
Programcode Oct 22, 2026
b2e92b6
Weight the daily AI quota by model and cap AI spend at $2 a week (BYO…
Programcode Oct 22, 2026
c27cace
Log the real cost of Anthropic (BYOK) calls and Exa research (#179)
Programcode Oct 22, 2026
cd1c814
Keep automatic Vercel deploys on main only (#186)
Programcode Oct 22, 2026
d749051
Make guide product claims match the app (#157)
Programcode Oct 22, 2026
17c00f9
Run Claude only on the Anthropic BYOK key, with no fallback provider …
Programcode Oct 22, 2026
311ee3e
Pin the Supabase CLI to 2.121.0 so every worktree uses one image set …
Programcode Oct 22, 2026
71c083e
Make the public pages readable for AI answer engines (AEO) (#156)
Programcode Oct 22, 2026
a238ba6
Fall back to the structured Ask when a failed stream sent only whites…
Programcode Oct 22, 2026
298fbc1
Give the /tools pages a #short-answer section and drop their exemptio…
Programcode Oct 22, 2026
e75ad13
Patch the dev-tool dependencies Dependabot flagged (#192)
Programcode Oct 22, 2026
979a9bc
Keep a running speech when the timer's arrow keys hit either end (#188)
Programcode Oct 22, 2026
09faf68
Say only the timer saves anything in the /tools hub short answer (#193)
Programcode Oct 22, 2026
ce3836e
Fix rate-limit overrides, AI error reports, and the login crash (#190)
Programcode Oct 22, 2026
5770299
Re-enable buttons that leave the site after Back (AUTH-15, AUTH-16) (…
Programcode Oct 22, 2026
c5f3ad1
Fix the 22 Oct QA backend nits (batch C2) (#195)
Programcode Oct 22, 2026
b79f858
Delay Jam and align cache, CSP, and robots (#196)
Programcode Oct 22, 2026
c611ed4
Keep Jam out of the full-stack e2e harness
Programcode Oct 22, 2026
6962616
Fix import-source stripping whole Wikipedia pages (#195 regression) (…
Programcode Oct 22, 2026
1b00d89
Shrink icons and the share image, and name missing share links (#199)
Programcode Oct 22, 2026
2a1e82e
Name controls, headings, and the toast region (AX-01, AX-05, AX-06, A…
Programcode Oct 22, 2026
ee5674b
Charge Crossfire and Sparring per round, refund runs that produce not…
Programcode Oct 22, 2026
06b73de
Fix Library and History QA issues (T7: LB-01, LB-03–07, HI-01, MD-05,…
Programcode Oct 22, 2026
4338727
Fix sign-in links, the OAuth callback and per-account state (T2: AUTH…
Programcode Oct 23, 2026
508f243
test(share): wait for the not-found title and robots meta effect (#205)
Programcode Oct 23, 2026
45788cf
Drain live AI streams until the body closes (#204)
Programcode Oct 23, 2026
1b518d5
Fix Flowchart QA issues (T9: FC-01–06, PF-03) (#206)
Programcode Oct 23, 2026
b0b2ae7
Make billing states agree between Settings and the AI functions (T4: …
Programcode Oct 23, 2026
5ea2275
Fix login-screen UX: resend countdown, validation, demo-code mask, ph…
Programcode Oct 23, 2026
7407139
Polish the prep modes (T8: MD-04, MD-06–12, MD-14, VS-04, AX-05, AX-0…
Programcode Oct 23, 2026
45afb25
Harden Supabase grants, de-duplicate share views and index foreign ke…
Programcode Oct 23, 2026
87603cd
Fix phone layout, contrast, focus and touch targets (T10: VS-05, AX-0…
Programcode Oct 23, 2026
504ea07
Load only the active locale and open the app offline (T11: PF-01, PF-…
Programcode Oct 23, 2026
a7610fa
Disclose Jam in the privacy policy and fix public copy (T14: SC-01, S…
Programcode Oct 23, 2026
731a1a5
Apply DB-05 duplicate-index drop and promo_redeem_failures primary ke…
Programcode Oct 23, 2026
3aa123a
Record DB-03 legacy policy drop as a migration (#219)
Programcode Oct 23, 2026
91e1e85
Show usage, limits and plans consistently (T6: QB-03, QB-06, QB-16, V…
Programcode Oct 23, 2026
ed6b1c5
Stop mentioning API keys on the Account card; audit confirms BYOK is …
Programcode Oct 23, 2026
f1cb90c
Upgrade Tailwind CSS 3 to 4 with v3 visual parity (T17, Dependabot #9…
Programcode Oct 23, 2026
79cb1f8
Localize tab titles, validation and server errors; add ?lang= links (…
Programcode Oct 23, 2026
073dd08
Move default, Auto and test-agent model calls onto the Anthropic BYOK…
Programcode Oct 23, 2026
2ac31e6
Unify translations, plurals and number/date formats (T13: IN-02, IN-0…
Programcode Oct 23, 2026
37c1baa
Keep AI streams alive, recover dropped results, charge Auto Pro as So…
Programcode Oct 23, 2026
2e6d99a
Add the admin tables' missing columns and fix QA round 3 UI nits (T19…
Programcode Oct 23, 2026
a632e86
Constrain Sparring replies to a strict schema; drop the prefill conti…
Programcode Oct 23, 2026
5346a03
Address review round 1: keep the Stop floor, harden recovery
Programcode Oct 23, 2026
b2e7092
Pick billing states by name in bill-access, so the new promo-Pro stat…
Programcode Oct 23, 2026
7391338
Address review round 2: keep a stalled stream open during recovery
Programcode Oct 23, 2026
2cffa27
Merge pull request #225 from Programcode/fix/t19-db01-ui-nits
Programcode Oct 23, 2026
390788b
Merge remote-tracking branch 'origin/main' into fix/t18-ai-stream-rel…
Programcode Oct 23, 2026
c87128b
Merge remote-tracking branch 'origin/main' into fix/jam-e2e-streaming
Programcode Oct 23, 2026
cced73a
Bound stream finish by the wall clock; keep charged:false on deadline
Programcode Oct 23, 2026
c402ca6
Merge pull request #198 from Programcode/fix/jam-e2e-streaming
Programcode Oct 23, 2026
9f04763
Merge remote-tracking branch 'origin/main' into fix/t18-ai-stream-rel…
Programcode Oct 23, 2026
cd8e4de
Merge pull request #224 from Programcode/fix/t18-ai-stream-reliability
Programcode Oct 23, 2026
ea7c893
SEO: internally link the free tools
Programcode Oct 23, 2026
df0fe42
Add DebateOwl tokens, Fredoka and Nunito, light by default
Programcode Oct 24, 2026
ab96c87
Add the owl: pose cutouts, app mark and icons
Programcode Oct 24, 2026
28b1c92
Restyle shared components to the DebateOwl style guide
Programcode Oct 24, 2026
8b15cb4
Put button labels in sentence case
Programcode Oct 24, 2026
8b67a64
Owl loaders, Ask coach and Sparring opponent
Programcode Oct 24, 2026
6fa5b95
Restyle the landing page, Home and Library
Programcode Oct 24, 2026
f0874ea
Owl on the 404 and error pages; busy tool buttons keep their face
Programcode Oct 24, 2026
27eddf9
Owl on the Sparring verdict, onboarding tour in the new style
Programcode Oct 24, 2026
a4d502a
Success is never colour alone; amber text passes AA
Programcode Oct 24, 2026
433af86
Document the DebateOwl tokens, fonts and owl component
Programcode Oct 24, 2026
1482c73
Use Nunito and Fredoka in the embeddable timer too
Programcode Oct 24, 2026
51a0f01
Timers in JetBrains Mono; offline check follows the owl logo
Programcode Oct 24, 2026
5afdcf0
Reduced motion stops new entrances; owls work offline; guide pages re…
Programcode Oct 24, 2026
0990051
Recipes that compare themes switch the account to System first
Programcode Oct 24, 2026
c9cf5dd
Bold in answers stands out from Nunito body text; toast close button …
Programcode Oct 24, 2026
25db8f9
Merge pull request #227 from Programcode/seo/link-free-tools
Programcode Oct 24, 2026
aa962b8
Stop share and create-portal from returning internal error text
Programcode Oct 24, 2026
ec6c1a0
Before screenshots of the Ask and Generate menus
Programcode Oct 24, 2026
03e3f43
Ask Options join the mode row; Generate actions follow their purpose
Programcode Oct 24, 2026
56097ef
After screenshots of the Ask and Generate menus
Programcode Oct 24, 2026
8f6569b
Make the keepalive tables service-role only
Programcode Oct 24, 2026
91d93ba
Claim discount promo codes and apply exactly one Stripe promotion code
Programcode Oct 24, 2026
703b02f
Pin import-source connections to the address the SSRF check passed
Programcode Oct 24, 2026
4b75a7f
Start the discount recipe from an ended trial so both buttons say Upg…
Programcode Oct 24, 2026
aa92de4
Merge pull request #229 from Programcode/design/menu-layout-cleanup
Programcode Oct 24, 2026
cad752f
Give each source address its own connect budget and cancel stalled TLS
Programcode Oct 24, 2026
4b0245d
Merge remote-tracking branch 'origin/main' into fix/security-audit-fi…
Programcode Oct 24, 2026
41f5cb3
Generate toolbar rows split evenly on tablets and desktop
Programcode Oct 24, 2026
67628a8
Owls are traced SVGs: six new poses, WebP cutouts gone
Programcode Oct 24, 2026
42cb530
One owl on each key screen
Programcode Oct 24, 2026
6f93aa5
Merge pull request #230 from Programcode/fix/security-audit-findings
Programcode Oct 24, 2026
e66cf0b
Spanish coach alt text says coach, as the Ask title does
Programcode Oct 24, 2026
613b2c7
Merge pull request #232 from Programcode/design/debateowl-owls
Programcode Oct 24, 2026
5649e10
Before and after screenshots of the Generate toolbar rows
Programcode Oct 24, 2026
894e6d1
Merge pull request #231 from Programcode/design/generate-toolbar-even…
Programcode Oct 24, 2026
3508de4
Deepen the four format guides and shrink the shared About block
Programcode Oct 26, 2026
4ec18e3
Link every guide from its topic cluster and the home page, name the p…
Programcode Oct 26, 2026
29b69b9
Read site.json from disk in the Hungarian parity spec
Programcode Oct 26, 2026
417cede
Stack guide tables into labelled rows on narrow screens
Programcode Oct 26, 2026
54dbaad
Merge five thin guides into their survivors and deepen the skills guides
Programcode Oct 26, 2026
5b29824
Name the link guard in the build step of the testing guide
Programcode Oct 26, 2026
ef88cdd
Serve indexable Hungarian and Spanish pages with hreflang
Programcode Oct 26, 2026
11d7732
Put the permutation answer in the 2AC in the Policy example
Programcode Oct 26, 2026
b1aa06a
Redirect the homepage's ?lang=hu|es links to /hu and /es
Programcode Oct 26, 2026
f73bc6c
Merge branch 'seo/deepen-thin-guides' into seo/merge-thin-guides
Programcode Oct 26, 2026
c349293
Remove committed Python bytecode and ignore it
Programcode Oct 26, 2026
fe00edc
Apply the Hungarian review fixes and rename three HU tool slugs
Programcode Oct 26, 2026
988bb4a
Merge pull request #233 from Programcode/seo/deepen-thin-guides
Programcode Oct 26, 2026
f101649
Merge remote-tracking branch 'origin/main' into seo/merge-thin-guides
Programcode Oct 26, 2026
04e1a78
Merge pull request #235 from Programcode/seo/merge-thin-guides
Programcode Oct 26, 2026
a5a2556
Merge origin/main: drop the five retired guides from the link tables
Programcode Oct 26, 2026
92d7113
Merge pull request #234 from Programcode/seo/internal-links-brand-entity
Programcode Oct 26, 2026
6d20371
Merge origin/main (#233, #235, #234) into seo/hu-es-pages
Programcode Oct 26, 2026
12eaab1
Merge pull request #236 from Programcode/seo/hu-es-pages
Programcode Oct 26, 2026
748f3c9
One-time DebateOwl welcome on the first app open
Programcode Oct 26, 2026
715b2e5
Merge remote-tracking branch 'origin/main' into design/debateowl-restyle
Programcode Oct 26, 2026
5e5bc44
Welcome and rename notice in one dialog with one dismiss
Programcode Oct 26, 2026
b2fd202
Merge remote-tracking branch 'origin/design/debateowl-restyle' into d…
Programcode Oct 26, 2026
8917c29
Keep the owl nameless until a name is picked
Programcode Oct 26, 2026
e21d8ee
The owl is called Ollie
Programcode Oct 26, 2026
4778c66
Service worker offline test marks the welcome seen
Programcode Oct 26, 2026
c1fe62f
Ollie's greeting wraps evenly on phones
Programcode Oct 26, 2026
e5c6efc
Merge pull request #237 from Programcode/design/debateowl-intro
Programcode Oct 26, 2026
bbe42d9
Merge pull request #228 from Programcode/design/debateowl-restyle
Programcode Oct 26, 2026
dc131c8
DebateOwl polish: sentence case, even rows, touch targets, prerendere…
Programcode Oct 27, 2026
81f4125
Use Library as the one visible name (#238)
Programcode Oct 27, 2026
477eb06
Finish the visible DebateLab to DebateOwl rename (#241)
Programcode Oct 27, 2026
27ce0fe
The owl welcome leads straight into Start debate (#239)
Programcode Oct 27, 2026
d045977
Ollie blinks, breathes and waves, and results land with motion (#242)
Programcode Oct 27, 2026
f1fa967
Add a phone bottom tab bar (#240)
Programcode Oct 27, 2026
cc78bb4
Move to debateowl.com and 301 the old domain (#246)
Programcode Oct 27, 2026
dba5219
Rename the /debatelab-* pages to /debateowl-* and drop the last pi-st…
Programcode Oct 27, 2026
fea1ab9
SEO/AEO: DebateOwl entity, icons on every page, speech-times and comp…
Programcode Oct 27, 2026
69cf666
Landing page: less text, a phone-first hero, three fewer sections (#250)
Programcode Oct 27, 2026
9868daa
Clean up how DebateOwl shows in search results (#251)
Programcode Oct 27, 2026
baec275
Merge origin/main into the native iOS branch
Programcode Oct 28, 2026
3ee7cf9
Read the plan in the app's web preview too
Programcode Oct 28, 2026
2261bac
Share AI result parsers between web and mobile
Programcode Oct 28, 2026
c50be3e
Restyle the iOS app as DebateOwl
Programcode Oct 28, 2026
6c60aaf
Draw the timer ring, PDF export and flowchart edges in DebateOwl colours
Programcode Oct 28, 2026
0142c32
Charge an app Crossfire round once, as main does
Programcode Oct 28, 2026
5057575
Describe the DebateOwl look, the owl and the shared plan read in the …
Programcode Oct 28, 2026
2387d53
Let VoiceOver announce a tool's progress once
Programcode Oct 28, 2026
f79ace8
Merge the shared AI parsers from native-ios/core-ai-dedupe
Programcode Oct 28, 2026
6fb2664
Ask again without streaming when a failed stream sent only whitespace
Programcode Oct 28, 2026
3bb421d
Leave the website's plan unknown when the App Store read fails
Programcode Oct 28, 2026
a9f5a0a
Keep the owl loader still under Reduce Motion
Programcode Oct 28, 2026
bcfe3ec
Keep pinned actions whole and on a solid bar
Programcode Oct 28, 2026
336450e
Draw the plan badges as the website does
Programcode Oct 28, 2026
ead0e56
Give the iPad Library its full width until a source opens
Programcode Oct 28, 2026
00d09c9
Wrap Ask's options on iPad and fade the row's edge on iPhone
Programcode Oct 28, 2026
7fc6ae6
Let titles and choices wrap where Hungarian and Spanish cut them off
Programcode Oct 28, 2026
a214239
Shoot Spanish too and report clipped text in the app's screenshots
Programcode Oct 28, 2026
521d207
Fade a chip row only while it overflows, into the surface behind it
Programcode Oct 28, 2026
1ef3b2e
Keep switch thumbs white in the web preview and Library dates whole
Programcode Oct 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
26 changes: 15 additions & 11 deletions .claude/skills/verify-debatelab/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
name: verify-debatelab
description: Launch and drive the real DebateLab web app (React client + local Supabase Auth/Postgres/Edge Functions, with either a fake model provider or real OpenRouter pinned to the cheap meta/muse-spark-1.3-contributor model plus real Exa research) to prove a user-facing feature works, with screenshots, ARIA snapshots, provider calls, and database rows as evidence. Use when asked to verify, demo, reproduce, or screenshot DebateLab behavior in a browser, or before calling a DebateLab UI/Edge Function change done.
description: Launch and drive the real DebateOwl web app (React client + local Supabase Auth/Postgres/Edge Functions, with either a fake model provider or real OpenRouter pinned to Claude Haiku 5.5 on the Anthropic BYOK key plus real Exa research) to prove a user-facing feature works, with screenshots, ARIA snapshots, provider calls, and database rows as evidence. Use when asked to verify, demo, reproduce, or screenshot DebateOwl behavior in a browser, or before calling a DebateOwl UI/Edge Function change done.
---

# Verify DebateLab
# Verify DebateOwl

DebateLab is a web app. The surface a user touches is the browser client at `/login` and `/app/*`, backed by Supabase Auth, Postgres/RLS, and Deno Edge Functions. This skill runs all of that locally and drives it with Playwright. It has two modes:
DebateOwl is a web app. The surface a user touches is the browser client at `/login` and `/app/*`, backed by Supabase Auth, Postgres/RLS, and Deno Edge Functions. This skill runs all of that locally and drives it with Playwright. It has two modes:

- **Fake (default, free).** `e2e/full-stack/fake-openrouter.mjs` answers every model call with canned text. Proves wiring, rows, and UI, not model behavior.
- **Live (`up --live`, costs money).** The same container becomes a recording proxy to real OpenRouter. It rewrites every chat call to `meta/muse-spark-1.3-contributor` (override with `VERIFY_LIVE_MODEL`), records OpenRouter's reply model as proof, and stops forwarding after `--max-calls` (default 400). Edge Functions also get a real Exa key, so web research and verified citations are real.
- **Live (`up --live`, costs money).** The same container becomes a recording proxy to real OpenRouter. It rewrites every chat call to `anthropic/claude-haiku-5.5` pinned to the Anthropic provider with fallbacks off, so it bills the Anthropic BYOK key and not OpenRouter credits (override with `VERIFY_LIVE_MODEL`, which must be an `anthropic/` model), records OpenRouter's reply model as proof, and stops forwarding after `--max-calls` (default 400). Edge Functions also get a real Exa key, so web research and verified citations are real.

Everything goes through one helper, run from the repository root (`git rev-parse --show-toplevel`):

Expand Down Expand Up @@ -42,7 +42,7 @@ STRIPE_TEST_SECRET_KEY=sk_test_... # optional; live keys are refused
STRIPE_TEST_PRICE_ID=price_... # required with the Stripe key
```

It prints nothing about the values. Ask Adam before the first live run: it spends money and sends prompts to a contributor model that may use them for training, so never put real user data in a live run. Costs: Muse Spark 1.3 contributor is $0.10 per million prompt tokens and $0.20 per million completion tokens, so a full `drive all` is cents of model spend. Exa bills per search and is usually the larger part. Jev decisions go to `/api/alpha/decisions` with Jev's own model and are not pinned. `doctor` shows `live calls used N/max`; once the cap is hit the proxy answers 429 and tests fail rather than spend more.
It prints nothing about the values. Ask Adam before the first live run: it spends money (Exa, Jev, and the Anthropic key), so never put real user data in a live run. Model calls bill the Anthropic BYOK key; Exa bills per search. Jev decisions go to `/api/alpha/decisions` with Jev's own model and are not pinned. `doctor` shows `live calls used N/max`; once the cap is hit the proxy answers 429 and tests fail rather than spend more.

## Launch

Expand Down Expand Up @@ -81,13 +81,15 @@ It also prints the commit the stack started at and whether there are uncommitted
- The Current Debate helpers: `startDebate(page, motion)` starts one from the header, `chooseForMotion(page, "create" | "once")` answers the motion dialog, and `debateControl(page)` is the visible header control on either viewport.
- The voice helpers: `stubSpeech(page)` installs a scripted microphone, recogniser and browser voice; `say(page, words)` speaks; `spokenByBrowser(page)` reads back what the browser voice said.
- `admin`: a service-role client for reading rows as a second view.
- `fake` / `providerCall(feature)`: what the Edge Function actually sent upstream. Use `fake.fail(feature, status)` to force a provider error.
- `aiResponse(page, feature, operation?)`: the parsed body of the next `ai` Edge Function response. Assert that its fields reach the screen, never on model wording, so a recipe passes in both modes. `LIVE` and `AI_TIMEOUT` (30 s fake, 240 s live) let a recipe branch where a check only makes sense live, and a fake-mode branch adds an `unverified` annotation instead of passing silently.
- `fake` / `providerCall(feature)`: what the Edge Function actually sent upstream. Use `fake.fail(feature, status)` to force a provider error and `fake.truncate(feature)` (fake mode only) to cut the next reply off at its length cap. Each call records the `maxTokens` it asked for.
- `aiResponse(page, feature, operation?)`: the parsed body of the next `ai` Edge Function response. Pages ask for live generation, so most `ai` responses are event streams; `aiResponse` and `readAIResponse(response)` read the final `result` event (or a plain JSON body) for you, so never call `response.json()` on an `ai` response. Assert that its fields reach the screen, never on model wording, so a recipe passes in both modes. `LIVE` and `AI_TIMEOUT` (30 s fake, 240 s live) let a recipe branch where a check only makes sense live, and a fake-mode branch adds an `unverified` annotation instead of passing silently.
- `followSystemTheme(page)`: new accounts start on the light theme. A recipe that compares light and dark calls this first; it picks System in Settings, so `page.emulateMedia({ colorScheme })` then drives the theme.
- `expectStreamed([...])`: every provider call for those features asked the model to stream, which proves the page showed the answer live.
- `expectProviderCalls([...])`: what reached the provider. Each test writes `provider-calls.json`, and in live mode the fixture fails the test if any chat call was answered by a model other than the pin.
- `evidence`: `step(line)`, `aria(name, locator?)`, `shot(name)` and `json(name, value)`.
- Automatic failure on any uncaught page error, horizontal overflow, or remote Supabase request.

Every result, source and practice round belongs to a Current Debate or is explicitly one-off. A tool given a motion when no debate exists opens `Start a debate with this motion?`; a motion that differs from the Current Debate's opens `This is a different motion`. Both open after the submit click and before the AI request, so create the `aiResponse()` promise, click, answer with `chooseForMotion`, then await. Or call `startDebate` first, after which tools prefill its motion and open no dialog. The Library's `Add Source` is disabled until a debate exists. See `features/current-debate.md`.
Every result, source and practice round belongs to a Current Debate or is explicitly one-off. A tool given a motion when no debate exists opens `Start a debate with this motion?`; a motion that differs from the Current Debate's opens `This is a different motion`. Both open after the submit click and before the AI request, so create the `aiResponse()` promise, click, answer with `chooseForMotion`, then await. Or call `startDebate` first, after which tools prefill its motion and open no dialog. The Library's `Add source` is disabled until a debate exists. See `features/current-debate.md`.

```bash
$H drive all # every recipe, both viewports
Expand All @@ -104,9 +106,9 @@ Fake mode also runs `e2e/full-stack/`. Live mode runs the recipes, `e2e/live/`,

To prove a feature without a recipe, copy `recipes/case-generation.spec.ts` to `recipes/<feature>.spec.ts` and use the selectors from the matching file in `features/`. Recipes are maintained files. Keep the ones worth keeping.

**Interactive.** Run `$H user` to mint a code. It prints `DEMO_CODE=...`, and `down` deletes that user. Then point a browser tool (Playwright MCP `browser_navigate` etc.) at `http://127.0.0.1:18081/login`, choose the `Demo code` tab, fill the `Demo code` textbox, and click `Sign in with demo code`. Save your own screenshots into `.verify/artifacts/<run-id>/`. A new account shows the onboarding tour on `/app`. Its first step offers `Start debate`; to skip the tour, click `Skip Tour` (`[data-test-id="button-skip"]`). Then start a debate from the header (`Start debate`, test id `current-debate-desktop` or `current-debate-mobile`) or answer the motion dialog the first tool opens: `Start debate` files the work in a new debate, `Not now, use it once` keeps it one-off. Interactive runs have no remote-Supabase guard. Doctor's local-mode check is what protects you.
**Interactive.** Run `$H user` to mint a code. It prints `DEMO_CODE=...`, and `down` deletes that user. Then point a browser tool (Playwright MCP `browser_navigate` etc.) at `http://127.0.0.1:18081/login`, choose the `Demo code` tab, fill the `Demo code` textbox, and click `Sign in with demo code`. Save your own screenshots into `.verify/artifacts/<run-id>/`. The one-time DebateOwl welcome never opens on this stack (`VITE_LOCAL_PREVIEW`) or under Playwright (`VITE_E2E`); open `/app?intro=show` to see it, and close it with `Got it` or Esc. Closing it continues straight into the tour's Start debate step when that account has not finished the tour. A new account shows the onboarding tour on `/app`. Its first step offers `Start debate`; to skip the tour, click `Skip tour` (`[data-test-id="button-skip"]`). Then start a debate from the header (`Start debate`, test id `current-debate-desktop` or `current-debate-mobile`) or answer the motion dialog the first tool opens: `Start debate` files the work in a new debate, `Not now, use it once` keeps it one-off. Interactive runs have no remote-Supabase guard. Doctor's local-mode check is what protects you.

Selectors: use accessible names and roles as the feature files list them (`getByRole("button", { name: "Generate Debate Case" })`). The exceptions use `data-testid`: Crossfire's controls, the Current Debate control, strip and dashboard, and the voice controls (`voice-mode`, `voice-mic`). Use `exact: true` for short names such as `Start` or `Save`, because the header's `Start debate` also matches `Start`. Never use coordinates.
Selectors: use accessible names and roles as the feature files list them (`getByRole("button", { name: "Generate debate case" })`). The exceptions use `data-testid`: Crossfire's controls, the Current Debate control, strip and dashboard, and the voice controls (`voice-mode`, `voice-mic`). Use `exact: true` for short names such as `Start` or `Save`, because the header's `Start debate` also matches `Start`. Never use coordinates.

## Agentic tests and exploration

Expand All @@ -122,7 +124,7 @@ $H e2e cache ls # recorded agent flo

- `e2e` runs `doctor` first and refuses a broken stack, like `drive`. It turns e2e telemetry off and prints `EVIDENCE <dir>`, which holds `summary.md`, `report.json`, and per-attempt screenshots, traces, and failure videos.
- The suite is tool journeys (tag `journey`) and a page sweep (tag `pages`) of every student and public page in English, Spanish and Hungarian (not `/app/admin` or `/share/:code`). Every test fails on an uncaught error, `console.error` (React warnings included), a Supabase 5xx, horizontal overflow, or a request to a hosted project: `agentic/support/capture-errors.js` records them in the page. A failure that names `errors the page logged` is a real app error to fix, not test noise.
- The testing agent has its own OpenRouter models: `inclusionai/ling-3.0-flash-vl` acts (test steps on a cache miss, and explorations) and `meta/muse-spark-1.3-contributor` judges. `E2E_AGENT_MODEL` and `E2E_JUDGE_MODEL` override them; the model is not part of the replay key. The key comes from `OPENROUTER_API_KEY`, `LIVE_OPENROUTER_API_KEY`, or the live keys file, and is needed in fake mode too. A recorded `agent.act` replays with no model call; every judgment and every exploration step is a call. Without a key, agent tests skip. An OpenRouter error such as `[Meta] The requested model was not found` is infrastructure: rerun with `--last-failed`. The Muse Spark judge cannot act.
- The testing agent has its own OpenRouter models: `anthropic/claude-haiku-5.5` acts (test steps on a cache miss, and explorations) and `anthropic/claude-sonnet-5.5` judges, both pinned to the Anthropic provider (BYOK) with fallbacks off. Haiku is not reliable enough to judge screens: it reads content below the fold as cut off. `E2E_AGENT_MODEL` and `E2E_JUDGE_MODEL` override them but must be `anthropic/` models; the model is not part of the replay key. The key comes from `OPENROUTER_API_KEY`, `LIVE_OPENROUTER_API_KEY`, or the live keys file, and is needed in fake mode too. A recorded `agent.act` replays with no model call; every judgment and every exploration step is a call. Without a key, agent tests skip. An OpenRouter error naming Anthropic (an outage, or the key out of credit) is infrastructure: rerun with `--last-failed`.
- `--session student` starts an exploration signed in as a fresh demo user, minted by `agentic/sessions.e2e.ts`. `--agent` picks a persona: `first-timer`, `coach`, `edge-input`, or `hungarian`. `--target mobile` explores the phone-sized viewport.
- Explorations report `issue` (functional) and `warning` (cosmetic) findings, and exit 1 when there is an issue. Treat a finding as a lead: the stack serves Vite dev, so a route that is still compiling can look dead, and fake mode answers every motion with free-transport text. Prove a finding with a repro test tagged `repro` before you report it as a bug.
- Several explorations can run at once (a bug bash), because each gets its own evidence directory. They share this one stack, so give each a different area.
Expand Down Expand Up @@ -172,6 +174,8 @@ It never touches `.verify/artifacts/` or `.verify/logs/`, and it is safe to run
## Gotchas

- Live runs are slow: sparring and crossfire take several minutes each because the model must reason. Use `-g` to run one test while iterating.
- Tailwind v4 is configured in `src/index.css` (`@theme`, `@custom-variant`, `@utility`); there is no `tailwind.config.ts`. Edits to `src/` and `src/index.css` apply on reload.
- The fake provider streams a structured answer in 24-character chunks 10 ms apart when the request asks to stream, so a Generate draft is on screen for about a second in fake mode; `fake.streamDelay(ms)` slows it for one test (the next reset restores it). Short replies (a Crossfire turn) finish in well under that, so prove those with `expectStreamed` rather than by catching the draft.
- The fake provider rejects prompts it doesn't recognize. If a prompt change makes a feature fail with a provider error, update `e2e/full-stack/fake-openrouter.mjs`. Don't mock around it.
- Once, the fake-provider container was SIGKILLed about 20 seconds after `up`, and the cause was never found. Doctor catches this, and `drive` refuses to run until you `down && up`.
- Demo-code users are Pro with a daily limit of 999. To test quota or tier paths, change `user_settings` through `admin` inside the recipe, as `e2e/full-stack/case-generation.spec.ts` does.
Expand Down
11 changes: 8 additions & 3 deletions .claude/skills/verify-debatelab/bin/verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
REPO="$(git -C "$SKILL_DIR" rev-parse --show-toplevel)"
cd "$REPO"
source "$REPO/.superset/lib/lock.sh"
source "$REPO/.superset/lib/supabase-cli.sh"
use_pinned_supabase_cli "$REPO"

DB_LOCK="$HOME/.superset/debatelab-db.lock"
FAKE_PROVIDER=debatelab-fake-openrouter
Expand All @@ -38,8 +40,11 @@ STATE="$STATE_DIR/stack.env"
USERS="$STATE_DIR/users.tsv"
ARTIFACTS="$VERIFY_ROOT/artifacts" # evidence; never removed by this script
PROJECT_ID="$(basename "$REPO")" # supabase/config.toml has no project_id
# Adam's standing choice for live verification: the cheap contributor tier.
LIVE_MODEL="${VERIFY_LIVE_MODEL:-meta/muse-spark-1.3-contributor}"
# Live verification runs on Claude Haiku through DebateLab's Anthropic key
# (BYOK in OpenRouter). Other families bill OpenRouter credits, so they are
# refused; the proxy pins the rewritten call to the Anthropic provider.
LIVE_MODEL="${VERIFY_LIVE_MODEL:-anthropic/claude-haiku-5.5}"
case "$LIVE_MODEL" in anthropic/*) ;; *) printf 'FAIL VERIFY_LIVE_MODEL must be an anthropic/ model (Anthropic BYOK), not %s\n' "$LIVE_MODEL" >&2; exit 1 ;; esac
LIVE_KEYS_FILE="${VERIFY_LIVE_KEYS_FILE:-$HOME/.config/debatelab/live-verify.env}"

say() { printf '%s\n' "$*"; }
Expand Down Expand Up @@ -297,7 +302,7 @@ cmd_e2e() {
[ -n "$key" ] && export OPENROUTER_API_KEY="$key"
fi
if [ -n "${OPENROUTER_API_KEY:-}" ]; then
say "info testing agent: OpenRouter actor ${E2E_AGENT_MODEL:-inclusionai/ling-3.0-flash-vl}, judge ${E2E_JUDGE_MODEL:-meta/muse-spark-1.3-contributor} (replayed steps make no model call)"
say "info testing agent: OpenRouter actor ${E2E_AGENT_MODEL:-anthropic/claude-haiku-5.5}, judge ${E2E_JUDGE_MODEL:-anthropic/claude-sonnet-5.5}, Anthropic BYOK only (replayed steps make no model call)"
else
say "info no OpenRouter key: tests with agent steps will skip"
fi
Expand Down
Loading
Loading