using System; using System.Collections.Generic; using System.Text; namespace IdleSpectator; /// /// Honest live-verification ledger (Phase 0). Regenerated each run; not committed. /// Levels: none | feed | pipeline | id_drop | id | unsupported | fail /// public sealed class EventLiveCoverageRow { public string Domain = ""; public string Id = ""; public bool Camera; public bool Inject; public string LiveLevel = "none"; public string Pipeline = ""; public string Notes = ""; } public sealed class EventLiveCoverageSummary { public int Id; public int IdDrop; public int Pipeline; public int Feed; public int None; public int Unsupported; public int Fail; public int CameraRows; public int CameraNone; public string Detail => $"id={Id} id_drop={IdDrop} pipeline={Pipeline} feed={Feed} none={None} " + $"unsupported={Unsupported} fail={Fail} camera={CameraRows} camera_none={CameraNone}"; } public static class EventLiveCoverageLedger { private static readonly Dictionary Rows = new Dictionary(StringComparer.OrdinalIgnoreCase); private static string Key(string domain, string id) => (domain ?? "") + "\t" + (id ?? ""); public static int RowCount => Rows.Count; public static void Clear() { Rows.Clear(); } public static void SeedFromCatalogs() { Clear(); foreach (string id in EventCatalog.Happiness.AuthoredIds) { HappinessCatalogEntry e = EventCatalog.Happiness.GetOrFallback(id); bool camera = EventCatalog.IsCameraWorthy(e); AddSeed("happiness", id, camera, camera); } foreach (string id in EventCatalog.Status.AuthoredIds) { StatusInterestEntry e = EventCatalog.Status.GetOrFallback(id); bool camera = EventCatalog.IsCameraWorthy(e); AddSeed("status", id, camera, camera); } foreach (string id in EventCatalog.WorldLog.AuthoredIds) { WorldLogEventEntry e = EventCatalog.WorldLog.GetOrFallback(id); bool camera = EventCatalog.IsCameraWorthy(e); AddSeed("worldLog", id, camera, camera); } foreach (string id in EventCatalog.Disaster.AuthoredIds) { DisasterInterestEntry e = EventCatalog.Disaster.GetOrFallback(id); bool camera = e != null && EventCatalog.IsCameraWorthy(e.CreatesInterest); AddSeed("disasters", id, camera, camera); } foreach (string id in EventCatalog.WarType.AuthoredIds) { WarTypeInterestEntry e = EventCatalog.WarType.GetOrFallback(id); bool camera = e != null && EventCatalog.IsCameraWorthy(e.CreatesInterest); AddSeed("warTypes", id, camera, camera); } SeedDiscrete("relationship", EventCatalog.Relationship.AuthoredIds, id => EventCatalog.Relationship.GetOrFallback(id)); SeedDiscrete("plots", EventCatalog.Plot.AuthoredIds, id => EventCatalog.Plot.GetOrFallback(id)); SeedDiscrete("books", EventCatalog.Book.AuthoredIds, id => EventCatalog.Book.GetOrFallback(id)); SeedDiscrete("eras", EventCatalog.Era.AuthoredIds, id => EventCatalog.Era.GetOrFallback(id)); SeedDiscrete("traits", EventCatalog.Trait.AuthoredIds, id => EventCatalog.Trait.GetOrFallback(id)); foreach (string id in EventCatalog.Decision.AuthoredIds) { bool camera = EventCatalog.Decision.IsCameraWorthy(id); AddSeed("decisions", id, camera, camera); } SeedDiscrete("spell", EventCatalog.Spell.AuthoredIds, id => EventCatalog.Spell.GetOrFallback(id)); SeedDiscrete("item", EventCatalog.Item.AuthoredIds, id => EventCatalog.Item.GetOrFallback(id)); SeedDiscrete("power", EventCatalog.Power.AuthoredIds, id => EventCatalog.Power.GetOrFallback(id)); SeedDiscrete("gene", EventCatalog.Gene.AuthoredIds, id => EventCatalog.Gene.GetOrFallback(id)); SeedDiscrete("phenotype", EventCatalog.Phenotype.AuthoredIds, id => EventCatalog.Phenotype.GetOrFallback(id)); SeedDiscrete("worldLaw", EventCatalog.WorldLaw.AuthoredIds, id => EventCatalog.WorldLaw.GetOrFallback(id)); SeedDiscrete("subspecies_trait", EventCatalog.SubspeciesTrait.AuthoredIds, id => EventCatalog.SubspeciesTrait.GetOrFallback(id)); SeedDiscrete("biome", EventCatalog.Biome.AuthoredIds, id => EventCatalog.Biome.GetOrFallback(id)); } private static void SeedDiscrete(string domain, IEnumerable ids, Func get) { if (ids == null) { return; } foreach (string raw in ids) { string id = (raw ?? "").Trim(); if (string.IsNullOrEmpty(id)) { continue; } DiscreteEventEntry e = get(id); bool camera = EventCatalog.IsCameraWorthy(e); AddSeed(domain, id, camera, camera); } } private static void AddSeed(string domain, string id, bool camera, bool inject) { string key = Key(domain, id); Rows[key] = new EventLiveCoverageRow { Domain = domain, Id = id, Camera = camera, Inject = inject, LiveLevel = "none", Pipeline = "", Notes = "" }; } /// Overwrite live proof for one id. Does not invent catalog rows. public static void Claim(string domain, string id, string liveLevel, string pipeline, string notes) { string key = Key(domain, id); if (!Rows.TryGetValue(key, out EventLiveCoverageRow row)) { row = new EventLiveCoverageRow { Domain = domain ?? "", Id = id ?? "", Camera = true, Inject = false }; Rows[key] = row; } row.LiveLevel = string.IsNullOrEmpty(liveLevel) ? "none" : liveLevel.Trim(); row.Pipeline = pipeline ?? ""; row.Notes = notes ?? ""; } public static EventLiveCoverageSummary Summarize() { var s = new EventLiveCoverageSummary(); foreach (EventLiveCoverageRow row in Rows.Values) { if (row.Camera) { s.CameraRows++; } switch ((row.LiveLevel ?? "none").Trim().ToLowerInvariant()) { case "id": s.Id++; break; case "id_drop": s.IdDrop++; break; case "pipeline": s.Pipeline++; break; case "feed": s.Feed++; break; case "unsupported": s.Unsupported++; break; case "fail": s.Fail++; break; default: s.None++; if (row.Camera) { s.CameraNone++; } break; } } return s; } public static string Write(string outputDirectory) { var tsv = new StringBuilder(); tsv.AppendLine("domain\tid\tcamera\tinject\tlive_level\tpipeline\tnotes"); var keys = new List(Rows.Keys); keys.Sort(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < keys.Count; i++) { EventLiveCoverageRow row = Rows[keys[i]]; tsv.Append(row.Domain).Append('\t') .Append(row.Id).Append('\t') .Append(row.Camera ? "true" : "false").Append('\t') .Append(row.Inject ? "true" : "false").Append('\t') .Append(row.LiveLevel ?? "none").Append('\t') .Append(row.Pipeline ?? "").Append('\t') .Append(row.Notes ?? "").Append('\n'); } CatalogCoverageAudit.WriteReport(outputDirectory, "event-live-coverage.tsv", tsv.ToString()); return Summarize().Detail; } }