feat(events): 渠道事件桥接接线 + 组合根(design/26 E3+E4)

- E3:channelbridge/events.go 唯一插入点 recordEvent(两轴映射 Category→Tier、摘要恒过 SanitizeNoticeText、角色/账号只认白名单)+ Options.EventStore 注入
  - 未接线 store=nil ⇒ 内存计数 + 首次 DEBUG,绝不中断入站(变异实测:改成直接调 Record ⇒ panic,测试红)
  - 普通聊天消息零副作用(变异:去掉 Applicable 早退 ⇒ rows=1 红)
  - T1 遥测只计数不落行(变异:心跳误判 T2 ⇒ 「逐条落行 1 行,want 0」红)
- E4:wire_channel_events.go(启动期清扫 + 双 ticker + 退出 flush,逐字对齐 wire_document_gc 的三条取舍)、wire_channels 注入、main.go 加一行 startChannelEvents
- internal/config/duration_env.go:新 env 键的读取口径(进程环境 > .env > 默认;「没写」与「写了空」都当没配;非法值回落 + 报错)——避免「只写在 .env 里被静默忽略」
- 三个新 env 键:CHANNEL_EVENT_RETENTION / GC_INTERVAL / COUNTER_FLUSH(模板同批更新,测试钉住键名一致)
- 插入点比设计示意图晚一步(放 preEntryReview 之后,只归一化一次且 NoticeClass 已有结论),「留存无条件、在任何早退之前」这条性质不变
This commit is contained in:
AskaEth committed 2026-10-05 14:10:24 +08:00
1 parent 7aaf7731dc
commit afe9afb1b5
12 files changed
+1689 -2

No files matched your search

@@ -24,6 +24,7 @@ import (
"git.yeij.top/AskaEth/Cyrene_v2/internal/channel/session"
"git.yeij.top/AskaEth/Cyrene_v2/internal/logger"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/documents"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/events"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/history"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model"
@@ -162,6 +163,15 @@ type Options struct {
// 空即视为**未接线**:带文件的消息照旧能跑(模型会收到一行「读不到」的诚实
// 提示),只是不落库、不抽取 —— 绝不假装读到了。
DocumentStore documents.StoreConfig
// EventStore 是**渠道事件留存**面(design/26 §4/§5;切片 E3):所有非消息事件
// (含未知类型与解析失败)经 channelbridge/events.go 的 recordEvent **无条件**
// 写进它 —— T2/T3 与 unknown 逐条落行、T1 只累加计数。
//
// 它只依赖 `events.Store` 接口,因此为 nil 时桥接器走**降级路径**(内存计数 +
// 首次一条 DEBUG),入站流水线**绝不**因为没有存储而失败或丢帧(fail-visible 而
// 非 fail-crash,§4.3)。注入必须传**真 nil 接口**而不是装了 nil 指针的接口,
// 否则这条判据会失效(见 cmd/cyrene/wire_channel_events.go 的 channelEventStore)。
EventStore events.Store
}
// Bridge 掌管渠道适配器生命周期与入站消息流水线。它
@@ -180,13 +190,19 @@ type Bridge struct {
quietStartHour int
quietEndHour int
now func() time.Time
// noticeLog 是系统通知传入前审查(design/12 §6 策略一补充)的子功能日志器,
// 与 voiceLog 同款:`source=services/channelbridge/notice` 便于跨模块定位。
// noticeLog 是系统通知传入前审查(design/12 §6 策略一补充)的子功能日志器:
// `source=services/channelbridge/notice` 便于跨模块定位。三个通知类日志
// (notice / flow / event)都在构造期一次性标好来源,使「这条为什么没进她上下文」
// 「这一帧有没有留下可查痕迹」在日志里可追溯。
noticeLog *slog.Logger
// flowLog 是流控解析(design/12 §6 策略三,含账号级 directMsgPerMin)的子功能
// 日志器:`source=services/channelbridge/flowgate`,使「主人显式关掉某项流控」
// 在日志里可追溯(见 flowgate.go 的 directLimit)。
flowLog *slog.Logger
// eventLog 是渠道事件留存(design/26 §4;切片 E3)的子功能日志器:
// `source=services/channelbridge/events`。留存成功走 DEBUG(含 NoticeClass 的
// 裁决结果),未接线 / 落库失败走 DEBUG(首帧)+ WARN(失败),全部带来源。
eventLog *slog.Logger
// 参与度引擎状态(design/18):按会话的内存状态机,
// 加上约束它的角色提醒词 / 参与度参数,以及概率触发
@@ -219,6 +235,11 @@ type Bridge struct {
// documentsCfg 是入站附件落盘配置(design/24 §3;切片 M1)。零值 = 未接线:
// 带文件的消息照旧能跑,模型会收到一行「读不到」的诚实提示(绝不静默)。
documentsCfg documents.StoreConfig
// eventStore 是渠道事件留存面(design/26 §4;切片 E3)。**真 nil 接口** = 未接线:
// 非消息事件走内存计数降级,入站照常(见 events.go 的 recordEvent)。
// eventFallback 是那条降级路径的计数面(有界,fail-visible)。
eventStore events.Store
eventFallback *eventFallback
// voiceSTT / voiceSTTTimeout / voiceCircuit 是入站语音转写面(切片 IM-ASR;
// design/06 §1.1):注入点、独立短超时,以及按原因分类的**临时熔断**。
// voiceLog 是带 `services/channelbridge/voice` 来源的子功能日志器。
@@ -286,6 +307,7 @@ func New(opts Options) (*Bridge, error) {
now: now,
noticeLog: logger.WithSource(log, "services/channelbridge/notice"),
flowLog: logger.WithSource(log, flowgateLogSource),
eventLog: logger.WithSource(log, "services/channelbridge/events"),
triggerWords: opts.TriggerWords,
personaPrompt: opts.PersonaPrompt,
engage: opts.Engage,
@@ -301,6 +323,8 @@ func New(opts Options) (*Bridge, error) {
channelPersona: opts.ChannelPersona,
adapterPersona: make(map[string]string),
documentsCfg: opts.DocumentStore,
eventStore: opts.EventStore,
eventFallback: newEventFallback(),
voiceSTT: opts.VoiceSTT,
voiceSTTTimeout: voiceSTTTimeout(opts.VoiceSTTTimeout),
voiceLog: logger.WithSource(log, "services/channelbridge/voice"),