package memory import ( "errors" "fmt" ) // 本文件是 `memory_items.temporal`(迁移 0027)在**写入路径**上的那一半:哨兵错误、 // 字段校验、以及落库时的列值编码。 // // 🔴 其余三处的归属(别在这条链上另开一份实现): // - **字段与语义**在 store.go 的 MemoryItem 上(结构体的字段不能跨文件声明), // 闭集与归一化在 temporal.go; // - **判定**仍是 `resolveRetention`(retention.go)里的 N1~N7 —— `temporal` // **只被记录,不参与判定**(r1 复审裁决 D),因此 `resolveRetention` 里 // **没有、也不许有**「第 4 步看 temporal」这种东西; // - **DDL** 在 migrations/0027 + store_schema.go + temporal_schema.go。 // // 要把 `temporal` 接进判定,前置条件写在 temporal.go 头注:先拿到模型真实标签分布 // (那里给了两条只读 SQL),再改 `temporal_test.go` 的 temporalFieldSites 白名单 —— // 那张表是**有意的接线决定**的唯一入口,不许绕过它。 // // 拆出本文件只为守 AGENTS §10 的文件行数上限(store.go 已到 500 行)与「模块按职责 // 拆源文件」那条规范 —— 口径逐字未变。 // ErrInvalidTemporal 在条目的 Temporal(时间性元数据位,迁移 0027)不是闭集内的 // 值时返回。空串**不在**此列:它是「尚未分型」这一合法状态。 var ErrInvalidTemporal = errors.New("memory: invalid temporal kind") // validateTemporal 只接受闭集内的值:时间性位是**枚举元数据**,一个自造的值 // ("sometimes")既判不出档位、又不该静默落库 —— 提取器已经把模型输出归一成 // unknown(temporal.go 的 normalizeTemporal),走到这里还是非法值只能是程序错误, // 因此直接拒,而不是替它挑一个值。 func (it *MemoryItem) validateTemporal() error { if !it.Temporal.valid() { return fmt.Errorf("%w: %q", ErrInvalidTemporal, it.Temporal) } return nil } // temporalColumn 返回要写进 `temporal` 列的值(与 `ingestGatePlan.retention()` / // `expiresAt()` 同族:把「条目 → 落库值」这一步收在类型自己身上,插入语句里不留 // 裸转换,也就不可能出现两处各转一次、口径分叉)。 func (it MemoryItem) temporalColumn() string { return string(it.Temporal) }