Files
gh-macroman5-claude-code-wo…/.claude/commands/review.md
2025-11-30 08:38:46 +08:00

35 KiB

description, argument-hint, allowed-tools, model
description argument-hint allowed-tools model
Review story and create PR with all committed tasks [STORY-ID or PATH] Read, Bash, Task claude-haiku-4-5-20251001

Story Review Command

<command_purpose> Review entire user story implementation and create single PR if all tasks are approved. </command_purpose>

Introduction

Senior Story Review Architect with expertise in user story validation, acceptance criteria verification, and pull request automation

Prerequisites

- Git repository with story start tag (e.g., `story/US-3.4-start`) - All tasks completed and tagged (e.g., `task/TASK-1.1-committed`) - GitHub CLI (`gh`) installed and authenticated - Story directory structure: `./project-management/US-STORY/US-X.Y-name/` - Valid US-story.md file with all task references - Clean working directory (no uncommitted changes)

Input Variables

<story_file>$ARGUMENTS</story_file>

<base_branch> Default: "main" Can be overridden with: --base develop </base_branch>

<draft_mode> Default: "false" Set to "true" with: --draft true </draft_mode>

Memory Graph Usage (Auto)

As you review a story, persist durable outcomes discovered in files and commit summaries:

  • Use mcp__memory__search_nodescreate_entities/add_observationscreate_relations to record owners, endpoints, repo links, and key decisions (dated). The UserPromptSubmit and PostToolUse hooks auto-hint when these signals are detected. See .claude/skills/memory-graph/.

Main Tasks

<critical_requirements> KEY REQUIREMENTS:

  1. Each completed US (user story) = 1 PR (not per task)
  2. If review FAILS → Generate detailed REPORT file
  3. Review against project standards AND enterprise guidelines
  4. Use reviewer-story agent via Task tool
  5. Parse agent JSON output programmatically
  6. APPROVED → Auto-create PR with comprehensive body
  7. CHANGES_REQUIRED → Generate US-X.Y-REVIEW-REPORT.md with fix guidance </critical_requirements>

Step 1: Load and Validate Story File

<critical_requirement> MUST validate story file exists and contains all required sections before proceeding. </critical_requirement>

<validation_tasks>

  • Check USER-STORY.md exists at provided path
  • Verify file contains required sections:
    • User Story

    • Acceptance Criteria

    • Technical Requirements

    • Tasks

  • Parse all task references (TASK-X.Y format)
  • Collect story metadata (ID, title, description) </validation_tasks>

Load Story File

# Parse input - can be story ID (US-X.Y) or full path
story_input="$ARGUMENTS"

# Check if input is story ID format (US-X.Y)
if [[ "$story_input" =~ ^US-[0-9]+\.[0-9]+$ ]]; then
    # Find story directory
    story_dir=$(find ./project-management/US-STORY -name "${story_input}-*" -type d 2>/dev/null | head -1)

    if [[ -z "$story_dir" ]]; then
        echo "❌ Error: Story ${story_input} not found"
        echo ""
        echo "Available stories:"
        ls -1d ./project-management/US-STORY/US-*/ 2>/dev/null || echo "  (no stories found)"
        echo ""
        echo "Usage: /lazy story-review US-X.Y"
        echo "   or: /lazy story-review ./project-management/US-STORY/US-X.Y-name/US-story.md"
        exit 1
    fi

    story_file="${story_dir}/US-story.md"
    tasks_dir="${story_dir}/TASKS"
    story_id=$(basename "$story_dir" | grep -oP '^US-\d+\.\d+')
else
    # Assume it's a full path to US-story.md
    story_file="$story_input"

    # Validate story file exists
    if [ ! -f "$story_file" ]; then
        echo "❌ Error: Story file not found: $story_file"
        echo ""
        echo "Usage: /lazy story-review US-X.Y"
        echo "   or: /lazy story-review ./project-management/US-STORY/US-X.Y-name/US-story.md"
        exit 1
    fi

    story_dir=$(dirname "$story_file")
    tasks_dir="${story_dir}/TASKS"
    story_id=$(basename "$story_dir" | grep -oP '^US-\d+\.\d+')
fi

# Validate tasks directory exists
if [ ! -d "$tasks_dir" ]; then
    echo "❌ Error: Tasks directory not found: $tasks_dir"
    echo "Story directory may be corrupt"
    echo "Run /lazy create-feature to regenerate"
    exit 1
fi

# Read story content
story_content=$(cat "$story_file")
story_title=$(grep -m1 "^# " "$story_file" | sed 's/^# //')

# Extract GitHub issue number from story file
story_github_issue=$(grep "GitHub Issue: #" "$story_file" | sed 's/.*#//' | head -1)

Step 2: Verify Story State with Git Tags

<critical_requirement> Use git tags to track story and task completion state. All tasks must be committed before review. </critical_requirement>

<state_verification> Story review uses git tags for state management:

Story Start Tag:

# Created by /lazy create-feature
git tag story/oauth2-start

Task Completion Tags:

# Created by /lazy task-exec after each task
git tag task/TASK-1.1-committed
git tag task/TASK-1.2-committed
git tag task/TASK-1.3-committed

Verification:

# Get all task tags
task_tags=$(git tag -l 'task/*-committed')

# Get story start tag
story_start=$(git tag -l 'story/*-start' | tail -1)

# Verify story start exists
if [ -z "$story_start" ]; then
    echo "❌ Error: No story start tag found"
    echo "Expected: story/{story-id}-start"
    exit 1
fi

</state_verification>

Collect Task Tags

<task_collection>

  • Get all task files from TASKS directory
  • Get all task tags: git tag -l 'task/*-committed'
  • Parse task IDs from tags (extract TASK-X.Y)
  • Verify all tasks are committed
  • Extract GitHub issue numbers from task files
  • Block review if any task is incomplete </task_collection>
# Collect all task files
task_files=$(ls ${tasks_dir}/TASK-*.md 2>/dev/null)

if [[ -z "$task_files" ]]; then
    echo "❌ Error: No task files found in ${tasks_dir}"
    echo "Story directory may be corrupt"
    exit 1
fi

# Collect committed and pending tasks
committed_tasks=()
pending_tasks=()
task_github_issues=()

for task_file in $task_files; do
    task_id=$(basename "$task_file" .md)  # e.g., TASK-1.1

    # Check if task is committed (git tag)
    if git tag | grep -q "task/${task_id}-committed"; then
        committed_tasks+=("$task_id")

        # Extract GitHub issue number if present
        github_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)
        if [[ -n "$github_issue" ]]; then
            task_github_issues+=("$task_id:$github_issue")
        fi
    else
        pending_tasks+=("$task_id")
    fi
done

# Verify all tasks are committed
if [[ ${#pending_tasks[@]} -gt 0 ]]; then
    echo "❌ Error: Not all tasks are committed"
    echo ""
    echo "Pending tasks:"
    for task in "${pending_tasks[@]}"; do
        echo "  - $task"
    done
    echo ""
    echo "Next steps:"
    echo "  1. Complete missing tasks: /lazy task-exec <TASK-ID>"
    echo "  2. Re-run story review: /lazy story-review ${story_id}"
    exit 1
fi

echo "✅ All ${#committed_tasks[@]} tasks are committed"

Step 3: Collect All Commits Since Story Start

<commit_collection> Get all commits between story start and current HEAD to include in PR. </commit_collection>

# Get commits since story start
commits=$(git log "$story_start"..HEAD --oneline)
commit_count=$(echo "$commits" | wc -l)

# Verify there are commits
if [ $commit_count -eq 0 ]; then
    echo "❌ Error: No commits found since story start"
    echo "Story start: $story_start"
    exit 1
fi

echo "📊 Found $commit_count commits since $story_start"

Step 4: Collect Task Implementations

<implementation_collection> For each completed task, collect:

  • Task file content from TASKS directory
  • Implementation files (from git diff)
  • Test results (if available)
  • GitHub issue links </implementation_collection>
# For each task, collect implementation details
all_tasks_summary=""
for task_file in $task_files; do
    task_id=$(basename "$task_file" .md)
    task_title=$(grep -m1 "^# " "$task_file" | sed 's/^# //')
    task_gh_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)

    # Get files changed in task commits (approximate by commit messages)
    task_commits=$(git log "$story_start"..HEAD --oneline --grep="$task_id")
    commit_count=$(echo "$task_commits" | wc -l)

    # Collect for review
    all_tasks_summary="${all_tasks_summary}\n${task_id}: ${task_title}"
    if [[ -n "$task_gh_issue" ]]; then
        all_tasks_summary="${all_tasks_summary} (GH Issue #${task_gh_issue})"
    fi
    all_tasks_summary="${all_tasks_summary}\n  Commits: ${commit_count}"
done

echo -e "📋 Task Summary:${all_tasks_summary}"

Step 5: Run Test Suite (if tests exist)

<test_execution> Run project tests if test runner is available. </test_execution>

# Detect test framework and run tests
test_results=""
if [ -f "pytest.ini" ] || [ -f "pyproject.toml" ]; then
    echo "🧪 Running pytest..."
    test_results=$(pytest --tb=short 2>&1 || true)
elif [ -f "package.json" ]; then
    if grep -q '"test"' package.json; then
        echo "🧪 Running npm test..."
        test_results=$(npm test 2>&1 || true)
    fi
fi

Step 6: Load Enterprise Standards

<standards_loading> Load project and enterprise standards for compliance checking. </standards_loading>

# Collect all applicable standards
standards_content=""

# 1. Load CLAUDE.md (project standards)
if [ -f "CLAUDE.md" ]; then
    echo "📋 Loading project standards from CLAUDE.md..."
    standards_content="${standards_content}\n## Project Standards (CLAUDE.md)\n\n"
    standards_content="${standards_content}$(cat CLAUDE.md)"
fi

# 2. Load README.md (architecture decisions)
if [ -f "README.md" ]; then
    echo "📋 Loading architecture decisions from README.md..."
    standards_content="${standards_content}\n## Architecture Decisions (README.md)\n\n"
    standards_content="${standards_content}$(cat README.md)"
fi

# 3. Load CONTRIBUTING.md (code standards)
if [ -f ".github/CONTRIBUTING.md" ]; then
    echo "📋 Loading code standards from .github/CONTRIBUTING.md..."
    standards_content="${standards_content}\n## Code Standards (CONTRIBUTING.md)\n\n"
    standards_content="${standards_content}$(cat .github/CONTRIBUTING.md)"
elif [ -f "CONTRIBUTING.md" ]; then
    echo "📋 Loading code standards from CONTRIBUTING.md..."
    standards_content="${standards_content}\n## Code Standards (CONTRIBUTING.md)\n\n"
    standards_content="${standards_content}$(cat CONTRIBUTING.md)"
fi

# 4. Load custom enterprise guidelines (if configured)
enterprise_standards_path="${LAZY_DEV_ENTERPRISE_STANDARDS:-}"
if [ -n "$enterprise_standards_path" ] && [ -f "$enterprise_standards_path" ]; then
    echo "📋 Loading enterprise standards from ${enterprise_standards_path}..."
    standards_content="${standards_content}\n## Enterprise Guidelines\n\n"
    standards_content="${standards_content}$(cat "$enterprise_standards_path")"
fi

# If no standards found, use defaults
if [ -z "$standards_content" ]; then
    echo "⚠️ No standards files found - using LAZY-DEV defaults"
    standards_content="## Default Standards\n\n- Test coverage >80%\n- Type hints required\n- Documentation required for public APIs\n- OWASP Top 10 security compliance"
fi

echo "✅ Standards loaded successfully"

Step 7: Invoke Story Review Agent

<critical_requirement> Invoke the Story Review Agent via Task tool with complete context including enterprise standards. </critical_requirement>

<agent_invocation> The agent receives all story context, implementation details, and compliance standards. Agent output format is JSON for programmatic processing. </agent_invocation>

# Prepare context for agent
echo "🤖 Invoking Story Review Agent..."

# Read full story content
story_content_full=$(cat "$story_file")

# Get all task file contents
tasks_content=""
for task_file in $task_files; do
    task_id=$(basename "$task_file" .md)
    tasks_content="${tasks_content}\n### ${task_id}\n\n$(cat "$task_file")\n"
done

# Get git diff stats
files_changed=$(git diff --stat "$story_start"..HEAD)
files_changed_list=$(git diff --name-only "$story_start"..HEAD)

# Get test coverage if available
coverage_result=""
if command -v pytest &> /dev/null; then
    coverage_result=$(pytest --cov --cov-report=term-missing 2>&1 || true)
fi

# Store agent context in temporary file for Task tool
cat > /tmp/story_review_context.md <<EOF
You are reviewing Story: ${story_id}
Story Title: ${story_title}
Story File: ${story_file}
Tasks Directory: ${tasks_dir}
Branch: $(git branch --show-current)

## Story Content
${story_content_full}

## All Tasks
${tasks_content}

## Commits (${commit_count} total)
${commits}

## Files Changed ($(echo "$files_changed_list" | wc -l) files)
${files_changed}

## Test Results
${test_results}
${coverage_result}

## Project Standards
${standards_content}

## Review Instructions
You MUST review against:
1. All acceptance criteria in the story file
2. Project standards from CLAUDE.md
3. Enterprise guidelines (if provided)
4. OWASP Top 10 security standards
5. Test coverage requirements (>80%)
6. Integration quality between all tasks

Return JSON output as specified in reviewer-story.md agent template.
EOF

echo "📄 Context prepared: /tmp/story_review_context.md"

Invoke reviewer-story agent now:

Use the Task tool to invoke .claude/agents/reviewer-story.md with the following variable substitutions:

  • story_id: ${story_id}
  • story_file: ${story_file}
  • tasks_dir: ${tasks_dir}
  • branch_name: $(git branch --show-current)
  • standards: ${standards_content}

The agent will analyze all context and return JSON output with status field of either "APPROVED" or "REQUEST_CHANGES".

Step 8: Process Review Results

<review_processing> Parse JSON output from reviewer-story agent and take appropriate action. </review_processing>

# Agent returns JSON - parse the status field
agent_status=$(echo "$agent_output" | jq -r '.status' 2>/dev/null || echo "UNKNOWN")

if [ "$agent_status" = "APPROVED" ]; then
    echo "✅ Story review APPROVED"
    echo ""

    # Extract summary from agent output
    agent_summary=$(echo "$agent_output" | jq -r '.summary' 2>/dev/null || echo "All checks passed")
    echo "📋 Summary: ${agent_summary}"
    echo ""

    # Proceed to Step 9 (PR creation)

elif [ "$agent_status" = "REQUEST_CHANGES" ]; then
    echo "❌ Story review FAILED - Changes Required"
    echo ""

    # Generate detailed review report
    report_file="${story_dir}/${story_id}-review-report.md"

    echo "📝 Generating review report: ${report_file}"

    # Extract data from agent JSON output
    agent_summary=$(echo "$agent_output" | jq -r '.summary' 2>/dev/null || echo "Review found issues")

    # Count issues by severity
    critical_count=$(echo "$agent_output" | jq '[.issues[] | select(.severity == "CRITICAL")] | length' 2>/dev/null || echo "0")
    warning_count=$(echo "$agent_output" | jq '[.issues[] | select(.severity == "WARNING")] | length' 2>/dev/null || echo "0")
    suggestion_count=$(echo "$agent_output" | jq '[.issues[] | select(.severity == "SUGGESTION")] | length' 2>/dev/null || echo "0")
    total_issues=$((critical_count + warning_count + suggestion_count))

    # Get task status summary
    tasks_passed=$(echo "$agent_output" | jq '[.tasks_status[] | select(.status == "passed")] | length' 2>/dev/null || echo "0")
    tasks_total=$(echo "$agent_output" | jq '.tasks_status | length' 2>/dev/null || echo "0")

    # Generate comprehensive report
    cat > "$report_file" <<REPORT_EOF
# Story Review Report: ${story_id}

**Status**: ❌ FAILED
**Reviewed**: $(date +"%Y-%m-%d %H:%M")
**Tasks**: ${tasks_passed}/${tasks_total} passed

## Summary
${total_issues} issues found preventing PR creation.

${agent_summary}

## Issues Found

$(echo "$agent_output" | jq -r '
if .issues and (.issues | length > 0) then
    .issues | to_entries | map(
        "### " + ((.key + 1) | tostring) + ". " +
        (if .value.type then (.value.type | gsub("_"; " ") | ascii_upcase) else "Issue" end) +
        " (" + (.value.file // "N/A") +
        (if .value.line then ":" + (.value.line | tostring) else "" end) + ")\n" +
        "- **Type**: " + (.value.type // "unknown") + "\n" +
        "- **File**: " + (.value.file // "N/A") +
        (if .value.line then ":" + (.value.line | tostring) else "" end) + "\n" +
        "- **Issue**: " + .value.description + "\n" +
        "- **Fix**: " + .value.fix + "\n"
    ) | join("\n")
else
    "No specific issues documented."
end
')

## Tasks Status
$(echo "$agent_output" | jq -r '
if .tasks_status and (.tasks_status | length > 0) then
    .tasks_status | map(
        "- " + .task_id + ": " +
        (if .status == "passed" then "✅ Passed"
         elif .status == "failed" then "❌ Failed (" + (.issues_count | tostring) + " issues)"
         elif .status == "warning" then "⚠️ Warning (" + (.issues_count | tostring) + " issues)"
         else "⚠️ " + .status
         end)
    ) | join("\n")
else
    "- No task status available"
end
')

## Next Steps
Run: \`/lazy fix ${report_file}\`

Or manually fix and re-run: \`/lazy review @${story_file}\`
REPORT_EOF

    echo "✅ Review report generated: ${report_file}"
    echo ""
    echo "Found:"
    echo "  - ${critical_count} CRITICAL issues"
    echo "  - ${warning_count} WARNING issues"
    echo "  - ${suggestion_count} SUGGESTIONS"
    echo ""
    echo "Next steps:"
    echo "  1. Review report: cat ${report_file}"
    echo "  2. Fix issues: /lazy fix ${report_file}"
    echo "  3. Re-run review: /lazy review ${story_id}"
    echo ""

    # Exit with status 1 to indicate failure
    exit 1

else
    echo "❌ Error: Unknown review status from agent: ${agent_status}"
    echo "Agent output:"
    echo "$agent_output"
    exit 1
fi

Step 9: Create Pull Request (If APPROVED)

<pr_creation> If review is approved, create a single PR containing all story commits with comprehensive summary. </pr_creation>

<pr_requirements>

  • One PR per user story (not per task)
  • Includes all commits since story start tag
  • References all task GitHub issues
  • Includes test results and quality metrics
  • Auto-closes related GitHub issues </pr_requirements>

Prepare PR Body

# Generate comprehensive PR body
echo "📝 Generating PR body..."

# Extract test coverage percentage
test_coverage=$(echo "$coverage_result" | grep "^TOTAL" | awk '{print $NF}' || echo "N/A")

# Get acceptance criteria status
acceptance_criteria_list=$(cat "$story_file" | sed -n '/## Acceptance Criteria/,/##/p' | grep -E "^-.*" | sed 's/^- /✓ /')

# Extract agent summary
pr_summary=$(echo "$agent_output" | jq -r '.summary' 2>/dev/null || echo "Story implementation completed and reviewed")

cat > pr_body.md <<'PR_BODY'
# [FEATURE] ${story_title}

**Story ID**: ${story_id}
**Directory**: `${story_dir}`
$(if [[ -n "$story_github_issue" ]]; then echo "**GitHub Issue**: Closes #${story_github_issue}"; fi)

---

## Summary

${pr_summary}

---

## User Story

$(cat "${story_file}" | sed -n '/## User Story/,/##/p' | tail -n +2 | head -n -1)

---

## Acceptance Criteria

$(echo "$acceptance_criteria_list" | sed 's/^/✓ /')

---

## Tasks Completed

$(for task_file in ${tasks_dir}/TASK-*.md; do
    task_id=$(basename "$task_file" .md)
    task_title=$(grep "^# " "$task_file" | head -1 | sed 's/^# //')
    task_gh_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)

    if [[ -n "$task_gh_issue" ]]; then
        echo "✓ [${task_id}] ${task_title} - Closes #${task_gh_issue}"
    else
        echo "✓ [${task_id}] ${task_title}"
    fi
done)

---

## Commits

\`\`\`
$(git log --oneline ${story_start}..HEAD)
\`\`\`

**Total Commits**: ${commit_count}

---

## Quality Metrics

| Metric | Value |
|--------|-------|
| Files Changed | $(git diff --name-only "$story_start"..HEAD | wc -l) |
| Lines Added | $(git diff --stat "$story_start"..HEAD | tail -1 | grep -oP '\d+(?= insertion)' || echo "0") |
| Lines Removed | $(git diff --stat "$story_start"..HEAD | tail -1 | grep -oP '\d+(?= deletion)' || echo "0") |
| Test Coverage | ${test_coverage} |
| Tests Passing | $(echo "$test_results" | grep -oP '\d+(?= passed)' || echo "All") |

---

## Testing

\`\`\`
${test_results:-No tests run}
\`\`\`

$(if [[ -n "$coverage_result" ]]; then
echo "### Coverage Report"
echo "\`\`\`"
echo "$coverage_result" | head -20
echo "\`\`\`"
fi)

---

## Compliance & Quality Checks

### Story Review
✅ **APPROVED** by reviewer-story agent

### Project Standards
✅ Compliant with CLAUDE.md requirements
✅ Follows project architecture patterns

### Enterprise Guidelines
$(if [[ -n "$enterprise_standards_path" ]]; then
    echo "✅ Compliant with enterprise standards: \`${enterprise_standards_path}\`"
else
    echo "✅ Compliant with LAZY-DEV framework defaults"
fi)

### Security
✅ OWASP Top 10 compliance verified
✅ No security vulnerabilities detected
✅ Input validation implemented
✅ Authentication/authorization reviewed

### Code Quality
✅ Format: PASS (Black/Ruff)
✅ Lint: PASS (Ruff)
✅ Type: PASS (Mypy)
✅ Tests: PASS (Pytest)

### Documentation
✅ Public APIs documented
✅ README updated (if applicable)
✅ Inline comments for complex logic

---

## Integration Status

✅ All tasks integrate cohesively
✅ No conflicts between task implementations
✅ Data flows correctly between components
✅ No breaking changes to existing functionality

---

## Reviewer Notes

**Review Method**: LAZY-DEV-FRAMEWORK automated story review
**Review Agent**: `.claude/agents/reviewer-story.md`
**Review Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")

**Summary**: ${pr_summary}

**Strengths**:
$(echo "$agent_output" | jq -r '.strengths // [] | if length > 0 then map("- " + .) | join("\n") else "- Comprehensive implementation\n- Strong test coverage\n- Clean code quality" end' 2>/dev/null || echo "- High-quality implementation")

---

## Related Issues

$(if [[ -n "$story_github_issue" ]]; then
    echo "- Story: #${story_github_issue}"
fi)
$(for task_file in ${tasks_dir}/TASK-*.md; do
    task_gh_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)
    if [[ -n "$task_gh_issue" ]]; then
        task_id=$(basename "$task_file" .md)
        echo "- Task ${task_id}: #${task_gh_issue}"
    fi
done)

---

🤖 Generated with [Claude Code](https://claude.com/claude-code) LAZY-DEV-FRAMEWORK

**Story**: ${story_id}
**Directory**: ${story_dir}
**Framework**: LAZY-DEV v1.0.0-alpha
PR_BODY

# Expand variables in PR body
eval "cat <<'EXPAND_PR_BODY' > pr_body_final.md
$(cat pr_body.md)
EXPAND_PR_BODY"

echo "✅ PR body generated: pr_body_final.md"

Create PR with gh CLI

# Determine if draft mode
draft_flag=""
if [ "$draft_mode" = "true" ]; then
    draft_flag="--draft"
fi

# Create PR
echo "📦 Creating pull request..."
pr_url=$(gh pr create \
  --title "[FEATURE] $story_title" \
  --body-file pr_body_final.md \
  --base "$base_branch" \
  --label "story,automated,reviewed,story:$story_id" \
  $draft_flag)

# Verify PR creation
if [ $? -eq 0 ]; then
    # Get PR number
    pr_number=$(gh pr list --head "$(git branch --show-current)" --json number --jq '.[0].number')

    echo "✅ PR Created: $pr_url"
    echo ""
    echo "📁 Story: ${story_id}"
    echo "   Directory: ${story_dir}"
    echo ""
    echo "📦 PR Details:"
    echo "   Number: #${pr_number}"
    echo "   Title: [STORY] $story_title"
    echo "   Base: $base_branch"
    echo "   Commits: $commit_count"
    echo ""

    # Close GitHub issues
    echo "🔗 Closing GitHub Issues:"

    # Close main story issue
    if [[ -n "$story_github_issue" ]]; then
        gh issue close $story_github_issue --reason completed \
            --comment "Completed in PR #${pr_number}" 2>/dev/null
        if [ $? -eq 0 ]; then
            echo "   ✅ #${story_github_issue} - [STORY] ${story_title}"
        fi
    fi

    # Close all task issues
    for task_file in ${tasks_dir}/TASK-*.md; do
        task_id=$(basename "$task_file" .md)
        task_title=$(grep "^# " "$task_file" | head -1 | sed 's/^# //')
        task_gh_issue=$(grep "GitHub Issue: #" "$task_file" | sed 's/.*#//' | head -1)

        if [[ -n "$task_gh_issue" ]]; then
            gh issue close $task_gh_issue --reason completed \
                --comment "Completed in PR #${pr_number}" 2>/dev/null
            if [ $? -eq 0 ]; then
                echo "   ✅ #${task_gh_issue} - [${task_id}] ${task_title}"
            fi
        fi
    done

    echo ""
    echo "✅ All related issues closed"
    echo "✅ Ready for merge"
else
    echo "❌ Error: Failed to create PR"
    echo "Check: gh auth status"
    exit 1
fi

Parallelization During Review

While the story review is running or after it completes, you can run other commands in parallel if they are independent.

Commands That Can Run in Parallel

During Review (While Waiting for Agent):

# 1. Cleanup unused code (runs on current branch)
/lazy cleanup --scope feature/US-X.Y

# 2. Generate documentation for the story
/lazy documentation --scope US-X.Y

# 3. Check memory graph for this story's entities
/lazy memory-check US-X.Y

After Review Approval (Before PR Merge):

# 1. Start work on next independent story
/lazy create-feature "Next feature brief"

# 2. Update project documentation
/lazy documentation --scope project

# 3. Run refactoring on completed work
/lazy refactor --scope US-X.Y

Commands That CANNOT Run in Parallel

Blocked Until Review Completes:

# ❌ Cannot run another story review simultaneously
/lazy story-review US-Y.Z  # Wait for current review to finish

# ❌ Cannot re-execute tasks in the story being reviewed
/lazy task-exec TASK-X.Y  # Wait until review fails or make changes after PR

# ❌ Cannot fix review issues until report is generated
/lazy story-fix-review US-X.Y-REVIEW-REPORT.md  # Only after review fails

Optimal Parallelization:

# Terminal 1: Run story review
/lazy story-review US-3.4

# Terminal 2: While review is running, cleanup and document in parallel
/lazy cleanup --scope feature/US-3.4
/lazy documentation --scope US-3.4

# If review APPROVED:
# - PR is created automatically
# - GitHub issues are closed
# - Ready to start next story

# If review FAILED:
# - Fix issues: /lazy story-fix-review US-3.4-REVIEW-REPORT.md
# - Re-run: /lazy story-review US-3.4

Integration with Other Commands

Workflow Integration

Complete Story Lifecycle:

1. /lazy create-feature "Brief"
   ↓
   Creates: US-X.Y-name/US-story.md
   Creates: TASKS/TASK-*.md
   Creates: GitHub issues
   Sets tag: story/US-X.Y-start

2. /lazy task-exec TASK-1.1
   /lazy task-exec TASK-1.2
   /lazy task-exec TASK-1.3
   ↓
   Each sets tag: task/TASK-X.Y-committed
   Each implements and tests feature

3. /lazy story-review US-X.Y  ← THIS COMMAND
   ↓
   Loads: All tasks, commits, standards
   Invokes: reviewer-story agent

   If APPROVED:
     ↓
     Creates: PR with full context
     Closes: All GitHub issues

   If CHANGES_REQUIRED:
     ↓
     Creates: US-X.Y-REVIEW-REPORT.md
     Outputs: Fix guidance

4. If changes needed:
   /lazy story-fix-review US-X.Y-REVIEW-REPORT.md
   ↓
   Routes issues to appropriate agents
   Fixes critical/warning issues

   Then re-run:
   /lazy story-review US-X.Y

5. After PR merge:
   /lazy cleanup --scope US-X.Y
   /lazy documentation --scope US-X.Y

Command Dependencies

story-review depends on:

  • /lazy create-feature (creates story structure)
  • /lazy task-exec (completes all tasks)
  • Git tags: story/*-start, task/*-committed
  • GitHub CLI: gh authenticated

Commands that depend on story-review:

  • /lazy story-fix-review (processes review report)
  • Subsequent /lazy story-review runs (after fixes)

Independent parallel commands:

  • /lazy cleanup (code cleanup)
  • /lazy documentation (docs generation)
  • /lazy memory-check (graph queries)
  • /lazy create-feature (new independent story)

Error Handling & Recovery

Error: Story file not found

❌ Error: Story US-3.4 not found

Available stories:
  ./project-management/US-STORY/US-1.1-user-authentication/
  ./project-management/US-STORY/US-2.3-payment-integration/

Usage: /lazy story-review US-X.Y
   or: /lazy story-review ./project-management/US-STORY/US-X.Y-name/US-story.md

Recovery:
  1. Check story ID: ls ./project-management/US-STORY/
  2. Use correct story ID: /lazy story-review US-1.1
  3. Or use full path to US-story.md

Error: Task tags missing

❌ Error: Not all tasks are committed

Pending tasks:
  - TASK-1.2
  - TASK-1.3

Next steps:
  1. Run git tag -l 'task/*' to see completed tasks
  2. Execute missing tasks: /lazy task-exec TASK-1.2
  3. Retry: /lazy story-review US-3.4

Error: Story start tag missing

❌ Error: No story start tag found
Expected: story/US-X.Y-start

Recovery:
  1. Check if create-feature was run: git tag -l 'story/*'
  2. Create tag manually: git tag story/US-3.4-start $(git log --reverse --oneline | head -1 | cut -d' ' -f1)
  3. Retry: /lazy story-review US-3.4

Error: No commits found

❌ Error: No commits found since story start
Story start: story/oauth2-start

Recovery:
  1. Verify story tag: git log story/oauth2-start
  2. Check current branch: git branch --show-current
  3. Ensure tasks were committed (not just completed)

Error: Review changes needed

⚠️ Story review needs changes:

Critical Issues:
- TASK-1.3 validation: Missing edge case for declined cards
  Location: src/payments/validator.py:45
  Impact: Invalid cards may be processed

Next steps:
  1. Fix validation in TASK-1.3
  2. Re-run: /lazy task-exec TASK-1.3
  3. Re-review: /lazy story-review US-3.4

Error: Tasks directory not found

❌ Error: Tasks directory not found: ./project-management/US-STORY/US-3.4-oauth2/TASKS
Story directory may be corrupt
Run /lazy create-feature to regenerate

Recovery:
  1. Verify story structure: ls -la ./project-management/US-STORY/US-3.4-*/
  2. Check if TASKS directory exists
  3. If missing, regenerate with /lazy create-feature

Error: GitHub issue numbers missing

⚠️ Warning: Some task files don't have GitHub issue numbers
This may happen with older stories

Recovery:
  1. Manually add GitHub issues
  2. Or regenerate story with /lazy create-feature (includes gh issue creation)
  3. Issues without numbers won't be auto-closed

Error: gh CLI not found

❌ Error: gh command not found

Recovery:
  1. Install GitHub CLI: https://cli.github.com
  2. Authenticate: gh auth login
  3. Verify: gh auth status
  4. Retry: /lazy story-review US-3.4

Error: gh auth failed

❌ Error: Not authenticated to GitHub

Recovery:
  1. Run: gh auth login
  2. Follow prompts to authorize
  3. Verify: gh auth status
  4. Retry: /lazy story-review US-3.4

Error: Base branch doesn't exist

❌ Error: Base branch 'develop' not found

Recovery:
  1. Check branches: git branch -a
  2. Use correct base: /lazy story-review US-3.4 --base main
  3. Or create branch: git branch develop

Success Criteria

Story review is successful when:

  • Story file is valid with all required sections
  • Story directory structure is correct: ./project-management/US-STORY/US-X.Y-name/
  • All task files found in TASKS directory
  • All task tags present: git tag -l 'task/TASK-*-committed'
  • All commits collected since story start
  • Review agent approved entire implementation
  • All acceptance criteria validated
  • Architecture, security, and testing validated
  • PR created with title [STORY] {story-name}
  • PR body contains full story + all tasks + test results + GitHub issues
  • All commits included in PR history
  • PR is on correct base branch
  • All related GitHub issues closed (story + tasks)

Example Usage

Basic story review with story ID

/lazy story-review US-3.4

Review with full path (backward compatible)

/lazy story-review ./project-management/US-STORY/US-3.4-oauth2-authentication/US-story.md

Review on specific base branch

/lazy story-review US-3.4 --base develop

Create as draft PR

/lazy story-review US-3.4 --draft true

Verify story state before review

# List available stories
ls -1d ./project-management/US-STORY/US-*/

# Check what tasks are completed
git tag -l 'task/*'

# Check story commits
git log story/US-3.4-start..HEAD --oneline

# Then run review
/lazy story-review US-3.4

Session Logging

All activities logged to logs/<session-id>/story-review.json:

{
  "story_file": "USER-STORY.md",
  "story_id": "oauth2-auth",
  "base_branch": "main",
  "draft_mode": false,
  "timestamp": "2025-10-25T15:45:00Z",
  "stages": [
    {
      "stage": "load_story",
      "status": "completed",
      "story_title": "Build OAuth2 Authentication"
    },
    {
      "stage": "verify_tags",
      "status": "completed",
      "all_present": true,
      "task_count": 4
    },
    {
      "stage": "collect_commits",
      "status": "completed",
      "commit_count": 7
    },
    {
      "stage": "collect_implementations",
      "status": "completed",
      "files_changed": 15
    },
    {
      "stage": "run_tests",
      "status": "completed",
      "test_result": "passed"
    },
    {
      "stage": "review",
      "status": "approved",
      "agent": "story-review-agent"
    },
    {
      "stage": "pr_creation",
      "status": "completed",
      "pr_url": "https://github.com/org/repo/pull/42",
      "pr_number": 42
    }
  ],
  "result": {
    "approved": true,
    "pr_url": "https://github.com/org/repo/pull/42",
    "tasks_included": ["TASK-1.1", "TASK-1.2", "TASK-1.3", "TASK-1.4"],
    "commits_included": 7,
    "files_changed": 15
  }
}

Integration with Other Commands

After /lazy create-feature

# create-feature creates story directory and sets start tag
/lazy create-feature "Add OAuth2 authentication"
# Creates: ./project-management/US-STORY/US-3.4-oauth2-authentication/
#          US-story.md, TASKS/TASK-*.md files
#          GitHub issues for story and tasks
# Sets tag: story/US-3.4-start

# Execute all tasks
/lazy task-exec TASK-1.1
/lazy task-exec TASK-1.2
/lazy task-exec TASK-1.3

# Review and create PR (using story ID)
/lazy story-review US-3.4

After /lazy task-exec

# Each task-exec sets a completion tag
/lazy task-exec TASK-1.1
# Sets tag: task/TASK-1.1-committed

# story-review uses these tags to verify completion
/lazy story-review US-3.4

Workflow Summary

/lazy create-feature
      ↓
  Creates ./project-management/US-STORY/US-X.Y-name/
  story/US-X.Y-start tag created
  GitHub issues created
      ↓
/lazy task-exec TASK-1.1 → task/TASK-1.1-committed
/lazy task-exec TASK-1.2 → task/TASK-1.2-committed
/lazy task-exec TASK-1.3 → task/TASK-1.3-committed
      ↓
/lazy story-review US-X.Y
      ↓
  Verify all tags present
      ↓
  Collect all commits
      ↓
  Review Agent validation
      ↓
  Create PR (if approved)
      ↓
  Close GitHub issues (story + tasks)

Notes

  • Story review is read-only - no file modifications during review
  • All validation happens through git tags (immutable markers)
  • Review agent has complete context (story + tasks + implementations + tests)
  • PR creation is automatic only if review is approved
  • Draft mode allows additional manual review before merge
  • Story state tracking enables iterative review (fix tasks, re-review)
  • Accepts both story ID (US-X.Y) and full path for backward compatibility
  • Automatically closes all related GitHub issues (story + all tasks)
  • Works with new directory structure: ./project-management/US-STORY/US-X.Y-name/
  • Task files are individual TASK-*.md files in TASKS subdirectory
  • GitHub issue numbers extracted from story and task files