worldbox-observer-mod/docs/story-planner.md
DazedAnon ba58a9ff38 feat(saga): deepen session cast stakes and cut idle hitch spikes
- Keep LifeSagaSession across Clear; wipe on map load/clear with bind key
- Soft-bias Prefer/cross-MC/cast and prefer roster MCs in aftermath/recover/park
- Resolve war/plot principals plus discrete/WorldLog labels from live libraries
- Amortize roster world scans, gate Relayout, and add hitch probe/save-slot helpers
2026-07-22 14:37:36 -05:00

13 KiB
Raw Blame History

Story Planner

IdleSpectator commits to short multi-beat stories instead of channel-surfing ranked tips.

Feeds, sticky ensembles, presentability, and InterestDirector stay in place. StoryPlanner sits above the director and owns which story the next 3090s belongs to.

Short-arc board (not the dossier rail)

Hard storylines (notable duel / mass / war / plot / love / grief) still form a small watching + parked board (cap 4) for short-chapter resume. Cutting away parks a hard arc; soft anonymous scraps still end. There is no rail Commit / hard pin anymore.

  • Lore browse uses browsePause - freezes idle without StoryPlanner.Clear().
  • StoryPlanner.Clear does not wipe the life-saga roster.
  • Combat spine Kind comes from sticky/live ensemble scale + StoryArcKind, not tip Label prefixes.

Dossier life-saga rail is owned by LifeSagaRoster / LifeSagaRail (up to 10 MCs). Click toggles Prefer (soft favorite). Dossier/Saga tabs and hover preview are owned by LifeSagaViewController + LifeSagaPanel. Durable observed facts live in LifeSagaMemory (independent of ChronicleEnabled). Hover temporarily pauses camera switching without disabling Idle Spectator. See life-saga.md.

Crisis camera hold: WarFront always blocks Mass/Battle cut-ins (war_theater_hold). Disaster / outbreak signals use the same class rule while their chapter is live (crisis_theater_hold), classified via live AssetManager.disasters + catalog categories (not tip-string IndexOf).

InterestDirector is a partial class: session orchestrator + StickyMaintain + SwitchPolicy.

Harness: story_lore_pause_keeps, story_board_park_resume (short-arc park/resume via story_resume_parked), story_crisis_war, story_crisis_disaster, war_front_sticky, plus saga_* scenarios.

See also: life-saga.md, scoring-model.md, event-reason.md.

Pipeline

Feeds → InterestRegistry → StoryPlanner (boost / inject)
       → InterestVariety.Pick → InterestDirector → CameraDirector

Director still owns camera, sticky maintain, and switch margins. Planner never calls MoveCamera.

Arc model

Kind Climax Hard hold
CombatDuel sticky pair only notable pairs (2+ notables)
CombatMass Skirmish+ yes
WarFront / Plot / Love / Grief existing sticky / life yes

Phases: Climax → Aftermath → Epilogue → Done.

  • Aftermath injects on climax cold (quiet grace / follow_lost), or claims natural death_* grief.
  • Only grief / love-outcome pending tips block synthesis - cast hatch/food noise does not.
  • Injected story beats bypass FixedDwell beat hard-skip and PreferOver cast life tips while the arc is live.
  • Soft duel Mass↔Duel key flips still cold-hook once per theater anchor.
  • Epilogue once after aftermath if a living lover/friend resolves.
  • Soft anonymous duels still get aftermath tips; they do not use raised arcHoldMargin.
  • Aftermath follow, cast recovery, and epilogue pick Prefer/MC among living theater/cast candidates via LifeSagaRoster.PreferRosterUnit (never MCs outside the cast).
  • Parked-board trim drops anonymous scraps before Prefer/MC/cast arcs when over cap.

Dossier spine

While the current watch tip is the active arc's climax or story aftermath/epilogue beat, the dossier shows a muted line under the orange reason: Kind · Phase (e.g. Duel · Aftermath, War front · Climax).

Hidden when idle is off, the dossier is hidden, a status banner owns the reason row, or the camera has left the story for an unrelated tip (cast membership alone is not enough).

Love climax is outcome-only (set_lover / fallen-in-love). find_lover seeking stays camera-worthy but does not open a Love arc. Leaving a climax without aftermath ends the arc (Done).

Sticky combat reframes (Battle ↔ Duel) sync climax Kind in place via SyncActiveClimax so the spine cannot say Mass · Climax on a Duel tip.

arcHoldMargin applies only while the watch tip is the aftermath/epilogue beat. Cast life tips (parenthood, sleep) no longer keep the raised cut-in wall.

Family life chapters (just_had_child, pregnancy, …) share arc:life:family, use a longer beat cool (including world-wide happiness cool), and bleed ledger heat so the village cast cannot monopolize the next picks.

Intimacy chapters (just_kissed / shares intimacy) use arc:life:intimacy with the same soft-life cool class (pair + world) so one couple cannot keep cutting between combat tips.

Settlement finds (just_found_house / finds a home) use arc:life:home with the same soft cool (world + subject) so house crumbs cannot keep cutting between combat beats.

Kill crumbs (milestone_kill / Killed X (species) / just_killed) use arc:life:kill with the same soft cool (subject + world) so hunter kill tips cannot keep cutting between mass beats.

Courtship crumbs (fallen_in_love / smitten / find_lover seeking) use arc:life:love soft cool (subject + world + pair). Bond outcomes (set_lover) stay hotter.

Life-intent decisions (sexual_reproduction_*, decision find_lover, …) share arc:decision:intent soft cool (subject + world). Outcomes (pregnancy, child, seeking) stay hotter.

Ordinary civ construction finishes (building:complete / tents / houses) share arc:construction soft cool. Spectacle wonders stay hotter.

Soft personal status FX (taking_roots, singing, moods, …) share arc:status:fx soft cool. Danger / combat statuses stay hotter. Hatch crumbs use arc:life:hatch.

Sleep / wake / dream cycle (sleeping, just_slept, had_*dream, had_nightmare, …) share arc:life:rest soft cool so rest crumbs cannot monopolize between richer beats.

WorldLog politics meta (king_dead, city_destroyed, favorite fell, …) share arc:worldlog:meta soft cool so sticky death crumbs cannot re-monopolize.

Interrupted resume: already-cooled moment beats are not parked / not resumed after a cut-in (hatch/reproduce cannot bounce back after combat).

Story spine: aftermath tips must match the active arc CorrelationKey (no stale duel aftermath under a Mass spine). Combat Kind word follows tip Label (Battle / Skirmish / Mass / Duel).

Wiped opposing combat camps collapse to a living-side pack label at live scale (never Mass - A (n) vs B (0)).

Combat aftermath names only a dead theater partner (stands over X), else stands over the fallen. Living lover/friend fallbacks are never the fallen.

Spine Kind follows the live tip Label for combat (Duel vs Mass/Skirmish/Battle), not sticky scale-hold alone. Cold climax tips do not show · Aftermath - only the aftermath tip does. Aftermath Follow loss promotes another living cast member before follow_lost.

Harness: story_spine / story_hold_margin / story_family_variety / story_intimacy_cool / story_settlement_cool / story_kill_cool / story_courtship_cool / story_decision_intent_cool / story_decision_intent_live / story_construction_cool / story_status_fx_cool / story_rest_cool / story_resume_cooled / story_worldlog_meta_cool / combat_wiped_side / reason_life_principal (story_arc_combat, story_spine_scoped, story_aftermath_combat, story_family_variety).

Crisis chapters (Phase 4)

Parallel overlay beside short StoryArc - war / disaster / outbreak thresholds open a multi-minute chapter without thrashing when unrelated tips cut in.

Signal Enter when
WarFront live participants ≥ crisisWarParticipantMin (default 8), both sides present (peak lock alone does not enter)
EarthquakeActive / Disaster category live or EventStrength ≥ crisisDisasterStrengthMin (95)
StatusOutbreak EventStrength ≥ disaster floor

While live:

  • crisisOwnershipBoost + crisisHoldMargin on matching tips
  • Character-fill ambient is suppressed (SuppressAmbientFill)
  • Epic peers (≥ disaster floor) may still cut

On exit (signal linger / max duration / harness interest_crisis_end): inject epilogue_crisis ({a} surveys the aftermath of the crisis), then cooldown.

Disaster / outbreak chapters use a shared family anchor (disaster / outbreak), a longer linger after the last WorldLog pulse, and crisisDisasterCooldownSeconds (default 120) armed when the closer injects so stacked tornado tips cannot double-close.

War chapters stamp a kingdom theater pair. Local Mass/Battle on that pair keeps the chapter warm and cannot steal the War tip (war_theater_hold). Crisis closers clear short-arc spine and suppress combat task detail crumbs under the orange reason.

Short-arc related epilogue is skipped when a crisis closer owns the exit. When a short-arc war linger injects while a war crisis is live, the crisis quiet-closes (no second epilogue_crisis). Harness batch end and interest_story_purge_leftovers drop leftover crisis closers so free AFK does not inherit a fake ending. After hard story/crisis ends, softFillQuietSeconds suppresses soft-life crumbs, short interrupt FX (stunned / invincible), and character-fill ambient briefly. FamilyPack does not break that quiet window (see life-saga.md).

Selection discipline

  • InterestVariety.Pick takes #1 when score gap ≥ story.nearTieEpsilon (default 8).
  • Prefer / MC / MC-cast tips may still win when the gap is below story.sagaNearTieEpsilon (default 28).
  • Near-ties among peers still Prefer > MC > cast, else roll among top-3.
  • Causal heat + life-saga Prefer/MC/cast soft bias + cross-MC bonus add into RecalcTotal.
  • See life-saga.md for camera / rival / dual-rail contracts.

Knobs

scoring-model.jsonstory block (loaded by InterestScoringConfig.Story).

Catalog policy ids live under event-catalog.jsonstory (aftermath_survivor, aftermath_mourner, aftermath_war_linger, epilogue_crisis, …).

Harness

Scenario Proves
story_crisis_war WarFront → crisis active → epilogue_crisis
story_crisis_disaster EarthquakeActive → crisis → epilogue_crisis; cool blocks reopen
story_aftermath_combat duel cold → aftermath tip
story_aftermath_partner_truth aftermath never names living lover as fallen
story_aftermath_cast_noise hatch noise pending still gets aftermath
reason_duel_principal bystander Follow cannot own duel reason
reason_life_principal Follow hijack cannot keep intimacy Label
story_intimacy_cool just_kissed cools; peer wins next pick
story_settlement_cool finds-a-home cools; peer wins next pick
story_kill_cool kill crumbs cool; peer wins next pick
story_courtship_cool smitten/seeking cool; peer wins next pick
story_decision_intent_cool reproduce/find-lover decisions cool as a class
story_decision_intent_live live EmitDecision path cools intent class
story_construction_cool tent/house finishes cool; peer wins
story_status_fx_cool taking_roots FX cool; peer wins
story_rest_cool sleep/wake rest cycle cools; peer wins
story_resume_cooled cooled soft tip does not resume after cut-in
story_worldlog_meta_cool king_dead cools; peer wins next pick
combat_wiped_side wiped camp never prints vs (0)
story_aftermath_war war sticky cold → aftermath; no dual crisis closer
story_crisis_hygiene auto-opened war crisis + short-arc linger; purge leaves no epilogue leak
story_near_tie large gap always picks #1
story_arc_combat climax → aftermath ownership
story_arc_preempt_resume epic cut then fresh scrap aftermath
story_ledger_revisit featured unit wins near-tie
./scripts/harness-run.sh --repeat 3 story_crisis_war
./scripts/harness-run.sh --repeat 3 story_crisis_disaster
./scripts/harness-run.sh --repeat 3 story_aftermath_war
./scripts/harness-run.sh --repeat 3 war_front_sticky
./scripts/harness-run.sh --repeat 3 story_aftermath_combat
./scripts/harness-run.sh --repeat 3 story_aftermath_partner_truth
./scripts/harness-run.sh --repeat 3 story_aftermath_cast_noise
./scripts/harness-run.sh --repeat 3 reason_duel_principal
./scripts/harness-run.sh --repeat 3 story_near_tie
./scripts/harness-run.sh --repeat 3 story_arc_combat
./scripts/harness-run.sh --repeat 3 story_ledger_revisit
./scripts/harness-run.sh --repeat 3 story_kill_cool
./scripts/harness-run.sh --repeat 3 story_courtship_cool
./scripts/harness-run.sh --repeat 3 story_decision_intent_cool
./scripts/harness-run.sh --repeat 3 story_decision_intent_live
./scripts/harness-run.sh --repeat 3 story_construction_cool
./scripts/harness-run.sh --repeat 3 story_status_fx_cool
./scripts/harness-run.sh --repeat 3 story_rest_cool
./scripts/harness-run.sh --repeat 3 story_resume_cooled
./scripts/harness-run.sh --repeat 3 story_worldlog_meta_cool
./scripts/harness-run.sh --repeat 3 combat_wiped_side

Files

  • IdleSpectator/Story/StoryPlanner.cs - short-arc ownership, cold-hook, inject, spine, crisis
  • IdleSpectator/Story/LifeSagaRoster.cs - durable MC cast + Prefer + chapter stamps
  • IdleSpectator/Story/LifeSagaOverview.cs / LifeSagaRail.cs - saga hover + rail
  • IdleSpectator/Story/CrisisChapter.cs - parallel crisis chapter state
  • IdleSpectator/Story/CausalHeat.cs - decaying cast heat
  • IdleSpectator/Story/StoryReason.cs - presentable aftermath Labels
  • IdleSpectator/WatchCaption.cs - dossier Kind · Phase spine row