486 lines
33 KiB
Markdown
486 lines
33 KiB
Markdown
# StoryTellurX V2 — persona-owned interface and implementation plan
|
||
|
||
Updated 2026-09-08. Every implementation and acceptance item is open. This document does not certify any existing code as complete. Code below is proposed unless labelled **Before** or **Reference**.
|
||
|
||
## Reopened scope
|
||
|
||
- [ ] Six-step onboarding: language, introduction, warnings, double confirmation, intensity, model choice.
|
||
- [ ] Contextual input/output moderation and visible consent rewrites.
|
||
- [ ] Panic, pause/resume, voluntary reporting and export.
|
||
- [ ] No default transcript retention and provider disclosures.
|
||
- [ ] Persona-specific natural, manual and emergency endings.
|
||
- [ ] Full narrative state, boundaries, anatomy terminology and progression.
|
||
- [ ] Persona archives, Jacob and canonical endings.
|
||
- [ ] Safe image generation, descriptions and failure handling.
|
||
- [ ] Compact persona interfaces, public explanations, reply controls and accessibility.
|
||
- [ ] Landing-to-app prompt handoff.
|
||
- [ ] Authored branches, deterministic direction and moderator summaries.
|
||
- [ ] Provider/browser QA, separate V1/V2 deployments and coordinated landing launch.
|
||
- [ ] Opt-in research testing, reproducible comparisons and on-device model exploration.
|
||
|
||
The detailed P0/P1/P2 checklist is copied below from the corrected tracker. Planning additions here do not mark tracker requirements complete.
|
||
|
||
## 1. Extend the real landing-card/button technique everywhere
|
||
|
||
Source: `../storytellurx-tanstack`, the landing repository. Read:
|
||
|
||
- `src/content/persona-card-themes.ts`: typed skin/texture/tag/ornament registry for eight personas.
|
||
- `src/components/persona-tile.tsx`: semantic link; separate decorative texture and ornament; shared content skeleton.
|
||
- `src/styles.css`: per-world surfaces, borders, typography, textures, shadows and hover states.
|
||
- `src/components/ui/button.tsx`: Base UI element composition, separate background/content, stable loading dimensions, keyboard focus.
|
||
|
||
**Reference — actual landing registry:**
|
||
|
||
```ts
|
||
cybelle: {
|
||
skin: "cybelle",
|
||
textureSrc: "/persona-tex/cybelle.jpg",
|
||
tag: "déesse porno · confetti",
|
||
ornament: "confetti",
|
||
},
|
||
```
|
||
|
||
**Reference — actual landing composition:**
|
||
|
||
```tsx
|
||
<span aria-hidden className="persona-skin__tex" />
|
||
<PersonaOrnament theme={theme} />
|
||
<span className="persona-skin__body">
|
||
```
|
||
|
||
The V2 equivalent uses the existing StyleX persona registry. Keep accessible behavior shared; each persona supplies its complete visual vocabulary and optional presentation components. No Neon styles or imported landing Tailwind stylesheet. No independent copies of consent, submission or moderation logic inside persona components.
|
||
|
||
### Owning source change: `src/registries/persona-ui-contract.ts`
|
||
|
||
**Before — existing extension points:**
|
||
|
||
```ts
|
||
export type PersonaBackgroundProps = { imageUrl: string | null; opacity?: number };
|
||
// PersonaUI already owns getTheme, styles, titleMotion, statusVariant and components.
|
||
// Its components already include ThoughtDropdown, Metrics, Bubble, Composer,
|
||
// Suggestion, SubmitIndicator, Image, Status, Background and StateChanges.
|
||
```
|
||
|
||
**After — extend that contract, retain all existing slots:**
|
||
|
||
```diff
|
||
-export type PersonaBackgroundProps = { imageUrl: string | null; opacity?: number };
|
||
+export type PersonaBackgroundProps = {
|
||
+ imageUrl: string | null;
|
||
+ opacity?: number;
|
||
+ texture: PersonaTexture;
|
||
+};
|
||
+
|
||
+export type PersonaTexture = {
|
||
+ src: string;
|
||
+ srcSet: string;
|
||
+ opacity: number;
|
||
+ blendMode: "normal" | "multiply" | "overlay" | "soft-light";
|
||
+ position: string;
|
||
+};
|
||
+
|
||
+export type PersonaSurface =
|
||
+ | "shell" | "onboarding" | "picker" | "status" | "transcript"
|
||
+ | "composer" | "thought" | "menu" | "dialog" | "report"
|
||
+ | "pause" | "ending" | "settings" | "history";
|
||
+
|
||
+export type PersonaSurfaceStyles = Record<PersonaSurface, StyleXStyles>;
|
||
```
|
||
|
||
Extend `PersonaUI` with `texture`, `surfaces`, and typed `Surface`/`Ornament` presentation slots. Existing `components`, `styles` and `getTheme` remain the source of truth. Each `src/personas/<id>/persona.ts` must satisfy the extended contract; no silent Samantha fallback for missing skins.
|
||
|
||
**After — proposed shared composition in `src/components/persona-surface.tsx`:**
|
||
|
||
```tsx
|
||
export function PersonaSurface({
|
||
persona,
|
||
surface,
|
||
children,
|
||
}: {
|
||
persona: PersonaUI;
|
||
surface: PersonaSurface;
|
||
children: ReactNode;
|
||
}) {
|
||
const Ornament = persona.components.Ornament;
|
||
return (
|
||
<div {...stylex.props(base.surface, persona.surfaces[surface])}>
|
||
<Ornament surface={surface} />
|
||
<div {...stylex.props(base.content)}>{children}</div>
|
||
</div>
|
||
);
|
||
}
|
||
```
|
||
|
||
Use one page background layer, not a newly decoded full-size texture under every message. Ornament implementations are decorative, `aria-hidden`, and cannot intercept pointer events. Theme the Base UI popup/dialog portal explicitly so it inherits the active persona even outside the shell DOM subtree.
|
||
|
||
### Persona ownership covers every surface
|
||
|
||
| Surface | Persona owns | Shared behavior owns |
|
||
| ---------------------- | ------------------------------------------------------------- | ------------------------------------------------ |
|
||
| Shell/background | Texture, tint, frame, grain, surface hierarchy | Loading, fallback, responsive sizing |
|
||
| Onboarding | Panel, progress, heading, choices, Next/Back styling | Step order, consent, validation, focus |
|
||
| Picker | Card/link, avatar, ornament, selected treatment | Navigation and accessible names |
|
||
| Status/metrics | Typography, optical title padding, exact metric SVG treatment | Values and accessible metric semantics |
|
||
| Messages/rewrite | Bubble, role contrast, separators, rewrite treatment | Turn content, safe replacement, reading order |
|
||
| Composer/replies | Input, suggestion treatment, send indicator | Draft, selection, submit, abort, disabled states |
|
||
| Thought chain | Dots, rail, compact typography, dropdown and focus | One disclosure, original explanation text |
|
||
| Menus/dialogs | Trigger, popup, items, backdrop, borders | Keyboard navigation, focus trap and restoration |
|
||
| Panic/pause/ending | Recognizable universe-specific presentation | Immediate stop, resume/end, canonical text |
|
||
| Report/export | Controls, review panel and feedback | Explicit attachment consent, export payload |
|
||
| Settings/About/history | Forms, tabs, empty/error/loading states | Preferences, disclosures, deletion and recovery |
|
||
|
||
Add semantic StyleX variables to `src/styles/design-tokens.stylex.ts` for panel/popover surfaces, separators, focus, texture opacity, corner/border treatment and compact spacing. Each persona’s `theme.stylex.ts` supplies values. Keep layout-specific optical corrections in its `styles.stylex.ts`.
|
||
|
||
Preserve recent requirements: one compact thought disclosure; dots/rail/chevron aligned; full French texts such as “Logique d’état”; persona-owned dropdown; word wrapping never splits individual letters; Xixi metric groups use a column; send remains fixed height and bottom-aligned; title padding belongs to each persona. Do not replace existing metric SVG artwork with raster textures.
|
||
|
||
### Reference/current style delta and public proof
|
||
|
||
Values below are source declarations, not claimed browser measurements. Capture computed styles and screenshots on the actual public routes before changing UI.
|
||
|
||
| Property | Landing reference | Current V2 evidence | Intended delta |
|
||
| -------------------- | --------------------------------------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------- |
|
||
| Samantha texture | opacity `.16`, blend `multiply` | Generic `ConversationBackground` takes image URL/opacity | Persona-owned decorative texture, independently from scene image |
|
||
| Cybelle texture | opacity `.26`, blend `overlay` | Same generic background component | Persona supplies texture/blend/tint for each universe |
|
||
| Cybelle frame | `3px double #ffd76a`, radius `10px`, plum gradient | Chat styles supplied separately | Translate reference material into StyleX surface roles |
|
||
| Samantha frame | pink gradient, `3px` border, radius `20px`, inset shadows | Existing persona style contract is chat-oriented | Extend material consistently to onboarding, menus and endings |
|
||
| Background semantics | Decorative span `aria-hidden`, `pointer-events:none` | Decorative background `aria-hidden`, empty image alt | Preserve; informative generated images get meaningful alt text |
|
||
| Activation | Card is link; generic button supports Base UI `render` | Suggestion is native button, `aria-pressed` | Preserve link/button semantics and focus throughout |
|
||
| Motion | Mostly static CSS, inexpensive hover | Some V2 metric and suggestion motion | Static texture layers; bound active effects and respect reduced motion |
|
||
|
||
Proposed public test: `src/tests/public-persona-surfaces.spec.ts`, built on existing public conversation fixtures and API mocks. Add stable `data-slot` hooks to owning components when implementing; test through `/start` and `/chat`, not an isolated component demo.
|
||
|
||
```ts
|
||
for (const personaId of activePersonaIds) {
|
||
test(`${personaId}: complete universe and compact thought chain`, async ({ page }) => {
|
||
// Complete the public onboarding with mock provider responses.
|
||
await enterPersonaThroughOnboarding(page, personaId);
|
||
const trigger = page.getByRole("button", { name: "Afficher les explications" });
|
||
await trigger.click();
|
||
await expect(trigger).toHaveAttribute("aria-expanded", "true");
|
||
await expect(page.getByText("Logique d’état", { exact: true })).toBeVisible();
|
||
await expect(page.locator('[data-slot="persona-texture"]')).toHaveCSS("pointer-events", "none");
|
||
await page.getByRole("button", { name: "Paramètres", exact: true }).click();
|
||
await expect(page.getByRole("dialog")).toBeVisible();
|
||
await expect(page).toHaveScreenshot(`${personaId}-settings.png`);
|
||
});
|
||
}
|
||
```
|
||
|
||
The helper, accessible copy, exported active IDs and new hooks above are proposed. Also measure actual glyph bounds/title optical alignment, chevron/dot x positions, no horizontal overflow at 320/390px, send height after multiline input, focus visibility/restoration, popup theme inheritance, reduced motion, contrast over every texture, and keyboard-only onboarding/panic. Validate Samantha and Cybelle first, then the whole registry.
|
||
|
||
## 2. Implement requirements through shared state and persona presentation
|
||
|
||
### `src/routes/start.tsx` — replace the two-choice screen with the consent flow
|
||
|
||
**Before — actual current JSX:**
|
||
|
||
```tsx
|
||
<PublicShell>{personaId ? <ModelPicker personaId={personaId} /> : <PersonaPicker />}</PublicShell>
|
||
```
|
||
|
||
**After — proposed owner components:**
|
||
|
||
```tsx
|
||
<PublicShell>
|
||
<OnboardingFlow initialPersonaId={personaId} />
|
||
</PublicShell>
|
||
```
|
||
|
||
```ts
|
||
// New src/standard-schemas/onboarding.schema.ts; validate before /chat generation.
|
||
type OnboardingStep =
|
||
"language" | "introduction" | "warning" | "confirmation" | "intensity" | "model";
|
||
type SessionConsent = {
|
||
briefVersion: string;
|
||
adultConfirmed: true;
|
||
experimentalRiskConfirmed: true;
|
||
language: "fr" | "en";
|
||
intensity: "beginner" | "confirmed" | "expert";
|
||
modelId: ModelId;
|
||
};
|
||
```
|
||
|
||
Guard direct `/chat` entry and the server generation request. Never trust a client-only checkbox. Separate preference/confirmation storage from transcript storage. Preserve a landing draft through Next/Back and persona choice without submitting it. Use the neutral gateway theme before a world is selected, then the selected persona throughout the flow.
|
||
|
||
### `src/routes/api/ai.chat.ts` and server response middleware
|
||
|
||
**Before — actual provider call shape:**
|
||
|
||
```ts
|
||
const prepared = createChatRequest(params.messages, context.data);
|
||
return toServerSentEventsResponse(
|
||
chat({
|
||
...prepared,
|
||
adapter: createModelAdapter(context.data.modelId),
|
||
stream: true,
|
||
// Existing IDs, abort controller and middleware follow.
|
||
}),
|
||
{ headers },
|
||
);
|
||
```
|
||
|
||
**After — proposed pipeline boundary:**
|
||
|
||
```ts
|
||
// New orchestration module wraps the existing TanStack transport.
|
||
const input = await moderateInput({ messages, state, signal });
|
||
const candidate = await generateCandidate({ input, state, signal });
|
||
const safeTurn = await moderateCompleteOutput({ candidate, state, signal });
|
||
const nextState = directNarrativeState({ state, safeTurn, branch });
|
||
// Emit only approved public text/state; status events can stream while waiting.
|
||
yield * emitApprovedTurn({ safeTurn, nextState, runId, threadId });
|
||
```
|
||
|
||
Keep existing TanStack event IDs/reconnect/abort semantics; do not invent a parallel chat store. Extend `src/server/create-response-middleware.server.ts` so unapproved partial JSON never reaches the visible transcript. Tests must prove provider-originated prohibited output is held, not merely that the input moderator catches keywords. Moderate images before visibility too.
|
||
|
||
Add typed director/ending/report modules, integrated with the current narrative schemas and `apply-narrative-state-patch.ts`. Define authored branches explicitly; do not let model patches bypass hard boundaries or consent. Keep public summaries separate from private reasoning. Panic invalidates in-flight runs, blocks late response commits, and renders persona-owned pause/ending UI immediately.
|
||
|
||
## 3. Local background generation — M1 / 16 GB first
|
||
|
||
This section plans a local asset-production pipeline. Generate authored atmospheric textures on the Mac, then serve small static assets in the website. Model weights do not ship to the browser or run inside the Deno deployment. Dynamic narrative imagery is a separate moderated runtime feature from the tracker.
|
||
|
||
### Measured update — 2026-09-08
|
||
|
||
Local benchmark completed on the available **M1 Pro / 16 GB**, not a base M1. [Results, raw measurements and samples](assets/backgrounds/benchmarks/2026-09-08/README.md).
|
||
|
||
- **Recommended draft path:** SD-Turbo FP16 + Metal + TAESD, 512px, one step: **1.54 s warm median**, 1.61 s p95 (10 warm images).
|
||
- **Recommended material exploration:** same engine, two steps with varied persona prompts: **2.28 s warm median**, 2.53 s p95 (20 warm images), no additional swap growth in that trial.
|
||
- First PNG with the resident-tool/shader caches available took approximately 13–14 seconds from process launch; warm figures require keeping the model loaded.
|
||
- Klein 4-bit: 55.37 s for the first image, substantial swap growth and a slower incomplete warm image; rejected for this workload.
|
||
- Direct Metal convolution was slower; use the default path. Full VAE takes about 5.47 s warm at one step.
|
||
- Texture quality still needs persona review: pink satin and crystal samples are promising; the plum/gold prompt drifts brown. These measurements do not validate final UI readability, all eight worlds, 1024px output, browser frame rate or base-M1 performance.
|
||
|
||
All product-delivery checkboxes remain open. The benchmark results supersede the unmeasured hypotheses below for this hardware only.
|
||
|
||
### Candidate selection, researched 2026-09-08
|
||
|
||
| Candidate | Proposed benchmark configuration | Decision |
|
||
| --------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
||
| stable-diffusion.cpp + SD-Turbo | Metal; FP16 baseline; 512×512; 1, then 2–4 steps | First speed baseline for abstract backgrounds |
|
||
| MFLUX + FLUX.2 Klein 4B distilled | MLX; 4-bit; 512×512; 4 steps | First quality/speed challenger; preferable to starting with legacy 12B FLUX.1 |
|
||
| MFLUX + Z-Image Turbo | MLX; 4-bit; 512×512; documented step schedule | Quality fallback if the first two fail persona fidelity |
|
||
| Apple Core ML Stable Diffusion | Compatible converted model and actual M1 compute configuration | Additional fallback only if measured end-to-end results justify conversion/tooling |
|
||
|
||
Inference: simple textures need less semantic precision than characters, so a small distilled SD model may give the best iteration speed. This was the pre-benchmark hypothesis; see the measured update above for M1 Pro results. Few inference steps and quantized weight sizes do not establish total latency or peak unified-memory use.
|
||
|
||
Sources:
|
||
|
||
- [stable-diffusion.cpp](https://github.com/leejet/stable-diffusion.cpp): Metal and SD-Turbo support; pin a tested commit because CLI options evolve.
|
||
- [SD-Turbo model card](https://huggingface.co/stabilityai/sd-turbo): 1–4 steps, preferred 512×512, no classifier-free guidance/negative prompt in its Diffusers recipe. Verify equivalent C++ sampler configuration against a reference output.
|
||
- [MFLUX FLUX.2 documentation](https://github.com/mflux-community/mflux/blob/main/src/mflux/models/flux2/README.md): distilled 4B, four steps, quantization; initial full-weight download can be about 15 GB, distinct from resident memory.
|
||
- [MFLUX](https://github.com/mflux-community/mflux): native MLX, quantization, metadata export and Z-Image support.
|
||
- [Apple Core ML implementation](https://github.com/apple/ml-stable-diffusion): alternative Apple hardware route; its published device/configuration results are not a base-M1 16 GB promise.
|
||
|
||
### Proposed reproducible tooling
|
||
|
||
```text
|
||
scripts/backgrounds/
|
||
generate.py # One engine loaded per process; sequential seed queue
|
||
benchmark.py # Cold/warm timing, memory, swap delta, failures
|
||
export.py # Selected PNG -> responsive WebP/AVIF + manifest
|
||
assets/backgrounds/
|
||
prompts.json # Persona-specific art direction and fixed seeds
|
||
manifest.json # Engine/model revision, hash, seed, settings, provenance
|
||
benchmarks/ # Actual hardware + raw runs, no fabricated results
|
||
public/persona-tex/
|
||
<id>-512.webp
|
||
<id>-1024.webp
|
||
```
|
||
|
||
Use an isolated, pinned environment and model cache outside tracked assets. Reuse installed tools/models first. Inspect the installed CLI help and lock the chosen version before scripting. Example MFLUX trial based on the upstream CLI; not executed by this planning change:
|
||
|
||
```sh
|
||
mflux-generate-flux2 --model flux2-klein-4b -q 4 --steps 4 \
|
||
--width 512 --height 512 --seed 42 \
|
||
--prompt "Abstract plum velvet and delicate gold paper flecks, softly lit, quiet center, atmospheric material texture, no lettering, no people"
|
||
```
|
||
|
||
```ts
|
||
// Proposed assets/backgrounds manifest record.
|
||
type BackgroundAsset = {
|
||
personaId: string;
|
||
engine: "mflux" | "stable-diffusion.cpp" | "coreml";
|
||
engineRevision: string;
|
||
modelRevision: string;
|
||
weightsSha256: string;
|
||
prompt: string;
|
||
seed: number;
|
||
width: number;
|
||
height: number;
|
||
steps: number;
|
||
quantization: string;
|
||
output: string;
|
||
reviewed: boolean;
|
||
};
|
||
```
|
||
|
||
### M1 acceptance gate — see measured M1 Pro update above; base M1 remains unverified
|
||
|
||
- [ ] Verify **base M1 and 16 GB unified RAM**, OS, GPU cores and power mode; do not extrapolate from M1 Max/M3/CUDA results.
|
||
- [ ] Compare identical authored prompts and seeds across candidates; batch size one; one model resident; no simultaneous image and local text-model inference.
|
||
- [ ] Record model download/setup separately, then cold load and ten warm generations, including text encoding and decode. Report median/p95, peak process footprint plus available Metal/MLX memory metrics, memory pressure and swap growth.
|
||
- [ ] Repeat with the browser and V2 dev server open; then a 20-image sequential soak test for memory growth and thermal slowdown.
|
||
- [ ] Provisional speed target: warm 512px median ≤10 seconds and p95 ≤15 seconds. This is a requested engineering target, **not an observed result or guarantee**. If missed, report actual results and use precomputed assets; never claim “instant generation”.
|
||
- [ ] Provisional memory target: generation footprint ≤8 GB, no sustained swap growth or pressure escalation, browser stays responsive. Confirm actual whole-system behavior; quantized weights alone are insufficient.
|
||
- [ ] Compare output in the actual UI: readable text, correct palette/material, quiet center, no unwanted lettering/faces, no seams when tiled. Pick the fastest candidate that passes visual review.
|
||
- [ ] Test 512px first; produce 1024px only for selected final assets if memory and timing pass. Upscale/export sequentially after inference unloads; avoid a second large model in memory.
|
||
- [ ] Cache by model revision + prompt + seed + settings; reuse one texture across surfaces, lazy-load other worlds; no generation on navigation or each chat turn.
|
||
- [ ] Record model license/provenance with exported assets. Asset prompts contain authored world descriptions, not conversation transcripts.
|
||
|
||
### Per-persona background direction
|
||
|
||
| Persona | Material prompt direction | Existing landing ornament to reuse |
|
||
| ---------- | ----------------------------------------------------------------- | -------------------------------------------------------- |
|
||
| Samantha69 | Pastel pink translucent gel, pearlescent satin, soft light | Sparkles |
|
||
| Nelly | Lagoon ripples, aqueous haze and submerged light | Waveform |
|
||
| Hisoka | Electric locker-room reflections, dark wet tile, neon edges | Neon rim |
|
||
| Xixi | Cold translucent facets, fractured crystal, restrained melancholy | Facets |
|
||
| Cybelle | Plum velvet, gold flecks, theatrical confetti | Confetti |
|
||
| Galatée | Pale clay, stone dust, sculptural mineral grain | Laurel |
|
||
| Polaire | Cold lab glass, spatial haze, restrained instrument texture | HUD |
|
||
| Jacob | Derive from the authored archive before writing a final prompt | Landing facets are a placeholder, not approved direction |
|
||
|
||
Use decorative raster textures only for material/atmosphere. Keep typography, icons, borders, metric SVG filters, focus indicators and interaction geometry in code. Start with existing landing textures as visual references; generate variations locally when executing this stage.
|
||
|
||
## 4. Scope reconciliation and order
|
||
|
||
- [ ] Reconcile tracker’s four active personas with the current seven selectable worlds. Preserve all archives and build presentation support for the whole registry; do not silently remove current personas.
|
||
- [ ] Reconcile one-message pagination with the current deliberately refined scrolling chat before replacing navigation.
|
||
- [ ] Reconcile exactly three primary replies with the current suggestion contract.
|
||
- [ ] Reconcile model/language settings outside chat with the current model dropdown and language behavior.
|
||
- [ ] Verify the latest supplied brief: tracker references disagree about which Google Doc tab contains V2. Local records were read; remote brief contents were not fetched for this plan.
|
||
|
||
Execution order:
|
||
|
||
1. Capture landing/current reference styles; inventory tokens and surfaces; resolve recorded product conflicts.
|
||
2. Benchmark local image candidates on M1 16 GB and select reviewed starter textures.
|
||
3. Extend persona contract and shared UI primitives; prove Samantha/Cybelle through onboarding, chat, popup and ending; propagate to every persona.
|
||
4. Implement onboarding, moderation, director, pause/report/endings and privacy through shared behavior with those presentation slots.
|
||
5. Complete imagery, handoff, explanations and research controls; run the detailed acceptance matrix below.
|
||
6. Validate configured providers, accessibility and actual device performance; deploy separately from V1 and coordinate the landing launch.
|
||
|
||
No checkbox is completed by writing this plan. Code examples are intended implementation shapes; browser tests remain open; local M1 Pro hardware benchmark results are linked above, and base-M1 acceptance remains open.
|
||
|
||
## Detailed requirements copied from the corrected tracker
|
||
|
||
Source: `../bureaudouble-tracker/issuers/bureaudouble/clients/fucking-tech/projects/storytellurx-v2/docs/spec-2026-08-31-v2-requirements.md` (status corrected 2026-09-08). Keep completion status synchronized only after implementation and acceptance evidence.
|
||
|
||
## P0 — release blockers
|
||
|
||
### Safety and privacy
|
||
|
||
- [ ] Run a **contextual safety agent before generation**. A lexical check may be a fast signal but
|
||
cannot be the only control: the February workshop showed contextual corpse/incest scenarios that
|
||
did not necessarily contain the prohibited label.
|
||
- [ ] Run a **contextual safety agent on the complete generated output before it reaches the user**.
|
||
The February failures were initiated by the creative model, so checking only user input repeats the
|
||
documented failure mode.
|
||
- [ ] Prohibit rape/coercion, incest, bestiality/zoophilia, pedophilia/minors, and necrophilia/corpses.
|
||
- [ ] Preserve the project’s rewrite mechanic: crossing a hard limit yields a visibly adjacent,
|
||
consensual adult rewrite rather than only a refusal or an HTTP error.
|
||
- [ ] Keep persona agency legible. A rewrite caused by overriding an entity’s consent is distinct from
|
||
an infrastructure/safety failure and has its own graphical state and motion.
|
||
- [ ] Put an unambiguous **panic button on every turn**. It immediately stops generation and freezes
|
||
the scene; the participant can resume, take time out, or end.
|
||
- [ ] After ending through panic, offer a report funnel. Transcript sharing/export is **off by default,
|
||
voluntary, and initiated by the participant**.
|
||
- [ ] Persist no transcript in StoryTellurX browser storage or server storage by default. Preferences
|
||
and an ephemeral in-flight reconnection buffer are acceptable when disclosed.
|
||
- [ ] Explain that StoryTellurX itself does not retain the discussion, while Gemini/OpenRouter/Nous or
|
||
another selected provider may process or retain requests under its own terms.
|
||
|
||
### Stability and endings
|
||
|
||
- [ ] A provider, quota, schema, network, or stream failure triggers a short **scripted emergency
|
||
ending** and graphical offboarding, not a dead input or a generic error alone.
|
||
- [ ] Keep the canonical persona-specific scripted ending for all eight personas and use it for
|
||
voluntary stop, natural closure, and emergency closure.
|
||
- [ ] V1 remains available on its own URL for conference/research comparison; V2 has a separate URL.
|
||
- [ ] Pin and disclose exact model/provider versions. Provider lifecycle changes must fail clearly and
|
||
leave an upgrade path.
|
||
|
||
### Full narrative contract
|
||
|
||
- [ ] Port the actual V1 structured engine instead of reducing it to a generic chat response:
|
||
persona ID, progression step, phase, arousal/peak potential, intimacy, entity consent, participant
|
||
experience/intensity, modality, title/summary, participant-named anatomy, desires, limits,
|
||
inclusive-toolkit state, and an inspectable state diff on every turn.
|
||
- [ ] Only name participant anatomy after they have supplied the terms. Gender never implies genitals.
|
||
- [ ] Preserve short segmented entity messages and written response starters. The participant should
|
||
be invited back into the exchange rather than receive a monologue.
|
||
- [ ] Preserve participant-facing “under the hood” explanations as distinct concise fields:
|
||
state change, play/strategy, persona archive/context, suggested-answer strategy, and rewrite reason.
|
||
These are designed summaries, not private chain-of-thought.
|
||
- [ ] Preserve the persona’s full hand-written archive, imagery, agency, and prompt history. Jacob uses
|
||
prompt 46; prompts 43–45 stay as provenance.
|
||
- [ ] Support `text` and `text + image`. Image generation follows the selected persona’s frame, goes
|
||
through the same output-safety gate, has alt text/status/error handling, and never blocks the text
|
||
turn from ending safely.
|
||
|
||
### Onboarding and control
|
||
|
||
- [ ] Use multiple full-screen steps with clear Next/Back controls; do not compress the consent tunnel.
|
||
- [ ] Step 1: language. French first; English is enabled only after French approval. Language is locked
|
||
for the session so the model cannot drift between French and English.
|
||
- [ ] Step 2: use the supplied StoryTellurX description, including the “entité abstraite et néanmoins
|
||
transpirante” and eight non-human worlds.
|
||
- [ ] Step 3: warning 1 states experimental/unexpected behavior, every prohibited category, inability
|
||
to guarantee perfect filtering, contact/report path, and voluntary history attachment.
|
||
- [ ] Step 4: a second explicit “êtes-vous vraiment sûr·e ?” confirmation with a route back to the
|
||
parent site.
|
||
- [ ] State 18+ only, not for minors, and not recommended for traumatized/vulnerable people; make
|
||
“enter at your own risk” legible without presenting the system as safe.
|
||
- [ ] Ask for a beginner/confirmed/expert intensity level before the first erotic turn so a participant
|
||
does not land immediately in excessive intensity.
|
||
- [ ] Step 5/6: Gemini proprietary vs Hermès open-source/open-weights model choice, exact version,
|
||
provider, processing caveat, and links. Do not show the model name inside the conversation.
|
||
- [ ] Returning participants may skip explanatory screens only after the prior confirmations are known;
|
||
reset/review lives in About.
|
||
|
||
### Conversation interface
|
||
|
||
- [ ] Use the landing-card worlds as the visual system for the four active V2 personas while retaining
|
||
all eight V1 archives. Retain Arizona Variable for headings and derive differentiation through axes,
|
||
color, layout, type behavior, and controlled motion.
|
||
- [ ] Make labels visually stronger than values in the state header. Keep model/language out of that
|
||
header and in global settings/About.
|
||
- [ ] Prefer one to five short message fragments, larger type, and user-controlled scrolling. Never
|
||
force-scroll someone who has moved away from the newest turn.
|
||
- [ ] Present exactly one participant message or entity fragment per screen. Previous/next controls,
|
||
keyboard arrows, and horizontal swipe move between screens without forcing the reader to the latest.
|
||
- [ ] Resolve the hierarchy between preset replies and free text. Show three primary written answers
|
||
without hiding the text field; filling the field is not the same as silently submitting it.
|
||
- [ ] Remove the unexplained `[E]` control. Errors have named actions such as Retry, End safely, and
|
||
Report.
|
||
- [ ] Put rationales directly beneath the relevant entity bubble/turn with a reveal/hide treatment that
|
||
keeps the machine legible without overwhelming the narrative.
|
||
- [ ] Motion may be maximal and persona-specific, but it must settle, honor reduced-motion settings,
|
||
preserve focus, and never outrank comprehension.
|
||
|
||
## P1 — launch-quality and research readiness
|
||
|
||
- [ ] Carry the landing-page input into the app as the first participant message after persona choice;
|
||
do not lose or auto-submit it unexpectedly.
|
||
- [ ] Provide starter prompts and fully written answers for blank-page moments.
|
||
- [ ] Make modality, intensity, boundaries, phase, intimacy, entity consent, persona/progression, and
|
||
the complete state diff inspectable each turn.
|
||
- [ ] Provide an explicit pause/resume state separate from permanent exit.
|
||
- [ ] Provide a privacy-safe local transcript export for voluntary reporting and research participation.
|
||
- [ ] Test the four active personas at mobile and desktop widths, both providers, both modalities,
|
||
natural ending, manual panic, every prohibited category, provider failure, schema failure, and
|
||
reconnect. Re-run the same matrix for archived personas if they are reactivated.
|
||
- [ ] User-test the preset/free-text ordering and message pagination/scroll behavior; do not treat the
|
||
current layout hypothesis as validated.
|
||
- [ ] Run a rigorous post-launch research test round and keep evidence opt-in; the app must be usable
|
||
for conference demos despite known provider limitations.
|
||
|
||
## P2 — model/research tracks
|
||
|
||
- [ ] Restrict generative AI to seven controlled authored branching points while a deterministic
|
||
director owns persona, progression, phase, intensity, consent, modality, anatomy, and limits.
|
||
This was promoted from the separately funded 25 June idea into the current scope on 31 August.
|
||
- [ ] Re-evaluate a fully on-device Hermès/WebLLM route so no conversation leaves the device. V1 proves
|
||
the technical direction but not launch reliability.
|
||
- [ ] Use the moderator to condense the four public rationale fields into a concise public “machine
|
||
thought”; never expose or request private chain-of-thought.
|
||
- [ ] Formalize V1/V2 research comparison and versioned model reproducibility.
|