# Event audit (A/B layers) **Layer B (ticker):** Activity / Life coverage for live library ids - honest prose, completeness. **Layer A (story camera):** only `EventCatalog.IsCameraWorthy` beats register interest and cut the camera. **Single inventory:** [`EventCatalog`](../IdleSpectator/Events/EventCatalog.cs) (partials under `Events/Catalogs/`). Feeds/patches register A from those dials; `InterestDirector` only ranks candidates. ## Dials | Dial | Layer | Role | |------|-------|------| | Happiness `Presentation` | A if Signal | Ambient/Aggregate = B-only | | `CreatesInterest` | A gate | Discrete / status / WorldLog / libraries | | `EventStrength` | A rank | Base `TotalScore` (interrupt via margin) | | `Completion` | A hold | Hold-until-complete kind | | `MaxWatch` | A hold | Hard cap (`scoring-model.json`) | | `EventReason` / Label | A display | 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; sticky A scenes use `stickyCutInMargin`. Ambient / Character fill is exempt - A events may take the camera immediately. ## Sources (wired) | Source | Primary owner | Reason factory | Notes | |--------|---------------|----------------|-------| | WorldLog | `InterestFeeds.OnWorldLogMessage` | catalog / EventReason | A if CreatesInterest | | Happiness | `IngestHappiness` | catalog + EventReason | Signal = A; see [event-prose-audit.md](event-prose-audit.md) | | Status | `OnStatusChange` | EventReason.Status | Gain A if CreatesInterest; egg **loss** → hatch A | | Scanner combat | WorldActivityScanner | EventReason.Fight / Battle | `EventCatalog.Combat` | | War / Plot / Relationship / Trait / Building / Boat / Book / Era / Kingdom | Feeds + patches | EventReason / catalog | A via CreatesInterest; alpha via Family.setAlpha | | Libraries | Deferred feeds | EventReason.Library | Mostly B; spectacle ids A | | Character fill | InterestDirector.TryCharacterFill | empty Label | Only when no pending EventLed | ## Layer A policy Interesting beats register as interest candidates (`Signal` / `CreatesInterest`). Director ranks by `EventStrength` + scoring - do not hard-gate interesting life off Layer A. Happiness Ambient (B) only: `got_poked`, `got_caught`, `paid_tax`, `just_ate`, `just_pooped`. Happiness Aggregates stay civic mass (B unit camera). Status B: brief FX/cooldowns + egg gain only. Noise still skipped at patch (not dial): building_damage chips, boat_load, **ambient building/object destroy** (falls are Layer B; consume stays A). Presentability: production `EventFeedUtil.Register` rejects Labels the dossier would blank (`unpresentable` drop). See [camera-presentability-plan.md](camera-presentability-plan.md). ## Full surface See [world-event-inventory.md](world-event-inventory.md) for live library counts, gaps, and refresh commands. ## Interrupt / hold / grace 1. Instant cut when `next.TotalScore >= current + cutInMargin` (sticky: `stickyCutInMargin`). 2. Ambient fill: any A EventLed may take the camera immediately. 3. Else hold while `InterestCompletion.IsActive` and under MaxWatch. 4. Soft peer rotates on EventLed only after `minCameraDwell` (15s), never during protected sticky hold without margin. 5. Quiet grace 6s: still-worth-watching filter, then Character fill with empty reason. 6. Drops recorded in `InterestDropLog`. 7. Focus continuity: while Idle Spectator is on, a missing living camera focus is repaired the same director tick (reattach scene follow/related, else ambient fill / any alive unit). Orphan scenes (no living follow/related) end as `follow_lost` instead of sitting in quiet_grace with an empty camera. ## Mutation gap triage `mutation_discovery` refreshes `.harness/mutation_gaps.tsv`. Open rows are unexplained Wire candidates only. ## Idle quality Done (see [camera-presentability-plan.md](camera-presentability-plan.md) and `combat_focus`): - Presentability gate, ambient fall demotion, focus hold, tip placeholder ban - Status-overlap hold (onset requires live status; offsets stay FixedDwell) - Combat tip/focus alignment (highest-scored participant; tip subject matches focus; clears "is fighting" when combat goes cold) Done (0.25.52): dossier nametag tracks focus on handoff (`CameraDirector.Watch` focus-then-caption; `WatchCaption.ReconcileDossierToFocus`; `combat_focus` asserts `dossier_matches_focus`). Soak audit helper: `./scripts/soak-audit-player-log.sh [seconds]` (or pass `--since-bytes N`).