refactor(memory): M45 裁决 D —— temporal 位撤出判定,只保留观测

按 r1 复审裁决 D:这一位先只做观测,`resolveRetention` 不许读它。理由(实测):
无条件 one_off ⇒ temp 会当天删 21 条长期约定;只放开 N6 位置判据能翻的 13 条
逐条是约定、而复审点名的三条目标行 0/3 救得了。在「模型真实标签分布」这份证据
缺位时不该做 7 天后物理删的不可逆决定。

撤接线(结论集逐字回到 M45 之前):
- retention.go:resolveRetention 不再读 item.Temporal;与之对比 dev base
  (af61b8c)本文件**只有注释差异**,规则与判定入口逐字未变。
- extract_retention.go:judgeExtractionRetention 签名回退单参;删除
  judgeRetentionTimepointWide 与 n6_timepoint_wide 规则码。与 dev base 对比
  **同样只有注释差异** ⇒ 「结论集 = 不含 temporal 的那个集合」是结构性的,
  不是靠调用点记得别传。
- 连带取消初版的 durable / recurring ⇒ long(零影响必须是双向的)。

保留观测面(一律未动):迁移 0027 的列、自举前滚、提取器的 temporal 产出、
prompt 枚举、闭集与 normalizeTemporal、store_temporal.go 的校验/编码。
另外把 prompt 里「标成 one_off 会让它进临时层、到期消失」这句**撤接线后已是假话**
改成中性标注说明 —— 否则会诱导模型避开 one_off,观测数据直接被污染。

测试:
- TestTemporalBitDoesNotAffectRetention —— 4 类语料 × 5 个取值,(档位,规则码)
  与未分型逐字相同(核心正断言);
- TestTemporalOneOffDoesNotMakeAnythingTemporary / ...DoesNotRescueRuleHitRows
  —— 零影响的双向点名;
- TestTemporalIsStillRecorded —— one_off 的约定行仍落 temporal='one_off' 而档位
  long、expires 空(观测在、判定不动);
- TestTemporalDoesNotTouchExplicitTierOrRestrictedSource —— 人工入口与受限来源不变。
变异实测:把 `if item.Temporal == TemporalOneOff { return temp }` 插回
resolveRetention ⇒ 上述四条用例全红(FAIL 输出已贴给塔),恢复后全绿。

IngestRuleVersion 保持 d3.5,注释改准为「记录 temporal 信号,但不参与判定」
(留痕面变了:库里多了「模型当时标了什么」这一维,回退会让新旧留痕混在一起)。

P2 三条保留:store.go 500 行(拆 store_temporal.go)、temporal.go 头注('' 的口径
+ 两次被否的接线方案 + 接线前必须看的那两条统计 SQL)、报告语境段。

回归:go build ./... + go vet ./... 全绿;memory/db 包测试全绿;memory -race
38.2s 全绿。
This commit is contained in:
AskaEth committed 2026-10-26 19:21:24 +08:00
1 parent 3b9ae3f918
commit c7c0294a16
11 files changed
+280 -551

No files matched your search

@@ -276,13 +276,15 @@ func TestIngestGatePlanExpiresAtUsesSameLayoutAsTimeGate(t *testing.T) {
// 规则内容未改但判据的作用范围变了(每一行都在同一笔 INSERT 里落档位与有效期,
// 且不再依赖同步闸是否开启),因此按规矩升版。
//
// d3.5(切片 M45)给判定链补上「时间性元数据位」:`one_off` ⇒ temp、
// `durable` / `recurring` ⇒ long、`unknown` ⇒ 旧规则。N1~N7 的规则与阈值一字未改,
// 但同一段正文的结论会变(d3.4 只能靠词判),因此同样按规矩升版。
// d3.5(切片 M45)**记录 `temporal` 信号,但不参与判定**:提取器产出侧多标了一维
// 时间性位(迁移 0027),随同一笔 INSERT 落库;`resolveRetention` 不读它,因此
// 判定的结论集与 d3.4 逐字相同。仍升版是因为**留痕面变了**(库里多了「模型当时标了
// 什么」这一维),将来接线时要能区分「接线前/后」的结论 —— 理由见 preinsert.go
// 的版本史。
func TestIngestRuleVersionIsD35(t *testing.T) {
t.Parallel()
if IngestRuleVersion != "d3.5" {
t.Fatalf("IngestRuleVersion = %q, want d3.5(时间性元数据位接入判定链)", IngestRuleVersion)
t.Fatalf("IngestRuleVersion = %q, want d3.5(记录 temporal 信号,但不参与判定)", IngestRuleVersion)
}
}