refactor(memory): M45 r1 复审返工 —— temporal 位只放开 N6 位置判据
按 r1 复审裁定(p1-3items / fix-then-merge)重做三处: P1-1/P1-2:删掉自造的六条语义安全阀(temporalSanityVeto)与约定词表 (retentionStatesAgreement)。理由被复审用两条生产行否证:它们既把该救的行 杀了(「…睡得比平时早」被习惯词、「…以后不用再惦记」被永久化标记),又挡不住 同义异形的约定(说定 / 约了)。现在 `one_off` 的全部作用是**放开 N6 的位置判据**: judgeExtractionRetention 新增 temporal 入参 → judgeRetentionTransient → judgeRetentionTimepointWide(位置内命中仍返 n6_timepoint,只有靠放开位置才命中 才返新增的 n6_timepoint_wide,供观测区分)。N1~N5、N7、护栏①②、N6 的 1~7 条 语义安全阀一字不动;durable / recurring 仍直接判 long(fail-safe 方向)。 P1-3:上界口径改为「时点词存在 ∧ 语义安全阀全过 ∧ 当前 long」——不依赖任何 标注,可逐条列出。实测(生产库只读副本,快照 2026-10-26):最近 500 条 active 能翻 13 条、**逐条都是「约定 + 今天没走成」**;全量 3694 条能翻 26 条(13 条 约定 + 13 条状态行)。旧的「句首时点词」口径是同义反复,已删。 已知代价(写进 temporal.go 头注与 TestTemporalOneOffWidenedPositionTouchesAgreements, 不藏在词表后面):位置窗口今天正是那批约定行的唯一保护,放开后只要模型标 one_off 它们就会判 temp;而复审点名的两条目标行本片救不了(被语义阀挡,与位置 无关)。因此这一位在当前语料上**没有可测收益**,是否保留是产品裁决。 P2-1:store.go 503 → 497 行,拆出 store_temporal.go(哨兵错误 + 字段校验 + 列值编码)。 P2-2:temporal.go 头注改准 —— `''` 是「0027 之前的历史行 + 没做时间性判断的 写入路径(ManualExtractor / 网关手写 / 整理回填,它们由调用方显式给档位)」。 P2-3:报告补语境(retention_tier 非空仅 26 行、temp 1 行、temporal 列当时还不 存在 ⇒ 重放结论对新写入没有预测力)。 测试:验收点 ①~⑤ 按新语义重写;新增「位置放开可打红」的变异靶子与「N7 位置 不放宽」「无时点词时这一位不做事」「两条目标行救不了」「约定行会翻(已知风险)」 五条边界断言。变异实测:unlocksTimepointPosition 改恒 false ⇒ 三条用例红。 回归:go build ./... + go vet ./... 全绿;memory/db 包测试与 memory -race 全绿。
This commit is contained in:
1 parent
91101dedfb
commit
3b9ae3f918
9 files changed
+412
-370
No files matched your search
@@ -18,6 +18,14 @@ import (
|
||||
// **不进灰区**(于是 T1 一个 token 都花不出去);把闸摘掉时那条断言会立刻变红
|
||||
// (判成 create 且灰区非空)。
|
||||
|
||||
// judgeRetentionNoTemporal 是**本文件与 transient 测试的便捷封装**:不带时间性位
|
||||
// (= 0027 之前的旧规则)。切片 M45 把 `temporal` 作为入参加进了规则函数(它只在
|
||||
// N6 的位置判据上起作用),因此「旧规则」的每一处断言都显式传 TemporalUnset,
|
||||
// 而不是靠一个隐式默认值 —— 「不带这一位时行为逐字不变」这件事必须在调用点看得见。
|
||||
func judgeRetentionNoTemporal(content string) retentionRule {
|
||||
return judgeExtractionRetention(content, TemporalUnset)
|
||||
}
|
||||
|
||||
// retentionPositiveCases 是正向清单(design/03 §10.4)的脱敏样本与**两道护栏**
|
||||
// 的样本:它们必须**全部**放行(retentionNone)。
|
||||
func retentionPositiveCases() []struct {
|
||||
@@ -118,8 +126,8 @@ func TestExtractionRetention_EmotionWithObjectIsNotDeferred(t *testing.T) {
|
||||
t.Fatalf("%q:余部为空 = %t 与 wantDefer = %t 不一致",
|
||||
tc.content, rest == "", tc.wantDefer)
|
||||
}
|
||||
if rule := judgeExtractionRetention(tc.content); (rule == retentionEmotion) != tc.wantDefer {
|
||||
t.Fatalf("judgeExtractionRetention(%q) = %q, wantEmotionDefer=%t —— 带宾语的与纯情绪的必须给出相反结论",
|
||||
if rule := judgeRetentionNoTemporal(tc.content); (rule == retentionEmotion) != tc.wantDefer {
|
||||
t.Fatalf("judgeRetentionNoTemporal(%q) = %q, wantEmotionDefer=%t —— 带宾语的与纯情绪的必须给出相反结论",
|
||||
tc.content, rule, tc.wantDefer)
|
||||
}
|
||||
})
|
||||
@@ -161,7 +169,7 @@ func TestExtractionRetention_PositivesAreNeverDeferred(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if rule := judgeExtractionRetention(tc.content); rule != retentionNone {
|
||||
if rule := judgeRetentionNoTemporal(tc.content); rule != retentionNone {
|
||||
t.Fatalf("正例 %q 被拦成 %q —— 那是把真记忆丢进临时层(fail-safe 方向被违反)",
|
||||
tc.content, rule)
|
||||
}
|
||||
@@ -177,7 +185,7 @@ func TestExtractionRetention_NegativesAreDeferred(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if rule := judgeExtractionRetention(tc.content); rule != tc.rule {
|
||||
if rule := judgeRetentionNoTemporal(tc.content); rule != tc.rule {
|
||||
t.Fatalf("反例 %q 命中 %q, want %q", tc.content, rule, tc.rule)
|
||||
}
|
||||
})
|
||||
@@ -189,7 +197,7 @@ func TestExtractionRetention_NegativesAreDeferred(t *testing.T) {
|
||||
func TestExtractionRetention_UpperCaseASCII(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, content := range []string{"HI", "Thanks", "hello~"} {
|
||||
if rule := judgeExtractionRetention(content); rule != retentionChatter {
|
||||
if rule := judgeRetentionNoTemporal(content); rule != retentionChatter {
|
||||
t.Fatalf("%q 命中 %q, want %q(ASCII 词应先折小写)", content, rule, retentionChatter)
|
||||
}
|
||||
}
|
||||
@@ -294,7 +302,7 @@ func TestExtractionRetention_PersistentFactsAreNeverDeferred(t *testing.T) {
|
||||
content := content
|
||||
t.Run(content, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if rule := judgeExtractionRetention(content); rule != retentionNone {
|
||||
if rule := judgeRetentionNoTemporal(content); rule != retentionNone {
|
||||
t.Fatalf("持久事实 %q 被判成 %q —— 它会进临时层、7 天后被物理删除(不可逆)",
|
||||
content, rule)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user