feat(memory): D3 第五态 defer(入库审查)+ 提取留存规则闸 + 临时 TTL 配置面
主人原话:「收窄提取器,确实要给他一个主动式的记忆留存规则,不能想到什么都 往记忆里写」「.env 只做兜底用 …这些键优先从面板配置上取」「临时记忆到期删除」。 按 design/23 §18(D3 第五态 defer)、§19(到期处置)、design/03 §9.6 (tempTtlSec 默认 7 天 + 坏值口径)、§10(提取留存规则)落地。 - IngestDecision 闭集加第五态 defer:照常 active 落库 + 写短 expires_at 落 临时层(不删行、不改正文,回滚 = 清空该列);IngestRuleVersion d3.2 → d3.3。 - 落点:ingestGatePlan 增 ExpiresAt + expiresAt()(走 expiryText/formatTime 的 定宽 30 字节 UTC,与读侧时效闸同一套文本口径),由 finishIngest 在 defer 一态 补写 expires_at(INSERT 与补写之间的短暂窗口如实登记,方向 = 宁可多留)。 非 defer 三态一笔都不多写。 - T0 提取留存规则闸(extract_retention.go):design/03 §10.5 的 N1~N5 纯规则, 接进 judgeIngest 的候选比对之前,命中即 defer + reason=t0_low_value,不进 T1; 两道护栏(显式「记住」/ 持久信号)一票放行,fail-safe 方向 = 宁可多留。 - T1 闭集扩为 merge/modify/keep/defer(同一个 prompt、同一次调用,绝不新增 第二次模型调用):只有关系判为真新时才问价值;defer 要求 target=0,否则判 非法回落 create(reason=t1_reply_invalid)。 - 提取器提示词加固(design/03 §10.3 B):正向清单 + 反例清单 + 「允许返回 []」。 - 临时记忆 TTL:代码默认 tempTtlSec = 604800(7 天);面板 $DATA_DIR/config/memory-tidy.json 的 tempTtlSec 优先(ApplyReviewTuning 逐键 解析,坏值回落默认 + WARN,绝不写进 cfg)。该键在 .env 里没有出处且不新增 (.env 已冻结)⇒ 实际生效链是「面板 > 代码默认」。启动播种同步该键(*int + omitempty,nil 省略、绝不写 null),保证播种文件与生效值逐字一致。 - preinsert_store.go 的 listReviewCandidatesSQL 原位注释:这条内部召回 SQL 刻意不过时效闸的裁定与理由(design/03 §11.2 第 3 条)。 - 测试:defer 落库带短 expires_at(闸 + T1 两条路径)、写入口径与时效闸同源、 TTL 坏值与回落、规则版本 d3.3、整理候选幂等键不含 IngestRuleVersion、 提取规则正例 11 条 / 反例 11 条。 验收:go build ./... + go vet ./... + go test ./... 全绿;windows/darwin 交叉 编译通过(GOOS=darwin GOARCH=arm64 / GOOS=windows GOARCH=amd64)。
This commit is contained in:
1 parent
68ba85389b
commit
21b906ffb0
18 files changed
+1352
-35
No files matched your search
@@ -17,6 +17,10 @@ type ReviewStats struct {
|
||||
Merged int
|
||||
Modified int
|
||||
Created int
|
||||
// Deferred 是**异步审查层**判出第五态 defer 的条数(T0 规则闸 / T1 同一次
|
||||
// 调用都可能给出它)。它与 Created 分列:两者都留下新行,但只有 defer 带
|
||||
// 短 `expires_at`,它是「临时层新增」的观测量。
|
||||
Deferred int
|
||||
Dropped int
|
||||
Failed int
|
||||
// GateChecked 是**同步入库闸**实际做了一次判定的条数(跳过闸的条目不计)。
|
||||
@@ -26,6 +30,11 @@ type ReviewStats struct {
|
||||
GateAbsorbed int
|
||||
// GateFailed 是闸因预算/候选源不可用而 fail-open 的次数(照常插入 + 留痕)。
|
||||
GateFailed int
|
||||
// GateDeferred 是闸当场判定为**第五态 defer** 并**真的写成了** `expires_at`
|
||||
// 的次数(design/23 §18.1)。它与 GateAbsorbed 分列:「当场折回重复」与
|
||||
// 「当场放进临时层」是两条不同的观测线,加成一个数面板就读不出分型。
|
||||
// 只统计写成功的(写失败时那行停在长期层,不是临时记忆)。
|
||||
GateDeferred int
|
||||
// T1Called 是 T1 实际发出过**模型调用**的次数。每次审查至多 +1
|
||||
// (defaultT1MaxGray 只是把多条灰区候选打包进同一次 prompt,不多发请求)。
|
||||
T1Called int
|
||||
@@ -58,6 +67,10 @@ func (r *PreInsertReviewer) recordDecision(rev IngestReview) {
|
||||
s.Merged++
|
||||
case IngestModify:
|
||||
s.Modified++
|
||||
case IngestDefer:
|
||||
// 第五态单独一档:它与 create 都「留下了新行」,但一个有 TTL、
|
||||
// 一个没有 —— 混进 Created 就看不出「有多少记忆是临时的」。
|
||||
s.Deferred++
|
||||
default:
|
||||
s.Created++
|
||||
}
|
||||
@@ -79,8 +92,10 @@ func (r *PreInsertReviewer) auditWith(verb string, rev IngestReview) {
|
||||
|
||||
// reviewStatsLabel 把计数渲染成一条稳定日志串。
|
||||
func reviewStatsLabel(s ReviewStats) string {
|
||||
return fmt.Sprintf("reviewed=%d skip=%d merge=%d modify=%d create=%d dropped=%d failed=%d "+
|
||||
"gate_checked=%d gate_absorbed=%d gate_failed=%d t1_called=%d t1_decided=%d t1_throttled=%d",
|
||||
s.Reviewed, s.Skipped, s.Merged, s.Modified, s.Created, s.Dropped, s.Failed,
|
||||
s.GateChecked, s.GateAbsorbed, s.GateFailed, s.T1Called, s.T1Decided, s.T1Throttled)
|
||||
return fmt.Sprintf("reviewed=%d skip=%d merge=%d modify=%d create=%d defer=%d dropped=%d failed=%d "+
|
||||
"gate_checked=%d gate_absorbed=%d gate_deferred=%d gate_failed=%d "+
|
||||
"t1_called=%d t1_decided=%d t1_throttled=%d",
|
||||
s.Reviewed, s.Skipped, s.Merged, s.Modified, s.Created, s.Deferred, s.Dropped, s.Failed,
|
||||
s.GateChecked, s.GateAbsorbed, s.GateDeferred, s.GateFailed,
|
||||
s.T1Called, s.T1Decided, s.T1Throttled)
|
||||
}
|
||||
Reference in new issue
Block a user