Treatment 的 Temporal Validity 与 Reauthorization

解释一个 Treatment proposal 为什么可能在生成时合法、在稍后接受时却已经失效,以及如何用 source/current BodyState revision、Diagnosis freshness 与 material change 做重新授权。

#type / concept #status / growing #tech / ai #tech / architecture #tech / security #resource / bodysense #resource / agent

[!info] related notes

Treatment 的 Temporal Validity 与 Reauthorization

一句话定义

Temporal Validity 指一个 Treatment proposal 的业务资格只对特定历史上下文成立;当时间推进、BodyState 或 Diagnosis 状态变化后,系统必须在 Acceptance 或继续执行前重新验证,而不能把过去的授权当成永久授权。

最简公式:

Valid when generated

Still valid now

为什么“时间”本身不是问题,世界变化才是问题

一个 Proposal 放了 10 分钟不一定失效,放了 1 天也不一定必然失效。

真正关心的是:

从 Proposal World 到 Current World
发生了哪些 decision-relevant change?

因此 temporal validity 不应该简单实现成:

created_at > 1 hour
→ invalid

时间阈值可以作为重新检查触发器,但最终决定应基于业务状态变化。

为什么 Treatment 比 Diagnosis 更容易遇到时间问题

DiagnosisAnalysis 在产生以后主要成为历史分析事实:

R42 → D100

用户状态变化后:

R43 → D101

而 Treatment Proposal 常常会在系统里等待用户行动

R50 + D20
→ Proposal P3
→ [等待几小时/几天]
→ User Accept

这个等待窗口让“生成时上下文”和“接受时上下文”自然分离。

Proposal 应保存自己的 Source Context

一个可审计 TreatmentRevision 应知道自己是基于什么生成的,例如:

source_body_state_revision = R50
source_diagnosis_analysis_id = D20
agent_configuration_id = C7

这些字段不是普通 metadata,而是未来重新授权的锚点。

没有 source identity,就无法回答:

“当前 R54 和当初 P3 看到的世界到底差了什么?”

Source Context 最好包含“决策依赖”,而不是仅一个时间戳

例如:

source_body_state_revision
source_diagnosis_analysis_id
candidate assessment identity/state
safety state reference
configuration ID

因为 created_at=10:00 无法告诉系统 Proposal 当时依赖什么事实。

Temporal reauthorization 的基础是可比较的 source identity

Acceptance 时需要比较两个世界

Proposal World
R50 + D20

Current World
R54 + current Diagnosis freshness + current SafetyState

Acceptance Policy 要判断:

从 source world 到 current world 的变化,是否会实质影响这个 proposal 的适用性?

这就是 temporal authorization。

World Diff 应该是 Domain-aware,而不是 JSON Diff

如果 BodyState 有 100 个字段,R50→R54 变化 5 个字段,不代表这 5 个都影响 Treatment。

例如:

preferred_workout_time changed

可能只影响 UX。

而:

new radiating pain
new neurological red flag
new load intolerance

可能直接改变 action eligibility。

所以更合理:

BodyStateRevisionDelta
→ Domain Materiality Policy
→ material / non-material for this Treatment

而不是:

JSON != JSON
→ reject

Revision 变化本身不是自动 Blocker

一个常见误解是:

current_revision > source_revision
→ proposal 一律失效

这太保守。

例如 R50 → R51 只是:

补充了一个与当前 Treatment 无关的低风险观察

可能不影响 Proposal。

因此当前 BodySense 的 acceptance 逻辑更接近:

if current_revision > source_revision:
    inspect revisions after source
    evaluate material review policy

也就是:

Revision drift 是重新评估的触发器,不一定是最终拒绝理由。

为什么 current_revision < source_revision 应 Fail Closed

正常历史应满足:

current revision >= proposal source revision

如果出现:

current R49
source R50

说明可能有:

  • 数据恢复错误;
  • stale replica;
  • revision parsing bug;
  • cross-user/cross-environment mix-up。

这不是普通“状态没变”,而是历史顺序本身异常,应该阻断 acceptance 并调查,而不是继续推断。

Material Change:什么变化值得阻断旧 Proposal

Material change 指足以让原 Proposal 的依据、风险或动作资格发生实质变化的状态变化。

例如:

Safety Material Change

R50: no active red flag
R51: new red flag

旧 Proposal 即使当时完全合理,也不应继续直接接受。

Diagnosis Material Change

D20 originally fresh

new BodyState evidence

D20 becomes stale

Treatment 基于的 diagnosis epistemic foundation 已经发生变化。

Constraint Material Change

例如新的用户约束使某 intervention 不再适合:

previously able to load shoulder

new injury / movement restriction

Prescription-relevant Change

例如原计划:

load progression permitted

但当前用户出现:

post-intervention worsening

可能不要求整个 Diagnosis 重做,但会让原 prescription 不再适用。

Non-material Change

例如:

新增长期不相关的普通 profile 信息

可能不需要废弃旧 Proposal。

Materiality 是“相对于某个 Action”的,不一定是全局属性

同一个 BodyState change 对两个 Treatment 的影响可能不同。

例如:

new wrist limitation

对:

lower-body walking plan

可能 non-material。

对:

loaded wrist mobility plan

则 material。

所以更成熟的 policy 可以考虑:

MaterialChange(change, treatment/intervention context)

而不是每个 change 全局固定 material=true/false。

Diagnosis Freshness 为什么是 Treatment 的输入

Treatment 不应该把历史 DiagnosisAnalysis 看成永远正确的静态前提。

更准确的关系是:

DiagnosisAnalysis D20 = immutable historical artifact
DiagnosisFreshness(D20, current BodyState) = current applicability judgment

因此:

D20 itself never changes
but
D20 may become stale against R54

这延续了 Diagnosis 阶段的重要原则:

Historical truth

Current applicability

Treatment 正是第一个强烈依赖这个差异的下游系统。

Freshness 不应该通过修改 DiagnosisAnalysis 表达

不要:

D20.status = stale
并修改里面的 candidate/gap

更合理:

D20 remains immutable
FreshnessEvaluation(D20, R54) = stale

或者保存独立 applicability/freshness projection。

这避免下游 temporal logic 篡改上游历史事实。

为什么 Acceptance Authority 必须重新读取 durable truth

错误做法:

Frontend sends:
{
  revision_id: P3,
  safe: true,
  diagnosis_fresh: true
}

然后服务端信任这些状态。

正确做法:

AcceptProposal(P3)

Go loads current BodyState

loads source Diagnosis

evaluates freshness

loads candidate assessments

evaluates revisions since source

DecisionPolicy

原因是 Acceptance 是一个业务命令边界,authority facts 应由 durable owners 重新读取,而不是从 UI 带回来。

为什么 Client-supplied Facts 不可信,即使 UI 是自己写的

不是因为前端“恶意”,而是因为:

  • UI cache 可能 stale;
  • 多标签页并发;
  • 网络延迟;
  • API retry;
  • 其他客户端可能更新 BodyState;
  • 未来有移动端/自动化客户端。

所以 command boundary 必须以 server-side durable truth 为准。

Reauthorization 不等于重新调用 LLM

这是非常重要的区别。

重新授权首先是 deterministic:

current facts
+
versioned policy
→ allow / block

它不应该默认变成:

“让模型再看看旧 Proposal 现在还行不行。”

如果 Policy 判断旧 Proposal 已超出有效范围,系统可以:

block old acceptance
→ request/generate new revision

而不是让 LLM 临时给旧 Proposal 一个免责说明。

什么时候才需要重新生成 Proposal

Reauthorization 结果可能分:

Still valid
→ accept old proposal

Stale but repairable
→ maybe generate revised proposal

Safety-invalid
→ block/escalate, no ordinary generation

这避免“只要状态变了就自动重新问 LLM”的过度调用。

Ongoing Authorization:接受以后也不是永久有效

Temporal Validity 不只存在于:

Proposal → Acceptance

还存在于:

Accepted Treatment → Continued Execution

Treatment 可能经历:

active
→ review_recommended
→ paused
→ superseded
→ completed

新的 Outcome / BodyState revision 可能触发:

EvaluateCurrentReview

也就是说:

现实世界中的 action authorization 往往需要持续维持,而不是一次性永久授予。

为什么 Ongoing Review 不应该每次都重新调用 LLM

很多变化可以先 deterministic 判断:

new red flag
source diagnosis stale
material constraint changed

先决定:

pause/review required

之后如果需要新方案,再进入 Agent proposal。

这让 safety control 不依赖模型是否及时意识到风险。

时间轴例子

09:00
BodyState R70
Diagnosis D30 fresh
→ P8 generated
→ allow-proposal

12:00
BodyState R71
新增轻微、无关信息

13:00
User Accept P8
→ inspect R71-R70 delta
→ non-material
→ allow-acceptance

Day 3
Outcome O12 recorded
→ BodyState R72
→ material worsening signal
→ Treatment status = review_recommended

注意三个时间点对应三个不同问题:

09:00: Can we propose?
13:00: Can we accept now?
Day 3: Can this Treatment continue unchanged?

第二个例子:时间很短也可能失效

10:00 P9 generated
10:02 user reports new severe neurological sign
10:03 click Accept

只过去 3 分钟,但 source/current world 已 materially changed。

所以:

age of proposal

validity of proposal

与 optimistic locking 的区别

Temporal Validity 不是单纯数据库并发控制。

Optimistic locking 问:

“我读取以后这行数据库有没有被别人修改?”

Temporal Validity 问:

“即使没有写冲突,现实业务状态发生的变化是否让旧 Proposal 失去资格?”

两者可以同时使用,但解决的是不同问题。

与 Revision Guard 的组合

典型 acceptance:

1. Load proposal source R50
2. Load current R54
3. Evaluate materiality/freshness
4. Produce allow decision
5. Transaction checks current still R54
6. Commit acceptance/current pointer

第 3 步是 temporal validity;第 5 步是 concurrency guard。

如果只做第 3 步,validation 后到 commit 前仍可能有 R55 出现。

TOCTOU:检查通过后世界又变了

这就是 time-of-check-to-time-of-use 问题。

check current=R54
→ allow
→ before commit, R55 arrives
→ accept based on stale check ❌

所以关键 transition 要在事务中再次确认 revision/invariant。

这是一条非常典型的“领域 authorization + 数据库并发控制”组合。

Temporal Validity 与 Configuration Validity 也是两个轴

Proposal 可能:

source BodyState still valid

但生成它的 Agent Configuration 已被紧急撤回。

是否允许历史 proposal 被继续接受,需要独立 policy。

可能:

configuration revoked for safety
→ pending proposals blocked

也可能某些非安全升级不影响已经 generated proposal。

所以 production system 还需要明确:

state freshness
vs
configuration lifecycle

Behavioral Contract

可以为 Treatment 定义:

proposal acceptance state != proposed
→ acceptance forbidden

current BodyState revision < source revision
→ fail closed

source Diagnosis stale
→ acceptance forbidden

active safety concern
→ proposal/acceptance forbidden

current revision advanced + material change
→ old proposal acceptance forbidden

current revision advanced + no material change
→ acceptance may remain allowed

再加:

validation revision must equal commit-time revision

避免 TOCTOU。

DecisionTrace 应保存两个世界

Acceptance trace 至少需要能解释:

source_body_state_revision = R50
current_body_state_revision = R54
material_change = false
source_diagnosis = D20
freshness = fresh
safety = clear
policy = treatment-go-acceptance-v1
→ ALLOW

这样以后才能回答为什么一个 revision drift 的 proposal 仍然被接受。

Temporal Policy 也应该版本化

“什么 change 算 material”会演化。

例如 v1:

any new radiating symptom → material

v2 可能细分:

transient low-severity observation → review only
progressive neurological sign → block/escalate

这是行为变化,应通过 policy revision/qualification 管理,而不是在代码里静默修改。

测试 Temporal Validity 应覆盖什么

Same revision

current == source
→ no drift path

Advanced but non-material

R50→R51 unrelated update
→ acceptance may pass

Advanced and material

new red flag / relevant constraint
→ block

Diagnosis stale

immutable D20 still exists
freshness(D20,current)=stale
→ block

Impossible revision order

current < source
→ fail closed

TOCTOU

validation on R54
commit sees R55
→ transaction must fail/retry

Ongoing review

accepted treatment + worsening Outcome
→ review_recommended / pause path

自测题

  1. 为什么 Proposal 放了很久不一定失效,刚生成也可能立刻失效?
  2. Source Context 为什么不能只保存 created_at?
  3. Revision drift 为什么只是 re-evaluation trigger,不一定是 blocker?
  4. Material Change 为什么应相对于当前 Treatment/Intervention 判断?
  5. DiagnosisAnalysis immutable 与 Diagnosis freshness 如何同时成立?
  6. 为什么 acceptance 必须重新读取 server-side durable truth?
  7. Reauthorization 为什么不等于重新调用 LLM?
  8. Temporal validity 和 optimistic locking 各解决什么?
  9. TOCTOU 为什么要求 commit-time revision guard?
  10. Accepted Treatment 为什么仍需要 ongoing authorization/review?

最值得记住的一句话

Action-oriented artifacts have a validity window.

对现实世界采取行动的方案,不仅要问“当时生成得对不对”,还要问“在现在这个世界里,它是否仍然有资格生效”。

创建于 2026/8/22 更新于 2026/8/23