diff --git a/IdleSpectator/AgentHarness.cs b/IdleSpectator/AgentHarness.cs index aeac97c..4b08c58 100644 --- a/IdleSpectator/AgentHarness.cs +++ b/IdleSpectator/AgentHarness.cs @@ -7326,6 +7326,13 @@ public static class AgentHarness + $"kinds={kinds.Count}"; break; } + case "camera_a_inventory_ok": + { + CameraAInventoryResult inv = CameraAInventoryHarness.RunAudit(HarnessDir()); + pass = inv.Passed; + detail = inv.Detail; + break; + } case "library_ambient_policy_ok": { // Signal-only libraries: ambient dials must be B; phenotypes all B; diff --git a/IdleSpectator/CameraAInventoryHarness.cs b/IdleSpectator/CameraAInventoryHarness.cs new file mode 100644 index 0000000..d929bba --- /dev/null +++ b/IdleSpectator/CameraAInventoryHarness.cs @@ -0,0 +1,278 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace IdleSpectator; + +public sealed class CameraAInventoryResult +{ + public bool Passed; + public string Detail = ""; + public int Total; + public int CameraA; + public int CameraB; +} + +/// +/// Live dump of Layer A vs B fate for decisions + library dial domains. +/// Source of truth for Signal / decision promote work (never promote from memory). +/// +public static class CameraAInventoryHarness +{ + public static CameraAInventoryResult RunAudit(string outputDirectory) + { + var lines = new List + { + "domain\tid\tdisplay\tlayer\tstrength\treason" + }; + int total = 0; + int cameraA = 0; + int cameraB = 0; + var summary = new StringBuilder(); + + AppendDomain( + lines, + ref total, + ref cameraA, + ref cameraB, + summary, + "decisions", + "decision", + ActivityAssetCatalog.EnumerateLiveDecisionIds(), + id => EventCatalog.Decision.GetOrFallback(id), + id => EventCatalog.Decision.IsCameraWorthy(id) + ? (EventCatalog.Decision.TryGetAuthoredActionPhrase(id, out _) + ? "signal_predicate+phrase" + : "signal_predicate") + : ReasonDecisionB(id)); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "spells", "spell", + ActivityAssetCatalog.EnumerateLiveSpellIds(), + EventCatalog.Spell.GetOrFallback, + id => ReasonLibrary(EventCatalog.Spell.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "powers", "power", + ActivityAssetCatalog.EnumerateLivePowerIds(), + EventCatalog.Power.GetOrFallback, + id => ReasonLibrary(EventCatalog.Power.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "items", "item", + ActivityAssetCatalog.EnumerateLiveItemIds(), + EventCatalog.Item.GetOrFallback, + id => ReasonLibrary(EventCatalog.Item.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "genes", "gene", + ActivityAssetCatalog.EnumerateLiveGeneIds(), + EventCatalog.Gene.GetOrFallback, + id => ReasonLibrary(EventCatalog.Gene.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "phenotypes", "phenotype", + ActivityAssetCatalog.EnumerateLivePhenotypeIds(), + EventCatalog.Phenotype.GetOrFallback, + id => ReasonLibrary(EventCatalog.Phenotype.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "world_laws", "worldlaw", + ActivityAssetCatalog.EnumerateLiveWorldLawIds(), + EventCatalog.WorldLaw.GetOrFallback, + id => ReasonLibrary(EventCatalog.WorldLaw.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "subspecies_traits", "subspecies_trait", + ActivityAssetCatalog.EnumerateLiveSubspeciesTraitIds(), + EventCatalog.SubspeciesTrait.GetOrFallback, + id => ReasonLibrary(EventCatalog.SubspeciesTrait.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "biomes", "biome", + ActivityAssetCatalog.EnumerateLiveBiomeIds(), + EventCatalog.Biome.GetOrFallback, + id => ReasonLibrary(EventCatalog.Biome.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "culture_traits", "culture_trait", + ActivityAssetCatalog.EnumerateLiveCultureTraitIds(), + EventCatalog.CultureTrait.GetOrFallback, + id => ReasonLibrary(EventCatalog.CultureTrait.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "religion_traits", "religion_trait", + ActivityAssetCatalog.EnumerateLiveReligionTraitIds(), + EventCatalog.ReligionTrait.GetOrFallback, + id => ReasonLibrary(EventCatalog.ReligionTrait.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "clan_traits", "clan_trait", + ActivityAssetCatalog.EnumerateLiveClanTraitIds(), + EventCatalog.ClanTrait.GetOrFallback, + id => ReasonLibrary(EventCatalog.ClanTrait.GetOrFallback(id))); + + AppendDomain( + lines, ref total, ref cameraA, ref cameraB, summary, + "language_traits", "language_trait", + ActivityAssetCatalog.EnumerateLiveLanguageTraitIds(), + EventCatalog.LanguageTrait.GetOrFallback, + id => ReasonLibrary(EventCatalog.LanguageTrait.GetOrFallback(id))); + + try + { + if (!string.IsNullOrEmpty(outputDirectory)) + { + Directory.CreateDirectory(outputDirectory); + File.WriteAllLines(Path.Combine(outputDirectory, "camera-a-inventory.tsv"), lines); + File.WriteAllText( + Path.Combine(outputDirectory, "camera-a-inventory-summary.txt"), + summary.ToString()); + } + } + catch + { + // diagnostic dump only + } + + bool passed = total > 0 && cameraA > 0; + return new CameraAInventoryResult + { + Passed = passed, + Total = total, + CameraA = cameraA, + CameraB = cameraB, + Detail = $"total={total} A={cameraA} B={cameraB} domains=13" + }; + } + + private static void AppendDomain( + List lines, + ref int total, + ref int cameraA, + ref int cameraB, + StringBuilder summary, + string domain, + string displayKind, + List ids, + Func getEntry, + Func reasonFor) + { + if (ids == null) + { + ids = new List(); + } + + int a = 0; + int b = 0; + for (int i = 0; i < ids.Count; i++) + { + string id = ids[i]; + if (string.IsNullOrEmpty(id)) + { + continue; + } + + DiscreteEventEntry entry = getEntry(id); + bool isA = entry != null + && EventCatalog.IsCameraWorthy(entry); + string layer = isA ? "A" : "B"; + if (isA) + { + a++; + cameraA++; + } + else + { + b++; + cameraB++; + } + + total++; + string display = domain == "decisions" + ? EventReason.HumanizeId(id) + : LibraryAssetNames.DisplayName(displayKind, id); + display = SanitizeTsv(display); + float strength = entry != null ? entry.EventStrength : 0f; + string reason = SanitizeTsv(reasonFor(id) ?? ""); + lines.Add( + domain + "\t" + id + "\t" + display + "\t" + layer + "\t" + + strength.ToString("0.#") + "\t" + reason); + } + + summary.AppendLine(domain + "\tlive=" + ids.Count + "\tA=" + a + "\tB=" + b); + } + + private static string ReasonLibrary(DiscreteEventEntry entry) + { + if (entry == null) + { + return "missing"; + } + + if (entry.IsFallback) + { + return "fallback"; + } + + return entry.CreatesInterest ? "signal" : "ambient"; + } + + private static string ReasonDecisionB(string id) + { + if (string.IsNullOrEmpty(id)) + { + return "empty"; + } + + string s = id.ToLowerInvariant(); + if (s == "try_new_plot" || s.StartsWith("try_new_plot_", StringComparison.Ordinal)) + { + return "deny_plot_intent"; + } + + if (s.Contains("idle") + || s.Contains("walking") + || s.Contains("check") + || s.Contains("wait") + || s.Contains("sleep") + || s.Contains("random") + || s.Contains("play") + || s.Contains("jump") + || s.Contains("flip") + || s.Contains("diet_") + || s.Contains("move") + || s.Contains("swim") + || s.Contains("follow_parent") + || s.Contains("follow_desire") + || s.Contains("reflection") + || s.Contains("poop")) + { + return "deny_fluff"; + } + + return "no_signal_token"; + } + + private static string SanitizeTsv(string value) + { + if (string.IsNullOrEmpty(value)) + { + return ""; + } + + return value.Replace('\t', ' ').Replace('\n', ' ').Replace('\r', ' '); + } +} diff --git a/IdleSpectator/Events/Catalogs/EventCatalog.Decision.cs b/IdleSpectator/Events/Catalogs/EventCatalog.Decision.cs index 86ee072..ab5f7d3 100644 --- a/IdleSpectator/Events/Catalogs/EventCatalog.Decision.cs +++ b/IdleSpectator/Events/Catalogs/EventCatalog.Decision.cs @@ -51,6 +51,37 @@ public static partial class EventCatalog ["warrior_army_follow_leader"] = "follow their leader", ["warrior_train_with_dummy"] = "train with a dummy", ["warrior_try_join_army_group"] = "try to join an army", + ["warrior_army_leader_move_to_attack_target"] = "lead the army to attack", + + // Founding / territory + ["try_to_start_new_civilization"] = "start a new civilization", + ["build_civ_city_here"] = "found a city here", + ["claim_land"] = "claim this land", + ["king_check_new_city_foundation"] = "found a new city", + ["bee_create_hive"] = "create a hive", + + // Life / pack + ["sexual_reproduction_try"] = "try to reproduce", + ["asexual_reproduction_budding"] = "reproduce by budding", + ["asexual_reproduction_divine"] = "reproduce by divine means", + ["asexual_reproduction_fission"] = "reproduce by fission", + ["asexual_reproduction_parthenogenesis"] = "reproduce by parthenogenesis", + ["asexual_reproduction_spores"] = "reproduce by spores", + ["asexual_reproduction_vegetative"] = "reproduce vegetatively", + ["family_group_follow"] = "follow their family group", + ["family_group_join_or_new_herd"] = "join or form a herd", + ["family_group_leave"] = "leave their family group", + + // Spectacle / dark / civic + ["attack_golden_brain"] = "attack the golden brain", + ["make_skeleton"] = "raise a skeleton", + ["status_soul_harvested"] = "have their soul harvested", + ["possessed_following"] = "follow under possession", + ["try_to_take_city_item"] = "try to take a city item", + ["put_out_fire"] = "put out a fire", + ["burn_tumors"] = "burn tumors", + ["try_to_launch_fireworks"] = "launch fireworks", + ["try_affect_dreams"] = "affect dreams", }; /// Drop cached rows so the next Ensure re-applies JSON overlays. @@ -68,26 +99,6 @@ public static partial class EventCatalog } string s = id.ToLowerInvariant(); - // Pure AI ticks / daily fluff - not story beats. - if (s.Contains("idle") - || s.Contains("walking") - || s.Contains("check") - || s.Contains("wait") - || s.Contains("sleep") - || s.Contains("random") - || s.Contains("play") - || s.Contains("jump") - || s.Contains("flip") - || s.Contains("diet_") - || s.Contains("move") - || s.Contains("swim") - || s.Contains("follow_parent") - || s.Contains("follow_desire") - || s.Contains("reflection") - || s.Contains("poop")) - { - return false; - } // Intent-only: setDecisionCooldown fires before a Plot exists (and often never does). // Real plot tips come from PlotInterestFeed / live World.plots. @@ -96,7 +107,15 @@ public static partial class EventCatalog return false; } + // Daily AI / check ticks. Foundation checks stay eligible for Signal tokens. + if (IsFluffDecision(s)) + { + return false; + } + return HasToken(s, "war") + || HasToken(s, "king") + || HasToken(s, "leader") || s.Contains("rebellion") || s.Contains("revolt") || s.Contains("alliance") @@ -114,14 +133,79 @@ public static partial class EventCatalog || s.Contains("banish") || s.Contains("steal") || s.Contains("kill_unruly") - || HasToken(s, "king") - || HasToken(s, "leader") || s.Contains("clan") || s.Contains("religion") || s.Contains("culture") || s.Contains("baby_make") || s.Contains("have_child") - || s.Contains("birth"); + || s.Contains("birth") + || s.Contains("reproduction") + || s.Contains("civilization") + || s.Contains("civ_city") + || s.Contains("claim_land") + || s.Contains("golden_brain") + || s.Contains("make_skeleton") + || s.Contains("soul_harvest") + || s.Contains("possessed") + || s.Contains("create_hive") + || s.Contains("fireworks") + || s.Contains("affect_dreams") + || s.Contains("family_group") + || s.Contains("take_city_item") + || s.Contains("put_out_fire") + || s.Contains("burn_tumors"); + } + + /// + /// Pure AI ticks / daily fluff. Not story beats. + /// city_foundation checks are excluded so kings can Signal founding intent. + /// + private static bool IsFluffDecision(string s) + { + if (string.IsNullOrEmpty(s)) + { + return true; + } + + if (s.Contains("city_foundation")) + { + return false; + } + + if (s.StartsWith("check_", StringComparison.Ordinal) + || s.Contains("_check_") + || s.EndsWith("_check", StringComparison.Ordinal)) + { + return true; + } + + return s.Contains("idle") + || s.Contains("walking") + || s.Contains("sleep") + || s.Contains("play") + || s.Contains("jump") + || s.Contains("flip") + || s.Contains("diet_") + || s.Contains("reflection") + || s.Contains("poop") + || s.Contains("follow_parent") + || s.Contains("follow_desire") + || s.Contains("move_random") + || s.Contains("random_move") + || s.Contains("random_fun") + || s.Contains("random_swim") + || s.Contains("random_teleport") + || s.Contains("random_emotion") + || s.Contains("warrior_random") + || s.Contains("captain_waiting") + || s.Contains("captain_idle") + || s.Contains("_waiting") + || s == "wait5" + || s.Contains("swim_to") + || s.Contains("move_to_water") + || s.Contains("bored_sleep") + || s.Contains("monophasic") + || s.Contains("polyphasic"); } /// Underscore-token match so war does not hit warrior. diff --git a/IdleSpectator/Events/Catalogs/EventCatalog.Libraries.cs b/IdleSpectator/Events/Catalogs/EventCatalog.Libraries.cs index 1ed41de..18ca629 100644 --- a/IdleSpectator/Events/Catalogs/EventCatalog.Libraries.cs +++ b/IdleSpectator/Events/Catalogs/EventCatalog.Libraries.cs @@ -143,6 +143,17 @@ public static partial class EventCatalog } string s = id.ToLowerInvariant(); + // God-tool editors / drip brushes stay B. + if (s.Contains("_edit") + || s.Contains("traits_") + || s.Contains("equipment_rain") + || s.EndsWith("_brush", StringComparison.Ordinal) + || s.Contains("draw_") + || s.Contains("paint")) + { + return false; + } + return s.Contains("meteor") || s.Contains("earthquake") || s.Contains("tornado") @@ -150,12 +161,28 @@ public static partial class EventCatalog || s.Contains("nuke") || s.Contains("bomb") || s.Contains("rain_blood") + || s.Contains("blood_rain") || s.Contains("hell") || s.Contains("lightning") || s.Contains("storm") || s.Contains("acid") || s.Contains("fire") - || s.Contains("disaster"); + || s.Contains("disaster") + || s.Contains("dragon") + || s.Contains("demon") + || s.Contains("plague") + || s.Contains("zombie") + || s.Contains("crabzilla") + || s == "ufo" + || s.Contains("god_finger") + || s.Contains("cold_one") + || s.Contains("heatray") + || s.Contains("curse") + || s.Contains("lava") + || s.Contains("ash") + || s.Contains("golden_brain") + || s.Contains("corrupted_brain") + || s.Contains("infection"); } private static void Ensure() @@ -218,7 +245,8 @@ public static partial class EventCatalog } string s = id.ToLowerInvariant(); - // Top-tier materials from live items library (mythril/adamantine) plus named relics. + // High / mid-spectacle materials from live items library plus named relics. + // Leather/wood/copper/iron stay ambient B. return s.Contains("legendary") || s.Contains("mythic") || s.Contains("mythril") @@ -230,7 +258,12 @@ public static partial class EventCatalog || s.Contains("dragon") || s.Contains("nuke") || s.Contains("excalibur") - || s.Contains("wonder"); + || s.Contains("wonder") + || s.Contains("silver") + || s.Contains("steel") + || s.Contains("_bone") + || s.StartsWith("bone_", StringComparison.Ordinal) + || s.EndsWith("_bone", StringComparison.Ordinal); } private static void Ensure() @@ -306,7 +339,12 @@ public static partial class EventCatalog || s.Contains("undead") || s.Contains("dragon") || s.Contains("evolve") - || s.Contains("mutate"); + || s.Contains("mutate") + || s.Contains("mutation") + || s.Contains("death") + || s.Contains("blood") + || s.Contains("horror") + || s.Contains("tentacle"); } private static void Ensure() @@ -379,10 +417,25 @@ public static partial class EventCatalog d.AmbientStrength, signalIds: null, d.SignalStrength, - signalPredicate: id => id != null && (id.Contains("warfare") || id.Contains("magic") || id.Contains("mutation")), + signalPredicate: IsSignalGene, ambientCreatesInterest: d.AmbientCreatesInterest); } + private static bool IsSignalGene(string id) + { + if (string.IsNullOrEmpty(id)) + { + return false; + } + + string s = id.ToLowerInvariant(); + return s.Contains("warfare") + || s.Contains("magic") + || s.Contains("mutation") + || s.Contains("mutagen") + || s.Contains("damage"); + } + public static IEnumerable AuthoredIds { get @@ -501,7 +554,17 @@ public static partial class EventCatalog || s.Contains("hunger") || s.Contains("rebell") || s.Contains("disaster") - || s.Contains("angry"); + || s.Contains("angry") + || s.Contains("cursed") + || s.Contains("forever_") + || s.Contains("tumor") + || s.Contains("mutant") + || s.Contains("evolution") + || s.Contains("old_age") + || s.Contains("kingdom_expansion") + || s.Contains("border_steal") + || s.Contains("civ_army") + || s.Contains("exploding"); } public static IEnumerable AuthoredIds @@ -596,7 +659,18 @@ public static partial class EventCatalog || s.Contains("zealot") || s.Contains("fanatic") || s.Contains("schism") - || s.Contains("royal"); + || s.Contains("royal") + || s.Contains("conscript") + || s.Contains("join_or_die") + || s.Contains("necro") + || s.Contains("evil") + || s.Contains("shattered") + || s.Contains("titan") + || s.Contains("ethno") + || s.Contains("flame") + || s.Contains("ice_weapon") + || s.Contains("shotgun") + || s.Contains("blaster"); } public static class CultureTrait diff --git a/IdleSpectator/HarnessScenarios.cs b/IdleSpectator/HarnessScenarios.cs index 61b29c2..3a5d695 100644 --- a/IdleSpectator/HarnessScenarios.cs +++ b/IdleSpectator/HarnessScenarios.cs @@ -1994,6 +1994,7 @@ internal static class HarnessScenarios Step("dea1", "assert", expect: "domain_event_audit"), Step("dea1b", "assert", expect: "library_asset_labels_ok"), Step("dea1c", "assert", expect: "library_ambient_policy_ok"), + Step("dea1d", "assert", expect: "camera_a_inventory_ok"), Step("dea2", "snapshot") }; } diff --git a/IdleSpectator/event-catalog.json b/IdleSpectator/event-catalog.json index 4ac1359..3af85bf 100644 --- a/IdleSpectator/event-catalog.json +++ b/IdleSpectator/event-catalog.json @@ -73,6 +73,131 @@ "id": "warrior_try_join_army_group", "action": "try to join an army", "strength": 64 + }, + { + "id": "warrior_army_leader_move_to_attack_target", + "action": "lead the army to attack", + "strength": 72 + }, + { + "id": "try_to_start_new_civilization", + "action": "start a new civilization", + "strength": 90 + }, + { + "id": "build_civ_city_here", + "action": "found a city here", + "strength": 86 + }, + { + "id": "claim_land", + "action": "claim this land", + "strength": 70 + }, + { + "id": "king_check_new_city_foundation", + "action": "found a new city", + "strength": 88 + }, + { + "id": "bee_create_hive", + "action": "create a hive", + "strength": 68 + }, + { + "id": "sexual_reproduction_try", + "action": "try to reproduce", + "strength": 66 + }, + { + "id": "asexual_reproduction_budding", + "action": "reproduce by budding", + "strength": 64 + }, + { + "id": "asexual_reproduction_divine", + "action": "reproduce by divine means", + "strength": 78 + }, + { + "id": "asexual_reproduction_fission", + "action": "reproduce by fission", + "strength": 64 + }, + { + "id": "asexual_reproduction_parthenogenesis", + "action": "reproduce by parthenogenesis", + "strength": 66 + }, + { + "id": "asexual_reproduction_spores", + "action": "reproduce by spores", + "strength": 64 + }, + { + "id": "asexual_reproduction_vegetative", + "action": "reproduce vegetatively", + "strength": 62 + }, + { + "id": "family_group_follow", + "action": "follow their family group", + "strength": 52 + }, + { + "id": "family_group_join_or_new_herd", + "action": "join or form a herd", + "strength": 58 + }, + { + "id": "family_group_leave", + "action": "leave their family group", + "strength": 56 + }, + { + "id": "attack_golden_brain", + "action": "attack the golden brain", + "strength": 92 + }, + { + "id": "make_skeleton", + "action": "raise a skeleton", + "strength": 80 + }, + { + "id": "status_soul_harvested", + "action": "have their soul harvested", + "strength": 86 + }, + { + "id": "possessed_following", + "action": "follow under possession", + "strength": 74 + }, + { + "id": "try_to_take_city_item", + "action": "try to take a city item", + "strength": 66 + }, + { + "id": "put_out_fire", + "action": "put out a fire", + "strength": 60 + }, + { + "id": "burn_tumors", + "action": "burn tumors", + "strength": 62 + }, + { + "id": "try_to_launch_fireworks", + "action": "launch fireworks", + "strength": 58 + }, + { + "id": "try_affect_dreams", + "action": "affect dreams", + "strength": 56 } ], "species": [ diff --git a/IdleSpectator/mod.json b/IdleSpectator/mod.json index 4d7ce7d..034e654 100644 --- a/IdleSpectator/mod.json +++ b/IdleSpectator/mod.json @@ -1,7 +1,7 @@ { "name": "IdleSpectator", "author": "dazed", - "version": "0.28.25", + "version": "0.28.27", "description": "AFK Idle Spectator (I) + Lore (L). Killer button retargets dossier to the killer.", "GUID": "com.dazed.idlespectator" } diff --git a/docs/event-catalog-discovery.md b/docs/event-catalog-discovery.md index 09270c2..4906b60 100644 --- a/docs/event-catalog-discovery.md +++ b/docs/event-catalog-discovery.md @@ -15,12 +15,14 @@ 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`). -The feeling of “lots of events/tips we are not tracking” is mostly **tip quality and Layer A noise**, not missing catalog rows: +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). -1. Library Labels still interpolate raw `{id}` (`culture gains xenophobic`, `forges armor_leather`). -2. Large ambient-A surfaces (items, genes, phenotypes, subspecies traits, meta traits, world laws) own the camera with generic templates. -3. Building **complete / wonder finish** still has no Layer A wire (destroy/consume only). -4. Meta-trait domains are live-seeded and TSV-audited but **not fail-gated** by `domain_event_audit`. +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. @@ -60,27 +62,32 @@ Seeded via `LiveLibraryInterest.EnsureSeeded` + JSON `libraries.*` dials. | Domain | Live | Camera A | Dial label template | Notes | Priority | |--------|-----:|---------:|---------------------|-------|----------| -| decisions | 127 | 12 | `{a} decides to {action}` | 12 camera ids have action phrases; 2 JSON overlays are non-camera (`try_new_plot`, `warrior_train_with_dummy`) | P1 only if new interesting decisions appear | -| spells | 12 | 12 | `{a} casts {id}` | 7 signalIds @86; 5 ambient A @44 | P1 display names; P2 signal set | -| powers | 339 | 23 | `God power: {id}` | ambient CI=false; spectacle predicate | P1 display names | -| items | 111 | 111 | `{a} forges {id}` | ambient A; “forges” weak for armor/non-craft | P1 tip quality | -| genes | 47 | 47 | `{a} gains gene {id}` | ambient A | P1 names; P2 demote ambient spam | -| phenotypes | 52 | 52 | `{a} shows {id}` | ambient A | P1 names; P2 demote ambient spam | -| world_laws | 49 | 49 | `Law changed: {id}` | ambient A | P1 names | -| subspecies_traits | 204 | 204 | `{a} evolves {id}` | ambient A | P1 names; P2 Signal heuristics | +| decisions | 127 | **37** | `{a} decides to {action}` | Signal tokens + authored phrases; fluff/`try_new_plot` B; dump `.harness/camera-a-inventory.tsv` | P3 expanded 0.28.27 | +| 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 | **42** | `{a} gains {id}` | Signal mythril/adamantine + silver/steel/bone; leather/iron B | P3 expanded 0.28.27 | +| genes | 47 | **7** | `{a} gains gene {id}` | warfare/damage/mutagen Signal | P3 expanded 0.28.27 | +| phenotypes | 52 | 0 | `{a} shows {id}` | all B | P3 | +| world_laws | 49 | **17** | `Law changed: {id}` | dramatic + forever_/cursed/army/expansion… | P3 expanded 0.28.27 | +| 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 | 78 | `{a} culture gains {id}` | ~14 dramatic @74; rest ambient @34 | P1 names; hygiene gate | -| religion_traits | 40 | 40 | `{a} faith gains {id}` | dramatic heuristic | P1 names; hygiene gate | -| clan_traits | 29 | 29 | `{a} clan gains {id}` | dramatic heuristic | P1 names; hygiene gate | -| language_traits | 26 | 26 | `{a} tongue gains {id}` | dramatic heuristic | P1 names; hygiene gate | +| culture_traits | 78 | **27** | `{a} culture gains {id}` | dramatic + conscript/necro/craft weapons… | P3 expanded 0.28.27 | +| religion_traits | 40 | 6 | `{a} faith gains {id}` | dramatic heuristic | P3 | +| clan_traits | 29 | 13 | `{a} clan gains {id}` | dramatic heuristic | P3 | +| language_traits | 26 | 2 | `{a} tongue gains {id}` | dramatic heuristic | P3 | -Decision camera set (all have authored action phrases): -`try_to_steal_money`, `kill_unruly_clan_members`, `banish_unruly_clan_members`, `find_lover`, -`king_change_kingdom_{language,culture,religion}`, `leader_change_city_{language,culture,religion}`, -`warrior_try_join_army_group`, `warrior_army_follow_leader`. +**Library+decision Layer A inventory (0.28.27):** live dump total **219 A / 924 B** across 13 domains (`camera_a_inventory_ok`). -Spell signalIds (strength 86): `summon_lightning`, `summon_tornado`, `cast_curse`, `cast_fire`, `cast_blood_rain`, `summon_meteor`, `teleport`. -Ambient-A spells @44: `cast_silence`, `cast_grass_seeds`, `spawn_vegetation`, `spawn_skeleton`, `cast_shield`, `cast_cure`. +### Decision camera classes (0.28.27) + +Allow-token Signal after fluff filter (not 127 ambient). +Authored action phrases required for every A id (`domain_event_audit` decision_prose). + +Classes: founding/territory (`civilization`, `civ_city`, `claim_land`, `city_foundation`), reproduction/pack (`reproduction`, `family_group`), army/war/politics (existing), spectacle/dark (`golden_brain`, `make_skeleton`, `soul_harvest`, `possessed`), civic soft (`put_out_fire`, `burn_tumors`, `fireworks`, `affect_dreams`), hive (`create_hive`). + +Stay B: `try_new_plot*`, 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. ## Patch-only / no catalog rows @@ -156,6 +163,14 @@ Status (2026-07-17): **implemented** in mod `0.28.14`. 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`. diff --git a/docs/event-catalog-discovery.tsv b/docs/event-catalog-discovery.tsv index cc9e652..f15f9ee 100644 --- a/docs/event-catalog-discovery.tsv +++ b/docs/event-catalog-discovery.tsv @@ -9,44 +9,21 @@ traits 116 authored 0 116 wired authored_labels P3 disasters 17 authored 0 via_worldlog wired authored_labels P3 disaster_war_audit PASS war_types_library 5 authored 0 dials wired authored_labels P3 relationship 11 authored_discrete 0 11 wired authored_labels P3 no AssetManager lib -decisions_library 127 live+dial 0 12 wired 12_action_phrases P1 try_new_plot and warrior_train_with_dummy authored non-camera -spells 12 live+dial 0 12 wired raw_id_in_label P1 7 signalIds@86; 5 ambient@44 -powers 339 live+dial 0 23 wired raw_id_in_label P1 ambient CI=false -items 111 live+dial 0 111 wired raw_id_forges_verb P1 ambient A; forge verb weak -genes 47 live+dial 0 47 wired raw_id_in_label P1/P2 ambient A spam risk -phenotypes 52 live+dial 0 52 wired raw_id_in_label P1/P2 ambient A spam risk -world_laws_library 49 live+dial 0 49 wired raw_id_in_label P1/P2 ambient A -subspecies_traits 204 live+dial 0 204 wired raw_id_in_label P1/P2 ambient A -biome_library 29 live+dial 0 0 wired raw_id_template P3 ambient CI=false -culture_traits 78 live+dial 0 78 wired raw_id_in_label P1 TSV audited; not fail-gated -religion_traits 40 live+dial 0 40 wired raw_id_in_label P1 TSV audited; not fail-gated -clan_traits 29 live+dial 0 29 wired raw_id_in_label P1 TSV audited; not fail-gated -language_traits 26 live+dial 0 26 wired raw_id_in_label P1 TSV audited; not fail-gated +decisions_library 127 live+dial 0 37 wired 37_action_phrases P3 expanded 0.28.27; camera-a-inventory.tsv +spells 12 live+dial 0 6 wired display_names P3 Signal spectacle; 6 FX B +powers 339 live+dial 0 41 wired display_names P3 Signal widened 0.28.27; ambient CI=false +items 111 live+dial 0 42 wired gains_verb P3 Signal mythril/adamantine/silver/steel/bone +genes 47 live+dial 0 7 wired display_names P3 warfare/damage/mutagen Signal +phenotypes 52 live+dial 0 0 wired display_names P3 all B +world_laws_library 49 live+dial 0 17 wired display_names P3 dramatic + forever_/cursed/army… +subspecies_traits 204 live+dial 0 21 wired display_names P3 dramatic + mutation/death/blood +biome_library 29 live+dial 0 0 wired display_names P3 ambient CI=false +culture_traits 78 live+dial 0 27 wired display_names P3 dramatic widened 0.28.27 +religion_traits 40 live+dial 0 6 wired display_names P3 +clan_traits 29 live+dial 0 13 wired display_names P3 +language_traits 26 live+dial 0 2 wired display_names P3 buildings 618 patch_only n/a consume_and_civ_complete partial EventReason.BuildingEat_BuildingComplete P3 civ complete/wonder A; destroy demoted B boats n/a patch_only n/a trade_unload wired EventReason.Boat P3 load skipped combat n/a csharp_policy n/a pair_keys wired EventReason.Fight P3 -architecture_library 53 none n/a 0 covered_by_building_activity n/a P3 -city_build_orders 3 none n/a 0 covered_by_building_activity n/a P3 -kingdoms_traits 5 none n/a 0 covered_by_trait_meta_feeds n/a P3 -items_modifiers 59 none n/a 0 covered_by_item_feed n/a P3 -combat_action_library 11 none n/a 0 covered_by_spell_combat_feeds n/a P2 only if distinct beats -loyalty_library 29 none n/a 0 covered_by_worldlog_happiness n/a P3 -opinion_library 24 none n/a 0 covered_by_worldlog_happiness n/a P3 -knowledge_library 11 none n/a 0 covered_by_worldlog_happiness n/a P3 -communication_library 10 none n/a 0 covered_by_worldlog_happiness n/a P3 -story_library 1 none n/a 0 covered_by_worldlog_happiness n/a P3 -citizen_job_library 13 none n/a 0 covered_by_activity_dossier n/a P3 -professions 5 none n/a 0 covered_by_activity_dossier n/a P3 -personalities 5 none n/a 0 covered_by_activity_dossier n/a P3 -tasks_actor 217 none n/a 0 activity_taxonomy n/a P3 unmappedTasks=0 -actor_library 322 scoring_overlay n/a 0 species_discovery n/a P3 taxonomy PASS -plot_category_library 9 none n/a 0 category_only n/a P3 -AllianceManager.removeObject n/a worldlog 0 via_alliance_dissolved worldlog_covers authored_worldlog P3 not mutation gap -KingdomManager.removeObject n/a worldlog 0 via_kingdom_destroyed worldlog_covers authored_worldlog P3 not mutation gap -building_complete_wonder n/a patch n/a civ_complete Building.completeConstruction EventReason.BuildingComplete P3 temple/statue spectacle strength -World.era_manager_poll n/a wired n/a era_change WorldAgeManager.startNextAge EventCatalog.Era P3 update→startNextAge already emits -World.earthquake_manager_poll n/a wired n/a quake_sticky Earthquake.startQuake EarthquakeActive P3 holds while isQuakeActive -combat_action_library 11 covered_by_spell_combat n/a 0 CombatActionLibrary.tryToCastSpell n/a P3 no separate catalog -story_knowledge_opinion n/a covered_by_worldlog_happiness n/a 0 n/a n/a P3 Wave3 closed -personalities_professions 5+5 covered_by_activity_dossier n/a 0 n/a n/a P3 Wave3 closed +camera_a_inventory 1143 harness 0 219 wired camera-a-inventory.tsv P3 A=219 B=924 domains=13; gate camera_a_inventory_ok mutation_gaps 0 harness 0 n/a gaps_empty n/a P3 managers=57 libraryAssets=2893 diff --git a/docs/world-event-inventory.md b/docs/world-event-inventory.md index 8af9164..9a38107 100644 --- a/docs/world-event-inventory.md +++ b/docs/world-event-inventory.md @@ -52,10 +52,11 @@ Only true brief FX, cooldowns, civic Aggregates, and god-tool / biome spam stay | Relationship | 11 | all interesting discrete | | Plot / Era / War / Book | 28 / 11 / 5 / 12 | all A | | Trait | 116 | all CI | -| Decision | 127 live / 14 prose overlays | 12 camera-interesting | -| Spell / Item / Gene / Phenotype / WorldLaw / SubspeciesTrait | live | Signal-only A (ambient CI=false); phenotypes all B | -| Culture / Religion / Clan / LanguageTrait | live dials | Signal-only via dramatic heuristic | -| Power / Biome | live | Signal predicate only / ambient CI=false | +| Decision | 127 live / 37 prose overlays | **37** camera-interesting (0.28.27) | +| Spell / Item / Gene / Phenotype / WorldLaw / SubspeciesTrait | live | Signal-only A: spell 6 / item 42 / gene 7 / phenotype 0 / law 17 / subsp 21 | +| Culture / Religion / Clan / LanguageTrait | live dials | Signal dramatic: 27 / 6 / 13 / 2 | +| Power / Biome | live | Power Signal **41**; biome 0 (ambient CI=false) | +| Library+decision inventory dump | 1143 rows | **219 A / 924 B** (`.harness/camera-a-inventory.tsv`) | | Building / Boat | none | destroy/consume/trade/unload; damage/load skipped | ## Wired hooks (major)