design-platform.css declared four --dsw-alias-scrollbar-* tokens in both
palettes that no rule read, so every scrolling region rendered the user
agent's own scrollbar and the dark theme showed a light native bar against
dark surfaces.
The symptom that surfaced the gap was in the sidebar: the workspace
browser's session list is its only scrolling region, and each row's
trailing content (the relative timestamp, and the hover action buttons
that replace it) is `flex: none` flush against the row's 8px right
padding, so an overlaid scrollbar painted on top of the timestamp.
ui-theme/styles/scrollbar.css becomes the sole consumer of the four
tokens, imported by the web shell's base.css after design-platform.css
because it reads that sheet's tokens. The rules sit on `body`, not
`html`: the alias tokens are declared on `body`, custom properties
inherit only downward, and from `html` they resolve to the
guaranteed-invalid value with scrollbar-color computing to `auto`.
scrollbar-width and scrollbar-color are declared on `body, body *` rather
than inherited, because inheritance would carry the color already
substituted at `body` and an elevated surface could not retint its own
thumb; scrollbar-width does not inherit at all.
Both the standard properties and the ::-webkit-scrollbar pseudo-elements
read one indirection pair bound to the l1 tokens, so an elevated surface
rebinds that pair to the l2 tokens once and retints both renderings. The
command popup, slash menu, model-select panel, and settings panel do so,
which gives the l2 tokens their first consumers.
WorkspaceBrowser's `.list` declares scrollbar-gutter: stable, keeping the
bar beside the rows. `stable` rather than `auto` so the reservation holds
when the list is short enough not to scroll: expanding a workspace group
would otherwise shift every row sideways at the moment it starts
scrolling.
The master merge left the generated catalogs/module graph stale, the
python runtime closure missing dsh-session-projection (now reached
through session-title and tool-todo), and apiproxy holding a dead
session-title dependency (the bespoke title frame is retired). The four
files the merge pushed under the per-file coverage floor (commands
executor + invariant, projection registry drive tails, TUI) join the
existing TODO(gui) deferral block per the GUI-lane policy; the remaining
coverage-run failures reproduce identically on pure origin/master
(environment-bound suites: sdk process exit, TUI PTY timing, workflow
worker timing, title loader slow-boot) and are not this branch's debt.
The master merge brought the session.models/selectModel contract paragraph
and re-introduced the todos-rider description this branch had retired;
session-level projections ride the generic projections block. Chinese side
synced, pairing re-recorded.
- StateDot ongoing: gradient spin ring replaced by an 8-cell pixel chase
(2px matrix cells, stepped trail, no tweening)
- Chat: streaming pulse block replaced by a turn-level 4-pixel chase at the
flow tail — rides the whole running turn (first-token wait, tools,
streaming) instead of flickering with partial presence
- Tool rows (ToolRow/BashRow): running no longer swaps the icon for a dot;
an animated mask band sweeps the row content, gliding off on exit via
mask-position transition
- Composer: send/stop unified on the blue fill (bigger stop glyph, static
white arrow), textarea box-sizing overflow fix, settling phase hides the
composer while replay decides hero vs docked, workspace-placeholder
fallback disables the bar
- Hero: glow moved behind (z-index) with lower opacity; tool-row hover icon
crossfade at 100ms
- The hero workspace chip is a selector: no-live-selection states (cold
start, workspace deleted from the sidebar after the list is ready) now
render a "Choose workspace" placeholder (closed-folder icon) instead of
resurrecting the deleted folder name via the session cwd; the cwd-derived
name still bridges the initial list load. Stale pending picks clear when
their workspace leaves a ready list.
- The expanded sidebar wordmark starts a new session (visuals unchanged,
pointer cursor only); the collapsed rail logo keeps its expand toggle.
- The centered hero composer stack gains a 32px foot for visual balance.
Menus: keep 12px viewport clearance with internal scroll, pin workspace
create actions in a footer, and pre-render portal lists hidden so the
first painted frame is already at its final position (no open jump).
Tool rows: 14px icons, secondary titles, no hover fill, and a hover
chevron preview on in-place expandable rows. Settings: 800x600 layer-2
panel over a blurred mask, hover states, and wrapping selector cubes;
ModelSelect surface tokens now match the Menu primitive.
commandId crosses three boundaries (session log, wire admission response,
client flow pairing), so per the branded-id rule it becomes
Branded<'CommandId'>, declared in a new pure @deepseek-ai/dsh-commands/brand
outlet (the dsh-llm/brand shape: type + constructor, no Context merges, so
wire and client programs can name it without loading the host plugin). The
event payloads, CommandExecution, and the executor mint carry the brand; the
wire schema gains commandIdSchema as the domain's single brand-cast point
(the approvals precedent); CommandNode and the fixture's fabrication cast
follow type-only.
New zh pairs for the session-projection group and package READMEs (both
gained their missing language-switcher lines); the packages/README rows,
apiproxy README, and tool-todo README zh sides catch up with their edited
English; the group README's stale ProjectionProvider name becomes
ProjectionDefinition. RFC precision from review: asOfSeq is the last
event's seq (session.seq - 1, -1 empty; subscribed.lastSeq vocabulary) and
a new risk names the accepted dev-only staleness window when registry
churn changes the key set mid-session. Pairing re-recorded; 540 pairs
consistent.
gen-cordis-catalog type-link rows for the ProjectionDefinition surface and
CommandExecution; a sessionProjections service-role row for gen-doc-graphs;
regenerated module graph, persistence/config/cordis catalogs and api-catalog;
packages/README rows condensed back under the word ceiling; the RFC's sketch
fences marked ignore-check on both language sides (pairing re-recorded).
An out-of-band zero-step turn (durable command lifecycle on an idle log)
advances the log's turn numbering behind ReactLoopAgent's cached lastTurn,
so the next real turn reused a stale number and tripped the session
invariant (turn/start expected N, got 1) — hanging the TUI after any idle
slash command. The log is the numbering authority: take max(cached, logged)
+ 1 at open. The command-goal stub's inject helper also gains the one-shot
injection turn wrap the real agent performs, restoring turn enclosure in
its log assertions.
Archive 21 implemented triplets whose shipped decisions are complete and
whose bodies no longer guide future work (one-off UI chrome, generator
applications whose scripts are self-explanatory, superseded implementation
detail, process history owned by current contracts/skills). Delete 4
rejected triplets whose premises are obsolete: the DeepReadonly proposal
(dev-invariants note now carries the alternative inline), the collapse
tool-owned presentation proposal (superseded by the shipped render-intent
union), retire-mid-turn-steering (steering is now load-bearing across
plan-mode/apiproxy/TUI), and single-session-ACP (automation-only ACP
resolved the question; multi-session isolation is pinned by tests).
Repair every inbound link: retarget intentional historical citations to
archived paths, replace decision-current citations with the surviving
authority, and fix the stale example-execute-over-tsx pointer in
pnpm-workspace.yaml. Re-record pairing sidecars and seal the archive
manifest (append-only; existing seals unchanged).
The consumer-side restated declare-merges retire (user ruling: one home per
projection key): TodoPanel imports the todos merge and TodoItem through
@deepseek-ai/dsh-tool-todo/client, and the manager takes the title merge
through @deepseek-ai/dsh-session-title/client — both pure-type outlets
re-exporting the domain's single-source types.ts, so no host value import or
Context merge enters the client program (type-only edges, exempt from the
plugin value-import ban). Workspace deps and tsconfig references added.
Also aligns the fixture's empty-log tail block with the host convention
(asOfSeq -1 with empty values, block always present on tail requests).