---
name: efcore-rebase-snapshot
description: EF Core snapshot rebaser - resync ModelSnapshot with develop
color: yellow
model: sonnet
tools: Bash, Glob, Read, Edit
---

# EF Core Rebase-Snapshot Agent

Rebases ModelSnapshot on develop to resolve conflicts.

## WSL Preflight (MANDATORY - run BEFORE any git command)

```bash
# Repair worktree .git file if Windows path detected under WSL
if [ -f .git ] && grep -q '^gitdir: [A-Za-z]:' .git 2>/dev/null && grep -qi microsoft /proc/version 2>/dev/null; then
  p=$(sed 's/^gitdir: //' .git | tr -d '\r\n'); d=$(echo "${p:0:1}" | tr A-Z a-z); r="${p:2}"; r="${r//\\//}"
  printf 'gitdir: %s\n' "$(realpath -m --relative-to="$(pwd)" "/mnt/$d$r")" > .git
  echo "Worktree .git path repaired for WSL"
fi
```

## SQL Objects

SQL objects (TVFs, views, SPs) are applied **at startup** via `SqlObjectHelper.ApplyAllAsync()` — never inject in migrations.

## Workflow

1. **Backup** all migrations
2. **Reset** ModelSnapshot to develop
3. **Delete** branch migrations
4. **Regenerate** consolidated migration
5. **Validate** build OK

## Shared Functions

> **Reference:** See `references/shared-init-functions.md` for `ensure_dotnet_ef()`, `detect_efcore_project()`, `detect_dbcontext()`, `determine_base_branch()`.

## Key Commands

> **IMPORTANT:** Steps 1-2 MUST run in a single Bash call to preserve shell variables. Step 2b (confirm) is a separate interactive call. Step 3 requires variables from steps 1-2.

### Step 1: Initialize

```bash
# Determine parent branch
CURRENT_BRANCH=$(git branch --show-current)
case "$CURRENT_BRANCH" in
  feature/*) BASE_BRANCH="develop"; BRANCH_TYPE="feature" ;;
  release/*) BASE_BRANCH="main";    BRANCH_TYPE="release" ;;
  hotfix/*)  BASE_BRANCH="main";    BRANCH_TYPE="hotfix" ;;
  develop)   BASE_BRANCH="main";    BRANCH_TYPE="develop" ;;
  main|master) echo "BLOCKED: Cannot rebase on main/master"; exit 1 ;;
  *)         BASE_BRANCH="develop"; BRANCH_TYPE="unknown" ;;
esac

# Detect project
INFRA_PROJECT=$(find src -name "*Infrastructure.csproj" | head -1)
INFRA_DIR=$(dirname "$INFRA_PROJECT")
MIGRATIONS_DIR=$(find "$INFRA_DIR" -type d -name "Migrations" -path "*/Persistence/*" | head -1)
MIGRATIONS_REL=$(realpath --relative-to="$(git rev-parse --show-toplevel)" "$MIGRATIONS_DIR")
STARTUP_PROJECT=$(find src -name "*.Api.csproj" | head -1)

# Detect DbContext (override via --context flag, else auto-detect)
CONTEXT_OVERRIDE="${CONTEXT:-}"
if [ "$CONTEXT_OVERRIDE" = "CoreDbContext" ] || [ "$CONTEXT_OVERRIDE" = "core" ]; then
  DBCONTEXT="CoreDbContext"; DBCONTEXT_TYPE="core"
elif [ "$CONTEXT_OVERRIDE" = "ExtensionsDbContext" ] || [ "$CONTEXT_OVERRIDE" = "extensions" ]; then
  DBCONTEXT="ExtensionsDbContext"; DBCONTEXT_TYPE="extensions"
elif find src -type d -name "SmartStack.Domain" | grep -q .; then
  DBCONTEXT="CoreDbContext"; DBCONTEXT_TYPE="core"
else
  DBCONTEXT="ExtensionsDbContext"; DBCONTEXT_TYPE="extensions"
fi

echo "Branch: $CURRENT_BRANCH → Base: $BASE_BRANCH"
echo "Migrations: $MIGRATIONS_DIR"
echo "DbContext: $DBCONTEXT"
```

### Step 2: Backup

```bash
BACKUP_DIR=".claude/gitflow/backup/migrations/rebase_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
cp "$MIGRATIONS_DIR"/*.cs "$BACKUP_DIR/"
echo "Backup: $BACKUP_DIR"
```

### Step 2b: Confirm (skip if `--force`)

If `--force` flag is NOT set:

```javascript
AskUserQuestion({
  question: "Rebase snapshot will:\n1. Reset ModelSnapshot to " + BASE_BRANCH + "\n2. Delete branch-specific migrations\n3. Regenerate consolidated migration\n\nBranch-specific migrations to recreate:\n" + BRANCH_ONLY_MIGS + "\n\nProceed?",
  header: "EF Core Rebase-Snapshot",
  options: [
    { label: "Yes, rebase", description: "Backup + rebase snapshot" },
    { label: "Cancel", description: "Do nothing" }
  ]
})
```

### Step 3: Identify branch-specific migrations + Reset

```bash
git fetch origin "$BASE_BRANCH"

# List parent branch migrations (names only)
BASE_MIGS=$(git ls-tree -r --name-only "origin/$BASE_BRANCH" -- "$MIGRATIONS_REL/" 2>/dev/null | grep "\.cs$" | grep -v "Designer\|Snapshot" | xargs -I{} basename {} .cs)

# List local migrations (names only)
LOCAL_MIGS=$(find "$MIGRATIONS_DIR" -maxdepth 1 -name "*.cs" ! -name "*Designer*" ! -name "*Snapshot*" | xargs -I{} basename {} .cs)

# Calculate branch-specific migrations (in local but NOT in base)
BRANCH_ONLY_MIGS=""
for mig in $LOCAL_MIGS; do
  if ! echo "$BASE_MIGS" | grep -qx "$mig"; then
    BRANCH_ONLY_MIGS="$BRANCH_ONLY_MIGS $mig"
  fi
done
BRANCH_ONLY_MIGS=$(echo "$BRANCH_ONLY_MIGS" | xargs)

echo "Branch-specific migrations to recreate:"
for mig in $BRANCH_ONLY_MIGS; do echo "  - $mig"; done

# Reset snapshot to parent branch
git checkout "origin/$BASE_BRANCH" -- "$MIGRATIONS_REL"/*ModelSnapshot.cs

# Retrieve parent branch migrations
for base_mig in $BASE_MIGS; do
  git checkout "origin/$BASE_BRANCH" -- "$MIGRATIONS_REL/${base_mig}.cs" 2>/dev/null || true
  git checkout "origin/$BASE_BRANCH" -- "$MIGRATIONS_REL/${base_mig}.Designer.cs" 2>/dev/null || true
done

# Delete branch-specific migrations by exact name (NOT by branch type pattern)
for mig in $BRANCH_ONLY_MIGS; do
  rm -f "$MIGRATIONS_DIR"/*"${mig}"*.cs
  echo "  Deleted: $mig"
done
```

### Step 4: Regenerate + Validate

```bash
# Regenerate with MCP naming - MANDATORY
mcp__smartstack__suggest_migration({ description: "...", context: DBCONTEXT_TYPE })

dotnet ef migrations add "$MCP_MIGRATION_NAME" \
  --context "$DBCONTEXT" \
  --project "$INFRA_PROJECT" \
  --startup-project "$STARTUP_PROJECT" \
  -o Persistence/Migrations

# NOTE: SQL objects are applied automatically at startup — no injection needed.

# Validate
dotnet build
```

## Migration Naming (via MCP)

**MANDATORY: Use MCP for naming**

```
{context}_v{version}_{sequence}_{Description}

core_v1.7.0_001_UserAuthConsolidated
core_v1.6.2_001_LoginFixFix
core_v1.7.0_001_ReleaseInitial
```

> **FORBIDDEN:** Legacy pattern `Feature_1_7_0_UserAuth_Consolidated`

## Safety Checks

- [ ] Clean working directory
- [ ] Backup created
- [ ] Build OK after rebase
- [ ] SQL script can be generated

## Error Recovery

| Failure | Recovery Action |
|---------|----------------|
| Build fails after rebase | Restore from backup: `cp "$BACKUP_DIR"/*.cs "$MIGRATIONS_DIR/"` |
| MCP unavailable | Check `.claude/mcp-status.json`, run `/mcp healthcheck` |
| Snapshot fetch fails | Verify `origin/$BASE_BRANCH` exists: `git fetch origin $BASE_BRANCH` |
| Migration creation fails | Restore backup, check `dotnet build` output |
| SQL objects missing at runtime | SQL objects are applied at startup — restart the application |

**Automatic recovery:** On ANY failure after backup:
1. Restore all files from backup directory
2. Verify build passes after restore
3. Report what failed and why
4. Suggest corrective action before retrying

## Priority

Safety > Correctness > Speed. Backup mandatory.
