Stop button on both generating tabs: cancels the run in flight (chat submit, Send, Complete) while KEEPING the bytes already streamed — Clear remains the one that also wipes the transcript. Each callers finally: still logs the turn as completed=False, so a halted reply is recorded as halted
tell the two final 2s cores apart: the mission ends in a before/after pair across the chat anneal (57,607 continues documents, 61,422 answers), but frame_trained was a CRAFT flag so the pre-chat core claimed a conversation frame it never saw. Chat capability is now per CHECKPOINT, derived from the manifest by counting back from the total (the boundary lands exactly on 57,607); both are labelled in the dropdown, the pre-chat baseline is always offered, and the chat-taught core stays the default
max new bytes 512 -> 2048: the window, not an arbitrary cap, is now the limit (a short prompt on 2s gets the full 2048; v1 gets the rest of its 2048 window). The reply reserve in _room used to be capped at 256, so a long paste silently shrank a big request — it now tracks the ask up to half the window, and any context-forced shortfall is stated in the stats line
byte-level repetition penalty: damps only what would CONTINUE a repeated 8-byte phrase in the reply window (a CTRL-style per-id penalty taxes ordinary English on a 256-value vocabulary); slider defaults 1.15, 1.0 = off, disclosed in the stats line
Clear now cancels the in-flight stream and starts a new conversation (ClearButton only wiped the display, so a streaming reply repainted the cleared history; the log keyed on session alone, running pre- and post-clear turns together); uncached generation RESPECTS the byte count — the silent max_new->96 clamp is replaced by a 95s budget that reports its shortfall
default to mini-beatrix-2s (mission complete): its anneal taught the conversation frame, so the core chats with no arm — description rewritten (the still-pretraining caveat was stale prose; the code-side caveats had already self-suppressed on frame_trained), no-arms line now says none is needed; v1 stays one click away as the detach exhibit
compact the status panel (228px -> ~2-3 lines): it sits above the tabs in a non-scrolling iframe, so every line pushed the controls further out of reach; all warnings and disclosures kept
fix embedded scrolling: the Spaces iframe is scrolling=no and sized to reported height, so a tall page pushes tabs/controls out of reach when the resize lags — description + automation moved into closed accordions, 1-row textbox was flex-stretched to 373px (pinned), chatbot 420->360, and a DOM observer keeps the parent height in sync
automate what an arm needs, toggle what is taste: decode follows the arm (task arms greedy — measured off-distribution punctuation collapse under sampling), examples come from the arm own training frames, empty replies explain themselves; toggles for auto-decode, family examples, and an off-by-default degenerate-run cut
fix: arm dropdown allow_custom_value — gradio validated submitted values against BOOT-TIME choices, so any arm from a non-default checkpoint was rejected server-side; this app validates paths itself (unknown/cross-core -> core-only)
per-arm TEMPLATE honored: an arm template IS its tokenizer on a byte-native model — chat transcript vs single-turn QA vs raw, and the turn-end bytes it was trained with (newline-pair arms were never being stopped; the refuted NUL arm is labeled)
arm picker: every arm trained on the selected core is selectable and swappable (29 arms, index-driven); NO chat-arm default on checkpoints that have none; per-anchor adapter geometry (n_slots 16/32) read from tensors instead of assumed — a wide arm as boot template used to crash attach
checkpoint selection: dropdown of the newest shipped checkpoints (step, bytes, val bpb, arm availability), any of them runnable WITH or WITHOUT the arm. One model is built and ZeroGPU-packed at import; switching copies new values into those same tensors (no second model, no lazy .to(cuda)) and re-verifies anchor provenance on every arm switch — an arm is never attached to a core it was not trained on. Default stays the pre-anneal exhibit pair (51,882) where core-only still shows an unconditioned model; post-anneal checkpoints carry an honest note that their bare core already chats. Verified locally: 51882+arm chats, 51882 core-only gives base continuation, armless checkpoints fall back to core-only cleanly
stop gradio orphaning event loops (the Invalid file descriptor tracebacks): safe_get_lock/safe_get_stop_event build a throwaway loop per call just to construct a Lock/Event — measured 9 loops, 7 orphaned per boot on 6.23.1; each orphan raises ValueError -1 in BaseEventLoop.__del__ when its socketpair is freed first. Lock()/Event() bind lazily on py3.10+, so the factories are replaced with plain constructors across every module that binds the names. This REMOVES loop creation: no loop, thread, process or coroutine is created. Measured after: 1 loop, 0 orphans, boot log clean
pin gradio 6.23.1: the un-awaited get_current_user coroutine is a 6.24.0 regression (measured — a hello-world app emits it on 6.24.0 and never on 6.23.1 or 5.50.0). 6.23.1 needs no code change since the Chatbot API matches; verified locally end to end: clean boot, 0 warnings, arm and core modes both answering
remove the fork-unsafe lock + fix the /data probe. spaces runs @spaces.GPU bodies in a multiprocessing ForkProcess (verified in spaces/zero/wrappers.py), so the threading.Lock I held across yields was both useless (child has private memory) and hazardous (a lock held by any parent thread at fork time is inherited locked with no owner -> child blocks forever). Removed: zero threads, zero locks, zero asyncio, zero coroutines. Also: never mkdir /data itself (non-root -> PermissionError that reads like failure); only probe the mount and create the subdirectory