Remove the no-model demo path; make setup the single road to a real first conversation - #474
Merged
Merged
Conversation
…irst conversation The first conversation decides whether there is a second one. The text-only demo (fake runtime: the same hard-coded reply every turn) and the scripted tutorial taught a new player 'this is a bad chatbot' at the exact moment of maximum skepticism. Both are gone from every user-facing surface; the fake/scripted runtimes remain as internal test/dev infra. Fixes #473 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C9WmcidRL3ABq7qhWHUsrG
…uites The issue-#473 backstop refuses unpinned sessions that would resolve to the fake/scripted runtimes; these suites run outside services/convsim-core and were missed in the first pass. Swap-runtime tests stay unpinned and activate a real selection instead, so they keep following app.state.runtime. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C9WmcidRL3ABq7qhWHUsrG
charneykaye
added a commit
that referenced
this pull request
Aug 22, 2026
Follow-up 360 cleanup pass over #474. Three containers in the first-run welcome and installing steps carried an `aria-label` equal to their own visible heading: - Welcome "Not a chatbot. Not a mirror." promise note - Installing "While that downloads…" section - Installing "Your first missions" list (labelled by its visible `<h3>`) Each caused a screen reader to announce the heading twice ([duplicating visible text in aria-label is a documented anti-pattern](https://www.w3.org/WAI/ARIA/apg/practices/names-and-descriptions/)). Removed the redundant labels; the visible headings remain the accessible names, and content is announced once. The one genuinely non-redundant label — the how-to-play ordered list, whose "How to play" heading is not rendered visually — is intentionally kept. No visual change. tsc clean, eslint unchanged from baseline, `vite build` clean, and FirstRunWizard's 72 tests (including the while-you-wait content assertions) pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01C9WmcidRL3ABq7qhWHUsrG Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The first conversation a new player has decides whether there is a second one — and its one job is to prove this is not a chatbot: the entity across the table has its own universe of concern, and the player succeeds by investigating it, appealing to it, and compelling within it. The no-model paths did the opposite. The
fakeruntime returns the same hard-coded reply on every turn, forever ("Hello there. I am a simulated NPC."), and the scripted tutorial is on rails. Offering either as first contact taught "this is a bad chatbot" at the exact moment of maximum skepticism — then lost the player for good.This PR removes the entire no-model conversation offering from every user-facing surface and reinvests the first-run flow in getting the player to a real conversation. Closes #473.
What's removed
DemoConfirmStepand thedemo-warningstep are deleted.handleConfirmDemo,handleStartTutorial, thedemoonboarding outcome write, and thetutorialComplete/tutorialInstallId/activeRuntimeHintlocalStorage keys (stale legacy values are inert).What replaces it
Backstop (API-level guarantee)
POST /api/sessionsnow refuses (409, with a clear finish-setup message) any session that would resolve to thefakeorscriptedruntime unless the request pins that runtime explicitly — covering both a persisted model-free selection and the config-defaultfakeshared runtime on a profile that never installed a model. Tests and dev tooling keep the explicit pin; a player can never fall through to a puppet by accident. Thefake/scriptedruntimes and thefirst_words_tutorialscenario remain as internal test/dev infrastructure.Migration
A legacy profile with a recorded
demooutcome no longer counts as having a model:GET /api/setup/statusresolvesincomplete(nevernever-run, so no wizard bounce), which shows the existing non-blocking finish-setup banner steering the user to install the real thing.Verification
tscclean; eslint identical to main (no new issues); i18n audit clean.actionlintclean on the workflow change.64cff7df).🤖 Generated with Claude Code
https://claude.ai/code/session_01C9WmcidRL3ABq7qhWHUsrG