Closes#58: the Context panel hung off two registrations at once (the
conversation tab and the right-Sidebar guide entry), with no way to keep
just one. A new per-user `defaultPlacement` preference — the first row of
the Plugin configuration card — picks who carries the view: the
conversation tab, the right Sidebar, or both (the default, so existing
deployments see no change).
- shared: `DefaultPlacement` vocabulary (`all` | `tab` | `sidebar`) on the
settings namespace; the Host schema gains a loose `defaultPlacement`
field so a stale persisted value degrades to `all`
- client: `placement.ts` mounts each registration through its own factory
and, on a preference flip, disposes exactly what the new value drops
(the harness's own dynamic-mount idiom); `watchSidebarContextTab`
returns its deferred-inject disposer so the sidebar mount can be taken
down and put back; the settings card leads with the placement row
The Token Stats and Timing Stats legends — the only two SliceList users — sat 6px apart between rows; 4px tightens the list without touching the two-tier row anatomy.
The row's own container query (1045px) folded a 1280px viewport to 2x2: the shell's sidebar plus the tab's own frame leave only ~946px of head row there. The fold moves to 940px, so the four cards share ~231px each — narrow enough to trip the donut cards' own lc-card reflows (the ring stacks over its legend, the 8-cell grid folds to 2 columns). Four sections on one line is what the lower threshold buys.
A ring with a neighbour on each side now gives half a 0.5-unit gap off
both ends of every arc (1 unit ≈ 1% of the circumference, so ~1px on the
96px card ring), letting the card's own background draw the line between
neighbouring colours. A lone painted slice keeps its full ring — a gap
there reads as a nick — and the cut never takes more than a quarter per
end, so a sliver like the 0.2% overhead wedge never vanishes whole.
Bundle the colourful document sheet as the plugin's own icon and fill the
right-Sidebar tab type's two glyph seats with it, the way the shipped files
type does: the guide capsule's `icon`, and a new `sidebar.right.pane.tab.title`
registration that draws the emblem beside the chip label.
The chip's close control sits out of flow over the title's last 14px and an
active chip fades the 16px before it, so the shipped files chip stays readable
only by its short label. The label now carries a trailing gutter so that fade
lands past the text instead of on the last glyphs.
Registration turns rollback-safe (each disposer is tracked) so a partial
failure unwinds cleanly, and the obsolete primitives-icon resilience spec goes
with the icon read it guarded.
`SidebarRightGuideEntry` carries `order`, `title`, and an OPTIONAL
`description` again at dsh 0.1.5-rc.1 — it was required at 0.1.5-alpha.1,
dropped at 0.1.5-alpha.2, and restored optional now. The plugin's guide
capsule re-adds its `description` thunk and the `sidebar.guideDescription`
dictionary keys, so the right Sidebar's guide entry renders the one-line
subtitle the shipped Files type does.
The mirrored face marks the thunk optional: a line whose guide body ignores
it simply goes without, so the same contribution stays valid across the
whole 0.1.5 line.
The supported V3 line follows the newest release: the baseline becomes
v0.1.5-rc.1 (tag, vendored session package) and the declared release map
names 0.1.5-rc.1. The release workflow fetches the new tag, and the
disposable-profile install/uninstall was verified for real against the
published 0.1.5-rc.1 CLI (install OK -> 1 composed row -> uninstall OK ->
0 rows).
At 0.1.5-rc.1 `SidebarRightGuideEntry` regained its optional `description`
line, so the guideEntry probe pins order/title/description/icon and the
now-pointless "absent" assertion plumbing is dropped.
Every support/capability label states the 0.1.5-rc.1+ floor;
`0.1.5-alpha.x+` remains only as the V3 LOG-generation label (the format
first appeared at 0.1.5-alpha.1). The docs record the verified matrix and
the seam movement across alpha.1/alpha.2/rc.1.
The family matcher required a `v4` marker, so `deepseek-flash` requests
went unpriced. Accept `deepseek` as an alternative marker — proxy
spellings like `deepseek/deepseek-flash` land too, while foreign
flash-named models (gemini-2.0-flash) still match no family. The stats
board's price-list label and both locales' cost tooltip name the new
model beside deepseek-v4.1-flash.
Every rich detail section (system prompt, tool schema descriptions,
messages, tool results, compaction summaries, and the same cards inside
the /context modal) gains an icon-only copy control beside the Raw/MD
switch. It copies the section's exact SOURCE text, never the rendered
markdown, via the harness's own writeClipboard primitive; success flips
the glyph to a check for a beat, a rejected write claims no success, and
a repeat click inside the window is a no-op — the shipped code-block
control's behavior. Both icons and the writer are platform-module
exports present on all three supported baselines.
The added control tipped the head's trailing group out of the clipped
section card at the narrowest pane, so rich-text heads now fold that
group onto a second line under width pressure. The wrap is scoped to
those heads: the call-name head must stay one line (long MCP names
ellipsize instead).
A slice that never happened still rendered as a row — "0.0%" plus a count
borrowed from elsewhere on the card — which reads as "this ran 323 times in
no time". The ring has always skipped zero arcs; now the legend matches it,
so the card shrinks to the slices that actually carry time.
Zero slices are common: across 307 local sessions, reasoning is zero in
23.5%, answer text in 14.3%, tool args in 13.7%, and tools in 14.3% (a
one-turn "hi" session collapses from six rows to two). Overhead is the
residual and effectively never zero, so the change bites the decode and
tool rows. Every slice is a share of the wall total, so dropping rows never
distorts the remaining percentages.
The Timing card's model slice expands into Thinking / Answer / Tool args
whenever the host served the split; an older cached row (or a log whose
stream carried no block markers) keeps the single LLM Gen row, so nothing
degrades. The ring shares the generation window across the buckets in card
order, clamped exactly as tools already were.
The decode rows carry no call-count qualifier: they count decode BLOCKS,
and one model call emits zero to many of them (a single call routinely
requests several tools; most calls emit no reasoning at all), so the
session's call count was a false per-slice tally. Measured on a real
236-call session: 236 calls produced 302 tool-call blocks, and 1078 of
3037 calls emitted no reasoning. TTFT and tools keep their counts — those
happen exactly once per call/run.
`timingOf` narrows the new optional scalars without materializing absent
ones, and the fast path applies the same non-negative gate as the slow
path so a hostile bucket cannot slip through.
The timing totals priced a model call as TTFT + one opaque generation
window, so thinking, answer text, and tool-argument decoding were
indistinguishable. Fold the stream's `block-start` framing into three new
additive-optional buckets — `reasoningMs`, `textMs`, `toolArgMs` — that
tile the window's marker span.
Both log generations feed the same split: a V0 log's `assistant/chunk`
markers open and close spans in the step slot; a V2+ log carries no chunk
events, so `decodeSpansOfStream` reads them off the embedded settlement
stream. The split is priced only when the window was (an unstamped call's
model time stays unattributed wholesale), and a zero span stays absent so
pre-split-shaped state gains no dead properties.
The fields are additive-optional, so `stateVersion` stays at 15 and
cached rows keep parsing — a bump would discard them and orphan the key
for idle sessions (the #37 regression).
Measured over 305 local sessions: reasoning 31.3% of active time, tool
args 15.3%, answer text 3.5% — the answer is 1/9th of what the model
spends decoding.
The right Sidebar's Context panel split its three main cards into three
columns, so a pane too narrow for three folded into a ragged 2+1: a hole
under the composition card and the trend card alone on its own row. The
conversation tab read differently, from the same component.
Drop the per-host arrangement: both hosts now use one two-column row
(composition over trend in the left column, the browser beside it and
stretched to the pair's height). The panel's row simply folds to a single
column at the shared 360px floor instead of splitting across two rows.
The head row is untouched, so the panel still shows its two donut cards.
The dockkit pane body no longer pads itself and leaves each tab its own insets, so the Context tab sat flush against all four panel edges. Give the sidebar-scoped root a 12px frame instead of zero, matching the harness's own body inset; the conversation tab and the /context modal are unaffected.
DeepSeek reprices the Flash series effective 2026-09-10 12:00 BJT
(off-peak per 1M tokens: hit ¥0.02/$0.003, miss ¥1/$0.15, out ¥4/$0.6;
peak at 2x). Between the V4.1 Flash launch and the V4.1 Pro release
every Pro request is routed to V4.1 Flash and billed at the Flash
rates, so pro shares the flash triple until V4.1 Pro is priced — swap
that one reference when it ships. The stats-board tooltip names the
flash row deepseek-v4.1-flash, and both locales note the interim
routing. Fold logic is untouched: the substring family match already
lands v4.1 spellings (new fixture), and the peak windows are
unchanged. Logs spanning the cutover estimate entirely at the new
table — the cell is a reference estimate by contract.
SidebarRightGuideEntry now carries only `order`, `title`, and `icon`,
and the guide page renders a glyph + title capsule, so the plugin's
contribution drops its description thunk and the now-unused
`sidebar.guideDescription` dictionary keys. The mirrored face and the
sidebar's version labels state the supported 0.1.5-alpha.2+ floor.
The supported V3 line follows the newest release: the baseline becomes
v0.1.5-alpha.2 (tag, vendored session package) and the declared release
map names 0.1.5-alpha.2. The release workflow fetches the new tag.
The alpha.2 client seams are pinned in the matrix: the conversation
surface moved under the keyed `main` panel (`main.conversation`) while
the plugin's `conversation.view` seat keeps its name, and
`SidebarRightGuideEntry` dropped its description line. tests/baselines.ts
therefore gains a guideEntry probe (the fields present plus the dropped
copy field asserted absent).
Every support/capability label states the 0.1.5-alpha.2+ floor;
`0.1.5-alpha.x+` remains only as the V3 LOG-generation label. The docs
record the verified matrix, the two moved seams, and the install row
that still waits on the CLI's npm publication (the `alpha` dist-tag
lags the release).
The DNA strip's card-colored divider was a fixed 1px inset box-shadow on
every band. Long sessions pin hundreds of bands at the 100/N floor
(≤1px wide), where the divider covers the whole band and blanks the
strip — a 792-item context rendered mostly background with a few
surviving ticks. Draw the divider as a gradient layer capped at
min(1px, 25%) of the band's own width instead: bands ≥4px keep the
exact 1px divider, narrower ones keep at least 75% of their color.
Segments set backgroundColor (longhand) so the inline style no longer
resets the stylesheet's background-image.
- Use English-first bilingual labels across every field.
- Require reproduction steps and split expected vs actual behavior.
- Add environment and affected-surface fields; make screenshots optional.
- Auto-apply the bug label and the [Bug] title prefix.
- Refresh the version placeholder and note the supported dsh range.
Record the three session-log generations the plugin folds, how the seam matrix and the statistics differential verify them, and the one caveat of keeping the projection stateVersion stable (a session folded by an older build keeps its cached figures until its log moves; delete its cache row to force a refold).