Skip to content
Back to skills

2504 Design Ae3b0ee4

ASecurity

- **Feature**: orchestrator-coordination-fix - **Status**: APPROVED - **Created**: 2026-02-04 - **GitHub Issues**: Related to #65, #119 (bite-sized-planning rush failures)

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added May 31, 2026
testingpythongotestinggit

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned May 31, 2026

npx -y skills add tools-only/X-Skills --skill 2504-design_ae3b0ee4 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 2504 Design Ae3b0ee4?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 2504 Design Ae3b0ee4
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-2504-design-ae3b0ee4/badge)](https://www.skillsdirectory.com/skills/tools-only-2504-design-ae3b0ee4)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# Technical Design: Orchestrator Coordination Fix

## Metadata
- **Feature**: orchestrator-coordination-fix
- **Status**: APPROVED
- **Created**: 2026-02-04
- **GitHub Issues**: Related to #65, #119 (bite-sized-planning rush failures)

---

## 1. Overview

### 1.1 Summary

Fix 6 critical bugs in ZERG orchestrator that cause merge conflicts, level violations, and redundant gate runs. The core fix is simple: defer all merges to ship time instead of merging after each level.

### 1.2 Goals

- Main branch untouched during rush execution
- Strict level enforcement at task claim time
- Strict dependency enforcement at runtime
- Quality gates run exactly once (at ship)
- Live status streaming for user visibility

### 1.3 Non-Goals

- Changing ship command's PR creation logic
- Adding new merge strategies
- Modifying worker spawn behavior

---

## 2. Architecture

### 2.1 Current Flow (Broken)

```
Level 1 complete → merge_level() → full_merge_flow(target="main") → MAIN MODIFIED
Level 2 complete → merge_level() → full_merge_flow(target="main") → MAIN MODIFIED (again)
...
```

### 2.2 Fixed Flow

```
Level 1 complete → set_level_status("complete") → advance to Level 2 → NO MERGE
Level 2 complete → set_level_status("complete") → advance to Level 3 → NO MERGE
...
All levels complete → Rush DONE (main untouched)

/z:git --action ship:
  → Create staging from main
  → Merge all worker branches to staging
  → Run quality gates ONCE
  → Merge staging to main / Create PR
  → Cleanup
```

### 2.3 Component Changes

| Component | Current | After Fix |
|-----------|---------|-----------|
| `level_coordinator.py` | Calls `merge_level()` on level complete | Skips merge if `defer_merge_to_ship=True` |
| `state.py:claim_task()` | Only checks status + worker | Also checks level + dependencies |
| `merge.py:full_merge_flow()` | Always runs gates | Skips gates if `skip_gates_until_ship=True` |
| `git_cmd.py:action_ship()` | Uses `gh pr merge` directly | Uses `MergeCoordinator` with gates |
| `merge.py:finalize()` | Checkouts target branch | Uses detached HEAD |

---

## 3. Detailed Design

### 3.1 Config Changes

```python
# zerg/config.py

class RushConfig(BaseModel):
    # Existing fields...

    # NEW: Coordination fixes
    defer_merge_to_ship: bool = Field(
        default=True,
        description="Defer all merges to /z:git --action ship"
    )
    gates_at_ship_only: bool = Field(
        default=True,
        description="Run quality gates only at ship time, not per level"
    )
```

### 3.2 DependencyChecker Helper

```python
# zerg/dependency_checker.py

class DependencyChecker:
    def __init__(self, state: StateManager, parser: TaskParser):
        self._state = state
        self._parser = parser

    def are_dependencies_complete(self, task_id: str) -> bool:
        """Check if all dependencies of task_id are COMPLETE."""
        task = self._parser.get_task(task_id)
        if not task:
            return False

        for dep_id in task.get("dependencies", []):
            dep_status = self._state.get_task_status(dep_id)
            if dep_status != TaskStatus.COMPLETE.value:
                return False

        return True

    def get_incomplete_dependencies(self, task_id: str) -> list[str]:
        """Return list of dependency IDs that are not COMPLETE."""
        task = self._parser.get_task(task_id)
        if not task:
            return []

        incomplete = []
        for dep_id in task.get("dependencies", []):
            dep_status = self._state.get_task_status(dep_id)
            if dep_status != TaskStatus.COMPLETE.value:
                incomplete.append(dep_id)

        return incomplete
```

### 3.3 EventEmitter for Live Streaming

```python
# zerg/event_emitter.py

class EventEmitter:
    def __init__(self, feature: str, state_dir: Path):
        self._event_file = state_dir / f"{feature}-events.jsonl"

    def emit(self, event_type: str, data: dict | None = None) -> None:
        """Append event to JSONL file."""
        entry = {
            "ts": datetime.now().isoformat(),
            "event": event_type,
            "data": data or {}
        }
        with open(self._event_file, "a") as f:
            f.write(json.dumps(entry) + "\n")

    def subscribe(self, callback: Callable[[dict], None]) -> None:
        """Tail event file and call callback for new events."""
        # Implementation: use watchdog or simple polling
```

### 3.4 Modified claim_task()

```python
# zerg/state.py

def claim_task(
    self,
    task_id: str,
    worker_id: int,
    current_level: int | None = None,
    dependency_checker: DependencyChecker | None = None
) -> bool:
    """Attempt to claim a task for a worker."""
    with self._atomic_update():
        task_state = self._state.get("tasks", {}).get(task_id, {})

        # NEW: Level enforcement
        if current_level is not None:
            task_level = task_state.get("level", 1)
            if task_level != current_level:
                logger.warning(f"Task {task_id} (L{task_level}) blocked - current level is {current_level}")
                return False

        # NEW: Dependency enforcement
        if dependency_checker is not None:
            if not dependency_checker.are_dependencies_complete(task_id):
                incomplete = dependency_checker.get_incomplete_dependencies(task_id)
                logger.warning(f"Task {task_id} blocked by incomplete deps: {incomplete}")
                return False

        # Existing checks...
        current_status = task_state.get("status", TaskStatus.PENDING.value)
        if current_status not in (TaskStatus.TODO.value, TaskStatus.PENDING.value):
            return False

        existing_worker = task_state.get("worker_id")
        if existing_worker is not None and existing_worker != worker_id:
            return False

        # Claim it
        self.set_task_status(task_id, TaskStatus.CLAIMED, worker_id=worker_id)
        self.record_task_claimed(task_id, worker_id)
        return True
```

### 3.5 Modified handle_level_complete()

```python
# zerg/level_coordinator.py

def handle_level_complete(self, level: int) -> bool:
    """Handle level completion."""
    # Check config
    if self.config.rush.defer_merge_to_ship:
        # NEW: No merge during rush
        logger.info(f"Level {level} complete. Merge deferred to ship.")
        self.state.set_level_status(level, "complete")
        self._emit_event("level_complete", {"level": level, "merge": "deferred"})
        return True

    # Legacy behavior: merge to main
    # ... existing merge code ...
```

### 3.6 Modified finalize()

```python
# zerg/merge.py

def finalize(self, staging_branch: str, target_branch: str) -> str:
    """Finalize merge to target branch."""
    # NEW: Use detached HEAD to avoid worktree lock
    current = self.git.current_branch()
    if current == staging_branch or current == target_branch:
        self.git.run(["checkout", "--detach"])

    # Checkout target and merge
    self.git.checkout(target_branch)
    commit = self.git.merge(staging_branch, message=f"ZERG: Complete level merge from {staging_branch}")

    # Cleanup
    self.git.delete_branch(staging_branch, force=True)

    return commit
```

---

## 4. Key Decisions

### 4.1 Decision: Config Flags for Backward Compatibility

**Context**: Need to avoid breaking existing workflows.

**Options**:
1. Hard-code new behavior (breaking change)
2. Config flags with new behavior as default
3. Config flags with old behavior as default

**Decision**: Option 2 - Config flags, new behavior default.

**Rationale**: Fixes bugs by default, but users can opt-out if needed.

### 4.2 Decision: Detached HEAD for finalize()

**Context**: Worktree lock errors when staging branch is checked out.

**Options**:
1. Dedicated merge worktree
2. Detached HEAD checkout
3. Force delete with `--force`

**Decision**: Option 2 - Detached HEAD.

**Rationale**: Simpler than worktree management, safer than force delete.

---

## 5. Implementation Plan

### 5.1 Task Summary

| Level | Tasks | Parallel | Est. Time |
|-------|-------|----------|-----------|
| Foundation (L1) | 3 | Yes | 30m |
| Core (L2) | 4 | Partial | 25m |
| Integration (L3) | 5 | Yes | 35m |
| Testing (L4) | 4 | Yes | 35m |
| Quality (L5) | 1 | No | 20m |

**Total**: 17 tasks, ~145m sequential, ~50m with 3 workers

### 5.2 File Ownership

| File | Task(s) |
|------|---------|
| `zerg/config.py` | OCF-L1-001 |
| `zerg/dependency_checker.py` | OCF-L1-002 |
| `zerg/event_emitter.py` | OCF-L1-003 |
| `zerg/state.py` | OCF-L2-001, OCF-L2-002 |
| `zerg/level_coordinator.py` | OCF-L2-003 |
| `zerg/merge.py` | OCF-L2-004, OCF-L3-002 |
| `zerg/commands/git_cmd.py` | OCF-L3-001 |
| `zerg/orchestrator.py` | OCF-L3-003 |
| `zerg/commands/status.py` | OCF-L3-004 |
| `zerg/worker_manager.py` | OCF-L3-005 |

---

## 6. Risk Assessment

| Risk | Probability | Impact | Mitigation |
|------|-------------|--------|------------|
| Breaking existing workflows | Low | High | Config flags with opt-out |
| Gate failures at ship time | Medium | Medium | Clear error messages, manual fix path |
| Event file growth | Low | Low | Cleanup at rush end |

---

## 7. Testing Strategy

### 7.1 Unit Tests

- `test_dependency_checker.py`: All dependency scenarios
- `test_event_emitter.py`: emit, subscribe, cleanup
- `test_claim_task_enforcement.py`: Level + dependency validation

### 7.2 Integration Tests

- `test_deferred_merge.py`: Main untouched during rush
- `test_claim_enforcement.py`: End-to-end level/dep enforcement

---

## 8. Parallel Execution Notes

### 8.1 Recommended Workers

- Minimum: 2 workers
- Optimal: 3 workers
- Maximum: 4 workers

### 8.2 Estimated Duration

- Single worker: ~145m
- With 3 workers: ~50m
- Speedup: ~3x

---

## 9. Approval

| Role | Status |
|------|--------|
| Architecture | APPROVED |
| Engineering | APPROVED |

Files in this skill

  • README.md977 B
  • skill.md9.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.