Skip to main content

matchUp Governor

import { matchUpGovernor } from 'tods-competition-factory';

abandonTournamentMatchUps​

Bulk "end the tournament": sets every still-playable matchUp to ABANDONED. Intended for tournaments whose draws cannot be completed (for example, rain) — rather than leaving unplayed matchUps as TO_BE_PLAYED, a director marks them ABANDONED in a single call.

Selection is driven by the derived readyToScore state: a matchUp with assigned participants on both sides, no winningSide, and an active structure. As a result BYEs, already-decided matchUps (COMPLETED, WALKOVER, RETIRED, …), already-terminal matchUps (ABANDONED, CANCELLED), and empty downstream rounds (no participants yet) are never touched. ABANDONED is a non-directing status, so no participant is advanced.

This mutates matchUps only — it does not change event or tournament status. TEAM container matchUps and tie collection matchUps are out of scope.

const { abandoned, matchUpIds } = engine.abandonTournamentMatchUps({
eventIds, // optional - restrict to these events
drawIds, // optional - restrict to these draws
requireNoScore, // optional - default true; when true, in-progress matchUps that already
// have a partial score are left untouched. Set false to also abandon
// started-but-unfinished matchUps.
});
// abandoned: number of matchUps set to ABANDONED
// matchUpIds: ids of the matchUps that were abandoned

allCompetitionMatchUps​

Returns all matchUps from all tournaments in a competition. See examples in Using proConflicts() for Analysis.

const { matchUps } = engine.allCompetitionMatchUps({
tournamentRecords, // required - array of tournament records
});

allDrawMatchUps​

Returns all matchUps from a specific draw.

const { matchUps } = engine.allDrawMatchUps({
drawId, // required
});

allEventMatchUps​

Returns all matchUps from a specific event.

const { matchUps } = engine.allEventMatchUps({
eventId, // required
});

allTournamentMatchUps​

Returns all matchUps from a tournament.

const { matchUps } = engine.allTournamentMatchUps();

analyzeMatchUp​

Analyzes a matchUp to extract detailed information.

const { analysis } = engine.analyzeMatchUp({
matchUp, // required
});

For an aggregate matchUpFormat (the match-level A modifier) the winner is the side with more points across every set, not the side that won more sets, and the totals are returned as aggregateScores. Every set the format plays must be recorded. Equal totals give no calculatedWinningSide: a decider is owed.

// SET2XA-S:T10 with sets 22-21 and 15-19
// aggregateScores: [37, 40], calculatedWinningSide: 2

applyLineUps​

Applies lineUps to the sides of a TEAM matchUp. Order is not important as team side is determined automatically. Does not check to ensure that participants in lineUps are part of teams; this is assumed. It is possible to have some participants assigned to a team side who are not part of a team.

result = engine.applyLineUps({
matchUpId, // must be { matchUpType: TEAM }
lineUps, // array of at most two lineUps (see CODES)
drawId, // reference to draw in which matchUp occurs
});

assignMatchUpSideParticipant​

Assign participant to AD_HOC matchUp.

Refused with SHARED_INDIVIDUAL_PARTICIPANT when the participant shares an individual with the opposing side, and with EXISTING_ROUND_PARTICIPANT when the participant — or a PAIR/TEAM sharing one of its individuals — already plays in another matchUp of the same round.

engine.assignMatchUpSideParticipant({
participantId,
sideNumber,
matchUpId,
drawId,
});

assignTieMatchUpParticipantId​

Used when interactively assigning participants to matchUps. When individual participantIds are assigned to { matchUpType: 'DOUBLES' } it handles creating { participantType: PAIR } participants dynamically. See examples: Creating Pairs Automatically.

engine.assignTieMatchUpParticipantId({
teamParticipantId, // optional - participant team can be derived from participantId. This supports assigning "borrowed" players from other teams.
participantId, // id of INDIVIDUAL or PAIR participant to be assigned to a matchUp
tieMatchUpId, // matchUpId of a SINGLES or DOUBLES that is part of a matchUp between teams
sideNumber, // optional - only necessary if a participant is part of both teams (edge case!)
drawId, // identifies draw in which matchUp is present
});

Refused with INVALID_MATCHUP when tieMatchUpId names a SINGLES or DOUBLES matchUp that is not a line of a TEAM matchUp (7.8.0; before, the refusal named an unrelated cause: team not found, not found, or missing matchUp). A TEAM matchUp itself is refused the same way.


bulkMatchUpStatusUpdate​

Provides the ability to update the outcomes of multiple matchUps at once.

const outcomes = [
{
eventId,
drawId,
matchUpId,
matchUpFormat,
matchUpStatus,
winningSide,
score,
},
];
engine.bulkMatchUpStatusUpdate({ outcomes });

checkInParticipant​

Set the check-in state for a participant. Used to determine when both participants in a matchUp are available to be assigned to a court. See examples: Sign-In Management, Participant Check-In.

engine.checkInParticipant({
participantId,
matchUpId,
drawId,
});

checkOutParticipant​

engine.checkOutParticipant({
participantId,
matchUpId,
drawId,
});. See examples: [Sign-In Management](../concepts/participants.md#sign-in-management).

calculateWinCriteria​

Calculates the win criteria for a matchUp based on format.

const { criteria } = engine.calculateWinCriteria({
matchUpFormat, // required
});

checkMatchUpIsComplete​

Checks if a matchUp has a winning side.

const { isComplete } = engine.checkMatchUpIsComplete({
matchUp, // required
});

competitionScheduleMatchUps​

Returns scheduled matchUps across all tournaments in a competition, with support for publish-state filtering and embargo enforcement. See examples: Querying Published Schedules.

const {
completedMatchUps, // completed matchUps (for the filtered date when not using alwaysReturnCompleted)
mappedParticipants, // { [participantId]: participant } - returned when hydrateParticipants is false
dateMatchUps, // all incomplete matchUps for the filtered date(s)
courtPrefix, // court prefix string (returned when withCourtGridRows is true)
courtsData, // array of court objects, each with a matchUps array
groupInfo, // group/round-robin information
venues, // venue data
rows, // court grid rows (returned when withCourtGridRows is true)
} = engine.competitionScheduleMatchUps({
courtCompletedMatchUps, // boolean - include completed matchUps in court.matchUps; useful for pro-scheduling
alwaysReturnCompleted, // boolean - return completed matchUps regardless of publish state
activeTournamentId, // optional string - target a specific tournament in multi-tournament competitions
hydrateParticipants, // boolean - defaults to true; when false, sides contain participantId and context-specific attributes only
participantsProfile, // optional - specify additions to context (see getParticipants())
policyDefinitions, // optional - e.g. privacy policies
withCourtGridRows, // optional boolean - return { rows } of matchUps for courts laid out as a grid, with empty cells
minCourtGridRows, // optional integer - minimum number of rows to return
sortDateMatchUps, // boolean - optional - defaults to true
usePublishState, // boolean - filter by publish state: published eventIds, scheduledDates, and embargo timestamps
contextFilters, // optional - filters based on context attributes (e.g. drawIds)
matchUpFilters, // optional - { scheduledDate, scheduledDates[], courtIds[], stages[], roundNumbers[], matchUpStatuses[], matchUpFormats[], eventIds[], isMatchUpTie }
sortCourtsData, // boolean - optional
nextMatchUps, // boolean - include winnerTo and loserTo matchUps
status, // optional string - publish status key, defaults to 'PUBLIC'
});

Publish-state filtering​

When usePublishState: true, the method reads the PUBLISH.STATUS timeItem from the tournament and applies the following filters:

  • Published dates: only matchUps whose scheduledDate is in orderOfPlay.scheduledDates are returned. An empty scheduledDates array (or omitted) means all dates are published.
  • Published events: if orderOfPlay.eventIds is non-empty, only matchUps from those events are returned.
  • Published draws: only matchUps from published draws are included, determined by event-level publish status.

Embargo enforcement​

When usePublishState: true, this method also enforces embargo timestamps at all levels:

  • Order of Play embargo: returns empty dateMatchUps if the OOP embargo timestamp has not passed
  • Draw embargo: filters out matchUps from embargoed draws
  • Stage embargo: filters out matchUps from embargoed stages
  • Structure embargo: filters out matchUps from embargoed structures
  • Round-level filtering: roundLimit on a structure caps which rounds appear in the schedule. scheduledRounds is an override map for per-round control within the ceiling — unlisted rounds pass through normally; { published: false } hides the round; embargoed rounds are returned without schedule data (schedule stripped) until the embargo passes. See Scheduled Rounds.

See: Embargo for details on how embargo timestamps work.


disableTieAutoCalc​

Disable default behavior of auto calculating TEAM matchUp scores.

engine.disableTieAutoCalc({ drawId, matchUpId });

This is a per-matchUp override — "this particular tie's score was entered by hand" — and is cleared when the score is removed. To state that an entire competition publishes only team results and never line detail, declare scoreSource: REPORTED on the tieFormat instead: it is inherited by every tie under it and carries no per-matchUp state.


enableTieAutoCalc​

Re-enable default behavior of auto calculating TEAM matchUp scores, and trigger auto calculation.

engine.enableTieAutoCalc({ drawId, matchUpId });

drawMatchUps​

Returns matchUps from a specific draw with filtering options.

const { matchUps } = engine.drawMatchUps({
drawId, // required
matchUpFilters, // optional - filter criteria
inContext, // optional - add context attributes
});

eventMatchUps​

Returns matchUps from a specific event with filtering options.

const { matchUps } = engine.eventMatchUps({
eventId, // required
matchUpFilters, // optional
inContext, // optional
});

filterMatchUps​

Filters matchUps based on provided criteria.

const { matchUps } = engine.filterMatchUps({
matchUps, // required - matchUps to filter
matchUpFilters, // required - filter criteria
});

findMatchUp​

Finds a matchUp by matchUpId. If drawId is not provided, performs a brute-force search across all tournament matchUps.

const {
matchUp, // HydratedMatchUp — the found matchUp
structure, // Structure — containing structure (convenience)
drawDefinition, // DrawDefinition — containing draw (convenience)
} = engine.findMatchUp({
matchUpId, // required — matchUp to find
drawId, // optional — narrows search scope; auto-resolved if omitted
eventId, // optional — narrows search scope
inContext, // optional boolean — hydrate matchUp with context (drawId, structureId, participants, etc.)
nextMatchUps, // optional boolean — include winnerTo and loserTo matchUp details
afterRecoveryTimes, // optional boolean — include recovery time calculations
participantsProfile, // optional — control participant hydration (see getParticipants())
contextProfile, // optional — control which context attributes are included
contextContent, // optional — pre-computed context content (optimization)
});

getAllDrawMatchUps​

Returns all matchUps from all structures in a draw.

const { matchUps } = engine.getAllDrawMatchUps({
drawId, // required
inContext, // optional
});

getAllStructureMatchUps​

Returns all matchUps from all structures.

const { matchUps } = engine.getAllStructureMatchUps({
structures, // required - array of structures
inContext, // optional
});

getCheckedInParticipantIds​

Returns participant IDs that have checked in for a matchUp.

const { participantIds } = engine.getCheckedInParticipantIds({
matchUpId, // required
drawId, // required
});

getCompetitionMatchUps​

Returns matchUps from all tournaments in a competition.

const { matchUps } = engine.getCompetitionMatchUps({
tournamentRecords, // required
matchUpFilters, // optional
});

getEventMatchUpFormatTiming​

Returns format timing configuration for an event. When categoryType is not supplied it is resolved from the event's own category.

const { eventMatchUpFormatTiming } = engine.getEventMatchUpFormatTiming({
eventId, // required
matchUpFormats, // optional - can be retrieved from policy
categoryType, // optional - falls back to the event's category when not supplied
});

See queryGovernor.getEventMatchUpFormatTiming for category resolution details.


getMatchUpCompetitiveProfile​

Returns competitive profile analysis for a matchUp.

const { profile } = engine.getMatchUpCompetitiveProfile({
matchUp, // required
});

getMatchUpContextIds​

Returns context IDs (tournamentId, eventId, drawId) for a matchUp.

const { contextIds } = engine.getMatchUpContextIds({
matchUpId, // required
});

getMatchUpDailyLimits​

Returns daily participation limits for matchUps. undefined when no scheduling policy is attached.

const { matchUpDailyLimits } = engine.getMatchUpDailyLimits();

See queryGovernor.getMatchUpDailyLimits for the undefined-means-no-limit contract.


getMatchUpDailyLimitsUpdate​

Calculates updated daily limits after a matchUp.

const { updatedLimits } = engine.getMatchUpDailyLimitsUpdate({
participantId, // required
matchUpFormat, // required
});

getMatchUpDependencies​

Builds a directed acyclic graph (DAG) of matchUp dependencies across all structures and draws. Returns the complete transitive closure of upstream matchUpIds, direct downstream dependents, optional participant tracking, and cross-structure POSITION link dependencies (e.g., Round Robin → Playoff).

Used internally by the automated scheduling pipeline to enforce dependency ordering, recovery time, and participant conflict constraints. Also used by the DependencyAdapter pattern in courthive-components for interactive scheduling profile validation.

const {
matchUpDependencies, // Record<matchUpId, { matchUpIds, dependentMatchUpIds, participantIds, sources }>
sourceMatchUpIds, // Record<matchUpId, string[]> — direct feeder matchUpIds
positionDependencies, // Record<structureId, string[]> — cross-structure POSITION link deps
matchUps, // HydratedMatchUp[] — the matchUps used for analysis
} = engine.getMatchUpDependencies({
includeParticipantDependencies, // optional boolean (default false)
drawDefinition, // optional — scope to a single draw
matchUps, // optional — pre-fetched inContext matchUps
matchUpIds, // optional — restrict to specific matchUpIds
drawIds, // optional — restrict to specific drawIds
});

For full documentation including return value details, cross-structure awareness, scheduling integration, and the DependencyAdapter pattern, see getMatchUpDependencies in the Query Governor.


getMatchUpFormat​

Returns the matchUp format for a matchUp.

const { matchUpFormat } = engine.getMatchUpFormat({
matchUpId, // required
drawId, // optional
eventId, // optional
});

getMatchUpFormatTiming​

Returns timing parameters for a matchUp format.

const { averageMinutes, recoveryMinutes, typeChangeRecoveryMinutes, overnightMinutes, recoveryFromPlayedMinutes } =
engine.getMatchUpFormatTiming({
matchUpFormat, // required
eventType, // optional - defaults to SINGLES
categoryName, // optional
categoryType, // optional
policyDefinitions, // optional - evaluate against a policy not attached to the record
playedMinutes, // optional - measured duration; keys byPlayedMinutes bands
});

See queryGovernor.getMatchUpFormatTiming for the full parameter and return reference.


getMatchUpFormatTimingUpdate​

Returns updated timing after format modifications.

const { timing } = engine.getMatchUpFormatTimingUpdate({
matchUpFormat, // required
modifications, // required
});

getMatchUpScheduleDetails​

Returns detailed schedule information for a matchUp.

const { details } = engine.getMatchUpScheduleDetails({
matchUpId, // required
drawId, // required
});

getMatchUpType​

Returns the matchUp type (SINGLES, DOUBLES, TEAM).

const { matchUpType } = engine.getMatchUpType({
matchUp, // required
});

getMatchUpsStats​

Returns statistics for a collection of matchUps.

const { stats } = engine.getMatchUpsStats({
matchUps, // required
});

getModifiedMatchUpFormatTiming​

Returns timing with custom modifications applied.

const { timing } = engine.getModifiedMatchUpFormatTiming({
matchUpFormat, // required
eventId, // optional
});

getParticipantResults​

Returns results for participants across matchUps.

const { results } = engine.getParticipantResults({
matchUps, // required
});

getPredictiveAccuracy​

Returns accuracy metrics for predictive algorithms.

const { accuracy } = engine.getPredictiveAccuracy({
matchUps, // required
});

getRoundMatchUps​

Returns matchUps for a specific round.

const { matchUps } = engine.getRoundMatchUps({
drawId, // required
structureId, // required
roundNumber, // required
});

getRounds​

Returns round information for a structure.

const { rounds } = engine.getRounds({
drawId, // required
structureId, // required
});

getHomeParticipantId​

const { homeParticipantId } = engine.getHomeParticipantId({ matchUp });

isValidMatchUpFormat​

Validates a matchUp format string or object.

const { valid } = engine.isValidMatchUpFormat({
matchUpFormat, // required
});

matchUpActions​

Returns available actions for a matchUp. The returned validActions array contains action objects with type, method, and payload that can be dispatched. Action types include SCORE, STATUS, SCHEDULE, REFEREE, ADD_PENALTY, START, and END.

const {
validActions, // array of action objects
structureIsComplete, // boolean — all matchUps in the structure are complete
isDoubleExit, // boolean — matchUp has DOUBLE_WALKOVER or DOUBLE_DEFAULT
isByeMatchUp, // boolean — matchUp involves a BYE
} = engine.matchUpActions({
matchUpId, // required — target matchUp
drawId, // optional — resolved by engine; auto-resolved via brute force if omitted
policyDefinitions, // optional — override matchUp action policies
sideNumber, // optional — restrict actions to a specific side (1 or 2)
participantId, // optional — scope actions to a specific participant
enforceGender, // optional boolean — enforce gender restrictions for tie matchUp assignments
restrictAdHocRoundParticipants, // deprecated, no effect — a participant (or a PAIR sharing one of its individuals) already in the round is never offered
tournamentParticipants, // optional — pre-fetched participants (optimization)
inContextDrawMatchUps, // optional — pre-fetched inContext matchUps (optimization)
matchUpsMap, // optional — pre-fetched matchUps map (optimization)
});

participantScheduledMatchUps​

Returns scheduled matchUps for a specific participant.

const { matchUps } = engine.participantScheduledMatchUps({
participantId, // required
scheduleDate, // optional - filter by date
});

publicFindMatchUp​

Finds a matchUp with privacy policies applied.

const { matchUp } = engine.publicFindMatchUp({
matchUpId, // required
policyDefinitions, // optional
});

removeMatchUpSideParticipant​

Removes participant assigned to AD_HOC matchUp.

engine.removeMatchUpSideParticipant({
sideNumber, // number - required
matchUpId, // required
drawId, // required
});

replaceTieMatchUpParticipantId​

engine.replaceTieMatchUpParticipantId({
existingParticipantId,
newParticipantId,
tieMatchUpId,
drawId,
});

Refused with INVALID_MATCHUP when tieMatchUpId names a SINGLES or DOUBLES matchUp that is not a line of a TEAM matchUp (7.8.0; before, the refusal named an unrelated cause: team not found, not found, or missing matchUp). A TEAM matchUp itself is refused the same way.


removeTieMatchUpParticipantId​

engine.removeTieMatchUpParticipantId({
participantId, // id of INDIVIDUAL or PAIR be removed
tieMatchUpId, // tieMatchUp, matchUpType either DOUBLES or SINGLES
drawId, // draw within which tieMatchUp is found
});

Refused with INVALID_MATCHUP when tieMatchUpId names a SINGLES or DOUBLES matchUp that is not a line of a TEAM matchUp (7.8.0; before, the refusal named an unrelated cause: team not found, not found, or missing matchUp). A TEAM matchUp itself is refused the same way.


removeDelegatedOutcome​

Removes a delegated outcome from a matchUp.

engine.removeDelegatedOutcome({
matchUpId, // required
drawId, // required
});

resetMatchUpLineUps​

Clears lineups from a TEAM matchUp.

engine.resetMatchUpLineUps({
matchUpId, // required
drawId, // required
});

resetAdHocMatchUps​

Will remove all results (scores) and optionally all participant assignments from specified matchUps (via matchUpIds or roundNumbers).

const result = engine.resetAdHocMatchUps({
removeAssignments, // optional; remove all assigned participants
roundNumbers, // optional if matchUpids provided
matchUpIds, // optional only if roundNumber(s) provided
structureId, // optional unless matchUpIds not provided
drawId,
};

export function resetAdHocMatchUps(params: ResetAdHocMatchUps) {
const paramsCheck = checkRequiredParameters(params, [
{ [DRAW_DEFINITION]: true, [EVENT]: true },
{
[ONE_OF]: { [MATCHUP_IDS]: false, roundNumbers: false },
[INVALID]: INVALID_VALUES,
[OF_TYPE]: ARRAY,
},
]);
if (paramsCheck.error) return paramsCheck;

const structureResult = getAdHocStructureDetails(params);
if (structureResult.error) return structureResult;
const { matchUpIds } = structureResult;
})

resetScorecard​

Removes all scores from tieMatchUps within a TEAM matchUp; preserves lineUps. If tiebreakReset is true, checks whether a "Tiebreaker" collectionDefinition was added to the matchUp's tieFormat and resets it back to the inherited tieFormat if so.

Validates that the matchUp is { matchUpType: TEAM } and that there are no active downstream matchUps (returns CANNOT_CHANGE_WINNING_SIDE error if downstream is active).

engine.resetScorecard({
matchUpId, // required — must be a TEAM matchUp
drawId, // required — resolved to drawDefinition by engine
tiebreakReset, // optional boolean — check for added tiebreak collectionDefinition and reset tieFormat
matchUpStatus, // optional — set a specific matchUpStatus after reset
});

resetTieFormat​

Remove the tieFormat from a TEAM matchUp if there is a tieFormat further up the hierarchy; modifies matchUp.tieMatchUps to correspond.

engine.resetTieFormat({
tournamentId, // required
matchUpId, // must be a TEAM matchUp
drawId, // required
uuids, // optional - in client/server scenarios generated matchUps must have equivalent matchUpIds
});

setDelegatedOutcome​

Sets a delegated outcome for a matchUp (e.g., referee decision, or a crowd-sourced score the tournament director has accepted as provisional).

The outcome is the canonical outcome shape. Its score may be supplied either as pre-derived per-side strings ({ scoreStringSide1, scoreStringSide2 }) or as a canonical { sets } array. When only sets is supplied, the per-side score strings are derived internally via generateScoreString, so callers never have to round-trip the score into strings.

engine.setDelegatedOutcome({
matchUpId, // required
drawId, // required
outcome, // required - { score: { sets } | { scoreStringSide1, scoreStringSide2 }, winningSide?, matchUpStatus? }
});

setMatchUpFormat​

Sets the matchUpFormat for a specific matchUp or for any scope within the hierarchy of a tournamentRecord.

info

If an array of scheduledDates is provided then matchUps which have matchUpStatus: TO_BE_PLAYED and are scheduled to be played on the specified dates will have their matchUpFormat fixed rather than inherited. This means that subsequent changes to the parent structure.matchUpFormat will have no effect on such matchUps.

The force attribute will remove the matchUpFormat from all targeted matchUps which have matchUpStatus: TO_BE_PLAYED; this allows the effect of using scheduledDates to be reversed. Use of this attribute will have no effect if scheduledDates is also provided.

engine.setMatchUpFormat({
matchUpFormat, // CODES matchUpFormatCode
eventType, // optional - restrict to SINGLES or DOUBLES

matchUpId, // optional - set matchUpFormat for a specific matchUp
drawId, // required only if matchUpId, structureId or structureIds is present
force, // optional boolean - when setting for structure, draws or events, strip any defined matchUpFormat from all TO_BE_PLAYED matchUps

// scoping options
scheduledDates, // optional - ['2022-01-01']
stageSequences, // optional - [1, 2]
structureIds, // optional - ['structureId1', 'structureId2']
structureId, // optional
eventIds, // optional - ['eventId1', 'eventId2']
eventId, // optional
drawIds, // optional - ['drawId1', 'drawId2']
stages, // optional - ['MAIN', 'CONSOLATION']
});

setMatchUpState​

Deprecated on the engine surface since 7.5.0; removed at the next major. This is the internal state writer behind setMatchUpStatus. Called directly it skips the scoring policy's say over the propagation flags, score-string derivation, format validation and the exit-propagation cascade, so the draw may not agree with the result. Use setMatchUpStatus.

engine.setMatchUpState({
matchUpId, // required
drawId, // required
matchUpStatus, // optional
score, // optional
winningSide, // optional
});

setMatchUpStatus​

Sets either matchUpStatus or score and winningSide; values to be set are passed in outcome object. Handles any winner/loser participant movements within or across structures, including multi-level consolation propagation (e.g., COMPASS draws). See examples: Setting Scores, MatchUp Operations, Real-World Example: Live Scoring Updates.

const outcome = {
matchUpStatus, // optional — e.g. COMPLETED, RETIRED, WALKOVER, DEFAULTED, DOUBLE_WALKOVER
matchUpStatusCodes, // optional — array of status code strings
winningSide, // optional — 1 or 2
score, // optional — { sets } — see note; per-side strings are derived, not accepted
matchUpFormat, // optional — override matchUpFormat for this matchUp
};

engine.setMatchUpStatus({
matchUpId, // required
drawId, // required — resolved to drawDefinition by engine
outcome, // optional — score/status/winningSide object

matchUpFormat, // optional — set matchUpFormat before applying score (validated against); a score with no resolvable format is refused
disableScoreValidation, // optional boolean — skip score validation, including the completeness rule below
allowChangePropagation, // optional boolean — allow winner/loser swap to propagate through structures; a scoring policy that sets it wins
propagateExitStatus, // optional boolean — propagate exit status (WALKOVER, etc.) to consolation matchUps; a scoring policy that sets it wins
propagateRetirementAsExit, // optional boolean — with propagateExitStatus, carry a RETIRED loser on as an exit (default false); a scoring policy that sets it wins
disableAutoCalc, // optional boolean — applies only to TEAM matchUps
enableAutoCalc, // optional boolean — applies only to TEAM matchUps
setTBlast, // optional boolean — when true, tiebreak score appears last in set score string
policyDefinitions, // optional — scoring policies
tournamentId, // optional — for multi-tournament operations
eventId, // optional — helps resolve drawDefinition
notes, // optional — add note (string) to matchUp object

schedule: {
// optional — set schedule items alongside status
courtIds, // optional — applies only to TEAM matchUps => creates .allocatedCourts
courtId, // optional — requires scheduledDate
venueId, // optional
scheduledDate, // optional
scheduledTime, // optional
startTime, // optional
endTime, // optional
},
});

Propagation flags. A scoring policy that sets allowChangePropagation, propagateExitStatus or propagateRetirementAsExit to true or false overrides the value passed on the call, in both directions; the call decides only where the policy is silent (since 7.5.0). The resolution is policy ?? param ?? default, where the default is undefined for the first two and false for propagateRetirementAsExit. POLICY_SCORING_DEFAULT is silent on all three. See Scoring Policy.

Warnings. A successful call can return warnings. When the recorded score holds a set decided by its tiebreak with no tiebreak points (7-6), the result carries { code: 'TIEBREAK_POINTS_NOT_RECORDED', setNumbers } (since 7.5.0). It is not reported under disableScoreValidation, nor for a TEAM matchUp, whose score is the dual's tally.

A completed score must be complete​

Score validation asks two questions of score.sets, under the matchUp's effective matchUpFormat:

  1. Bounds — no set exceeds what the format allows, and the winningSide named is the one the set counts produce.
  2. Completeness — every set is one the format could actually produce:
    • every set before the last is a finished, legal set;
    • the last set is finished too when the outcome claims completion (COMPLETED, or a winningSide with no matchUpStatus);
    • otherwise (RETIRED, DEFAULTED, IN_PROGRESS, SUSPENDED …) the last set may be unfinished, but never past the format's ceiling. This holds even when the set carries a winningSide, as parseScoreString gives one to the side leading an unfinished set.

Under SET3-S:6/TB7 this refuses 3-7 6-4 6-4 (a 7-3 set does not exist with a tiebreak at six) and 4-2 2-6 2-6 (the first set never finished), both of which were previously recorded as COMPLETED. A refusal returns INVALID_SCORE with an info naming the set, e.g. Set 1: …, and the matchUp is left unchanged. A score with no resolvable matchUpFormat is refused with ERR_MISSING_MATCHUP_FORMAT (CA, 2026-10-02): every rule above is a question about the format. A TEAM line's format is its collection definition's, and is resolved from there.

To record a score the format cannot produce — an import, a migration, a correction to history, an abandoned line — pass disableScoreValidation: true. It skips both questions.

Three tiebreak records are settled (CA, 2026-10-02):

  • 7-6 with no tiebreak points is a finished set. It is recorded, and validateScore names the set in a TIEBREAK_POINTS_NOT_RECORDED warning. Score entry still asks for the points: the completeness check used while typing does not call a bare 7-6 finished.
  • A match tiebreak recorded as 1-0 in its game fields is a finished set whose points were not kept. 1-0 in the tiebreak-point fields is refused, except under TB1.
  • Impossible tiebreak points are refused, such as 7-6(10-7) with a tiebreak to seven. An ingestion pipeline can call scoreGovernor.repairScore first, which drops such points and keeps 7-6.

Score strings are derived, never trusted​

score.sets is the source of truth. scoreStringSide1 / scoreStringSide2 are regenerated from sets on every call, and any strings supplied by the caller are discarded rather than persisted.

Previously generation was skipped whenever the caller supplied its own strings, so a client could persist strings the factory would never emit and its own parseScoreString could not round-trip — including set scores present in the string but absent from sets. Callers that hand-author score strings should stop doing so; send sets and read the derived strings back.

Two consequences worth knowing:

  • The matchUp's effective matchUpFormat is resolved via getMatchUpFormat rather than read off outcome.matchUpFormat, which is usually absent. Without it a tiebreak-only deciding set (F:TB10) rendered as a plain game score instead of [10-8].
  • The derived score object is merged into outcome.score rather than replacing it, so non-derived attributes such as score.side1PointScore survive.

Recording an exit before the second opponent arrives​

A WALKOVER or DEFAULTED can be recorded against the one participant present before the opponent arrives, whether or not propagateExitStatus is on (since 7.5.0). The outcome names no winner, or awards the empty side; whoever later arrives takes the walkover and advances. See Who may receive a directing outcome and the EXIT action in MatchUp Actions.

A double exit (DOUBLE_WALKOVER, DOUBLE_DEFAULT) entered directly needs both seats reached: one exit per seat. Beside a seat nobody has reached it is refused (since 7.5.0).

Reversing a propagated exit​

A propagated exit can advance through a consolation BYE into a later matchUp that then resolves — a real participant falls through into the empty winner slot and advances onward. Once that has happened the downstream consolation matchUp is active, and the standard active-downstream rule applies: the source result cannot be reset to TO_BE_PLAYED until the resolving consolation matchUps are undone first. This holds whether you attempt to reset the exit source itself or the later fall-through completion, and for both WALKOVER and DEFAULTED exits.

isActiveDownstream looks past the fed FMLC BYE the exit advanced through, so the resolved walkover is correctly detected as active rather than being masked by the BYE. A still-pending propagated exit (its winning side is an empty feed slot, nothing has fallen through yet) is not active, so the source result can still be reset while pending.

A carried exit is corrected at its origin. Where the exit was carried, a direct write that would re-score it, name another winner, relabel it as a played result or clear it is refused with CANNOT_CHANGE_OUTCOME; clearing or re-scoring the origin re-derives it (since 7.5.0).

An exit recorded against a vacant side, rather than carried there, is active whatever the other side holds. Flipping the winner of the matchUp that feeds it is refused with CANNOT_CHANGE_WINNING_SIDE (since 7.5.0).

Reverting a completed matchUp to a live status​

A COMPLETED matchUp whose score validates as a completed outcome (a decisive winningSide backed by valid completed sets) cannot be reverted directly to a "still live" status — IN_PROGRESS or SUSPENDED — when no new outcome is supplied. Such a call returns INCOMPATIBLE_MATCHUP_STATUS. This guards against a completed result being silently stripped and the draw un-advanced (e.g. an upstream client re-asserting IN_PROGRESS on already-finished matches).

The guard is deliberately narrow:

  • Allowed — submitting a new outcome (a corrected score / winningSide), which is a re-score rather than a bare downgrade.
  • Allowed — reverting RETIRED / DEFAULTED (irregular endings whose incomplete scores do not validate as a completed outcome) to IN_PROGRESS.
  • Blocked — a bare { matchUpStatus: IN_PROGRESS } (or SUSPENDED) on a validated COMPLETED matchUp.

To reopen a completed match, submit a new outcome or clear the result first (e.g. removeWinningSide, or reset to TO_BE_PLAYED).

The inverse is also rejected: a single submission whose score/winner implies completion cannot carry a live status. Passing an explicit winningSide, or a score that resolves a winner under the matchUpFormat (e.g. 6-2 6-3 in a best-of-3), together with matchUpStatus: IN_PROGRESS (or SUSPENDED) returns INCOMPATIBLE_MATCHUP_STATUS. A non-decisive in-progress score (e.g. a single set won in a best-of-3) is unaffected. TEAM matchUps are excluded (their tie score is auto-calculated).


setOrderOfFinish​

Sets the orderOfFinish attribute for matchUps specified by matchUpId in the finishingOrder array.

Validation​

Validation is done within a cohort of matchUps which have equivalent structureId, matchUpType, roundNumber, and matchUpTieId (if applicable).

  • matchUpIds in finishingOrder must be part of the same cohort
  • orderOfFinish values must be unique positive integers within the cohort
engine.setOrderOfFinish({
finishingOrder: [{ matchUpId, orderOfFinish: 1 }],
drawId,
});

substituteParticipant​

Substitutes one participant for another in a matchUp.

engine.substituteParticipant({
matchUpId, // required
drawId, // required
participantIdToRemove, // required
participantIdToAdd, // required
});

tallyParticipantResults​

Calculates participant results/standings from matchUps.

const { results } = engine.tallyParticipantResults({
matchUps, // required
});

toggleParticipantCheckInState​

engine.toggleParticipantCheckInState({
participantId,
tournamentId,
matchUpId,
drawId,
});. See examples: [Sign-In Management](../concepts/participants.md#sign-in-management).

updateTieMatchUpScore​

Trigger automatic calculation of the score of a TEAM matchUp.

engine.updateTieMatchUpScore({
tournamentId, // optional if default tournament set
matchUpId,
drawId,
});

tournamentMatchUps​

Returns all matchUps from the current tournament.

const { matchUps } = engine.tournamentMatchUps({
matchUpFilters, // optional
inContext, // optional
});

validMatchUp​

Validates a single matchUp object.

const { valid, errors } = engine.validMatchUp({
matchUp, // required
});

validMatchUps​

Validates an array of matchUp objects.

const { valid, errors } = engine.validMatchUps({
matchUps, // required
});