The native port is finished off with the readability work the earlier rounds
left open, plus the cleanup of everything the shadcn era or the older canvas
left behind.
- Geometry: node height is now composed from named parts (chrome, two title
lines, meta row) and per-node extras, so a teammate card that carries a task
line no longer gets clipped by the old fixed 68px budget; the layout spec
follows the new model and GRAPH_ROW_STRIDE stays exported for it.
- Readability: row rhythm (28-32px), three ink levels for title/meta/owner,
truncation with title hints, current-row and hover expressed as an accent bar
plus a hover fill (no shadows), phase frames and edges back on the l1/l2
hairlines, control cluster uniformly 28px, drawer durations on tabular
figures, kill action revealed on hover/focus without shifting the row, no
horizontal overflow at 360px.
- Task window: the markdown body is pulled onto the page scale (12px body,
12/13px headings, tightened list indent and paragraph spacing) while the
shared MarkdownText/markdownTextProps contract is untouched.
- Cleanup: dead stylesheet rules, unused TSX exports and helpers, stale
comments that still described the retired Variant-D canvas, zero-reference
i18n keys across the dictionaries, and the Tailwind/shadcn/Variant-D
narrative in the design doc, AGENTS.md and the plugin guide (kept as one
short "why it was rolled back" section).
Verified here: typecheck and lint clean; 133 files / 1413 tests; build with no
radix-ui or --tw- strings in lib/client.js (988.9 KiB); the 70-assertion
real-browser contract at 70/70 with the 20 reference screenshots regenerated;
mount e2e 7/7.
shadcn's defaults are built for a standalone app: 14px body, 36px controls,
solid primary fills and elevation read as a foreign surface next to this
plugin's own tabs (files, changes, side chat, settings), which are 12/11/10px
type, 28px controls, hairline borders and flat panels. Retuning the layer did
not converge, so the layer goes.
- Removed: src/client/ui/** (21 vendored components), components.json,
scripts/ui-css.mjs, the Tailwind/PostCSS compile step in tsdown, and the deps
tailwindcss / @tailwindcss/postcss / postcss / radix-ui /
class-variance-authority / tailwind-merge. (diff and simple-icons stay: they
patch undeclared bare imports of the host primitives, unrelated to shadcn.)
- The seven page surfaces are back on the plugin's own base: *.module.css with
--dsw-* tokens plus the host primitives (Button/Menu/Modal/Pill/Tag/Switch/
Input/Tooltip/StateDot/MarkdownText). Behaviour, data-* hooks, aria labels,
i18n keys and the AnchoredPopover geometry/drag/dismiss contract are
unchanged; the non-styling fixes landed during the shadcn era (model id
dedupe, task-window CAS, drawer arming, popover dragging, the chunk packaging
glob) were re-applied and are covered by the existing specs.
- The tasks page returns to the core bundle: `tasks` left CHUNK_NAMES /
CHUNKS / ChunkName, src/client/chunks/tasks.tsx is gone and tabs.tsx imports
SubagentView directly.
- The reverted stylesheet was retuned to the plugin's measured vocabulary
(12/11/10px, 28px controls, border-l2 with border-l1 hairlines, hover fills,
no static shadows, --dsw-shadow-lv2/3 on floating layers only) and verified
against a 70-assertion real-browser contract; the harness's own two
measurement defects were fixed with a falsification test proving the
assertions still catch injected regressions (56/70, 14 FAIL).
- Tests: ui-foundation / ui-bundle / ui-shadows (the shadcn guards) deleted,
theme.spec scoped back to the plugin's own stylesheets, bundle-route and
manifest-consistency chunk lists back to four. Docs: AGENTS.md and the plugin
guide drop the Tailwind/shadcn guidance; the design doc marks those sections
superseded and records why the layer was removed.
Verified: typecheck/lint clean; 133 files / 1410 tests; core bundle 987.3 KiB
with no radix-ui/--tw-/tailwind strings and no client-tasks.js; mount e2e 7/7;
20 real-browser screenshots at 360/720 for graph, tree, board, task window,
drawer (including armed), both popovers and the 77-node fixture.
The previous round kept a hand-trimmed, shadow-less, 11-13px variant of the
component set. This replaces it with the registry's own defaults and the
registry's own composition primitives, keeping only the adaptations this host
actually requires.
Registry refresh (npx shadcn@latest add --overwrite): the whole vendored set is
back to upstream sources, plus label, field, input-group, item and button-group.
Re-applied adaptations (documented in the design doc):
- cn from ./utils and explicit ./x.tsx specifiers (the registry writes virtual
aliases this repo has no resolver for);
- host IconXxx instead of lucide (skin contract);
- no dark: variants (the DSH tokens already flip) and no palette literals;
- React.forwardRef on Button (the host is React 18, so radix Slot needs it);
- tw-animate-css animation utilities stripped: installing that dependency would
inject generic keyframes into a page we do not own.
Restored to stock: the full Button variant/size set, shadow-xs on outline,
transition-all, badge ghost/link.
Recomposition on the newest primitives (per-file, verified here):
- board: full Card composition, Item rows, ToggleGroup filter, dropdown items
grouped, Empty for the empty state;
- task window: Card composition, FieldGroup/Field with data-invalid validation,
ToggleGroup owner (default variant: the outline variant's hover and pressed
states measured identically, hiding the selection), destructive-armed delete,
FieldError for conflicts;
- popovers: both portal cards use the same Card composition, rows are Item;
- drawer/header: Item rows with ItemActions, Separator bands, Spinner, Empty;
- graph/tree: stock node recipe, outline buttons, cn() for conditional classes.
Two no-preflight traps found by rendering, not by types:
- stock Empty ships border-dashed without a width, so the UA's 3px medium dashed
frame wrapped the whole page: border-0 on that Empty;
- <Spinner size={12}/> stayed type-clean after the refresh (size is a valid span
attribute) while the glyph silently rendered at size-4: className="size-3".
Verified: typecheck/lint clean; 136 files / 1515 tests; build with the core and
chunk bundle guards (core 836.3 KiB, chunk 734.7 KiB); mount e2e 7/7; and the
real-host-stylesheet mirror page re-shot for graph, tree, board, task window and
the 77-node stress fixture at 360 and 720.
Real-device report: the Tasks page "looks like it has no CSS at all, with
blurry borders". Two hypotheses were falsified before the real cause surfaced:
the sheet IS delivered (the chunk carries both the CSS and its injector, and
the bundle route serves it) and the cascade is NOT the problem (with the real
host stylesheet plus the real compiled sheet, a controlled sample keeps our
padding, radius, border, background and font; host CSS-module selectors only
match host nodes, and its global element rules are element-level specificity).
The cause is what we deliberately excluded: PREFLIGHT is also what normalizes
form controls. Measured on a plugin icon button that sets only an icon size,
the UA chrome survived as padding 1px 6px, border 2px outset, background
ButtonFace (#efefef) and a 13.33px system font - gray beveled buttons with a
soft double border, i.e. "no CSS".
- ui/theme.css: a .dsw-tasks-scoped preflight subset (zero margins/padding,
border width+style, background, appearance none, inherit color/spacing,
cursor rules) inside @layer base, written with :where() so it stays at
(0,1,0) and utilities in the later layer still win; plus an explicit
"@layer theme, base, components, utilities;" statement - layer order follows
first appearance, and without it the utilities import registered utilities
BEFORE base, so the reset beat rounded-md (measured: square buttons). The
built chunk's order was re-checked: properties, theme, base, components,
utilities.
- Stock shadcn restyle: static cards carry stock shadow-xs/shadow-sm again
(floating layers keep shadow-lg), body/meta text is text-sm/text-xs instead
of 11-13px, status uses stock Badge variants, controls use stock Button
variants and sizes, row actions appear on hover/focus while staying keyboard
reachable, node cards are 176x68 with shadow-xs.
- bandColsFor budgets columns at the readability floor (width / 0.78) instead
of 1:1, so a 360px panel keeps two columns; FIT_MIN_SCALE moved into the
layout module as GRAPH_FIT_MIN_SCALE so the fit and the column budget share
one constant.
- Guards: tests/ui-foundation.spec.ts pins the scoped reset declarations and
the layer-order statement; tests/ui-shadows.spec.ts now allows shadow-xs and
shadow-sm on static panels and bans md and above; the theme guard's inert
paint rule forced the reset to spell border-width/border-style instead of the
"border: 0 solid" shorthand.
Verified: typecheck and lint clean; 136 files / 1505 tests; build with the
core/chunk bundle guards; mount e2e 7/7 (mount 444ms, longtasks 2 of 8); the
visual mirror page (real host stylesheet + real components) re-shot at 360 and
720 for graph, tree and the 77-node stress fixture.
Pinning the lane to 0.1.6-alpha.2 makes plugin-mount fail deterministically:
the shell boots into the new-session empty state, no session scope reaches the
sidebar, and [data-dsh-better-sidebar] [title] never attaches
(mount.e2e.ts:216 plus perf.e2e.ts:182). Falsified against this branch with a
probe: origin/main + that one-line pin, run 35484961070, same red, zero plugin
changes involved.
So the dev tree keeps alpha.2 (the line the maintainer's desktop runs) while
the lane stays on the released pin; the evidence and the follow-up (teach the
lane to activate the seeded session on the alpha line) are recorded in
AGENTS.md §2/§3 and docs/plans/2026-09-17-dsh-0.1.6-alpha.2-adaptation.md.
0.1.6-alpha.2 removed ConnectionIndicator's reconnectLabel, but the peer range
(^0.1.5-rc.1) still covers the rc line, where the prop is REQUIRED and renders
the retry button's hover/focus action text. Widening the component type once
keeps both lines correct: rc renders the label, alpha.2 ignores the extra key.
The shim carries a comment naming the condition for deleting it.
The maintainer's desktop already runs the 0.1.6-alpha line while the plugin
pinned 0.1.5-rc.2 (latest/next still point there). The peer range stays
^0.1.5-rc.1, so rc.1/rc.2 users are unaffected.
Upstream delta that actually touches this plugin (primitives .d.ts diff plus a
full scan of bare imports in its lib/**/*.js):
- IconSendOutline16 was removed (the only icon drop) -> IconSendOutline14.
- TerminalBlockLabels gained a REQUIRED noExitCode label -> new
sideChatBlockNoExitCode copy across all 20 dictionaries.
- ConnectionIndicator dropped reconnectLabel -> prop removed.
- Menu/Modal changed only in docs/keyboard semantics; new exports
(Checkbox/isDarwinDesktop/MarkdownDelegateProvider) are additive.
- dsh-tools no longer peers on dsh-code-runtime, and that package was never
published at alpha.2 -> its devDependencies hoist is removed instead of
mixing an rc.2 package into an alpha.2 tree.
- the primitives bundle still declares zero dependencies but now bare-imports
'diff' (DiffBlock) and 'simple-icons' -> hoisted as diff@^9.0.0 (matching the
host) and simple-icons@^15.0.0; missing them failed six jsdom suites at
vite's import-analysis stage.
Verified: pnpm install + peers check clean; typecheck/lint 0; 136 files /
1503 tests; build green with the core/chunk bundle guards; mount e2e 7/7 on
0.1.6-alpha.2 (longtasks 2/8, and /sidebar/bundle/tasks.js really downloads).
Also recorded: origin/main is an ancestor of this branch (nothing to rebase in
git terms), and README's published-version wording is left to release time.
Visual base replacement for the Tasks page after the 'hard shadows make a
dense graph unreadable' review. Behaviour, hooks, aria labels and i18n are
unchanged; the base layer is not.
- FOUNDATION: Tailwind v4 wired into tsdown's css-inline plugin (theme +
utilities ONLY — preflight is excluded because the plugin's stylesheet is a
global <style data-plugin> tag and would repaint the host page), shadcn
tokens bridged to --dsw-* so the DSH theme keeps flipping light/dark with no
dark: overrides, cn() util, components.json for the CLI, src/client/ui/.
- COMPONENTS: shadcn's component source vendored into src/client/ui (button,
card, badge, separator, input, textarea, tooltip, popover, dropdown-menu,
scroll-area, collapsible, toggle-group, skeleton, spinner, empty) with a
documented local diff: lucide-react replaced by host IconXxx (no new icon
dep), shadow-* dropped from non-floating variants, unused variants pruned,
and React.forwardRef restored on Button — the host runs React 18, where
radix's Slot cannot hand a ref to a plain function component (dev warns,
production silently mis-anchors the floating layer).
- SHADOWS: static panels are now hairline + surface tiers with hover:bg-muted;
shadows exist only on floating layers. Settled nodes recede by ink
(text-muted-foreground/foreground-3) instead of opacity.
- DENSITY: node cards widened 132 -> 150px with a two-line clamped title
(13px text in a 132px card left ~7 CJK characters), reserved height 46 -> 60.
- CHUNK: the whole page (graph, tree, task window, board, drawer, shadcn/radix
layer and its stylesheet) moved into the lazy 'tasks' chunk. Core bundle
988.5 -> 835.6 KiB (-153 KiB); the 709.8 KiB UI payload loads only when the
Tasks tab opens.
- MODEL: workflow members whose childId is already a real node elsewhere are
no longer synthesized into a duplicate id (React keys/edges), with a
last-resort per-id dedupe.
- GUARDS: tests/ui-foundation.spec.ts, tests/ui-bundle.spec.ts (core/chunk
split + size budget + no preflight/oklch/lucide), tests/ui-shadows.spec.ts,
extended tests/theme.spec.ts (no colour literal / palette class in
src/client/ui/** and the migrated files).
- REVIEW FIXES: portal popovers re-scoped under .dsw-tasks, graph loading
state, 11px floor, error nodes no longer tint a whole border, TeamBoard's
delete item is neutral (the window owns the two-step confirm).
Verified: typecheck / lint / 136 files 1502 tests / build bundle assertions /
mount e2e 7-7; browser harness 65-65 checks with 0 console errors.
Round-three review feedback:
- NO PER-CARD DETAIL BUTTON: the ellipsis control is gone from graph cards
and tree rows — the card IS the affordance, and clicking it opens the
detail window (the transcript jump moved inside as the primary button).
Fold aggregates keep click-to-expand.
- ONE TASK WINDOW: every task surface (board row, agent node task line, the
node detail list, and creating a task) now opens the same non-fullscreen
DRAGGABLE window (TaskWindow.tsx + its TaskPopover shell): markdown
description by default, 编辑 switches the same card to multi-line editing,
plus owner reassignment, complete/reopen and a two-step delete. The board
lost its overflow menu and its Modal entirely; create uses the same window
in create mode.
- REUSE: TaskPopover (4 call sites), MultilineField (the plugin's own
multi-line input — the host primitive set has none), OwnerPicker,
TaskCreateButton, and the shared glyph/TaskLine helpers across both modes.
- 3 new copy keys across zh/en/ja and the 18 third-language dictionaries.
Tests: the node-click spec now asserts the detail window (and that the jump
button inside it navigates), a new spec pins 'no nested control inside a
card', and two more cover the shared window: markdown-first view then
multi-line edit posting an 'edit' with the current revision, and immediate
owner reassignment. Full suite 1406 passed / 133 files.
Round-two review feedback, all three points:
- TASKS ON NODES: the model maps each shared task (ownerName -> member name
-> member session id) onto its owner's node; graph cards and tree rows
render a fourth line (icon + subject + status + '+N'), and the node detail
popover lists every owned task.
- TEAM BOARD: member Pills double as the owner filter; each task row is a
status dot + subject + owner + status Tag + ONE overflow Menu (complete /
reopen / edit / reassign submenu / delete with a two-step arm). Creating
and editing moved into a real Modal with labeled Inputs and owner Pills —
the narrow strip is no longer where you type.
- HOST PRIMITIVES ONLY: the board and the jobs drawer now use Menu / Modal /
Input / Button / Pill / Tag / Switch / StateDot; no native select or input
remains (guarded by a spec).
- ICONS, NOT HAND-DRAWN GLYPHS: every text glyph (circle/diamond/triangle/
check/chevrons/i/house) is replaced by a host icon — agent preset, user
(teammate), branch (workflow run), checklist (fold + tasks), tree corner,
fullscreen (fit), ellipsis (node details), copy/stop (jobs). The live line
now shows the tool's own icon + name + args without the drawn box.
- JOBS UX: the output popover is DRAGGABLE (offset clamped to the viewport,
double click re-anchors, controls do not start a drag), defaults to 380px,
and gains copy-output, a follow-latest switch, kind/status Tags and a drag
hint; the drawer highlights the open row.
- 19 new copy keys across zh/en/ja and the 18 third-language dictionaries.
Tests: 4 new specs (task rendered on its node, no native select/input +
menu-driven board, create-through-dialog posts the CAS-free create, job
popover drag moves the card). Full suite 1404 passed / 133 files.
Review feedback from the live 3384 install, fixed at the root:
- COLORS: the new stylesheet used var(--dsw-alias-accent) in 17 places — a
token the DSH theme does NOT define, so every declaration was dropped
(older files only survived because they carry fallbacks); container edges
used border-l1 (4% black, invisible). Accent now rides
--dsw-alias-state-business-primary, container edges --dsw-alias-border-l4.
- CLICKS: the canvas called setPointerCapture on pointerdown, which
retargets the derived click to the container and killed every node (and
ⓘ) interaction; jsdom cannot see this, a real browser can. Capture is
gone and panning only starts from the background.
- LAYOUT: fit gave up silently at zero container size and never retried,
centered only horizontally, and capped at 100% while a five-child level
scaled to 35%. Now: ResizeObserver + first non-zero fit, both axes
centered, a 0.78 readability floor, and layoutTasksGraphForWidth picks
the flattest sibling arrangement that still meets that floor.
- CARDS: title (one line) + mono meta + live line only; display title,
team role, full model id and latest text moved into the ⓘ popover.
- PANEL: metrics follow the approved 360x660 mockup (132x46 cards, 112 row
stride), explicit line-heights, user-select:none, horizontal control
cluster with a labelled mode button, always-visible team board strip.
- Tokens for two new popover headings across all 20 dictionaries.
Tests: 3 new page-interaction specs (click after background pointerdown,
node gestures never pan, team board visible without a click) and a
rewritten 9-case layout suite (band wrap, row reservation, width solver,
reserved live row). Full suite 1400 passed / 133 files.
The rc.1 adapter first went out as 0.21.0-rc.1, but DSH 0.1.7-rc.1 is
upstream's release batch, so the plugin that targets it must not sit on a
prerelease channel. Re-cut it as v0.21.1: the version is now free of `-`,
so release.yml publishes it under npm's `latest` instead of `alpha`.
Version literals only — package.json, dsh.plugin.json and
SIDEBAR_SERVICE_VERSION (tests/service.spec.ts still pins the last two
together). No code change: the peer floor stays ^0.1.7-rc.1 and the
support line stays "DSH 0.1.7-rc.1 and later".
Docs follow the channel move: README/README_EN/guide drop the "alpha
channel" framing, the install command becomes @latest, and every older
DSH line now gets an explicitly pinned command in the version table
(@0.19.1 and so on) because `latest` no longer covers them. The rc.1
design record keeps its history and gains a §8 for the re-cut.
New design record `docs/plans/2026-09-23-dsh-0.1.7-rc.1-adaptation.md`
(method, the version-bump-only delta, the code-card break and the mermaid
regression it exposed, the over-yield recovery, the live 3080 upgrade with
its boot-log findings, and the evidence — including the note that the
mount lane first ran against a stale tarball because `e2e_resolve_tarball`
picks the newest existing one instead of packing).
AGENTS.md §3 gains the rc.1 rules: the boot-time peer preflight (a new
§3.4 item 12) with its four gotchas, the vendor hoist lesson, and the
code-card/toolbarLabels contract. Two claims are corrected while we are
here: the guide's four-entry description cap was attributed to rc.1 but
`GuideBody.tsx` and the host's terminal guide entry are byte-identical
across alpha.1 / alpha.2 / rc.1, and the icon surface is 25 named imports
plus a type-only `IconProps`, not 26.
README / README_EN / guide: version, badges, peer floor, the pinned-DSH
advice (`alpha` is now 0.1.7-alpha.2 while rc.1 rides `next`), the reduced
refusal list, and the correction that npm `latest` is 0.1.5-rc.3.
DSH 0.1.7-alpha.1 is 1299 commits past 0.1.6-alpha.2 and rewrites four
contracts this plugin was built on. The peer floor moves to
^0.1.7-alpha.1 (semver's prerelease rule means ^0.1.6-alpha.2 can never
match a 0.1.7 prerelease); 0.1.6-alpha.2 and earlier stay on v0.19.1.
Released as 0.21.0-alpha.1 (dist-tag alpha).
Hard breaks:
- dsh-settings was rewritten: register(ns, schema) is gone, a form is
addressed by the plugin row's Loader entry id and read from the
module's exported Config. The preferences are merged into Config and
marked volatile — which requires DSH's own schemastery, because only
that build wraps a volatile field in the cosmokit reference the
loader's volatile commit walks. With the public package a settings
write reports success and revision 1 while the effective value never
changes.
- ui-primitives renamed its whole icon family (IconXxx14/16 ->
IconXxxRegular/Medium): 26 imported symbols, 17 files. The failing
mode is render-time, not load-time. Five call sites that relied on the
old 14px default now pass size={14} explicitly.
- Session format v4 rejects source.kind === 'plugin'; the side-chat
boundary injection now writes plugin:dsh-better-sidebar, the same kind
DSH's own v3->v4 migration produces, so historical threads survive.
Tool results moved to role 'tool' with top-level content/isError; all
four parsers accept both shapes.
- The client session snapshot dropped subagentsByParent/jobsBySession
and the on-demand subagent-catalog observation API. The Tasks page
reads projectionsBySession and a new jobs.list route.
Yields and convergence:
- The read-only previews go to DSH's documentpreview (Office->PDF, a
spreadsheet worker, zoom, per-directory refresh); editor.canOpen
refuses those 26 extensions. Markdown, HTML (with its sandbox
switches) and the editable code buffer stay.
- The host browser kind is desktop-profile-only now, so the web e2e
lanes expect no browser entry and assert its absence.
- Link takeover claims only urlTarget links and passes the rest to the
host, fixing a regression from the 0.1.6 round: the fallback pointed
at a 'browser' type the plugin no longer registers, so http links in
its own markdown did nothing.
Also fixed, found along the way:
- The file tree refreshes live (new directory watch over the plugin's
own socket), since the plugin owns the `files` kind.
- ctx.sessions.list has no `current` field at either tag; the three
readers were dead. They now use ctx.sidebarRight.mounted.
- package.json.files was missing lib/client-locale.js.
- Two genuinely dead call sites: sessions.openSubagent/open/
refreshSubagents do not exist on the current baseline, so the
topology click, the jump-back and the retry were all no-ops.
- The test harness window shim lacked addEventListener, which the 0.1.7
primitives call at module-evaluation time; and the e2e token exchange
needs Playwright's request stack, not Node's fetch.
Adds the per-version adaptation record (docs/plans/2026-09-21-…-adaptation.md),
rewrites AGENTS.md §3 for the new baseline (the two silent contract breaks, the
terminal/browser handoff, the new official plugin-manager surface, the three
ui-primitives breaks, the widened primitives bare-import set), and updates both
READMEs and the integration guide for the v0.20.0 feature set.
Also retires the support text the terminal deletion made false: the install
flow is one step again (no build-script approval), the FAQ's two node-pty rows
collapse into one pointing at DSH's own terminal, the platform note no longer
promises prebuilt native binaries (there are no native deps left), and the
installers drop the -Repair mode and their allowBuilds writes along with
pnpm-workspace.yaml's now-empty allowBuilds block. Removes the dead
browserNoSandboxWarning locale key (its setting went with the plugin's browser)
and tightens theme.spec's capsule guard so a literal colour fails it.
The e2e resolver now refuses a PATH that is not on the baseline line:
this machine's PATH is 0.1.6-alpha.1, and running the mount lane against
it fails at 'the bundle was not registered' with a zero exit from the CLI —
a misleading dead end worth one explicit error instead.
Copilot review: the openTab JSDoc claimed createTab descriptors ignore
title/path/id, but that is only the bottom-workbench landing (the
factory mints the tab wholesale there). On the native right Sidebar the
seed fields are forwarded as navigation params (createTab values as
defaults, seed wins) and only the id is host-minted. State both
landings so consumers do not drop path seeds.
The native openTab branch rerouted EVERY path seed into openResource (a
dsh-resource://file/... open) without looking at seed.type, so any
component tab opened with a path landed in the editor (the only
dsh-resource://file/** claimant) and its registered component never
mounted. This also contradicted the guide, whose TabDescriptor/openTab
contract and WebDocsView example document path-seed component tabs.
Route by type instead: only the editor kind (the only registration with
dsh-resource://file/** patterns) turns its path seeds into resource
opens; every other kind keeps the page open and carries the path in the
navigation params, which NativeTabRecords.ensure already merges back
onto the synthetic record's tab.path for the component. The bottom
workbench path is untouched, editor opens behave exactly as before, and
onOpen still receives the synthetic tab with the path seed.