Extract infractions from the rulebook so they can be extended on for suspensions and customizations.
Requirements
Scoresheet entry needs to be able to pull a list of infractions applicable to the branch
Currently outside of a game page (e.g., play profile) this isn’t exactly a simple as everything else as the rulebook is in the way
Suspensions and sanctioning rules need to be able to reference infractions to target accumulation rules
Currently penalties are not using infraction ids, so forced to target based on code
SQL-based reports need to be able to determine infraction names properly
Currently using initcap based on the infraction code to show infraction names and i18n is not possible
Branches need to be able to customize infraction options and extend the HC rulebook
Currently should be possible, but hasn’t been tested in practice
QC requires an automatic Major when a Match is assessed (similar to Major+GM)
Branches may need to be able to override how codes are displayed for each infraction (TBD)
Currently not supported
Specific types of infractions need to be able to trigger other infractions (ejections) based on accumulation
Currently possible
Ice hockey requires ejection after 3x stick infraction or 3x head contact
Ball hockey requires ejection after 3x any penalty
Scoresheet needs to be able to understand how infractions are grouped to keep editing accurate
When deleting a major penalty, the game misconduct should be deleted with it
This isn’t well solved below yet
Existing
Currently infractions exists within the rulebook only, and penalties reference infraction codes instead of ids. This makes it difficult to reference infractions in other contexts, especially providing a list of possible infractions.
Infraction Models
Extracting the nested infractions of the rulebook into separate tables for simpler relations and querying.
Bit of a challenge coming up for the names of each part. Infractions
have a Duration
and belong to Rules
which belong to Categories
. Infractions are grouped as Options
to require Major+GM or Double Minors to be selected together.
InfractionDuration
Minor, Major, Match, Misconduct, Game Misconduct
Property | Type | Description |
---|---|---|
id | uuid | |
officeId | id | Hockey Canada |
name | string | Minor |
description | string | |
abbreviation | string | |
length | number | Minutes |
legacyName | string | Used to set |
InfractionCategory
07 Physical Fouls
Property | Type | Description |
---|---|---|
id | uuid | |
seasonId | id | 2024-25 |
officeId | id | Hockey Canada |
name | string | Physical Fouls |
code | text | 7 |
InfractionRule
Head Contact
Property | Type | Description |
---|---|---|
id | uuid | |
seasonId | id | 2024-25 |
officeId | id | Hockey Canada |
name | string | Head Contact |
code | string | 7.6 |
categoryId | id | Physical Fouls |
Infraction
7.6(b) - Head Contact - Minor
Property | Type | Description |
---|---|---|
id | uuid | |
seasonId | id | 2024-25 |
officeId | id | Hockey Canada |
ruleId | id | 7.6 Head Contact |
durationId | id | Minor |
code | string | 7.6 (b) |
parentId | id | Allows overriding a parent infraction by a lower office |
externalId | uuid | For syncing with Spordle ID |
legacyName | string | Used to set |
Behaviour Options | ||
severity | enum | |
requiresIncidentReport | boolean | |
isTimed | boolean | |
isServable | boolean |
Infraction Option Models
Options define how infractions are used by each office and what the scorekeeper can select.
The part that combines double minors or majors and game misconducts as one and results in a time offset.
This is very important when editing so you can make sure that double minors are deleted together or the GM is deleted together with the Major.
Also fun, HQ doesn’t combine majors and game misconducts, so this definitely needs to be configurable by branch.
InfractionOption
This is a container that represents the options the scorekeeper can select.
Property | Type | Description |
---|---|---|
id | uuid | |
seasonId | id | 2024-25 |
officeId | id | Hockey Canada |
ruleId | id | 7.6 Head Contact (07 Physical Fouls) |
parentId | id | Allows overriding a parent option by a lower office |
InfractionOptionMember
These are the effective infractions upon selecting the option. Order is significant and allows for sequencing penalties as consecutive (e.g., major = 0, GM = 1) or parallel (same order) for start times
Property | Type | Description |
---|---|---|
id | uuid | |
optionId | id | |
infractionId | id | 7.6 (b) No unique constraint to allow for double minors |
order | number |
Infraction Accumulation Models
When creating a penalty, we need to check for accumulation rules to stack an additional infraction.
Typical examples are 3x Stick Infraction → Game Ejection or 2x Misconduct → Game Ejection.
InfractionAccumulation
This acts as a grouping that defines the count of the member infractions necessary and what the resulting infraction is.
Property | Type | Description |
---|---|---|
id | uuid | |
seasonId | id | 2023-24 |
officeId | id | Hockey Canada |
name | string | Stick Infractions |
count | number | 3 |
infractionId | id | Resulting infraction when accumulation reached 4.8 (b) |
InfractionAccumulationMember
These are the list of infractions that are part of the accumulation group. Order is not significant; any member infraction counts towards the accumulation group.
So for stick infractions, receiving 9.1 (a), 9.2 (a) and 9.3 (a) would result in a game ejection upon receiving 9.3 (a).
To account for double minors, penalties with the same infraction, game time and option are counted as one. Therefore a minor head contact (1x 7.6 (a)) by a double minor head contact (2x 7.6 (a)) continues to be counted as 2 despite there being 3x 7.6 (a).
Property | Type | Description |
---|---|---|
id | uuid | |
accumulationId | id | 2023-24 |
infractionId | id | 9.1 (a) |
Penalty Models
GamePenalty
Instances of an infraction in a game are called penalties. This is a scoresheet artifact.
Property | Type | Description |
---|---|---|
id | uuid | |
gameId | id | |
teamId | id | |
participantId | id | |
servedById | id | |
isInjured | boolean | Necessary for suspensions |
Time | ||
gameTime | GameTime | Time of infraction |
startTime | GameTime | Time the penalty started to be served |
endTime | GameTime | Time the penalty ceased to be served |
isEnded | boolean | Whether or not the penalty was ended |
Infraction | ||
infractionId | id | |
durationId | id | Technically not really necessary since the durationId is part of the infraction above |
optionId | id | Link penalties part of the same option group when creating instead of trying to reverse them as we currently do |
accumulationId | id | Link penalties that were created by an accumulation rule |
Legacy infraction options (deprecated) | ||
infraction | string | Infraction “id” which is something like “head-contact” in the rulebook |
duration | string | Duration “id” which is something like “minor” in the rulebook |
code | string | Infraction “code” |
Penalties are consisted linked if they have the same participantId
, gameTime
and optionId
or have an accumulationId
that matches.
Implementation
Scoresheets are effectively versioned by season. This is limited to 2024-25 and beyond seasons; 2023-24 and past seasons would maintain legacy rulebook support. Must maintain the same behaviour for past seasons (2018 - 2023), but new seasons would use the new models.
The /meta API should return all applicable infraction, infraction option and accumulation entities.