CONTRACT PARITY ANALYSIS: SHIFT vs TASK SELF-ASSIGNMENT
========================================================

SHIFT SELF-ASSIGNMENT MUTATION PATH:
------------------------------------
Hook: useSignUpShift() in frontend/src/hooks/useShifts.ts:104-120
Endpoint: POST /api/shifts/{shiftId}/signup
Method: Server-side inference of current member via session
Body: Empty (no explicit memberId sent)
Permission: Member role (inferred from endpoint access control)
Pattern: shift.signups.some((s) => s.memberId === session?.user?.id)

TASK UPDATE MUTATION PATH:
---------------------------
Hook: useUpdateTask() in frontend/src/hooks/useTasks.ts:109-116
Endpoint: PATCH /api/tasks/{id}
Interface: UpdateTaskRequest (lines 41-47) with assigneeId?: string
Method: Client explicitly sends assigneeId in request body
Permission: Assumed member role (no explicit gate observed)
Existing usage: assigneeId field exists in Task, CreateTaskRequest, UpdateTaskRequest

ASSIGNMENT SEMANTICS COMPARISON:
---------------------------------
Shift: Implicit self-assignment via POST to /signup endpoint
Task: Explicit assigneeId field update via PATCH with assigneeId in body

MEMBER ROLE PERMISSION ASSUMPTION:
-----------------------------------
Both flows assume member role can:
1. Sign up for shifts (POST /api/shifts/{id}/signup)
2. Update task assigneeId field (PATCH /api/tasks/{id} with assigneeId)

DETECTION PATTERN FOR "ASSIGN TO ME" BUTTON:
--------------------------------------------
Shift: isSignedUp = shift.signups.some((s) => s.memberId === session?.user?.id)
Task equivalent: task.assigneeId === session?.user?.id

CONTRACT COMPATIBILITY:
-----------------------
✓ UpdateTaskRequest.assigneeId field exists and accepts string
✓ useUpdateTask mutation supports arbitrary UpdateTaskRequest fields
✓ Task model includes assigneeId: string | null
✓ No observed frontend restrictions on member role updating assigneeId

DECISION:
---------
PARITY CONFIRMED: Task self-assignment flow should use:
- Mutation: useUpdateTask({ id: taskId, data: { assigneeId: session.user.id } })
- Detection: task.assigneeId === session?.user?.id
- Button label: "Assign to Me" (when not assigned) / "Unassign Me" (when assigned)

BACKEND VERIFICATION REQUIRED:
-------------------------------
Backend policy must permit member role to:
1. PATCH /api/tasks/{id} with assigneeId field
2. Set assigneeId to self (current member id)
(Deferred to T8 - conditional backend policy adjustment task)
