[GH-ISSUE #2666] fix(setup): empty DSH_HOME writes the Harness registration into the working directory #968

Closed
opened 2026-10-15 18:29:58 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 13, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2666

Summary

With DSH_HOME set to an empty string, approved rea setup --client dsh --skill=false --yes --json creates cordis.patch.yml in the working directory and reports ready. DeepSeek Harness treats that empty override as unset and selects its default home patch instead. The default patch remains absent in the isolated reproduction. Unsetting the variable or supplying a nonempty absolute home restores agreement.

Steps to reproduce

Use a source checkout at a revision stated under Runtime or environment. For a fresh checkout, select the pinned toolchain described in CONTRIBUTING.md, run npm ci, then run npm run build:cached in the checkout to prepare its compiled dispatcher. Those preparation commands are prerequisites; the recorded reproduction used an already prepared checkout. With the supported Node executable on PATH, save this fixture as reproduce.py and run python3 reproduce.py PATH_TO_CHECKOUT/scripts/rea.mjs. Each case uses a fresh nonempty home, separate workspace and isolated temporary/cache directories. The exact fixture below ran during focused verification and reproduced all three placement results. The verification also inspected the written REA entries and independently ran the released client path helper.

import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile

node = shutil.which("node")
assert node, "Put the supported Node executable on PATH"
cli = str(Path(sys.argv[1]).resolve())
assert Path(cli).is_file(), "Pass the checkout's scripts/rea.mjs"

with tempfile.TemporaryDirectory(prefix="rea-dsh-check-") as temporary:
    root = Path(temporary).resolve()
    for case in ("empty", "unset", "explicit"):
        base = root / case
        home, workspace, temporary_files = (
            base / "home", base / "workspace", base / "temp"
        )
        for directory in (home, workspace, temporary_files):
            directory.mkdir(parents=True)
        environment = {
            "PATH": os.environ["PATH"],
            "HOME": str(home),
            "USERPROFILE": str(home),
            "TMPDIR": str(temporary_files),
            "XDG_DATA_HOME": str(base / "data"),
            "XDG_CACHE_HOME": str(base / "cache"),
            "XDG_STATE_HOME": str(base / "state"),
            "npm_config_cache": str(base / "npm-cache"),
        }
        if case == "empty":
            environment["DSH_HOME"] = ""
        if case == "explicit":
            environment["DSH_HOME"] = str(base / "profile")
        result = subprocess.run(
            [node, cli, "setup", "--client", "dsh", "--skill=false",
             "--yes", "--json"],
            cwd=workspace, env=environment,
            capture_output=True, text=True, timeout=15,
        )
        report = json.loads(result.stdout)
        targets = [
            str((workspace / action["target"]).resolve().relative_to(base))
            for action in report["plannedActions"]
            if action["kind"] == "configure_client"
        ]
        patches = sorted(str(path.relative_to(base))
                         for path in base.rglob("cordis.patch.yml"))
        print(json.dumps({"case": case, "exit": result.returncode,
                          "status": report["status"],
                          "targets": targets, "patches": patches}))

No Harness installation or analysis provider is required to reproduce REA's placement failure. The expected client lookup was independently established from the released Harness path helper, as described in Evidence. Skill installation is disabled to isolate registration placement.

Expected behavior

An empty DSH_HOME should select the same home patch as an unset variable, home/.dsh/cordis.patch.yml in this fixture. Setup should create that patch, leave the workspace without a patch and check readiness at the client-selected path. A nonempty absolute override should continue selecting profile/cordis.patch.yml.

Actual behavior

The three executed setup commands all exited 0, returned status: "ready" and applied configured_dsh. The empty case created a patch containing rea-mcp in the workspace while the default home patch remained absent. The unset and explicit controls created the corresponding client-selected patch.

case      setup target and created patch     client-selected home patch
empty     workspace/cordis.patch.yml          home/.dsh/cordis.patch.yml
unset     home/.dsh/cordis.patch.yml           home/.dsh/cordis.patch.yml
explicit  profile/cordis.patch.yml            profile/cordis.patch.yml

The client-selected column comes from executing the released Harness pure path resolver in a separate process with the same environment and working directory. A complete native Harness session was not started, and actual MCP connection behavior was not tested.

Evidence

  • Expected source: docs/client-configuration.md:204-211 documents DSH setup registration in the Harness home patch. Released @deepseek-ai/dsh-home-paths package, package/lib/index.js:63-76, explicitly treats empty or whitespace-only DSH_HOME as unset. Released @deepseek-ai/dsh package, package/lib/profile-boot-BZ2ZjNWi.js, uses that resolver in homePatchPath() before joining cordis.patch.yml.
  • Failure source: The executed public setup commands and patch readback produced the results above. src/application/SupportedClients.ts:160-164 preserves the empty variable when resolving the patch. The prepared compiled resolver has the same rule at dist/application/SupportedClients.js:50-51. Source path resolution independently agreed with every observed setup target.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Restoration check

Repeat the empty, unset and explicit cases. The empty case must plan and create home/.dsh/cordis.patch.yml, with no workspace/cordis.patch.yml. Readiness must check the client-selected home patch. The unset control must retain the same default placement, and the nonempty absolute override must retain its selected profile placement. Verify actual file placement and the REA entry rather than using ready alone as the passing signal.

Runtime or environment

Source checkout a2d8b94dd50dab8d966239dd63ab84718aa8b4b4, package metadata 6.4.0, with its prepared compiled dispatcher and matching DSH resolver. The focused source test used Node 24.18.0 and npm 11.16.0 on a POSIX host. A separately installed published REA package was not tested. The inspected released Harness CLI and home-path helper were both 0.2.0-rc.2. No analysis artifact or provider session was involved. Current source recheck at 3ae826ceba6f25b08bce50bcb51001209bc16b57 confirms the same empty-value path resolution and setup admission from source; no new runtime reproduction was run, and this source revision is not the published package runtime.

Additional context

The resolved reports for empty HOME and empty XDG_CONFIG_HOME concern different inputs. This reproduction keeps HOME nonempty and changes only DSH_HOME. It covers the Harness registration patch only; other client overrides and skill destinations are outside the verified report. Related: #2149 tracks publishing the source-main DSH integration, which is absent from the latest registry release; that release-availability request does not cover this empty-value mismatch.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A bounded empty-variable input makes setup create a registration outside the Harness-selected home patch while reporting readiness. The intended patch remains absent, and the workspace gains an unexpected recoverable file. Native MCP startup was not tested.
  • Workaround status: available
  • Workaround basis: The executed unset-variable control restored default home placement. A nonempty absolute DSH_HOME also produced a patch at the client-selected location.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2666 ## Summary With `DSH_HOME` set to an empty string, approved `rea setup --client dsh --skill=false --yes --json` creates `cordis.patch.yml` in the working directory and reports `ready`. DeepSeek Harness treats that empty override as unset and selects its default home patch instead. The default patch remains absent in the isolated reproduction. Unsetting the variable or supplying a nonempty absolute home restores agreement. ## Steps to reproduce Use a source checkout at a revision stated under Runtime or environment. For a fresh checkout, select the pinned toolchain described in `CONTRIBUTING.md`, run `npm ci`, then run `npm run build:cached` in the checkout to prepare its compiled dispatcher. Those preparation commands are prerequisites; the recorded reproduction used an already prepared checkout. With the supported Node executable on `PATH`, save this fixture as `reproduce.py` and run `python3 reproduce.py PATH_TO_CHECKOUT/scripts/rea.mjs`. Each case uses a fresh nonempty home, separate workspace and isolated temporary/cache directories. The exact fixture below ran during focused verification and reproduced all three placement results. The verification also inspected the written REA entries and independently ran the released client path helper. ```python import json import os from pathlib import Path import shutil import subprocess import sys import tempfile node = shutil.which("node") assert node, "Put the supported Node executable on PATH" cli = str(Path(sys.argv[1]).resolve()) assert Path(cli).is_file(), "Pass the checkout's scripts/rea.mjs" with tempfile.TemporaryDirectory(prefix="rea-dsh-check-") as temporary: root = Path(temporary).resolve() for case in ("empty", "unset", "explicit"): base = root / case home, workspace, temporary_files = ( base / "home", base / "workspace", base / "temp" ) for directory in (home, workspace, temporary_files): directory.mkdir(parents=True) environment = { "PATH": os.environ["PATH"], "HOME": str(home), "USERPROFILE": str(home), "TMPDIR": str(temporary_files), "XDG_DATA_HOME": str(base / "data"), "XDG_CACHE_HOME": str(base / "cache"), "XDG_STATE_HOME": str(base / "state"), "npm_config_cache": str(base / "npm-cache"), } if case == "empty": environment["DSH_HOME"] = "" if case == "explicit": environment["DSH_HOME"] = str(base / "profile") result = subprocess.run( [node, cli, "setup", "--client", "dsh", "--skill=false", "--yes", "--json"], cwd=workspace, env=environment, capture_output=True, text=True, timeout=15, ) report = json.loads(result.stdout) targets = [ str((workspace / action["target"]).resolve().relative_to(base)) for action in report["plannedActions"] if action["kind"] == "configure_client" ] patches = sorted(str(path.relative_to(base)) for path in base.rglob("cordis.patch.yml")) print(json.dumps({"case": case, "exit": result.returncode, "status": report["status"], "targets": targets, "patches": patches})) ``` No Harness installation or analysis provider is required to reproduce REA's placement failure. The expected client lookup was independently established from the released Harness path helper, as described in Evidence. Skill installation is disabled to isolate registration placement. ## Expected behavior An empty `DSH_HOME` should select the same home patch as an unset variable, `home/.dsh/cordis.patch.yml` in this fixture. Setup should create that patch, leave the workspace without a patch and check readiness at the client-selected path. A nonempty absolute override should continue selecting `profile/cordis.patch.yml`. ## Actual behavior The three executed setup commands all exited 0, returned `status: "ready"` and applied `configured_dsh`. The empty case created a patch containing `rea-mcp` in the workspace while the default home patch remained absent. The unset and explicit controls created the corresponding client-selected patch. ```text case setup target and created patch client-selected home patch empty workspace/cordis.patch.yml home/.dsh/cordis.patch.yml unset home/.dsh/cordis.patch.yml home/.dsh/cordis.patch.yml explicit profile/cordis.patch.yml profile/cordis.patch.yml ``` The client-selected column comes from executing the released Harness pure path resolver in a separate process with the same environment and working directory. A complete native Harness session was not started, and actual MCP connection behavior was not tested. ## Evidence - Expected source: `docs/client-configuration.md:204-211` documents DSH setup registration in the Harness home patch. Released [`@deepseek-ai/dsh-home-paths` package](https://registry.npmjs.org/@deepseek-ai/dsh-home-paths/-/dsh-home-paths-0.2.0-rc.2.tgz), `package/lib/index.js:63-76`, explicitly treats empty or whitespace-only `DSH_HOME` as unset. Released [`@deepseek-ai/dsh` package](https://registry.npmjs.org/@deepseek-ai/dsh/-/dsh-0.2.0-rc.2.tgz), `package/lib/profile-boot-BZ2ZjNWi.js`, uses that resolver in `homePatchPath()` before joining `cordis.patch.yml`. - Failure source: The executed public setup commands and patch readback produced the results above. `src/application/SupportedClients.ts:160-164` preserves the empty variable when resolving the patch. The prepared compiled resolver has the same rule at `dist/application/SupportedClients.js:50-51`. Source path resolution independently agreed with every observed setup target. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete ## Restoration check Repeat the empty, unset and explicit cases. The empty case must plan and create `home/.dsh/cordis.patch.yml`, with no `workspace/cordis.patch.yml`. Readiness must check the client-selected home patch. The unset control must retain the same default placement, and the nonempty absolute override must retain its selected profile placement. Verify actual file placement and the REA entry rather than using `ready` alone as the passing signal. ## Runtime or environment Source checkout `a2d8b94dd50dab8d966239dd63ab84718aa8b4b4`, package metadata 6.4.0, with its prepared compiled dispatcher and matching DSH resolver. The focused source test used Node 24.18.0 and npm 11.16.0 on a POSIX host. A separately installed published REA package was not tested. The inspected released Harness CLI and home-path helper were both 0.2.0-rc.2. No analysis artifact or provider session was involved. Current source recheck at `3ae826ceba6f25b08bce50bcb51001209bc16b57` confirms the same empty-value path resolution and setup admission from source; no new runtime reproduction was run, and this source revision is not the published package runtime. ## Additional context The resolved reports for [empty HOME](https://github.com/morluto/rea/issues/2325) and [empty XDG_CONFIG_HOME](https://github.com/morluto/rea/issues/2168) concern different inputs. This reproduction keeps `HOME` nonempty and changes only `DSH_HOME`. It covers the Harness registration patch only; other client overrides and skill destinations are outside the verified report. Related: #2149 tracks publishing the source-main DSH integration, which is absent from the latest registry release; that release-availability request does not cover this empty-value mismatch. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A bounded empty-variable input makes setup create a registration outside the Harness-selected home patch while reporting readiness. The intended patch remains absent, and the workspace gains an unexpected recoverable file. Native MCP startup was not tested. - Workaround status: available - Workaround basis: The executed unset-variable control restored default home placement. A nonempty absolute DSH_HOME also produced a patch at the client-selected location.
bsakaguchi 2026-10-15 18:29:58 +00:00
  • closed this issue
  • added the
    bug
    label
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#968
No description provided.