The step and the Models page both asked one question of a join that
describes every provider: is deepseek-official's credential stored? A user
who configured some other route was taken over on every blank session, and
the DeepSeek setup card opened over them on every visit to Models with a
Cancel that could not close it — while clearing the add card's draft,
because it shared the row-editor close handler.
providerUsable(row) now answers what both surfaces need: the route is
registered and whatever credential its profile names is stored. Readiness
(renamed onboardingReadiness) ends on any usable row, needsSetup takes the
same fact, and each card kind owns its own close handler.
Fixes#2325
Second alignment step for #2248: document-level drag intake behind the new
DropOverlay atom, lightbox close icon and shared dialog mask, DeepSeek Chat
thumbnail rules (single 240px long edge with ratio clamp, 64px tiles, merged
consecutive assistant images), image limits raised to 20/10MiB/100MiB and
published to clients as the imageLimits projection, whole-batch intake
pre-check with product-copy banners, and attachment-error reasons mapped to
localized copy.
The flat-list ordering change duplicated the document-level native-drag
acceptance effect and the status-dot block across the search and session
rows, tripping the duplication gate. Extract useNativeDragAcceptance and
SessionStatusDots so both call sites share one implementation.
`USER_PRESET_DIR` was exported with no production consumer — only the new test
read it, and a test that imports the implementation constant cannot catch that
constant being wrong. It stays module-internal, and the test spells the segment
it expects.
Overlaps master on the preset e2e, the web scaffold, and the generated
config-catalog triplet; all merged textually, so the catalog is regenerated and
its pairing hashes re-recorded rather than trusted.
Adapt to two contract changes master introduced:
- The generated Remote face now wraps every business result in
RemoteResult, folding carrier failures into an ok:false branch instead
of rejecting. The controller reads that envelope at its three call
sites and maps a carrier failure onto the same settled shape the
controls already render; three specs cover the new branch.
- Client packages split their tsconfig into host and client halves, and
the host aggregate now compiles any test not named *.client.spec.*.
Rename this package's specs to the client convention and drop the
../connection project reference, which pointed at a solution file that
no longer carries the client sources.
Keep master's mount loop with its rollback-on-failure in api-remotes and
add messageFeedbackRemote to it.
The source-through-tsx fallback in windowsAclRunnerInvocation was only
reachable while sandbox-windows-acl/lib/runner.js was absent, so the
per-file 100% gate failed wherever a gate had already built it. In
ci-primary and ci-windows-complete the typert-contracts gate runs
build:lib:host ahead of test:coverage in one workspace, leaving both
fallback statements uncovered; the sharded coverage job never builds
first and stayed green.
Cover the fallback through an injected entry path that is guaranteed not
to exist, and keep the uninjected case asserting only the verdict that
holds under either arm. Verified at 100% statements/branches/functions/
lines with lib/runner.js both present and absent.
The locale plugin's inject list gained 'remote' and 'settingsScope' on
2026-08-10, but the built-bundle harness mounted it without providing
those services, so the locale fiber never started and the trajectory
plugin's apply never ran — the ring assertion saw no 'trajectory' entry.
Provide the same stubs ui-layout's apply bench uses.
A test file under packages/client now says which face it covers:
`*.client.spec.{ts,tsx}` and its `*.client.{ts,tsx}` helpers belong to the
Client aggregate, `*.host.spec.ts` to the host aggregate. The carrier's four
node-half specs take the Host suffix.
The two suffixes are mutually exclusive, so each aggregate excludes the
other's and both keep one broad test glob: `exclude` wins over `include`, and
`packages/client/**` no longer has to be excluded wholesale from the host
program with per-file `files` entries carved back out of it. A Host-face spec
that reaches only Host source therefore needs no cross-face project
reference, which the split-project rule rejects.
vitest still discovers every file through `**/*.spec.{ts,tsx}`.
Re-record the sidebar regions that the redesign intentionally changed:
group session counts are gone, search is a collapsed header action, and
grouping lives in the View options menu. Session rows also follow the new
recency ordering, so their tree order updates with the counts.
The sidebar redesign removed group session counts, collapsed search into a
header action, and moved grouping into the View options menu. Update the
browser scenarios that waited on the old surfaces:
- Wait on the Ungrouped bucket row instead of the removed session-count text.
- Expand the collapsed search control before filling the renamed input.
- Open the View options menu instead of the removed Group by button.
- Assert the persisted grouping under the new dsh.workspace.view.v4 key.
- built-boot: assert the fixture workspace group row instead of its count.
Resolve the note-erasure race the review found: a control that rendered
before the first list read held no item and passed note=undefined, so
switching a rating silently dropped the stored note. The controller now
owns note resolution and toggle-vs-retract, deciding from the committed
item inside the serialized mutation, and clearNote expresses deletion.
Also from review:
- serialize the reconnect re-read behind queued mutations (resync), so a
list reply cannot resurrect a version a newer mutation replaced
- re-check disposal after the seeding read, so an unloaded fiber never
reaches the wire
- drop Object.freeze on Maps, which does not prevent set/delete
- declare the @deepseek-ai/dsh-client-connection dependency it imports
- surface a failed list load in the controls
- drop the /client value exports that had no consumer
- state the per-turn render scope in the README and subsystem pages
- align the package version with the root
The preset-roster loop added by this PR names the \cordis\ preset id in
apps/cli/tests/windows-shell.spec.ts; the bare token is product data like
the existing agent-preset allowlist entries, not a package reference, so
the rescope-vendor hygiene check must not rewrite it.
Every generated method resolves to RemoteResult, so the plain-Node script
must read the business value through `.value`: the CAS ref it passed on to
goals/edit was undefined, which the client codec rejected before the request
left. The invalid-payload case keeps its try/catch — a codec-rejected
argument still throws at the Client Remote face rather than folding into the
error branch.
Review follow-ups that are logic rather than documentation:
- rpc.schema.ts had lost the credential-rejected branch while api-proxy.ts
still returns that code, so a legitimate business error failed the
client's response parse. Restore the branch and assert it.
- rpc-schemas.spec.ts had lost the workspace list, archiveSession and
insertSessionBefore cases along with the command schemas; those routes
still ship, so restore their coverage.
- An omitted SRC field is now recognized by an absent key instead of an
undefined value, which makes the allowance assertExactArguments already
granted reachable; an explicitly undefined field stays invalid input. A
weak descriptor's undefined result rides the wire as an absent value,
matching the envelope removal.
- The chooser unmounts an already-created backend when the surface entry
fails to load, and no longer reverses the captured id array in place.