What this is: Extending the room engine for teams with multiple users per side. A 3v3 match is a standard room with 2 Teams, each containing 3 Users. Does not touch the tournament layer.
Owner: Can be a second developer working in parallel with Stage 6A–6B.
Tasks
-
ContestTeam multi-user logic
- Room creation with
teamSize: 3: accept teams: [{ name, members: [userId, userId, userId] }].
- Validate team sizes (1 or 3 per team, consistent within a contest).
- Populate
team:<teamId>:users Set with all member userId values.
- In the
cf_sync_queue worker: resolve userId → teamId by checking team:<teamId>:users membership before updating room:<id>:scores.
-
Team score aggregation
- Any team member's AC increments the team's score:
ZINCRBY room:<id>:scores <points> <teamId>.
- Individual attribution is preserved in
ContestSubmission via the userId field.
- Activity appended to
room:<id>:submissions stream: { userId, teamId, problemId, ... }.
-
Arena team claim
- A problem is locked by
teamId when any member of the team claims it.
- Lua claim script uses
teamId|cfTimestamp as the lock value (not userId|cfTimestamp).
-
Ready check for teams
- All members of all teams must
POST /api/contests/rooms/:id/ready.
- If any member fails to ready within 60s, their entire team is withdrawn as a unit.
Testing Gate
Handoff Contract
What this is: Extending the room engine for teams with multiple users per side. A 3v3 match is a standard room with 2 Teams, each containing 3 Users. Does not touch the tournament layer.
Owner: Can be a second developer working in parallel with Stage 6A–6B.
Tasks
ContestTeam multi-user logic
teamSize: 3: acceptteams: [{ name, members: [userId, userId, userId] }].team:<teamId>:usersSet with all memberuserIdvalues.cf_sync_queueworker: resolveuserId → teamIdby checkingteam:<teamId>:usersmembership before updatingroom:<id>:scores.Team score aggregation
ZINCRBY room:<id>:scores <points> <teamId>.ContestSubmissionvia theuserIdfield.room:<id>:submissionsstream:{ userId, teamId, problemId, ... }.Arena team claim
teamIdwhen any member of the team claims it.teamId|cfTimestampas the lock value (notuserId|cfTimestamp).Ready check for teams
POST /api/contests/rooms/:id/ready.Testing Gate
room:<id>:scores. VerifyContestTeam.scorein MongoDB after room end.Handoff Contract
ContestTeamschema works for both standalone rooms and knockout tournament context (nullableroundId,contestIdfields).