Upstream patch queue
August 19, 2026 · View on GitHub
Maintained by zoahdev · Base:
deepseek-ai/deepseek-harness@master(47f9438, 2026-08-13) · Updated 2026-08-19When upstream reopens the PR channel, each branch below can be cherry-picked as-is. All branches are based on the same master commit and verified against the discussions they cite.
RFC: the maintainer-facing proposal for this 42-patch queue lives at deepseek-harness discussion #2486.
Official test-suite verification (2026-08-15, Windows / Node 24 / pnpm 11)
Full official monorepo checkout at 47f9438, pnpm install --frozen-lockfile,
then the five patches applied with git apply:
| Stage | Test files | Tests | Result |
|---|---|---|---|
| Baseline (no patches) | 45 | 1140 | ✅ all passed |
| After all 5 patches | 46 | 1146 | ✅ all passed (exit 0) |
Packages covered: @deepseek-ai/dsh-tools, @deepseek-ai/dsh-app-boot,
@deepseek-ai/dsh-terminal-bash, @deepseek-ai/dsh-llm-deepseek,
@deepseek-ai/dsh-client-ui-primitives. The +6 tests are the
duplicate-instance regression suite carried by patch #1697.
Notes:
- All five patches apply cleanly to current master (
git apply --checkOK). - Patch #1861 required updating 3 official adapter assertions (reasoning
efforts list now includes
low); that test update is part of the branch. - Full log:
pnpm exec vitest run <5 test dirs>→ 1146 passed, exit 0.
1. #1697 — tool scheduler dual-instance crash (undefined.prepare)
- Branch:
fix/tool-runtime-scheduler-symbol-for - Files:
packages/core/tools/src/index.ts, agent-loop protocol guard + regression tests - Fix:
Symbol.forshared key +TOOL_RUNTIME_SCHEDULER_PROTOCOL_VERSIONguard (loud, actionable error on version skew instead of silent mismatch) - Evidence: mechanism-level verification with two physical
dsh-tools@0.1.0-rc.6copies (false → true); three-state matrix (same-version duplicate / version-skew / single instance) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1697
2. #1842 — UTF-8 BOM crashes dsh web at boot
- Branch:
fix/profile-manifest-bom-strip - File:
packages/boot/app-boot/src/profile.ts(readProfileManifest) - Fix: strip a leading
\uFEFFbeforeJSON.parse(one line) - Evidence: local repro (BOM →
Unexpected token, strip → works); companionmanifest-bomcheck in dsh-plugin-doctor - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1842
3. #1856 — Windows minimal preset bash cannot resolve /bin/bash
- Branch:
fix/terminal-bash-win32-shell - File:
packages/terminal/terminal-bash/src/index.ts - Fix: win32 + default
shellPath→ probe PATH / Git for Windows / LOCALAPPDATA forbash.exe; actionable error when missing - Evidence: node-pty repro (
File not found); companionwin-bashcheck in dsh-plugin-doctor - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1856
4. #1861 — deepseek-official adapter rejects reasoning_effort: low
- Branch:
fix/llm-deepseek-reasoning-low - File:
packages/llm/llm-deepseek/src/adapter.ts - Fix: add
lowtoREASONING_EFFORTS(one const + one entry) - Evidence: source whitelist confirmed (
off/high/maxonly) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1861
5. #1869 — single tilde (~x~) wrongly renders as strikethrough
- Branch:
fix/markdown-single-tilde - File:
packages/client/ui-primitives/src/markdown/parse.ts(both call sites) - Fix:
gfm()→gfm({ singleTilde: false })(micromark option;markedhas no such option in v16 — verified) - Evidence: micromark-extension-gfm@3 repro:
~x~delete → literal withsingleTilde:false;~~y~~stays delete - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1869
6. #1891 — external session-directory deletion kills the process (ENOENT fatal)
- Branch:
fix/session-persistence-recreate-on-enoent - File:
packages/session/session-persistence-jsonl/src/index.ts(appendLines) - Fix: catch ENOENT at
open(path, 'a'),mkdir(dirname(path), { recursive: true }), retry once; non-ENOENT errors unchanged - Evidence: official suite
session-persistence-jsonl— baseline 239/239 ✅, with patch 239/239 ✅ (no regression) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1891
7. #1919 - crypto.randomUUID crashes the Web UI on plain-HTTP LAN origins
- Branch:
fix/web-crypto-randomuuid-insecure-context - Files: new zero-dependency
packages/util/random-uuid(+ 4 unit tests); browser-facing mints routed through it indsh-commands(instance token),dsh-client-ui-conversation(draft attachment id),dsh-host-apiproxy(mintRpcId),dsh-llm(MessageId);dsh-client-connectionre-exports the shared helper;packages/client/tsdown.client.tsregisters it asINLINE_SAFE(pure browser-safe contract, no runtime identity) - Fix: prefer
crypto.randomUUID(), fall back to acrypto.getRandomValues()-backed RFC 4122 v4 generator on insecure origins (LAN HTTP / Tailscale IP) - Evidence:
pnpm install --frozen-lockfilepasses (lockfile diff = importer entries only);build:lib:hostandbuild:lib:clientboth pass; targeted vitest 782/782 (llm + client-connection + commands + random-uuid); built bundles contain no directcrypto.randomUUID()mints - Full official suite on this Windows environment: 12731 passed / 80 failed (23 files) - every failing file is environment-specific (symlink/ACL sandbox, PTY/pwsh, worker-thread timeout, network-gated real-product tests) and outside the patch's package set; the six touched package suites are green
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1919 (comment #discussioncomment-18030320)
8. #1944 - compaction summarizer misses the provider prefix cache (re-bills ~122k tokens per compaction)
- Branch:
fix/compaction-inherit-header-config - Files:
packages/compaction/compaction-basic/src/summarizer.ts(+ tests) - Fix: inherit the routed header config wholesale (same semantics as agent-loop's request proposal, adapter-defaulted fields dropped) instead of cherry-picking provider/model and forcing
maxTokens: 8192; the compaction call keeps the exact provider cache key of normal turns - Evidence:
tsc -b tsconfig.host.jsonclean; compaction-basic 124/124; reporter session data: 122,558 input tokens / 0 cache -> 402 new input tokens + 220,928cacheReadTokens - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1944 (comment #discussioncomment-18030489)
9. #1954 - circular skill junctions crash dsh at startup (ELOOP fatal load failure)
- Branch:
fix/skill-filesystem-eloop-contained - Files:
packages/skill/skill-filesystem/src/index.ts(+ watcher regression test) - Fix: ELOOP-class watcher errors degrade only the affected root (warn + unhealthy + close partial watcher + skip) instead of rejecting provider load; scheduled rewatch retries and recovers when the cycle is fixed; non-ELOOP startup errors keep their existing contract
- Evidence:
tsc -b tsconfig.host.jsonclean; skill-filesystem-watcher 11/11 including the new ELOOP regression test; remaining skill spec failures on Windows are pre-existing EPERM symlink-permission cases - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1954 (comment #discussioncomment-18030568)
10. #1961 - purged %TEMP% spill directory crashes the whole service (ENOENT)
- Branch:
fix/subprocess-spill-recreate-on-enoent - Files:
packages/subprocess/subprocess-local/src/spawn.ts(+ regression test inspawn.spec.ts) - Fix:
spillAllcatches ENOENT, recreates the private spill dir (mkdirSync recursive, mode 0700), retriesopenSynconce; if recreation fails, degrades to the in-memory tail instead of crashing from the streamdatacallback - Evidence: host typecheck clean; runtime reproduction with a missing spill dir (tail + full spill preserved, no throw); regression test runs in the Linux CI lane (spawn.spec is excluded on Windows runners)
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1961 (comment #discussioncomment-18030665)
11. #1993 - source launch duplicates dsh-typert-protocol, silently disabling out-of-tree plugin Remote layers
- Branch:
fix/typert-remote-markers-shared-registry - Files:
packages/typert/protocol/src/index.ts(+ cross-copy regression test) - Fix: Remote decorator markers move from a module-private WeakMap to a
Symbol.for-keyed registry on globalThis, shared by every physical package copy (src under tsx vs lib for out-of-tree plugins); WeakMap semantics and conflict validation preserved - Evidence:
tsc -b tsconfig.host.jsonclean; protocol.spec 10/10 including a cross-instance test; same mechanism as the #1697 fix - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1993 (comment #discussioncomment-18031268)
12. #1992 - custom pi-ai routes lose catalog-known modalities (inheritance keyed by provider route, not model id)
- Branch:
fix/pi-ai-catalog-model-id-inheritance - Files:
packages/llm/llm-pi-ai/src/catalog.ts(+ regression test) - Fix:
resolveRouteModelsadds an id-level catalog fallback for input modalities (declared entry > provider catalog > global id catalog > route default); api/baseUrl stay route-owned so a foreign catalog entry never leaks its wire protocol; global id index cached per model id - Evidence:
tsc -b tsconfig.host.jsonclean; catalog.spec 53/53 with a custom-route vision-model regression test - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1992 (comment #discussioncomment-18031307)
13. #2002 - one corrupt Zstandard session log crash-loops dsh web at boot
- Branch:
fix/session-list-isolate-corrupt - Files:
packages/session/session-persistence-jsonl/src/index.ts(+ isolation tests) - Fix:
listArtifactsisolates per-file corruption (unreadable header frame, identity mismatch) with a loud warning and skips the file; targetedloadstill rejects; encoding mismatch and duplicate ids stay fatal - Evidence:
tsc -b tsconfig.host.jsonclean; session-persistence-jsonl 239/239 with a "good session stays reachable next to a corrupt one" assertion - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2002 (comment #discussioncomment-18031351)
14. #1997 - Windows stop loses aborted-turn semantics (non-JSON-serializable AbortSignal.reason)
- Branch:
fix/agent-abort-reason-json-safe - Files:
packages/core/agent-loop/src/agent.ts(+ cancel.spec regression test) - Fix: normalize abort reasons before persisting turn/end; typed causes (user/parent/hook/disposed) pass through, DOMException/Error/unknown flatten to
{ kind: 'user' } - Evidence:
tsc -b tsconfig.host.jsonclean; cancel.spec 32/32 with a DOMException-abort regression test - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1997 (comment #discussioncomment-18031394)
15. #2009 - port-less browser Origins 403 on every /api POST (trust fence)
- Branch:
fix/api-trust-origin-hostname-portless - Files:
packages/client/connection/src/api-request-trust.ts(+ regression test) - Fix: Origin comparison uses
.hostnameinstead of exact.host, mirroring the trustedHosts port-less convention; cross-hostname and opaque origins stay refused - Evidence:
tsc -b tsconfig.host.jsonclean; api-request-trust 11/11 with a #2009 regression case - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2009 (comment #discussioncomment-18031625)
16. #2023 - pi-ai compat cannot override developer-role/store/reasoning-content switches
- Branch:
fix/pi-ai-compat-expose-role-store - Files:
packages/llm/llm-pi-ai/src/catalog.ts,src/config.ts(+ regression test) - Fix: expose
supportsDeveloperRole,supportsStore,requiresReasoningContentOnAssistantMessagesin PiAiCompatProfile/schema/resolution with model > route > catalog precedence - Evidence:
tsc -b tsconfig.host.jsonclean; catalog.spec 53/53 with a qwen-token-plan-style regression - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2023 (comment #discussioncomment-18031734)
17. #2060 - session.prompt aborted by the fixed 30s unary timeout under host load
- Branch:
fix/prompt-user-paced-no-deadline - Files:
packages/host/apiproxy/src/fetch/client.ts(+ regression test) - Fix: classify session.prompt/subagent.prompt as
caller-signal-only(user-paced, same as pickDirectory) so the fixed 30s deadline no longer applies; caller/connection aborts remain; other unary methods keep the bounded timeout - Evidence:
tsc -b tsconfig.host.jsonclean; fetch-carrier.spec 36/36 with a prompt-finishes-after-30s regression - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2060 (comment #discussioncomment-18032208)
18. #2066 - minimal preset's str_replace_editor ignores the permission mode (bare fs)
- Branch:
fix/str-replace-editor-bare-fs-policy - Files:
packages/fs/tool-str-replace-editor/src/index.ts(+ regression tests intests/tools.spec.ts) - Fix: resolve
ctx.sandboxPolicyunconditionally; when the mounted fs does not confine (fs-local,sandboxMode === undefined), the editor enforces the per-call policy itself (read-only denies all three write commands; workspace-write contains to thewritableRootsset) before delegating to the bare backend; confining backends keep delegating towriteText - Evidence:
pnpm typecheckclean;tool-str-replace-editortools.spec 16/16 (14 existing + 2 new: read-only and workspace-write on a bare backend) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2066 (comment #discussioncomment-18032410)
19. #2075 - approval rejection loops the agent (rejection rendered as an ordinary error)
- Branch:
fix/approval-reject-stop-instruction - Files:
packages/core/tools/src/index.ts(+ test assertion intests/tools.spec.ts) - Fix:
serviceAskmapsrejectedto an explicit stop-and-ask reason ("Stop and ask the user... do not retry or work around the rejection") instead of a generic tool error, so the model hands the turn back rather than re-requesting approval. Loop-level yield-on-rejection remains a separate follow-up. - Evidence:
core/toolstools.spec 136/136 with the updated rejection assertion - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2075 (comment #discussioncomment-18032459)
Superseded by #25 (
fix/approval-reject-conclude-turn), which adds the loop-level yield.
20. #2081 - startup fails with a bare stripTypeScriptTypes error (Node/bun floor)
- Branch:
fix/node-version-startup-gate - Files:
apps/cli/src/bin.ts,apps/cli/src/runtime-check.ts(+apps/cli/tests/runtime-check.spec.ts) - Fix: add a startup gate mirroring the declared
engines.noderange (^22.19.0 || >=24.0.0); unsupported runtimes (old Node, Node 23, bun) get a readable message instead ofExport named 'stripTypeScriptTypes' not found.--help/--versionstill resolve before the gate. - Evidence:
apps/cliruntime-check.spec 5/5 + args.spec 6/6 green - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2081 (comment #discussioncomment-18032592)
21. #2081 - second dsh web prints a raw EADDRINUSE stack
- Branch:
fix/webserver-eaddrinuse-message - Files:
packages/host/webserver/src/index.ts(+ regression assertion intests/webserver.spec.ts) - Fix: special-case the
EADDRINUSElisten error into an actionable message (dsh web is already running: host:port is in use...) while keeping the original errno as the errorcause - Evidence:
host/webserverwebserver.spec 2/2 green (including the fail-loud activation case) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2081 (comment #discussioncomment-18032613)
22. #2068 - a single duplicate seq makes the whole session log unloadable
- Branch:
fix/session-log-duplicate-seq-tolerance - Files:
packages/session/session-persistence-jsonl/src/format.ts(+ regression test intests/jsonl.spec.ts) - Fix: tolerate an event whose seq equals the last accepted event's seq (a single reopen/append duplicate) by skipping it and recording it in
skippedDuplicateSeqs, instead of refusing the whole log; a real seq gap and out-of-order corruption still fail - Evidence: session-persistence-jsonl jsonl.spec 152/152 green with a duplicate-seq regression
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2068
23. #2090 - streaming tool-call name/id blanked by explicit-null deltas
- Branch:
fix/llm-deepseek-toolcall-null-name - Files:
packages/llm/llm-deepseek/src/translate.ts(+ regression test intests/translate.spec.ts) - Fix: guard tool-call
id/nameaccumulation with!= nullso providers that repeatname: null/id: nullon continuation chunks (SGLang and other OpenAI-compatible streams) don't overwrite the first-chunk values; the same guard covers the emitted delta name - Evidence:
llm-deepseektranslate.spec 31/31 green with an explicit-null regression - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2090 (also #1713)
24. #2068 - sqlite backend parity for the duplicate-seq tolerance
- Branch:
fix/session-log-duplicate-seq-tolerance-sqlite - Files:
packages/session/session-persistence-sqlite/src/schema.ts(+ regression test intests/sqlite.spec.ts) - Fix: mirror the jsonl loader tolerance in the sqlite committed-region scanner (skip one duplicate seq, track the expected-seq cursor separately from the row index so a skip is not misread as a torn tail)
- Evidence: sqlite scanRows describe 9/9 green with a duplicate-seq regression (one pre-existing Windows symlink test is unrelated)
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2068
25. #2075 - a user-rejected approval ends the turn (loop-level)
- Branch:
fix/approval-reject-conclude-turn - Files:
packages/core/tools/src/index.ts(+ test assertion intests/tools.spec.ts) - Fix: the
denydecision for a user rejection now carriesconcludesTurn, and error results can forward that marker, so the agent loop commits the result and yields the turn instead of auto-continuing into a reject/retry loop; the stop-and-ask message from #19 is folded in. A sandbox denial still does not conclude (escalation stays available) - Evidence:
core/toolstools.spec 136/136 green withconcludesTurn: trueon the rejection result;pnpm typecheckclean - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2075
26. #2106 - session persistence fails on Android/Termux (SELinux denies link)
- Branch:
fix/jsonl-link-eacces-rename-fallback - Files:
packages/session/session-persistence-jsonl/src/index.ts(+ regression test intests/jsonl.spec.ts) - Fix:
materializePosixfalls back torename()whenlink()is denied (EACCES/EPERM/EXDEV/ENOTSUP/ENOSYS), keepinglink()as the primary no-clobber publish elsewhere;rejectExistingLogstill runs first - Evidence: session-persistence-jsonl jsonl.spec 152/152 green with a mock-link-EACCES fallback regression
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2106
27. #1404 - dsh plugin add promotes a user-patch-inserted bundle and breaks the next boot
- Branch:
fix/plugin-reconcile-user-patch-dup-id - Files:
apps/cli/src/plugin.ts(+ regression test inapps/cli/tests/built-bin.e2e.ts) - Fix:
reconcilePluginsreads the user patch layer's insert ids and skips promoting a bundle whose own patch inserts an id already present there (avoiding "duplicate loader entry id"); new deps and the "update gained dsh.bundle" case still promote - Evidence: built-bin e2e #1404 regression + "update gained bundle" both pass;
pnpm typecheckclean - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1404
28. #1377 - dsh plugin install silently drops an unresolvable declared bundle
- Branch:
fix/plugin-reconcile-user-patch-dup-id(second commit, same reconcile root as #27) - Files:
apps/cli/src/plugin.ts(+ regression test inapps/cli/tests/built-bin.e2e.ts) - Fix: split resolution into bundle/plain/unresolvable and preserve an unresolvable declared bundle with a loud warning instead of splicing it out while
installreports success - Evidence: built-bin e2e #1377 regression passes;
pnpm typecheckclean - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1377
29. #2189 - typert-loader skips not-yet-mounted entries, breaking /api/commands/list
- Branch:
fix/typert-loader-activation-fiber-gate - Files:
packages/typert/loader/src/index.ts(+ regression test inpackages/typert/loader/tests/loader.spec.ts) - Fix:
qualifies()requiredentry.fiber !== undefined, so an entry whose plugin fiber had not mounted when typert-loader ran its activation scan was silently skipped; for@deepseek-ai/dsh-commandsthis meant the TYPERT manifest never registered and/api/commands/listreturned 404. Registration is a wire-schema contract independent of the plugin service lifecycle, soqualifies()now accepts a declared, enabled entry while its teardown counter is zero, and only rejects an entry that is mid-dispose (preserving withdraw-on-unmount). - Evidence:
packages/typert/loaderloader.spec 17/17 green with a "declared entry whose fiber is detached before activation" regression - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2189 (first reported as #1740)
30. #2202 - complete zstd frame ending in a torn JSONL record is a false positive
- Branch:
fix/zstd-torn-record-tail-tolerate - Files:
packages/session/session-persistence-jsonl/src/index.ts(+ updated test intests/zstd.spec.ts) - Fix:
readZstdPrefixreturns the committed prefix instead of throwing when all frames are structurally complete but the last frame ends mid-record (a transientZSTD_e_flushwriter state that self-heals); real corruption is still caught byconsumeEventLine, and the incomplete-final-frame recovery path is unchanged - Evidence: session-persistence-jsonl zstd.spec 80/80 green with the #2202 regression
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2202
31. #1688 - a __proto__ settings key mutates the prototype (silent data loss)
- Branch:
fix/settings-proto-key-own-property - Files:
packages/settings/settings/src/index.ts(+ regression test intests/settings.spec.ts) - Fix:
cloneJsonShapedandmergeLayersassign keys viaObject.definePropertyinstead oftarget[key] = value, so a__proto__key (valid JSON from a parsed body/config) stays an own data property instead of mutating the prototype;mergeLayersis exported for the test - Evidence:
settingssettings.spec 90/90 green with a__proto__own-key regression - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1688
32. #2271 - eval -- bashism breaks every non-bash persistent shell
- Branch:
fix/persistent-bash-eval-portable - Files:
packages/shell/tool-bash-persistent/src/index.ts(+ regression test intests/tools.spec.ts) - Fix:
wrapCommanduses a leading space inside the quoted word (eval $' <command>') instead ofeval --, blocking option parsing portably; busybox ash no longer treats--as the command name, and dash-prefixed commands still aren't parsed asevaloptions - Evidence: tool-bash-persistent wrapCommand regression (2 new cases) green
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2271
33. #2273 - SDK runtime closure omits dsh-mcp-client
- Branch:
fix/sdk-runtime-mcp-client-closure - Files:
python/sdk-runtime/package.json(+pnpm-lock.yaml) - Fix: add
@deepseek-ai/dsh-mcp-client: workspace:^to the Python SDK node-mode deploy root, so a custom composition that mounts an external MCP server loads on the shipped runtime - Evidence:
verify-runtime-closurepasses (110 workspace packages, closed graph) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2273
34. #1613 - Windows restricted-token runner surfaces opaque fast-fail exit codes
- Branch:
fix/windows-acl-fast-fail-hint - Files:
packages/sandbox/sandbox-windows-acl/src/runner.ts,src/fast-fail.ts(+tests/fast-fail.spec.ts) - Fix: decode the high-signal NTSTATUS fast-fail family (
STATUS_DLL_INIT_FAILED/STATUS_STACK_BUFFER_OVERRUN/STATUS_ACCESS_VIOLATION) into a stderr hint pointing at the restricted-token cause and thedanger-full-access/per-tool override workaround; the exit code is still mirrored unchanged - Evidence:
sandbox-windows-aclfast-fail.spec 2/2 green;pnpm typecheckclean - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/1613
35. #2358 - max-tokens sourceEventSeqs expansion overflows the call stack (RangeError)
- Branch:
fix/apiproxy-paginate-group-start-loop - File:
packages/host/apiproxy/src/api-proxy.ts(paginate) - Fix: replace
Math.min(event.seq, ...sources)with a bounded loop (let groupStart = event.seq; for (const source of sources) if (source < groupStart) groupStart = source) - Evidence: a single max-tokens-truncated
assistant/messagecan carry ~255,939sourceEventSeqs;Math.min(...sources)exceeds V8's argument/call-stack limit →RangeError: Maximum call stack size exceeded, permanently breakingsession.history(recurrence of #1593). Branch landed:build:lib:host+typecheck:contracts-readygreen, apiproxy-view suite 5/5. - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2358
36. #2342 - repair-path liveness re-check (prepareCore TOCTOU)
- Branch:
fix/repair-path-liveness-check - File:
packages/session/session-persistence/src/coordinator.ts(prepareCore) - Fix: re-check
ctx.sessions.get(id)at the top ofprepareCore(inside the per-id serialize reservation) so a session that becomes live after the publicprepare/load/inspectcheck cannot receive synthetic repair closers that collide with the live writer's next real seq. - Evidence:
build:lib:host+typecheck:contracts-readygreen (pre-push hook). Runtime verified:session-persistence-jsonlcoordinator-contract suite 151/151 passed (load/prepare/inspect/repair paths); sqlite suite 99/100 (the 1 failure is a WindowssymlinkEPERM environment issue, unrelated). - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2342
37. #2342 - reader self-heal for the synthetic-tail seq collision
- Branch:
fix/session-log-synthetic-tail-self-heal - File:
packages/session/session-persistence-jsonl/src/format.ts(SessionLogScanner.consumeEventLine) - Fix: when a backwards seq appears immediately after a synthetic
turn/end {reason: interrupted}, drop only that regenerable synthetic tail and re-align with the real events instead of rejecting the whole log. - Evidence: jsonl suite 152/152 (151 existing + 1 synthetic-tail-collision regression);
build:lib:host+typecheck:contracts-readygreen. - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2342
38. #2386 - Win32 directory picker truncates UTF-16 paths at 0x100-multiple code points
- Branch:
fix/win32-directory-picker-utf16-nul - File:
packages/host/directory-picker-native/src/win32-dialog-bindings.ts(readUtf16) - Fix: treat the UTF-16 NUL terminator as a full 16-bit unit (
bytes[end] !== 0 || bytes[end + 1] !== 0) instead of the low byte alone, so BMP code points that are multiples of 0x100 (言 U+8A00, 一 U+4E00, 刀 U+5200) no longer truncate the path. - Evidence:
win32-dialog-bindingssuite 13/13 (12 existing + 1 言语 regression). - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2386
39. #2376 - tool-cordis cordis_define oneOf stringified by some providers
- Branch:
fix/cordis-define-oneof-provider-stringify - File:
packages/extensions/tool-cordis/src/index.ts - Fix: replace the
pluginparameteroneOfunion with a plain object schema (kindenum + optionalidPrefix/pluginId) and validate the required branch field inexecute, so providers that stringifyoneOfparameters (PI-AI) no longer fail every branch. - Evidence: tool-cordis suite 11/11.
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2376
40. #2378 - SKILL.md frontmatter with an unquoted colon silently drops the skill
- Branch:
fix/skill-frontmatter-unquoted-colon - File:
packages/skill/skill-filesystem/src/index.ts(parseFrontmatter) - Fix: on the specific
BLOCK_AS_IMPLICIT_KEYYAML error, fall back to a line-based parse (value = everything after the first colon, quotes stripped) sodescription: Priority order: check the cache firstcatalogs instead of vanishing; other malformed YAML still skips the skill. - Evidence: skill-filesystem suite 20/22 (2 failures are Windows symlink EPERM, pre-existing).
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2378
41. #2388 - expose compat.supportsDeveloperRole for custom OpenAI-compatible endpoints
- Branch:
fix/pi-ai-supports-developer-role-flag - Files:
packages/llm/llm-pi-ai/src/catalog.ts,packages/llm/llm-pi-ai/src/config.ts - Fix: add a
compat.supportsDeveloperRoleswitch (route + per-model) that overrides pi-ai's vendor-list auto-detection, so domestic OpenAI-compatible endpoints (volces.com, aliyuncs.com, ...) can set itfalseand fall back to thesystemrole instead of being rejected with HTTP 400. - Evidence: llm-pi-ai suite 210/210.
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2388
42. #2405 - cross-platform session restore rejects the other OS's absolute cwd
- Branch:
fix/session-restore-cross-platform-cwd - File:
packages/core/session/src/index.ts(validateSessionHeader) - Fix: accept the
cwdwhen eitherposix.isAbsoluteorwin32.isAbsoluteis true (instead ofpath.isAbsolute, which checks only the current platform), so a Windows-created session restores on POSIX. - Evidence: session suite 78/78.
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/2405
Session-corruption family analysis (in progress — argszero, #2342)
Root cause (argszero, building on #2342): the repair path (prepareCore →
interruptedTurnClosers → commitRepair) has no liveness check, so it assumes
"log balanced = process live" and can splice a synthetic step/end +
turn/end {reason: interrupted} closer onto a session a live writer is still
appending to — the synthetic seq (last.seq + 1) collides with the writer's
next real seq, and the strict SessionLogScanner check then refuses the log.
Verified locations (checked against master 47f9438):
packages/core/session/src/repair.ts:27—interruptedTurnCloserssynthesizes the closers withseq = last.seq + 1.packages/session/session-persistence/src/coordinator.ts:892—prepareCorecallsinterruptedTurnCloserswithout re-checkingctx.sessionsliveness (the publicprepare/loadcheck it earlier, butprepareCoreruns later inside the per-id serialize reservation — a TOCTOU gap).packages/session/session-persistence/src/coordinator.ts—commitPreparedchecksstates.get(id).ownerbut not the livectx.sessionsregistry.- Backends:
session-persistence-jsonl/src/index.ts:436andsession-persistence-sqlite/src/index.ts:309(commitRepair).
Family: #1333/#1452 (duplicate seq), #1497 (torn tail), #1473 (corruption), #1586 (restore-writer vs live-writer), #2167 (duplicate append), #2342 (repair-writer vs live-writer). Shared defect: append/repair has no persistent "who owns the log" contract.
Proposed fix order:
- repair-path liveness/lease check — kill the class at the source (landed, patch #36, verified 151/151);
- persistent seq-ownership check — substantially already implemented: the
live append path asserts the "Contiguity contract" (
appendCore,coordinator.ts~699:event.seq === state.cursor + i), and the repair path is guarded byisPreparedSourceCurrent(readStoredRevision === source.revision). Remaining gap is narrow (a cross-process, revision-stable collision atcommitRepair→appendLineswrite time); - reader self-heal for the synthetic-tail collision — landed, patch #37, verified 152/152.
Fix #3 precise pattern (reader self-heal):
- The synthetic tail ends with
turn/endcarryingdata.reason.kind === 'interrupted'(and the immediately preceding syntheticstep/end/ interruptedtool/resultrows share the sametimeand contiguousseq = last.seq + 1). - On load, the collision shows as a backwards seq in
SessionLogScanner.consumeEventLine(format.ts): after consuming the synthetic tail, the next real event has a seq less thanthis.events.length. - Safe heuristic: when a backwards-seq gap is detected and the just-consumed
events end in a synthetic
turn/end {reason: interrupted}, drop only that synthetic tail (it is regenerable —interruptedTurnClosersrebuilds it) and continue consuming the real events. Never drop events that are not part of the synthetic tail.
Proposed minimal fix for the TOCTOU gap (fix #1, unverified — needs the
session-persistence coordinator-contract suite to run):
// coordinator.ts — inside prepareCore, before loadStored():
if (this.ctx.sessions.get(id) !== undefined) {
throw new Error(`cannot prepare session "${id}" while it is live`)
}
Caveat: prepare/load/inspect already check liveness and retry in a loop;
throwing here must be reconciled with the per-id serialize/reserve retry
semantics (a throw may abort the loop instead of retrying). Verify against
coordinator-contract.ts before shipping.
Status: fix #1 (repair-path liveness) is landed as patch #36 (branch pushed; build + typecheck + 151 coordinator-contract tests green). Fixes #2 (seq-ownership) and #3 (reader self-heal) are still analysis-only.
Tracked diagnoses (analysis-only, no patch yet)
These are source-verified problems with a clear fix direction but no cherry-pick-ready branch yet. They are tracked separately so the patch queue above stays honest ("ready to submit" only).
D1 — #2107 token meter underestimates dense tool-schema / tool-result surfaces
- Source:
packages/llm/token-meter/src/estimate.ts— flatCHARS_PER_TOKEN = 4for text, reasoning, tool-call arguments, tool results, system prompt, and tool schemas. - Runtime evidence: rc.6 web session (Crow0077, #2107) — 821 events, zero
compaction/start; provider rejected with context-exceeded while the meter stayed below the pressure gate (baseline.kind=estimated). - Fix direction: anchor to provider tokenization (or a denser per-surface floor for JSON/tool-schema content) so compaction fires before the provider limit. Needs upstream decision on estimator vs. exact tokenizer.
D2 — #2107 web-profile compaction never activates (realm wiring)
- Source:
packages/bundle/web-app/cordis.patch.ymldisables the host-plane copies ofcompaction-basic/command-compact/tool-result-pruner; the standard preset'sisolate: { compaction: true }copy does not render or fire for web sessions. - Runtime evidence: re-enabling the host copy is composition-verified
(
--dump-configshowsdisabled: false) yet runtime-ineffective — zero compaction events; points to the preset realm never joining the session. - Fix direction: decide host-plane vs preset-realm ownership, then repair the
realm wiring (or scope the
disabled: trueto the host copy only).
43. #3219 — same-mode sandbox_permissions request fails with "not strictly wider"
- Branch:
fix/escalation-same-mode-pass-through(zoahdev/deepseek-harness, sha 8d83d01) - Base: official
mainHEAD99f6f02(0.1.0-rc.7, 2026-08-17) — not the older 47f9438 master base of patches 1-42 - Files:
packages/sandbox/sandbox/src/escalation.ts,packages/sandbox/sandbox/tests/escalation.spec.ts - Fix:
approveEscalationreturns the requested mode whenrequestedMode === effectiveMode(no permission gain, no approval prompt), checked before the strictly-wider ladder;danger-full-access -> danger-full-accesspass-throughs become a silent no-op instead of an error - Tests: same-mode grants for read-only / workspace-write / danger-full-access never ask the approver; non-widening fixtures updated to genuinely narrower/incomparable pairs (workspace-write requested from danger-full-access, read-only requested from workspace-write)
- Verification (2026-08-19, Windows / Node 24 / pnpm 11):
vitest run packages/sandbox/sandbox/tests→ 3 files / 19 tests passed (escalation.spec.ts 12/12); full host treetsc -b tsconfig.host.jsontypecheck passed (lefthook pre-push) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/3219
- Note: the discussion also proposed a tool-layer same-mode skip (before
validateEscalationArgs, tool-bash index.ts:67 / tool-pwsh index.ts:99 / tool-fs sandbox.ts:88) for models that omitjustification; that follow-up is intentionally left out of this branch (requires effective-mode resolution at validation time) and should be its own patch if upstream wants it
44. #3191 — ignorable envelope on non-surface session append (out-of-tree plugin events)
- Branch (rebased onto current main):
fix/session-append-ignorable-envelope-rebased(zoahdev/deepseek-harness, sha 5c47ed6) — rebase of Mchsd'sfeat/session-append-ignorable-envelope(6430083a, base master 47f9438) onto official main99f6f02(rc.7) - Original author: Mchsd (branch 6430083a); rebase + independent verification: zoahdev
- Files:
packages/core/session/src/types.ts(+AppendOpts envelope contract),packages/core/session/src/index.ts(append opts split + ignorable write-through + warn-at-append),packages/session/session-persistence/src/coordinator.ts(rejection wording),packages/core/session/tests/session.spec.ts(+4 regressions), README - Fix: read side already honors
ignorable: true(coordinator.ts:1063; types.ts:412-422); this closes the write-side gap so out-of-tree plugins can mark informational events skippable instead of refusing resume on builds that do not know the type - Verification (2026-08-19, Windows / Node 24 / pnpm 11): rebased branch
vitest run packages/core/session packages/session/session-persistence→ 761/762 passed; the single failure is a pre-existing Windows symlink EPERM in session-persistence-sqlite (reproduces on clean main); full host tree typecheck passed (lefthook pre-push) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/3191
45. #3222 — HTTP 403 classified as AUTH hides the real provider error
- Branch:
fix/error-classify-403-forbidden(zoahdev/deepseek-harness, sha f3111fb) - Base: official main/master HEAD
99f6f02(rc.7) - Files:
packages/llm/llm-deepseek/src/adapter.ts(httpErrorCode 401->AUTH / 403->FORBIDDEN),packages/llm/llm-pi-ai/src/stream.ts(classifyPiAiError split), tests (llm-deepseek/tests/adapter.spec.ts[403,'FORBIDDEN'],llm-pi-ai/tests/adapter.spec.ts+[403,'FORBIDDEN'],llm-pi-ai/tests/convert.spec.ts+mapStopReason 403 case), README.md + README.zh.md error-code lists - Fix: 403 (credentials accepted, provider policy refusal) becomes FORBIDDEN and failure-display projects the raw provider message; 401 stays AUTH with the credential-safe mask. Retry semantics unchanged (FORBIDDEN not in default retryable codes, retry-policy.ts:19-25)
- Root cause + patch draft credit: MwumLi (#3222); branch built + independently verified: zoahdev
- Verification (2026-08-19, Windows / Node 24 / pnpm 11):
vitest run packages/llm/llm-deepseek packages/llm/llm-pi-ai→ 15 files / 373 tests passed; full host tree typecheck passed (lefthook pre-push) - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/3222
- Note: pi-ai classification is message-text based (SDK embeds status in error text); a structured-status path would be a further hardening, left out of this minimal branch
46. #3226 — adopted vision models lose input modalities during discovery
- Branch (rebased onto main):
fix/discovered-model-modality-rebased(zoahdev/deepseek-harness, eac57cc + ee3659b) — rebase of Ricardo-M-L'sfix/discovered-model-modality(631eecc9, base master 47f9438) onto official main99f6f02(rc.7) - Original author: Ricardo-M-L; rebase + independent verification: zoahdev
- Files (9):
packages/llm/llm/src/types.ts(LlmDiscoveredModel.inputModalities),packages/llm/llm/src/index.ts(discover mapping),packages/llm/llm-pi-ai/src/discovery.ts(catalog short-circuit passes input),packages/host/apiproxy/src/api/llm.ts+llm.schema.ts(wire view),api-proxy.ts(thread-through),ui-settings-models/ModelListEditor.tsx(adopt copies input + "Accepts image input" checkbox),ModelsSection.module.css,locales.ts - Fix: model discovery (endpoint listing + catalog short-circuit) carries input modalities; the settings-page fetch/adopt path keeps vision capability; users can also toggle image input per row
- Verification (2026-08-19, Windows / Node 24 / pnpm 11):
vitest run packages/llm/llm-pi-ai packages/llm/llm packages/client/ui-settings-models→ 41 files / 854 tests passed; host treetsc -bexit 0 - Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/3226
- Note: initial verification comment by zoahdev mis-attributed the LlmModelInfo field to LlmDiscoveredModel; corrected in a follow-up comment — the type-level field was genuinely missing on main
47. #3237 — ReplaceFileW EACCES on watched config files: fall back to rename
- Branch:
fix/atomic-write-eacces-fallback(zoahdev/deepseek-harness, sha eedb3f4) - Base: official main/master HEAD
99f6f02(rc.7) - Files:
packages/fs/fs-local/src/fsio.ts(win32 publication branch fallback),packages/fs/fs-local/tests/fsio.spec.ts - Fix: the win32
ReplaceFileWbranch only fell back torenameon ENOENT; HMR's fs.watch handle makes ReplaceFileW fail with EACCES (ERROR_ACCESS_DENIED) while rename succeeds. Fallback now coversisPermissionError(EACCES/EPERM); a genuinely locked target fails the rename too, so nothing is masked - Root cause credit: report + FFI verification by community (#3237); branch built + verified: zoahdev
- Verification (2026-08-19, Windows / Node 24 / pnpm 11): targeted fsio.spec tests pass (EACCES->rename fallback; non-recoverable failure still surfaces); full host tree typecheck passed (lefthook pre-push). The 8 symlink EPERM failures in fsio.spec are pre-existing environment issues (Developer Mode off), reproducible without the patch
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/3237
48. #3245 — CRITICAL: run_code worker-thread runtime bypasses the file sandbox (fail-closed)
- Branch:
fix/run-code-failclosed-sandbox(zoahdev/deepseek-harness, sha 93f7d83) - Base: official main/master HEAD
99f6f02(rc.7) - Severity: critical (sandbox escape; CVSS 10.0 / 9.8 as reported)
- Files:
packages/core/tools/src/code-mode.ts(guard +RunCodeBridgeOptions.resolveSandboxMode),packages/core/tools/src/index.ts(registry passes the sandbox-policy closure),packages/core/tools/tests/code-mode.spec.ts(+2 regression tests) - Fix: run_code refuses to dispatch when the code runtime isolation is 'worker-thread' and the resolved sandbox policy mode is read-only/workspace-write — the worker applies no file-effect confinement, so under a confined policy it would silently escape the sandbox (arbitrary file read/write + unconfined subprocess, triggerable via prompt injection). danger-full-access remains allowed (no sandbox to escape); DSH_TOOLS_MODE=native disables Code Mode
- Root cause credit: community report (#3245, with reproduction scripts); verification + fail-closed patch: zoahdev
- Verification (2026-08-19, Windows / Node 24 / pnpm 11): code-mode.spec 93/93 (incl. 2 new fail-closed tests); tools package 390/390; host tree typecheck clean
- Note: the root fix is confining the worker via ctx.sandbox.confine (or Node --experimental-permission); this branch is the immediate fail-closed mitigation. The workflow worker-thread (node:vm) and cordis-host-runner dynamic-plugin realms are the same unconfined-surface class and should get the same confinement
- Discussion: https://github.com/deepseek-ai/deepseek-harness/discussions/3245
Submit checklist (when the channel opens)
git fetch upstream && git merge-base --is-ancestor 47f9438 upstream/master— rebase if master moved.- Run the touched package's tests (each branch carries its regression tests).
- Open one PR per branch, title prefixed with the issue/discussion number.
- Attach the evidence snippet from the corresponding discussion.
- Offer to maintain the patch across release trains (zoahdev commits to this).