worldbox-observer-mod/IdleSpectator/Narrative/NarrativePersistenceMapper.cs
DazedAnon ff4b40d00e feat(narrative): enhance narrative probes and presentation coverage.
- Introduce new narrative probes for episode grammar, ensemble balance, and prose redundancy
- Implement narrative presentation coverage tracking for better event visibility
- Update harness scenarios to include new narrative ingestion and persistence tests
- Refactor event emission to include narrative development IDs and presentations
- Expand InterestCandidate to support narrative presentation models and roles
2026-07-23 14:12:23 -05:00

378 lines
15 KiB
C#

using System.Collections.Generic;
namespace IdleSpectator;
internal static class NarrativePersistenceMapper
{
public static NarrativeEventRecordDto ToDto(NarrativeEventRecord value) =>
new NarrativeEventRecordDto
{
id = value?.Id ?? "",
dedupeKey = value?.DedupeKey ?? "",
kind = (int)(value?.Kind ?? NarrativeEventKind.Unknown),
subjectId = value?.SubjectId ?? 0,
subject = ToDto(value?.Subject ?? default),
otherId = value?.OtherId ?? 0,
other = ToDto(value?.Other ?? default),
developmentId = value?.DevelopmentId ?? "",
correlationKey = value?.CorrelationKey ?? "",
familyKey = value?.FamilyKey ?? "",
cityKey = value?.CityKey ?? "",
kingdomKey = value?.KingdomKey ?? "",
warKey = value?.WarKey ?? "",
plotKey = value?.PlotKey ?? "",
previousState = value?.PreviousState ?? "",
newState = value?.NewState ?? "",
outcome = value?.Outcome ?? "",
note = value?.Note ?? "",
resolved = value?.Resolved ?? false,
evidenceSource = value?.EvidenceSource ?? "",
dateLabel = value?.DateLabel ?? "",
worldTime = value?.WorldTime ?? 0d,
observedAt = value?.ObservedAt ?? 0f,
magnitude = value?.Magnitude ?? 0f,
confidence = value?.Confidence ?? 0f
};
public static NarrativeEventRecord FromDto(NarrativeEventRecordDto value) =>
value == null ? null : new NarrativeEventRecord
{
Id = value.id ?? "",
DedupeKey = value.dedupeKey ?? "",
Kind = (NarrativeEventKind)value.kind,
SubjectId = value.subjectId,
Subject = FromDto(value.subject),
OtherId = value.otherId,
Other = FromDto(value.other),
DevelopmentId = value.developmentId ?? "",
CorrelationKey = value.correlationKey ?? "",
FamilyKey = value.familyKey ?? "",
CityKey = value.cityKey ?? "",
KingdomKey = value.kingdomKey ?? "",
WarKey = value.warKey ?? "",
PlotKey = value.plotKey ?? "",
PreviousState = value.previousState ?? "",
NewState = value.newState ?? "",
Outcome = value.outcome ?? "",
Note = value.note ?? "",
Resolved = value.resolved,
EvidenceSource = value.evidenceSource ?? "",
DateLabel = value.dateLabel ?? "",
WorldTime = value.worldTime,
ObservedAt = value.observedAt,
Magnitude = value.magnitude,
Confidence = value.confidence
};
public static NarrativeDevelopmentDto ToDto(NarrativeDevelopment value)
{
var dto = new NarrativeDevelopmentDto
{
id = value?.Id ?? "",
kind = (int)(value?.Kind ?? NarrativeDevelopmentKind.Unknown),
function = (int)(value?.Function ?? NarrativeFunction.Noise),
subjectId = value?.SubjectId ?? 0,
subject = ToDto(value?.Subject ?? default),
otherId = value?.OtherId ?? 0,
other = ToDto(value?.Other ?? default),
correlationKey = value?.CorrelationKey ?? "",
familyKey = value?.FamilyKey ?? "",
cityKey = value?.CityKey ?? "",
kingdomKey = value?.KingdomKey ?? "",
warKey = value?.WarKey ?? "",
plotKey = value?.PlotKey ?? "",
previousState = value?.PreviousState ?? "",
newState = value?.NewState ?? "",
outcome = value?.Outcome ?? "",
evidenceSource = value?.EvidenceSource ?? "",
dateLabel = value?.DateLabel ?? "",
occurredAt = value?.OccurredAt ?? 0f,
magnitude = value?.Magnitude ?? 0f,
confidence = value?.Confidence ?? 0f,
presentable = value?.Presentable ?? false,
isNewStateChange = value?.IsNewStateChange ?? false
};
if (value != null) dto.otherIds = value.OtherIds.ToArray();
return dto;
}
public static NarrativeDevelopment FromDto(
NarrativeDevelopmentDto value,
double savedWorldTime,
double currentWorldTime)
{
if (value == null) return null;
var result = new NarrativeDevelopment
{
Id = value.id ?? "",
Kind = (NarrativeDevelopmentKind)value.kind,
Function = (NarrativeFunction)value.function,
SubjectId = value.subjectId,
Subject = FromDto(value.subject),
OtherId = value.otherId,
Other = FromDto(value.other),
CorrelationKey = value.correlationKey ?? "",
FamilyKey = value.familyKey ?? "",
CityKey = value.cityKey ?? "",
KingdomKey = value.kingdomKey ?? "",
WarKey = value.warKey ?? "",
PlotKey = value.plotKey ?? "",
PreviousState = value.previousState ?? "",
NewState = value.newState ?? "",
Outcome = value.outcome ?? "",
EvidenceSource = value.evidenceSource ?? "",
DateLabel = value.dateLabel ?? "",
OccurredAt = NarrativePersistence.Rebase(
value.occurredAt, savedWorldTime, currentWorldTime),
Magnitude = value.magnitude,
Confidence = value.confidence,
Presentable = value.presentable,
IsNewStateChange = false
};
if (value.otherIds != null) result.OtherIds.AddRange(value.otherIds);
return result;
}
public static NarrativeThreadDto ToDto(NarrativeThread value)
{
var dto = new NarrativeThreadDto
{
id = value?.Id ?? "",
kind = (int)(value?.Kind ?? NarrativeThreadKind.Unknown),
protagonistId = value?.ProtagonistId ?? 0,
anchorKey = value?.AnchorKey ?? "",
openedByDevelopmentId = value?.OpenedByDevelopmentId ?? "",
latestMeaningfulChangeId = value?.LatestMeaningfulChangeId ?? "",
centralQuestion = value?.CentralQuestion ?? "",
pressureEvidence = value?.PressureEvidence ?? "",
resolution = value?.Resolution ?? "",
phase = (int)(value?.Phase ?? NarrativePhase.Setup),
status = (int)(value?.Status ?? NarrativeThreadStatus.Abandoned),
openedAt = value?.OpenedAt ?? 0f,
updatedAt = value?.UpdatedAt ?? 0f,
momentum = value?.Momentum ?? 0f,
urgency = value?.Urgency ?? 0f,
coherence = value?.Coherence ?? 0f,
novelty = value?.Novelty ?? 0f,
coverageDebt = value?.CoverageDebt ?? 0f
};
if (value != null)
{
var cast = new List<NarrativeCastRoleDto>(value.Cast.Count);
for (int i = 0; i < value.Cast.Count; i++)
{
NarrativeCastRole role = value.Cast[i];
if (role != null)
cast.Add(new NarrativeCastRoleDto
{
characterId = role.CharacterId,
role = role.Role ?? ""
});
}
dto.cast = cast.ToArray();
dto.developmentIds = value.DevelopmentIds.ToArray();
}
return dto;
}
public static NarrativeThread FromDto(
NarrativeThreadDto value,
double savedWorldTime,
double currentWorldTime)
{
if (value == null) return null;
var result = new NarrativeThread
{
Id = value.id ?? "",
Kind = (NarrativeThreadKind)value.kind,
ProtagonistId = value.protagonistId,
AnchorKey = value.anchorKey ?? "",
OpenedByDevelopmentId = value.openedByDevelopmentId ?? "",
LatestMeaningfulChangeId = value.latestMeaningfulChangeId ?? "",
CentralQuestion = value.centralQuestion ?? "",
PressureEvidence = value.pressureEvidence ?? "",
Resolution = value.resolution ?? "",
Phase = (NarrativePhase)value.phase,
Status = (NarrativeThreadStatus)value.status,
OpenedAt = NarrativePersistence.Rebase(
value.openedAt, savedWorldTime, currentWorldTime),
UpdatedAt = NarrativePersistence.Rebase(
value.updatedAt, savedWorldTime, currentWorldTime),
Momentum = value.momentum,
Urgency = value.urgency,
Coherence = value.coherence,
Novelty = value.novelty,
CoverageDebt = value.coverageDebt
};
if (value.cast != null)
{
for (int i = 0; i < value.cast.Length; i++)
{
NarrativeCastRoleDto role = value.cast[i];
if (role != null)
result.Cast.Add(new NarrativeCastRole
{
CharacterId = role.characterId,
Role = role.role ?? ""
});
}
}
if (value.developmentIds != null) result.DevelopmentIds.AddRange(value.developmentIds);
return result;
}
public static CharacterConsequenceDto ToDto(CharacterConsequence value) =>
new CharacterConsequenceDto
{
id = value?.Id ?? "",
characterId = value?.CharacterId ?? 0,
threadId = value?.ThreadId ?? "",
developmentId = value?.DevelopmentId ?? "",
kind = (int)(value?.Kind ?? CharacterConsequenceKind.Unknown),
role = value?.Role ?? "",
otherId = value?.OtherId ?? 0,
other = ToDto(value?.Other ?? default),
context = value?.Context ?? "",
outcome = value?.Outcome ?? "",
dateLabel = value?.DateLabel ?? "",
occurredAt = value?.OccurredAt ?? 0f,
importance = value?.Importance ?? 0f,
confidence = value?.Confidence ?? 0f
};
public static CharacterConsequence FromDto(
CharacterConsequenceDto value,
double savedWorldTime,
double currentWorldTime) =>
value == null ? null : new CharacterConsequence
{
Id = value.id ?? "",
CharacterId = value.characterId,
ThreadId = value.threadId ?? "",
DevelopmentId = value.developmentId ?? "",
Kind = (CharacterConsequenceKind)value.kind,
Role = value.role ?? "",
OtherId = value.otherId,
Other = FromDto(value.other),
Context = value.context ?? "",
Outcome = value.outcome ?? "",
DateLabel = value.dateLabel ?? "",
OccurredAt = NarrativePersistence.Rebase(
value.occurredAt, savedWorldTime, currentWorldTime),
Importance = value.importance,
Confidence = value.confidence
};
public static CharacterStoryStateDto ToDto(CharacterStoryState value)
{
var dto = new CharacterStoryStateDto
{
characterId = value?.CharacterId ?? 0,
identity = ToDto(value?.Identity ?? default),
storyMomentum = value?.StoryMomentum ?? 0f,
storyPotential = value?.StoryPotential ?? 0f,
lastMeaningfulChangeAt = value?.LastMeaningfulChangeAt ?? 0f
};
if (value != null)
{
dto.openThreadIds = value.OpenThreadIds.ToArray();
dto.resolvedThreadIds = value.ResolvedThreadIds.ToArray();
dto.recentDevelopmentIds = value.RecentDevelopmentIds.ToArray();
dto.consequenceIds = value.ConsequenceIds.ToArray();
}
return dto;
}
public static CharacterStoryState FromDto(
CharacterStoryStateDto value,
double savedWorldTime,
double currentWorldTime)
{
if (value == null) return null;
var result = new CharacterStoryState
{
CharacterId = value.characterId,
Identity = FromDto(value.identity),
StoryMomentum = value.storyMomentum,
StoryPotential = value.storyPotential,
LastMeaningfulChangeAt = NarrativePersistence.Rebase(
value.lastMeaningfulChangeAt, savedWorldTime, currentWorldTime)
};
Add(result.OpenThreadIds, value.openThreadIds);
Add(result.ResolvedThreadIds, value.resolvedThreadIds);
Add(result.RecentDevelopmentIds, value.recentDevelopmentIds);
Add(result.ConsequenceIds, value.consequenceIds);
return result;
}
public static LifeSagaFactDto ToDto(LifeSagaFact value) =>
new LifeSagaFactDto
{
key = value?.Key ?? "",
kind = (int)(value?.Kind ?? LifeSagaFactKind.Unknown),
subjectId = value?.SubjectId ?? 0,
otherId = value?.OtherId ?? 0,
subject = ToDto(value?.Subject ?? default),
other = ToDto(value?.Other ?? default),
at = value?.At ?? 0f,
worldTime = value?.WorldTime ?? 0d,
dateLabel = value?.DateLabel ?? "",
strength = value?.Strength ?? 0f,
provenance = value?.Provenance ?? "",
kingdomKey = value?.KingdomKey ?? "",
cityKey = value?.CityKey ?? "",
clanKey = value?.ClanKey ?? "",
familyKey = value?.FamilyKey ?? "",
warKey = value?.WarKey ?? "",
plotKey = value?.PlotKey ?? "",
resolved = value?.Resolved ?? false,
note = value?.Note ?? "",
mcCrossover = value?.McCrossover ?? false
};
public static LifeSagaFact FromDto(LifeSagaFactDto value) =>
value == null ? null : new LifeSagaFact
{
Key = value.key ?? "",
Kind = (LifeSagaFactKind)value.kind,
SubjectId = value.subjectId,
OtherId = value.otherId,
Subject = FromDto(value.subject),
Other = FromDto(value.other),
At = NarrativePersistence.Rebase(value.at, value.worldTime, value.worldTime),
WorldTime = value.worldTime,
DateLabel = value.dateLabel ?? "",
Strength = value.strength,
Provenance = value.provenance ?? "",
KingdomKey = value.kingdomKey ?? "",
CityKey = value.cityKey ?? "",
ClanKey = value.clanKey ?? "",
FamilyKey = value.familyKey ?? "",
WarKey = value.warKey ?? "",
PlotKey = value.plotKey ?? "",
Resolved = value.resolved,
Note = value.note ?? "",
McCrossover = value.mcCrossover
};
private static NarrativeIdentityDto ToDto(LifeSagaIdentity value) =>
new NarrativeIdentityDto
{
id = value.Id,
name = value.Name ?? "",
speciesId = value.SpeciesId ?? ""
};
private static LifeSagaIdentity FromDto(NarrativeIdentityDto value) =>
value == null ? default : new LifeSagaIdentity
{
Id = value.id,
Name = value.name ?? "",
SpeciesId = value.speciesId ?? ""
};
private static void Add(List<string> target, string[] source)
{
if (source != null) target.AddRange(source);
}
}