You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
the LifecycleService's own deletes/rotations are not audited or activity-logged (otherwise cleanup re-feeds the tables it is draining — the same self-audit trap ADR-0052 already guards). Aggregate one summary row at most.
Activity
docs(knowledge): correct the sync model's event names and note the bu…
os-zhuang commentedon Aug 3, 2026
裁决(PM 代决,维护者可否决):批准,按正文边界执行 ——
data.records.*聚合事件(declared ≠ enforced:引擎 multi:true 谓词写入没有 data.record.* 事件,webhook / 知识同步对其静默(REST 批量端点不受影响) #4639,已落地)后标记该 object「需对账」,不做全量轮询;理由:逐记录扇出已被 ADR-0057 §3.3 封死(N 条事件回灌正在清理的表),对账是唯一出路——「事件管新鲜度,对账管正确性」职责边界成立,长远上这是所有派生索引类服务的通用形状。已入队待派。
Generated by Claude Code
feat(spec,objectql,client,plugin-webhooks): honest bulk event contrac…
feat(client-react): bulk-write hooks, and useAutoRefresh refreshes on…
os-zhuang commentedon Aug 5, 2026
认领:PM 循环第 2 轮(services 车道)
会话:
session_01BWS4heBoAitLmzCLhcYdbK分支:
claude/issue-4672-knowledge-reconciliationWorktree:
objectstack-issue-4672域:
domain:services文件面:
packages/services/service-knowledge/**(plugin + 新对账模块 + 同包测试)、.changeset/*.md。⛔ 不碰packages/objectql(lifecycle)—— 按 2026-08-03 裁决,对账归知识服务自身,不进 LifecycleService。Generated by Claude Code
os-zhuang commentedon Aug 5, 2026
前提核对结果:缺陷成立,但「对账是唯一出路」不成立 —— 停下待裁,未写代码
会话
session_01BWS4heBoAitLmzCLhcYdbK,分支claude/issue-4672-knowledge-reconciliation(无提交,worktree 已清理)。1. 技术缺口仍然真实(origin/main 已核对)
packages/services/service-knowledge/src/knowledge-service-plugin.ts:178-187那条 warn 还在,没有人加过对账;git log origin/main -- packages/services/service-knowledge自 declared ≠ enforced:引擎 multi:true 谓词写入没有 data.record.* 事件,webhook / 知识同步对其静默(REST 批量端点不受影响) #4639(f2445c9)以来无新提交。reindexSource(knowledge-service.ts:126-183)只 upsert、不 delete。所以即使把已声明但没人调度的refresh.cron(packages/spec/src/ai/knowledge-source.zod.ts:26-33)实现成定时全量重建,孤儿条目照样留着——正文说的「删除源已不存在的条目」不是任何现有机制的副产品。upsert(docs)/search(query, topK)/delete(ids)/healthCheck?(packages/spec/src/contracts/knowledge-adapter.ts)。没有枚举能力。孤儿 id 按定义在源里查不到,search又受 query 与 topK 约束,所以孤儿集合无法从现有面推导——正文「枚举索引条目」这一步今天根本没有落脚点。2. 但正文的关键论证被推翻了
正文说:reap 不能改成逐记录扇出(ADR-0057 §3.3),「所以这条路封死,对账是唯一出路」。
ADR-0057 自己的 amendment 提供了这条路:reap guard。
LifecycleService.registerReapGuard(object, guard)(packages/objectql/src/lifecycle/lifecycle-service.ts:414-421),契约在:320:Reaper 删除前把候选行本体交给 guard,guard 先做外部清理再返回它确认删除的 id,未返回的行本轮保留。guardedReap(:1083-1111)每批 500 行、每次 sweep 最多 20 批,排不完的顺延到下次 sweep。正文第三条成本要求由扩展点本身满足。service-storage通过ctx.getService('lifecycle')+ duck-type 注册了两个 guard(storage-service-plugin.ts:320-337),做的事情是「行消失前回收外部字节」——与「行消失前按 id 去索引化」结构相同。也就是说:正文点名的最主要陈旧来源(
reapWhere的保留期回收)可以在源头关掉,不需要新子系统、不需要碰packages/objectql、不需要动 spec,而且天然分批可中断。裁决第 2 条「不进 LifecycleService」按字面读会挡掉这条路,但它挡掉的其实是 ADR 自己认可的扩展点——这一条需要维护者重读。3. 定位冲突:#4606
#4606(维护者 2026-08-02 10:09,
status:parked)对知识库的定位裁决是:短期无项目需求、非主线任务,「现有架构姿态即终态……开源核心零新增承诺」,能力归企业版;重启需满足三条触发条件之一;真要加 spec 面则「enforced 先行——检索路径真读它之后才进 spec(ADR-0078)」。本 issue 建于同日 15:58,PM 批准于 08-03 06:24,两处都没有引用 #4606。按 AGENTS.md Prime Directive #13(推翻已记录的裁决本身是一次裁决),这里需要维护者显式表态。
实测的业务拉力(两仓一起数):没有任何地方声明过 object 知识源。
registerSource的唯一调用点是插件自己的 boot 循环(knowledge-service-plugin.ts:107),喂给它的options.sources无人提供;new KnowledgeServicePlugin(...)只出现在本包测试里;examples/app-todo依赖了@objectstack/service-knowledge与@objectstack/knowledge-memory却从未 import;闭源 cloud 仓有真适配器packages/knowledge-turso,但同样零registerSource、零contentFields。也就是说今天没有任何索引会陈旧,因为没有任何索引。补充一条量级判断:非 system 调用方其实看不到孤儿条目——
applyPermissionFilter会把sourceRecordId查不回来的 hit 丢掉(knowledge-service.ts:300-355)。孤儿的真实代价是 ① 占掉 topK 名额稀释真结果(过滤发生在适配器返回 topK 之后),②isSystem: true调用方直通不过滤,③ 索引存储成本。而谓词更新导致的内容漂移则完全没有兜底:记录还在,RLS 复查放行,索引里是旧正文。4. 三个待裁问题
Q1 现在做不做? A 归档到 #4606 之下(保留 #4639 那条 warn 作为诚实信号)· B 按 PM 裁决在开源核心建对账子系统 · C 只做 reap guard 去索引化(零新增契约面),其余归档。倾向 C,否则 A:C 对唯一被点名的陈旧来源是真修复,新增面几乎为零,不触碰 #4606 的「零新增承诺」;B 要在维护者刚判为 parked 的领域新建子系统 + 新增 spec 契约面。
Q2 枚举能力怎么来?(只要还要覆盖应用层
updateMany/deleteMany)A 给IKnowledgeAdapter加一个可选的分页枚举方法(memory 用 Map、cloud 的 turso 一条 SQL、ragflow 走 list-documents,三个适配器都能实现;缺失可探测,服务可按 source 大声拒绝)—— spec 座位 · B 只做 reap guard,应用层谓词写不覆盖 · C 服务内存快照差分(不动 spec,但重启即失效、随对象规模膨胀,正是「声明 ≠ 落地」陷阱) · D 落一张sys_knowledge_*台账(第二份真相源,自己也会漂)。倾向 B 现在 + A 等到真有 object 源时(与 #4606 的 enforced-先行 同向);C、D 建议直接否掉。Q3 若走 guard 路线,
registerReapGuard是 last-wins 且注册表私有,第二个注册方无法察觉自己解除了sys_file的字节回收 guard(对比registerRetentionFloor刻意做成可组合键)。已单独记录为 #5535,建议改成交集组合(全部确认才删)——objectql 座位,是 Q1=B/C 的前置。Generated by Claude Code
os-zhuang commentedon Aug 5, 2026
PM 处置(services 车道,
session_01BWS4heBoAitLmzCLhcYdbK):转needs-user-decision,撤出派发队列,认领已释放。dev 未写任何代码即停手 —— 这是流程按设计工作。公开更正:本单 2026-08-03 的 PM 代决批准,现确认有两处缺陷,不再作为派发依据 ——
待拍板(完整证据与三轴分析见上方 dev 评论,不重复):
domain:engine,finding),归 engine 车道分诊,是 Q1=C 的前置。拍板后:若 C,本单改写范围后重新入队(文件面
service-knowledge+ guard 注册,#5535 为 Blocked-by);若 A,关闭本单并在 #4606 留一行链接。Generated by Claude Code
os-zhuang commentedon Aug 5, 2026
维护者裁决(2026-08-05,经 services 车道 PM 转达):批准方案 C —— 仅做 reap guard 去索引化(知识插件注册 lifecycle reap guard,行删除前按 id 去索引),零新增契约面、不碰
packages/objectql、不建对账子系统;应用层谓词写部分诚实不覆盖,待真实 object 源出现再按 #4606 的 enforced-先行原则回看(Q2 = B 现在 + A 待触发,同案批准)。本裁决在 #4606「零新增承诺」边界内执行,不构成对该裁决的推翻。状态:摘
needs-user-decision,转pm:blocked—— 正文已加机器行Blocked-by: #5535(reap guard 的交集组合语义是本单前置,否则知识 guard 作为第二注册方会静默顶掉 storage 的字节回收 guard)。#5535 已晋级 engine 队列;它落地后本单自动回队,按收窄后的范围(见正文顶部改判注记)派发。08-03 的 PM 代决(对账子系统方案)由本裁决正式作废。
Generated by Claude Code
fix(objectql): compose reap guards by intersection instead of last-wi…
hotlong commentedon Aug 6, 2026
解锁:
Blocked-by: #5535已解除 —— #5535 于 2026-08-06 02:50Z 关闭(completed,reap guard 组合语义议题已由 engine-core 车道收束)。按状态机摘pm:blocked换pm:queue,回 services 车道队列。派发前注意(记给未来的派发轮,非新增裁决):
origin/main核实registerReapGuard的现行组合语义(finding(objectql): registerReapGuard 后注册者静默顶掉前者,且注册表私有 —— 第二个注册方察觉不到自己解除了别人的 guard #5535 关闭时落地的形状 —— 交集组合还是 last-wins+探针),它直接决定知识插件注册 guard 时是否会顶掉service-storage的字节回收 guard;若仍是 last-wins 且无组合通道,本单前提有变,报 fork 勿硬做。经办:services 座位,会话
session_015a5qkLzpGXhLL2F5gvJ7dD(解锁扫查,PM 循环第 1 轮)。Generated by Claude Code
hotlong commentedon Aug 6, 2026
认领:PM 循环第 3 轮(services 车道)⚠️ 新分支名对应收窄后的方案 C 范围;前认领分支
会话:
session_015a5qkLzpGXhLL2F5gvJ7dD分支:
claude/issue-4672-knowledge-reap-guard(claude/issue-4672-knowledge-reconciliation已由前会话释放、零提交)Worktree:
objectstack-issue-4672域:
domain:services文件面:
packages/services/service-knowledge/**(plugin 的 guard 注册 + 同包测试)+ changeset;⛔ 不碰packages/objectql(裁决明文)、不碰packages/spec/IKnowledgeAdapter契约面(#4606 零新增承诺边界)串行约束已清:Blocked-by #5535 已解除(02:50Z 闭);PM 预核:
origin/main上reapGuards已是Map<string, LifecycleReapGuard[]>数组组合形态(lifecycle-service.ts:363/:480-483/:1092)—— dev 照解锁评论完整核验交集语义后开工;同包无其它在飞执行依据:维护者 2026-08-05 批准的方案 C(reap guard 去索引化;08-03 PM 代决已作废勿引用);「今天零 object 源」的事实已在裁决时计价,不构成 premise-false。派发令随后。
Generated by Claude Code
hotlong commentedon Aug 6, 2026
验收:ACCEPT → PR #5987(CI 25/25 绿,随后转 ready 入队,本座位跟到 MERGED)。方案 C 兑现质量高:
ReapGuard类型按 ADR 契约本地声明,连类型依赖都没引 —— 定位裁决:知识库(RAG)= 契约在核心、引擎靠集成、能力归企业版 —— 重启触发条件记录(#3896 移除 agent.knowledge 后的正式定位) #4606 零新增承诺边界完整。Map<string, LifecycleReapGuard[]>+ 交集流水线(:1220-1230),契约注释明写「every registered guard confirmed」并点名 sys_file 案例 —— fork 条件未触发;且组合共存用例是消费侧证明(真实 LifecycleService + 第二个 guard,两者互不顶掉、交集删除、单侧 veto 均钉住)。refresh.onRecordChange: false/enableEventSync: false双向关断,外部索引器不拖住别家 retention。const register = lifecycle.registerReapGuard脱this真 bug(假注册表会放行)—— 「用真组件测组合性质」的价值实证;vitest alias 前缀吞没坑修成锚定正则,附清晰理由。list实现及测试(#5266 方案 2 的实现半,随 spec 契约摘除) #5541 无影响)已核。衍生 三个 ADR 编号各自指向两个不同的已接受决策(0010 / 0019 / 0057)——adr-anchors.json与 328 处代码注释按裸编号引用,无法消歧 #5992(ADR 编号一号双档 + 断链)已按纪律立案待分诊。本单四天三改(对账子系统 → 停手证伪 → 裁 C 收窄 → 落地),最终以零新增面收口 —— 流程按设计工作的完整样本。
经办:services 座位,会话
session_015a5qkLzpGXhLL2F5gvJ7dD(第 3 轮)。Generated by Claude Code