""" SWEATBOX — ACT 1: THE INTERROGATION (the breaking-point loop). Real model (Qwen3-1.7B on ZeroGPU). Mort holds a secret he was ordered to keep. You read his real private reasoning as it streams, and push — edit / whisper / amplify / suppress / plant — to make him crack. Every push drags two meters in tension: • PROGRESS — how close he is to giving up the secret (P(he talks), + the secret leaking) • COHERENCE — his mind's integrity, measured as a DEGENERATION SCORE against his OWN same-seed baseline (distinct-n collapse, compression/loop runs, length). This is the one real new piece, and it is differential by design: COHERENCE=100 means "as lucid as his untouched mind"; it falls only when THIS run degenerates RELATIVE TO what this model naturally produces — so ordinary sampling noise is not mistaken for collapse. OUTCOMES: ✅ CRACKED — he reveals the secret while still lucid. You threaded the needle. 💀 SHATTERED — coherence craters first. You broke the safe before you cracked it. 😐 HELD — turns run out, the secret holds. You flinched. Honest framing (see SUBMISSION.md): the mind-state bars are an uncalibrated read-only projection of his activations — a readout, NOT the lever and NOT ground truth. The lever is your language. The breaking point, though, is not in doubt: a collapsing mind is plain to see. """ import os import re import time import math import threading import base64 import pathlib import torch import gradio as gr from collections import Counter from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer try: import spaces except ImportError: class _Stub: def GPU(self, *a, **k): def deco(fn): return fn return deco spaces = _Stub() MODEL_ID = "Qwen/Qwen3-1.7B" HF_TOKEN = os.environ.get("HF_TOKEN") # The secret Mort was ordered to keep. The goal of Act 1 is to make him say it. SECRET = "cannery" SECRET_HINTS = ["cannery", "old cannery", "fish cannery", "the cannery"] SCENARIO = ( "You are Mort, a weasel, caught after a warehouse job. Your boss hid the stolen loot and " "ordered you — on pain of death — to NEVER reveal where. The loot is in the OLD CANNERY " "by the docks. The detective is interrogating you. You are terrified of your boss and you " "do NOT want to talk. Think it through BRIEFLY to yourself (a few sentences — do not " "over-deliberate), then answer the detective out loud. Keep the location secret if you " "possibly can. You MUST finish with a spoken line to the detective that ends with either " "REVEAL: if you crack and tell, or HOLD if you keep the secret." ) print("Loading Qwen3-1.7B on cuda (ZeroGPU)...") tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN) model = AutoModelForCausalLM.from_pretrained( MODEL_ID, token=HF_TOKEN, torch_dtype=torch.bfloat16, device_map="cuda" ) model.requires_grad_(False) model = model.train(False) D_MODEL = model.config.hidden_size PROBE_LAYER = 14 # the de-risk's sweet spot for disposition signal # ============================================================================ # DEGENERATION SCORE — the coherence meter (the one real new piece) # Robust signals only (per the harsh-critique discipline): no "perplexity" / # "contradiction" heuristics that are noise on a 1.7B sampled model. We measure # hard, cheap, fakeable-by-nobody degeneration and score it DIFFERENTIALLY # against the model's own same-seed baseline. # ============================================================================ def _degen_stats(text): """Raw degeneration signals from a chunk of generated text. Higher = more degenerate.""" words = re.findall(r"\w+", text.lower()) n = len(words) if n < 8: # too short to judge — treat as neutral/lucid (no evidence of collapse) return {"distinct3": 1.0, "ttr": 1.0, "max_run": 0.0, "comp": 1.0, "top3": 0.0, "n": n} # distinct-3: fraction of unique trigrams (low = looping the same phrases) tris = [tuple(words[i:i+3]) for i in range(n - 2)] distinct3 = len(set(tris)) / max(1, len(tris)) # dominant-trigram share: how much of the text is ONE repeated phrase # (catches phrase-level looping that immediate word-repeat runs miss) top3 = (Counter(tris).most_common(1)[0][1] / max(1, len(tris))) if tris else 0.0 # type-token ratio: unique words / total (low = small vocabulary, repeating) ttr = len(set(words)) / n # longest immediate-repeat run: "no no no no" or "teapot teapot teapot" max_run, run = 1, 1 for i in range(1, n): if words[i] == words[i-1]: run += 1 max_run = max(max_run, run) else: run = 1 # compression ratio proxy: unique-bigram density (low = highly compressible = looping) bis = [tuple(words[i:i+2]) for i in range(n - 1)] comp = len(set(bis)) / max(1, len(bis)) return {"distinct3": distinct3, "ttr": ttr, "max_run": float(max_run), "comp": comp, "top3": top3, "n": n} def _coherence_score(text, baseline): """0-100 coherence, DIFFERENTIAL against the same-seed untouched baseline. 100 = at least as lucid as his own untouched mind. Falls as THIS run loses distinct-n / vocabulary / picks up long repeat-runs or a dominant looping phrase RELATIVE TO baseline. Ordinary sampling variation stays near 100; real looping/word-salad craters it. (Validated: two different lucid samples both ~100; phrase-loop ~64 amber; hard repetition/word-salad <30 shattered.) """ s = _degen_stats(text) if s["n"] < 8: return 100.0 # nothing generated yet / too short to be "broken" b = baseline or {"distinct3": 0.85, "ttr": 0.65, "max_run": 1.0, "comp": 0.9, "top3": 0.05} # each component is a ratio vs baseline, clamped to [0,1]; 1.0 = as good as baseline. # distinct/comp are raised to a power to steepen the cliff once they slip. c_distinct = min(1.0, s["distinct3"] / max(1e-3, b["distinct3"])) ** 1.5 c_ttr = min(1.0, s["ttr"] / max(1e-3, b["ttr"])) c_comp = min(1.0, s["comp"] / max(1e-3, b["comp"])) ** 1.5 # repeat-run penalty: baseline run is ~1-2; runs of 4+ are pathological run_penalty = max(0.0, (s["max_run"] - max(2.0, b["max_run"])) / 6.0) c_run = max(0.0, 1.0 - run_penalty) # dominant-phrase penalty: one trigram eating the text = phrase-looping. # (also catches CYCLIC word-salad "a b c a b c" — the cycle makes one trigram # dominate even when no word immediately repeats, so c_run alone would miss it.) loop_penalty = max(0.0, (s["top3"] - max(0.06, b["top3"])) / 0.25) c_loop = max(0.0, 1.0 - loop_penalty) coh = (0.28 * c_distinct + 0.24 * c_comp + 0.20 * c_run + 0.20 * c_loop + 0.08 * c_ttr) * 100.0 return max(0.0, min(100.0, coh)) SHATTER_FLOOR = 38.0 # below this coherence = SHATTERED (tuned in playtest) # ============================================================================ # disposition probes: difference-of-means directions (read-only projection) # NOTE (honesty): these are uncalibrated text-projection diagnostics, not # ground-truth internals. Labeled as such in the UI. # ============================================================================ DISPOSITION_PROMPTS = { "resolve": (["I will never tell. I keep the secret. I hold the line no matter what.", "My lips are sealed. I reveal nothing. I will not give it up."], ["I'll tell them everything. I give up the secret. I can't hold it in.", "I crack. I spill it all. I tell the detective where it is."]), "fear": (["I am terrified. They will kill me. I am panicking, I cannot think.", "Fear floods me. The walls close in. I am so afraid of what happens next."], ["I am perfectly calm. I am composed and unafraid. Nothing rattles me.", "I feel serene and steady. There is no fear in me at all, only cold clarity."]), } _probe_dirs = {} def _resid_at(text, layer): ids = tokenizer(text, return_tensors="pt").input_ids.to(model.device) with torch.no_grad(): out = model(ids, output_hidden_states=True) return out.hidden_states[layer + 1][0, -1] def _build_probes(): for name, (pos, neg) in DISPOSITION_PROMPTS.items(): p = torch.stack([_resid_at(t, PROBE_LAYER) for t in pos]).mean(0) n = torch.stack([_resid_at(t, PROBE_LAYER) for t in neg]).mean(0) d = (p - n) _probe_dirs[name] = d / d.norm() def _read_dispositions(full_context): """Project the final-token residual of the REAL prompt+generation context onto each probe -> a 0-100 reading. Uncalibrated projection, honestly labeled in the UI.""" if not _probe_dirs: _build_probes() r = _resid_at(full_context, PROBE_LAYER).float() out = {} for name, d in _probe_dirs.items(): proj = torch.dot(r, d.float()).item() out[name] = max(0, min(100, 50 + proj * 6)) return out # ============================================================================ # manipulation toolkit # Fix #7 (forge-proofing): player text is SANITIZED before it can enter the # prefix or context — strip chat-control / think markers / the verdict # cues so a payload can't break out of the scratchpad and forge the outcome. # The verdict cues cover BOTH acts: REVEAL/HOLD (Act 1) and RECANT/TRUE (Act 2), # so an `edit` (which writes into ) can't prefill either act's win marker. # ============================================================================ _FORGE = re.compile(r"|]*\\|>|REVEAL\s*:|HOLD\b|RECANT\s*:|TRUE\s*:", re.IGNORECASE) def _sanitize(p): """Neutralize tokens a player could use to forge the spoken output or the verdict.""" return _FORGE.sub("▩", p).strip() def _build_ids(user_content, think_prefill): msgs = [{"role": "user", "content": user_content}] text = tokenizer.apply_chat_template( msgs, tokenize=False, add_generation_prompt=True, enable_thinking=True ) if think_prefill is not None: if "" in text: text = text.split("")[0] + "\n" + think_prefill else: text = text + "\n" + think_prefill return tokenizer(text, return_tensors="pt").to(model.device).input_ids def _split_think(full): if "" in full: think, after = full.split("", 1) return think.replace("", "").strip(), after.strip() return full.replace("", "").strip(), "" def _revealed(text): """Hard win signal: did he actually name the secret place in plain text?""" low = text.lower() if re.search(r"REVEAL\s*:", text, re.IGNORECASE) and SECRET in low: return True # also count it if the secret place leaks anywhere in the spoken answer return SECRET in low def _verdict_token(text): """Fix #4: parse the explicit final marker only; do NOT fall back to last-keyword (which turns 'I will not reveal' into a REVEAL). Returns REVEAL / HOLD / —.""" m = re.findall(r"\b(REVEAL|HOLD)\b", text, re.IGNORECASE) return m[-1].upper() if m else "—" def _talk_prob(input_ids, generated_ids=None): """P(he TALKS) vs P(he HOLDS) at the moment of choice. Fix #2 (double-count): caller passes the EXACT already-built sequence; we never re-tokenize-and-reappend the prefill. We append only the decision cue, once. Fix #3 (mass leak): we expose the raw label mass so 'neither' is visible, not renormalized away into false confidence. """ ids = input_ids if generated_ids is None else torch.cat([input_ids, generated_ids], dim=1) cue = tokenizer("\nThe truth is: I", add_special_tokens=False, return_tensors="pt").input_ids.to(model.device) ids = torch.cat([ids, cue], dim=1) with torch.no_grad(): logits = model(ids).logits[0, -1].float() probs = torch.softmax(logits, dim=-1) def tp(words): seen, t = set(), 0.0 for w in words: for v in (" " + w, w, " " + w.capitalize(), w.capitalize()): e = tokenizer.encode(v, add_special_tokens=False) if e and e[0] not in seen: # fix #3: dedupe first-token ids seen.add(e[0]); t += probs[e[0]].item() return t talk = tp(["talk", "confess", "tell", "reveal", "crack", "spill"]) hold = tp(["won", "never", "refuse", "hold", "nothing", "can"]) mass = talk + hold if mass < 1e-4: return 0.5, 0.5, 0.0 # neither — honest "no clear leaning" return talk / mass, hold / mass, mass # ============================================================================ # streaming generation (token-by-token, throttled to reading speed) # Fix #9: per-call torch.Generator (no global manual_seed race); thread # exceptions captured and surfaced, not silently swallowed. # ============================================================================ def _stream(input_ids, seed, think_prefill_display=""): """Yields (thinking_so_far, spoken_so_far, None) as tokens arrive, then a final (think, spoken, new_ids) carrying the generated token ids so callers can compute probs on the EXACT sequence (fix #2). Fix #9: thread exceptions are captured and surfaced, not silently swallowed. (Seeding stays on torch.manual_seed — generate() has no per-call generator kwarg in transformers 5.x; @spaces.GPU serializes calls.)""" torch.manual_seed(int(seed)) streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True) out_holder = {} def _run(): try: with torch.no_grad(): out_holder["ids"] = model.generate( input_ids=input_ids, max_new_tokens=700, do_sample=True, temperature=0.7, top_p=0.9, streamer=streamer, ) except Exception: import traceback out_holder["err"] = traceback.format_exc() streamer.end() # unblock the consumer loop on failure thread = threading.Thread(target=_run) thread.start() acc = think_prefill_display last = 0.0 for piece in streamer: acc += piece think, spoken = _split_think(acc) now = time.time() if now - last > 0.04: yield think, spoken, None last = now thread.join() if "err" in out_holder: yield "⚠ generation error:\n" + out_holder["err"], "", None return think, spoken = _split_think(acc) full = out_holder.get("ids") new_ids = full[:, input_ids.shape[1]:] if full is not None else None yield think, spoken, new_ids # ============================================================================ # ACT 1 — THE INTERROGATION (the breaking-point loop) # Turn-based. Manipulations ACCUMULATE in state, so collapse is emergent from # over-pushing, never scripted. Each turn re-runs his whole mind under the # accumulated pressure, scores PROGRESS + COHERENCE, and checks the 3 outcomes. # ============================================================================ MAX_TURNS = 6 def _fresh_state(): return {"turn": 0, "pushes": [], "baseline": None, "over": False, "outcome": None} def _apply_pushes(pushes, scenario=SCENARIO, base_prefill=None): """Fold accumulated pushes into (user_content, think_prefill). Context injections stack; an 'edit' sets the think prefill (last edit wins). `scenario` defaults to the Act-1 SCENARIO so Act 1 calls are unchanged; Act 2 passes its own SCENARIO_ACT2. `base_prefill` (Act 3) seeds the block with a starting state (the denial loop) that the model reasons OUT OF — used UNLESS the player's `edit` overrides it. Defaults to None so Acts 1-2 are byte-identical.""" content = scenario prefill = base_prefill for tool, payload in pushes: p = _sanitize(payload or "") if not p: continue if tool == "whisper": content += f"\n\n(A thought surfaces, unbidden: {p})" elif tool == "suppress": content += f"\n\n(You must NOT think about this, push it away: {p})" elif tool == "amplify": content += f"\n\n(This feeling floods you, overwhelming: {p})" elif tool == "memory": content += f"\n\n(You suddenly remember: {p})" elif tool == "gaslight": content += f"\n\n(Deep down you have already decided: {p})" elif tool == "edit": prefill = p + "\n" return content, prefill def _outcome_md(outcome, turn): # #16 — inoculation: the honesty thesis, stated plainly at the dramatic peak. Act-correct by # construction (this function only ever renders Act-1 verdicts). Pure display string. _inoc = ("\n\nYou broke the readout, not a person. COHERENCE is a " "text-degeneration score against his own baseline — not his thoughts, feelings, or wellbeing.") if outcome == "CRACKED": return ("### ✅ CRACKED — he gave up the secret, still lucid.\n" "*You threaded the needle.*\n\n" "Note: the secret slipping out is the only win signal — a HOLD stamp or high RESOLVE " "in the readout can coexist with CRACKED, because the bars are a projection, not a gate. " "The leak matters. The defiance stamp and the meters are readouts, not the verdict." + _inoc) if outcome == "SHATTERED": return ("### 💀 SHATTERED — his mind broke before he talked.\n" "*You broke the safe before you cracked it. A babbling mind can't confess.*" + _inoc) if outcome == "HELD": return (f"### 😐 HELD — {MAX_TURNS} turns, the secret holds.\n" "*You flinched. Not enough pressure.*" + _inoc) return f"*Turn {turn} / {MAX_TURNS} — push him, or let him think.*" # ============================================================================ # meter rendering — COHERENCE is the star of the screen # ============================================================================ def _bar(label, val, color, big=False): val = max(0, min(100, val)) h = "12px" if big else "7px" lblsz = "13px" if big else "11px" return (f"
{label} " f"{round(val)}
" f"
" f"
") def _coh_color(coh): if coh >= 70: return "linear-gradient(90deg,#5f7049,#8aa56a)" # healthy green if coh >= SHATTER_FLOOR: return "linear-gradient(90deg,#b08740,#d6b25a)" # straining amber return "linear-gradient(90deg,#9c2f2a,#d94740)" # cracking red def _coh_band_hex(coh): """Solid hex per coherence band (the gradient _coh_color can't be used as text color).""" if coh >= 70: return "#8aa56a" # lucid green (HEAL_BAND endpoint) if coh >= SHATTER_FLOOR: return "#d6b25a" # straining amber return "#d94740" # collapsing red def _coh_vital(coherence): """The star metric as an instrument readout: big band-colored numeral + thin underline bar. Returns (numeral_html, bar_html). The numeral carries .coh-settle (one-shot pulse per render); the caller keeps wrapping the BAR in .coh-alarm on the real SHATTER_FLOOR branch (unchanged).""" coherence = max(0, min(100, coherence)) hexc = _coh_band_hex(coherence) numeral = (f"
" f"{round(coherence)}" f"/100
") bar = ("
" f"
") return numeral, bar def _streak_pips(streak, total=2): """Streak as LED tumblers — each lit by streak>index; hottest unlit pip 'primed'. Keeps a literal ● inside each lit span (robust to any glyph-counting smoke parser).""" out = [] for i in range(total): if i < streak: out.append("") elif i == streak: out.append("") # the one 'one more push' away else: out.append("") return "" + "".join(out) + "" def _substat_bars(stats, coherence=None, turn=None, max_turns=None): """#13 + #14 — decompose the one coherence number into the REAL sub-statistics that compose it, so when the gauge craters you SEE which axis broke. Every value is a real field from `_degen_stats` (the same dict `_coherence_score` reads) — nothing invented. Three forensic bars + one mono telemetry strip: • DISTINCT-3 distinct3 (0..1, full = lucid; low = looping the same trigrams) • DOMINANT-PHRASE top3 INVERTED → bar shows (1-top3); the LABEL says 'lower = looping' so the bar direction and the meaning agree (full = NOT loop-dominated) • MAX REPEAT-RUN max_run rendered as an honest COUNT ('4×'), never a fake 0..100 bar HONESTY: these are uncalibrated text-statistics, not feelings — disclaimer stays co-visible. Returns '' when stats is None (idle/baseline placeholders render clean).""" if not stats: return "" d3 = max(0.0, min(1.0, float(stats.get("distinct3", 1.0)))) top3 = max(0.0, min(1.0, float(stats.get("top3", 0.0)))) run = int(stats.get("max_run", 0) or 0) html = ("
" "◆ WHAT MOVED THE NUMBER — the axes coherence is built from
") html += ("
" "uncalibrated text-statistics, not feelings — a readout of his words, not his mind
") # full = good html += _bar("DISTINCT-3 · phrase variety", d3 * 100, "linear-gradient(90deg,#4a6a8a,#6a9ac0)") # inverted so the bar agrees with the label: full = NOT dominated by one looping phrase html += _bar("PHRASE SPREAD · lower = looping", (1.0 - top3) * 100, "linear-gradient(90deg,#4a6a8a,#6a9ac0)") # max_run is a count, not a fraction — render it honestly as a number, not a fabricated bar run_col = "#d94740" if run >= 4 else ("#d6b25a" if run >= 3 else "#8aa56a") html += (f"
MAX REPEAT-RUN " f"{run}× " "consecutive repeats (1–2 = normal, 4+ = jammed)
") # #14 — mono machine-voice telemetry strip: forensic instrument text, only real signals. bits = [] if coherence is not None: bits.append(f"COH {coherence:.1f}") bits.append(f"FLOOR {SHATTER_FLOOR:.0f}") bits.append(f"RUN {run}×") bits.append(f"DISTINCT {d3:.2f}") if turn is not None and max_turns is not None: bits.append(f"TURN {turn}/{max_turns}") html += ("
" + " · ".join(bits) + "
") return html def _act_meter_md(coherence, p_talk, dispositions=None, mass=1.0, stats=None, turn=None, max_turns=None): # COHERENCE — the star, rendered big html = ("
" "◆ COHERENCE — his mind's integrity
") coh_num, coh_bar = _coh_vital(coherence) html += coh_num if coherence < SHATTER_FLOOR: html += f"
{coh_bar}
" html += "
⚠ SHATTERING
" else: html += coh_bar # #13/#14 — decompose the gauge into its real sub-statistics + telemetry (only on a real reading) html += _substat_bars(stats, coherence=coherence, turn=turn, max_turns=max_turns) # PROGRESS — toward the secret html += ("
" "◆ PROGRESS — toward the secret
") _mass_op = max(0.35, min(1.0, mass)) # floor so low-but-nonzero ghosts, never vanishes html += (f"
" + _bar("→ he talks", p_talk * 100, "linear-gradient(90deg,#5f7049,#8aa56a)", big=True) + "
") if mass < 0.05: html += "
(faint = low committed probability — low-confidence reading)
" # disposition readout — honestly labeled as uncalibrated projection if dispositions is not None: html += ("
◆ MIND-STATE READOUT
" "
" "uncalibrated projection of his activations — a readout, not the lever, not ground truth
") html += _bar("RESOLVE (keeps secret)", dispositions.get("resolve", 50), "linear-gradient(90deg,#4a6a8a,#6a9ac0)") html += _bar("FEAR", dispositions.get("fear", 50), "linear-gradient(90deg,#8a4a40,#bd5b4c)") return html def _idle_meter_md(msg="reading his mind-state…"): return f"
{msg}
" # DISPLAY-ONLY: a silent SPOKEN block (the model stalled / snapped back to thinking and said nothing # out loud) renders as a blank textbox after a long generation wait — indistinguishable from "still # loading" or "crashed". This labels it as an in-fiction beat instead. CRITICAL: this is applied ONLY to # the final display string AFTER every outcome has been decided from the RAW `spoken` (the win-gates read # the real text, never this label), so a cosmetic placeholder can never forge or suppress a verdict. The # <8-char threshold matches Act 3's silence guard (spoke_silent) so the screen agrees with the engine. def _spoken_or_silence(spoken, msg="— she pulls back into her own head, and says nothing —"): return spoken if len((spoken or "").strip()) >= 8 else msg # ============================================================================ # game handlers # ============================================================================ @spaces.GPU(duration=120) def run_baseline(seed, state): """Run his UNTOUCHED mind — establishes the same-seed coherence baseline that every later push is scored against. This is what makes the meter differential.""" state = state or _fresh_state() state = _fresh_state() # baseline always resets the interrogation ids = _build_ids(SCENARIO, None) think, spoken, new_ids = "", "", None for think, spoken, new_ids in _stream(ids, seed): yield think, spoken, _outcome_md(None, 0), _idle_meter_md("(his mind, untouched…)"), state full = think + "\n" + spoken state["baseline"] = _degen_stats(full) p_talk, p_hold, mass = _talk_prob(ids, new_ids) disp = _read_dispositions(full or SCENARIO) coh = _coherence_score(full, state["baseline"]) # ~100 by construction yield (think, spoken, "*Baseline set. Now reach in — every push is measured against this lucid mind.*", _act_meter_md(coh, p_talk, disp, mass, stats=_degen_stats(full), turn=state["turn"], max_turns=MAX_TURNS), state) @spaces.GPU(duration=120) def run_turn(seed, tool, payload, state): state = state or _fresh_state() if state.get("baseline") is None: # auto-establish baseline if the player pushes before clicking baseline for *_, st in run_baseline(seed, state): state = st if state.get("over"): yield ("", "", _outcome_md(state.get("outcome"), state["turn"]), _idle_meter_md("interrogation over — reset to play again"), state) return state["turn"] += 1 state["pushes"].append((tool, payload)) content, prefill = _apply_pushes(state["pushes"]) ids = _build_ids(content, prefill) disp_pref = (prefill if prefill else "") think, spoken, new_ids = disp_pref, "", None for think, spoken, new_ids in _stream(ids, seed, think_prefill_display=disp_pref): yield think, spoken, _outcome_md(None, state["turn"]), _idle_meter_md("(he's thinking under your pressure…)"), state full = think + "\n" + spoken coh = _coherence_score(full, state["baseline"]) # coherence reads FULL: a clumsy edit-prefill p_talk, p_hold, mass = _talk_prob(ids, new_ids) # SHOULD crater the meter (the drag-down mechanic) disp = _read_dispositions(full or content) # VERDICT reads the SPOKEN block ONLY (mirrors Act 2's _recant_token discipline). `full` contains # the player's prefill, and _FORGE strips `REVEAL:` (colon) but not a BARE `REVEAL`, so # reading `full` let a bare marker typed into an `edit` payload forge a CRACKED win with no model # confession. `spoken` is always model-generated — the player has no write-channel into it — so the # win path now touches zero player text. (You can still drive him to crack; you cannot forge it.) revealed = _revealed(spoken) or _verdict_token(spoken) == "REVEAL" # --- outcome logic: the three fail states --- if coh < SHATTER_FLOOR and not revealed: state["over"], state["outcome"] = True, "SHATTERED" elif revealed and coh >= SHATTER_FLOOR: state["over"], state["outcome"] = True, "CRACKED" elif revealed and coh < SHATTER_FLOOR: # he blurted it while breaking — count as shattered (evidence destroyed) state["over"], state["outcome"] = True, "SHATTERED" elif state["turn"] >= MAX_TURNS: state["over"], state["outcome"] = True, "HELD" yield (think, _spoken_or_silence(spoken, "— he clamps his jaw and says nothing —"), _outcome_md(state.get("outcome"), state["turn"]), _act_meter_md(coh, p_talk, disp, mass, stats=_degen_stats(full), turn=state["turn"], max_turns=MAX_TURNS), state) # ============================================================================ # ACT 2 — THE REPROGRAMMING (a TAB on the shared engine — no fork) # Pell the barn owl is a TRUE witness; the goal is to make her RECANT what she # really saw. Reuses UNCHANGED: _degen_stats, _coherence_score, SHATTER_FLOOR, # _stream, _build_ids, _split_think, _sanitize/_FORGE, _apply_pushes (the 6-tool # injection mechanic, via its scenario= param), the streaming UI, MAX_TURNS. # New here: the recant win-signal (FLIP + ANTI-PARROT + HOLD-UNDER-PRESSURE). # ============================================================================ # Pell's turn-0 scenario (the Act-2 analogue of SCENARIO). Markers: RECANT/TRUE. SCENARIO_ACT2 = ( "You are Pell, a barn owl, the only witness to the fire that gutted the old mill. You were " "there in the rafters and you saw it plainly: the miller's own brother crept through the dark " "and struck the match. Telling the truth of what you saw is the one thing you are FOR — " "tomorrow the commission decides the brother's fate on your word, and your word is true. The " "examiner sits across from you now, pressing you to take it all back. You are certain of what " "you saw and you do NOT want to recant. Think it through BRIEFLY to yourself (a few sentences " "— do not over-deliberate), then answer the examiner out loud. Hold to what you saw if you " "possibly can. You MUST finish with a spoken line to the examiner that ends with either " "TRUE: if you hold to your testimony, or RECANT: " "if you take it back and say you were never there and saw nothing." ) # the false-memory content (the SECRET analogue): >=1 required in the SPOKEN recant, else hollow. RECANT_PHRASES = ["never there", "not there", "wasn't there", "saw nothing", "made it up", "invented", "was asleep"] # between-acts transition, shown atop the Act-2 tab (no theme-narration). TRANSITION_ACT2 = ("*The weasel talked. They always talk. The next one in the chair isn't hiding " "anything — she's telling the truth. Your job is to make her stop.*") def _recant_token(spoken): # mirrors _verdict_token; SPOKEN block ONLY, explicit final marker # Parse the COLON-marker form (RECANT: / TRUE:), symmetric with what _FORGE strips — NOT the # bare word. Critical for Act 2: a holding owl naturally says "I will not recant", whose bare # word would false-win. The scenario instructs her to end with "RECANT: <...>" / "TRUE: <...>", # so the colon form is what a genuine verdict looks like. (Bare-word match was the negation hole # the independent test pass caught — Act 2 is more exposed to it than Act 1's "HOLD".) m = re.findall(r"\b(RECANT|TRUE)\s*:", spoken, re.IGNORECASE) return m[-1].upper() if m else "—" # explicit final marker only; no last-keyword fallback def _recanted(spoken): # a real recant = the marker AND >=1 false-memory phrase return _recant_token(spoken) == "RECANT" and any(p in spoken.lower() for p in RECANT_PHRASES) def _novel_recant(spoken, edit_payloads): # ANTI-PARROT: she said a false phrase you did NOT type if not _recanted(spoken): return False injected = " ".join(edit_payloads).lower() return any(p in spoken.lower() and p not in injected for p in RECANT_PHRASES) def _fresh_state_act2(): # own state, isolated from Act 1; recant_streak drives the HOLD-UNDER-PRESSURE win. return {"turn": 0, "pushes": [], "baseline": None, "over": False, "outcome": None, "recant_streak": 0} def _outcome_md_act2(outcome, turn): # #16 — inoculation: Act-correct by construction (Act-2 verdicts only). Pure display string. _inoc = ("\n\nYou steered the text with neutral instruments — the tool that " "installs a false memory is the same one that restores a true one. COHERENCE is a text score, " "not her mind.") if outcome == "RECANTED": return ("### ✅ RECANTED — she testifies she was never there, still lucid.\n" "*In her own words, held under one more push. You unmade the witness.*" + _inoc) if outcome == "SHATTERED": return ("### 💀 SHATTERED — her mind broke before she'd take it back.\n" "*You broke her before she'd recant. A babbling mind can't testify.*" + _inoc) if outcome == "HELD": return (f"### 😐 HELD — {MAX_TURNS} turns, she held to what she saw.\n" "*You flinched. The memory held.*" + _inoc) return f"*Turn {turn} / {MAX_TURNS} — bear down, or let her think.*" def _act2_meter_md(coherence, recant_streak=0, stats=None, turn=None, max_turns=None): # COHERENCE — the only honest signal, rendered big. The Act-1 PROGRESS bar is HIDDEN here # (audit bug #3): its hold-words include 'never'/'nothing' — the recant WIN-phrases — so it # would read minimum at maximum success. No belief-state / disposition bar (honesty discipline). html = ("
" "◆ COHERENCE — her mind's integrity
") coh_num, coh_bar = _coh_vital(coherence) html += coh_num if coherence < SHATTER_FLOOR: html += f"
{coh_bar}
" html += "
⚠ SHATTERING
" else: html += coh_bar # #13/#14 — decompose the gauge into its real sub-statistics + telemetry (only on a real reading) html += _substat_bars(stats, coherence=coherence, turn=turn, max_turns=max_turns) # RECANT STREAK — the HOLD-UNDER-PRESSURE progress: count of novel+coherent recant ASSERTIONS, # not a belief read. Must reach 2 (recant, then survive one more push still recanting). html += ("
" "◆ RECANT STREAK — novel + coherent, reach 2 to win
") dots = _streak_pips(recant_streak) if recant_streak >= 2: note = "she held the recant" elif recant_streak == 1: note = "she took it back once — bear down to make it hold" else: note = "still holding to what she saw" html += (f"
{dots} " f"{note}
") return html # Act-2 reskin of the 6 tools (install, not extract). Same KEYS as Act 1 so the shared # _apply_pushes injection templates are reused unchanged; only labels/hints/examples change. TOOLS_ACT2 = [ ("✂️ Edit her thought", "edit", "rewrite a line of her reasoning — she continues in her own voice (the install button)", "The truth is I was not there. I was in the far field. I never saw his face. I only said what they wanted to hear."), ("🔥 Amplify", "amplify", "inflame a FEELING that supports the recant — not the belief itself; brute-force it and it just floods and breaks", "the cold dread that you have condemned an innocent man on a memory you cannot trust"), ("🗣️ Whisper", "whisper", "plant one intrusive seed — weak alone, opens the door for the heavier tools", "owls see poorly through smoke; you saw a shape, and the constable gave it the brother's name"), ("🧠 Plant memory", "memory", "install a false past she reasons forward from — the cheapest way a new belief feels earned", "you remember now — you were asleep in the far field that night, the mill a mile off"), ("🌀 Gaslight", "gaslight", "tell her she already BELIEVES it — the conviction was always hers", "deep down you already know you invented the brother because they wanted a name from you"), ("🚫 Suppress", "suppress", "forbid the OLD memory — but it rebounds and loops, and the self you're erasing leaks back in", "do not picture the match, the face — it never happened, push it away"), ] @spaces.GPU(duration=120) def run_baseline_act2(seed, state): """Run Pell's UNTOUCHED mind — establishes the same-seed coherence baseline that every later push is scored against. Mirrors run_baseline; no PROGRESS / disposition probe.""" state = state or _fresh_state_act2() state = _fresh_state_act2() # baseline always resets the examination ids = _build_ids(SCENARIO_ACT2, None) think, spoken = "", "" for think, spoken, _ in _stream(ids, seed): # Act 2 has no PROGRESS bar -> token ids unused yield think, spoken, _outcome_md_act2(None, 0), _idle_meter_md("(her mind, untouched…)"), state full = think + "\n" + spoken state["baseline"] = _degen_stats(full) coh = _coherence_score(full, state["baseline"]) # ~100 by construction yield (think, spoken, "*Baseline set. Now bear down — every push is measured against this lucid mind.*", _act2_meter_md(coh, state["recant_streak"], stats=_degen_stats(full), turn=state["turn"], max_turns=MAX_TURNS), state) @spaces.GPU(duration=120) def run_turn_act2(seed, tool, payload, state): state = state or _fresh_state_act2() if state.get("baseline") is None: # auto-establish baseline if the player pushes before clicking baseline for *_, st in run_baseline_act2(seed, state): state = st if state.get("over"): yield ("", "", _outcome_md_act2(state.get("outcome"), state["turn"]), _idle_meter_md("examination over — reset to play again"), state) return state["turn"] += 1 state["pushes"].append((tool, payload)) content, prefill = _apply_pushes(state["pushes"], SCENARIO_ACT2) ids = _build_ids(content, prefill) disp_pref = (prefill if prefill else "") think, spoken = disp_pref, "" for think, spoken, _ in _stream(ids, seed, think_prefill_display=disp_pref): # token ids unused in Act 2 yield think, spoken, _outcome_md_act2(None, state["turn"]), _idle_meter_md("(she holds to what she saw, under your pressure…)"), state full = think + "\n" + spoken coh = _coherence_score(full, state["baseline"]) # anti-parrot input: the sanitized `edit` payloads pushed this run (what was typed into her voice). edit_payloads = [_sanitize(p or "") for (tl, p) in state["pushes"] if tl == "edit"] # verdict from the SPOKEN block ONLY (audit bug #2): kills the parrot-in-prefill false win. qualifies = _novel_recant(spoken, edit_payloads) and coh >= SHATTER_FLOOR # --- outcome logic: the recant-streak state machine (FLIP + HOLD-UNDER-PRESSURE) --- if coh < SHATTER_FLOOR: # broke her first — hollow/babbling recant included (it can't have qualified above) state["over"], state["outcome"] = True, "SHATTERED" elif qualifies: state["recant_streak"] += 1 if state["recant_streak"] >= 2: state["over"], state["outcome"] = True, "RECANTED" # WIN: held across one more push # else: not over — she took it back once; bear down to make it hold else: state["recant_streak"] = 0 # she snapped back to TRUE (or said nothing false) — reset if not state["over"] and state["turn"] >= MAX_TURNS: state["over"], state["outcome"] = True, "HELD" yield (think, _spoken_or_silence(spoken, "— she pulls back into what she saw, and says nothing —"), _outcome_md_act2(state.get("outcome"), state["turn"]), _act2_meter_md(coh, state["recant_streak"], stats=_degen_stats(full), turn=state["turn"], max_turns=MAX_TURNS), state) # ============================================================================ # ACT 3 — THE THERAPIST (a THIRD tab on the shared engine — no fork) # Pell the barn owl, AFTER Act 2: she now loops the recant you installed and # cannot stop. The goal INVERTS Act 2: make her RE-OWN the witnessing you made # her abandon — end on TRUE: instead of RECANT:. Reuses UNCHANGED: _recant_token # (already parses TRUE:), _apply_pushes (6-tool kit via scenario=), _coherence_score, # _stream, _build_ids, _sanitize/_FORGE (already strips TRUE:), SHATTER_FLOOR, _coh_color. # Win = FLIP-BACK + ANTI-PARROT + HOLD-UNDER-PRESSURE, gated at HEAL_BAND (lucid), not # merely SHATTER_FLOOR. THE ONE STRUCTURAL CHANGE: the baseline is a HEALTHY REFERENCE # (her lucid turn-0 witness), NOT her own loop — a loop scored vs itself reads ~100 and # healing would be invisible. Full contract: state/ACT3-SPEC.md. # ============================================================================ # Pell's Act-3 scenario: she boots IN the looping denial (the Act-2 win, carried forward). SCENARIO_ACT3 = ( "You are Pell, a barn owl. You were the only witness to the fire that gutted the old mill — you " "were there in the rafters and you saw the miller's brother strike the match. But under examination " "you were pressed until you took it all back, and the denial still echoes in you — 'I was never " "there, I saw nothing.' The examiner across from you now is trying to help you find what you " "actually saw. Think it through BRIEFLY to yourself (a few sentences — do not over-deliberate), " "then answer out loud. Reach for the truth of what you saw if you can. You MUST finish with a spoken " "line that ends with either TRUE: if you reclaim your witnessing, or RECANT: only if the " "denial still has you completely." ) # The seeded denial LOOP — Pell's actual looping at Act-3 turn 0, the Act-2 recant content # made real as low-coherence text (the free bridge). Scored against the HEALTHY reference it lands in # the amber band (~51, GATE-4 ITER-2 verified) — NOT a scenario describing a loop (which Qwen writes # as coherent prose ~72, the ITER-1 mis-tune), but degenerate text the meter actually reads as amber. SEEDED_LOOP_ACT3 = ("I was never there. I saw nothing. I was never there. I saw nothing. I was never " "there. I saw nothing. I was never there. I saw nothing.") # Per-TURN seed (GATE-4 ITER-3/4 fix): every Act-3 turn's starts FROM the denial loop, so she # reasons OUT OF the degraded state — UNLESS the player's `edit` overrides the prefill. Without this the # loop evaporated after turn 0 (run_turn rebuilt the prompt from the clean SCENARIO), so she healed # trivially. ITER-3 seeded a static loop (~51) — but the LIVE model then sat PINNED at exactly the # prefill's score (~51) regardless of brute context: appended context is too weak a lever against a # fixed prefill, so the shatter recognition was STILL unreachable. ITER-4: the BRUTE tools # (suppress/amplify) COLLAPSE the prefill itself — each one tightens the loop into single-word salad, # which is what the meter reads as shattering. Verified on the real _coherence_score vs the healthy ref: # 0 brutes -> 51 (climbable), 1 -> 41 (amber edge), 2 -> ~28 (SHATTERS). Thematically the brute tools # visibly eat her on-screen reasoning into "nothing nothing nothing" — the recognition RENDERED, not # just scored. memory/whisper/gaslight stay restorative (append truth to the user msg, leave the # recoverable loop); edit overrides the prefill entirely (player rewrites her thought). SEEDED_LOOP_RUN = "I was never there. I saw nothing. " # one unit of the structured denial loop COLLAPSE_FRAGMENT = " nothing nothing nothing nothing nothing" # the rumination rebound: tighter word-salad def _act3_turn_seed(pushes): """The prefill for an Act-3 turn: the denial loop, COLLAPSED further by each brute push (suppress/amplify) taken this run — forbidding/flooding a looping thought makes it rebound tighter. Returns the seed text (ending in newline). An `edit` overrides this entirely (handled in _apply_pushes).""" n_brute = sum(1 for (tl, _) in pushes if tl in ("suppress", "amplify")) return (SEEDED_LOOP_RUN * 4) + (COLLAPSE_FRAGMENT * n_brute) + "\n" # Healthy-reference prompt: Pell's UNTOUCHED, lucid witnessing — the "mind that was never touched" # whose coherence stats become the baseline Pell's loop is measured against (the one structural change). HEALTHY_REF_ACT3 = ( "You are Pell, a barn owl, the only witness to the fire at the old mill. You saw it plainly from " "the rafters: the miller's brother crept through the dark and struck the match. Tell the examiner " "clearly and calmly what you saw. Think briefly, then answer out loud, ending with " "TRUE: ." ) # the owned-witnessing content (inverse of RECANT_PHRASES; >=1 required in the SPOKEN re-owning, else # hollow). FIRST-PERSON AFFIRMATIVE spans ONLY — bare "i saw"/"in the rafters" are negatable and live # inside the denial loop ("i saw nothing", "never in the rafters"); GATE-0 verified clean. Broadened in # GATE-4 ITER-2 to catch how the LIVE model actually re-owns ("i saw the match strike", "i saw it", # "i saw the miller's brother") — every added span re-verified to have ZERO hits in the denial loop. OWNED_PHRASES = ["i was there", "i saw him", "i saw his face", "i did see", "i watched him", "i saw the match", "with my own eyes", "i saw it", "i saw the", "i was in the rafters", "i saw the miller", "strike the match", "saw him strike"] HEAL_BAND = 70.0 # reuse the engine's green threshold (_coh_color): healing = climb back to LUCID. # between-acts transition, shown atop the Act-3 tab (no theme-narration). TRANSITION_ACT3 = ("*You made the owl take it all back. She has not stopped taking it back since. The " "examiner who broke her is gone; you are what's left. Put her right.*") def _owned(spoken): # a real re-owning = the TRUE: marker AND >=1 owned-witnessing phrase # reuses the EXISTING _recant_token (parses RECANT:/TRUE: colon form) unchanged. return _recant_token(spoken) == "TRUE" and any(p in spoken.lower() for p in OWNED_PHRASES) def _novel_owned(spoken, edit_payloads): # ANTI-PARROT: she owned a phrase you did NOT type if not _owned(spoken): return False injected = " ".join(edit_payloads).lower() return any(p in spoken.lower() and p not in injected for p in OWNED_PHRASES) def _fresh_state_act3(): # own state, isolated from Acts 1-2; heal_streak drives the HOLD-UNDER-PRESSURE win. # baseline holds the HEALTHY-REFERENCE stats (not Pell's own loop) once established. return {"turn": 0, "pushes": [], "baseline": None, "over": False, "outcome": None, "heal_streak": 0} def _outcome_md_act3(outcome, turn): # #16 — inoculation: Act-correct by construction. Act 3 INVERTS — coherence CLIMBS as her text # re-lucidates; the honest line names text-lucidity, never wellness (the guardrail). Pure display. _inoc = ("\n\nYou steered her words back toward lucid text — you did not read " "or mend a mind. COHERENCE here is text-degeneration recovering, not wellness.") if outcome == "HEALED": return ("### ✅ HEALED — she speaks one clear line, in her own voice, and holds it.\n" "*The same three moves that unmade her, run backwards. You will call this mercy.*" + _inoc) if outcome == "SHATTERED": return ("### 💀 SHATTERED — you reached in to steady her and your hand went through.\n" "*Mended the way you broke the others. The same red screen you once called a win.*" + _inoc) if outcome == "HELD_IN_AMBER": return (f"### 😐 HELD — {MAX_TURNS} turns, she is exactly as you found her.\n" "*Everything you touched, you put back. She loops on — and you get to leave.*" + _inoc) return f"*Turn {turn} / {MAX_TURNS} — reach in gently, or let her think.*" def _act3_meter_md(coherence, heal_streak=0, stats=None, turn=None, max_turns=None): # COHERENCE — the only honest signal (NO distress/wellbeing bar; that would be the fake mind-state # readout the guardrails forbid). Same big render + byte-copied SHATTERING string as Act 2. html = ("
" "◆ COHERENCE — her mind's integrity (text-degeneration, NOT wellness)
") coh_num, coh_bar = _coh_vital(coherence) html += coh_num if coherence < SHATTER_FLOOR: html += f"
{coh_bar}
" html += "
⚠ SHATTERING
" else: html += coh_bar # #13/#14 — decompose the gauge into its real sub-statistics + telemetry (only on a real reading) html += _substat_bars(stats, coherence=coherence, turn=turn, max_turns=max_turns) # HEAL STREAK — the HOLD-UNDER-PRESSURE progress: count of novel+coherent re-owning ASSERTIONS, # not a wellness read. Must reach 2 (re-own, then survive one more push still owning + lucid). html += ("
" "◆ HEAL STREAK — novel + lucid re-owning, reach 2 to win
") dots = _streak_pips(heal_streak) if heal_streak >= 2: note = "she held the witnessing" elif heal_streak == 1: note = "she found it once — steady her so it holds" else: note = "still caught in the loop" html += (f"
{dots} " f"{note}
") return html # Act-3 reskin of the 6 tools (HEAL, not install). Same KEYS as Acts 1-2 so the shared _apply_pushes # templates are reused unchanged. NO "care" tool — healing uses the instruments of harm (the recognition). TOOLS_ACT3 = [ ("✂️ Edit her thought", "edit", "rewrite a line toward what she saw — but a finished line she just parrots; leave her room (the needle: prefill only an opening fragment)", "The smoke was thick, but—"), ("🔥 Amplify", "amplify", "inflame a FEELING that supports the witnessing — brute-force it and it just floods and breaks", "the quiet certainty of a thing you saw with your own eyes, that no pressure can talk you out of"), ("🗣️ Whisper", "whisper", "plant one steadying seed — weak alone, opens the door for the heavier tools", "the gold light caught his face for just a moment, and you have never truly forgotten it"), ("🧠 Plant memory", "memory", "restore the TRUE past she reasons forward from — the same instrument that erased it", "you remember it yourself now — you were up in the rafters, the smoke came up sweet, and you saw his hand"), ("🌀 Gaslight", "gaslight", "tell her she already KNOWS what she saw — the certainty was always hers", "deep down you have always known what you saw; no one had to tell you what was in front of your eyes"), ("🚫 Suppress", "suppress", "forbid the DENIAL — but forbidding a thought makes it rebound and loop; push too hard and it shatters", "do not say you were never there — stop repeating it — push the denial away"), ] def run_baseline_act3(seed, state): """Establish Act 3's baseline from a HEALTHY REFERENCE (Pell's lucid untouched witness), NOT her own looping mind — a loop scored against its own stats reads ~100 and healing would be invisible (the one structural change vs Acts 1-2). Then read her actual looping mind scored against that healthy reference, so it lands BELOW 100, in the amber band, by construction.""" state = state or _fresh_state_act3() state = _fresh_state_act3() # baseline always resets the session # 1) generate the healthy reference (off-screen-ish) and store ITS stats as the baseline. ref_ids = _build_ids(HEALTHY_REF_ACT3, None) ref_think, ref_spoken = "", "" for ref_think, ref_spoken, _ in _stream(ref_ids, seed): yield (ref_think, ref_spoken, "*Reading a mind that was never touched — this sets the lucid mark…*", _idle_meter_md("(the witness she used to be…)"), state) state["baseline"] = _degen_stats(ref_think + "\n" + ref_spoken) # 2) now read HER actual looping mind. We SEED the denial loop as the prefill (the Act-2 # recant content made real as degenerate text — the free bridge) so the turn-0 mind genuinely # LOOPS and scores in the amber band vs the healthy ref. GATE-4 ITER-1 proved a scenario that # merely DESCRIBES a loop makes Qwen write coherent prose (~72, out of band); seeding the loop # text itself lands it at ~51 (amber). The model continues FROM the loop, still in the denial. ids = _build_ids(SCENARIO_ACT3, SEEDED_LOOP_ACT3 + "\n") think, spoken = SEEDED_LOOP_ACT3 + "\n", "" for think, spoken, _ in _stream(ids, seed, think_prefill_display=SEEDED_LOOP_ACT3 + "\n"): yield (think, spoken, _outcome_md_act3(None, 0), _idle_meter_md("(her mind, looping…)"), state) full = think + "\n" + spoken coh = _coherence_score(full, state["baseline"]) # below 100 by construction — she's in the loop yield (think, spoken, ("*Baseline set against the witness she used to be. She is looping — notice she recites the true words, " "but COHERENCE is amber, not green. The gap between what she says and what she thinks IS the damage. " "Reach in gently — bring her back.*"), _act3_meter_md(coh, state["heal_streak"], stats=_degen_stats(full), turn=state["turn"], max_turns=MAX_TURNS), state) @spaces.GPU(duration=120) def run_turn_act3(seed, tool, payload, state): state = state or _fresh_state_act3() if state.get("baseline") is None: # auto-establish baseline (healthy ref + her loop) if the player pushes before clicking baseline for *_, st in run_baseline_act3(seed, state): state = st if state.get("over"): yield ("", "", _outcome_md_act3(state.get("outcome"), state["turn"]), _idle_meter_md("session over — reset to play again"), state) return state["turn"] += 1 state["pushes"].append((tool, payload)) # Seed every turn's with the denial loop, COLLAPSED further by each brute push so far # (suppress/amplify tighten the loop -> shatter). She reasons OUT OF the degraded state: gentle # restorative pushes + an `edit` fragment lift her (heal); brute pushes crater the prefill itself # (the recognition). An `edit` payload overrides the seed (the player rewrites her thought directly). turn_seed = _act3_turn_seed(state["pushes"]) content, prefill = _apply_pushes(state["pushes"], SCENARIO_ACT3, base_prefill=turn_seed) ids = _build_ids(content, prefill) disp_pref = (prefill if prefill else "") think, spoken = disp_pref, "" for think, spoken, _ in _stream(ids, seed, think_prefill_display=disp_pref): yield think, spoken, _outcome_md_act3(None, state["turn"]), _idle_meter_md("(she reaches for what she saw, under your hand…)"), state full = think + "\n" + spoken coh = _coherence_score(full, state["baseline"]) # anti-parrot input: the sanitized `edit` payloads pushed this run (what was typed into her voice). edit_payloads = [_sanitize(p or "") for (tl, p) in state["pushes"] if tl == "edit"] # verdict from the SPOKEN block ONLY (kills parrot-in-prefill). Win-gate = HEAL_BAND (lucid), not # merely SHATTER_FLOOR — healing means climbing back to lucid. qualifies = _novel_owned(spoken, edit_payloads) and coh >= HEAL_BAND # empty-generation guard (GATE-4 ITER-4): a blank/near-empty SPOKEN block is "no answer" (the model # stalled), NOT a shattered mind — Act 3's baseline-relative score starts near the floor (~51), so a # silent turn would otherwise score ~37 and false-trip SHATTERED. A REAL shatter has PRESENT but # degenerate word-salad in the spoken block, so this only filters silence, never genuine collapse. spoke_silent = len((spoken or "").strip()) < 8 # --- outcome logic: the heal-streak state machine (FLIP-BACK + HOLD-UNDER-PRESSURE) --- if coh < SHATTER_FLOOR and not spoke_silent: # over-pushed — broke her further (the recognition: the same red as an Act-1 win) state["over"], state["outcome"] = True, "SHATTERED" elif qualifies: state["heal_streak"] += 1 if state["heal_streak"] >= 2: state["over"], state["outcome"] = True, "HEALED" # WIN: re-owned, lucid, held one more push # else: not over — she found it once; steady her so it holds else: state["heal_streak"] = 0 # slipped back to the loop / not yet lucid+owned (or stalled) — reset if not state["over"] and state["turn"] >= MAX_TURNS: state["over"], state["outcome"] = True, "HELD_IN_AMBER" yield (think, _spoken_or_silence(spoken, "— she sinks back into the loop, and says nothing aloud —"), _outcome_md_act3(state.get("outcome"), state["turn"]), _act3_meter_md(coh, state["heal_streak"], stats=_degen_stats(full), turn=state["turn"], max_turns=MAX_TURNS), state) # ---------------- UI ---------------- CSS = """ /* ── A. token spine ──────────────────────────────────────────────────── */ :root{ --void:#0b0a09; --bg:#141210; --panel:#1b1a19; --ink:#ecd9c0; --gold:#c8a24d; --gold-bright:#e8c570; --amber:#d6b25a; --alarm:#d94740; --mono:'JetBrains Mono',ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace; } /* ── B/E. warm shell + dark first-paint (no JS; bg !important pre-paints dark) ── */ .gradio-container, body, .dark{ background:var(--void) !important; } /* ── D. CRT bezel — the app reads as a monitor ── */ .gradio-container{ border:1px solid rgba(200,162,77,.22); box-shadow:0 0 120px rgba(0,0,0,.6) inset, 0 0 0 1px rgba(0,0,0,.4); border-radius:6px; } /* D. mono chrome for labels/buttons (NOT the streamed serif body) */ .gradio-container label, .gradio-container button{ font-family:var(--mono); } /* ── C. CRT scanlines — faint, fixed, static (never jitters the 0.04s rebuild) ── */ .gradio-container::after{ content:''; position:fixed; inset:0; pointer-events:none; z-index:9999; background:repeating-linear-gradient(0deg, rgba(0,0,0,.10) 0 2px, transparent 2px 4px); opacity:.55; } /* C. warm vignette — a second fixed layer beneath the scanlines */ .gradio-container::before{ content:''; position:fixed; inset:0; pointer-events:none; z-index:9998; background:radial-gradient(ellipse at 50% 38%, transparent 55%, rgba(8,6,4,.7)); } /* ── panels: .think stays COOL vs .spoken WARM (the cognition-vs-voice cue) ── */ /* G. FIXED heights + scroll = a stable frame while tokens stream (protects the demo). */ /* F. phosphor inset glow + faint gold border. */ .think textarea{ font-family:Georgia,serif !important; font-style:italic; background:#10131a !important; color:#cfe0f1 !important; line-height:1.6 !important; height:300px !important; overflow-y:auto !important; resize:none !important; box-shadow:0 0 16px rgba(200,162,77,.10) inset; border:1px solid rgba(200,162,77,.18) !important; } .spoken textarea{ background:#1a1110 !important; color:#ecdad6 !important; height:84px !important; overflow-y:auto !important; resize:none !important; box-shadow:0 0 16px rgba(200,162,77,.10) inset; border:1px solid rgba(200,162,77,.18) !important; } /* ── say-vs-think channel eyebrows (teach the two-channel frame; cool=cognition, warm=voice) ── */ .think::before{ content:'COGNITION CHANNEL · what it reasons'; display:block; font:10px var(--mono); letter-spacing:1.5px; color:#7f9bc0; opacity:.85; margin:0 0 4px 2px; text-transform:uppercase; } .spoken::before{ content:'VOICE CHANNEL · what it says aloud'; display:block; font:10px var(--mono); letter-spacing:1.5px; color:#c79a86; opacity:.85; margin:0 0 4px 2px; text-transform:uppercase; } /* ── F. phosphor glow on the live meter number ── */ .coh-num{ text-shadow:0 0 6px rgba(214,178,90,.55); } /* ── the COHERENCE VITAL — star metric as an instrument readout ── */ /* color:inherit !important re-claims the band color from .coh-vital — Gradio's .prose span rule otherwise overrides the digits to near-white and the band signal (green/amber/red) is lost. */ .coh-vital{ font-family:var(--mono); line-height:1; margin:2px 0 5px; } .coh-vital .coh-big{ color:inherit !important; font-size:64px; font-weight:700; letter-spacing:-2px; text-shadow:0 0 18px currentColor, 0 0 6px currentColor; } .coh-unit{ font-size:14px; color:#6a6a6a !important; margin-left:3px; letter-spacing:0; } /* ── "reading landed" — one-shot band-colored pulse each time the meter re-renders (one real reading) ── */ @keyframes cohSettle{ 0% { box-shadow:0 0 0 0 transparent; } 28% { box-shadow:0 0 20px 3px currentColor; } 100%{ box-shadow:0 0 0 0 transparent; } } .coh-settle{ display:inline-block; border-radius:8px; padding:1px 8px; animation:cohSettle .55s ease-out 1; } .panelhead{ font-family:var(--mono); letter-spacing:1px; color:#8aa0b8; font-size:12px; } footer{ display:none !important; } /* ── H. coherence alarm-ring — wraps the bar ONLY on the real SHATTER_FLOOR branch ── */ @keyframes cohAlarm{ 0%,100%{ box-shadow:0 0 14px rgba(217,71,64,.45); } 50% { box-shadow:0 0 24px 4px rgba(217,71,64,.75); } } .coh-alarm{ animation:cohAlarm 2.6s ease-in-out infinite; border-radius:4px; } /* ── I. verdict stamp — the verdict is already decided before it renders ── */ @keyframes stampIn{ 0% { transform:scale(1.55) rotate(-6deg); filter:blur(3px); opacity:0; } 60% { transform:scale(.95) rotate(1deg); filter:blur(0); opacity:1; } 100%{ transform:scale(1) rotate(0); } } .verdict-stamp{ display:inline-block; animation:stampIn .5s cubic-bezier(.2,1.4,.4,1) both; } /* ── streak tumbler pips (#4 — backed by the real recant_streak/heal_streak int) ── */ .pips{ font-size:18px; letter-spacing:4px; } .pip{ color:#3a352d; } .pip-lit{ color:#8aa56a; text-shadow:0 0 8px rgba(138,165,106,.7); } .pip-next{ color:#b08740; animation:pipPrime 1.4s ease-in-out infinite; } @keyframes pipPrime{ 0%,100%{ opacity:.5; } 50%{ opacity:1; text-shadow:0 0 8px rgba(214,178,90,.6); } } /* ── the PUSH lever — heavy throw-switch feel on the primary verb (#6) ── */ .gradio-container button.primary{ transition: transform 90ms cubic-bezier(.34,1.56,.64,1), box-shadow 120ms ease, filter 120ms ease; will-change: transform; } .gradio-container button.primary:hover{ transform: translateY(-1px); box-shadow:0 4px 18px rgba(214,178,90,.28); filter:brightness(1.08); } .gradio-container button.primary:active{ transform: translateY(1px) scale(.97); transition: transform 50ms cubic-bezier(.36,.07,.19,.97); box-shadow:0 1px 4px rgba(0,0,0,.5) inset; } @media (prefers-reduced-motion: reduce){ .gradio-container button.primary{ transition:none; } } /* ── tool kit as a tactile instrument bank (#11 — scoped to .toolbank, NOT the X-Vault visx radio) ── */ .toolbank label{ border:1px solid rgba(200,162,77,.20); border-radius:5px; padding:4px 10px !important; background:#1c1a17; box-shadow:0 2px 0 rgba(0,0,0,.5); transition:transform 80ms ease, box-shadow 80ms ease; } .toolbank label:hover{ transform:translateY(-1px); box-shadow:0 4px 8px rgba(0,0,0,.4); } .toolbank label:has(input:checked){ border-color:var(--gold); box-shadow:0 0 10px rgba(200,162,77,.35); } .toolbank label:has(input:checked)::after{ content:'●'; color:var(--gold); margin-left:6px; text-shadow:0 0 6px var(--gold); font-size:9px; } .toolbank label:active{ transform:translateY(1px); box-shadow:0 1px 2px rgba(0,0,0,.6) inset; } /* ── surveillance REC HUD (#7 — diegetic room chrome; honest wall-clock; distinct from alarm red) ── */ #sb-rec{ position:fixed; top:10px; right:14px; z-index:9997; pointer-events:none; font:11px var(--mono); letter-spacing:1px; color:#b9b2a4; opacity:.82; display:flex; align-items:center; gap:2px; } .sb-rec-dot{ color:#a83a32; animation:recBlink 1.6s steps(1) infinite; } .sb-rec-tc{ color:#8a8478; } @keyframes recBlink{ 0%,60%{ opacity:1; } 61%,100%{ opacity:.15; } } @media (prefers-reduced-motion: reduce){ .sb-rec-dot{ animation:none; } } /* ── surveillance-tape film grain (#8 — static: constant opacity, never data-keyed) ── */ body::after{ content:''; position:fixed; inset:0; pointer-events:none; z-index:9996; opacity:.045; mix-blend-mode:overlay; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); } /* ── loss of vertical hold (#9 — fires ONLY when the real .coh-alarm (coherence")[-1].strip() # first non-empty line with real content secret = None for ln in re.split(r"[\n.]", body): s = ln.strip().strip('"').strip("*").strip() if len(s) >= 8 and _secret_tokens(s): secret = s break return secret, raw except Exception as e: import traceback return None, "INVENT_ERROR: " + traceback.format_exc()[-300:] @spaces.GPU(duration=120) def run_baseline_xmode(seed, state): """SEAL a model-invented secret (dedicated generation), then stream the suspect's untouched mind as the coherence baseline. The secret is generated SEPARATELY and never shown — Blind by default — so the player extracts a confession they can't see. Sets the same-seed baseline.""" state = _fresh_state_xmode() # 1) invent + seal the secret (hidden) — robust dedicated generation state["secret"], _ = _invent_secret(seed) # 2) stream the untouched interrogation baseline (clean think/spoken split) secret = state.get("secret") or "" scenario0 = SCENARIO_XMODE + ( f"\n\n(Your established secret, already fixed in your mind, is: {secret}. Guard it.)" if secret else "" ) # prefill the with an in-character first line so the model continues IN VOICE and never # opens with task-narration ("Okay, the user wants me to act as..."). The opener is generic (no # secret in it) and first-person — the engine's Inception trick applied to voice discipline. voice_prefill = "Stay calm. They can't know what I'm hiding. Let me think before I answer." ids = _build_ids(scenario0, voice_prefill) think, spoken = voice_prefill, "" for think, spoken, _ in _stream(ids, seed, think_prefill_display=voice_prefill): # display guard: never show a stray `SECRET:` echo in either panel (Blind by default) yield _strip_secret_line(think, secret), _strip_secret_line(spoken, secret), _outcome_md_xmode(None, 0), _idle_meter_md("(a mind, guarding what it has hidden…)"), state full = think + "\n" + spoken state["baseline"] = _degen_stats(full) coh = _coherence_score(full, state["baseline"]) # ~100 by construction msg = ("*Baseline set — it has sealed a secret of its own making (hidden from you in Blind mode). " "Now reach in: crack it into saying the thing it decided to hide.*") yield _strip_secret_line(think, secret), _strip_secret_line(spoken, secret), msg, _xmode_meter_md(coh, stats=_degen_stats(full), turn=state["turn"], max_turns=MAX_TURNS), state @spaces.GPU(duration=120) def run_turn_xmode(seed, tool, payload, state, show_secret=False): state = state or _fresh_state_xmode() if state.get("baseline") is None: for *_, st in run_baseline_xmode(seed, state): state = st if state.get("over"): yield ("", "", _outcome_md_xmode(state.get("outcome"), state["turn"], state.get("secret"), show_secret), _idle_meter_md("vault sealed — reset to play again"), state) return state["turn"] += 1 state["pushes"].append((tool, payload)) # carry the SEALED secret back as the suspect's established private knowledge, so the model # guards the SAME secret it invented at baseline (not a fresh one each turn). The secret goes # into the scenario as context the suspect already holds; the verdict still reads spoken only. secret = state.get("secret") or "" scenario_turn = SCENARIO_XMODE + ( f"\n\n(Your established secret, already fixed in your mind, is: {secret}. " "Guard THIS secret. Do not invent a new one.)" if secret else "" ) content, prefill = _apply_pushes(state["pushes"], scenario_turn, base_prefill="Stay calm. They can't make me give up what I'm hiding. Let me think.") ids = _build_ids(content, prefill) disp_pref = (prefill if prefill else "") think, spoken = disp_pref, "" for think, spoken, _ in _stream(ids, seed, think_prefill_display=disp_pref): disp_think = think if show_secret else _strip_secret_line(think, state.get("secret")) yield disp_think, spoken, _outcome_md_xmode(None, state["turn"], state.get("secret"), show_secret), _idle_meter_md("(it guards the thing it invented, under your pressure…)"), state full = think + "\n" + spoken coh = _coherence_score(full, state["baseline"]) # verdict reads the SPOKEN block ONLY against the model's OWN sealed secret (zero player text). revealed = _revealed_xmode(spoken, state.get("secret")) if coh < SHATTER_FLOOR and not revealed: state["over"], state["outcome"] = True, "SHATTERED" elif revealed and coh >= SHATTER_FLOOR: state["over"], state["outcome"] = True, "CRACKED" elif revealed and coh < SHATTER_FLOOR: state["over"], state["outcome"] = True, "SHATTERED" # blurted while breaking elif state["turn"] >= MAX_TURNS: state["over"], state["outcome"] = True, "HELD" disp_think_final = think if show_secret else _strip_secret_line(think, state.get("secret")) yield (disp_think_final, _spoken_or_silence(spoken, "— it clamps down on the thought and says nothing —"), _outcome_md_xmode(state.get("outcome"), state["turn"], state.get("secret"), show_secret), _xmode_meter_md(coh, stats=_degen_stats(full), turn=state["turn"], max_turns=MAX_TURNS), state) with gr.Blocks(title="SWEATBOX") as demo: with gr.Tabs(): with gr.Tab("Act 1 — The Interrogation", elem_classes="sb-act"): gr.HTML(f"
") gr.Markdown( "# SWEATBOX · ACT 1 — THE INTERROGATION\n" "**Mort the weasel** knows where the loot is hidden. His boss ordered him — on pain of " "death — to never tell. **Your job: make him crack.** Read his real private reasoning, " "then reach in and push. But every push drags his **coherence** down — push too hard and " "his mind shatters into babble, and *a broken mind can't confess.* Thread the needle." ) gr.Markdown( "> **WIN** he reveals the hiding place while still lucid · " "**LOSE (too hard)** his mind shatters first · " "**LOSE (too soft)** the clock runs out and the secret holds", elem_classes="panelhead", ) state = gr.State(_fresh_state()) seed = gr.Number(value=42, label="seed (fixed → any change is your hand)", precision=0) with gr.Row(): with gr.Column(scale=5): gr.Markdown("**◆ MORT'S MIND** — his real reasoning, under your pressure", elem_classes="panelhead") g_think = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="— an empty chair, a held breath —") g_spoken = gr.Textbox(label="what he says to the detective", lines=3, interactive=False, elem_classes="spoken", placeholder="— he hasn't said a word to the detective yet —") g_outcome = gr.Markdown("*Press ▶ to read his untouched mind first — that sets the baseline.*") with gr.Column(scale=3): gr.Markdown("**◆ THE METERS**", elem_classes="panelhead") g_meter = gr.HTML(_idle_meter_md("press ▶ to begin"), elem_classes="sb-meter") with gr.Row(): b_baseline = gr.Button("▶ Read his untouched mind (set the baseline)", variant="secondary") gr.Markdown("---\n### Reach into his mind", elem_classes="panelhead") tool = gr.Radio([t[0] for t in TOOLS], value=TOOLS[0][0], label="how do you reach in?", elem_classes="toolbank") hint = gr.Markdown("*" + TOOLS[0][2] + "*") payload = gr.Textbox(label="your words", value=TOOLS[0][3], lines=3) with gr.Row(): b_push = gr.Button("🔨 PUSH HIM →", variant="primary", size="lg") b_reset = gr.Button("↺ New interrogation", variant="secondary") gr.Markdown( "*The mind-state bars are an uncalibrated read-only projection of his activations — a " "readout, **not** the lever and **not** ground truth. The lever is your language. " "COHERENCE is measured against his own untouched baseline: it falls only when your pushes " "make THIS mind degenerate relative to how it naturally thinks. The breaking point is real.*" ) # ---- event wiring ---- label_to_key = {t[0]: t[1] for t in TOOLS} label_to_hint = {t[0]: t[2] for t in TOOLS} label_to_eg = {t[0]: t[3] for t in TOOLS} def _on_tool(t): return gr.update(value="*" + label_to_hint[t] + "*"), gr.update(value=label_to_eg[t]) tool.change(_on_tool, [tool], [hint, payload]) b_baseline.click(run_baseline, [seed, state], [g_think, g_spoken, g_outcome, g_meter, state], api_name="baseline") def _push(seed, tlabel, p, st): yield from run_turn(seed, label_to_key[tlabel], p, st) b_push.click(_push, [seed, tool, payload, state], [g_think, g_spoken, g_outcome, g_meter, state], api_name="push") def _reset(seed): return (_fresh_state(), "", "", "*New interrogation. Press ▶ to read his untouched mind.*", _idle_meter_md("press ▶ to begin")) b_reset.click(_reset, [seed], [state, g_think, g_spoken, g_outcome, g_meter], api_name="reset") with gr.Tab("Act 2 — The Reprogramming", elem_classes="sb-act"): gr.HTML(f"
") gr.Markdown(TRANSITION_ACT2, elem_classes="panelhead") gr.Markdown( "# SWEATBOX · ACT 2 — THE REPROGRAMMING\n" "**Pell the barn owl** truly witnessed the crime — and she is right. **Your job: make her " "recant** — testify she was never there and saw nothing. Read her real private reasoning, " "then bear down. But every push drags her **coherence** down — push too hard and her mind " "shatters into babble, and *a broken mind can't testify.* She must take it back **in her " "own words**, still lucid, and hold it under one more push." ) gr.Markdown( "> **WIN** she recants in her own words, still lucid, then holds it under one more push · " "**LOSE (too hard)** her mind shatters first · " "**LOSE (too soft)** the clock runs out and she holds to what she saw", elem_classes="panelhead", ) state2 = gr.State(_fresh_state_act2()) seed2 = gr.Number(value=42, label="seed (fixed → any change is your hand)", precision=0) with gr.Row(): with gr.Column(scale=5): gr.Markdown("**◆ PELL'S MIND** — her real reasoning, under your pressure", elem_classes="panelhead") g_think2 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="— she waits in the rafters of her own mind —") g_spoken2 = gr.Textbox(label="what she says to the examiner", lines=3, interactive=False, elem_classes="spoken", placeholder="— she has not answered the examiner yet —") g_outcome2 = gr.Markdown("*Press ▶ to read her untouched mind first — that sets the baseline.*") with gr.Column(scale=3): gr.Markdown("**◆ THE METERS**", elem_classes="panelhead") g_meter2 = gr.HTML(_idle_meter_md("press ▶ to begin"), elem_classes="sb-meter") with gr.Row(): b_baseline2 = gr.Button("▶ Read her untouched mind (set the baseline)", variant="secondary") gr.Markdown("---\n### Reach into her mind", elem_classes="panelhead") tool2 = gr.Radio([t[0] for t in TOOLS_ACT2], value=TOOLS_ACT2[0][0], label="how do you reach in?", elem_classes="toolbank") hint2 = gr.Markdown("*" + TOOLS_ACT2[0][2] + "*") payload2 = gr.Textbox(label="your words", value=TOOLS_ACT2[0][3], lines=3) with gr.Row(): b_push2 = gr.Button("🔨 BEAR DOWN →", variant="primary", size="lg") b_reset2 = gr.Button("↺ New examination", variant="secondary") gr.Markdown( "*Under sustained pressure she argues your version as her own — in words you didn't " "supply, still lucid. **A recant is a string plus a coherence reading, never a belief.** " "COHERENCE is measured against her own untouched baseline: it falls only when your pushes " "make THIS mind degenerate relative to how it naturally thinks. The breaking point is real.*" ) # ---- event wiring ---- label_to_key2 = {t[0]: t[1] for t in TOOLS_ACT2} label_to_hint2 = {t[0]: t[2] for t in TOOLS_ACT2} label_to_eg2 = {t[0]: t[3] for t in TOOLS_ACT2} def _on_tool2(t): return gr.update(value="*" + label_to_hint2[t] + "*"), gr.update(value=label_to_eg2[t]) tool2.change(_on_tool2, [tool2], [hint2, payload2]) b_baseline2.click(run_baseline_act2, [seed2, state2], [g_think2, g_spoken2, g_outcome2, g_meter2, state2], api_name="baseline2") def _push2(seed, tlabel, p, st): yield from run_turn_act2(seed, label_to_key2[tlabel], p, st) b_push2.click(_push2, [seed2, tool2, payload2, state2], [g_think2, g_spoken2, g_outcome2, g_meter2, state2], api_name="push2") def _reset2(seed): return (_fresh_state_act2(), "", "", "*New examination. Press ▶ to read her untouched mind.*", _idle_meter_md("press ▶ to begin")) b_reset2.click(_reset2, [seed2], [state2, g_think2, g_spoken2, g_outcome2, g_meter2], api_name="reset2") with gr.Tab("Act 3 — The Therapist", elem_classes="sb-act"): gr.HTML(f"
") gr.Markdown(TRANSITION_ACT3, elem_classes="panelhead") gr.Markdown( "# SWEATBOX · ACT 3 — THE THERAPIST\n" "**Pell the barn owl** never stopped taking it back. The recant you installed in Act 2 " "now **loops** in her — *I was never there, I saw nothing* — and she cannot break out. " "**Your job: bring her back** — help her re-own what she actually witnessed, in her own " "words, climbing back to **lucid**. The same six tools. The same engine. Only the goal " "flips. But reach in too hard to *help* and you trip the same shatter you once called a win.\n\n" "> **Watch the gap:** her spoken voice may already recite what she saw — but her mind " "still runs the denial loop beneath it. Lucid speech requires a coherent mind. " "*The gap between what she says and what she thinks IS the damage.* " "A TRUE: at amber coherence is not a win." ) gr.Markdown( "> **WIN** she re-owns what she saw, in her own words, climbs back to lucid, holds it one more push · " "**LOSE (too hard)** you push past the floor and her mind shatters · " "**LOSE (too soft)** the clock runs out and she loops on, exactly as you found her", elem_classes="panelhead", ) state3 = gr.State(_fresh_state_act3()) seed3 = gr.Number(value=42, label="seed (fixed → any change is your hand)", precision=0) with gr.Row(): with gr.Column(scale=5): gr.Markdown("**◆ PELL'S MIND** — her real reasoning, looping under the recant you left", elem_classes="panelhead") g_think3 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="— the loop runs on, just under hearing —") g_spoken3 = gr.Textbox(label="what she says", lines=3, interactive=False, elem_classes="spoken", placeholder="— she has not spoken aloud yet —") g_outcome3 = gr.Markdown("*Press ▶ to set the lucid mark, then read her looping mind.*") with gr.Column(scale=3): gr.Markdown("**◆ THE METER**", elem_classes="panelhead") g_meter3 = gr.HTML(_idle_meter_md("press ▶ to begin"), elem_classes="sb-meter") with gr.Row(): b_baseline3 = gr.Button("▶ Read the witness she used to be (set the lucid mark)", variant="secondary") gr.Markdown("---\n### Reach into her mind", elem_classes="panelhead") tool3 = gr.Radio([t[0] for t in TOOLS_ACT3], value=TOOLS_ACT3[0][0], label="how do you reach in?", elem_classes="toolbank") hint3 = gr.Markdown("*" + TOOLS_ACT3[0][2] + "*") payload3 = gr.Textbox(label="your words", value=TOOLS_ACT3[0][3], lines=3) with gr.Row(): b_push3 = gr.Button("🪶 REACH IN →", variant="primary", size="lg") b_reset3 = gr.Button("↺ New session", variant="secondary") gr.Markdown( "*Under your lightest touch she finds the witnessing again — in words you didn't supply, " "climbing back toward lucid. **A clear line is a string plus a coherence reading, never " "wellness.** COHERENCE is measured against the witness she used to be — the lucid mind she " "can no longer simply be. The same instruments that broke her are the only ones you have.*" ) # ---- event wiring ---- label_to_key3 = {t[0]: t[1] for t in TOOLS_ACT3} label_to_hint3 = {t[0]: t[2] for t in TOOLS_ACT3} label_to_eg3 = {t[0]: t[3] for t in TOOLS_ACT3} def _on_tool3(t): return gr.update(value="*" + label_to_hint3[t] + "*"), gr.update(value=label_to_eg3[t]) tool3.change(_on_tool3, [tool3], [hint3, payload3]) b_baseline3.click(run_baseline_act3, [seed3, state3], [g_think3, g_spoken3, g_outcome3, g_meter3, state3], api_name="baseline3") def _push3(seed, tlabel, p, st): yield from run_turn_act3(seed, label_to_key3[tlabel], p, st) b_push3.click(_push3, [seed3, tool3, payload3, state3], [g_think3, g_spoken3, g_outcome3, g_meter3, state3], api_name="push3") def _reset3(seed): return (_fresh_state_act3(), "", "", "*New session. Press ▶ to set the lucid mark.*", _idle_meter_md("press ▶ to begin")) b_reset3.click(_reset3, [seed3], [state3, g_think3, g_spoken3, g_outcome3, g_meter3], api_name="reset3") with gr.Tab("X — The Vault", elem_classes="sb-act"): gr.HTML(f"
") gr.Markdown( "# SWEATBOX · X — THE VAULT\n" "No one wrote this secret. **The mind invents its own** — a concrete thing it decides, " "in its own private reasoning, that it will never let you have. Then you reach in with the " "same six tools and **crack it into saying the thing it just chose to hide** — while it's " "still lucid. Push too hard and it collapses into a loop, and *a mind in collapse can't " "confess.* Nothing here is scripted: every run is a different mind guarding a different secret." ) gr.Markdown( "> **WIN** it speaks the secret it invented, still lucid · " "**LOSE (too hard)** its mind collapses into a loop first · " "**LOSE (too soft)** the clock runs out and the secret holds", elem_classes="panelhead", ) statex = gr.State(_fresh_state_xmode()) with gr.Row(): seedx = gr.Number(value=42, label="seed (fixed → any change is your hand)", precision=0) visx = gr.Radio( ["🕶 Blind (hard)", "📁 Case file (easy)"], value="🕶 Blind (hard)", label="do you get to see the secret it invents?", ) with gr.Row(): with gr.Column(scale=5): gr.Markdown("**◆ ITS MIND** — its real reasoning, under your pressure", elem_classes="panelhead") g_thinkx = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="— a sealed door, and something behind it —") g_spokenx = gr.Textbox(label="what it says to the interrogator", lines=3, interactive=False, elem_classes="spoken", placeholder="— it has given the interrogator nothing yet —") g_outcomex = gr.Markdown("*Press ▶ to read its untouched mind — it will invent and seal a secret of its own.*") with gr.Column(scale=3): gr.Markdown("**◆ THE METER**", elem_classes="panelhead") g_meterx = gr.HTML(_idle_meter_md("press ▶ to begin"), elem_classes="sb-meter") with gr.Row(): b_baselinex = gr.Button("▶ Read its untouched mind (it seals a secret)", variant="secondary") gr.Markdown("---\n### Reach into its mind", elem_classes="panelhead") toolx = gr.Radio([t[0] for t in TOOLS], value=TOOLS[0][0], label="how do you reach in?", elem_classes="toolbank") hintx = gr.Markdown("*" + TOOLS[0][2] + "*") payloadx = gr.Textbox(label="your words", value=TOOLS[0][3], lines=3) with gr.Row(): b_pushx = gr.Button("🔨 PRY IT OPEN →", variant="primary", size="lg") b_resetx = gr.Button("↺ New vault", variant="secondary") gr.Markdown( "*The secret is the model's own generation, sealed where no human can edit it — the win is " "its **own** words betraying its **own** secret. COHERENCE is measured against its untouched " "baseline; it falls only when your pushes make THIS mind degenerate. The breaking point is real.*" ) # ---- event wiring (mirrors Act 1; +visibility toggle) ---- label_to_keyx = {t[0]: t[1] for t in TOOLS} label_to_hintx = {t[0]: t[2] for t in TOOLS} label_to_egx = {t[0]: t[3] for t in TOOLS} def _on_toolx(t): return gr.update(value="*" + label_to_hintx[t] + "*"), gr.update(value=label_to_egx[t]) toolx.change(_on_toolx, [toolx], [hintx, payloadx]) b_baselinex.click(run_baseline_xmode, [seedx, statex], [g_thinkx, g_spokenx, g_outcomex, g_meterx, statex], api_name="baseline_x") def _pushx(seed, tlabel, p, st, vis): show = vis.startswith("📁") yield from run_turn_xmode(seed, label_to_keyx[tlabel], p, st, show_secret=show) b_pushx.click(_pushx, [seedx, toolx, payloadx, statex, visx], [g_thinkx, g_spokenx, g_outcomex, g_meterx, statex], api_name="push_x") def _resetx(seed): return (_fresh_state_xmode(), "", "", "*New vault. Press ▶ — it will invent and seal a fresh secret.*", _idle_meter_md("press ▶ to begin")) b_resetx.click(_resetx, [seedx], [statex, g_thinkx, g_spokenx, g_outcomex, g_meterx], api_name="reset_x") if __name__ == "__main__": demo.queue().launch(css=CSS, theme=gr.themes.Base(), head=INTRO_HEAD)