Skip to content

feat: structured conflict resolution with hold mechanism#39

Merged
justinjdev merged 5 commits intomainfrom
worktree-fellowship/structured-conflict-resolution
Mar 8, 2026
Merged

feat: structured conflict resolution with hold mechanism#39
justinjdev merged 5 commits intomainfrom
worktree-fellowship/structured-conflict-resolution

Conversation

@justinjdev
Copy link
Copy Markdown
Owner

@justinjdev justinjdev commented Mar 8, 2026

Summary

  • Add fellowship hold --dir <worktree> [--reason "msg"] and fellowship unhold --dir <worktree> CLI commands that structurally block a quest's tools via the gate-guard hook
  • Extend GateGuard to check held state before gate_pending — blocks Edit/Write/Bash/Agent/Skill/NotebookEdit when held: true
  • Add conflict resolution protocol to the fellowship skill (Gandalf's playbook): Pause → Assess → Resolve (sequence/partition/merge) → Resume
  • Add quest_held and quest_unheld herald tiding types for activity tracking

Test plan

  • 3 new unit tests in guard_test.go (blocks when held, includes reason, held priority over gate_pending)
  • All existing tests pass (go test ./...)
  • Build succeeds
  • CLI smoke test: fellowship hold and fellowship unhold show correct usage

Closes #14

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added hold/unhold CLI commands to pause/resume quests; status now shows held state and optional reason; actions are blocked while held and events are announced/logged.
  • Documentation

    • Added conflict-resolution, lead-behavior, progress-tracking, and spawn-prompts guides; updated onboarding/state examples and condensed fellowship skill docs.
  • Tests

    • Added tests verifying held-state blocking and held-reason messaging.

Add CLI hold/unhold commands that structurally block a quest's tools
via the gate-guard hook when held. Gandalf uses this to pause quests
during file conflict resolution detected by Palantir.

Closes #14

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 8, 2026

Warning

Rate limit exceeded

@justinjdev has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 10 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1fcd4a89-c7b0-4ec5-939b-4d6cdfefb46c

📥 Commits

Reviewing files that changed from the base of the PR and between b156f7d and 1c6285f.

📒 Files selected for processing (4)
  • cli/internal/dashboard/fellowship.go
  • cli/internal/filelock/filelock_unix.go
  • cli/internal/filelock/filelock_windows.go
  • cli/internal/state/state.go
📝 Walkthrough

Walkthrough

Adds a persistent hold/unhold mechanism: CLI commands, persisted state fields with file-locking, Herald events, gate-guard short‑circuit that blocks modification tools while held, unit tests for guard behavior, and documentation describing a Conflict Resolution Protocol.

Changes

Cohort / File(s) Summary
CLI Commands & Usage
cli/cmd/fellowship/main.go
Added hold and unhold subcommands, usage text updates, implementations that mutate held state under lock, emit Herald tidings, and print confirmations.
State Management & Concurrency
cli/internal/state/state.go
Added Held bool and HeldReason *string fields (json tags), exported ErrNoSave, and new WithLock(path string, fn func(s *State) error) error implementing exclusive file locking for load→mutate→save.
Herald Events
cli/internal/herald/herald.go
Added QuestHeld and QuestUnheld TidingType constants.
Hook Enforcement & Tests
cli/internal/hooks/guard.go, cli/internal/hooks/guard_test.go
GateGuard now short‑circuits when Held is true (blocks tools, includes optional reason) and takes precedence over pending checks; added tests covering held behavior and message content.
Docs — Fellowship Skill
plugin/skills/fellowship/SKILL.md, plugin/skills/fellowship/resources/*.md
Rewrote/condensed SKILL.md and added conflict-resolution, lead-behavior, progress-tracking, and spawn-prompts documentation describing the Conflict Resolution Protocol and hold workflow.
Docs — Quest Skill
plugin/skills/quest/SKILL.md
Phase 0 example state extended to include held and held_reason fields.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as "Fellowship CLI"
    participant State as "State File"
    participant Herald as "Herald Log"
    participant Hook as "Gate Guard Hook"
    participant Tool as "Edit/Write/Bash Tool"

    User->>CLI: fellowship hold --dir <worktree> --reason "conflict"
    CLI->>State: WithLock: load → set Held=true, HeldReason="conflict" → save
    CLI->>Herald: emit QuestHeld
    CLI-->>User: print held confirmation

    User->>Tool: attempt modification
    Tool->>Hook: invoke GateGuard
    Hook->>State: read Held/HeldReason
    State-->>Hook: return Held=true, reason
    Hook-->>Tool: block (exit 2) with message
    Tool-->>User: operation blocked

    User->>CLI: fellowship unhold --dir <worktree>
    CLI->>State: WithLock: load → clear Held/HeldReason → save
    CLI->>Herald: emit QuestUnheld
    CLI-->>User: print unhold confirmation

    User->>Tool: retry modification
    Tool->>Hook: invoke GateGuard
    Hook->>State: read Held
    State-->>Hook: return Held=false
    Hook-->>Tool: allow operation
    Tool-->>User: success
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: introducing a structured conflict resolution protocol backed by a hold mechanism.
Linked Issues check ✅ Passed The PR implements all key coding objectives from issue #14: hold/unhold CLI commands, state struct extensions (Held, HeldReason), WithLock atomic mutations, GateGuard hook enforcement with held-state checks, Herald event types (QuestHeld/QuestUnheld), comprehensive unit tests, and documentation of the conflict-resolution protocol.
Out of Scope Changes check ✅ Passed All changes align with issue #14 scope: CLI commands, state mutations, hook enforcement, Herald events, tests, and documentation of the conflict-resolution protocol. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch worktree-fellowship/structured-conflict-resolution

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/cmd/fellowship/main.go`:
- Around line 417-433: The hold/unhold code is doing an unsafe read-modify-write
on quest-state.json using state.Load → mutate s.Held/s.HeldReason → state.Save
which can race with other writers; change these paths to use the shared
atomic/locking helper in the state package (instead of open-coding Load/Save) so
updates are serialized — e.g., call the state package’s atomic update function
(e.g., state.Update/Mutate/WithLock or implement one) and perform the
Held/HeldReason mutation inside that callback, returning any save error from the
helper; apply the same change to the other block (lines corresponding to the
unhold path) so both hold and unhold use the lock/atomic update helper rather
than direct state.Load/state.Save.

In `@plugin/skills/fellowship/SKILL.md`:
- Around line 385-391: Update the hold semantics paragraph to explicitly state
that NotebookEdit is blocked by the gate-guard hook: when a quest is held (via
the fellowship hold command) the guard prevents Edit/Write/Bash/Agent/Skill
tools and also NotebookEdit from running; modify the paused-tools list (the
sentence referencing paused tools) to include the NotebookEdit symbol so the
documentation accurately reflects the guard behavior and that the quest cannot
resume notebook edits until unheld.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cfd0f45d-00a9-4122-9243-d76e6344e276

📥 Commits

Reviewing files that changed from the base of the PR and between 5f4f928 and 1944e16.

📒 Files selected for processing (7)
  • cli/cmd/fellowship/main.go
  • cli/internal/herald/herald.go
  • cli/internal/hooks/guard.go
  • cli/internal/hooks/guard_test.go
  • cli/internal/state/state.go
  • plugin/skills/fellowship/SKILL.md
  • plugin/skills/quest/SKILL.md

Comment thread cli/cmd/fellowship/main.go Outdated
Comment thread plugin/skills/fellowship/SKILL.md Outdated
Comment on lines +385 to +391
Hold the later quest immediately to prevent further divergence:

```bash
fellowship hold --dir <later-quest-worktree> --reason "file conflict with <other-quest>: <file_path>"
```

This structurally blocks the held quest's Edit/Write/Bash/Agent/Skill tools via the gate-guard hook. The quest cannot proceed until unheld.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Document NotebookEdit as blocked during a hold.

Line 391 lists the paused tools, but the current guard behavior also blocks notebook edits while held. This section currently understates the hold semantics and can mislead teammates about what remains allowed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/skills/fellowship/SKILL.md` around lines 385 - 391, Update the hold
semantics paragraph to explicitly state that NotebookEdit is blocked by the
gate-guard hook: when a quest is held (via the fellowship hold command) the
guard prevents Edit/Write/Bash/Agent/Skill tools and also NotebookEdit from
running; modify the paused-tools list (the sentence referencing paused tools) to
include the NotebookEdit symbol so the documentation accurately reflects the
guard behavior and that the quest cannot resume notebook edits until unheld.

Extract spawn prompts, lead behavior, progress tracking, and conflict
resolution into resources/ for progressive disclosure. Reduces SKILL.md
from 613 to 197 lines — loaded into Gandalf's context at startup,
resources loaded on-demand only when needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ef9dda9b-392b-46c3-b832-862d09a32417

📥 Commits

Reviewing files that changed from the base of the PR and between 1944e16 and 7e8a6f0.

📒 Files selected for processing (5)
  • plugin/skills/fellowship/SKILL.md
  • plugin/skills/fellowship/resources/conflict-resolution.md
  • plugin/skills/fellowship/resources/lead-behavior.md
  • plugin/skills/fellowship/resources/progress-tracking.md
  • plugin/skills/fellowship/resources/spawn-prompts.md
✅ Files skipped from review due to trivial changes (1)
  • plugin/skills/fellowship/resources/conflict-resolution.md

Comment thread plugin/skills/fellowship/resources/lead-behavior.md
Comment on lines +10 to +21
When the user asks for "status" or Gandalf proactively reports progress:

```
## Fellowship Status

| Task | Type | Phase | Progress |
|------|------|-------|----------|
| quest-auth-bug | Quest | Implement | ████░░ 3/5 |
| quest-rate-limit | Quest | Research | █░░░░░ 1/5 |
| scout-auth-analysis | Scout | Validating | ██░░ 2/3 |

**Quests:** 2 active | **Scouts:** 1 active | **Completed:** 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Surface held quests in the status format.

This report shape has no way to show that a quest is paused by hold, so a held quest will still read like a normal active quest. Please add a visible held indicator here (for example in Phase, a separate Status column, or alongside the progress cell) and include the hold reason when present.

Comment thread plugin/skills/fellowship/resources/spawn-prompts.md
Comment thread plugin/skills/fellowship/SKILL.md Outdated
Add state.WithLock for atomic load→mutate→save on quest-state.json,
matching the WithStateLock pattern used for fellowship-state.json.
Migrate gate approve, gate reject, hold, and unhold to use it.

Also add NotebookEdit to the list of blocked tools in conflict
resolution docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d84b87ce-d829-4f98-a67d-6230c82c0c81

📥 Commits

Reviewing files that changed from the base of the PR and between 7e8a6f0 and 7e1addb.

📒 Files selected for processing (3)
  • cli/cmd/fellowship/main.go
  • cli/internal/state/state.go
  • plugin/skills/fellowship/resources/conflict-resolution.md

Comment thread cli/cmd/fellowship/main.go Outdated
Comment thread cli/cmd/fellowship/main.go
Comment thread cli/internal/state/state.go Outdated
justinjdev and others added 2 commits March 8, 2026 11:50
- Add file locking to hook mutations (gate-submit, gate-prereq,
  metadata-track) via state.WithLock with ErrNoSave sentinel
- Add hold/unhold as proactive commands in lead-behavior docs
- Surface held quests in progress tracking status format
- Explain hold mechanism in quest runner spawn prompt
- Name concrete hold/unhold commands in SKILL.md conflict section
- Fix usage text: list specific blocked tools instead of "all tools"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract file locking into internal/filelock package with build tags:
unix uses syscall.Flock, windows uses LockFileEx/UnlockFileEx via
kernel32.dll. Fixes compilation on Windows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
cli/internal/state/state.go (2)

106-111: Use errors.Is for sentinel error comparison.

Direct equality (err == ErrNoSave) can fail if the error is wrapped. Use errors.Is(err, ErrNoSave) for robust sentinel detection.

♻️ Proposed fix
+import "errors"
 	if err := fn(s); err != nil {
-		if err == ErrNoSave {
+		if errors.Is(err, ErrNoSave) {
 			return nil
 		}
 		return err
 	}

96-99: Silently ignoring unlock errors may hide issues.

The deferred syscall.Flock(..., LOCK_UN) discards its error. While unlock failures are rare, logging or returning them could help diagnose file system issues.

plugin/skills/fellowship/SKILL.md (1)

145-149: Consider documenting blocked tools inline.

The hold/unhold commands are now explicitly named (addressing prior feedback), but the blocked tools (Edit/Write/Bash/Agent/Skill/NotebookEdit) are only documented in spawn-prompts.md. Consider adding a brief note here that the hold mechanism blocks the same tools as gate-pending, or list them explicitly for completeness.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a593d91b-6512-4c94-9418-b3ad5adda979

📥 Commits

Reviewing files that changed from the base of the PR and between 7e1addb and b156f7d.

📒 Files selected for processing (6)
  • cli/cmd/fellowship/main.go
  • cli/internal/state/state.go
  • plugin/skills/fellowship/SKILL.md
  • plugin/skills/fellowship/resources/lead-behavior.md
  • plugin/skills/fellowship/resources/progress-tracking.md
  • plugin/skills/fellowship/resources/spawn-prompts.md
✅ Files skipped from review due to trivial changes (1)
  • plugin/skills/fellowship/resources/progress-tracking.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugin/skills/fellowship/resources/lead-behavior.md

@justinjdev justinjdev merged commit b79a420 into main Mar 8, 2026
2 checks passed
@justinjdev justinjdev deleted the worktree-fellowship/structured-conflict-resolution branch March 8, 2026 16:57
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.

feat: structured conflict resolution protocol with hold mechanism

1 participant