← 返回文章列表

“已批准”不等于“当前事实”:Relation 治理里的时间语义

拆开 Relation 的审核生命周期、时间投影和 Graph 写入状态,解释为什么 active、current、upcoming 与 historical 不能被一个布尔值替代。

很多关系模型只有一个 active=true。它看起来简单,却同时混合了至少三个问题:这条关系是否经过治理批准、它现在是否处于有效时间区间、它是否已经写进产品 Graph。

这三个问题一旦混在一起,就会产生危险的误读。例如:

  • “用户将在下个月加入项目 A”已被 owner 批准,但今天不应出现在 current projection;
  • “用户曾属于团队 B”是真实历史,但不应被当前授权逻辑使用;
  • Foundation 已批准一条 Relation,不代表产品 Neo4j 已经同步;
  • 一条自然语言里提到某个人名,不代表实体已经被可靠解析。

Agent Foundation 的做法是把 Relation 的治理生命周期、时间投影与 Graph 应用状态拆开。

查看 Agent Foundation 项目总览 · 打开本文交互图

第一层:模型只能提交 typed candidate

Relation 不是从句子里抓到两个名词就直接写库。adopter 必须显式提供 typed V2 proposal,包括 allowlisted predicate、主体和客体的 binding references、时间区间以及当前 Observation/route。

Foundation 随后执行共享的零写 preflight:

  • 当前 Registration 是否启用了 personal-safe-relations
  • 实际 principal 是否拥有准确 scope;
  • binding refs 是否能在 Registration 范围内重新解析;
  • predicate 和 operation 是否属于冻结策略;
  • Evidence、route 和 request identity 是否仍是当前状态。

自然语言 mention 不是实体权威。无法解析的候选返回 item-level unresolved,Relation 写入为零;如果同一 turn 还包含安全的 Memory,Memory 可以继续成功,不会被 Relation provider 的失败回滚。

第二层:personal-safe-relations 的 Runtime 候选都进入 owner review

通过 admission 的候选不是 active Relation,而是 pending_owner。ReviewDecision 的目标是冻结的 formation;reviewer 可以批准或拒绝,却不能在审批时悄悄改端点、时间或 action。

这条规则避免了一种常见的“审批漂移”:界面上批准的是 A→B,执行时却因为重新解析或请求体改写变成 A→C。

批准后 Relation 的治理生命周期进入 active;拒绝会形成不可变的 denied 事实,并从可用投影中排除。

Relation 治理生命周期与时间投影

技术解释图:横向是 candidate 到 owner approval;右侧是独立的 upcoming/current/historical 时间投影;下方是不解析、拒绝和 provider 降级。

第三层:active 不等于 current

active 回答的是:这条 Relation 是否已经完成治理并被接受。

current 回答的是:在查询时刻,它的有效区间是否覆盖现在。

因此一条未来关系可以同时满足:

lifecycle_state = active
temporal_projection = upcoming

它不会出现在默认 current projection。到达 valid_from 后,投影变为 current;越过 valid_until 后,生命周期历史仍被保留,但默认投影变为 historical。

这些状态分别记录“批准过”“现在有效”和“历史存在”,避免用一个布尔值同时表达三个不同事实。

第四层:Relation 仍然不是产品 Graph

AF-C04 的 Relation bridge 只调用现有 Relation planning 与 temporal propose/confirm/reject primitives,不调用 RelationEvolution.apply(...),也不持有产品 Graph port。

因此返回状态始终明确包含:

graph_state = not_applied

这意味着 Foundation Relation 可以被治理、审核和时间投影,但不会凭空修改 adopter 的产品 Graph。需要 Graph mutation 时,必须走另一条 Graph Proposal → ReviewDecision → durable outbox → independent executor 链路。

把两者分开有两个好处:

  1. Relation 审核不会因为产品 Graph 暂时不可用而失去审计事实;
  2. 产品不会把“Foundation 接受了语义关系”误解为“真实数据面已经完成变更”。

为什么没有复用 Memory 的自动应用策略

低风险、owner-explicit 的偏好 Memory 在 sealed local development 中可以按严格规则审计式 auto-apply。Relation 的风险不同:它通常连接多个业务实体,可能影响权限、推荐、组织结构或时间判断。

因此当前 personal-safe-relations Runtime 合同中的 Relation candidate 全部进入 owner review,没有把“看起来像普通关系”的模型分类当作自动写入依据。敏感内容、实体未解析、策略缺失或 provider 降级都 fail closed。

exact replay 与 semantic duplicate

同一 request identity 的 exact replay 不应重复创建 candidate、ReviewDecision 或 temporal event。Foundation 通过稳定 identity 和 receipt 返回同一结果。

新的 semantic duplicate 可以保留必要的 Observation/Formation 审计,但不会因此把产品 Graph 写两次。这里需要继续区分“请求重放”“语义相似”和“真实 Graph 幂等 marker”,它们不是同一个去重层。

采用方仍然拥有产品语义

Foundation 不拥有全局 ontology,也不会把两个自由文本名字猜成同一个实体。adopter 决定:

  • 哪些 predicate 被允许;
  • binding reference 指向哪些产品实体;
  • 时间字段的业务含义;
  • 谁是 represented owner;
  • 哪些 approved Relation 需要进一步生成 Graph Proposal。

Foundation 拥有的是 admission、身份重验、冻结候选、ReviewDecision、temporal state 与 receipt,而不是产品世界观。

已验证到哪里

当前本地版本化基线已经验证:

  • typed Relation capability 和 shared preflight;
  • unresolved entity、capability 缺失与 provider degraded 的 item-level 结果;
  • owner approve/reject 与 exact replay;
  • future Relation 的 active + upcoming,以及默认 current read 不可见;
  • SQLite 与 PostgreSQL temporal Relation 路径;
  • Relation/Graph Evidence dependency convergence;
  • Graph 写方法 fail-fast spy 调用数为零。

仍然没有由这条链证明:

  • 产品 Graph 已同步;
  • 大规模时间图查询性能;
  • 生产 IAM、TLS、HA/DR;
  • 模型能可靠地自动抽取所有 Relation;
  • Relation 的业务正确性优于 adopter 自有策略。

最终原则很简单:治理批准、时间有效和数据面应用必须分别可证明。 只有这样,“这条关系存在过”“它现在有效”“它已经写入产品系统”才不会在 Agent 时代被一个模糊的 active=true 混为一谈。

← 返回文章列表