Repository navigation
Fix team_spawn on opencode 2.x, silent worktree fallback, and unvalidated depends_on - #41
Its-Satyajit wants to merge 1 commit into
Conversation
…on validation Fixes three bugs from issue hueyexe#40. - v2-client: feature-detect ctx.permission.rules before the permission re-assert. opencode >= 2.0.4 removed the API, so every team_spawn threw. The call is skipped, not deleted, so the re-assert still runs where the API exists. - team-spawn: report worktree creation failure in the tool result. The catch block only toasted, so the lead saw "spawned" while the teammate worked in the shared directory. - team-tasks-add: validate depends_on ids before inserting. A typo used to produce a blocked task that could never be claimed or completed.
…, read-only agents (#46) fixes the `team_spawn` crash + silent worktree failure from #40 on opencode 2.0.19+, plus the stuff that still stops teammates from working after that. ## vs #41 / #43 both guard `ctx.permission.rules`, #41 also validates `depends_on`. this does both, plus: ▸ **worktree root cause**: #41 adds a warning but couldn't find why `worktree.create` made nothing. 2.0.19+ worktree endpoints need a `projectID`. ensemble never sent one → creation failed → everyone shared the base tree. now passes `ctx.location.project.id` to create/list/remove/refresh ▸ **detached worktrees (2.0.32+)**: opencode now does `git worktree add --detach` (`packages/core/src/git.ts`). teammate commits land on a detached HEAD → `team_merge`: "not something we can merge". if the new worktree has no branch, ensemble creates it ▸ **edits stuck on approval**: v2 checks in-location files as relative paths, so `edit <worktree>/** allow` never matched → ask nobody answers. worktree teammates also get `edit * allow`. outside-the-worktree stays behind `external_directory` ▸ **read-only detection**: was name-only (`plan`, `explore`). custom reviewers got a worktree + `shell * allow`. now reads the agent's own rules via `agent.get`, names as fallback not touched: the 4th #40 thing (notifications redelivered after purge). on `permission.rules`: since 2.0.19 core merges session rules *after* agent rules (`merge(agent, session)`, last match wins), so the `session.create` permissions already win. skipping `rules()` when it's gone loses nothing. ## verification ✓ `bun run typecheck` clean ✓ `bun test` 857 pass / 0 fail (new: projectID pass-through, detached naming, read-only from rules, `edit *`, unknown `depends_on`) ✓ `bun run lint` only pre-existing warnings ✓ live on **2.0.24 + 2.0.32**: ``` team_create → team_spawn(build, worktree) → own worktree + branch → commit → team_shutdown → team_merge ✓ → team_cleanup ``` ✗ not verified: subagent-mode teammates (`explore` etc.) on opencode's free `big-pickle`. they get "free tier can only be used from within OpenCode", built-ins too, so it looks like a host/provider thing, not ensemble. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01GUtz6gBn7rhXaufK97d8cm --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ty, isolation warning - team_spawn: bind session to the worktree directory when workspace binding is unavailable, so the 'edit * allow' rule scopes to the worktree instead of the whole shared tree - v2-client: gitCreateBranch now returns the effective branch (or null); logs failures and falls back to 'git switch' for the existing-branch re-spawn race. worktree.create records the effective branch only — a failed create can no longer point team_merge at a stale same-named branch whose commits would silently shadow new work - v2-client: guard ctx.permission?.rules against a missing permission domain - team_spawn: spawn result now warns plainly when worktree isolation did not complete (cherry-picked from PR #41, issue #40 bug 2) - tests: branch-failure error path, cross-team depends_on rejection (from PR #41)
|
Closing as superseded by #46 — with real credit due: a deep review found your |
Fixes three of the four bugs in #40. Each fix has a test that fails on
mainand passes here.1.
team_spawnthrows on opencode 2.x (blocker)src/v2-client.ts:122calledctx.permission.rulesunconditionally. opencode 2.0.4 removed that plugin API, so every spawn died with:That made the whole plugin unusable on 2.x, not just degraded.
The fix feature-detects the call and skips the re-assert when the API is absent. Skipping rather than deleting matters. The comment at
v2-client.ts:118-121records why the re-assert exists:session.createpermissions lose to agent rules, which strips team tools from read-only agents, andrules()evaluates after the agent's rules to restore them. On 2.x the re-assert cannot run, so agent rules still win and read-only agents may lose their team tools. Please call that out in the release notes. It is silent, and it is the one part of this bug I could not verify away.2.
worktree: truereported success and created nothingOn opencode 2.0.19, spawning with
worktree: truecreated no worktree.git worktree listshowed only the base directory, a filesystem search for the worktree name found nothing, and both teammates committed straight ontomaster. The lead sawTeammate "alpha" spawned (agent: build).team_mergelater reportedNo branch to merge for "alpha".The cause on our side is
src/tools/team-spawn.ts:114-124, which catches everyworktree.createfailure and downgrades it to a TUI toast. Nobody watching the tool output sees it.The fix appends a warning to the spawn result naming the teammate and stating that they share the working directory, so
branch:is never the only thing in the string.I could not determine why
worktree.createproduced nothing. opencode 2.0.19 documents the command as loading the project's canonical configuration, creating a worktree with its selected strategy, then running the project's setup script, and no worktree strategy is configured here. A missing project worktree strategy is the likely cause, but I have not confirmed it and this fix does not address the cause.3. A typo in
depends_onproduced a permanently dead taskteam_tasks_addaccepted any string independs_on. A typo produced a task that wasblocked, whichteam_claimrefuses, whichteam_tasks_completealso refuses. Nothing else editsdepends_on, so only purging the team freed it.The fix validates every dependency against the current team before inserting anything, and rejects the whole call listing the unknown ids. Validation is scoped to
team_id, so an id from another team is rejected too. Nothing is inserted when validation fails, so a batch cannot land half-written.Not fixed here
The fourth bug in #40, teammates in
shutdownstate redelivering notifications to a lead whose team was purged, is untraced. Theteam_messagetable is empty after a purge, so the redelivery is not DB-driven, and I did not find the source. I left it out rather than guess.Verification
Run with
bun install --frozen-lockfileon bun 1.4.2, matching the lockfile.One caveat on the test count.
recovery.test.tshas a test that intermittently times out at 5s under full-suite load and passes when the file runs alone. It is unrelated to these changes and pre-existing.A note on how I first read the typecheck. Installing with a newer
@types/bunthan the lockfile pins produced 50Response.text/Response.jsonerrors in unrelated test files. Restoring the lockfile version cleared all of them. If you see those errors, check the@types/bunversion before assuming they are real.