Documentation
¶
Overview ¶
Package domain — glossary.go owns the canonical kendo-term dictionary used by the Preact <Term> tooltip component (web-mobile/js/glossary.jsx) AND by API error responses (handlers_*.go ResolveReasonHuman).
The source of truth is specs/003-tournament-gap-closure/glossary.md. When entries are added or tooltip wording changes, update both this file AND the spec. A unit test (glossary_test.go) parses glossary.md and asserts the Go map covers every term in it, so a forgotten entry fails the build.
The JS side reads the same data via web-mobile/js/glossary.js, which is generated from this file by `go generate ./internal/domain/...` (see the go:generate directive below). Running `make go/build` regenerates it; CI catches drift.
Package domain defines the core domain models for the bracket creator
Index ¶
- Variables
- func AssignSeeds(players []Player, assignments []SeedAssignment) error
- func IsKikenDecision(d Decision) bool
- func IsKikenDecisionStr(s string) bool
- func ResolveReasonHuman(reason string) string
- func ValidateAssignments(assignments []SeedAssignment) error
- type CompetitorStatus
- type Decision
- type EnchoMetadata
- type Match
- type MatchResult
- type MatchWinner
- type Player
- type Pool
- type Position
- type SeedAssignment
- type Side
- type TeamLineup
- type Term
- type Tournament
Constants ¶
This section is empty.
Variables ¶
var ( ErrCompetitorStatusMissingPlayerID = errors.New("competitor_status: playerId must be set") ErrCompetitorStatusMissingReason = errors.New("competitor_status: reason required when not eligible") )
Sentinel errors so callers can switch on the validation failure without parsing strings.
var ( ErrLineupMissingSenpo = errors.New("team_lineup: senpo must be present") ErrLineupMissingTaisho = errors.New("team_lineup: taisho must be present") ErrLineupTooManyMissing = errors.New("team_lineup: 3+ missing positions — team is disqualified") ErrLineupTeamSizeInvalid = errors.New("team_lineup: teamSize must be positive") )
var Glossary = map[string]Term{ "hikiwake": { ID: "hikiwake", Kanji: "引き分け", Short: "Draw", Tooltip: "The match ended tied — both competitors finished with equal points and no winner is declared. Common in pool matches; knockout matches go to overtime (encho) instead.", SeeAlso: []string{"encho"}, }, "encho": { ID: "encho", Kanji: "延長", Short: "Overtime", Tooltip: "Overtime — when a knockout match is tied at the end of regulation, an extra period is played until someone scores. Scoring in Encho follows ippon-shobu rules: first to one point wins.", SeeAlso: []string{"ippon-shobu", "ippon"}, }, "kiken": { ID: "kiken", Kanji: "棄権", Short: "Withdrawal", Tooltip: "The competitor withdraws. Two sub-types: Voluntary (FIK Art. 31) — permanent disqualification from the competition; Injury (FIK Art. 30) — can be reinstated if a doctor and shinpan permit it. The opponent wins 2–0 by default.", }, "kiken-voluntary": { ID: "kiken-voluntary", Kanji: "棄権", Short: "Voluntary withdrawal", Tooltip: "FIK Article 31 — the competitor voluntarily withdraws. They forfeit this match (opponent wins 2–0) and are permanently barred from all later matches in this competition.", }, "kiken-injury": { ID: "kiken-injury", Kanji: "棄権", Short: "Injury withdrawal", Tooltip: "FIK Article 30 — the competitor withdraws due to injury or illness. They forfeit this match (opponent wins 2–0) and are blocked from later matches, but can be reinstated if a doctor and shinpan-in approve.", }, "fusenpai": { ID: "fusenpai", Kanji: "不戦敗", Short: "No-show forfeit", Tooltip: "The competitor didn't appear when called to court. The opponent wins 2–0 by default. (Literal meaning: no-fight loss.)", }, "fusensho": { ID: "fusensho", Kanji: "不戦勝", Short: "Bye-win", Tooltip: "In a team match, when one team is short a player for a bout, the present opponent wins that bout 2–0 without fighting. (Literal meaning: no-fight win.)", }, "daihyosen": { ID: "daihyosen", Kanji: "代表選", Short: "Representative bout", Tooltip: "Tiebreaker for team knockout matches. When two teams finish equal on both individual wins and points, each picks one player to fight a single-point bout (ippon-shobu) to decide the match.", SeeAlso: []string{"ippon-shobu", "ippon"}, }, "hansoku": { ID: "hansoku", Kanji: "反則", Short: "Penalty", Tooltip: "A foul. Two hansoku awarded to a competitor give the opponent one free point.", }, "shiro": { ID: "shiro", Kanji: "白", Short: "White", Tooltip: "The competitor wearing a white ribbon at the back. Always shown on the left in this app.", }, "aka": { ID: "aka", Kanji: "赤", Short: "Red", Tooltip: "The competitor wearing a red ribbon at the back. Always shown on the right in this app.", }, "shiaijo": { ID: "shiaijo", Kanji: "試合場", Short: "Court", Tooltip: "The marked floor area where matches are fought. Labelled A, B, C, etc.", }, "ippon": { ID: "ippon", Kanji: "一本", Short: "Point", Tooltip: "A valid point — a clean strike with correct form, posture, and spirit. First competitor to two ippon wins the match (or one in overtime).", }, "ippon-shobu": { ID: "ippon-shobu", Kanji: "一本勝負", Short: "Single-point match", Tooltip: "First competitor to score one ippon wins. Used in overtime (encho) and tiebreaker (daihyosen) bouts.", SeeAlso: []string{"ippon", "encho", "daihyosen"}, }, "kachinuki": { ID: "kachinuki", Kanji: "勝ち抜き", Short: "Winner-stays-on", Tooltip: "A team format where the winner of each bout stays on to face the next opponent. A draw retires both. The match ends when one team has no more players left.", }, "senpo": { ID: "senpo", Kanji: "先鋒", Short: "First player", Tooltip: "The team's first player — fights bout 1 in a 5-person team. Senpo must be filled; this position cannot be left vacant, even when a teammate is withdrawn.", }, "jiho": { ID: "jiho", Kanji: "次鋒", Short: "Second player", Tooltip: "The team's second player — fights bout 2. If a team is short one player, FIK rules require that the Jiho position is the one left vacant.", }, "chuken": { ID: "chuken", Kanji: "中堅", Short: "Middle player", Tooltip: "The team's middle player — fights bout 3 in a 5-person team.", }, "fukusho": { ID: "fukusho", Kanji: "副将", Short: "Vice-captain", Tooltip: "The team's vice-captain — fights bout 4. If a team is short two players, FIK rules require jiho and Fukusho to be the two vacant positions.", SeeAlso: []string{"jiho"}, }, "taisho": { ID: "taisho", Kanji: "大将", Short: "Captain", Tooltip: "The team's captain — fights the final bout (bout 5). Like senpo, Taisho must be filled; this position cannot be left vacant.", SeeAlso: []string{"senpo"}, }, "zekken": { ID: "zekken", Kanji: "ゼッケン", Short: "Back name-tag", Tooltip: "The cloth name-tag worn on the competitor's back. The display can show this name (instead of the registered name) so spectators see what's physically visible.", }, "dojo": { ID: "dojo", Kanji: "道場", Short: "Club or school", Tooltip: "The training school or club a competitor represents. The pool generator avoids placing two competitors from the same dojo in the same pool when it can.", }, "dan": { ID: "dan", Kanji: "段", Short: "Rank", Tooltip: "A competitor's grade — shodan (1st), nidan (2nd), sandan (3rd), up to 8th. Optional in the entry form.", }, "waza": { ID: "waza", Kanji: "技", Short: "Technique", Tooltip: "The specific type of strike scored — for example, men, kote, or do. Recorded with each ippon for the match record.", SeeAlso: []string{"ippon"}, }, "kachinuki-exhaustion": { ID: "kachinuki-exhaustion", Kanji: "", Short: "Team exhausted", Tooltip: "A kachinuki match ended because one team has no remaining players to send. The opposing team wins.", SeeAlso: []string{"kachinuki"}, }, "sune": { ID: "sune", Kanji: "すね", Short: "Shin strike", Tooltip: "A strike to the shin. Scores a point in Naginata competitions. Not a valid scoring technique in Kendo.", }, }
Glossary is the full term map keyed by lowercase romaji ID. The entries here mirror specs/003-tournament-gap-closure/glossary.md verbatim — tooltips are copied as-is so the spec and code never drift. Don't paraphrase.
Functions ¶
func AssignSeeds ¶
func AssignSeeds(players []Player, assignments []SeedAssignment) error
AssignSeeds applies valid seed assignments to a list of players It swaps seeds if a collision occurs. Returns error if a seeded participant is not found.
func IsKikenDecision ¶ added in v0.16.0
IsKikenDecision reports whether d is any kiken variant (legacy, voluntary, or injury). Use this instead of comparing against DecisionKiken alone — the legacy value is kept for backward compatibility but new code should use the specific sub-types.
func IsKikenDecisionStr ¶ added in v0.16.0
IsKikenDecisionStr is the string-argument twin of IsKikenDecision, for call sites that hold the wire value as a string (e.g. MatchResult.Decision).
func ResolveReasonHuman ¶ added in v0.16.0
ResolveReasonHuman returns the human-friendly gloss for an engine-emitted reason string, or "" when no pattern matches.
Callers wire this into error responses alongside the raw `reason` field so UIs can show "withdrew from match m_12" instead of "kiken at m_12". Returning "" rather than echoing the input lets the caller decide whether to omit the field or fall back to the raw reason — the JSON omitempty tag on ReasonHuman handles the typical case.
func ValidateAssignments ¶
func ValidateAssignments(assignments []SeedAssignment) error
ValidateAssignments checks a list for duplicate seed ranks, valid properties, and gapless sequences.
Types ¶
type CompetitorStatus ¶ added in v0.16.0
type CompetitorStatus struct {
PlayerID string `json:"playerId" yaml:"playerId"`
Eligible bool `json:"eligible" yaml:"eligible"`
Reinstateable bool `json:"reinstateable,omitempty" yaml:"reinstateable,omitempty"`
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
MatchID string `json:"matchId,omitempty" yaml:"matchId,omitempty"`
RecordedAt time.Time `json:"recordedAt" yaml:"recordedAt"`
}
CompetitorStatus tracks whether a player is eligible to compete after a kiken/fusenpai withdrawal recorded earlier in the tournament.
FR-034, data-model §3.
func (CompetitorStatus) Validate ¶ added in v0.16.0
func (c CompetitorStatus) Validate() error
Validate enforces FR-034: PlayerID must be set, and an ineligible status must carry a non-empty Reason.
type Decision ¶ added in v0.16.0
type Decision string
Decision identifies how a match was concluded.
FR-030, NFR-011, FR-044 — see data-model §1.
const ( DecisionNone Decision = "" DecisionFought Decision = "fought" DecisionHikiwake Decision = "hikiwake" DecisionKiken Decision = "kiken" DecisionKikenVoluntary Decision = "kiken-voluntary" DecisionKikenInjury Decision = "kiken-injury" DecisionFusenpai Decision = "fusenpai" DecisionFusensho Decision = "fusensho" DecisionDaihyosen Decision = "daihyosen" DecisionKachinukiExhaustion Decision = "kachinuki-exhaustion" DecisionIpponShobu Decision = "ippon-shobu" )
func (*Decision) UnmarshalYAML ¶ added in v0.16.0
UnmarshalYAML migrates legacy `decision` values (NFR-025, R6):
- bool true → DecisionHikiwake (the historical "draw" flag)
- bool false → DecisionFought (legacy YAML only persisted the field on completed matches; "not a draw" meant the match was fought to a result)
- any defined string wire value → that Decision
- any other string → DecisionNone (schema-tolerant load)
type EnchoMetadata ¶ added in v0.16.0
type EnchoMetadata struct {
PeriodCount int `json:"periodCount" yaml:"periodCount"`
}
EnchoMetadata records overtime (encho) periods played to resolve a tied match.
type MatchResult ¶ added in v0.16.0
type MatchResult struct {
Decision Decision `json:"decision,omitempty" yaml:"decision,omitempty"`
DecisionBy Side `json:"decisionBy,omitempty" yaml:"decisionBy,omitempty"`
DecisionReason string `json:"decisionReason,omitempty" yaml:"decisionReason,omitempty"`
Encho *EnchoMetadata `json:"encho,omitempty" yaml:"encho,omitempty"`
}
MatchResult captures the outcome metadata of a match.
FR-030, FR-032, data-model §2.
type MatchWinner ¶
MatchWinner represents a player who has won a match
type Player ¶
type Player struct {
ID string `json:"id,omitempty"` // stable UUID assigned at first persist
Name string `json:"name"`
DisplayName string `json:"displayName"`
Dojo string `json:"dojo"`
Metadata []string `json:"metadata,omitempty"`
Tag string `json:"tag,omitempty"` // e.g. "manual", "registered", "transfer", "reserved"
CheckedIn bool `json:"checkedIn"`
PoolPosition int64 `json:"-"`
Seed int `json:"seed"`
Number string `json:"number,omitempty"` // e.g. "K1" — assigned when --number-prefix is set
}
Player represents a tournament participant. It is the canonical participant type across state, engine, mobileapp, and helper packages; internal/helper re-exports it under helper.Player as a type alias for rendering-side ergonomics (NFR-007).
type Position ¶ added in v0.16.0
type Position string
Position names a slot in a team lineup. For 5-person teams the named FIK constants apply; for other sizes positions are numeric strings "1".."N" produced by PositionNumbered.
FR-040, data-model §4.
func PositionNumbered ¶ added in v0.16.0
PositionNumbered returns the canonical Position value for a non-5 team size, where positions are 1-indexed numeric strings.
type SeedAssignment ¶
type SeedAssignment struct {
Name string `json:"name"`
Dojo string `json:"dojo,omitempty"`
SeedRank int `json:"seedRank"`
}
SeedAssignment represents the mapping of a previous winner to a seed position.
func (*SeedAssignment) Validate ¶
func (s *SeedAssignment) Validate() error
Validate checks if the seed assignment is valid.
type Side ¶ added in v0.16.0
type Side string
Side identifies which side of a match (Shiro = white, Aka = red).
FR-032, data-model §2.
type TeamLineup ¶ added in v0.16.0
type TeamLineup struct {
TeamID string `json:"teamId" yaml:"teamId"`
CompetitionID string `json:"competitionId" yaml:"competitionId"`
Round int `json:"round" yaml:"round"`
Positions map[Position]string `json:"positions" yaml:"positions"`
LockedAt *time.Time `json:"lockedAt,omitempty" yaml:"lockedAt,omitempty"`
}
TeamLineup pins which player occupies each Position for a team in a given round. The lineup is replaceable up until the round's first match goes live, at which point LockedAt is set and further PUT/PATCH operations are rejected.
FR-040, data-model §4.
func (TeamLineup) Validate ¶ added in v0.16.0
func (t TeamLineup) Validate(teamSize int) error
Validate enforces FR-037 / FR-041 / R4 / CHK012: a 5-person lineup must include Senpo and Taisho, and any kiken vacancies must follow the FIK back-fill rule (the missing position is Jiho first, then Jiho+Fukusho). For non-5 sizes positions must be numeric "1".."N".
Returning a non-nil error signals the team should not be allowed to take the court (either reject the lineup PUT or DQ the team via CompetitorStatus).
type Term ¶ added in v0.16.0
type Term struct {
ID string `json:"id"`
Kanji string `json:"kanji"`
Short string `json:"short"`
Tooltip string `json:"tooltip"`
SeeAlso []string `json:"seeAlso,omitempty"`
}
Term is a single dictionary entry. ID is the lowercase romaji ("kiken", "ippon-shobu", "kachinuki-exhaustion"); it doubles as the map key and as the `name` prop of the JSX <Term> component. Kanji is the Japanese spelling (or empty for the few entries without one, e.g. "kachinuki-exhaustion"). Short is the one-word English gloss the /glossary page renders next to the term. Tooltip is the full volunteer-facing sentence (rendered inside the popover and the /glossary page). SeeAlso lists the IDs of cross-referenced terms; the JSX component uses it to render nested <Term> spans inside the tooltip so hovered cross-references reveal their own tooltips.
type Tournament ¶
Tournament represents the complete tournament structure
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
glossarygen
command
Package main — glossarygen emits web-mobile/{js,dist}/glossary_data.js from internal/domain/glossary.go (the Go-side dictionary).
|
Package main — glossarygen emits web-mobile/{js,dist}/glossary_data.js from internal/domain/glossary.go (the Go-side dictionary). |