# Life-saga roster Dynamic top-10 cast of interesting lives (MCs). Owns the dossier rail and soft camera bias. Chronicle stays a history book and never drives the camera. Short combat/love/war arcs stay in [`StoryPlanner`](../IdleSpectator/Story/StoryPlanner.cs) as chapter beats. Durable observed facts live in [`LifeSagaMemory`](../IdleSpectator/Story/LifeSagaMemory.cs) and survive roster churn. AFK caption is a **character beat**: Identity (who) + Beat (live tip) + Context (spine or stake). [`CaptionComposer`](../IdleSpectator/Story/CaptionComposer.cs) merges saga identity into the live caption without baking titles into `InterestCandidate.Label`. [`SagaProse`](../IdleSpectator/Story/SagaProse.cs) owns all player-facing relation/stake English. ## Ownership | Concern | Owner | |---------|--------| | Top-10 MCs, diversity, Prefer | `LifeSagaRoster` | | Durable observed facts | `LifeSagaMemory` | | Adaptive presentation model | `LifeSagaPresentation` | | Player-facing saga/caption English | `SagaProse` | | Identity + Beat + Context caption | `CaptionComposer` → `WatchCaption` | | Hover Cast/Legacy depth | `LifeSagaViewController` + `LifeSagaPanel` | | Rail icons / Prefer click | `LifeSagaRail` | | Camera read-pause lease | `InterestDirector` | | Short climax → aftermath → epilogue | `StoryPlanner` (thinned) | | Context spine (`Kind · Phase`) | `StoryPlanner.FormatSpineLabel` (via ContextLine) | | Full history | Chronicle / Lore | ## Admission Live discovery (no tip-string allowlists): - Game favorite, king, city leader, kills/renown floors (`InterestScoring.IsNotable`) - Pack alpha, clan chief, army captain, active plot author, founder, species singleton Standing is recomputed from live roles each refill. Heat comes from chapter stamps / featured tips and decays with idle time. Each slot keeps its original admission reason even when its live role later changes. Hard-arc admissions also retain the arc kind and chapter context that brought the life onto the roster. ## Dynamic top-10 - Cap stays 10; order follows Effective = Standing + Heat + pin bonuses. - Prefer and WorldBox favorites are hard pins and fully count toward Cap. - Admission-role units always compete on the periodic scan. - Non-admission "nobodies" challenge Cap only via hard-arc chapter stamps (Combat / War / Plot / Love / Grief). - Hard-arc admit heat escalates with climax age (re-stamped while the arc holds) so a prolonged stranger duel can displace dull Cap slots and light Active chrome. - Soft `NoteFeatured` heats existing MCs only. - Newcomers need a small challenger margin over the weakest non-pin so the rail does not thrash. ## Camera (soft) - No rail camera lock. Prefer is a toggle soft-favorite for idle scoring. - Score ladder: crisis ownership > active short-arc ownership > Prefer soft > MC soft > MC cast > CausalHeat. - `nearTieEpsilon` (8) picks #1 for ordinary gaps; Prefer/MC/cast may still win within `sagaNearTieEpsilon` (28). - Soft ranks: Prefer > CrossMC (>1 roster MC) > MC > MC cast (lover/friend/kin/earned rival of a roster MC). - Tips that touch two or more roster MCs get `sagaCrossMcBonus` (~11); scoring touch inventory matches rail Involved ids. - Sticky combat/war/plot maintain heats both MCs early when two roster principals share the tip. - Mid-fight follow uses Prefer/MC/cast soft weight in `CombatFocusWeight` (spectacle floors can still win). - Ambient / character-fill yields immediately to Prefer/MC tips (not vs crisis/combat/short-arc holds). - Soft-fill quiet still suppresses anonymous crumbs; Prefer/MC tips may break quiet. - Glyph hover acquires a camera read-pause lease: feeds/story/roster continue, but selection and focus repair are deferred until release. ## Character beat caption Always-on AFK chrome (no Dossier/Saga tabs): | Row | Source | MC | Nobody | |-----|--------|----|--------| | Identity | `CaptionComposer` | `Name · Title` (real roles only; else species/job) | `Name (Species/Job)` | | Beat | owned tip + `SagaProse.BeatClause` | tip enriched with one relation clause | tip as today | | Context | muted | spine if live short-arc; else unresolved stake hitch (omits kill/role/founding under love/rest tips; RoleChange that echoes Identity always omitted) | spine only | Hard rule: saga titles and stake slogans never enter `InterestCandidate.Label`. Selection/`identity_filter` stay event-first. Beat other resolves `RelatedId` then `PairPartnerId` (no living-name parse). Status banners still own/suppress Beat; Identity + Context keep updating. Hover panel tracks the hovered MC; caption Identity/Beat/Context always track camera focus. ## Rail UX - Up to 10 slots with live inspect-UI sprites (refreshed ~3x/sec for animation frames). - Egg forms and tiny/blank atlas crops fall back to the species icon (letter last). - Active chrome = camera follow MC; Involved chrome = other tip-touched MCs (subject/related/follow/pair/short-arc cast only - not mass `ParticipantIds`). - Prefer uses a star pip / distinct border. - Click toggles saga Prefer only (does not mutate WorldBox unit favorite; does not pin a Saga subject). - Rail sits at the top of caption chrome (no tabs). - Hovering a glyph opens Cast/Legacy depth (`LifeSagaPanel`) and pauses camera switching. - Leaving the glyph hides the panel, restores dossier body rows, and releases the pause lease. - Hover never swaps the orange tip to the hovered life. - Panel is Cast + Legacy only (caption already owns name · title; no portrait / stake chrome). - Cast budget is 8 (two rows); Legacy prefers turning points over Cast-echo kin crumbs. - No Evidence stats dump. No Open Lore button (press L). - ParentChild is capped (one named beat, or a lineage summary when there are 3+ children). - Living Cast lover/friend/kin are not repeated as Legacy relationship lines. - Legacy lines may prefix the world date (`Month Year · beat`). - Context spine (`Kind · Phase`) is hidden when the orange beat already names the same kind and phase is Climax. - Never show live task/status/trait rows or call a live attack target a rival. ## Saga prose `SagaProse` is the single voice owner. Evidence drives copy; enum names never appear in UI. Relation classes: Bond, Friend, Kin (Parent/Child/Heir/Packmate/Kin), Foe (Old Foe/War Enemy/Plot Enemy/Blood Foe), Plot Partner, Grief. Ban list (player-facing): `earned rival`, `Earned a rival`, `Rivalry with`, `saga hero`, `fellow saga hero`, `War foe`, `Plot ally`, `Likely successor`, `A life in motion` on Identity, mood wallpaper stakes. Capitalization: - Identity titles / Cast labels: Title Case (`Pack Alpha`, `Old Foe`, `Best Friend`) - Beat clauses after ` · `: lowercase start - Stake / Legacy: Sentence case - Unit names and owned tip body: leave as-is ## Opposition facts (memory) Notable only: - Living rematches (≥ `sagaRivalEncounterThreshold`, default 3) while both are alive (sticky combat hook; kill/death do not count). - Kin blood (`killed_kin` / `kin_slain`). - War / plot opposition (opposing principals on the same war/plot tip). - MC↔MC living rematches earn rivalry one encounter sooner; a single MC kill is crossover Legacy, not automatic RivalEarned. - Cast shows living credible foes only; weak kill-cycle `repeated_encounters` facts are pruned. - Heir cast label only when a game-authored heir API probe succeeds (`Heir`, not `Likely successor`). - Unresolved `WarJoin` / `PlotJoin` Others fill Cast as `War Enemy` / `Plot Partner` when still living. - Crown / Combat / Intrigue / Pack / Bond lenses fill remaining Cast slots with live family peers (`Packmate` for Pack, `Kin` otherwise) after lover/friend/parents/children/heir/foe. ## Stake - Primary stake: strongest unresolved war/plot/rival/role/founding/grief (and McCrossover beats of those kinds). - Fallback stake when nothing stronger exists: unresolved `HardArcCombat`, open `BondFormed`, or McCrossover `Kill`. - War/plot prose names the opposing principal and kingdom/plot display when known (`Still at war with…`). - Role rises (king/leader/alpha/clan chief/army captain) emit `RoleChange` from live roster deltas. - Current role/founding facts live in Identity and are omitted from Context, Legacy, and rail tooltip stakes when they would only repeat the title. - Titleless MCs (hard-arc, no crown) keep species/job Identity; Context stake hitch is required when memory has unresolved facts. ## Cross-MC moments When subject and other are both roster MCs, facts are flagged `McCrossover` (named stake/legacy prose + heat on both). Prose stays plain (`Bound with X`, `Slew X`) - no “saga hero” wording. Both rail glyphs light (Active + Involved) when the current tip touches multiple MCs. ## Soft-fill quiet (AFK hygiene) After hard story/crisis closers, soft-fill quiet suppresses soft-life crumbs and short interrupt FX (`stunned` / `invincible`). `FamilyPack` does not break quiet (ambient cluster fill). Combat / war / plot / outbreak / earthquake / story beats / epic strength / Prefer/MC still cut in. Quiet can refresh briefly when a soft crumb ends (bounded). ## Performance (idle) - Roster role refresh runs on the ~3.5s amortized scan (not every frame). Soft heat does not force a world Refill. - Dirty Prefer / membership changes re-rank existing slots only; full world admission stays on the timed cadence. - World admission walks ~260 units/frame, then BuildSlots only the best ~2× Cap challengers (skips when pins fill Cap). - Dossier `Relayout` runs only when chrome geometry changes; leaving hover restores dossier rows once. - Live portrait tile refresh is ~5 Hz; rail live sprites are only for the watched glyph (others use species icons). - Rail face animation refreshes the Active glyph ~1/s; other glyphs stay static between structure changes. - Plot join memory records the joiner only; full member snapshots stay on create/finish/cancel. - RelationEvidence caches invalidate on memory revision + live lover/friend change. - Hitch probe: harness `hitch_probe` / load save via `load_save_slot` (slot 2 = Box of Magic). Optional `.harness/autoload_slot`. ## Session - `StoryPlanner.Clear` does not wipe the roster or saga memory. - Lore browse / brief idle-off keeps the roster and memory. - World replacement, map load-complete (`MapBox.finishingUpLoading`), `clearWorld`, harness batch end, and `interest_saga_clear` / `saga_session_reset` wipe roster + memory (+ `CaptionComposer.Clear`). - Bind key uses live `map_stats.name`, `current_world_seed_id`, `map_stats` identity, `_load_counter`, and map size - not world reference alone. - Same-map spectator re-enable does not clear when the bind key is unchanged. - Read-only soak dumps use `soak_probe` (or `snapshot` with `value=preserve`) and skip the batch-end wipe. ## Harness - `saga_roster_diversity` - `saga_camera_prefers_mc` - `saga_prefer_soft_bias` - `saga_wins_moderate_gap` - `saga_combat_follow_mc` - `saga_cast_soft_bias` - `saga_cross_mc_light` - `saga_cross_mc_wins_gap` - `saga_cross_mc_kill` - `saga_rival_not_single_kill` - `saga_rival_rematch` - `saga_prefer_cuts_ambient` - `saga_hard_arc_escalates` - `saga_overview_has_mc` - `saga_adaptive_dossier` (hover depth; no tabs / empty-pick) - `saga_memory_survives` - `saga_war_memory_both_sides` - `saga_plot_cast_members` - `saga_cast_kin_non_pack_lens` - `saga_stake_from_role_live` - `saga_legacy_quality` - `saga_session_reset` - `saga_hover_read_pause` - `saga_replace_on_death` - `saga_admit_roles` - `saga_replace_weaker` - `saga_rail_active_highlight` - `saga_rail_prefer_click` - `saga_soft_fill_no_pack` - `caption_character_beat` - `caption_prose_voice` See also: [story-planner.md](story-planner.md).