# Event audit (post-expand) Inventory policy after the full gap expand. Camera interrupt is score-margin only (`cutInMargin`); no Signal/Ambient ownership gate. **Single inventory:** [`EventCatalog`](../IdleSpectator/Events/EventCatalog.cs) (partials under `Events/Catalogs/`). Nested domains: `Status`, `Happiness`, `WorldLog`, `Trait`, `Combat`, `Spell`, … Feeds/patches register from those dials; `InterestDirector` only ranks candidates. ## Dials | Dial | Role | |------|------| | `CreatesInterest` | Whether a live id may register at all | | `EventStrength` | Base contribution to `TotalScore` (interrupt via +`cutInMargin`) | | `Completion` | Hold-until-complete kind | | `MaxWatch` | Hard cap (class defaults in `scoring-model.json`) | | `EventReason` | Orange dossier sentence | ## MaxWatch class defaults | Class | Seconds | JSON field | |-------|--------:|------------| | Moment / FixedDwell | 15 | `maxWatchMoment` | | Status | 30 | `maxWatchStatus` | | Grief | 45 | `maxWatchGrief` | | Combat | 60 | `maxWatchCombat` | | Epic world | 50 | `maxWatchEpic` | Peer rotate / soft cut on EventLed floors at `minCameraDwell` (15s). Score-margin interrupts bypass that floor. Ambient / Character fill is exempt - events may take the camera immediately. ## Sources (wired) | Source | Primary owner | Reason factory | Notes | |--------|---------------|----------------|-------| | WorldLog | `InterestFeeds.OnWorldLogMessage` | catalog / EventReason | Strength from `EventCatalog.WorldLog` | | Happiness | `IngestHappiness` | `EventCatalog.Happiness` + EventReason | Prose must match game call sites - see [event-prose-audit.md](event-prose-audit.md) | | Status | `OnStatusChange` | EventReason.Status | `drowning` CreatesInterest=true, strength ~50; notable via CharacterSignificance | | Scanner combat | WorldActivityScanner | EventReason.Fight / Battle | Completion CombatActive; dials `EventCatalog.Combat` | | War | WarEventPatches + WarInterestFeed.Tick | war type labels | | | Plot | PlotEventPatches + PlotInterestFeed.Tick | `EventCatalog.Plot` | | | Relationship | RelationshipEventPatches + happiness lovers | EventReason.* | | | Trait | TraitEventPatches | EventReason.Trait | Spawn window filters routine traits | | Building | BuildingEventPatches | EventReason.Building* | Eat/damage/falls | | Boat | BoatEventPatches | EventReason.Boat | | | Book | BookEventPatches | `EventCatalog.Book` sentences | | | Era / Meta | MetaEventPatches | EventReason.MetaNew / era labels | | | Spell | CombatActionLibrary.tryToCastSpell | EventReason.Library | Ambient CreatesInterest=false except spectacle ids | | Power | PlayerControl.clickedFinal | EventReason.HumanizeId | Spectacle ids create interest | | Decision | setDecisionCooldown | EventReason.Library | IsCameraWorthy filter | | Item | ItemManager | EventReason.Library | Legendary CreatesInterest | | Gene | Subspecies.mutateFrom | EventReason.Library | Ambient CreatesInterest=false | | Phenotype | generatePhenotypeAndShade | EventReason.Library | | | World law | WorldLaws.enable / toggle | EventReason.HumanizeId | Location-only | | Biome | catalog ready | EventReason.HumanizeId | Ambient CreatesInterest=false; emit via power terraform path | | Subspecies trait | SubspeciesManager biome hooks | EventReason.Library | | | Character fill | InterestDirector.TryCharacterFill | empty Label | Only when no pending EventLed | ## Ambient statuses (intentional off) `festive_spirit`, `laughing`, `singing`, `sleeping`, `handsome_migrant` - CreatesInterest=false. ## Same-moment ownership Prefer typed feeds over WorldLog when both fire (relationship / status / combat). Registry Upsert merges same key and refreshes `LastSeenAt` for sticky combat/status/grief. ## Interrupt / hold / grace 1. Instant cut when `next.TotalScore >= current + cutInMargin` (no settle; ignores min dwell). 2. Ambient fill: any EventLed may take the camera immediately (no `minCameraDwell`). 3. Else hold while `InterestCompletion.IsActive` and under MaxWatch (moments floor to `minCameraDwell`; combat uses class 60s). 4. Soft peer rotates on EventLed only after `minCameraDwell` (15s). 5. Quiet grace 6s: still-worth-watching filter, then Character fill with empty reason. ## Mutation gap triage `mutation_discovery` refreshes `.harness/mutation_gaps.tsv`. Open rows are unexplained Wire candidates only. False positives (clear/load/UI/FX/getters) and covered-by-primary paths are filtered or listed in `AlreadyWired`. Library fields are inventory-complete via catalogs / activity / WorldLog (`mutation_libraries.tsv` notes).