# Event catalog discovery Live gap map of AssetManager libraries, mutation hooks, and IdleSpectator event-catalog coverage. Expansion of [`event-catalog.json`](../IdleSpectator/event-catalog.json) should cite this ledger, not guessed id lists. Audit date: 2026-07-17. WorldBox harness refresh: `mutation_discovery`, `domain_event_audit`, `activity_happiness_audit`, `activity_status_audit`, `world_log_audit`, `disaster_war_audit`, `activity_taxonomy_audit` (all PASS). Artifacts: `IdleSpectator/.harness/` (especially `mutation_*.tsv`, `domain_event_audit.tsv`). Machine worksheet: [`event-catalog-discovery.tsv`](event-catalog-discovery.tsv). ## Verdict **Id inventory is complete for every EventCatalog domain.** Authored 1:1 libraries match live counts with zero missing/orphan ids. Live+dial libraries are fully seeded. `mutation_gaps.tsv` is empty (`gaps=0`). Id inventory and interesting Layer A policy are in good shape as of **0.28.27** (`camera_a_inventory`: **219 A / 924 B** on library+decision domains; decisions **37** camera with phrases). Remaining feel of thin tips is mostly **soak share / strength vs filler**, not missing catalog rows: 1. Library Labels use display names (Wave 1); keep watching for weak verbs. 2. Ambient CI stays false; Signal predicates own library A (expanded 0.28.27). 3. Building civ complete / wonder A is wired. 4. Meta-trait domains are fail-gated by `domain_event_audit` + `camera_a_inventory_ok`. Tips here means watch tip / orange reason Labels from interest feeds, not dossier chip hover tooltips. ## How to read priorities | Priority | Meaning | |----------|---------| | P0 | Missing wire or authored sync that drops a real lifecycle beat | | P1 | Tip/prose quality for already-seeded high-visibility classes | | P2 | New surfaces or Signal tuning after P0/P1 | | P3 | Intentional Layer B / covered-by another feed | ## Authored 1:1 domains Live audits: `missingAuthored=0` / `orphan=0` for all closed libraries. | Domain | Live | Authored | Catalog mode | Camera policy (approx) | Priority | |--------|-----:|---------:|--------------|------------------------|----------| | happiness | 67 | 67 | authored | Signal 49 / Aggregate 13 / Ambient 5 | P3 sync done | | status | 58 | 58 | authored | CreatesInterest 42; B FX 16 | P3 sync done | | worldLog | 41 | 41 | authored | CreatesInterest 40 (`auto_tester` B) | P3 sync done | | plots | 28 | 28 | authored | all A | P3 sync done | | eras | 11 | 11 | authored | all A | P3 sync done | | books | 12 | 12 | authored | all A | P3 sync done | | traits | 116 | 116 | authored | all A | P3 sync done | | disasters | 17 | 17 | authored | via WorldLog pairs | P3 sync done | | warTypes | 5 | 5 | authored | dials | P3 sync done | | relationship | n/a | 11 | authored discrete | all A | P3 sync done | Happiness Ambient (stay B): `got_poked`, `got_caught`, `paid_tax`, `just_ate`, `just_pooped`. Status B: recovery_*, egg gain, spell_silence/boost, on_guard, just_ate, afterglow, slowness, cough, shield, dodge, dash, flicked. ## Live + dial domains Seeded via `LiveLibraryInterest.EnsureSeeded` + JSON `libraries.*` dials. `authored=1` in `domain_event_audit.tsv` means live-seeded entry exists, not a per-id JSON prose row. | Domain | Live | Camera A | Dial label template | Notes | Priority | |--------|-----:|---------:|---------------------|-------|----------| | decisions | 127 | **16** politics/spectacle | `{a} decides to {action}` | Soft pack/fireworks/asexual/steal demoted B; fluff + intent-genesis B | noise pass 0.28.41 | | spells | 12 | 6 | `{a} casts {id}` | Signal spectacle only; FX spells B | P3 | | powers | 339 | **41** | `God power: {id}` | ambient CI=false; widened spectacle + creature powers; UI `_edit` B | P3 expanded 0.28.27 | | items | 111 | **20** mythril/adamantine | `{a} gains {id}` | steel/silver/bone demoted B | noise pass 0.28.41 | | genes | 47 | **0** | `{a} gains gene {id}` | all B (gain/remove tips not camera-worthy) | demoted | | phenotypes | 52 | 0 | `{a} shows {id}` | all B | P3 | | world_laws | 49 | **7** crisis | `Law changed: {id}` | hunger/army/expansion/UI toggles B | noise pass 0.28.41 | | subspecies_traits | 204 | **21** | `{a} evolves {id}` | dramatic + mutation/death/blood/horror | P3 expanded 0.28.27 | | biomes | 29 | 0 | `Biome shifts: {id}` | ambient CI=false | P3 stay B | | culture_traits | 78 | **8** politics | `{a} culture gains {id}` | lovers/layout/craft B; conscript/xenophobe/expansion A | noise pass 0.28.41 | | religion_traits | 40 | 6 | `{a} faith gains {id}` | dramatic heuristic | P3 | | clan_traits | 29 | **0** | `{a} clan gains {id}` | all B (blood/vein soak) | noise pass 0.28.41 | | language_traits | 26 | **0** | `{a} tongue gains {id}` | all B | noise pass 0.28.41 | **Library+decision Layer A inventory (0.28.41):** live dump total **125 A / 1018 B** across 13 domains (`camera_a_inventory_ok`). Decisions **16 A**. ### Decision camera classes (0.28.41) Allow-token Signal after fluff + intent-genesis + soft-noise filter (not 127 ambient). Authored action phrases required for every A id (`domain_event_audit` decision_prose). Classes: sexual reproduction / lover / child, army/war/politics, spectacle/dark (`golden_brain`, `make_skeleton`, `soul_harvest`, `possessed`), hive (`create_hive`). Stay B (soft noise 0.28.41): `family_group`, `fireworks`, `affect_dreams`, `put_out_fire`, `burn_tumors`, `asexual_reproduction`, steal/take city item, `warrior_army_follow_leader`, `warrior_try_join_army_group`. Stay B (intent-only; camera on outcome feeds): `try_new_plot*`, `try_to_start_new_civilization*`, `build_civ_city*`, `*city_foundation*`, `claim_land*` → real tips from `PlotInterestFeed` / `MetaEventPatches` (`new_city` 86, `new_kingdom` 92). Also stay B: diet/sleep/random/check ticks, `warrior_train_with_dummy`, boat trade/fish, house/job/tax chores. Spell Signal: spectacle summons/curses/fire/teleport/meteor; FX silence/shield/cure/grass/vegetation/skeleton stay B. Power Signal: disasters plus spectacle creature drops (`evil_mage`, `white_mage`, `necromancer`, `druid`, `plague_doctor`, dragons/demons, …) via live spectacle asset discovery - not B ambient. ## Patch-only / no catalog rows | Surface | Live / notes | Wire status | Priority | |---------|--------------|-------------|----------| | buildings | 618 | consume A; ambient destroy demoted B; **no complete/wonder A** | P0 complete/wonder | | boats | patch | trade/unload A; load B | P3 | | combat | policy in `EventCatalog.Combat` | scanner + fight feeds | P3 | | architecture / city_build_orders | 53 / 3 | covered_by_building_activity | P3 | | kingdoms_traits | 5 | covered_by_trait_meta_feeds | P3 | | items_modifiers | 59 | covered_by_item_feed | P3 | | combat_action_library | 11 | covered_by_spell_combat_feeds | P2 only if distinct beats | | loyalty / opinion / knowledge / communication / story | 29/24/11/10/1 | covered_by_worldlog_happiness | P3 | | citizen_job / professions / personalities | 13/5/5 | Activity/dossier labels | P3 | | tasks_actor | 217 | Activity taxonomy (unmappedTasks=0) | P3 | | actor_library | 322 | SpeciesDiscovery / voice (taxonomy PASS) | P3 | | plot_category_library | 9 | categories only | P3 | WorldLog already covers end beats that inventory once flagged as open wire work: `alliance_dissolved`, `kingdom_destroyed`, `kingdom_shattered`, `kingdom_fractured`, `city_destroyed`. Manager `removeObject` is intentionally not event-worthy in `MutationDiscoveryHarness` because those WorldLog rows exist. ## Mutation discovery | Metric | Value | |--------|------:| | managers | 57 | | managerMethods | 189 | | actorMethods | 256 | | beh | 93 | | libraries | 39 | | libraryAssets | 2893 | | gaps | 0 | `World.era_manager` / `World.earthquake_manager` report `null` on this build (unwired PollState, not gap rows). Age change remains wired via `WorldAgeManager.startNextAge`. Ongoing era/earthquake poll is still optional fill (P2), not a missing id catalog row. Unwired ManagerEnd / Beh rows exist in TSVs but are filtered out of `mutation_gaps` by design (Beh → activity path; `removeObject` → WorldLog). ## Tip quality gap (main expansion lever) Status (2026-07-22): **class path shipped** - discrete `MakeLabel` resolves `{id}` via `LibraryAssetNames` when `LibraryKind` is set on live-seeded library rows; WorldLog `MakeLabel` prefers `world_log_library` translated names, else humanize. Remaining work is playtest-driven Signal A / weak decision-WorldLog prose only where soak or camera-A inventory still shows awkward phrases - not mass new JSON libraries. Status check (2026-07-22): live `library_asset_labels_ok` / `camera_a_inventory_ok` dumps show **0** snake_case displays and **0** camera-A rows with raw-id displays. No mass prose pass needed until a soak/camera tip shows a new awkward class. Previous gap notes (historical): `EventReason` / discrete `MakeLabel` used to replace `{id}` with the raw asset id. Status/trait Activity and dossier paths already used locale/`getTranslatedName` helpers. Examples of weak watch tips today: - `{a} culture gains xenophobic` instead of a localized culture-trait name - `{a} forges armor_leather` (wrong verb + raw id) - `{a} gains gene warfare_3` - `God power: atomic_bomb` (readable but not localized) Recommended class fix: resolve `{id}` through live asset display names inside Label builders for library domains (same pattern as status), not thousands of JSON rows. ## Audit hygiene `DomainEventHarness` diffs culture/religion/clan/language traits into `domain_event_audit.tsv` but omits those diffs from `Passed`. If meta traits are first-class EventCatalog domains (they are), the pass condition should include them. ## Expansion waves ### Wave 0 - done by this audit Authored 1:1 sync and live seed inventory: no missing ids. ### Wave 1 (first implementation PR) - tip quality + building complete Status (2026-07-17): **implemented** in mod `0.28.14`. 1. `LibraryAssetNames` + `EventReason.Library` resolve live display names (localized when available, else humanized). 2. Item verb is `gains` by default; `forges` only for forge/smith/anvil ids. Catalog template `{a} gains {id}`. 3. `Building.completeConstruction` wires Layer A for `Building_Civ` (temple/statue spectacle strength bump). 4. `domain_event_audit` fail-gates culture/religion/clan/language trait diffs; `library_asset_labels_ok` dumps `.harness/library-asset-labels.tsv`. ### Interesting A expansion (Phases 0–2) Status (2026-07-17): **implemented** in mod `0.28.27`. 1. `camera_a_inventory_ok` dumps `.harness/camera-a-inventory.tsv` (nested in `domain_event_audit`). 2. Decisions: fluff filter refined; Signal classes for founding/reproduction/pack/spectacle; **37** camera A with authored phrases. 3. Library Signal widened (power/item/gene/worldLaw/subspecies/meta); ambient CI stays false; phenotypes/biomes stay 0 A. ### Wave 2 - Signal / ambient A tuning Status (2026-07-17): **implemented** in mod `0.28.16`. 1. `ambientCreatesInterest=false` for spell/item/gene/phenotype/worldLaw/subspecies/meta trait dials (Signal predicates / signalIds own Layer A). 2. Spells: `IsSpectacleSpell` keeps summon/meteor/tornado/lightning/teleport/curse/blood/fire as A; silence/shield/cure/grass/vegetation/skeleton stay B. 3. World laws: dramatic class includes hunger/rebellion/disaster/angry (plus war/death/plague). 4. Phenotypes: all B (no Signal predicate). 5. Items: Signal for mythril/adamantine (+ named relic tokens); leather/iron ambient B. 6. JSON loader now ingests culture/religion/clan/language trait dials; default ambient CI is false. 7. Gate: `library_ambient_policy_ok` (nested in `domain_event_audit`). Era change was already wired (`WorldAgeManager.update` → `startNextAge`). Earthquake ongoing hold: **implemented** (`Earthquake.startQuake` → `EarthquakeActive` sticky) in `0.28.17`. ### Wave 3 - new surfaces only if playtests demand Status (2026-07-17): **triaged closed** - no new EventCatalog domains. | Surface | Live | Decision | |---------|------|----------| | combat_action_library (11) | melee/range/spell/dodge/… | Covered by combat scanner + `tryToCastSpell` → spell catalog | | story / knowledge / communication / loyalty / opinion | small libs | Covered by WorldLog / happiness civic paths | | personalities / professions | 5 / 5 | Activity/dossier labels only | | architecture / city_build_orders | build helpers | Building complete / consume path | Do not mass-author powers/items/buildings into JSON. ## First implementation PR recommendation **Title focus:** Improve library event tip labels and wire building completion. **Scope:** - Display-name resolution for library Labels (class fix) - Item label template improvement - Building complete / wonder Layer A path + harness gate - `domain_event_audit` pass includes culture/religion/clan/language trait diffs - Refresh this doc + [`world-event-inventory.md`](world-event-inventory.md) counts **Out of scope for that PR:** mass JSON rows; scoring-model changes; dossier chip tooltips. ## Refresh commands ```bash ./scripts/worldbox-ctl.sh status ./scripts/harness-run.sh --no-launch mutation_discovery ./scripts/harness-run.sh --no-launch domain_event_audit ./scripts/harness-run.sh --no-launch activity_happiness_audit ./scripts/harness-run.sh --no-launch activity_status_audit ./scripts/harness-run.sh --no-launch world_log_audit ./scripts/harness-run.sh --no-launch disaster_war_audit ./scripts/harness-run.sh --no-launch activity_taxonomy_audit ```