Competition Profile
drawDefinition.competitionProfile is a first-class, versioned configuration attribute. It describes the competition format; matchUps, scores and applied-round provenance live separately. It is separate from competitionFormat, which describes how a sport is played.
Configure a rotating-partner draw
Create an AD_HOC doubles draw with no matchUps, then set its profile:
const result = tournamentEngine.setCompetitionProfile({
drawId,
competitionProfile: {
version: 1,
format: 'MEXICANO',
entrantScope: 'INDIVIDUAL',
matchUpType: 'DOUBLES',
scoring: { combinedPointTotal: 32 },
standings: { metric: 'SIDE_POINTS', attribution: 'EACH_INDIVIDUAL' },
pairing: {
seed: baseSeed,
algorithmVersion: 1,
groupBy: 'ADJACENT_STANDINGS',
partners: 'FIRST_FOURTH_SECOND_THIRD',
},
completion: { kind: 'ROUND_COUNT', rounds: 7 },
},
});
For Americano, use format: 'AMERICANO', pairing: { seed, algorithmVersion: 1 } and completion: { kind: 'PARTNERSHIP_COVERAGE' }. Store the Americano generator's seedUsed or Mexicano's baseSeed. Seeds must be safe integers; combined point totals and round counts must be positive safe integers. Version and pairing algorithm version are currently 1.
Tie resolution belongs to the governing scoring policy, rather than the profile. Profiles store configuration; individual admission and round application use the APIs below. Manual/live fixed-total scoring and individual standings use the historical contracts saved with applied rounds.
Read, change and remove
const { competitionProfile } = tournamentEngine.getCompetitionProfile({ drawId });
const result = tournamentEngine.removeCompetitionProfile({ drawId });
Queries and writes copy profile data, so changing caller objects does not change the record. An absent profile returns success with an undefined profile. Mutations emit the ordinary draw modification notice and the containing tournament record can be saved by its consumer. The attribute is first-class in every schema write mode; no extension migration is involved.
Once any matchUps exist in the draw or its nested structures, attaching, changing or removing the profile returns EXISTING_MATCHUPS. Reapplying an identical profile is an idempotent success. This protects already-generated rounds from being reinterpreted. Future correction and configuration-amendment workflows require their own explicit contracts.
Ladder configuration and state
A LADDER draw accepts { version: 1, format: 'LADDER' }. This identifies its format without changing existing ladder policy resolution. Challenge eligibility, movement and validation rules remain in the inherited ladder policy.
Rank standings are stored in structure position assignments; rating standings are derived from participant rating scales. Challenges and result attestations use matchUps and their timeItems, while dated participant scale items preserve standing history. Neither those records nor mutable standings belong in a policy or this configuration attribute. A later ladder normalization can add explicit configuration fields without copying its existing state here.
Governing scoring policy
getRotatingPartnerScoringPolicy({ drawId, structureId?, selectedVariant? }) returns the resolved
contract, scoringPolicy and selectionLocked. It reads the existing scoring policy's
rotatingPartners.AMERICANO or rotatingPartners.MEXICANO section. Policy precedence is
structure → draw → event → tournament; a nearer scoring policy replaces the whole scoring policy,
rather than merging nested fields. Missing format rules use the engine default; malformed rules fail.
const policyDefinitions = {
scoring: {
rotatingPartners: {
AMERICANO: {
defaultVariant: { tieResolution: 'ALLOW' },
permittedVariants: [{ tieResolution: 'ALLOW' }, { tieResolution: 'DECIDING_POINT' }],
permittedPointTotals: [24, 32],
},
},
},
};
tournamentEngine.attachPolicies({ drawId, policyDefinitions });
const result = tournamentEngine.getRotatingPartnerScoringPolicy({ drawId });
A singleton permitted list locks the organizer's choice. Otherwise the selected variant must match
one of the permitted variants exactly. WIN_BY_MARGIN requires a safe-integer winningMargin
of at least two; other variants prohibit a margin. Point totals must be positive safe integers and,
when restricted, belong to permittedPointTotals.
The engine default permits ALLOW, DECIDING_POINT, and WIN_BY_MARGIN with margin two,
defaulting to ALLOW. This query validates and previews configuration; use the persistence mutation below to save a
selection. Neither method changes manual/live scoring yet. Resolved rules must be captured when applying a round.
Separate deciding phases remain open work; inline extra-point attribution and individual standings are supported by the rotating-partner tally policy.
Persisting the scoring choice
Call setRotatingPartnerScoring({ drawId, selectedVariant? }) before generating matchUps. Omitting
selectedVariant saves the approved policy default. The mutation stores the choice in
competitionProfile.scoring.selectedVariant; point total and selected variant together define the
resolved match contract. Direct profile writes validate these choices against the governing policy.
getRotatingPartnerScoringContract({ drawId }) reads that saved contract without consulting current
policies. It refuses an unconfigured profile. This is the query historical scoring must use; the
policy query remains the preview of current governing rules. Changing inherited policies cannot
rewrite the saved contract. Repeating an identical write succeeds without effect; changing or removing
the profile is refused once any matchUps exist. The new mutation also respects DRAWS locks.
The draw-level match contract is captured in each applied round. Future-round amendments, separate deciding phases and tally rules remain outstanding.
Individual entrants and partnership sides
For a configured Americano or Mexicano draw, pass drawId to addEventEntries to enter individual
competitors into its doubles event as UNGROUPED (or explicitly UNPAIRED) and into the rotating
draw with an accepted status. DIRECT_ACCEPTANCE belongs only to the rotating draw, never the doubles
event. Standard doubles entry behavior remains unchanged
when no rotating draw is targeted. Gender/category checks remain in force. An invalid mixed batch is
refused before event or draw entry writes; PAIRs, unknown IDs and non-competitor roles are refused.
checkValidEntries recognizes the individual roster only in the targeted rotating draw. Event
validation uses the existing ungrouped-status convention. Ordinary draws cannot accept these
individuals as doubles competitors; existing loose, ungrouped AD_HOC entries remain supported.
Deleting the rotating draw retains valid ungrouped event entries. Remove its individual draw entries
before removing its competitionProfile.
Match sides remain PAIR participants. addAdHocMatchUps accepts partnerships outside the draw entry
list when each has two distinct individual entrants. It requires positive logical round numbers and
refuses any individual appearing twice within a round, including matchUps already inserted. Repeating
people across different rounds is permitted. These insertion guards also apply to the atomic round API below.
Preview and apply a round
const preview = tournamentEngine.getRotatingPartnerRoundPreview({
drawId,
structureId, // optional when the draw has exactly one structure
roundNumber: 1,
});
if (!preview.error) {
const result = tournamentEngine.generateRotatingPartnerRound({
drawId,
structureId: preview.structureId,
roundNumber: 1,
requestId, // unique application identifier; retain for retries
expectedPairings: preview.round,
expectedScoringContract: preview.scoringContract,
});
}
Preview creates no participants or matchUps. Application recomputes the preview, refuses changed approved pairings or scoring rules and stages PAIR creation and match insertion before committing. Existing partnerships are reused; new participants and matchUps have IDs derived from the draw, request and round for server/client replay. Successful retries with the same request return the stored round without additional writes. Changed request arguments, removed matches or edited PAIR membership are refused.
Applied provenance lives in drawDefinition.competitionRounds, separate from configuration. Each round record
captures side memberships, matchUp IDs, algorithm version, base/round seeds and scoring/tally contracts.
The frozen roster is stored once in drawDefinition.competitionRoster; Mexicano records also capture
the source standings snapshot and round cutoff. No freshness token is persisted. Do not edit PAIR memberships after application.
Americano supports sequential application of its complete saved rotation. Mexicano starts from zero
points and uses authoritative individual standings for subsequent rounds. Every prior result must be
settled under its saved tally contract before the next Mexicano round can be previewed.
The roster must stay fixed after application. The round API honours DRAWS locks and participant locks
when adding PAIRs. Court allocation uses existing scheduling methods. Each matchUp carries a fixed-total matchUpFormat derived from the saved round scoring contract.
Applied round formats cannot be changed through matchUp, structure, draw or event scope. Scheduling
edits and unrelated PAIR additions do not invalidate approved pairings.
Individual standings and tally policies are documented in Rotating Partner Pairing.