Skip to content

Resolve folder-mode entity dispatch via worktree fallback (fixes #184)#185

Open
iamcxa wants to merge 1 commit into
spacedock-dev:mainfrom
iamcxa:fix/folder-mode-entity-helper
Open

Resolve folder-mode entity dispatch via worktree fallback (fixes #184)#185
iamcxa wants to merge 1 commit into
spacedock-dev:mainfrom
iamcxa:fix/folder-mode-entity-helper

Conversation

@iamcxa
Copy link
Copy Markdown
Contributor

@iamcxa iamcxa commented May 4, 2026

Fixes #184.

Problem (recap)

Folder-mode entities (<id>-<slug>/index.md) live on a worktree branch until merge; the Rule 10 os.path.isfile(entity_path) gate in cmd_build rejects them outright, forcing break-glass dispatch.

A secondary defect surfaced while patching: os.path.splitext(os.path.basename(entity_path))[0] returns the literal "index" for every folder-mode entity, so TeamCreate rejects the duplicate names whenever multiple folder-mode entities are dispatched in the same team.

Changes — all in cmd_build (skills/commission/bin/claude-team)

1. New helper _list_worktrees(git_root)

Parses git worktree list --porcelain into [(path, branch_or_None), ...]. Returns [] on any subprocess failure (git missing, not a repo) so callers can surface a clean error rather than silently fall through.

2. New helper _resolve_entity_read_path(entity_path, workflow_dir)

Two-step resolver:

  1. If os.path.isfile(entity_path) — return it (flat-layout & merged-folder happy path; zero behavior change).
  2. Else enumerate worktrees via _list_worktrees() and probe each for <wt_path>/<entity_rel>. First match wins.

Returns (resolved_path, tried_paths). On total failure the helper hands every probed path back to the caller so the error message can list exactly where it looked.

3. New helper _derive_entity_slug(entity_path)

Layout-aware slug derivation:

  • index.md → parent directory name (folder mode)
  • anything else → filename stem (flat layout, unchanged)

4. Wire into cmd_build

  • Rule 10 gate replaced with the resolver. On failure, the error lists every probed path:

    entity file not readable at '<path>'. Folder-mode worktree fallback also failed: no checked-out worktree contains a copy at the same repo-relative location. Tried: ['<a>', '<b>', ...].

  • Frontmatter read (parse_frontmatter) now uses the resolved path so folder-mode worktree-only entities yield real worktree: / title: fields instead of empty values.
  • Slug derivation goes through _derive_entity_slug().

5. No changes to status binary or to the emitted prompt's worktree path / git branch / read-instruction logic

The emitted prompt's worktree path was already computed from the entity's worktree: frontmatter field. Once the frontmatter is read from the resolved location, every downstream branch (worktree_path, branch = worker_key/slug, "Read the entity file at …") works without further change.

Tests

tests/test_claude_team.py::TestBuildFolderModeWorktreeOnly adds three:

Test Verifies
test_folder_mode_worktree_only_entity_dispatches Real git init + git worktree add of a folder entity NOT on main; build returns exit 0, agent name is spacedock-ensign-<folder-slug>-ship (not …-index-…), prompt's read-target points at worktree-side index.md, working-dir line points at the worktree.
test_folder_mode_fallback_failure_lists_tried_paths When no worktree owns the file, error includes Folder-mode worktree fallback also failed, the project-root path, AND the unrelated worktree's candidate path.
test_flat_layout_regression_unchanged_when_file_present Flat-layout fixture (no git repo at all) short-circuits via os.path.isfile; derived name still uses filename stem. Guards against accidental subprocess overhead and confirms the original happy path is byte-equivalent.

108 passed total (was 105 + 3 new).

What this PR does NOT touch

  • plugin.json version (per maintainer release cadence).
  • skills/commission/bin/status (folder-mode resolution is local to claude-team).
  • The Rule 12 worktree-path rejection (line 209) — entity_path must still be project-root absolute. Folder-mode resolves THROUGH the project-root path, never around it.
  • The emitted-prompt worktree-instruction block.

Verification on a real folder-mode worktree-only entity

The captain's failing dispatch from the issue, rerun against this branch:

echo '{"schema_version":1,
       "entity_path":"/Users/kent/Project/<consumer>/docs/ship-flow/057-<slug>/index.md",
       "workflow_dir":"/Users/kent/Project/<consumer>/docs/ship-flow",
       "stage":"ship",
       "checklist":["1. test"],
       "team_name":"test-team",
       "feedback_context":null,
       "scope_notes":null,
       "bare_mode":false,
       "is_feedback_reflow":false}' \
  | skills/commission/bin/claude-team build --workflow-dir /Users/kent/Project/<consumer>/docs/ship-flow

Result on this branch: exit 0, valid Agent spec JSON, prompt working-dir points at /Users/kent/Project/<consumer>/.worktrees/ship-flow-<branch-suffix>, name uses the folder slug.

claude-team build rejected entity paths whose filesystem copy did not
exist on main, even when a checked-out worktree branch had the file at
the same repo-relative location. Folder-mode entities
(<id>-<slug>/index.md) are git-tracked on a worktree branch until
merge — this gate forced break-glass dispatch every time.

Two fixes in cmd_build:

1. Replace the os.path.isfile(entity_path) gate with
   _resolve_entity_read_path(): try the project-root path first
   (zero behavior change for flat layout / merged folders), then
   probe each worktree from `git worktree list --porcelain` for
   a copy at the same repo-relative location. On total failure,
   surface every probed path so the captain can debug.

2. Make slug derivation layout-aware. Folder-mode (<slug>/index.md)
   now uses the parent directory name; flat-layout keeps the
   filename stem. Without this, every folder-mode entity collided
   on the literal "index" in derived agent names.

The emitted prompt's worktree path / git branch / read-instruction
target are unchanged: they were already computed from the entity's
`worktree:` frontmatter field, which is now read from the resolved
worktree-side file.

Tests:
  * test_folder_mode_worktree_only_entity_dispatches — folder entity
    on worktree branch only (not on main) resolves and dispatches
    with the correct slug-based agent name.
  * test_folder_mode_fallback_failure_lists_tried_paths — clean error
    message lists every probed path when no worktree owns the file.
  * test_flat_layout_regression_unchanged_when_file_present — flat
    layout file with main-side copy short-circuits via os.path.isfile,
    derived name uses filename stem.

108 passed (was 105 + 3 new), zero regressions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

claude-team build: folder-mode entities (<slug>/index.md) fail when only on worktree branch

1 participant