worldbox-observer-mod/docs/event-audit.md
2026-07-16 21:54:44 -05:00

4.7 KiB

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 (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
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.

Full surface

See 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 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).