package counterfactual import ( "git.flytoex.net/yuanwei/flyto-agent/pkg/evolve" ) // Meta keys carried on the produced evolve.ReplayEvent. Cross-package // consumers (Reflector implementations that want to read reverse-thinking // context off ReplayEvent.Meta or ReplayEvent.Log.Meta) match these literal // strings. Constants centralized so future renames are coordinated. // // 产出的 evolve.ReplayEvent 上携带的 Meta key. 跨包消费方 (想从 // ReplayEvent.Meta 或 ReplayEvent.Log.Meta 读反向思维上下文的 Reflector // 实现) 按这些字面量匹配. 集中常量化便于协调改名. const ( // MetaKeyStep tags ReplayEvent.Log.Meta with the Step constant value // (StepRead / StepReverse / etc.) so a Reflector can filter events // produced from a specific phase of the five-step cycle. // // MetaKeyStep 标 ReplayEvent.Log.Meta 携带 Step 常量值 (StepRead / // StepReverse 等), Reflector 可按五步中具体哪一步过滤. MetaKeyStep = "flyto.counterfactual.step" // MetaKeyVerdict tags ReplayEvent.Log.Meta with the Verdict string // so a Reflector can fan events by verdict label without unmarshaling // the full Deliverable from Payload. // // MetaKeyVerdict 标 ReplayEvent.Log.Meta 携带 Verdict 字符串, Reflector // 可按 verdict 标签分发, 不必从 Payload unmarshal 完整 Deliverable. MetaKeyVerdict = "flyto.counterfactual.verdict" // MetaKeySource tags ReplayEvent.Meta to mark the upstream source // of the event ("reverse_think" for events produced by this adapter). // Reflectors that consume from multiple LogReplayer sources use this // to route correctly. // // MetaKeySource 标 ReplayEvent.Meta 表事件上游来源 ("reverse_think" // 表本 adapter 产出). 多 LogReplayer 来源的 Reflector 据此路由. MetaKeySource = "flyto.counterfactual.source" // SourceReverseThink is the canonical value for MetaKeySource on // events produced by AsReplayEvent. // // SourceReverseThink 是 AsReplayEvent 产出事件上 MetaKeySource 的规范值. SourceReverseThink = "reverse_think" ) // AsReplayEvent adapts the Deliverable into an evolve.ReplayEvent so a // reverse-thinking conclusion can be pushed through evolve.LogReplayer // for consumption by registered evolve.Reflector implementations. This // closes the "evolution sink" loop: reverse-thinking verdicts are // replayed against real KPI feedback over time so the system learns // the correlation between "what reverse-think said" and "what actually // happened". // // # Why the adapter lives in counterfactual, not in evolve // // evolve stays schema-agnostic by design (doc.go: "All interfaces // exchange business data as any / string / float64. The engine makes no // assumption about any industry schema."). Importing counterfactual // into evolve would couple a generic learning loop to one specific // upstream signal type. The reverse direction is fine -- counterfactual // declares "I know how to feed evolve" -- and mirrors the reflector // umbrella's 4 cross-family adapters (Validator/Evaluator/evolve.Reflector // are sibling-callable, replaceable backends; counterfactual provides // a Deliverable-to-LogEntry bridge in the same shape). // // # Feedback nil at production time // // At reverse-think time the decision has not yet produced a real-world // outcome -- there is no KPI to score against. Feedback returns nil // here, matching evolve.ReplayEvent's documented "decision just landed, // KPI has not arrived yet" semantics. The platform layer fills Feedback // later, when the actual KPI signal arrives (e.g. on-time rate from a // settlement match), via evolve.FeedbackChannel.Report. Reflectors that // pair Log + Feedback to learn the verdict / outcome correlation read // both from a paired-up event downstream. // // # Payload safety // // Payload is a Clone of d, not d itself, so a Reflector that mutates // the Payload (some implementations rewrite Meta during ingestion) does // not retroactively corrupt the staging Record or audit log that still // holds a reference to d. // // # nil receiver // // Calling on a nil *Deliverable returns the zero ReplayEvent rather // than panicking. This is consistent with Clone's nil tolerance and // lets defensive callers chain the adapter without explicit nil checks. // // AsReplayEvent 把 Deliverable 适配为 evolve.ReplayEvent, 让反向思维结论 // 可经 evolve.LogReplayer 推给注册的 evolve.Reflector 实现消费. 这关上 // "进化沉淀" 循环: 反向思维 verdict 与现实 KPI 反馈随时间重放, 系统学习 // "反向思维说的" 与 "实际发生的" 相关性. // // 为什么 adapter 在 counterfactual 包不在 evolve 包: evolve 保持 schema- // agnostic (doc.go 明示). evolve import counterfactual 会把通用学习循环 // 绑到一种上游信号类型. 反方向 OK -- counterfactual 声明 "我知道怎么喂 // evolve" -- 与 reflector umbrella 4 个跨家族 adapter 同形态 (Validator / // Evaluator / evolve.Reflector 同族可换后端, counterfactual 提供 Deliverable // 到 LogEntry 的桥, 形态一致). // // 反向思维时 Feedback 为 nil: 决策尚未产生现实后果, 没有 KPI 可打分. 与 // evolve.ReplayEvent godoc 的 "决策刚发生, 反馈延迟中" 语义一致. platform // 层在真实 KPI 到达时 (如账单匹配的准时率) 经 evolve.FeedbackChannel.Report // 填 Feedback. Reflector 配对 Log + Feedback 学习 verdict / 后果相关性时 // 从下游配对事件读两端. // // Payload safety: Payload 是 d 的 Clone 而非 d 本身. Reflector 修改 Payload // (有些实现摄入时重写 Meta) 不回溯污染仍持引用的 staging.Record 或审计日志. // // nil receiver: 在 nil *Deliverable 上调返回零值 ReplayEvent 而非 panic. // 与 Clone 的 nil 兼容一致, 防御性调用方可链式调不必显式 nil 检查. func (d *Deliverable) AsReplayEvent() evolve.ReplayEvent { if d == nil { return evolve.ReplayEvent{} } return evolve.ReplayEvent{ Log: evolve.LogEntry{ Timestamp: d.OccurredAt, DecisionID: d.DecisionID, Entity: d.ToolName, Payload: d.Clone(), Meta: map[string]any{ MetaKeyStep: d.Step, MetaKeyVerdict: string(d.Verdict), }, }, Feedback: nil, Meta: map[string]any{ MetaKeySource: SourceReverseThink, }, } }