- 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
378 lines
15 KiB
C#
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);
|
|
}
|
|
}
|