# 02 — CFB27 Dynasty Save Table Inventory

Documentation suite for **CoachCarouselRecruitTool**. Synthesized 2026-07-14. Record counts are **real, from
the user's own dynasty saves** (DYNASTY-QQ = brand-new 2026 preseason; DYNASTY-QQ2b = 2028 preseason after
one carousel; DYNASTY-QQ2 = 2029 offseason stage 2 = the transfer-portal stage our tool targets).

Source tags: `[inv]` = `research/dumps/tables-inventory.json` (full 2,269-table dump of DYNASTY-QQ);
`[dump]` = `research/notes-save-dump.md` + `research/dumps/*`; `[diff]` = `research/notes-save-diff.md`;
`[schema]` = `research/notes-schema.md`; `[carousel]/[fc]/[pipe]/[jersey]/[web]` = the respective
`research/notes-*.md` files. UNVERIFIED claims are marked.

---

## Table of contents

1. [Global statistics](#1-global-statistics)
2. [Resolution rules (read this before touching any table)](#2-resolution-rules)
3. [Master registry: the tables our tool cares about](#3-master-registry-the-tables-our-tool-cares-about)
4. [Deep annotations by domain](#4-deep-annotations-by-domain)
   - [4.1 Recruiting](#41-recruiting)
   - [4.2 Coaching & carousel](#42-coaching--carousel)
   - [4.3 Teams, conferences, league](#43-teams-conferences-league)
   - [4.4 Calendar & singleton state](#44-calendar--singleton-state)
   - [4.5 History & news](#45-history--news)
   - [4.6 Pipelines](#46-pipelines)
5. [Largest tables by capacity](#5-largest-tables-by-capacity)
6. [Duplicate-name groups](#6-duplicate-name-groups)
7. [Engine-plumbing taxonomy (the other ~2,000 tables)](#7-engine-plumbing-taxonomy)
8. [Sources](#sources)

---

## 1. Global statistics

- **2,269 tables** in the year-0 save (DYNASTY-QQ), **2,471/2,472** by dynasty years 2–3 — the table count
  grows over a dynasty's life (new `Team[]`, stat and history instances get appended). `[inv][diff §5]`
- **1,295 distinct table names**; 76 names are shared by more than one table. `[inv]`
- Schema in play: C27_468_2 (major 468, minor 2, gameYear 27); the schema bundle defines 3,498 schemas, of
  which only a subset are instantiated as save tables. `[inv][schema §1]`
- tableIds (4096+) did **not** shift between any of the five saves examined (same build + dynasty lineage);
  cross-build stability is UNVERIFIED — always resolve by `header.uniqueId`. `[diff §5]`

## 2. Resolution rules

1. **Resolve by `getTableByUniqueId(uid)`** (null-check the result — it returns `undefined` on a miss). `[pipe §1]`
2. Name collisions that will bite you: `Team` ×9 (real one = uid 3359508968, cap 143; 8 decoys cap 1–6),
   `Coach` ×2 (real = uid 1860529246 cap 632; decoy uid 2796679390 cap 1), `ProspectTargetSchool` ×2 (two
   real pools), `Player[]` ×179, `Team[]` ×9+, `StaffPersonContractOffer[]` ×2. `[dump §15][diff §5][inv]`
3. Unique-by-name (safe either way): `Recruit`, `RecruitTarget`, `Player`, `JobOpening`, `SeasonInfo`,
   `StaffPersonContractOffer`, `Conference`. `[diff §5]`
4. For array tables reached from a ref (e.g. `Team.Roster`), **follow the ref** rather than guessing which
   same-named array table it is. `[fc §2][dump §7]`

## 3. Master registry: the tables our tool cares about

All uniqueIds/tableIds verified live; non-empty counts per save from `[dump §1]` / `[inv]` / `[diff]`.
tableId column = the 2026-07 build (stable across the five saves examined, `[diff §5]`).

| Table | uniqueId | tableId | cap | non-empty QQ / QQ2 / QQ2b | isArray | t2 | Purpose |
|---|---|---|---|---|---|---|---|
| `Recruit` | 1873209313 | 4269 | 7600 | 4101 / 4101 / 3467* | no | no | one row per recruit (HS/JUCO/transfer); row 0 = sentinel |
| `RecruitTarget` | 59043175 | 4288 | 4870 | 0 / 4795 / 0 | no | no | AI school board entries; EMPTY outside recruiting cycle |
| `RecruitTarget[]` | 2412159097 | 5847 | 138 | 138 always | 35 slots | no | per-school board slot array; row index == TeamIndex (coincidence — follow refs) |
| `UserRecruitTarget` | 3987156317 | 4168 | 1120 | 0 / 31 / 0 | no | no | the human user's board entries (RecruitTarget subclass) |
| `RecruitingBoard` | 220276943 | 4251 | 138 | 138 | no | no | per-school wrapper {Recruits → RecruitTarget[], recruiting hours} |
| `ProspectTargetSchool` (pool A) | 3789266353 | 5840 | 41010 | 41000 | no | no | {TeamId, TeamInfluence} top-school elements; 10 per recruit |
| `ProspectTargetSchool` (pool B) | 3843719174 | 5841 | 35000 | 0 (next=23589 in later saves) | no | no | spare pool; no sampled TopSchoolsList slot pointed here — purpose UNVERIFIED |
| `ProspectTargetSchool[]` | 2332540366 | 5842 | 7600 | 4100 | 10 slots | no | one row per recruit = the TopSchoolsList target |
| `Player` | 1612938518 | 4244 | 16500 | 16257 | no | yes | shared by rostered players AND recruit prospects (recruits have TeamIndex 255) |
| `Coach` | 1860529246 | 4173 | 632 | 497 (all saves) | no | yes | all coaching staff; 136 fields |
| `Team` | 3359508968 | 6334 | 143 | 143 | no | yes | 138 FBS + 5 FCS pseudo-teams (shared TeamIndex 255); 408 fields |
| `Conference` | 3820706130 | 4291 | 12 | 12 | no | yes | conference rows; membership via `TeamSlots` |
| `Team[]` (conference slots) | 2477738738 | 6336 | 21 | 6–10 rows used | 20 slots | no | target of `Conference.TeamSlots` `[carousel §1f]` |
| `SeasonInfo` | 3123991521 | 4141 | 1 | 1 | no | no | THE calendar/stage singleton (59 fields) |
| `JobOpening` | 263453863 | 4151 | 408 | **0 in all three** (next = 0/235/251) | no | no | carousel job openings; live only during season weeks ~15–20 |
| `JobOpening[]` | 2358764614 | 4711 | 1 | 1 | arr | no | master list target of `StaffHiringEval.JobOpenings` (second `JobOpening[]` uid 738456991 exists) `[inv]` |
| `StaffPersonContractOffer` | 674348040 | 4298 | 804 | 1 junk row | no | no | carousel candidate offers; live only in-window |
| `StaffPersonContractOffer[]` | 4119397260 | 5180 | 408 | 0 | 6 slots | no | per-opening ordered candidate list (decoy uid 1063701971 cap 1) |
| `CoachTransactionHistoryEntry` | 2701814500 | 4271 | 300 | 1 / 135 / 103 | no | no | ★ persistent carousel event log — best post-hoc coaching-change source |
| `MySchoolTrackingTable` | 349376083 | 4218 | 138 | 138 | no | no | per-school motivation grades (CoachPrestigeGrade, CoachStabilityGrade, …) |
| `LeagueSetting` | 87558994 | 4310 | 4 | record 0 used | no | yes | league settings (CoachFiring, CoachXPSpeedSetting, IsRecruitFlippingEnabled, …) |
| `SchoolOffer` | 3367540198 | 4108 | 138 | 0 | no | no | per-team offer/interest snapshot {Team, HasOffer, OfferType, InterestLevel, AdjustedOVR, …} — empty in all sampled saves |
| `StaffPerson[]` | 234515779 | 6332 | 138 | 138 | 16 slots | no | per-school staff lists (contents unsampled — UNVERIFIED) |
| `RecruitSummaryEntry` | 3883582324 | 4184 | 640 | 0 | no | no | {Recruit, UserEntity, TransactionUpdate} |
| `Story` | 53507767 | 4277 | 250 | 19 (QQ2b) / 0 (QQ2) | no | yes | news items; purged in offseason — NOT a reliable history source |
| `SchoolPipelineInfluence` | 4261714800 | 4306 | 1500 | 1368 used (QQ) | no | no | 10 pipeline rows per school {Pipeline, InfluenceLevel, InfluenceValue} |
| `SchoolPipelineInfluence[]` | 3284177001 | 5919 | 138 | 138 | 10 slots | no | Team.SchoolPipelineInfluenceList target |
| `Franchise` | 2226370608 | 4553 | 1 | 1 | no | no | dynasty root: `LeagueID` (dynasty identity key), Transfers, RecruitingClassPlayers, SeasonInfo… |
| `StaffHiringEval` | 1794614061 | 5171 | 1 | 1 | no | no | carousel engine module (JobOpenings list, offer loop tunables) |
| `CoachRetirementEval` | 3236482084 | 4451 | 1 | 1 | no | yes | retirement engine + un-retirement lists |
| `CoachRetirementEvalInfo` | 3489055009 | 5945 | 1 | 1 | no | no | retirement tunables (RetirementAgeThreshold 65 …) |
| `CoachManager` | 1668651075 | 4444 | 1 | 1 | no | no | coach lifecycle functions (SignCoach, RetireCoach, …) |
| `CoachTalentEffects` | 2084066789 | 4264 | 138 | 138 | no | no | pre-resolved per-team coach-ability effects (recruiting boosts, transfer retention) |
| `ProspectInteraction` | 3021228601 | 4260 | 3700 | 0 | no | no | user-team scouting state per recruit |
| `ActiveRecruitingPitch` | 1559900276 | 4190 | 9380 | 0 | no | no | pitch instances {Pitch, Intensity} |
| `ActiveRecruitingPitch[]` | 3826510315 | 5790 | 4830 | 0 | arr | no | per-target pitch arrays — pool can be EXHAUSTED (`[web §5a, 1SRC]`) |
| `ActiveVisitInfo` | 3093586546 | 4176 | 4830 | 0 | no | no | scheduled visits {Activity, WeekNumber, WeekType} |
| `RecruitingActionFeedbackEntry` | 2349105625 | 4207 | 8960 | 0 | no | no | user-board feedback rows |
| `LeavingPlayer` | 1418279587 | 4158 | 3800 | 0 (QQ) | no | no | UNVERIFIED: players leaving (transfer/graduation) staging table |
| `Recruit[]` | 1611551904 | 4976 | 1 | 1 | arr | no | single-row array over the recruit class — UNVERIFIED which Franchise field targets it (candidate: `Franchise.RecruitingClassPlayers`) |

\* QQ2b Recruit count 3467 from `[diff §3]`.

QQ/QQ2/QQ2b non-empty counts and free-list heads: `[dump §1]`, `[diff §2.4]`, `research/dumps/*/scan.json`.

## 4. Deep annotations by domain

### 4.1 Recruiting

- **`Recruit`** — 15 fields; commitment state machine lives here (`RecruitStage`, `RecruitStageAdvance`,
  `CommitScore`, `TopSchoolsList`, `TotalScholarshipOffers`, `Class`, ranks, `QualityModifier`). Full schema,
  enums and live value distributions in doc 04 §2. Row 0 is a junk `Invalid` sentinel in every save. `[dump §2]`
- **`RecruitTarget` / `UserRecruitTarget`** — one row per (school, recruit) pursuit. UserRecruitTarget =
  same 20 fields + `IsFavorite` + two feedback array refs; user board slots point into it (confirmed live:
  RT[] row 43 = LSU = the user school held 31 UserRecruitTarget refs). Boards are **wiped between cycles**
  (0 rows in both preseason saves). `[dump §4][schema §3]`
- **`RecruitingBoard`** — `{Recruits: ref → RecruitTarget[], RecruitingHoursTotal/Assigned/Processed (0–4095)}`;
  reached via `Team.RecruitingBoard`. Hours observed 350 at preseason. `[dump §4]`
- **`ProspectTargetSchool` pools** — pool A (41010 = 10 × 4101 recruits) serves TopSchoolsList in all sampled
  saves; pool B (35000) never referenced by sampled slots but shows `nextRecordToUse` 23589 in later saves —
  purpose UNVERIFIED. Validate slot refs against the resolved table's tableId. `[dump §3][diff §3]`
- **`Player`** — recruits and rostered players share it; a recruit's Player row has `TeamIndex = 255`.
  282 fields live (288 in schema); the slow read — use projections. `[dump §9]`
- **`ProspectInteraction`** (cap 3700, empty at sampled moments) — user scouting: `{Recruit, Team,
  TimesScouted, UnlockedIntelBitfield, IsDevTraitUnlocked, HasOfferedScholarship, IsVisitScheduled,
  VisitActivityType, VisitWeekNumber, VisitWeekType}`. `[web §5a, 2SRC]`
- **`SchoolOffer`** (cap 138, empty in all sampled saves) — `{AdjustedOVR, EstimatedPlayerDepth, HasOffer,
  InterestLevel, OfferInterestLevel, OfferType, Team}`; likely UI-facing snapshot (UNVERIFIED when populated).
  `[dump §1][web §5a]`

### 4.2 Coaching & carousel

- **`Coach`** — 632 cap / 497 in use in every save (the coach pool is conserved; movement changes rows, not
  count). 136 live fields. Full schema in doc 03. `[dump §5]`
- **`JobOpening` + `StaffPersonContractOffer` (+`[]`)** — live only during the in-season carousel window
  (weeks ~15–20). By offseason stage 2 all rows are freed; free-list heads (235/251) are the residue proving
  ~235–251 openings per cycle. Stale freed rows keep `Reason`/`Position` (aggregate value) but Team refs are
  destroyed by the free-list pointer and PrevCoach/SelectedCoach read null. `[dump §10][diff §2.4]`
- **`CoachTransactionHistoryEntry`** — 300 cap; the persistent per-coach carousel event log (survives into
  the following season; cleared/rewritten at each new carousel). THE post-hoc data source for our tool.
  Full treatment in doc 03 §10. `[dump §6]`
- **`StaffHiringEval`** (singleton) — carousel engine: `JobOpenings: JobOpening[]`,
  `OutstandingStaffPersonOffersList`, CPU offer-loop tunables, lifecycle handler functions. `[schema §2][web §6]`
- **`StaffHiringTuning`** — 120 carousel dials (MaxJobCandidates=6, firing thresholds, poach thresholds,
  contract-points economy). `[schema §2]`
- **`CoachRetirementEval` / `CoachRetirementEvalInfo`** — retirement engine incl. un-retirement lists
  (`CoachesReturningThisYear/AfterOneYear/...: Coach[]`) and tunables (`RetirementAgeThreshold` 65,
  `RetirementReturnEnable` false). `[web §6][schema §2]`
- **`CoachManager`** — function surface only (SignCoach, RetireCoach, UnRetireCoach, AgeCoach,
  ExtendContract, DeleteStaffPerson, ProgressStaffPersonContract, HandleComebackCoaches,
  UpdateCoachContractStatus). `[web §6]`
- **`CoachTalentEffects`** (138 rows, one per FBS school) — pre-resolved coach-ability effects with direct
  recruiting relevance: `Recruiting_InfluenceBoost_Start[8]`, `Recruiting_BonusHours[8]`,
  `PlayersLeaving_LessTransferChance[8]`, `ProgramPoints_DecreaseRiskOfTransfer`,
  `CoachCarousel_IncreaseCoachPoints_NewContract`, etc. (int[8] indexed by CoachTalentPosGroup: QB=0, RB=1,
  WR_TE=2, OL=3, DB=4, LB=5, KP_ATH=6, LE_RE_DT=7). `[web §6, CODE via table-map.json]`
- Request/staging tables (cap>1, usually empty): `CreateCoachContractOffersRequest` (32),
  `CreateCoachResignContractOffersRequest` (140), `MakeContractOffersRequest` (32), `OfferManagementRequest`
  (32), `StaffHiring_IssueStaffPersonOfferRequests` (32), `FillStaffRequest` (96), `StaffMovesRequest` (32),
  `Retirement_ForceRetirementRequest` (32), `ComebackCoach` (3). `[inv][dump §1]`

### 4.3 Teams, conferences, league

- **`Team`** — 143 rows: 138 real FBS + 5 FCS pseudo-teams ("FCS East/Midwest/Northwest/Southeast/West",
  rows 30–34) which **all share TeamIndex 255** (collides with the "unassigned" sentinel — key teams by row,
  not TeamIndex). FCS rows have real HC/OC/DC coach refs (placeholder staff). `TEAM_VISIBLE` does NOT mark
  them (Air Force reads false too) — visibility semantics UNVERIFIED, don't filter on it. Earlier notes'
  "5 placeholders with blank DisplayName / TeamIndex 255" refers to the same rows. `[diff §5][dump §7][pipe §2]`
- **`Conference`** — 12 rows (schema base is literally `Enum`): `Name`, `ConferenceEnum: CollegeConferences`
  {ACC=0, BigTen=1, Big12=2, AAC=3, CUSA=4, Independents=5, MAC=6, MWC=7, Pac12=8, SEC=9, SunBelt=10,
  None=13, DefunctConference=14, Invalid_=255}, `TeamSlots: Team[]`, divisions/championship/scheduling
  config. Membership = walk `TeamSlots` (there is NO Conference field on Team). The user's dynasty has custom
  realignment and one empty-name conference row — never hardcode compositions. `[schema §8][dump §7]`
- **`LeagueSetting`** — record 0; 141 fields; verified values: `CoachFiring='ON'` (enum ON/CPU_ONLY/OFF — if
  OFF there are no carousel firings!), `CoachXPSpeedSetting` (CoachExperienceSpeed Slowest..Fastest=4),
  `IsRecruitFlippingEnabled: bool`, `SkillLevel='HEISMAN'`, `FranchiseStyle='Classic'`. Every setting has a
  paired `*Description` string. `[dump §12]`
- **`Franchise`** (singleton, 49 members) — dynasty root object: **`LeagueID` (numeric, stable per dynasty —
  the key for our local DB)** `[pipe §2]`; `Teams/FCSTeams/HighSchoolTeams: Team[]`;
  `RecruitingClassPlayers: Recruit[]`; **`Transfers: Recruit[]` = the transfer-portal master list**;
  `RecruitingClassCoaches/FreeAgentCoaches/RetiredCoaches/DraftClassCoaches/HallOfFameCoaches: Coach[]`;
  `SeasonInfo`, `LeagueSetting`, `RecruitManager`, `FreeAgents/RetiredPlayers: Player[]`. `[schema §3]`
- **`MySchoolTrackingTable`** — 138 rows × 36 fields; ten motivation LetterGrades (incl. CoachPrestigeGrade,
  CoachStabilityGrade), ten positional ProPotentialGrade*, plus raw scores (AthleticFacilitiesScore,
  BrandExposure counters, ChampionshipContender ranks) and PlayingStyle ref tables. `[dump §8][schema §6]`

### 4.4 Calendar & singleton state

- **`SeasonInfo`** — the calendar/stage singleton; full treatment in doc 05.
- Offseason/season event singletons exist for nearly every phase transition (`OffseasonStartEvent`,
  `OffseasonWeekStartEvent`, `PreseasonStartEvent`, `PostSeasonWeekStartEvent`, `RecruitingStartEvent`,
  `EncourageTransfersStart/EndEvent`, `AddToTransferPortalEvent`, `EarlySigningDayStartEvent`,
  `NationalSigningDayStartEvent`, `CoachCarouselStartEvent`, …) — all cap-1 plumbing rows with no persistent
  payload of interest. `[dump §1][inv]`

### 4.5 History & news

- **`CoachTransactionHistoryEntry`** — see §4.2 and doc 03 §10.
- **`Story`** (news): 34 fields incl. `Tag` (full sentence), `Header`, `Category`, `Team`, `Character1..4`
  refs, `SeasonYear/Week/CurrentStage`, `IsTopStory/IsBreaking/IsNew`. Purged in offseason (0 rows at QQ2) —
  not a history source. `[dump §13]`
- `PlayerPositionChangeHistoryEntry` (742 cap), `DraftPickTransactionHistoryEntry` (250 cap),
  `TransactionHistoryManager` + `TransactionHistoryEntry` (generic base: OldTeam, NewTeam, SeasonStage,
  SeasonWeek, SeasonYear, TransactionId). `HistoryEntry` big pool (38,400 cap, 0 used at year 0). `[inv][schema §11]`
- `LeagueHistoryAward` (750), `LeagueHistoryConferenceChampion` (330), `TeamHistoricSeriesYear` (4140, 138
  used) — league record-book tables. `[inv]`

### 4.6 Pipelines

- **`SchoolPipelineInfluence`** — 1500 cap (10 slots × ~143 teams + spares; 1368 used at year 0):
  `{Pipeline: Pipeline enum (43 regions), InfluenceLevel: PipelineInfluenceLevel {Unrecognized=0,
  NicheInterest=1, Respected=2, Popular=3, HouseholdName=4, CulturalPillar=5, Invalid=7},
  InfluenceValue: int 0–1000}`. Placeholder-slot noise: `Unrecognized` + value 0. `[schema §7][pipe §2][inv]`
- Reached via `Team.SchoolPipelineInfluenceList → SchoolPipelineInfluence[]` (10 refs/row). `[pipe §2]`
- The Dynamic Pipeline Tool's write (rewriting InfluenceLevel/Pipeline/InfluenceValue on 980 of 1500 rows)
  round-tripped through the game cleanly — proof these rows are game-honored writable. `[diff §4]`

## 5. Largest tables by capacity

Top of the size league table (name / uid / tableId / cap / non-empty at year 0) — the giants are stats,
visuals and recruiting pools. `[inv]`

| Table | uid | tableId | cap | non-empty (QQ) |
|---|---|---|---|---|
| GameDefensiveStats | 698792022 | 4177 | 45600 | 0 |
| ProspectTargetSchool (A) | 3789266353 | 5840 | 41010 | 41000 |
| HistoryEntry | 3363303785 | 6379 | 38400 | 0 |
| ProspectTargetSchool (B) | 3843719174 | 5841 | 35000 | 0 |
| GameOffensiveStats | 3937354187 | 4110 | 27360 | 0 |
| Player | 1612938518 | 4244 | 16500 | 16257 |
| GameOLineStats | 2067273102 | 4129 | 16416 | 0 |
| CharacterVisuals | 1429178382 | 4222 | 16000 | 3013 |
| CharacterGameplay | 3811111829 | 5798 | 16000 | 0 |
| UnpublishedGameStats | 1307057589 | 4239 | 14960 | 0 |
| PlayerGoal[] | 2703187747 | 5725 | 11730 | 0 |
| SeasonDefensiveStats | 314624969 | 4220 | 11100 | 0 |
| ActiveRecruitingPitch | 1559900276 | 4190 | 9380 | 0 |
| RecruitingActionFeedbackEntry / RecruitingActionBonus | 2349105625 / 2498877428 | 4207 / 4242 | 8960 | 0 |
| PlayerAward | 657983086 | 4249 | 8505 | 600 |
| Recruit | 1873209313 | 4269 | 7600 | 4101 |
| ProspectTargetSchool[] | 2332540366 | 5842 | 7600 | 4100 |
| RecruitTarget | 59043175 | 4288 | 4870 | 0 |
| ActiveVisitInfo / ActiveRecruitingPitch[] | 3093586546 / 3826510315 | 4176 / 5790 | 4830 | 0 |
| LeavingPlayer | 1418279587 | 4158 | 3800 | 0 |
| ProspectInteraction | 3021228601 | 4260 | 3700 | 0 |

(CharacterVisuals uid 1429178382 also independently reported by the franchise-mcp-server listing `[web §7, 1SRC]`.)

## 6. Duplicate-name groups

Top collision groups (count × name) — the reason uniqueId resolution is mandatory: `[inv]`

```
179× Player[]        143× TeamHistoricalData   118× Transition      78× Stage
 78× Transition[]     36× PlayerStatRecord      31× ScheduleKnownGame[] / TutorialInfo / ScheduleStructureEntry[]
 30× ScheduleNeutralStadium[]                   24× int[]            17× TutorialInfo[]
 13× TeamHistoricSeriesYear[]                    12× Scheduler.RelativeDateTime
  9× Team              9× Team[]                 9× ReSignResponseText[]
  8× PlayerPositionLookupTable                   5× SeasonGame        2× Coach, 2× ProspectTargetSchool …
```

`SeasonGame` note: 5 tables share the name; the real games table is uid 4049338978 (tableId 6330, cap 983,
934 used — one row per scheduled game with HomeTeam/AwayTeam refs, scores, SeasonWeek/SeasonWeekType). `[inv][web §6]`

## 7. Engine-plumbing taxonomy

Roughly 2,000 of the 2,269 tables are single-row engine plumbing rather than data. Categories (with examples
from the inventory `[inv]`, schema roles from `[schema §1]`):

| Category | Naming pattern | Count scale | Examples | Relevance |
|---|---|---|---|---|
| Events | `*Event` | ~315 schema subclasses | `CoachCarouselStartEvent`, `AddToTransferPortalEvent{Recruit}`, `RecruitSignedEvent{Recruit}` | signal names only; no persisted payload observed |
| Reactions | `*Reaction` | ~495 schema subclasses | `CoachCarousel_PostSeasonWeekStartReaction`, `RecruitingEvalTransferAddedToPortalReaction` | reveal engine flow/timing |
| Transactions | `*Transaction` | 24 | `RecruitingAdvanceBoardsTransaction`, `ProcessEndOfRecruitingCycleTransaction` | in-memory week-advance jobs, not logs |
| Managers/Evals | `*Manager`, `*Eval` | dozens | `RecruitManager`, `StaffHiringEval`, `CoachRetirementEval`, `TransactionHistoryManager` | singletons; some hold real data (JobOpenings list, tunables) |
| UI flows | `FranchiseServer_*Flow`, `DynastyServer_*Flow` | ~70 | `FranchiseServer_StaffHiringFlow`, `DynastyServer_RecruitingBoardFlow` | irrelevant to data |
| Requests | `*Request` | dozens, cap 32–140 | `CreateCoachContractOffersRequest` | staging buffers, usually empty |
| Tuning | `*Tuning`, `*Tunables` | ~10 relevant | `StaffHiringTuning`, `RecruitingTunables`, `VisitTunables`, `NewsTuning` | readable dials — see docs 03/04 |

## Sources

- `research/dumps/tables-inventory.json` (full 2,269-table inventory of DYNASTY-QQ; summarized here via
  `research/dumps/inventory-relevant.txt` generated during synthesis)
- `research/notes-save-dump.md` + `research/dumps/QQ|QQ2|QQ2b/*.sample.json`, `research/dumps/*/scan.json`,
  `research/dumps/QQ2/commit-analysis.json`, `research/dumps/QQ2*/misc-checks.json`
- `research/notes-save-diff.md` + `research/dumps/save-diff.json`
- `research/notes-schema.md` + `research/schema-relevant-tables.json`, `research/schema-all-tables.txt`
- `research/notes-carousel-tool.md`, `research/notes-force-commit.md`, `research/notes-pipeline-tool.md`,
  `research/notes-jersey-tool.md`, `research/notes-web.md`
