100 Commits
Author SHA1 Message Date
小唯 7f7171ac14 feat(recall): 召回契约字段 + trace 回溯 + 生命周期/实体质量判据(工作树收口)
这批是 10-26~27 已在生产二进制(zhiyid-protectrails-20261027)里运行、
但一直留在工作树未提交的改动。收口原因:三件改造要开分支,工作树脏 =
分支基准与回滚点都不存在。

主要内容:
- api/routes/contract.go + trace.go:召回响应契约字段(trace_id/status/scope/
  continuation/channel)与 /api/v1/trace 回溯端点
- governance/entity_quality.go:实体质量闸
- storage/trace.go + recall.go/recall_write_buffer.go:召回写入缓冲与轨迹
- 测试:contract/recall_contract_fields/recall_lifecycle/stale_lifecycle/
  entity_quality/trace

同时修一个 flaky:recall_lifecycle_test 原本硬编码「今天 11:00 已过」,
凌晨跑就会把「已失效」fixture 当成仍有效。改成相对时间(过期=now-1h),
生命周期判据与运行时刻无关。修完 go test ./internal/api/routes ./internal/storage 全绿。
2026-10-28 02:09:19 +08:00
小唯 0b2b4f01d8 fix(storage): recall_seen_count 批更新加 COALESCE —— NULL 行不再吞召回观测值 (t_5aa7cb77)
批路径 .column("recall_seen_count", "recall_seen_count + delta") 下推 DataFusion,
SQL 语义 NULL+n=NULL ⇒ 17717 行(43.8%)观测值静默丢失。改 COALESCE(recall_seen_count,0)+delta。
逐条 fallback 路径本就 NULL-aware(读现值 unwrap_or(0))且其 split_whitespace 3 段
解析不容 COALESCE,故不动并加注释防后人误改。
2026-10-27 04:34:48 +08:00
小唯 d7a73d7e6c fix(recall): top_k 收口 + 恢复 main 可构建性
1) top_k 收口(t_9025b0eb)
   /api/v1/recall 无视 top_k:top_k=5 实测返回 341 条(5 distilled + 336 graph_expanded),
   top_k=10 返回 521 条。因 ExpandFromResults 扩展结果 append 无上限。
   后果:插件记忆预取被撑爆(journal 实测单次 flush 合并 900/780/613/549/351 条),
   真相关条目落在被截断段;count 失真;使用追踪按千级记账稀释指标。
   修法:capRecallResults —— results = 主结果 ≤top_k;扩展单独走 graph_expanded 字段
   (上限 top_k,能力仍可观测);主结果不足时用扩展补齐(稀疏查询仍受益)。
   + core_topk_test.go 5 例 6 断言钉住契约。

2) 恢复 main 可构建性(P0,非本卡范围但阻塞一切构建)
   rebase 丢了 metrics.ConsolLastSuccessTime / ConsolConsecutiveFailures /
   ConsolidateBusyWaitTotal / MetaNoteRejectTotal 的定义(只在 f96c828),
   而调用方已进 main,且 consolidation_track.go 整个文件不在树上 ⇒ go build 失败。
   从 f96c828 原样恢复 4 个指标定义并注册;从 2275b83 恢复 consolidation_track.go。
2026-10-26 16:29:43 +08:00
小唯 1c7882ce34 fix(graph): SQLiteGraphStore.ExpandFromResults 恒 0 产出 — from/to 是节点ID却拿裸名比对(t_724f31ad)
816/819 行把 Navigate 返回的节点 ID(n_织忆)与裸实体名 entity 做 == ⇒ 恒不相等 ⇒ 路径全被 continue ⇒ 结构性 0 条附加。
修:比对改用 nodeID(normalizeEntityID(entity));附加结果补 Category=graph_expanded + ID=邻居节点ID(非空,修复 recall.go ID 去重与审计计数);Content 用可读显示名(displayNodeName)。
补单测:正向(n_织忆→n_图谱 链+1条recall ⇒ 补入 graph_expanded 且 ID 非空) + 反向(图外实体 ⇒ 0 补入不凭空加)。
2026-10-26 14:55:01 +08:00
小唯 2ac7c9d5a1 feat(write-ops): t_writeops_llm_judge — 写时判定器改 LLM 三分类 + apply 硬保护
问题(离线回放实测,非推测):
- 规则基 defaultJudge 以 ZHIYI_WRITE_SIM_UPDATE=0.70 判 UPDATE,17179 条影子日志里
  14435 条(84%)被判「新事实应覆盖旧事实」
- 人工抽检 15 条低相似度样本,15/15 不是真覆盖(「用户查看知乎链接」vs「用户查看微信文章」
  都被判成覆盖);低档 LLM 判定精度同样不足(0.70-0.85 档 REPLACE 精度约 25%)
- 结论:相似度只反映「话题相关」,不反映「是否同一属性的新旧值」

改动:
- 新增 llm_judge.go:REPLACE/DUPLICATE/KEEP 三分类,仅 sim>=ZHIYI_WRITE_JUDGE_SIM(0.95)
  才问模型,低档短路 ADD;调用失败兜底 ADD(宁可不覆盖)
- JudgeWriteOp:judge 显式注入 > apply/llm 模式用 LLMJudge > 规则基
- writeOpsApply 硬保护:apply 强制要求 ZHIYI_WRITE_JUDGE=llm,否则降级 shadow 并留痕
  (防止规则基 84% UPDATE 在 apply 下误覆盖上万条)
- 单测 8 条 + 真实 LLM e2e 3 条(ZHIYI_LIVE_JUDGE=1 才跑)

验收:go test ./internal/distill/ 全绿;live e2e 真覆盖→UPDATE / 假覆盖→ADD / 重复→NOOP 3/3
部署:shadow 模式(不改库),观察 2-3 天后 op 分布应从 84% UPDATE 降到 5-15% 再考虑 apply
2026-10-25 23:06:42 +08:00
小唯 66d5049151 feat(feedback): t_11245d30 区分人机信号 — MarkUseful 支持 source=auto → 记 auto_feedback
人工点「有用」仍 user_feedback(行为不变);插件自动反馈(_auto_feedback_for_reply)
传 source=auto → 记 auto_feedback,让 zhiyi:vprop_decisions 可辨「牧尘认可 vs 机器自评」。

纯观测,零行为变化:不改 V 权重/语义闸阈值/_MAX_PER_TURN。待 Go toolchain 重建后生效。
2026-10-24 04:34:25 +08:00
小唯 f979bd6ffc feat(recall): 融合权重可配 ZHIYI_FUSION_W(默认0.7=零变化,1.0=纯向量)
t_5624c0ff → 牧尘 2026-10-21 批准「按推荐执行」。

依据(strict n=134,golden-v4):
- 现状 fuse 0.1125 vs 纯向量 0.1898 ⇒ 现状是负收益,比纯向量低 39%
- 去 usage 0.2019 但逐 query worst −100%(12/134 从答对变彻底答错)
- MoA expert-panel 4 槽:3 槽指向止血 + intern-s2 指出根因是召回不足(相关文档在 pool#10-14)
- A/C 绝对差 0.0121 在 n=134 上不显著 ⇒ 不为它背 9% 硬失败率

改动:三处硬编码 0.7/0.3 参数化为 fusionW(candidates.QualityScore / reranked.Score / base 展示分)。
回滚:ZHIYI_FUSION_W=0.7 或删除该 env(逐位回到改动前)。
2026-10-21 20:35:30 +08:00
小唯andClaude Opus 4.8 8ea82fbec3 fix(storage): t_cf680fad SoftDelete 冲突耗尽静默丢 — 修「重试成功=0」+ 残留根治
根因(实证):runMerges O(n²) 软删 + 并发遗忘碎片器 在同一张 memories 单表上
制造 MVCC 写风暴;旧 3 次/~350ms 无 jitter 预算下每次重放都撞已推进的新版本
(单次 op 3 次重放 version 598346→598347→598348→598350 逐版推进仍耗尽),
失败软删被 consolidation_pipe.go:252 的 `_ =` 静默丢弃 ⇒ 源记录 is_deleted 停
false,每次重启窗口留新残留(检索重复命中)。

修(3 件,均 Go 侧 zhiyid):
① durable pending-softdelete 队列(softdelete_pending.go):MVCC 冲突耗尽 ⇒
   把 (id, reason) 追加进 /var/lib/memoryweave/pending-softdelete.jsonl
   (单写者 append + 原子 tmp/rename + 同 id 去重);zhiyid 启动 + 每 30s 触发器
   tick 各 drain 一次(SET is_deleted=true 幂等、重读最新已提交版本),风暴退去
   后重放必落盘 —— 根治「每次重启窗口都留新残留」。
② retrySoftDeleteRPC 预算 3→5 + 退避加 0~50% jitter:破 50+ 并发软删锁步雷群
   (锁步本身是冲突持续的主因),多两次机会跨风暴窗口。
③ consolidation_pipe.go:252 `_ =` → 显式 log(观测、禁静默);队列负责最终落盘。

测试:storage 全绿(耗尽入队 / 非可重试不入队 / 同 id 去重 / 风暴退去 drain 落盘
清空 / 风暴未退 drain 保留队列)。6 文件:2 新 + 4 改。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-21 09:45:06 +08:00
小唯 2862f68631 feat(gate): 补提 t_bd63b641 门控复核资产 — quarantine 过滤 + junk 实体拒写 + ListPatterns 三返回值
- ListPatterns 改三返回值 (pats, skipped, err):单行 NULL/空 id 跳过计数不致全盘失败;
  排除 quarantine 名空间;COALESCE 防 NULL Scan 错误
- SQLiteGraphStore 增 isQuarantinedNode + Navigate/NavigateBiDir 过滤 quarantine 节点
- graph_auto.go 蒸馏写库前拒 junk 实体 (IsJunkName)
- 新增 entity_guard.go (实体名拒写门禁) + shadow_diff_test.go (影-复量具)
- docs/ac-evidence/t_bd63b641-shadow-gate/ 验收证据
- .gitignore 增 /go/tmp/ /verify.go,删 17.9M 编译二进制临时产物

build+test 均通过:go build ./... exit0;pattern+routes 两包 ok
2026-10-20 07:10:29 +08:00
小唯 b8d77547de chore: mark 79019bf (A10 huc 读侧+e2e) approved 2026-10-19 21:29:04 +08:00
小唯 79019bfc40 A10(t_d618dc7c): 补 human_useful_count 读侧接线 + 真实 LanceDB e2e 闸门
读侧静默 no-op 修复(t_4c810e02 同类:写进库但读不回):
- lancedb_ipc.go 读路径 unmarshal 结构体缺 human_useful_count 字段,
  导致 /recall、/memories 读回恒 null(列真实写入但读侧解包丢弃,无报错)。
  补 4 处:SearchWithTruncation 结构体+输出映射、Scan 结构体+输出映射、
  GetSkillCandidates(mapInt)、新增 mapIntPtr 可空整数映射(NULL≠0)。
- ScanAll/embedded-model 路径经 models.MemoryRecord 已带字段,无需改。

新增 human_useful_count_e2e_test.go(真实 sidecar 写→读回闸门,
仿 bitemporal_e2e 模式,未设 ZHIYI_HUC_E2E_SOCK 自动 skip):
- AC#4 读非空:存量行读回 NULL(nil);
- AC#5 同步+反例:人工 useful×2⇒huc=2/useful=2;机器 dedup 路径不污染 huc;
  人工 not-useful 只动 human_not_useful。

验证:go build 通过 + 全 storage 套件绿;真实 sidecar e2e 全绿
(AC4 读回 nil / AC5 huc=2 useful=2 / 反例隔离成立)。

git show --stat 212624a4341fac
2026-10-19 21:28:33 +08:00
小唯 a5bc27c3a4 feat(distill): 蒸馏落库前拒写空壳(t_e11207f8 治源①)— 共享判据 zhiyi_payload_guard_rules.json + Go payload_guard + OnDistillComplete 拦截 + /api/v1/payload-guard/stats + 3 单测;顺带修复 deploy-approved 清单坏行
- distill/payload_guard.go: 读共享 JSON(与 Python 同源),ShellCheck 带心跳/拦截计数
- api/server.go: OnDistillComplete fact 循环红act 后 ShellCheck 拒写空壳 + 启动加载 + stats 端点
- main_test.go: TestMain 加载共享规则供单测
- 修复 scripts/deploy-approved-commits.txt 尾行坏数据('appending:' 前缀 → 两条合法 SHA)
2026-10-19 21:16:57 +08:00
小唯 83c41963cf deploy: mark a293f7b+3533e55 (A10 human_useful_count) approved for deploy [t_d618dc7c] 2026-10-19 20:45:08 +08:00
小唯 3533e55801 feat(api): A10 recall/search 出口直通 human_useful_count(t_d618dc7c AC#4 读侧)
- models.RecallResult 加 HumanUsefulCount *int(nil=NULL=从未被人工点过,non-omitempty)
- storage/recall.go 主路径(800) + FTS词面通道(891) 两条 RecallResult 构造处接线 c.HumanUsefulCount
- api/routes/core.go supplement(shared 0.5 / notes 0.45) + keyword 通道三处接线 m/c.HumanUsefulCount
- 合成路径(graph_* / peer / pattern / graph fallback)无 MemoryRecord 来源,保持 nil(正确)
- 仅补『响应值==库值』显示缺口,不进排序公式(AC#6 排序零变化)
- 修复 t_4c810e02『加列不接 IPC=静默 no-op』同款坑:列现在真能读出
2026-10-19 20:06:12 +08:00
小唯 a293f7b784 feat(storage): A10 拆出人工有用 human_useful_count 单独列(t_d618dc7c)
- Rust lance schema 追加 human_useful_count (Int64, nullable);open() 自动加列
  迁移,存量回填 NULL(与 confidence/human_not_useful_count 迁移模式一致)
- MemoryRecord 读侧接线(get_by_id/search/scan_all/scan_deleted/record_from_batch)
  走 col_i64_opt(NULL 读回 None,区别于 0)
- insert_batch 写入侧:未声明/NULL → 写 NULL;显式整数 → 写值(与 confidence 同款)
- update() $inc 基数改 col_i64_opt(NULL 行按 0 起算,首次人工 useful NULL→1)
- Go IncrementUseful 同一次 Update 三 $inc:useful_count + recall_verified_count
  + human_useful_count(只有人工 feedback 路径调用,机器自评路径不写此列)
- Go MemoryRecord/memEntry 加 *int 字段(nil=NULL)
- 新增 human_useful_count_test.go:人工 useful 同时 +1、机器路径不动反例
- 排序公式/权重零改动(AC#6 排序零变化)
2026-10-19 19:42:29 +08:00
小唯 754976db52 deploy: mark c954aa2 (AC3/AC7 PosMode) approved for deploy [t_22b4e9d0] 2026-10-19 12:58:26 +08:00
小唯 c954aa2917 fix(storage): t_23b6a940 热度≠质量 — FeedbackScore pos 拆出 recall_verified_count(env ZHIYI_POS_MODE 四态, 默认 legacy 逐位一致)+ AC7 热门度运行时看门狗 + 5 Go 测试
金标 119 条离线 A/B(固定候选集 cands-119.json, 确定性 σ=0):
- baseline(pos含verified) MRR 0.7265
- champion(pos只信useful + importance w=0.15 + B=0.2) MRR 0.7699 (Δ+0.0434)
- 与 t_5d28ad74 已部署公式收敛(pos 去掉 recall_verified)
分层: chunk1 +0.0729 / chunk2 +0.0562 / chunk3 持平(无新增伤害)
门关(ZHIYI_FEEDBACK_BIAS=0)逐位等价; 回滚=置0零代码变更
AC4: 不读 deprecated not_useful_count ✓
5 Go 测试全 PASS: 门关delta=0 / 门开方向(none/weight/tiebreak) / 反向对照 / AC1 tiebreak同档
2026-10-19 03:33:01 +08:00
小唯 772a597a53 test(storage): t_7ba5e479 AC2 反馈信号进排序证明 — feedbackBias 门控 3 用例(门关 delta=0 / 门开 rank 下滑 / 正向对照)+ IncrementHumanNotUseful 走生产同一路径 2026-10-18 21:52:47 +08:00
小唯 1f30474cf3 feat(storage): t_789898bd importance 温度计 — 写入侧规则化 importance + env 回滚开关 + 存量回填工具
AC1 lancedb_ipc.go:159/:200 硬编码 importance 1.0 改为规则调用:
  EffectiveMemoryImportance(m)   显式值优先; 规则开⇒档位; 关(默认)⇒回落1.0(零行为变化)
  EffectiveEpisodeImportance()   episode 原始日志 规则开⇒0.3 预留档; 关⇒1.0
AC2 规则档位(全库实测标定, 每档>=1%, 无值==1.0): core=0.9(4.11%) / normal×wiki,llm_distill=0.7(70.06%) /
  normal×legacy,unknown=0.4(25.84%) / normal×recovery=0.3(预留档)
  未纳入: 内容深度(78.1%<50字⇒切档违反>=1%) / 时间衰减(排序已有运行时recency项, 避免双衰减) / 图谱连接度(红线不碰图谱)
AC3 存量回填: rust bin importance_backfill(仅写 importance 一列, id IN 组提交 25 版本,
  提交冲突有界退避, verify 逐行复算, rollback=整表1.0 一个版本)。
  生产执行: 46,930 行全部回填, 恒1.0 行数 46,930 -> 0 (verify mismatch=0)
  备份: ~/.hermes/state/t_789898bd-importance-backup/memories-id-importance.csv (46,913 行, 全部 1.0)
AC4 golden 集合 before/after: mrr 0.4345→0.4345, ndcg 0.4722→0.4722, keyword 14/14 不变(差 0%, <±10%)
AC5 回滚开关 ZHIYI_IMPORTANCE_RULE(off=默认, 逐位等同改动前); 回滚命令:
  importance_backfill --data-dir /var/lib/memoryweave --mode rollback
单测: go test ./internal/storage/ 全过(5 个新 importance 用例); 回归: storage+models+api/routes 全过
2026-10-18 21:27:17 +08:00
小唯 a1021bb70a feat(storage): t_7c0538eb AC5 低分可信评分记忆检索降权(可逆, env-gated, 默认关)
fuseQuality 对「可信且 0<qs<0.30」的行, rawQuality 贡献乘低分降权系数
lowScoreDownweight(qs)=max(floor=0.5, qs/0.30)(随分单调递增, 高分不动,
0.0/0.755-echo 走不可信分支不受影响)。

回滚开关 ZHIYI_LOWSCORE_DOWNWEIGHT: 缺省/0/false 全关→系数恒 1.0,
行为与改前逐位一致(go test TestFuseQuality 基线未变)。
测试 quality_fusion_lowscdw_test.go: 同一候选集 gate 关/开/再关,
验证 L(低分高重要性) 被 M(普通分) 反超 + 回滚复原。
2026-10-18 12:54:51 +08:00
小唯 e0412747f0 chore(deploy): t_20bfbd9a 批准清单补齐 14 个历史已评审提交 + HEAD 5f63b35 2026-10-18 02:22:18 +08:00
小唯 5f63b35602 chore(deploy): t_20bfbd9a 修正批准清单行粘连(每行一SHA) — 补齐 71d5f2a/941b7ee/3e29617 批准基线 2026-10-18 02:21:38 +08:00
小唯 3e29617cbe chore(deploy): t_20bfbd9a 追加批准部署基线 71d5f2a(优雅停止)+941b7ee(线程风暴根治) 2026-10-18 02:20:20 +08:00
小唯 941b7eec32 fix(storage): t_20bfbd9a 边车线程风暴根治 — Rust 连接并发上限+RSS护栏降级串行;命中事件重试跨commit指数退避+积压上限
AC1 Rust accept 循环对每连接 thread::spawn 无上限,Go 侧每 rpc 新 dial ⇒
   IPC 洪泛线程线性涨到 736。加 AtomicUsize 连接门(默认64, env ZHIYI_CONN_MAX),
   超限回 heavy_conn_busy;RSS 超上限(默认3000MB, env ZHIYI_RSS_LIMIT_MB)降级串行。
AC3 usage_recall 加 retry_count/next_retry_at:持久失败行指数退避(1s..600s)不再
   每 commit 热重扫;积压超 ZHIYI_USAGE_BACKLOG_MAX(默认500)本轮跳过扫描。
AC4 新增 usageBackoff/backlog 单测。Go 全仓测试通过。
2026-10-18 02:19:03 +08:00
小唯 71d5f2a7cd fix(storage): t_fa797edd 优雅停止全程有界 — Stop 最终落盘不再无限阻塞
根因:SIGTERM 到 StopRecallWriteBuffer(),Stop() 同步调用无界的 b.Flush()。
Rust/LanceDB 批量更新在活 IPC 流量下被卡住(生产实测 20:44 停止窗口内 Rust 侧
update_recall_batch 80s 未完成),Stop 永不返回,信号协程到不了 srv.Shutdown,
进程跑满 systemd 90s TimeoutStopSec 被 SIGKILL(丢写风险 + 重启不可控)。

修复:Stop() 全程有界 — 等后台协程 <=5s + 最终落盘 <=8s(goroutine+超时)。
召回统计丢失可接受(源码注释本就声明崩溃会丢最后一窗口),超时即放行退出。
新增反向用例 TestRecallWriteBufferStopBoundedWhenFlushHangs:flush 挂起时
Stop 在 8.0s 内放行(原实现无限阻塞)。storage 包全量测试通过,zhiyid 构建
exit=0。未部署(AC5 边界:仅改源码 + 隔离验证)。
2026-10-18 00:51:46 +08:00
小唯 f6c373ea94 fix(governance): t_818f77be ExpandFromResults 导航起点 r.Category→正文实体
InMemoryGraph(graph_expander.go:24)+FileGraph(graph_file.go:466) 旧实现拿
r.Category(类目名,如 distilled)当实体去 Navigate, 永远匹配不到任何图节点
⇒ 结构性零产出(实测 10/10 全 distilled, 0 graph_expanded)。InMemory 版另读
p[to]/p[from] 而 Navigate 返回 source/target, 双重零产出。

修复: 导航起点改为从 r.Content 提实体——复用现有 extract*Entities +
normalize*EntityID(与同文件 ExpandWithSummary 同一套), 不新造抽取逻辑;
InMemory 版路径键 to/from → source/target 一并对齐。Score:0.5 降权/去重/
pattern-peer 门控 均不动。

可观测性(AC2): 加 env 控 ZHIYI_GRAPH_EXPAND_DEBUG=1 的单行 debug 日志
(起点实体 N/命中 M/补入 K), 默认关低频, 保证下次坏了不沉默。

测试(AC4+AC3): graph_expand_e2e_test.go 4 用例锁死——小图(中文实体链)+
recall ⇒ 断言含 category=graph_expanded 且 Score=0.5; 10-recall 批量补入
改后 total=38(InMemory)/38(FileGraph); namespace 不匹配 ⇒ 补 0(次级阻塞
实证)。改前树副本跑同测试 ⇒ 全 0(复现结构零), 改后 ⇒ 38, 判别力成立。

FileGraph.AddNode/AddEdge 潜伏 RWMutex 自死锁(save 在写锁内取 RLock)不属
本卡, 测试改走 JSON 文件加载绕开。
2026-10-17 23:52:51 +08:00
小唯 978f27a164 feat(api): /api/v1/recall 暴露 Rust 侧单次重读行数上限截断标志 truncated(t_3aa2a8c1)
引擎已算(Rust ConsolidateResponse.truncated,t_576714de)且边车日志已打,
但 Go IPC 客户端只打日志不上抛 ⇒ /api/v1/recall 响应无法观测「结果被截断」。

- lancedb_ipc.go: 新增 SearchWithTruncation(上抛 ipcResp.Truncated;本地兜底/零结果恒 false);
  旧签名 Search 委托之(行为不变)。
- recall.go: RecallMeta 加 Truncated;可选扩展接口 SearchTruncationReporter
  (纯 Go 后端/测试 fake 不实现 ⇒ 恒未截断);粗检索两处调用点 OR 聚合。
- core.go: Recall 路由透传(hybrid/semantic/keyword + E4.2/wiki 补充搜 OR);
  响应语义 = truncated 只在 true 时暴露(键缺失 = 未截断,等价 omitempty,注释已写明)。
- 不改:阈值 20000/ZHIYI_HEAVY_READ_MAX_ROWS、降级行为、其他响应字段。
- 测试:假 sidecar 协议级验证透传 + 路由级 4 例(截断/未截断/纯Go后端/keyword),
  逐测试摘除 SearchCacheInstance(storage init() 全局 + 共享 Redis L2 ⇒ 跨 run flaky 的根因)。

实测(独立数据副本 /tmp + 独立 socket,未部署生产):
- cap=300:top_k=3/25000 响应均含 truncated:true;边车日志
  [zhiyi-ipc] search top_k=400 CLAMPED to 300 (single-read cap 300), truncated=true
- 默认 cap:truncated 键缺失;边车 CLAMPED 0 行
- 既有字段 cache_hit/candidates_scanned/count/mode/results 不变
2026-10-17 23:48:26 +08:00
小唯 0bfa7a4bc1 fix(storage): t_bd718662 /recall topK∈{1,2} 让位截断负索引 panic — FTS 尾部位让位数封顶 min(3,F,现有条数)
根因:results 已满(len==topK)时 budget 硬编码 3,topK∈{1,2} 且 fresh≥2/≥3 时
cut=len(results)-nAppend<0 ⇒ results[:cut] 负索引(线上 trace [:-2] @ recall.go:846,
48h 15 次 / 本次复现 20/20 确定性触发)。
修法(附录 C):让位前 nAppend=min(nAppend,len(results)) ⇒ cut≥0 恒成立;
让位只做等量替换不追加扩张(全仓唯一裁剪点仍 recall.go:854,AC-D 计数=1)。
topK≥3 路径 nAppend≤3≤len(results) 封顶不生效 ⇒ 零行为变化(golden diff 为空)。
新增 TestFTS_SmallTopKTailMatrix(topK∈{1,2,3}×len(results)∈{0,1,2,topK}×len(fresh)∈{0,1,2,3,5}
=50 格,断言不 panic+len≤topK+无重复 ID+尾部 FTS 集合精确)+ TestFTS_SmallTopKGolden
(topK 3/4/5 逐字输出,修前修后 diff 空)。修前 topK1_P1_F2 格 panic [:-1] 复现。
部署另开卡(本卡边界:源码+单测+本地验证,不部署)。
2026-10-17 23:15:40 +08:00
小唯 25f68831fd fix(test): 合并两个 TestMain 为单一合并体(t_e5997ca4 落盘点护栏 + t_b7a8ed9c 打分缓存护栏)
两卡分支各自在 routes 包加了 TestMain,合入 main 后 multiple definitions of TestMain
⇒ routes 包 setup failed(全套测试拦下)。按 t_b7a8ed9c 文件顶部的合并提示,把两个
TestMain 体合进 testmain_test.go 并删除 scorecache_guard_test.go。

验收(小怡实跑):
- go test ./internal/api/routes/ → ok 50.344s(修前 setup failed)
- E2E TestCommitConflictGate_E2E → PASS 3.70s;日志 '[scorecache] 已禁用(ZHIYI_SCORE_CACHE=0)'
- 测试不再污染生产 Redis:distill-score 键数 3096 → 3096(不变)
2026-10-17 22:53:43 +08:00
小唯 42fafc495f merge: t_b7a8ed9c 测试隔离(ffc5b10) —— 打分缓存测试不再写生产 Redis,经小怡在分支上实跑验证 2026-10-17 22:49:05 +08:00
小唯 d4b8688148 merge: t_e5997ca4 gap 计数器写侧统一(45726d2) —— 经小怡终审通过(+1 收敛到编译期唯一入口) 2026-10-17 22:49:05 +08:00
小唯 bd399dd007 merge: t_576714de 单次重读设界+IPC重连(c015feb) + t_c70f385c 指标N/A护栏(44fd0e9) —— 均经小怡终审通过 2026-10-17 22:49:05 +08:00
小唯 ffc5b108c6 fix(test): t_b7a8ed9c routes E2E 被 distill 打分缓存 Redis L2 静默短路 — TestMain 关缓存 + Once 活读 env
根因(非卡内假设的 flush 触发条件重构):
- a162e27 打分记忆化 + ce38465 L2 改生产 Redis(zhiyi:distill-score:*,TTL 168h)
  后,routes 包测试(无 TestMain 关闭开关)把「测试内容哈希→结果」写进生产 Redis;
  7 天内后续 run L2 命中 → mock LLM 被短路 → 计数断言 base+1 必挂。
- 实测 TestCommitConflictGate_E2E 16.5s 固定 FAIL(got 0);日志证明 flush 正常
  触发且跑完(batch=1 → DONE),缺的只是 LLM 那次 HTTP 调用。
  生产残留键 TTL≈40h(2026-10-17 复核 143207s)即污染源,TTL 自然过期。
- 对齐门禁规矩③(加缓存须给该包 TestMain 加关闭开关):
  routes 新增 scorecache_guard_test.go TestMain 设 ZHIYI_SCORE_CACHE=0;
  distill.getScoreCache 的 Once 闭包活读 env(包级变量 init 时定型,跨包测试设不了;
  生产语义不变,启动时 env 仍在此处生效)。

验证:go test ./internal/api/routes/ -count=1(不 -skip)ok 34.9s;
go test ./internal/distill/... ./internal/api/... ./internal/selfoptimize/... 全 ok。
⚠️ t_e5997ca4 分支同包加了 testmain_test.go(ZHIYI_DASHBOARD_PATH 护栏 TestMain),
两分支合并时须合并成一个 TestMain。
2026-10-17 22:34:01 +08:00
小唯 45726d26a7 fix(selfoptimize): t_e5997ca4 gap 计数器写侧统一 — +1 只在 open→closed 迁移点 + 计数器 v2 版本化重置
根因(小怡 2026-10-17 终审实测定位):写侧仍有未收口的事件式自增点,
ClosedGaps(9) 越过 TotalGaps(2),gap_closure_rate 被 -1 断言拦下但指标永久不可解读。
  ① routes/gaps.go:44  POST /close 在 Close() 之后无条件 Dash.RecordGapClosed()
     ⇒ 同一缺口每次调用都 +1(无限计数)。且实测现行注册为前缀路由
     /api/v1/gaps/close/(无 {topic} 通配)⇒ PathValue 恒为 ""、端点恒 400,
     该自增点当时不可达,但一旦注册改通配即复活。
  ② server.go:1950  gap_scan 自动修复循环 AutoRepair 成功只计数不关缺口
     ⇒ 同一缺口每轮再 +1(无限虚增,线上 9 vs 2 的主要来源)。

修复:
  - Close/RecordHit 返回 bool(是否真发生 open→closed 迁移);+1 唯一入口
    收敛到迁移点内部;RecordGapClosed 降为包内 recordGapClosed(编译期堵死
    跨包事件式自增)。
  - gaps.go 删无条件 +1;补前缀路由 topic 解析(端点自此真正可用),
    响应如实区分 closed / already_closed。
  - server.go 修复循环改「修复成功 ⇒ 关闭缺口」(RepairHandler 同语义),
    下一轮 !g.Closed 即跳过,计数只在迁移点。
  - 历史 9 vs 2 处置选 (b) 计数器版本化重置:dashboard_schema_version=
    dashboard_schema_v2 标记入 Redis HASH + 本地 JSON(既有 90 天 TTL 键,
    不新增键);首载无标记 ⇒ ClosedGaps/TotalGaps 归零并回写标记(一次性、
    可机械复核),标记在位 ⇒ 保真。代价:丢失不可信的 gap 历史累计。
  - 口径不变:ClosedGaps/TotalGaps = 缺口个数;Metrics() 越界断言保留作
    安全网(不当修复用)。

测试:
  - selfoptimize: Close×3 / RecordHit×3 / 修复循环 3 轮 ⇒ 各只 +1、rate<=1;
    SchemaV2 一次性重置 + 标记在位保真(v1 文件 9/2 载入归零、v2 值保真)。
  - routes: POST /close ×2(现行前缀注册 + {topic} 通配注册两形态)⇒ 只 +1、
    auto_* 计数器快照不变;新增 TestMain 把 ZHIYI_DASHBOARD_PATH 指到临时目录
    (先例:selfoptimize 包同款,防测试写生产落盘点)。
  - 判别力证明(/tmp 改前树 c015feb 旁证副本,不进仓库):逐字复刻改前两写
    路径 ⇒ ClosedGaps diff=6 > TotalGaps=2(rate 3.0 越界,线上 9 vs 2 同型)
    FAIL;改后同场景 diff=2、rate=1.0。

边界:只动 gap 计数器与调用点;部署不在本卡(t_ad887e7c,待牧尘放行)。
2026-10-17 22:12:40 +08:00
小唯 c015febb49 zhiyi: 单次重读行数上限 + Go IPC 读 deadline + 每 rpc 新 dial (t_576714de)
N=2 准入只拦并发堆叠、不拦单请求自身内存:一次 top_k 大 / scan_all
仍能把单条 zhiyi-consolidate 顶到 1~2GB+ 致 swap thrash(t_eedb2d39 根因)。

改动:
- rust/main.rs: ZHIYI_HEAVY_READ_MAX_ROWS(默认 20000,可覆盖)clamp
  lancedb_search top_k + scan_all/scan_deleted;响应体加 truncated:bool
  (#[serde(default)] 向后兼容旧 Go 客户端);zhiyi_ping 暴露当前 cap。
- rust/lancedb_ops.rs: scan_all/scan_deleted 的 .limit(200_000) 参数化为 max_rows。
- go/lancedb_ipc.go: ipcReq/ipcResp 加 Truncated;rpc() 用 SetWriteDeadline(30s)/
  SetReadDeadline(120s)(原 io.ReadFull 无 deadline = 侧车挂死永久阻塞的根源);
  Search/ScanAll/ScanDeleted 截断时打日志(不静默)。
- go/ipc_reconnect_test.go: TestIPCReadDeadlineBoundsHungSidecar(纯 Go,挂死侧车
  被读 deadline 兜住 ~801ms)+ TestIPCReconnectAfterSidecarRestart(env 门控,
  真 sidecar 杀→快速失败 37µs→重启→重连成功)。

隔离副本 /tmp 实测:封顶 20k peak RSS ~1.17GB vs 不封顶 200k ~1.60GB/80s。
不部署(部署另批,需小怡终审 + 牧尘放行)。
2026-10-17 21:52:06 +08:00
小唯 44fd0e95b4 fix(metrics): t_c70f385c 消费者 N/A 护栏 + daily-check N/A 显示 + 反例测试
小怡终审 2026-10-17 21:05 必须修的 4 项之一(-1 哨兵被当低分 ⇒ 触发器恒 fire):

1. selfoptimize.go: 新增 IsNA(v) 判 N/A(metricNA<0)。
2. executor.go: TGapDetected/TQualityDrop/TVValueLow 阈值比较前显式判 N/A,
   -1 不再被当「低于阈值」每轮触发(与旧 recall_hit_rate 恒=1 同类失真、方向相反)。
   配 executor_na_test.go 反例(v=-1 断言不触发)+ 正向对照。
3. tuning.go: AnalyticsHandler 建议 builder 抽为纯函数 AnalyticsSuggestions,
   统一走 ratioFor(-1/valid=0/样本不足 ⇒ 不产生建议);配 tuning_analytics_test.go 反例。
4. 两个 daily-check.sh: gap/auto/usefulness 值为 -1 时显示 —(N/A),不再打印误导性 -1/天。

测试命令(go.mod 在 go/ 下,须 cd go):
  cd go && go test ./internal/selfoptimize/... ./internal/api/routes/
(TestCommitConflictGate_E2E 为既有环境性 LLM 蒸馏用例,非本次改动路径,单独 FAIL)

生产部署仍待小怡终审 + 牧尘放行(本卡边界)。
2026-10-17 21:22:28 +08:00
小唯 b2a016e90f fix(metrics): t_c70f385c 指标口径修复 — recall_hit_rate 退役 + gap_closure_rate 断言 + 最小样本门 N=20
- recall_hit_rate 退役:分子原为 core.go 的 len(results)>0(恒=1、无区分度),
  「返回且被使用」语义已由 recall_usefulness_rate 承担(207 样本 0.98)。
  Metrics()/distributed/metrics-gauge/executor/tuning/CLI/daily-check 全链移除该键。
- gap_closure_rate 统一为「缺口个数」口径:Close() 加 !g.Closed 守卫(与 RecordHit 一致),
  根治同一缺口重复关闭导致 ClosedGaps 虚增、越界 4.5;Metrics() 加越界断言 gapRate>1 → -1。
- 所有率类指标加最小样本门 minRateSamples=20:样本<20 ⇒ -1 + valid=0,
  杜绝 auto_resolve_rate 2 样本判满分。
- 测试:metrics_retire_regression_test.go 用生产同款计数复现改前/改后 JSON;
  selfoptimize 全套通过。
2026-10-17 20:32:34 +08:00
小唯 cee68592e3 feat(deploy): 部署夹带闸门 preflight_reviewed_commits(t_3f83df64)——构建基准 HEAD 相对 tracked 批准清单比对,未评审提交默认拒绝(--allow-unreviewed / --mark-approved 显式放行);起因:01:18 生产二进制夹带 584fe37 等未评审提交 2026-10-17 08:28:01 +08:00
小唯 c3747755b6 feat(rust): t_690cc333 重读准入信号量 N=2 — search>1000/forget_window/scan_all/scan_deleted 计数门限并发内存(3×search10000吞1.5G swap⇒OOM⇒3800写失败的放大器);无许可有界等待100ms后拒heavy_read_busy(不排队不占内存),轻op(ping/insert/update/stats)永不门控;写路径零改动;env ZHIYI_HEAVY_READ_CONCURRENCY可调;zhiyi_ping增heavy_read_in_flight观测。AtomicUsize门(本机toolchain无std::sync::Semaphore) 2026-10-17 01:09:47 +08:00
小唯 4bbf59dabe feat(rust): t_89d22fc8 风暴守卫(AtomicBool+ConsolidatingGuard)+zhiyi_ping健康探针 —— 全量consolidate独占槽防线程堆积OOM;探针判据connect≤3s+ping往返≤5s 2026-10-17 00:06:40 +08:00
小唯 0c0494dabd fix(storage): t_34ec2b1f 时间偏置×信任系数门 ZHIYI_TIME_BIAS_TRUST(默认关·逐位等价)
门关=现状(旧循环, 连乘法都不产生)。门开只降「可靠打分且低质」(0<q<0.6):
  · 不可信族(legacy/recovery/migrat) f=0 → 低质迁移/恢复残留不享受新鲜度加分(P0: q=0.5 wiki:recovery:P0 残留 rank1→9)
  · 可信源 f=q(单调, f(0.5)=0.5<f(1.0)=1.0)
  · q<=0(未打分)/q>=0.6(含0.755 echo) 保原偏置 f=1.0 —— 回归护栏: 全量不可信族清零会误降 152 金标里高质量 legacy(q=0.755/0.805)答案(实测 152=73<75, golden=13<14), 本设计将其排除
与 ZHIYI_SOURCE_TIER_BIAS 作用域不相交(tier 只加 decision, 不含于不可信族)→ 不双重计数。
A/B(隔离实例·独立数据副本·不碰生产7821): 152=76≥75, golden=14/14 不退化; AC1 低质被抬升 396→194(-51%); AC4 双口径一致。
单测: TestIsUntrustedSource / TestTimeBiasTrustFactorMonotonic / TestTimeBiasGate{Off,On,NoDoubleCount}。
2026-10-16 23:05:56 +08:00
小唯 a214cf4a0e fix(storage): t_7793a484 命中事件写路径缺口 — AppendHitEvent 冲突即终态丢(当天 42 条)⇒ 加与 Update 同规格有界重试
- lancedb_ipc.go: AppendHitEvent 原单次 lancedb_append_hit_event(Rust 内部 20 次
  commit 重试耗尽后不重发)⇒ 冲突即终态丢。现加 retryAppendHitEventRPC(同
  t_28aa278e 规格:3 次重试 + 50/100/200ms 指数退避;仅可重试 MVCC 冲突;
  非可重试立即返回)。幂等安全:hit_events 是 append-only INSERT,行 id =
  memory_id+unix微秒 唯一,MVCC commit conflict 时整个提交原子不生效(不产版本),
  重放不产生重复行(与 update col+1 重算同语义,官方 rerun-the-operation)。
- usage_track.go CheckCommittedForUse: 修复前 _ = 吞 AppendHitEvent 错误(10-16
  42 条丢失的主来源);现终态失败 ⇒ 打 [usage] hit event append FAILED 行 +
  不消费 usage_recall(consumed=0 下轮 commit 重扫重试),与 t_28aa278e
  「更新成功后才消费」同构。
- metrics.go: 新增计数器 zhiyi_hit_event_append_failed_total(/metrics 暴露,
  AC3 异源口径:日志 AppendHitEvent FAILED 行 ⇔ 计数器值)。
- IncrementUseful 无需加重试(AC1 代码依据):它走 rc.Update → retryUpdateRPC
  (t_28aa278e 已含 3 次重试);当天 2 条 'IncrementUseful failed' 实测是
  'retry exhausted after 3 retries'(风暴内 4 次尝试全冲突的终态耗尽),
  非「一次冲突即放弃」。残留:feedback 人工路径无 rescan 兜底(同 Update 现状)。
- 测试 hit_event_retry_test.go(复用序列式 fakeServer,全程临时目录+fake socket,
  绝不打开 /var/lib/memoryweave):冲突 3 次→第 4 次成功(重试行 1/3,2/3,3/3 +
  retried OK after 3 + 终态失败归零)/ 恒冲突 4 次有界 + 计数器 +1 / 无冲突恰 1
  次 rpc 0 退避(AC4 逐位等价)/ 非可重试不重试 / 修复前后数值对比(终态失败 1→0)。
  更新 TestCheckCommittedForUse_NotConsumedOnExhaustion 断言(恒冲突总 rpc 5→4:
  AHE 先行耗尽即 continue)。
- 纯 Go 改动,无 Rust/无 schema/不部署(AC5:部署另提卡经牧尘放行,prod-write-gate 会拦)。
  回滚一行:git revert <本提交>。
2026-10-16 22:46:03 +08:00
小唯 05100339f8 feat(metanote): t_5ad3f843 meta-note 分类门禁(Go 侧,ZHIYI_META_FILTER=1 启用,默认零行为变化)
- internal/metanote:21 条正则 Go 等价式 + 判定逐步同序镜像 Python 口径真相源
  (scripts/lib/meta_note_filter.py);\b/\w 映射显式化:\w→[[:word:]\pL\pN]、
  \b 剥离改匹配值前缀边界校验(pre/post/both 三表,未被裸替代项覆盖才校验)
- parity/差分三件套(同 memprotect 范式):
  * Go 等价式 == 变换函数(Py 源式) 逐字节锁死
  * 实时 dump Python 常量逐字节比对(漂移即 FAIL)
  * /tmp 副本异变必须让 parity FAIL(负控)
  * 14 正+11 负+14 边界+SOT 用例表 全量差分 vs 真实 Python classify
- 咽喉点接线 4 处:Commit/WriteMemory/BatchCommit(422 拒绝+skipped_meta)
  + AutoDistillTrigger(admin distill/force 经此函数一并覆盖)
- handler 级验证:门禁开 meta⇒422 先于触碰 storage(零值 API 不 panic)
- 只新增/改 go 侧与判定,未碰 7821/生产二进制/生产 unit/存量记忆,门未激活
2026-10-16 21:59:28 +08:00
小唯 00747be2db chore(evidence): t_492e3f22 teardown 记录 + 零残留判据 + 4 条 run log
跨卡通知 t_004cc147(内存告警)要求补:测试栈 27G 全下线(双孤儿 zhiyid 已由
prof-cloud SIGTERM,本侧停 sidecar + 删 /tmp/zyvfuse-t492e3f22 + 顺带清
dryrun-dir/mem-copy.lance/spike*)。终验:ps -C zhiyid 空 + du /tmp/zyvfuse-* 无残留。
2026-10-16 19:45:25 +08:00
小唯 08a649792e feat(quality): fuseQuality V值分支 env 门 ZHIYI_V_FUSE_ENABLE(t_492e3f22 次症C)
默认(unset/0)= 保持现状逐位不变;=1 = 关 V 分支(v>0 不再加权)。
AC1 默认不碰: PRE(旧二进制) ≡ DEF(新·默认) — 152 verdict 指纹/top5 顺序/probe10/golden 全同
AC2 翻转证据: DEF vs NOV 排名变化=0(v>0 融合分轴生效、cosine margin 主导无换位)
AC4 受影响条数: v>0 实测 152×5=2/760, probe10×20=2/195(预期 2-3,V 衰减漂移)
AC5 回滚复核: RBK(重启·默认) == DEF verdict 指纹 2318948a + golden 14/14
AC6 异源复算: independent_recheck(第二张口径)与主口径一致,无矛盾
含代码 + 单测(TestFuseQuality_VGateOn/Off)+ 证据包 docs/ac-evidence/t_492e3f22-v-fuse-gate/
2026-10-16 19:40:24 +08:00
小唯 584fe37c35 feat(memory): 主症A 显式记忆直写路径 /api/v1/memory/write (t_fa6c9104)
- POST /api/v1/memory/write: 同步嵌入→去重(0.90合并)/插入 memories 表→
  矛盾检测(只报告不拦)→201 含 memory_id。嵌入失败=502 不写任何东西
  (杜绝零向量);短内容400;GET 405;commit 端点零回归(W6)。
- 插件 memory_write 工具改走新端点(直写可召回),404 自动回落旧 commit 路径。
- eval_test: 金标实跑读活密钥(/var/lib/memoryweave/.api-key),修 2026-09-21
  密钥轮换后 TestEvalGolden_Live 恒 SKIP 的 401 根因;判据未动。
- 已部署 /home/muc/bin/zhiyid-new(v3);重启待操作员执行(审批门控)。

不含 t_492e3f22 未提交的 quality_fusion 改动(留在工作树)。
2026-10-16 18:55:20 +08:00
小唯 525f11f531 fix(governance): t_944344b5 返修R2 — 保护口径逐字对齐 zhiyi_protection.py(10词表+distilled门)+ 口径一致性测试
第1轮评审阻断项修复:
- D1 关键词表 7→10 逐字对齐 Python DECISION_RE(用户明确/牧尘要求/牧尘拍板/
  用户拍板/拍板/明确要求/用户偏好/牧尘决定/用户决定/硬性要求),
  删除 Go 自造词(明确指示/决策/偏好/preference/decision)
- D2 关键词分支加 category=="distilled" 门(Python 为 elif cat==distilled),
  其他 category 含关键词不保护;标签 explicit_protected→decision_content(与 Python 同名)
- D3 注释更正:删除无出处的「2026-08-24 牧尘裁定/7词/完全同规则」声明,
  改为「zhiyi_protection.py 为口径唯一真相源 + 逐字对齐 + 改动须报 default」
- D4 新增口径一致性测试(终审侧硬要求):
  · TestDecisionKeywordsParity —— 实时解析 Python DECISION_RE.pattern/DECISION_CATS/
    V_THRESHOLD 与 Go 常量逐字比对,漂移即 fail(不许手抄声明同口径)
  · TestDifferential_PythonReference —— 同一 fixture 表(A~J+K/L)喂 Go IsProtected 与
    真实 Python is_protected(纯内存),逐例断言一致
  · TestDifferential_FixtureTable —— 手写期望表(CI 安全基线)
- D6 LoadState V 值解析失败聚合记一条日志(注释与代码一致)
- server.go/admin.go 守卫注释补「distilled 且命中」限定

全表差分(t944344b5-ruleset-diff-v2.py,只读):live 28350,
Python 保护 10587 == Go 保护 10587,PYTHON-only=0 / GO-only=0(对称差=0)。
staged 二进制 r2 sha 405d32e3…(未部署,AC5 门禁);生产二进制 7d9ed410… 未动。
2026-10-16 13:03:29 +08:00
小唯 8f57bd0fae feat(governance): t_944344b5 自动遗忘(decay/auto_forget)保护守卫 — 命中保护规则的记忆禁止软删
- 新增 internal/memprotect:与 zhiyi_protection.py 同口径的 4 条保护规则
  (category∈{decision,preference,pref}/distilled决策关键词, V值≥2.0,
   freshness=verified, id∈zhiyi:protected_ids);Redis 宕机降级为纯行内规则。
- server.go decay 循环 + admin.go 自动遗忘路由:在 fragment/ShouldForget
  两条 SoftDelete 道之前拦截,命中即 skip 并打 [decay|forget] protected skip 日志。
- redis.go 增补 SMembers/SIsMember(读 protected_ids)。
- lancedb_ipc.go:IPC 候选补 Freshness 列;forgetCursorPath 支持
  ZHIYI_FORGET_CURSOR 环境变量覆盖(测试不碰生产游标);
  抽出 unmarshalMemoryRecordsTolerant 统一 ScanAll/ScanDeleted 宽容解析
  (修复 ScanDeleted 遇空时间列 time.Time 解析报错的潜在 bug)。
- 新增 memprotect 单测(8) + 端到端回归测试 forget_guard_e2e_test.go
  (复制数据目录+独立 socket,未设 PROT_TEST_SOCK 自动跳过)。

AC1/AC2 已在副本 /tmp/mw-prot-copy-20261016-122000 上验证通过;
生产二进制已备份(zhiyid-new.bak-t_944344b5-20261016-115413, sha 7d9ed410…)
并另存 staged 二进制,**未**上活库(待 default 终审,AC5)。
2026-10-16 12:31:02 +08:00
小唯 211d516e5f fix(distill): t_a0831457 P0 解耦——写时四操作门控不再劫持基础 InsertMemory(shadow/off 恒插入,门控只管标记)+ env 改名 ZHIYI_WRITE_SEMANTIC_OPS(旧名兼容一档)
根因:ApplyWriteOp 在 shadow(默认)/off 恒返回 shouldInsert=false ⇒ api/server.go 蒸馏写回路径
`if !shouldInsert { continue }` 把基础 InsertMemory 整个跳过 ⇒ 2026-10-14 起每日蒸馏事实
2053/1094/1559 → 384 → 0 全丢(shadow log 2189 条判定,2120 条该落库的被弃;episodes 原始层完整可重蒸)。
违背了门控自身注释声明的「默认 shadow ⇒ 零行为变化」硬要求(零变化=等价特性不存在,之前基础插入总是发生)。

改动(三模式语义表):
- shadow(默认) ⇒ 插入新条 ✓ + 不做任何标记 ✓ + 记 shadow log ✓
- apply        ⇒ 插入新条 ✓ + 做标记 ✓(NOOP 丢弃;apply 语义不变,回归测试守住)
- off          ⇒ 插入新条 ✓ + 不跑判定 ✓(零开销)
1) write_ops.go ApplyWriteOp:!writeOpsApply() 分支 false→true(门控不参与插入决策)
2) api/server.go 调用点:verdict!=nil 包一层;err/!shouldInsert 丢弃路径仅剩 apply+NOOP 与 apply 标记失败,均显式 warning(禁静默)
3) AC10:ZHIYI_WRITE_OPS → ZHIYI_WRITE_SEMANTIC_OPS(防「所有写操作开关」误读);旧名兼容一档+弃用日志(sync.Once 只打一次);默认值仍是 shadow
4) 回归测试 write_ops_regression_test.go(旧代码上先红已实证:shadow 4 判定/默认/off 5 项 FAIL):
   断言 shadow 下四操作均 shouldInsert=true 且 MarkSuperseded/MarkConflict 零调用(AC2 增补)
5) 旧测试 TestWriteOps_Noop 改写:其「shadow+NOOP 不插入」断言即 bug 语义本身(量具自证:该测试随修复必须改,否则回归门失效)

边界(AC6):不动 episodes 层、不删任何 memories、不改默认值(仍 shadow,改的是 shadow 的语义);
与 284584c(lancedb_ipc.go/usage_track.go)文件不重叠,合并部署=一次观察协议+一个回滚点。
未部署:按 AC3/AC9 交证据包(diff+测试红/绿+md5+回滚方案+观察协议)本体转呈牧尘拍板。
2026-10-15 22:53:03 +08:00
小唯 284584c578 fix(storage): t_28aa278e 方案① Update 冲突自动重试+指数退避 且 usage_track 更新成功后才消费
- lancedb_ipc.go: Update() 遇 LanceDB MVCC 写冲突不再静默吞错(恒返 nil),改为复用
  isRetryableLanceConflict 模式做有界指数退避重试(updateMaxRetries=3, 50/100/200ms, cap 200ms,
  最坏+350ms);耗尽/非可重试返回明确错误(含尝试次数+id)。新增 retryUpdateRPC(table,id,fields)
  (table/fields 参数化,区别于软删专用 retrySoftDeleteRPC)。保留 "Update OK/FAILED" 日志标记,
  重试成功打 "retried OK"、耗尽打 "FAILED (retry exhausted)",失败数可查。
- usage_track.go: CheckCommittedForUse 改为「更新成功后才消费 usage_recall 行」——
  Update 返回非 nil(冲突耗尽/非可重试) ⇒ consumed 保持 0,下轮 commit 重扫会重试,
  计数增量不再静默丢失(修复前无条件 consumed=1 永久丢)。
- 测试: 复用序列式 fakeServer 新增 TestUpdate_{ConflictRetry_PreservesIncrement/AlwaysConflict_ExhaustsBounded/NoConflict_ExactlyOnce_NoBackoff/NonRetryableError_NoRetry/RetryFix_BeforeVsAfterComparison};
  更新 TestConcurrentCommitConflict_CrossPath(断言修复后重试到成功、缓存/库一致) 与
  TestCheckCommittedForUse_ConsumesOnConflict→NotConsumedOnExhaustion(耗尽不消费)。
- 纯 Go 改动,无 Rust/无 schema/不部署(AC5 边界);不改 t_2be29a01 评分、不碰 t_022b116f 守卫。
2026-10-15 21:32:41 +08:00
小唯 bdc18f6177 fix(recall): t_1a30330b scan_all 读侧漏接 last_recalled_at(恒 String::new() ⇒ 误诊全库为空)+ ZHIYI_LAST_RECALLED_WRITE 冲突重试门控(默认关=现状)
根因:本体审计用 scan_all 计数 last_recalled_at,而 rust/lancedb_ops.rs 的 scan_all/search/query_memories 三处均硬编码 last_recalled_at: String::new() ⇒ 全库看似 0 非空 ⇒ 误判「写入缺失、遗忘判据退化」。实际 forget_window(遗忘循环真正读侧)读到 78.8% 非空、含当日 321 条写入 ⇒ 写入工作正常。

修复:
1. 三处读侧接线 last_recalled_at: col_str(&batch,i,"last_recalled_at") —— 根治误诊,审计/列表/测量现可见真实值。
2. env 门控 ZHIYI_LAST_RECALLED_WRITE(默认关=现状):开=对 update_recall_batch 的 Commit conflict 重试一次(重开表拿新 read_version),提高并发下 last_recalled_at 落盘率。默认关 ⇒ 生产零行为变化。
2026-10-15 21:08:39 +08:00
小唯 b017c35d37 test(storage): t_b845d2d6 复现 recall_verified_count 并发提交冲突——两条写路径(Update持锁 vs UpdateRecallBatch不持锁)在单巨片段表上重叠必冲突 + Update静默吞错致计数丢失
机制: LanceDB MVCC 乐观并发, 全部 37358 行落在单 fragment(533268),
任何单行 update 都整段重写 ⇒ 两条重叠提交必冲突(与写哪行无关)。
Go _local.mu 只串行 Update-vs-Update, 串行不了 vs UpdateRecallBatch;
sidecar(main.rs:238) 每连接一线程, 无提交串行化。
本测试用 fake socket server 镜像该并发窗口, 确定性复现:
① 并发提交 conflicts>=1  ② Update() 对冲突返回 nil(静默)  ③ 冲突后 usage_recall 仍 consumed=1 ⇒ 计数丢失
2026-10-15 21:00:27 +08:00
小唯 c12f55ef71 feat(distill): t_ffcee190 非规则卡短事实 keep 档穿透(env 门控 ZHIYI_SHORTFACT_KEEP_PASSTHROUGH,默认关=现状)
observe 档真实对话自然短事实被 <20字/实体动词 启发式误杀(真实对话子集 ~62%,t_1c420e43 量化)。
新增 env 门控(默认关=零行为变化):
- effectiveFilterLane:env 开 且 lane=observe 且 非规则卡(content 非 [规则: 前缀) → 走 LaneKeep 穿透
- 规则卡恒返回原 lane ⇒ 碎片零泄漏(规则本体在 skill)
- 不动 IsQualityFact 阈值、不动 lane 分类器
单测 6 例锁定:默认关等价 / 规则卡不穿透 / 非规则卡救回 / 疑问状态硬否定仍生效 / 规则卡碎片仍丢 / 默认关委托现状
2026-10-15 20:20:12 +08:00
小唯 e52f335998 feat(recall/fts): t_287c6d51 FTS 尾部位门槛按 query bigram 数分档(1-bigram→env 可放宽至~0.15 / ≥2-bigram 与混合恒 0.5),默认全 0.5=零行为变化 2026-10-15 19:04:31 +08:00
小唯 24d6c46065 feat(recall/fts): t_da61c470 两处 env 门控(默认=现状,零行为变化)
改点A · FTS 纯 CJK(bigram-only)尾部位门槛可配:
  - FtsBigramTailGate()/IsBigramOnlyQuery()(fts_index.go)
  - Step 3.8 尾部位门槛:bigram-only 查询走 FtsBigramTailGate()(默认 0.5=现状),
    混合/ASCII 查询恒 0.5。权重公式不动。
  - env ZHIYI_FTS_BIGRAM_TAIL_GATE≈0.15 时,纯中文专名 bigram 档分 0.16~0.256 能拿尾部位。

改点B · rerankN 下限 env 门控:
  - envInt() 助手(recall.go)
  - rerankN:=topK*2 之后加 floor(env ZHIYI_RERANK_N_FLOOR,默认 10=V2 OFF 现值)。
    A/B 设 25 救『池内有货被二次截断』(8081 组 ANN #17~21 / QE 后淇县 #13)。
    只抬下限不抬上界,V2 ON 的 150 不动。

默认值 = 现状 ⇒ env 不设时行为零变化(AC2/AC4 判据);回滚 = unset 两个 env。
零 DB 写入;只读接口 + 本地源码。
2026-10-14 19:41:38 +08:00
小唯 e42d19cfd9 fix(eval): t_dfc93ad0 AC5 golden 缺省路径内嵌兜底 + AC6 回滚时效说明
AC5:部署二进制 CWD=/home/muc,旧版 LoadGoldenSet("") 回落相对
testdata/golden-set.json ⇒ POST /api/v1/eval/golden 不传 golden_path 时
500(2026-10-14 实测复现)。修://go:embed testdata/golden-set.json 打进
二进制,缺省/读不到的路径回落内嵌基线(仍可用);env ZHIYI_GOLDEN_SET
可指定绝对路径临时替换。新增 TestLoadGoldenSet_EmbedFallback_DeployCWD
(空 CWD 下缺省/相对路径均 14 条)防回归。

AC6:fts_index.go 门控注释补「撤标志 ≠ 立即生效」——recall 路径
TTL=60s 搜索缓存(cache_hit),撤门控后 60s 内同 query 命中 ON 态缓存
(终审「撤门控仍 14/14」假象根因=两次测量隔 9s)。可证伪判据:
回滚后等 >60s(实操 75s)或重启 zhiyid 再跑 eval/golden,期望 MMR 条
keyword_pass 13/14 且 cache_hit=false。
2026-10-14 17:32:09 +08:00
小唯 339642b2c8 Reapply "fix(recall): 中文关键词打分 V2 + 扩候选池(env/标志文件门控,默认关)"
This reverts commit 1cdeb4a54b.
2026-10-14 10:42:01 +08:00
小唯 c2683fd6a9 Reapply "fix(recall): V2 关键词分必须进入最终排序(原被 rerank 整段丢弃)"
This reverts commit 9236d8d4b4.
2026-10-14 10:42:01 +08:00
小唯 1cdeb4a54b Revert "fix(recall): 中文关键词打分 V2 + 扩候选池(env/标志文件门控,默认关)"
This reverts commit 4565026b09.
2026-10-14 10:40:44 +08:00
小唯 9236d8d4b4 Revert "fix(recall): V2 关键词分必须进入最终排序(原被 rerank 整段丢弃)"
This reverts commit 43a9cc8751.
2026-10-14 10:40:44 +08:00
小唯 43a9cc8751 fix(recall): V2 关键词分必须进入最终排序(原被 rerank 整段丢弃)
实测:Step 3.5 的 BM25 融合作用在 candidates 上,紧接着 rerank 按 cosine 重打分
并只保留 topK*2 条 ⇒ 关键词分被整段覆盖,且相关记忆(cosine 排名 #126)在那 20 条
之外 ⇒ 无论池子放多大都无效(V2 开/关结果逐条相同,就是这么来的)。

改动(仅 V2 生效):重排候选 topK*2 → 至少 150;rerank 后按
score = 0.7*rerankScore + 0.3*kwV2 融合,再进 MMR 与截断。
2026-10-14 10:38:49 +08:00
小唯 4565026b09 fix(recall): 中文关键词打分 V2 + 扩候选池(env/标志文件门控,默认关)
实测根因(2026-10-14,golden 条目「织忆如何通过 E1 提取和 MMR 实现多样去重」):
① 候选池太窄:per-ns 向量 top-50(candCap 100),而含 MMR 的记忆向量排名 #126/12094
   ⇒ 根本进不了池,后续任何打分都救不回来。
② 旧 ComputeBM25Score 用 strings.Fields 只按空格分词、整段短语做子串计数
   ⇒ 中文查询的关键词分基本失效,且无 IDF(稀有词不加权)。
③ 融合 0.7*quality + 0.3*kw,而 IPC 路径下 quality 会饱和到 1.0(代码注释原话)
   ⇒ 候选间质量分几乎相同 ⇒ 排序实际由失效的 kw 决定 ⇒ 退化成向量原始顺序。

改动(ZHIYI_RECALL_V2=1 或标志文件 /var/lib/memoryweave/recall-v2.on 开启):
- ComputeBM25ScoreV2:查询切 ASCII 词(权重 10,廉价 IDF 代理)+ CJK 二元组(权重 1)。
- 扩池:per-ns 50→200;candCap 100→300。
默认关 ⇒ 行为零变化。单测双向验证:mmr=0.3125 vs generic=0.0312。
2026-10-14 10:34:45 +08:00
小唯 b13cdea910 chore(eval): 按 per-item ns 重建金标基线(14 条 → 唯一基线)
- 基线全部按各条 ns 的当前 top-1 重建:原 14 条里 4 条共用同一 id,现已唯一。
- 结果:kw_hit 几乎全 true(此前失败的两条「技术栈」「牧尘偏好」现均命中)
  ⇒ 证实那 2 条是 ns 假失败,不是召回缺陷。
- 刷新结论 pass=2 / warn(漂移)=11 / fail=1 —— 漂移是基线重建的正常表现。
2026-10-14 10:22:39 +08:00
小唯 88d466d156 fix(eval): 金标集 per-item namespace —— 修「ID 指标按构造恒 0」
实测根因(2026-10-14,查 LanceDB 得到):金标的 expected_id 分散在
hermes-main / domain:HUB / soulful-xiaowei / wiki / shared 多个 namespace,
而 eval 只用请求里的单一 ns(hermes)召回 ⇒ 所有 ID 类指标必然为 0。
这不是「基线漂移」(我先前两次判断都错在这里)。

同时暴露金标集本身的问题:4 条(#1/#9/#11/#12)共用同一 expected_id、
多条基线内容与 query 不匹配(如「图谱扩展机制」钉的是「待处理织忆图谱更新」)。
⇒ 框架没问题,数据是烂的。

改动:
- GoldenSetItem 加 Namespace 字段;RunGolden 用 item.Namespace(空则回落到请求 ns)。
- 金标集 14/14 条补 namespace=hermes-main(内容实际所在),基线随后用
  golden-check.py --refresh 按当前 top-1 重建。
- 同口径修 Python 量具 golden-check.py(recall 支持 namespace 参数)。
2026-10-14 10:21:42 +08:00
小唯 faf71cbe99 fix(tuning): 调参接线消费方 + 阻尼 + 持久化(治「旋钮没接到任何东西」)
实测三真相(2026-10-14):
① 无消费者 —— grep Tuner. 全仓只有 3 处路由注册,没有任何代码读
   Diversity/GapThreshold/DecayRate/DistillInterval ⇒ 调参改了数字、行为零变化。
② 不幂等(棘轮)—— 同一判据每调一次推一步:连跑两次 decay 0.015→0.018→0.0216。
③ 不持久化 —— 包级内存变量,重启即回默认。

修法:
- 接线:storage.SetDefaultMMRDiversity / selfoptimize.SetGapThreshold(消费者持值、调参器推送,
  避免 storage←routes 反向依赖)。初值对齐消费方真实默认(Diversity 0.5→0.3)⇒ 当天行为不变。
- 阻尼:同一参数 6h 冷却。
- 持久化:/var/lib/memoryweave/tuning-state.json(env ZHIYI_TUNING_STATE 可覆盖),启动 load+接线。
- 删规则3(废弃率→提高衰减率):方向危险 —— NewForgetter 注释记载
  「0.015→0.03 曾致误删(36天库龄下 0-recall 长记忆全被清)」。
- 删规则5(蒸馏损失→缩短蒸馏间隔):无正确消费方 —— engine.go 的 batchTimeout 是
  「队列冻结兜底 ticker」(安全网),不是蒸馏节奏。

测试 4 个:哨兵/少样本拦截、冷却、推送、持久化(含「健康数据仍能调」反向验证)。
2026-10-14 09:50:09 +08:00
小唯 113e6e8274 fix(tuning): AutoTune 加指标可用性护栏 —— 无数据(-1)/退化/样本<30 一律不调参
事故面(实测现网):
- gap_closure_rate = -1(无数据哨兵)⇒ 规则4 'gapRate < 0.5' 恒真 ⇒ 每轮把 GapThreshold 往下砍
- recall_usefulness_rate 只有 9 个样本 ⇒ 一次偶然好评就改 Diversity
即:AutoTune 会**按垃圾指标改生产运行参数**,且从不记'为什么没调'。

修法:用 selfoptimize 早已定义好的约定(<_base>_rate / _valid / _samples,
分母退化时比率返回 -1)判定可用性;三类不可用一律跳过,绝不改参数。
并在 status/run 暴露 last_skipped,让外部能区分'健康'与'数据不可用'。

注:命名不统一(值键 avg_distill_loss 无 _rate 后缀),用 TrimSuffix 推 base ——
我第一版按 '<key>_samples' 拼键,护栏静默失效,被新增的双向验证测试当场逮住。
2026-10-14 09:41:36 +08:00
小唯 de0ddf4b8b chore(deploy): bi-temporal e2e 闸门接进部署流程(堵『写了但永不开火』的洞)
背景:t_763e8701 交付了 bitemporal_e2e_test.go,但该测试默认 t.Skip
(需 ZHIYI_BITEMPORAL_SOCK 指向运行中的 sidecar)。没人设环境变量 ⇒
这道『机器闸门』永不开火 ⇒ 等于不存在(机制铁律:写完无人调用 = 零效力)。

改动:do_verify 增加 verify_e2e_bitemporal() ——
用本次已安装的 sidecar 开临时 socket + 临时 data-dir(不碰生产库),
跑 Go e2e(真实 LanceDB 写→读回),失败即 die。

起因事故:t_3ada332b 单测全 PASS 但生产 no-op —— 三列在 LanceDB 边界
被静默丢弃(Go payload 缺 3 键 + Rust schema 缺 3 列),
validityExpired 永远拿到空串 ⇒ 降权永不触发。本闸门即该事故的守门人。

验证(双向):
- 通过路径:deploy.sh --verify-only 全绿,含『✔ bi-temporal e2e 闸门通过』
- 失败路径:把测试指向不存在的 socket ⇒ go test 返回 FAIL(非零)⇒ 函数 rc≠0 即 die
2026-10-14 05:05:24 +08:00
小唯 d0558e1fd5 fix(zhiyi): t_763e8701 返修 bi-temporal 三列未落 LanceDB — 补齐 Go payload+读回 & Rust schema+builder+读侧 5 层
根因:t_3ada332b 只改了 models 结构体 + server.go 算值,LanceDB 边界三层缺失
(Go lancedb_ipc.go 写 payload + 读回解包、Rust arrow_schema + struct + builder + col_str)
⇒ valid_to 永不持久化 ⇒ validityExpired("") 恒 false ⇒ 失效降权生产 no-op。

本次(照 t_3e98b65a 给 superseded_by 的 5 层模式逐一对齐):
1. Go lancedb_ipc.go 写侧 payload 补 valid_from/valid_to/provenance 三键
2. Go 读侧补三处:Search 解包struct+输出映射 / Scan 解包struct+输出映射 / GetSkillCandidates mapStr 路径
3. Rust lancedb_ops.rs struct 字段(#[serde(default)],存量行不报错)
4. Rust arrow_schema Field::new 三列(nullable,存量由 open() 迁移补列)
5. Rust 写 builder col vec + push + StringArray + 5 处读侧 col_str

新增 e2e 回归闸门 bitemporal_e2e_test.go:经真实 LanceDB sidecar 写一条 valid_to 已过期记忆
→ 读回断言三列非空且等于写入值(ZHIYI_BITEMPORAL_SOCK 门控,未设跳过)。
单测(AC1/AC2/AC3/AC4)+e2e 全 PASS;全量 go test 仅既有 flaky TestCommitConflictGate_E2E(clean baseline 同败)。
2026-10-14 05:01:27 +08:00
小唯 12f808d0e1 feat(zhiyi): t_3ada332b P3 bi-temporal 有效期 — memories 表加 valid_from/valid_to/provenance(默认空=永久有效) + 写时识别时间敏感事实(distill/bitemporal.go DetectValidTo 只认强时间词+带触发上下文显式日期, 误报止损) + 写路径填 valid_to/provenance + 召回降权(recall.go validityExpired, env 门控 ZHIYI_BITEMPORAL=0 默认关零行为变化, non-lossy 只剔候选不删库); 单测 storage 3(AC1/AC3/AC4)+recall 2(AC2)+distill 4 PASS; 全量 go test ./... 仅预存 flaky TestCommitConflictGate_E2E(clean baseline 同败,归因 t_fcadee04) 2026-10-14 04:11:52 +08:00
小唯 44ccb69ca5 chore(deploy): deploy.sh 加构建前洁净检查 + ignore 探针残留
起因(2026-10-14 当晚三次同族事故):
① f8ffcde 把另一任务在途的 server.go 布线一起提交 ⇒ HEAD 编译不过;
② deploy.sh 原先直接从**工作树**构建 ⇒ 任一 worker 在途改动会被顺手编进**生产二进制**,
   且部署后『运行二进制校验和 == 本次构建』仍然通过 ——
   校验和只能证明『跑的是本次构建』,不能证明『本次构建来自已提交代码』。这是验证链的洞。

改动:
- preflight_clean_tree(): git status --porcelain(含未跟踪)非空则拒绝构建;
  显式 --allow-dirty 可覆盖(风险自负,须在卡上记原因)。
  含未跟踪是刻意的:internal/peer 那类事故正是『已提交代码引用未跟踪文件』。
- .gitignore: /go/*-probe(清 17MB 残留 rulefirst-probe)

验证:闸门在 build 前 die(rc=1),生产未动(两服务仍 active、二进制时间戳不变);
--verify-only 不受影响。
2026-10-14 03:44:39 +08:00
小唯 95cc81db4b feat(zhiyi): P3 Peer Representation (t_f8fc97e6) — Honcho四层推理画像 explicit→deductive→inductive→abductive; 新 internal/peer 包(CollectFacts分类+Reasoner接口化:生产8081本地2B,测试Fake零网络)+peers表(graph.db同库,不碰state.db)+API POST /peer/{id}/refresh+GET explain+POST /recall/peer+主召回注入(env门控ZHIYI_PEER_RECALL默认0零行为变化)+commit异步钩子(非阻塞); 单测6+8+3 PASS; 幂等non-lossy合并 2026-10-14 03:39:49 +08:00
小唯 f8ffcde0f4 feat(distill): t_3e98b65a 写时四操作(ADD/UPDATE/NOOP/CONFLICT-MARK)+写前哈希去重——Mem0血统
影子默认(ZHIYI_WRITE_OPS=shadow,零行为变化;=apply才真改库):
- 新 distill/write_ops.go: 归一化+MD5哈希去重(ContentHash)、规则基四操作判定
  (defaultJudge可注入JudgeFunc/ContradictionFunc,生产可接governance矛盾检测)、
  shadow日志JSONL(/var/lib/memoryweave/write-ops-shadow.log)
- 四操作: ADD新建/UPDATE旧条标superseded_by+新条active/NOOP丢弃记log/
  CONFLICT-MARK双方标conflict交人工(永不自动删)
- server.go OnDistillComplete 写路径挂四操作判定(影子只记不改库)
- schema: models+sqlite.go+lancedb_ipc.go+rust 加 superseded_by 反向指针列(additive)
- 顺手: engine.go Weights/echoScoreVectors 补 MemOS 血统出处注释(借鉴溯源全清单§2.1)
- 报告生成器 scripts/tools/zhiyi-writeops-report.py(影子48h后出分布+误判抽样)

AC: 四操作各1单测+哈希去重+影子零变更全PASS; go build全过;
Rust release build 0; 除既有flaky TestCommitConflictGate_E2E(干净HEAD同败)外go test全绿
2026-10-14 03:18:13 +08:00
小唯 0afff5734e feat(zhiyi): L3 skill 自动草稿 (t_fcadee04) — skills表(graph.db同库,不碰state.db)+草稿落盘attachments(<pattern>/skill-draft.md带[AUTO-DRAFT],绝不进skills/)+POST /patterns/{id}/draft+promote(draft→active人工确认); 生成器接口化(生产复用8081本地2B,测试FakeGenerator零网络/CGO); 显式API不挂cron默认零行为变化; 单测11+5用例PASS; 幂等:重复draft覆盖内容,active不覆盖 2026-10-14 02:35:50 +08:00
小唯 ef4f379736 refactor(storage): t_5028c14d 抽出召回融合纯函数 + 回归测试锁死「频率/时间衰减参与排序」 — Search()内联算法逐位等价抽到 quality_fusion.go(computeRecencyFactor/computeImportance/fuseQuality), 行为零变化不改数值; 新增单测锁定频率↑/越近→融合分↑; go build 0; 除既有flaky TestCommitConflictGate_E2E(干净HEAD同败)外全绿 2026-10-14 02:05:00 +08:00
小唯 aab877a13c fix(distill): t_c06ad4d0 解污染——蒸馏回调改走独立计数 distill_success_count,不再灌 UsefulCount/recall_usefulness_rate 分子; 拆账不丢数(字段+RecordDistillSuccess+Redis/本地持久化+Metrics键); 回归测试10次蒸馏⇒UsefulCount仍0、无反馈样本rate仍metricNA 2026-10-14 02:01:36 +08:00
小唯 1cfb17ac5e chore(git): 停止跟踪 13 个 *.bak.* 改动前快照 + .gitignore 加规则防复发
这些 .bak.<topic>-<ts> 是各卡改动前的备份快照,被多张卡(proofchain/timedecay/standing)
陆续 commit 进版本库,累计约 4800 行纯垃圾,且会随历史永久保留。
git 本身就是版本历史,备份快照不属于版本库。

做法:git rm --cached(磁盘文件保留,不动内容)+ .gitignore 加 *.bak.* 。
本 commit 不触碰任何源码。
2026-10-14 01:57:18 +08:00
小唯 8364ff1b36 feat(standing-answers): t_e9a4d18f P2 常设答案(mental models)——standing_answers表(SQLite+Rust schema)+读写存储+API直读(/api/v1/standing-answers)+注册表(3问)+生成脚本zhiyi-standing-answers.py(复用本地2B); 单测4/4 PASS; 默认不注入行为零变化 2026-10-14 01:47:58 +08:00
小唯 57bdf7fa03 feat(zhiyi): ②L2 模式检测+召回注入 (t_d32e5f8a) — 复活 L1→L2 pattern 蒸馏: 新 internal/pattern 包(工具组合频率≥3 + 路径 cosine≥0.85 聚类,设计§4.1)→ upsert graph_nodes(type='pattern',ns=daemon-distill)(与 85 存量同表不开新表·modernc sqlite 短命开/关·不碰 state.db); API POST /patterns/detect + GET /patterns + zhiyi-cli pattern detect/list(cron 可单发); 召回注入 env 门控 ZHIYI_PATTERN_RECALL 默认关⇒零行为变化; 单测 12 用例(detect5+store4+注入3+route4 含空库幂等)PASS; 零新依赖不碰 state.db 2026-10-14 01:44:39 +08:00
小唯 d2348eda43 feat(distill): t_2515307a 确定性判据强化——召回侧规则过滤/降权(env门控ZHIYI_RULE_FIRST默认关); RecallRuleVerdict复用quality.go+admission_lane规则+URL/路径强实体豁免; routes/core.go Recall按verdict过滤drop/降权demote; 单测16用例PASS; 影子探针rulefirst-probe/scan取证26drop+4demote; 零新依赖不碰state.db 2026-10-14 01:28:10 +08:00
小唯 467d9b4ac1 fix(metrics): 分母退化返回 N/A(-1) 而非 1 + 每项比率自报 samples/positive/negative
牧尘批准「分母退化就返回 N/A 而非 1」。逐项落地:
- 新增 metricNA(-1) 哨兵:真实比率必落 [0,1],-1 不可能被误读成任何一档成绩
- 6 项比率/均值统一走 rateOrNA():分母<=0 ⇒ -1(旧实现返回 0,0 意为「0%」同样是没资格下的结论)
- 每项配 <name>_valid(1=可解读) / <name>_samples(分母) / usefulness 另配 positive/negative
  ⇒ 让「负样本饥饿」可被机器读出,无需魔法阈值
- distributed.go Prometheus 渲染同步:HELP 注明 -1 语义 + 输出 *_valid/*_samples,
  并警告看板须先按 *_valid 过滤,否则 -1 会拉低均值

只增键、不改键名 ⇒ 全部既有消费方(SyncFromDashboard / 各 JSON 端点)不受影响。
单测 5/5 新增 PASS;既有 2 例断言旧语义(零状态=0)已按本意更新为对齐零状态值。
go build ./... 通过;go vet 干净。

⚠️ 尚未解决(另案):recall_usefulness_rate 的真病灶是 server.go:384 在蒸馏完成回调里
调 RecordUseful() ⇒ 分子数的是「蒸馏成功次数」、分母是「召回负反馈次数」,两者不同源。
本 commit 只让它可被看见,未改该调用点(server.go 当前有其他 worker 在改,避免撞车)。
2026-10-14 01:25:45 +08:00
小唯 ef64da6df2 feat(zhiyi): ⑤使用追踪 (t_5aa4dcac) — 召回→后续内容携带→判定被用上, env门控ZHIYI_USAGE_TRACK默认关⇒零行为变化; 落hit_event(pos/downstream_use)+累加recall_verified_count供⑥反馈; /usage/report+/usage/detect; 单测6用例+真实corpus演示5样本; 零新依赖不碰state.db 2026-10-14 01:14:37 +08:00
小唯 ae39e1ce8a feat(evidence-chain): t_e9a4d18f P1 证据链+proof_count——SourceEvents(多证据列)+ProofCount派生+QualityFromProof(饱和x/(x+K),ZHIYI_PROOF_FALLBACK门控兜底)+Supersedes矛盾保留列; 单测5/5 PASS; Go+Rust build通过; 默认关行为零变化 2026-10-14 00:52:29 +08:00
小唯 a1c9fc1631 feat(distill): t_554b8122 对抗审计插槽——env门控ZHIYI_ADVERSARIAL_AUDIT(默认关⇒零行为变化)+按抽样比例送异源模型(NewAPI deepseek-v4-flash,非本地2B)审计,结论只写影子日志不改丢弃/准入; 单测6/6 PASS+liveprobe真模型3样本; 零新依赖不碰state.db 2026-10-14 00:28:18 +08:00
小唯 f37f5e744e feat(storage): t_e9a4d18f P0 时间维检索——ZHIYI_TIME_DECAY(env门控加性recency偏置,默认0)+stale标记(ZHIYI_STALE_AFTER_HOURS,默认0); 单测4/4 PASS; env=0行为零变化 2026-10-13 23:43:55 +08:00
小唯 0bdcae2b91 feat(storage): t_8f1f6e5e 反馈回路接通——FeedbackScore()(env门控加性偏置,默认0)+单测5/5; ep_*从VValueProvider排除(只改读侧); ZHIYI_FEEDBACK_BIAS=0行为零变化 2026-10-13 22:19:48 +08:00
小唯 1b6920e8e1 feat(storage): t_be3e958a 召回排序加来源分层偏置——决策类(wiki:decision)在 MMR 前加性加分,流水(llm_distill/episode)不动;env ZHIYI_SOURCE_TIER_BIAS 控制(0=关)+单测 2026-10-13 07:26:59 +08:00
小唯 a377a7f667 fix(distill): t_91af03e9 补停用词层——noiseEntity 精确匹配整名的结构性泛词表(任务/过程/状态/流程/词汇/工具/工具动词/判据/结论/结果/方案/内容/信息/原因/问题/步骤/阶段/记录/清单/备注/说明)+探针残留(甲/乙/丙/探针/PROBE前缀);先过停用词表再走现有正则;长实体名(≥4字)不因本表被拦,复合形态(任务状态/状态机)照常放行 2026-10-13 06:00:12 +08:00
小唯 e282a41bab fix(distill): t_62f35e62 补收口三——①noiseEntity 正则拆两并列分支,旧关键词(健康检查/部署流程/测试结果/代码修改/grep)恢复单独可拦,泛词(看板/任务/kanban)仍只组合形态 ②emitResult 早退条件放宽为 facts与entities都空才return,facts==0时实体仍进图(修复领域实体静默丢失) 2026-10-13 04:13:05 +08:00
小唯 0959af388b fix(distill): t_286d1310 写库闸门 lane 感知——server.go OnDistillComplete 改用 FilterQualityFactsWithLane(复用 engine 同函数),LaneKeep 时决策类 <20 字碎片不再被第三次丢弃(落库判定由 ClassifyAdmission 重算 lane)+ 新增写库判据单测 2026-10-13 03:26:06 +08:00
小唯 6d724dc937 ga-二收口 t_348cefc1: ①停写图 DERIVED_FROM 边(血缘由 memories.derived_from 字段承载, 图上无人读, 消除 ep_/f_ 目标节点恒增) ②noiseEntity 补看板卡ID t_[0-9a-f]{6,} + 任务/看板流程词组合形态(不单拦泛词) — 探针乙 4/4 泄漏形态全拦 2026-10-13 02:49:43 +08:00
小唯 6e21eef6da docs(recall): Step 6.5 缓存写回注释同步为 60s TTL(写路径 Invalidate + TTL 双保险) 2026-10-13 02:12:26 +08:00
小唯 5b9f75cc7f ga-meta-1b-3 t_1c12e000: 缓存失效写路径收口——TTL 1h→60s + 蒸馏/merge 落库后 Invalidate + recall 响应 cache_hit + cache/stats 暴露 search_cache 计数 2026-10-13 01:38:11 +08:00
小唯 ba81121efa ga-meta-1b-2 t_c6aebb8b: 补收口——来源类+内容形态双层层判定, 堵住 1b 漏掉的分身会话/空source/session-compress 活体写图路径 2026-10-13 01:09:16 +08:00
小唯 5565ec8a9b fix(distill): t_2ae69bb2 让 lane 结论穿透 fact 级质量门禁——LaneKeep 时跳过长度类规则,只留纯疑问/状态汇报两条硬否定 2026-10-13 00:23:57 +08:00
小唯 95bb930bd6 ga-meta-1b t_67d0279a: 方案A 来源分档 — auditSource(worklog-note/audit) 蒸馏实体不写图, 事实仍进记忆层
终审采用 1a 方案A:
- DistillInput +Source (additive)
- server.go OnDistillComplete / auto_distill.go 降级路径 补 Source: input.Source
- graph_auto.go UpdateFromDistill 顶部: auditSource(Source) 命中即 return (跳 AddNode/AddEdge, 事实照写 LanceDB)
- auditSource: TrimSpace → TrimPrefix(wiki:) → ToLower (前缀归一, 防静默 no-op)
- echo_guard.go 判据零改
AC1 复现 entities=10→0 新节点; AC2 dry-run 35412 行误杀0; AC5 正负对照+skip-entity 日志; AC4 节点 delta 非负
2026-10-12 23:56:58 +08:00
小唯 e900e4073f GA-P0-7 (t_dd64345a): 退役裸路由 /api/v1/feedback 写点(曾写旧 not_useful_count)
- server.go: 删 mux.HandleFunc("/api/v1/feedback", api.Feedback) 注册
- core.go: 删 Feedback handler(按 useful 写 useful_count/not_useful_count)
- 回归守卫 server_route_guard_test.go: 断言裸路由不注册 + 4 子路由在
- tests/integration_test.sh: 反馈改走 /api/v1/feedback/useful
- README.md: 裸路由文档改为拆分后 4 子路由

AC2 证伪无调用方:grep 'api/v1/feedback"' 仅命中自身注册行(现已删)。
AC3 退废后 not_useful_count 仅剩 schema/struct 向后兼容声明、[DEPRECATED] IncrementNotUseful(无路由调用)、迁移工具读、注释。
2026-10-12 21:38:01 +08:00
小唯 66d8e32bc6 fix(distill): GA-P0-6 返修 P0-5 卡号 t_6e16ebef——echo 判据补标点/空格不敏感 + 多示例词并列拦截 2026-10-12 20:23:13 +08:00
小唯 13ced12ce9 feat(memoryweave): GA-P0-4 落 hits+/hits− 双计数器——独立语义的 outcome 信号(禁部署)
新增 append-only 事件表 hit_events(sqlite/Rust-LanceDB/memvector 三后端同步),
带 created_at 时间戳可按周窗口聚合,只由真实 outcome 写入(人工反馈/矛盾/取代/
下游引用);dedup 降权/单纯召回出现**不算**(P0-1/P0-2 拆出的假信号,见 hit_event.go
排除项 + docs/hit-outcome-signal.md y 判据)。修正 已办.md:16623 的 hits+=useful_count
错误等同并标注更正依据。

写入点接线 feedback.go(/feedback/useful→pos, /not-useful→neg)。单测 5 例 PASS(含
dedup 降权不计入 hits− 反例 + sqlite 关库重开 read-back);Rust cargo build 通过;
LanceDB 真实 sidecar IPC append/count/get read-back 取证(count 时区归一修掉跨时区错位)。
禁部署:未动运行中二进制、未碰 live 库。
2026-10-12 19:50:58 +08:00
小唯 227b2979dd feat(distill): GA-P0-5 概念/实体提取路径接 echo 防线(防元污染闭环复发)
- 新增 distill.IsPromptEchoEntity(与 IsPromptEcho 同源读 promptEchoLiterals,清单零改动)
- server.go [graph/notes] 处理器过滤候选实体,命中即剔并打 [graph/notes][ECHO-DROP]
- 覆盖 3 个复活节点 n_galway/n_rothfuss/n_the_name_of_the_wind 同类输入
- 禁动 storage/rust(AC4 守住);commit 由小怡补(原 worker 未提交,共享树有覆盖风险)

卡: t_96580838
2026-10-12 19:04:45 +08:00
小唯 cb450e9c9d feat(memoryweave): GA-P0-3 拆分 is_deleted 删除原因 → delete_reason 枚举(禁部署)
- 新增 delete_reason 固定枚举列(merge_dup/contradiction/manual/retention/unknown)
- LanceDB(Rust arrow_schema+MemoryRecord+read/insert) 与 sqlite 双侧 additive 同步
- 所有软删写入点统一归一化写 delete_reason:
  SoftDelete(manual/merge_dup/contradiction/retention) · SoftDeleteBatch(unknown)
  · PurgeInvalid(retention) · Rust soft_delete_batch(unknown)/purge_invalid(retention)
- 新增 lancedb_scan_deleted IPC + Go ScanDeleted:存量已删行回填工具枚举用
- 回填工具 go/cmd/backfill_deletereason(dry-run 默认)+ 单测 7 例(每 reason≥1 写入用例)
- 直方图(副盘真跑):N=11240 全 unknown(tombstones 无 provenance,按 AC 判不出写 unknown)
- 禁部署/禁真删/禁改已删记录其它字段:live 库零改动
2026-10-12 18:52:09 +08:00