Expand description
The Phase-2a event-based possession match engine (MATCH_MODEL.md),
behind the same play_match call site the Phase-1 crude engine used to
occupy. State space, resolution model, the wide route, and the knob
table are a faithful Rust port of the calibrated Python prototype
(match_model_prototype.ipynb, referenced from MATCH_MODEL.md §1) —
nothing here is a re-guess of the shape-finding, only its translation.
Deferred to Phase 2e (behind this same call site, no structural change): tactics as transition-matrix modifiers, cards & fouls, injuries, set pieces, substitutions, and the character/hidden attributes.
Structs§
- Formation
Stats - Per-formation usage seen by
StreamTelemetry::record— one increment per side per match (a formation used by both home and away in the same match counts twice), keyed byLineup::formationin the caller. - Knobs
- Match
Event - One beat in the minute-by-minute stream.
zoneis the zone-entry context (MATCH_MODEL.md§9) so a beat can say where on the pitch it happened. - Match
Outcome - The result of a simulated match: the score that folds into
GameState(viaEvent::MatchPlayed) plus the minute-by-minute trace. The trace rides alongside the fold, never inside it (MATCH_MODEL.md§7) — it is a Trace, not a fold input, and callers are free to discard it. Nothing here is persisted bycommands::advance_matchday; only the score is. - Stream
Telemetry - Accumulates match aggregates directly from
MatchOutcometraces — everythingSeasonTelemetrycan’t see because the fold discards the stream. Mirrors the notebook’sreport()fields.
Enums§
- Match
Event Kind - Shot
Kind - How the ball arrived at the shot (
MATCH_MODEL.md§5) — the discriminant that makes headed vs long-range goals countable for the goal-source-mix metric. Through-ball, dribbled, and cutback finishes shareFinish; only the attacker-attribute selection and chance-quality knob differ between them internally (§9’s stream schema pins exactly these three variants). - Shot
Outcome - Shot
Source - How the possession reached the shot (
MATCH_MODEL.md§5’s arrival table) — finer-grained thanShotKind, which collapses through-ball, dribble, and cutback finishes intoFinish. This is what makes the wide-origin-goal-share calibration target (cross + cutback,MATCH_MODEL.md§8) actually computable from the stream, not just headed-goal share. A rebound follow-up shot keeps the source of the shot that created it — the rebound is a continuation of the same attack, not a new arrival route. - Side
- Which side an event belongs to. Distinct from
fforge_domain::ClubId— the stream is home/away-relative; a caller maps it to real clubs via theFixtureit came from. - Zone
Def/Mid/AttC/AttWare dwelling zones;Boxis not dwelt in — an edge that reaches it resolves a shot immediately (arrival = chance).
Functions§
- ai_
pick_ lineup - Deterministic AI team selection: for each formation, greedily fill slots with the best remaining player by CA-in-slot-role (ties → lower player id); keep the formation with the best mean. This is the Phase-1 stub of the layer-3 club decision AI — same seam, richer policy later.
- lineup_
strength - Mean CA-in-slot-role over the eleven — a squad-quality scalar independent
of any particular match-resolution model. Used for display and by
ai_pick_lineup’s formation comparison below. - play_
match - Simulate one match:
(lineups, world, rng)in, score + trace out. A pure function of its inputs — same seed stream, same outcome, by construction (MATCH_MODEL.md§7).