| name | swap-management |
| description | Schedule swap workflow expertise for faculty and resident shift exchanges. Use when processing swap requests, finding compatible matches, or resolving scheduling conflicts. Integrates with swap auto-matcher and MCP tools. |
| model_tier | sonnet |
| parallel_hints | [object Object] |
| context_hints | [object Object] |
| escalation_triggers | [object Object], [object Object], [object Object] |
Swap Management Skill
Expert procedures for managing schedule swaps while maintaining compliance and fairness.
When This Skill Activates
- Processing swap requests
- Finding compatible swap partners
- Resolving scheduling conflicts
- Answering swap policy questions
- Validating proposed swaps
- Handling emergency coverage
Swap Types
1. One-to-One Swap
Definition: Direct exchange between two people
Person A: Tuesday AM → Person B
Person B: Thursday PM → Person A
Requirements:
- Both parties consent
- Both qualified for swapped rotation
- Neither exceeds hour limits after swap
- Supervision ratios maintained
2. Absorb (Give Away)
Definition: One person takes another's shift without exchange
Person A: Gives away Friday PM
Person B: Absorbs Friday PM (no return)
Requirements:
- Receiver doesn't exceed limits
- Receiver qualified for rotation
- Giver has legitimate reason (PTO, conference, etc.)
3. Three-Way Swap
Definition: Circular exchange among three people
A → B's shift
B → C's shift
C → A's shift
Requirements:
- All three consent
- All compliance checks pass
- Tracked as linked transactions
Auto-Matching Algorithm
The system finds compatible swap partners using:
Match Criteria (Ranked)
- Qualification Match - Same rotation certification
- Hour Balance - Neither party exceeds limits
- Preference Alignment - Historical preferences
- Fairness Score - Workload distribution
- Proximity - Schedule adjacency for handoffs
MCP Tool
Tool: analyze_swap_compatibility
Input: { requestor_id, target_shift, swap_type }
Output: { matches: [...], compatibility_scores: {...} }
Validation Checklist
Before approving any swap:
Pre-Swap Checks
- Both parties have consented
- Qualification/credentialing verified
- 80-hour limit maintained for both
- 1-in-7 day off preserved
- Supervision ratios still valid
- No double-booking created
- Handoff timing adequate
Post-Swap Verification
- Calendar updated for both parties
- Notifications sent
- Audit trail created
- Metrics recalculated
Swap Request Workflow
Step 1: Request Submission
POST /api/swap/request
{
"requestor_id": "uuid",
"target_shift": { "date": "2025-01-15", "session": "PM" },
"swap_type": "one_to_one",
"reason": "Conference attendance",
"preferred_partners": ["uuid1", "uuid2"] // optional
}
Step 2: Auto-Match (if no partner specified)
System runs matching algorithm and returns:
- Top 5 compatible partners
- Compatibility scores
- Any warnings (approaching limits, etc.)
Step 3: Partner Response
Partner has 48 hours to:
- Accept → Proceeds to validation
- Decline → Returns to matching
- Counter-propose → New swap terms
Step 4: Validation
System performs full compliance check:
Tool: validate_swap
Returns: { valid: boolean, issues: [], warnings: [] }
Step 5: Execution
If valid:
- Update assignments in database
- Send calendar invites
- Notify stakeholders
- Log audit trail
Step 6: Rollback Window
24-hour window to reverse swap if issues discovered.
Emergency Coverage Protocol
When immediate coverage needed:
Tier 1: Available Pool
Check faculty/residents marked as backup:
SELECT * FROM persons
WHERE backup_available = true
AND NOT EXISTS (shift on target date)
AND weekly_hours < 75;
Tier 2: Swap Market
Broadcast need to all qualified personnel:
- Push notification
- Email alert
- Slack message (via n8n)
Tier 3: Absorb Request
Ask nearby shifts to extend coverage:
- Maximum 4-hour extension
- Must maintain 8-hour break
Tier 4: Escalation
If unfilled after 4 hours:
- Alert Program Director
- Consider schedule restructure
- Document coverage gap
Fairness Considerations
Swap Equity Tracking
Monitor swap patterns for fairness:
| Metric | Healthy | Warning | Action Needed |
|---|---|---|---|
| Swap Balance | ±2 per quarter | ±4 | Review workload |
| Weekend Swaps | Even distribution | >2 std dev | Redistribute |
| Holiday Coverage | Rotating | Same person 2x | Force rotation |
Protected Categories
Extra scrutiny for swaps affecting:
- Residents on probation
- Faculty approaching burnout indicators
- Personnel with documented accommodations
Examples
Example 1: Conference Swap Request
User Request: "Dr. Smith needs to swap her Thursday March 24 PM shift because she has a required conference. Can you help find a match?"
Claude Response:
Step 1: Verify shift eligibility
Checking shift details...
- Person: Dr. Sarah Smith (FAC-CORE-02)
- Date: March 24, 2026 (Thursday PM)
- Current assignment: Outpatient Clinic
- Shift status: Active (not frozen) ✅
Step 2: Run auto-matcher
Calling analyze_swap_compatibility...
Top 5 compatible matches:
1. Dr. Johnson (FAC-CORE-05) - Score: 0.92
- Available: Tuesday PM (clinic)
- Current hours: 45/80 (safe buffer)
- Historical preference: Prefers PM shifts ✅
2. Dr. Williams (FAC-CORE-01) - Score: 0.85
- Available: Wednesday AM (clinic)
- Current hours: 52/80
- Note: Approaching preferred workload limit
3. Dr. Davis (FAC-CORE-07) - Score: 0.78
- Available: Friday AM (procedures)
- Current hours: 38/80
- Note: Different rotation type (may need cross-training)
Step 3: Validate top match
Validating swap: Smith ↔ Johnson...
{
"valid": true,
"compliance_check": {
"smith_hours_post_swap": 47,
"johnson_hours_post_swap": 47,
"acgme_violations": 0,
"supervision_ratios": "maintained"
},
"warnings": []
}
Recommendation:
"✅ Dr. Johnson is the best match (92% compatibility). Both will remain well under work hour limits. Swap maintains all compliance requirements. Shall I notify Dr. Johnson and request consent?"
User: "Yes, please proceed"
Step 4: Execute swap
Sending swap request to Dr. Johnson...
- Notification sent via email + app
- Awaiting response (48-hour window)
- Swap ID: SWAP-20260312-001
I'll notify you when Dr. Johnson responds.
Example 2: Emergency Sick Coverage
User Request: "URGENT: Dr. Martinez just called in sick for her Sunday call shift. We need immediate coverage."
Claude Response:
🚨 Emergency coverage protocol activated
Step 1: Check backup pool
Querying available backup faculty...
Backup pool found: 3 available
1. Dr. Chen (FAC-CORE-08) - No assignments Sunday
- Current hours: 42/80 ✅
- Qualified for call ✅
- Marked as backup_available ✅
2. Dr. Patel (FAC-CORE-11) - Has AM shift only
- Could extend to cover PM call
- Current hours: 38/80 ✅
3. Dr. Kim (FAC-CORE-03) - Weekend off
- In backup pool but hours: 68/80 ⚠️
Step 2: Validate emergency absorb
Checking Dr. Chen for emergency coverage...
Compliance check:
- Post-absorb hours: 42 + 12 = 54/80 ✅
- 1-in-7 day off: Preserved ✅
- No double-booking: ✅
- Recent call: Last call 9 days ago ✅
✅ Dr. Chen is safe to absorb the shift
Step 3: Execute without consent (emergency)
Executing emergency absorb...
POST /api/swap/emergency-absorb
{
"original_person_id": "FAC-MARTINEZ",
"replacement_person_id": "FAC-CHEN",
"shift": "2026-03-27 PM (Sunday Call)",
"reason": "sick_call",
"emergency": true,
"skip_consent": true
}
✅ Assignment updated
✅ Dr. Chen notified (SMS + email + app)
✅ Calendar invite sent
✅ Program Director notified of emergency swap
Step 4: Workload balancing note
Emergency swap logged for fairness tracking:
- Dr. Chen: +1 emergency absorb (total this quarter: 2)
- Dr. Martinez: Sick day recorded
Recommendation: Offer Dr. Chen compensatory time off or first pick
on next swap request to maintain equity.
Summary:
"✅ Emergency coverage secured. Dr. Chen will cover Sunday call. All compliance requirements maintained. Dr. Martinez can focus on recovery."
Example 3: Standing Preference Swap
User Request: "Two residents want to permanently swap their clinic days - PGY-2 resident wants Mondays instead of Tuesdays. Is this possible?"
Claude Response:
Step 1: Identify swap scope
Request: Standing swap arrangement
- Resident A (PGY-2): Currently Tuesday PM clinic
- Resident B (PGY-2): Currently Monday PM clinic
- Duration: Remainder of academic year (6 months)
Step 2: Check long-term compliance
Validating standing swap arrangement...
Checking 24-week projection:
✅ Week 1-4: Both residents maintain <80hr limit
✅ Week 5-8: Both residents maintain <80hr limit
...
✅ Week 21-24: Both residents maintain <80hr limit
⚠️ Warning: Resident A has scheduled conference March 30 (Monday)
- Will need one-time exception that week
Long-term ACGME compliance: ✅ PASS
Step 3: Create recurring swap template
Creating standing swap template...
{
"template_id": "SWAP-TEMPLATE-001",
"type": "recurring_weekly",
"participant_a": "RES-PGY2-03",
"participant_b": "RES-PGY2-07",
"swap_pattern": {
"a_gives": "Tuesday PM Clinic",
"a_receives": "Monday PM Clinic",
"b_gives": "Monday PM Clinic",
"b_receives": "Tuesday PM Clinic"
},
"duration": "2026-03-12 to 2026-09-30",
"exceptions": ["2026-03-30 (Resident A conference)"],
"review_frequency": "quarterly"
}
✅ Template created
✅ Next 24 swaps auto-scheduled
Step 4: Fairness review schedule
Standing swap approved with quarterly review:
- First review: June 15, 2026
- Review criteria:
* Both residents satisfied with arrangement
* No negative impact on team dynamics
* Work hour compliance maintained
* Fair distribution of weekend coverage
I'll remind you 1 week before each quarterly review.
Recommendation:
"✅ Standing swap approved for 6 months. Both residents will swap clinic days weekly (with 1 exception for conference). Quarterly fairness reviews scheduled. Both residents notified of approval."
Common CLI Scenarios
Scenario: Conference Conflict
Request: Need Thursday off for required conference Process:
- Check if shift is swappable (not frozen)
- Find partner with complementary availability
- Validate both parties' compliance
- Execute swap with "conference" reason code
Scenario: Sick Coverage
Request: Called in sick, need immediate coverage Process:
- Skip consent (emergency protocol)
- Query backup pool first
- Broadcast if no backups available
- Log as emergency absorb
- Balance workload later
Scenario: Preference Swap
Request: Want to swap AM for PM regularly Process:
- Check if standing swap arrangement possible
- Validate long-term compliance
- If approved, create recurring swap template
- Review quarterly for fairness
Escalation Triggers
Escalate to Coordinator when:
- No compatible matches found
- Swap would create compliance violation
- Same person requesting >3 swaps/month
- Pattern suggests scheduling problem
- Conflict between swap participants
Reporting Format
## Swap Request Summary
**Request ID:** [ID]
**Type:** [One-to-One / Absorb / Three-Way]
**Status:** [Pending / Matched / Validated / Executed / Rejected]
### Parties
- Requestor: [Name] - [Current Hours: X/80]
- Partner: [Name] - [Current Hours: Y/80]
### Shifts Involved
- [Date] [Session] [Rotation] → From [A] to [B]
- [Date] [Session] [Rotation] → From [B] to [A]
### Validation Result
- Compliance: [PASS/FAIL]
- Warnings: [List any]
- Approval: [Auto/Manual Required]
### Next Steps
1. [Action item]
MCP Tools Reference
| Tool | Purpose |
|---|---|
analyze_swap_compatibility |
Find matching partners |
validate_swap |
Check compliance impact |
execute_swap |
Perform the swap |
rollback_swap |
Reverse within 24h window |
get_swap_history |
Audit trail query |
Concrete Usage Example
End-to-End: Processing a Conference Swap Request
Scenario: Dr. Smith needs Thursday PM off for a required conference. Find a compatible swap partner and execute the swap safely.
Step 1: Receive Swap Request
# Via API or admin interface
from app.models import SwapRequest
from datetime import date
swap_request = SwapRequest(
requestor_id="person-001", # Dr. Smith
target_date=date(2025, 2, 13), # Thursday
target_session="PM",
swap_type="one_to_one",
reason="ACFP Conference (required)",
preferred_partners=[] # Will auto-match
)
Step 2: Find Compatible Partners
from app.services.swap_matcher import SwapMatcher
matcher = SwapMatcher(db)
matches = await matcher.find_compatible_partners(
requestor_id="person-001",
target_shift={
"date": date(2025, 2, 13),
"session": "PM",
"rotation": "FM Clinic"
},
max_matches=5
)
print(f"Found {len(matches)} compatible partners:")
for match in matches:
print(f" {match.person_id}: {match.compatibility_score:.2f}")
print(f" - Current hours: {match.current_weekly_hours}/80")
print(f" - Qualified: {match.is_qualified}")
print(f" - Suggested return shift: {match.suggested_return_shift}")
Expected Output:
Found 3 compatible partners:
person-002: 0.92
- Current hours: 68/80
- Qualified: True
- Suggested return shift: 2025-02-18 AM (Tuesday)
person-005: 0.87
- Current hours: 65/80
- Qualified: True
- Suggested return shift: 2025-02-19 PM (Wednesday)
person-003: 0.75
- Current hours: 72/80
- Qualified: True
- Suggested return shift: 2025-02-20 AM (Thursday)
Step 3: Present Options to Requestor
# Dr. Smith reviews matches and selects person-002
swap_request.partner_id = "person-002"
swap_request.return_shift = {
"date": date(2025, 2, 18),
"session": "AM"
}
Step 4: Validate Swap
from app.services.swap_validator import SwapValidator
validator = SwapValidator(db)
validation_result = await validator.validate_swap(swap_request)
if validation_result.is_valid:
print("✅ Swap validation: PASS")
else:
print("❌ Swap validation: FAIL")
for issue in validation_result.issues:
print(f" - {issue.severity}: {issue.description}")
# Check warnings even if valid
if validation_result.warnings:
print("⚠️ Warnings:")
for warning in validation_result.warnings:
print(f" - {warning}")
Expected Output:
✅ Swap validation: PASS
⚠️ Warnings:
- person-002 will have 3 swaps this month (approaching limit of 4)
Step 5: Get Partner Consent
# Send notification to partner
from app.notifications import send_swap_request_notification
await send_swap_request_notification(
to_person_id="person-002",
swap_request=swap_request,
expiration_hours=48
)
print("Notification sent. Waiting for response...")
# Partner responds (via API or UI)
# Assume they accept
swap_request.partner_status = "accepted"
swap_request.partner_accepted_at = datetime.now()
Step 6: Execute Swap
from app.services.swap_executor import SwapExecutor
executor = SwapExecutor(db)
result = await executor.execute_swap(swap_request)
if result.success:
print(f"✅ Swap executed successfully!")
print(f" Swap ID: {result.swap_id}")
print(f" Audit trail: {result.audit_trail_id}")
# What changed:
for change in result.changes:
print(f" - {change.person_id}: {change.from_assignment} → {change.to_assignment}")
else:
print(f"❌ Swap failed: {result.error}")
Expected Output:
✅ Swap executed successfully!
Swap ID: swap-12345
Audit trail: audit-67890
Changes:
- person-001: 2025-02-13 PM FM Clinic → [unassigned]
- person-002: 2025-02-13 PM [unassigned] → 2025-02-13 PM FM Clinic
- person-001: 2025-02-18 AM [unassigned] → 2025-02-18 AM FM Clinic
- person-002: 2025-02-18 AM FM Clinic → [unassigned]
Step 7: Post-Execution Verification
# Re-validate ACGME compliance for both parties
from app.scheduling.acgme_validator import ACGMEValidator
acgme_validator = ACGMEValidator()
for person_id in ["person-001", "person-002"]:
assignments = await db.get_assignments_for_person(
person_id,
start_date=date(2025, 2, 1),
end_date=date(2025, 2, 28)
)
compliance_result = acgme_validator.validate_person_schedule(
person_id=person_id,
assignments=assignments
)
if compliance_result.is_compliant:
print(f"✅ {person_id}: ACGME compliant")
else:
print(f"❌ {person_id}: VIOLATIONS DETECTED - ROLLBACK NEEDED!")
await executor.rollback_swap(result.swap_id)
break
Expected Output:
✅ person-001: ACGME compliant
✅ person-002: ACGME compliant
Step 8: Send Confirmations
# Notify both parties
await send_swap_confirmation_notification(
swap_id=result.swap_id,
participants=["person-001", "person-002"],
calendar_updates=True # Send updated calendar invites
)
print("Swap complete! Confirmations sent.")
Total Time: ~5-10 minutes (most is waiting for partner response)
Workflow Diagram
┌─────────────────────────────────────────────────────────────┐
│ SWAP REQUEST WORKFLOW │
└─────────────────────────────────────────────────────────────┘
1. REQUEST SUBMISSION
├─ Requestor specifies shift to give away
├─ Optional: Suggest preferred partners
└─ Provide reason/justification
↓
2. AUTO-MATCHING (if no partner specified)
├─ Find qualified personnel
├─ Check hour limits
├─ Score compatibility
└─ Return top 5 matches
↓
3. PARTNER SELECTION
├─ Requestor reviews matches
├─ Selects preferred partner
└─ Proposes return shift
↓
4. VALIDATION
├─ Check qualifications
├─ Verify ACGME compliance impact
├─ Confirm no double-booking
└─ Generate warnings if any
↓
5. PARTNER CONSENT
├─ Send notification to partner
├─ 48-hour response window
├─ Partner accepts/declines/counters
└─ If declined, return to step 2
↓
6. EXECUTION
├─ Begin database transaction
├─ Update assignments for both parties
├─ Create audit trail
└─ Commit or rollback on error
↓
7. POST-EXECUTION VERIFICATION
├─ Re-validate ACGME compliance
├─ Check coverage maintained
├─ Update metrics
└─ If issues, rollback immediately
↓
8. NOTIFICATIONS
├─ Send confirmations to both parties
├─ Update calendar invites
├─ Log in swap history
└─ 24-hour rollback window begins
Common Failure Modes
Failure Mode 1: No Compatible Matches Found
Symptom: Auto-matcher returns empty list or very low compatibility scores
Cause: Shift is highly specialized, everyone at hour limits, or unusual constraints
Example:
matches = await matcher.find_compatible_partners(...)
# Returns: []
Resolution:
Relax constraints temporarily:
matches = await matcher.find_compatible_partners( ..., allow_near_limit=True, # Include people at 75+ hours extend_search_window=True # Look 2 weeks out instead of 1 )Emergency protocol:
# Broadcast to all qualified faculty await broadcast_emergency_coverage_request( shift=target_shift, reason="No matches found via auto-matcher" )Escalate to coordinator:
await create_coordinator_intervention_ticket( swap_request_id=swap_request.id, reason="No compatible partners available" )
Failure Mode 2: Partner Declines After Validation
Symptom: Swap validated successfully but partner says no
Cause: Personal reasons, schedule preference, or found better alternative
Example:
swap_request.partner_status = "declined"
swap_request.partner_decline_reason = "Prefer not to work that day"
Resolution:
Return to matching:
# Exclude declined partner matches = await matcher.find_compatible_partners( ..., exclude_person_ids=["person-002"] # They already declined )Counter-proposal:
# Partner might propose different return shift if swap_request.partner_counter_proposal: print(f"Partner proposes: {swap_request.partner_counter_proposal}") # Requestor can accept or decline
Failure Mode 3: ACGME Violation After Execution
Symptom: Swap executes but post-validation finds compliance issue
Cause: Validation logic bug, edge case, or cascading effect on other assignments
Example:
# Swap executes
result = await executor.execute_swap(swap_request)
# But post-validation fails
compliance_result = acgme_validator.validate_person_schedule(person_id)
# Returns: violations found - 81 hours in week of 2025-02-17
Resolution:
# Immediate rollback
await executor.rollback_swap(result.swap_id, reason="ACGME violation detected")
# Investigate why validation passed initially
await log_validation_discrepancy(
swap_id=result.swap_id,
pre_validation=validation_result,
post_validation=compliance_result
)
# Fix validation logic before allowing future swaps
Failure Mode 4: Double-Booking Created
Symptom: After swap, person assigned to two shifts at same time
Cause: Race condition, concurrent swap execution, or validation bug
Example:
# Person-002 now has:
# 2025-02-13 PM: FM Clinic (from swap)
# 2025-02-13 PM: Procedures (existing assignment not caught)
Detection:
# Check for overlaps
overlaps = await db.check_person_overlaps(person_id="person-002")
if overlaps:
print(f"❌ CRITICAL: Double-booking detected!")
for overlap in overlaps:
print(f" {overlap.date} {overlap.session}: {overlap.assignments}")
Resolution:
# Rollback immediately
await executor.rollback_swap(result.swap_id, reason="Double-booking detected")
# Implement locking to prevent concurrent swaps
# Add database-level unique constraint on (person_id, date, session)
Failure Mode 5: Swap Imbalance Tracking
Symptom: Person requests many swaps, always giving away shifts, never taking them
Cause: Gaming the system, burnout avoidance, or workload inequity
Example:
swap_history = await db.get_swap_history(person_id="person-001")
# Output:
# Swaps requested: 12
# Swaps given: 12 (always giving away shifts)
# Swaps taken: 0 (never absorbing others' shifts)
Detection:
# Calculate swap balance
balance = swap_history.swaps_taken - swap_history.swaps_given
if abs(balance) > 4:
print(f"⚠️ Swap imbalance: {balance}")
Resolution:
# Enforce balance requirement
if balance < -3:
raise ValidationError(
"You must accept incoming swaps before requesting more. "
"Current balance: -3 (you've given 3 more than taken)"
)
# Or implement points system
# Each swap given = -1 point
# Each swap taken = +1 point
# Require points >= -2 to request new swap
Integration with Other Skills
With schedule-optimization
When: Swaps have degraded schedule fairness Workflow:
- Execute swaps via swap-management
- Check fairness metrics (Gini coefficient)
- If fairness degraded significantly, invoke schedule-optimization
- Generate minimal-change rebalancing adjustments
- Execute as coordinated swaps
With acgme-compliance
When: Every swap execution Workflow:
- Before swap: Invoke acgme-compliance to validate
- After swap: Invoke acgme-compliance to verify
- If violations detected, rollback immediately
- Document in audit trail
With resilience-dashboard
When: Checking if swaps maintain backup capacity Workflow:
- Before executing swap, check current resilience status
- Model impact of swap on N-1 contingency
- If swap would degrade resilience below threshold, warn or block
- Document resilience impact in swap audit trail
With swap-analyzer
When: Analyzing patterns for fairness or abuse detection Workflow:
- Monthly: Invoke swap-analyzer to review all swaps
- Identify imbalances, clustering, or suspicious patterns
- Generate reports for program coordinator
- Recommend policy adjustments if needed
With security-audit
When: Suspicious swap patterns detected Workflow:
- swap-management detects unusual pattern (e.g., circular swaps)
- Invoke security-audit to investigate
- Check for collusion, manipulation, or system abuse
- Escalate to human if fraud suspected