fleetd#219: fix OpenCodeLauncher config/discovery roots under memberHerdrSocket #221
Reference in New Issue
Block a user
Delete Branch "worker/cb-219-opencode-roots-1f677e-1"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes fleetd#219 — OpenCodeLauncher decided both the ephemeral opencode.json config directory and opencode session discovery from fleetd's own filesystem (java.io.tmpdir / user.home), which breaks the moment memberHerdrSocket puts member panes under a different OS user (the #213 defect, twice).
Site 1 (config root, OpenCodeLauncher#writeConfig / #configParentDir): under memberHerdrSocket, the directory now goes under worktreeRoot and is shared read-only with worktreeGroup via EnvAllowListScrub#shareWithGroup (widened to package-private and generalized — the exact mechanism #213 built for the ZDOTDIR scrub, reused rather than duplicated). Unlike the ZDOTDIR scrub's degrade-to-overlay fallback, a missing worktreeRoot/worktreeGroup here REFUSES the spawn (IllegalStateException) instead of degrading — this config file is the member's only way to learn where the bridge MCP is, so writing it somewhere unreadable would just produce an undeliverable member with no signal pointing at the cause. memberHerdrSocket absent is byte-identical to before (config==null and a live-but-unset config supplier both verified).
Site 2 (discovery root, OpenCodeLauncher#defaultDiscoveryRoot / SessionAwareHandle#agentSessionId): under memberHerdrSocket, agentSessionId() now declares session discovery unavailable and logs one WARN per launcher instance instead of silently scanning fleetd's own /Users/dai.ha (opencode.db actually lives under the MEMBER's home). This is a decision, not a patch — full reasoning (three options weighed, why 'declare unavailable' was picked over a new config key or deriving the home) is in defaultDiscoveryRoot()'s javadoc.
Shared plumbing: HerdrPeerLauncher#memberHerdrSocketConfigured/memberScrubParentDir/memberGroup widened from private to package-private so OpenCodeLauncher reuses the exact same config resolution instead of re-deriving it.
Same-shape finding, NOT fixed (out of scope): ClaudeCodeLauncher#writeCharterFile (~line 465) writes the role-charter temp file via Files.createTempFile with no directory argument, i.e. under java.io.tmpdir — the same site-1 shape, unaddressed for the Claude Code adapter. Left for its own ticket per the brief.
Tests: 5 new tests in OpenCodeLauncherTest (site 1 success/2 refusal variants/byte-identical-absent, site 2 discovery-gated). All 4 behavior-asserting tests were verified red before the fix (reverted OpenCodeLauncher.java only, kept the test file): wrong parent dir used, IllegalStateException not thrown (x2), and agentSessionId() returned the hidden record instead of null. The byte-identical-absent test passes in both states, as expected for a regression guard.
Build:
mvn clean installfrom fleetd/ — BUILD SUCCESS, Tests run: 1086, Failures: 0, Errors: 0, Skipped: 0.