Remove dead design-session citations, change narration, indexical
stamps, and review-adjacent justification found by the
dsh-trim-cot-leakage recall batteries in prose that landed after the
last purge. Bilingual README pairs are re-recorded.
One Vite build emits dist/index.html and dist/preview.html sharing every
chunk; the only difference is one prepended bootstrap entry whose module
connects the worker host, so the page from the stock entry onward is the
served startup chain verbatim. The dist moves to a relative base so the
preview mounts under any static directory, and the served form anchors
deep SPA-fallback paths with a rendered <base href="/">. The preview-boot
e2e serves the real built pages, packs the VFS image when absent, and
holds the boot line's lowering contract, the interactive hero, and a
clean page-error channel in headless Chromium.
Two private experimental packages run the whole harness tree inside one
dedicated Web Worker. dsh-experimental-webworker-runtime owns the in-memory
VFS (BigInt stats with per-path identity and strictly increasing mtimes),
the CommonJS wrapper loader over a lazily-evaluated builtin table whose
shims typecheck against Node's own module types, the postMessage tunnel
speaking plain HTTP, the AsyncLocalStorage runtime, and the worker
assembly. dsh-experimental-webworker-packer lowers every module body at
pack time against the shared wrapper contract, sweeps the profile closure
by static reachability, and writes a deterministically gzip-compressed tar
the worker inflates through the browser's native DecompressionStream while
it downloads.
The turn-error Definition suppressed its node permanently once the owning
turn carried any llm/retry event — a rule from the retired model where a
retry opened a new numbered turn. Retries now run inside the failing turn,
so the suppression hid exactly the exhausted terminal failure it existed
to defer to: spending every transient retry left the conversation with a
neutral collapsed retry row and no error row at all.
Delete the suppression: turn-error matches only turn/start and error-reason
turn/end, and renders whenever its turn recorded a terminal error; the
settled retry chain renders beside it through the separate model-retry
node. The Definition suite now asserts the exhausted-retry error node in
full history, tail-only windows, and after prepending the chain, and a new
keyless live e2e scenario exhausts a scenario-owned two-retry policy and
pins the terminal error row beside the settled retry row (the scaffold
gains replayRetryPolicy so exhaustion runs in milliseconds).
Both stale notes are corrected to the same-turn retry reality, and the new
bug-fix note owns the removal rationale.
- dsh-authorization's manifest becomes a release member on current
master's terms: version matches the root 0.1.0-rc.6 and
publishConfig.access is public, which the constraints gate and the
tarball pack's version verify both enforce after the master merge.
- Regenerate docs/module-graph (zh mirror included) for the
authorization package and the llm-pi-ai -> authorization edge; the
graph gate lives outside doc-sync and was never regenerated when the
package was added.
- The built-bin smoke seeds the versioned credentials document; this
branch's provider refuses the pre-release flat layout by design, and
the master-side test still wrote the old shape.
Why the record union is one step more abstract than pi-ai's credential
in exactly two places, why a record key names the owning plugin rather
than the provider, why the flow owns the write, and why the interaction
travels with the request instead of a registry. Cross-links the release
fix it supersedes, and states what is still missing: the wire contract
and the Models-page control that would let a human start a login.
The two web e2e goldens regain exactly the openai-codex option line
they lost when the provider was withheld.
A caret Backspace or Delete replaces no selection, so `beforeinput` reports
the bare caret and the previous derivation produced a negative inserted
length and fell back to the ambiguous scan. The delete half of the defect
survived, and the component test missed it by pre-expanding the selection to
the span the engines never report.
The range for a caret delete now comes from the direction `inputType` names
and the number of characters the draft actually lost, measured rather than
assumed to be one, so a grapheme, word, or line deletion sizes correctly.
Only the insert and delete families are recorded; a history replay reports
wherever the caret sits and would name a wrong span while passing every check.
Component tests cover the caret Backspace, Delete, and word-delete gestures,
and an assembled browser scenario drives them as real key presses, which is
the only place an engine's reported range is observable.
The card-wide `border-box` reached `.fieldMirror`, so the growth cap counted
text plus padding. The inline variant carries none and landed on the declared
line count, while the optionless variant's 16px inset spent two thirds of a
line and delivered its last one as an 8px sliver. The e2e measured only the
inline shape, so nothing caught the drift.
The mirror now takes `box-sizing: content-box`, which states the cap in the
units it is written in, and the cap moves to six lines. The e2e asserts whole
text lines rather than a box height, and covers the optionless shape — asked
straight through the user-questions seam, since a layout metric needs no model
round — including that the reserved empty field is fully covered by its own
control.
Replace per-plugin tapIndex regex edits with pure-data IndexInjection rows
collected fresh per render over one webserver/index-inject event. One table,
two renderers: the served form renders rows into index.html; a static worker
form ships the same rows over its boot payload. tapIndex survives as the
raw-HTML escape hatch, applied after row rendering; client-modules and
ui-theme move to the event, and the manifest global renders as
globalThis["__DSH_BOOT__"].
The client boot chain gains the seams a pre-injected transport needs: the
module loader takes loadBundle from the transport global by default, HTTP
prefetch stands down when a transport owns bundle bytes, the web-app bundle
can decline frontend serving, the gateway client installs a namespace's
whole method group inside its fiber apply so a parked dependent never
observes the service without its methods, and the dynamic-code precheck
gates through new Function so hosts without a real node:vm keep the
define-time parse gate.
A question that carried options collected its free-text answer in a
single-line input: a long sentence scrolled sideways inside one line and
Shift+Enter was inert, so an answer with structure could not be typed.
The optionless question already used a textarea, but a fixed 64-140px box
that never followed the draft.
Both shapes now answer into one AnswerField: a `textarea rows=1` sharing a
grid cell with a hidden mirror that renders the draft plus a trailing
newline and so owns the height. Soft wraps are invisible to a '\n' count,
so the mirror is what grows the box; growth stops at eight lines and the
textarea scrolls from there, keeping the choices the answer belongs to in
view. Enter still continues and submits, Shift+Enter breaks the line, and
the IME guard is unchanged.
The themed WebKit scrollbar skin keeps a wide table's horizontal bar
permanently painted. Chromium never repaints state-conditioned scrollbar
styles (hover-conditioned ::-webkit-scrollbar* rules and :hover
scrollbar-color changes both compute but never reach the painted bar,
measured headed and headless), so the hover reveal toggles overflow-x
itself: hidden at rest with a padding-bottom matching the themed bar
height, auto on hover or keyboard focus with the padding released — the
appearing bar exactly replaces the padding and nothing below shifts.
Resting hidden overflow drops Chromium's implicit scroller focusability,
so wide wrappers carry an explicit tabindex for arrow-key scrolling.
Markdown tables were always rendered at natural width, so anything wider
than the 748px message column could only be read through horizontal
scrolling. Following the deepsuite chat TableWrapper treatment: tables
under four columns (and any table inside a blockquote) now fill the column
and wrap cell text down to the cells' minimum readable width, while
four-or-more-column tables keep their natural width behind the wrapper's
horizontal scroll and carry the stable md-table-wide hook. The chat
transcript widens hooked tables past the message column with a pure-CSS
container-query breakout (100cqw against ChatView's scroll container
standing in for deepsuite's JS-measured list width), keeping the table
content aligned with the message column and clamping to neutral when the
transcript is narrower than the column.