///|
pub(all) enum ReplayStepKind {
LoadMarketDataPlan
LoadMarketSnapshot
LoadPromptPacket
LoadModelExchange
LoadRoutineEventLog
LoadAnalysisProjection
LoadStructureLevels
LoadContextBudget
LoadBookCommit
LoadAnalysisRecord
LoadExperienceMemorySelection
LoadChartFrame
LoadReviewQueue
LoadImportedLegacyRecord
LoadImportedExperienceMemory
LoadImportedTradeLog
LoadImportManifest
RebuildFollowUpContext
CompareProjection
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct ReplayStep {
run_id : @domain.RunId
kind : ReplayStepKind
path : String
schema_id : String
required : Bool
purpose : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub(all) struct ReplayPlan {
run_id : @domain.RunId
status : @workflow.AnalysisRunStatus
source_id : @domain.SourceId
live_market_required : Bool
can_replay : Bool
blocking_reason : String?
steps : Array[ReplayStep]
} derive(Debug, Eq, ToJson, FromJson)
///|
pub fn replay_step(
run_id : @domain.RunId,
kind : ReplayStepKind,
path : String,
schema_id : String,
purpose : String,
required? : Bool = true,
) -> ReplayStep {
{ run_id, kind, path, schema_id, required, purpose }
}
///|
fn step_kind_for_anchor(kind : @followup.FollowUpAnchorKind) -> ReplayStepKind {
match kind {
MarketDataPlan => LoadMarketDataPlan
MarketSnapshot => LoadMarketSnapshot
PromptPacket => LoadPromptPacket
ModelExchange => LoadModelExchange
RoutineEventLog => LoadRoutineEventLog
AnalysisProjection => LoadAnalysisProjection
StructureLevels => LoadStructureLevels
ContextBudget => LoadContextBudget
BookCommit => LoadBookCommit
AnalysisRecord => LoadAnalysisRecord
ExperienceMemorySelection => LoadExperienceMemorySelection
ChartFrame => LoadChartFrame
ReviewQueue => LoadReviewQueue
ImportedLegacyRecord => LoadImportedLegacyRecord
ImportedExperienceMemory => LoadImportedExperienceMemory
ImportedTradeLog => LoadImportedTradeLog
ImportManifest => LoadImportManifest
}
}
///|
fn append_anchor_steps(
steps : Array[ReplayStep],
context : @followup.FollowUpContext,
) -> Unit {
for anchor in context.anchors {
steps.push(
replay_step(
context.run_id,
step_kind_for_anchor(anchor.kind),
anchor.path,
anchor.schema_id,
anchor.purpose,
),
)
}
}
///|
fn has_projection(context : @followup.FollowUpContext) -> Bool {
context.anchors.any(fn(anchor) { anchor.kind is AnalysisProjection })
}
///|
pub fn prepare_replay_plan(bundle : @workflow.AnalysisRunBundle) -> ReplayPlan {
let context = @followup.prepare_follow_up_context(bundle)
let steps : Array[ReplayStep] = []
append_anchor_steps(steps, context)
steps.push(
replay_step(
context.run_id,
RebuildFollowUpContext,
"records/followups/\{context.run_id}.json",
"followup-context",
"rebuild follow-up context from durable analysis evidence",
),
)
let can_replay = bundle.status is Completed && has_projection(context)
if can_replay {
steps.push(
replay_step(
context.run_id,
CompareProjection,
"records/projections/\{context.run_id}.json",
"dry-execution-projection",
"compare regenerated deterministic projection against stored evidence",
),
)
}
{
run_id: context.run_id,
status: bundle.status,
source_id: context.source_id,
live_market_required: false,
can_replay,
blocking_reason: if can_replay {
None
} else {
Some("stored market snapshot and projection are not available")
},
steps,
}
}