# Auto-oncall Evaluation 系统

> Status: Current behavior and agent lookup source  
> Updated: 2026-09-04
> Scope: 日报质量信号、Recent Focus、Recent Evaluation、Daily Recent Optimizer、优化归因

本文涉及的对客/对内消息身份、版本、replay 和消费边界统一遵守
`docs/DUAL_MESSAGE_CONTRACT.md`。

## 1. 这套系统解决什么

Evaluation 系统负责回答三个不同问题：

1. 最近真实 ticket 暴露了哪些回答问题？
2. 当前 Focus 选择的一个问题是否仍可复现、修改后是否改善？
3. 某个 Focus 内或 Focus 外的优化，对哪些具体问题已经实施、验证或确认无效？

一个 Focus 只解决一个可复用问题，不代表完整解决其中任何一个 ticket。一个
ticket 可以同时包含多个问题，这些问题可以进入不同 Focus，并具有不同优化状态。

## 2. 总体数据流

```text
Jira replay + paired customer/internal messages + later L1 reply + /ao feedback + successful-run execution state
  -> Daily report comparison
  -> problem-level target/control signals
  -> docs/opts optimization registry filtering
  -> no Active Focus: Focus selector
  -> fresh baseline on current main
  -> GitHub Focus Issue + checkpoints
  -> read-only previous-attempt review and bounded repair plan
  -> product dependency gate: current shared break + monotonic replay evidence -> separate Dependency Focus
  -> optimizer-process dependency / protected path / multiple stages -> human_handoff
  -> simple single-stage ordinary path -> isolated patch agent
  -> tests
  -> challenger replay
  -> candidate gate
  -> Draft PR
  -> later fresh replay / verification
  -> optimization status and weekly report

One-ticket bad-case signal (`/ao wrong|revise`, `human_better`, runtime degradation, or `/ticket`)
  -> latest persisted answer version + fresh read-only replay
  -> agent-driven full-chain investigation
  -> deterministic single-owner engineering gate
  -> bounded patch + regression test + CI + automatic merge
  -> exact-SHA staging deployment + post-change read verification
  -> publish exact read replay to stable Jira internal comment + optimized_verified record PR
```

日报持续产生质量信号。GitHub Focus Issue 只保存当前一个优化问题的执行状态，
不是所有 bad case 或所有优化记录的唯一来源。Focus 外优化通过 `docs/opts/`
独立记录。

第二条 single-ticket lane 由持久化 `wrong|revise` 人工反馈、Judge `human_better`、成功 run
中的 Provider 降级/失败或 Router/Final timeout 自动触发，也可由 `/ticket` 手工补跑；它不参与 Focus 选题和消费。它只处理一个 ticket 已经独立证明、
可以用确定性工程 criterion 验收的断链；语义和跨 case 问题返回 Focus candidate。完整契约
见 `docs/SINGLE_TICKET_OPTIMIZER.md`。

Single-ticket investigation 的 chain、首个断点、诊断影响和 repair decision 都以 current
main 加 fresh replay 为时间口径；历史被提名答案独有的问题只作为说明证据。首次结果若仅
违反分类字段组合，controller 复用同一只读调查 thread 做一次受限结构纠正；第二次仍不合法
才失败，且任何纠正都不能进入写 Agent 或降低确定性 repair gate。

## 3. 核心对象

### Daily comparison

日报和周报统一纳入 `initial` 与 `bot_assignment` 两种 Auto-oncall 入口；
`continuation` 不进入自主处理总量或自动评价。每个成功 run 以实际发布的 Auto-oncall
评论为比较锚点：已写入的 Public customer reply 优先，没有 Public 写入时才使用
written/updated internal comment。再将该回答版本的 customer message 与后续 L1 实质回复
进行比较，主要产出：

- `eligibility`：是否具备可比较条件；
- `verdict`：`ai_better`、`equivalent`、`human_better` 或 `not_compared`；
- `aiGaps`、`keyDifferences`、`aiStrengths`；
- `/ao wrong|revise` 等显式反馈。

同一个 Report Judge 还读取冻结 ticket 上下文、两份 Auto-oncall 消息、typed
`decision`、后续人工答案，以及该答案版本的 `/ao` action/reason。Runner-owned
`execution`、Provider status、failure codes 和 query attempts 不进入 Judge prompt；它们
保留为独立 runtime 状态和 Optimizer 输入。`ai_human_required` 在存在后续人工答案时也进入这个 Judge，而不是固定
`not_compared`：Judge 按 AI 当时可见的事实、实际可用能力和安全/操作边界进行阶段公平
比较。人工后来通过客户补充、共享屏幕、人工查询或生产操作获得的新事实不能反向证明 AI
更差；但 AI 对当时可见事实的遗漏、无依据结论、错误 owner 或不可执行 handoff 仍可判为
`human_better`。Judge 不得假设冻结输入未证明存在的内部查询能力。
如果 `human_required` AI 回复先承诺执行一项具体、可执行的 Support 内部查询，而人工答案
随后报告该查询没有匹配结果、再向客户索取 SQL 语句、截图或其他客户侧信息，Judge 不得把
人工查询后的结果倒灌到 AI 的时间点，也不得只因 AI 没有在第一条回复中立即索取这些信息而
判为 `human_better`。只有冻结输入或 AI 回答本身已经证明内部查询在 AI 回复前完成且穷尽、
下一步必须取得客户独有信息时，遗漏精准澄清请求才构成差距；否则按两个阶段各自是否合理
使用 `equivalent` 或 `different_but_valid`。
`mode=write` 生成不同 fingerprint 的新答案时，同一个 Judge 还必须读取写入前最近成功的
旧答案消息对和绑定旧 fingerprint 的最新 `/ao` action/reason。它同时判断新版是否解决了旧反馈
指出的问题，再评价新版与完整人工答案；旧问题仍存在时不能仅因新版来自一次新运行就判为可接受。
当 comparison 涉及 TiCDC architecture 时，同一个 Report Judge 还接收从对应
repository product-knowledge topic 提取的 `evaluationKnowledge`，并按与诊断相同的
证据分级评价：显式 control-plane 字段或对齐启动/部署标记是最强直接证据；直接证据
缺失时，同一 changefeed、同一窗口内 Maintainer、dispatcher、Event Service 以及可观测
时的 Event Store/Log Service 连贯活动，只能确认“正在经过新架构 runtime path”，且回答
必须披露直接字段/标记缺失。版本、dedicated/deploy type、Dataflow identity、指标族存在或
单一 owner/dispatcher 序列均不能单独确认。Judge 不得因缺少显式字段否定完整运行链，
也不得放过把运行链错误表述为 metadata 直接确认的回答。

Single-case `mode=read|write` 的 replay cutoff 与 Judge 人工参考是两个不同事实。
`anchor.targetHumanCommentId` 继续只拥有历史 replay cutoff；它不能把后续人工结论放进
analysis workspace。Evaluation 与 report/dashboard 使用同一个 comparison builder，把同一
ticket 的完整有序 Public customer/Support 时间线交给同一个 Report Judge，并用
`visibleToAi` 标明哪些评论属于冻结输入。代码只确定 comment 顺序、角色、可见性和答案版本，
不按“下一条 customer comment”或文本关键词决定人工答案范围。Judge 从
`role=support && visibleToAi=false` 中按时间顺序返回共同构成原问题完整人工答案的最小
`targetHumanCommentIds` 集合。客户催促、确认、致谢、重复问题或“仍在发生”但没有新增诊断
事实时不终止向后查找；若客户新增实体、时间、现象、日志、截图、SQL 或执行结果，Judge
必须区分依赖这些新事实的人工结论，不能把 AI 当时不可见的信息反向用于判差。只有确认、
进展或关闭话术而没有实质答案时通常必须 `not_compared`，不能因为人工参考为空泛而判 `ai_better`。
同一问题上的多条 Support 回复是一份持续演进的人工答案。Judge 只用 ticket summary、customer
question 和 `visibleToAi=true` 评论确定原问题及其明确要求；原因、机制、影响、处置或验证只是
可能的答案维度，不是检查清单，后续不可见评论不能反向扩张问题范围。Judge 再让每个所需维度
只保留最后一个仍有效的 Support 表述；后文重述、
补全、修正或替代前文时选择后文，早期内容仅在仍有效、未被覆盖且对完整回答不可缺少时保留。
完整回答形成后，客户后来提出的恢复检查、其他实体、配置或风险问题及其回复不再进入答案，除非
明确修正已选结论。多个集合语义等价时固定选择评论更少、使用更晚有效表述的集合。所选 ID
表示原问题的最终有效人工答案，而非全部调查更新。
选出人工答案后，Judge 仍须读取其后的 customer 评论：同一问题的明确结果确认、归因纠正或
实际验证可用于验证或反驳 AI 与人工答案，但不能进入 `targetHumanCommentIds`；普通偏好、无依据
猜测、致谢或关闭请求不自动成为权威结论。若客户明确把人工怀疑的问题说明为另案、并确认原
问题由另一机制导致，Judge 不得只因人工回复更具体而忽略该纠正；
若人工的更具体结论依赖后续信息，而 AI 在冻结输入下合理保留不确定性并给出可执行后续动作，
Judge 默认使用 `different_but_valid`；`ai_better` 必须由人工最终答案的明确事实错误、重要风险或
其他实质质量优势支持，不能只用于打破接近答案的平局。
但新版本 write 同时携带旧版本 `wrong|revise` 时，Judge 仍须先独立判断旧问题是否解决，不能用
人工答案缺少实质内容跳过版本比较。旧问题仍存在时，新版 verdict 必须为 `human_better`。
Evaluation 以 `referenceComments[]` 保存 Judge 实际选择的 comment ID、时间与正文 digest；
`targetHumanCommentId` 仍只是 cutoff anchor，不再兼任唯一人工答案。
Single-case `AnalyzeTicketEvaluation` 同时以 `humanAnswerMarkdown` 返回由 Judge 选择结果组合出的完整
组合正文，供受控的 Single-ticket Optimizer 做独立答案审阅；无可比较人工答案时为 `null`。
该正文不是第二套配对结果，仍由 Judge 的 `targetHumanCommentIds` 生成并由
`referenceComments[]` 审计。

### Answer version 与人工反馈

`/ao` 评价的是评论发生时已经发布的具体回答版本，不是永久评价整个 ticket，也不按
run 的生成时间简单取最新：

- 每个成功 run 按规范化后的 `customerReplyMarkdown` 与
  `internalHandoffMarkdown` 消息对计算稳定 `answerFingerprint`；任一消息发生语义变化都形成
  新答案版本，Jira 状态 footer、反馈提示和运行元数据不参与版本计算。历史单消息
  fingerprint 保持可读，不做重写。
- 反馈绑定到其评论时间之前最近一次发布的 run，首次落库后不得因稳定 Jira 评论被
  后续原地更新而改绑到其他 run。
- `/ao` 可以出现在上述 Public 或 internal Auto-oncall 评论之后。internal 评论中的命令
  保持现有信任边界；Public 评论中的命令只有在作者被稳定识别为 Support 时才接受，
  customer、bot 或无法识别角色的 Public 评论不能控制评价或 optimizer。
- Collector 在 lookback 内重新读取稳定 Jira 评论的当前正文。同一 source comment 的有效
  编辑只更新其 action 和完整 reason，reason 包含命令行之后的多行补充；原 job、run、
  answer fingerprint 和 source comment 创建时间保持不变。标准提示继续使用
  `/ao revise: 原因`，Parser 同时接受用户自然输入的 `.`、`。` 和旧评论使用的纯空格
  分隔符；兼容格式仍必须是以精确 `/ao` 和 action 开头的完整 trim 后行。
- 当前 run 与被评价 run 的 fingerprint 相同，即使当前 run 更晚，仍继承该 `/ao`
  action/reason。`accept|revise|wrong` 先直接决定 Base 质量解释；普通 report Judge 不覆盖
  它们。`human` 表示请求同一个 AI-vs-人工 Judge 复核，不直接映射为可接受或不可接受；
  Judge 尚无有效 verdict 时保持待评价。
- 同一答案版本存在 `accept|revise|wrong` 时，明确人工评价始终拥有 Base 质量投影；较早或较晚的
  `source=analyze_write` Judge 都不能覆盖它。Judge 只有在新 fingerprint 的 `mode=write` 评价中，
  结合旧答案、旧反馈、新答案和完整人工答案重新判断新版；人工反馈只在冻结输入中的明确事实直接
  证明其不成立时才可被反驳，并必须给出具体证据。
- 当前 run 的 fingerprint 不同，旧 `/ao` 只保留在旧答案版本历史中，不直接覆盖
  新版，但必须作为“旧问题是否已解决”的 version-bound Judge 输入。新版的 LLM verdict 是新版
  当前评价并独立展示，等待新的 `/ao` 时不得伪装成已有人工复核；下游 Optimizer 也不得把旧
  `/ao` 与新版 verdict 合成为同一对象的 `conflicted`。
- Judge 必须把 typed `decision` 当作路由事实：`internal_only` 表示自动回答、无需人工处理且
  没有 Support-owned 后续动作，`human_required` 才表示需要人工处理。若旧反馈批评错误地绕过
  人工，而新版仍为 `internal_only` 并要求 Support 后续查询、核对、重试或升级，不能仅凭 handoff
  中写了“Support 会继续核查”就宣称问题已经解决。
- 飞书 Base、日报 comparison 和 Recent Focus 使用同一答案版本关联。Recent Focus
  只能消费 comparison 自身版本的 wrong/revise，不能把同 ticket 其他版本的反馈
  提升为当前 problem signal。

答案版本变化只说明“评价对象已变化”，不证明旧问题已经优化；问题是否
`optimized_verified` 仍只由 `docs/opts/` 的 problem-level record 和对应验证证据决定。

Base 的有效 Judge verdict 映射为：`ai_better|equivalent|different_but_valid -> 1`，
`human_better -> 0`，`not_compared -> null`。原始 `Feedback` 与 `Manual Evaluation Value`
始终保留，只有 `AI Evaluation Source`、`AI Effect` 和 acceptable 投影按上述优先级变化。

### Successful-run runtime signal

最终 response 成功不代表底层证据链健康。Live initial run 会将同一次运行的
`responseGeneration`、`evidenceAcquisition.status`、provider capability 和
`failureCodes` 写入 run 的 `execution_json`。`failureCodes` 是同一 query 修正后且排除
supplemental query 的最终去重结果，只负责 execution status 和 runtime candidate 触发；
`providerQueryAttempts` 则按时间保留 Managed Provider 的每一次安全请求详情与结果，供
single-ticket 调查查看，不参与候选去重。Clinic 5xx 还会保存脱敏的
`providerSystemEvents`（query、尝试次数、状态序列、恢复/失败结果、上游错误码/消息和
request ID）。日报对这些自有结构化字段做确定性转换；整个 `execution` 对象不进入
report LLM 输入，也不要求模型从最终回答反推底层状态。Optimizer candidate/context
默认保留 `execution`，用于独立调查运行时问题：

长期 Provider 看板使用同一执行链路的独立观测事实：每个 materialized
Clinic/Wetech/Manus query 写入 `providerQueryEvents`，其中 `complete|empty` 计为逻辑
调用成功，`failed` 计为失败；Clinic 每个真实 HTTP response attempt 另写
`providerHttpAttempts`，按 200/400/500/502/other 区分。重试不会扩大逻辑调用分母，
HTTP attempt 也不会反向改变诊断、`evidenceAcquisition.status` 或 publication 判断。
DB 事务落库后按上海自然日投影到 Base，并另算加权 overall；旧 run 缺少完整成功分母时
不做推测性历史回填。

- 只有 `responseGeneration=complete` 且最终 run 成功时进入本信号通道；最终执行失败
  继续由现有失败发现路径处理；
- 已选择 Provider 的 evidence 为 `degraded|failed` 时，即使答案 verdict 是
  `equivalent|ai_better|not_compared`，仍产生独立 `runtime` problem signal；
- `complete`、未选择 Provider、旧 run 缺少 execution 字段时不产生该信号；
- v2 诊断策略在 route 前确定 `eligibility.eligible=false`、且 route/auth/scenario 均为
  `not_run` 时属于未选择 Provider run：execution 保留未来可能使用的 Provider route，但
  capability 为 `null`、不产生 runtime signal；
- 新日报采样优先保留具有 runtime signal 的成功 run，避免被普通比较样本截断；
- 同 case 的 runtime signal 排在表层答案差异之前，但答案差异仍保留为独立 problem
  ref，不会被 runtime 问题消费。

Runtime Focus 的 target 必须具有完全相同的 `stage + provider + failureCodes`；
`degraded|failed` 只描述证据覆盖程度，不作为根因身份。Controller 会拒绝将不同底层
机制仅按 ticket 表层主题聚成同一 Focus。

周报确定性汇总报告窗口内的 provider HTTP 5xx，分别列出重试后恢复与重试后仍失败、
涉及 ticket、最多尝试次数、脱敏上游错误以及 request ID，供底层系统 owner 对外沟通；
不要求报告模型从回答正文推断。

### Focus

Focus 是一个窄问题的版本化验收契约。新建 Focus 只允许一个 blocking criterion，
它代表本轮唯一要解决的有界问题；其他 criterion 只能用于保留行为或记录 follow-up，
不能扩大本轮修复范围。Focus 包含：

- `problemStatement`；
- 1～10 个 `acceptanceCriteria`；
- 至少 2 个 target；
- 0～2 个可选 control；
- 恰好一个本轮真正阻断候选的 `blockingCriterionIds`。

新建 Focus 使用 `recent-evaluation-focus-v2`。每个 case 还绑定一个不可变的
`recent-focus-case-source-v1`：日报 case ref、comparison/run/answer fingerprint、日报
artifact 更新时间、run cutoff、ticket question/content digest、参考人工 comment id 与正文
digest。它是 replay 输入版本，不是展示信息；旧 `recent-evaluation-focus-v1` 仍可读取，
但不迁移已经关闭的历史 Focus。

自动修改只处理简单通用 Focus：所有 target 共享同一个最早断点，repair plan 只落在
一个 evidence-chain stage，并且 implementation targets 全部是普通非 protected path。
当只有一个 target 出现独立的更早断点时，不创建 Dependency Focus。复用同一个只读
planning session 作为 manager：只有当前源码能证明该 stage 存在唯一、普通且非 protected
owner 时，才允许一次只针对该 case/owner 的 inline unblock；patch session 不得同时修改
父问题，不得加入 case data、target 猜测、fallback discovery、凭据、部署或 optimizer
流程。无法安全直修，或同 case/stage 的尝试没有产生预期 transition 时，controller 按
当前 base、stage status 和 failure codes 记录 `case_blocker`。它只是调度排除，不算通过，
也不修改验收分母；同 base/签名不再重试该 case。至少还剩两个未阻塞 target 才保留当前
Focus 为 Active，否则进入 `human_handoff`。
如果 planning 发现独立前置问题，可以继续创建 Dependency Focus，包括从已有 Dependency
Focus 继续拆分；不设置固定深度，但每条边必须通过确定性 Dependency gate：

- proposal 绑定父 Focus 的唯一 blocking criterion；
- 2～5 个当前 target replay 共享同一个 earliest failure point 和当前 stage status；
- `runtime_prerequisite` 声明该 stage 的前向状态转换，并由每案 `trace/` 或 `output/`
  artifact 验证；
- `observability_prerequisite` 不伪称 stage 已恢复，而是由每案 artifact 将 generic failure
  收敛为一个稳定的 bounded owner category；
- proposal 必须分别声明 prerequisite 与 parent repair 的精确 implementation targets，
  以及 parent repair 所属 stage；若当前 gap target 集合相同、stage 相同且实现 target 有
  交集，说明只是同一 owner 内为完成父修复所需的诊断步骤，不得拆 Dependency Focus；
- Focus id 和 blocking criterion id 不得与任一 ancestor 重复。

同 scope 的 ordinary 单 stage 修复直接留在 parent Focus；如果实际 owner 是 protected path，
或当前证据仍不足以安全自动完成父 criterion，则在 parent 上保存 `human_handoff`，不创建
只负责补日志、补 trace 或细化失败分类的 child Focus。比如恢复 Wetech readiness 与为同一
readiness helper/runner 增加失败归属都位于相同 target、`provider_request_input` 和实现 owner，
后者是前者的修复步骤；而 workload evidence Focus 被更早的独立 readiness product boundary
阻塞时，仍可创建合法 Dependency。

只改变 optimizer planning、validator、protected-path admission、authorization、scheduler
或其他工作流机制的 `optimizer_process` proposal，不是产品因果依赖，进入
`human_handoff`。protected implementation target 或跨 stage repair 也进入该状态。
Controller 保存 baseline、计划和验收证据，不启动写 Agent；Issue 保持打开供人工处理，
但不再占用 Active Focus 名额，原 problem refs 保持已消费。
此外，连续三个完整 rejected/inconclusive attempt 都没有 confirmed blocking improvement，
且 repair plan 已轮换至少三个不同 implementation target 时，也确定性转人工。这表示
controller 已没有稳定的单一 owner hypothesis；该状态不是提前退休，Issue 与历史证据仍保留。

### Target

Target 用于证明 Focus 问题在真实 case 中存在，并判断修改是否满足 blocking
criteria。Target 的执行失败、blocking criterion 不确定或修改后仍不满足，会阻断
相应阶段。

### Control

Control 是可选的相邻能力观察样本，用于展示可能的回退，不决定 target 问题是否
存在。找不到合适 control 时可以省略；control 有 gap 或执行失败时保留为 evidence，
但不阻止 Focus 创建、日常续跑或 Draft PR。

中文术语约定：`regression` 表示评测动作时写“回归”，例如“回归评测”；表示
状态、效果或 signal 时写“回退”，例如“能力回退”“回退 signal”。

### Evaluation finding

Judge 对每个 case 的每个 criterion 返回：

- `met`
- `gap`
- `inconclusive`
- `not_applicable`

整轮 finding 为：

- `gaps_found`：至少一个 case 有 gap；这是正常评测结果，不是任务失败。
- `criteria_met`：所有适用 criterion 都满足。
- `inconclusive`：没有确认 gap，但存在执行或证据不足，无法判断。

Focus 生命周期和 candidate gate 只读取 target blocking criteria；control 或
non-blocking gap 即使让整轮 finding 显示 `gaps_found`，也只作为 follow-up evidence。

Case 执行状态必须区分回答生成与 provider evidence 获取：

- `responseGeneration.status` 与 `evidenceAcquisition.status` 分别使用
  `complete`、`degraded` 或 `failed`；
- provider evidence 状态还记录 `providerCapabilityVerified` 和有界
  `failureCodes`，并透传到 Recent Evaluation 的确定性 reconciliation 与 candidate
  artifact，但不进入 Recent Evaluation Judge prompt；
- acceptance criterion 可选声明
  `requiredCapabilities: ["provider_evidence"]`。Selector 的结构化输出始终携带该数组，
  `[]` 表示未声明 provider 依赖。只有显式声明该依赖且当前
  provider capability 未验证时，该 criterion 才确定性转为
  `inconclusive`；非 load-bearing 的 provider degradation 不得抹掉回答本身已经
  满足的 criterion；
- response generation 失败时，除 `not_applicable` 外的 criterion 均为
  `inconclusive`，不得把执行环境失败记成能力 gap。
- Recent Evaluation 的失败 case 如果已经创建 replay workspace，必须从该 run 的真实
  trace 保留 selected provider、capability 和 failure codes，并单独把 response generation
  标为 `failed`；不得把下游失败改写成 `provider=none`。如果异常发生在
  workspace 创建前、没有任何 run evidence，则 execution 保持未知并省略，不能制造 provider
  成功或未选择 Provider 的结论。字段所有权和合法组合见
  `docs/AUTO_ONCALL_CORE_CONTRACT.md`。

Scenario evidence 使用统一边界：Scenario Router 首先只选定 scenario、entity、绝对窗口和
provider，并写明选择该 scenario 的 reason；每个 scenario 启动一个 persistent Scenario Diagnostic Agent，
由它先把 reason 当作待验证假设、对照最强备选，再提出一个中立、
有 observable stop condition 的证据问题；Evidence Agent 把该问题规划成只读 provider query，
runner-owned Provider Executor 执行已校验 plan，并确定性生成 compact report 与 handoff；同一个
Scenario Diagnostic Agent 消费每轮 handoff，完成局部诊断或提出一个新的 load-bearing question；
同一个 Scenario Router thread 回收所有局部结果，负责去重、
冲突处理、证据优先级、主因、备选、mitigation、severity 与 human handoff，形成唯一 ticket-level
诊断；Final Response Agent 只优化文字，不再做诊断。
Evidence Agent 不得判断 identity、因果、mechanism、alternative、severity、scenario status 或
human handoff；Scenario Diagnostic Agent 不得调用 provider、加载 provider skill 或启动另一个
Evidence Agent。`Judge` 只用于 evaluation，不是 runtime diagnosis role。

`workload-hotspot` 的历史基线也遵循这个 ownership。Scenario Router 只固定事故窗口，不能为了
历史对比把 `anchor.window` 扩成七天。Scenario Diagnostic Agent 在消费事故窗口证据后，只有当
“局部峰值”和“相对历史异常值”的区别仍会改变诊断、容量/headroom 或 mitigation 时，才通过
typed `prior_7_daily_same_clock` refinement 请求历史对比。Runner 从事故窗口确定性生成过去七天
每天同一时段的七个窗口；Evidence Agent 必须规划七个独立 range metric operation，Provider
batch 只负责传输，不能合成一个七天范围请求或一个跨天平均结果。

Scenario Diagnostic Agent 交给 Router 的是收敛后的局部 causal brief，不是 provider evidence dump：
最多四条 load-bearing observation、三条 counter-observation、一个带因果强度和精确 open link 的
leading mechanism、一个 strongest alternative、workload attribution、mitigation/handoff 和 severity。
Router 只在跨 scenario 重叠、冲突、去重、优先级或依赖链上做 ticket-level 裁决，不应重新从 observation
列表诊断单个 scenario。更多证据只能缩小 open boundary；缺少更深 trigger、唯一 workload 或精确 peak
对齐本身不能把一个已有边界结论的历史已恢复事件升级为 `human_required`。

每次 replay 的 Final Response 必须保留同一个 Router 决定下的两份消息：

- `customerReplyMarkdown` 是对客消息，可表现为最终回答、进展更新或一个精准反问；
- `internalHandoffMarkdown` 是对内消息，保存证据边界、缺口 owner、内部动作和升级条件。

客户独有信息缺失时，正常状态是 `clarification_needed`、聚焦的
`requestedContext` 和 `clarificationSimulation.required=true`；只要最终消息需要反问客户，
L1 保底就要求 `human_required`。关键内部信息自动取不到且必须由 Support 接手，或者存在
独立安全、生产操作、权限边界时，同样使用 `human_required`。如果分类时的缺口已被内部
证据消解、最终不再反问，则不因历史 `missingKeys` 单独升级。Recent Evaluation Judge 必须分别
检查两份消息，不能用对内消息里的正确说明掩盖对客消息中的错误索取，也不能因对客消息
是澄清问题却仍把它判为 `internal_only`。

两份消息的完整生产、持久化、Jira、replay、continuation 和 optimizer 消费契约见
`docs/DUAL_MESSAGE_CONTRACT.md`。日报只把对客消息与后续 L1 对客回复比较；对内消息按
evidence boundary、owner、next action 和 escalation 独立审查，不把两个受众的消息互相比优劣。
审查 owner 时要先看动作的执行边界：对 L1/Support 可直接执行的明确内部查询、核对或
重试，`Support` 是足够的 owner，不要为了更具体而制造额外团队。只有必需动作超出
Support 执行边界时，才要求相应产品、组件、平台、操作或审批角色。反之，只写笼统的
`Support 跟进`而没有可执行的精确动作，仍是有效的 `internalHandoffGaps`。
Judge 还必须区分 Auto-oncall 本轮的自动 Provider 能力和 Support 人工后续处理。
所有 Auto-oncall 工单都会由 Support 继续跟进；`provider=none`、能力未验证或自动查询
失败，只能证明本轮 Auto-oncall 没有取到该证据，不能推断 Support 无法人工核查。
当 `decision=human_required`、对客消息只说 Support 会继续内部核查并跟进，而对内消息
已给出明确查询、核对、重试或升级条件时，这不是虚假承诺，不得仅因 Provider
未选择或未验证就判 `human_better`。已宣称某个未执行的具体操作正在进行，或对内仍只有
空泛的“Support 跟进”，仍应记录为差距。

Clinic、Wetech、Manus 必须使用同一编排和 ownership；差异只存在于查询接口边界，包括精确 target
形态、provider skill/helper、plan/result schema、支持的 operation、readiness/auth 和执行并发方式。
需要共享 readiness/auth 的 provider 必须先由 Runner 完成一次 bootstrap；失败时本次 evidence pipeline
立即终止，不得继续启动 Scenario Evidence Request、Evidence Agent、Provider Executor 或后续合成。
Clinic batch 内互相独立的 operation 可以并发，Wetech 与 Manus query 严格串行。所有 provider
batch 最多包含十二个查询，但这是容量上限而非应填满的目标；已知的目标、对齐、机制和最强替代
检查应尽量在同一 batch 内声明，provider helper 自身的有界 transport retry 也属于当前 batch，
不占新的 refinement round。queryId 只需是唯一、稳定、最长 64 字符的安全 slug；它用于 artifact
路径和依赖解析，不是固定诊断分类。

Clinic helper 对 HTTP 500、502、503、504 在同一 query/batch 内最多尝试三次；其他 HTTP
状态不做盲目重试。重试成功必须保留 recovery，三次仍失败必须保留脱敏上游错误、状态序列
和 request ID。失败仍是 unavailable evidence，不能写成“无数据”。

自动 workload discovery 与归因只把 TopSQL 和 Slow Query 作为稳定 workload surface。
Statements 可以作为可选辅助查询，但必须在同一计划或先前 handoff 已通过 TopSQL/Slow Query
建立候选之后使用。Clinic 的冻结 target 无法证明 AWS-only Statements datasource，非 AWS 集群
可能未配置；Wetech 集群组采样率低，返回行不能证明排名、占比、聚合贡献或代表性 baseline，
空结果也不能证明不存在。Provider Executor 将 Statements 标为 `supplemental`：成功结果只能补强
已有候选；空、未配置或失败仍保留 query coverage、compact artifact 和 query event，但不进入
query repair、scenario partial、evidenceAcquisition degraded 或 human handoff。Clinic 对
supplemental Statements 失败也不做 transport retry。

Runner 校验 batch 后，必须从 compact result 中按允许字段确定性提取核心数值和实体事实写入
handoff observation；只传“查询成功”和 artifact ref 不是有效 handoff。原始 SQL、plan、完整
digest、凭据和 token 不得进入 handoff。到达 scenario deadline 时，只保留当前 attempt 已成功
materialize 的 compact facts 和明确 bounded failure；不得通过新的 agent/thread 修复格式，也不得
把 partial fact 提升为 identity、因果或 severity 结论。Provider Executor 尚未开始、batch artifact
尚未生成时，runner 可以把确定性 validator 的精确错误码返回同一 Evidence Agent thread，在同一
evidence round 内允许一次只修计划结构的重写；该重写不得改变 objective、target、时间窗或增加
refinement，第二次仍不合法就按原错误结束本轮。
中性查询描述若重复完整 opaque digest，Provider Executor 在 handoff 前只保留安全 prefix；不得因
这一条可局部规范化的字段而丢弃整批已成功 materialize 的独立证据。

同一 scenario 从首轮开始复用同一个离线只读 Scenario Diagnostic Agent thread，也复用同一个
Evidence Agent thread。Scenario Diagnostic Agent 先给 Evidence Agent 一个精确 evidence question
和 stop condition；每轮 materialize 后继续消费新增 compact handoff。不同 scenario 的两个 thread
都彼此隔离。Runner 只向续用 Evidence Agent thread 提供上轮 compact handoff 和 Scenario
Diagnostic Agent 的新问题，不重复加载 provider skill、历史文件或其他 run 输入。
首轮之后最多允许一个 adaptive refinement。只有 factual handoff 新发现、可能改变诊断结论的
load-bearing question 才可占用该 round；
重述已有结果、补取 handoff 已有事实、已知的小型辅助查询或 helper transport retry 都必须留在
当前 batch。没有有效 batch 时不得用 scenario prose 代替 provider evidence。

Auth bootstrap 不启动 Agent；Provider Executor 也不是 Agent。Runner 输入只包含冻结 target、当前
run context 和 Evidence Agent plan，输出只保留 compact target/session reference、bounded trace
和 compact batch。Wetech Router 可以接收只包含 region、canonical alias、business alias 和已知完整
集群名的脱敏候选列表，用于一次语义 target 选择；Grafana URL、Dashboard route、datasource UID、
凭据、cookie 和命令输出不得进入 Agent context 或 trace。
Evidence Agent 工作目录收窄到当前 scenario evidence 目录，并在启动前获得精确 provider、target、
绝对窗口和 auth context。
所有本地 Codex 诊断 thread 还必须使用当前 run 专属的 filesystem permission profile：当前
`runs` 根目录默认拒绝读取，只对本 run 恢复所需的 read/write 权限，并仅额外放行 Codex
可执行文件以及当前 stage 需要的确定性 Clinic helper、已安装 skills 和 Wetech 私有 session cache。
Evidence Agent 使用其 provider 所需的受限 profile；supplied-evidence Evidence Agent 使用离线可写
profile；Scenario Diagnostic Agent、Scenario Router reconciliation 和 Final Response Agent
使用离线只读 profile。不得再把
传统 `sandbox_mode` 与该 profile 混用，否则 current-run deny 规则会被覆盖。所有 child process
的 `TMPDIR` 必须指向当前 run 的 `work/scratch`；不得为浏览器或 helper 重新开放共享 `/tmp`。
TiDB Cloud provider 查询还必须在进入 scenario 前具备 typed `orgId` 和 runner-owned 精确
cluster target set。已有 typed `clusterId` 时直接绑定单一目标；仅有明确 cluster name/alias 时，
runner 可在该 org 内加载有界 Clinic inventory，由 Scenario Router 解析每个明确目标，并在任何
目标缺失或歧义时停止查询。Evidence Agent 不得自行使用 cluster search 补全或替换目标。Clinic Evidence Agent
只写 bounded multi-source query plan，runner-owned Provider Executor 调用 auto-oncall deterministic
batch helper；helper 对精确 target set 中的每个目标使用同一历史窗口，并发执行预声明的 metrics、Slow Query、
TopSQL/LogStats、Loki、topology、activity 或辅助 Statements 查询，同时压缩原始时序、SQL 与日志。
Statements 只可在 TopSQL 或 Slow Query 已建立候选后提供辅助上下文；其缺失、未配置、低采样或失败
必须保留为非阻塞 gap，不得影响 acquisition completeness、触发重试或要求 human handoff。
其中 `slow_query` 由 helper 最多查询一次精确 cluster metadata 后选择 transport：
Starter/Essential/shared 使用 NGM，其他 tier 使用带日期分区和时间边界的 Data Proxy SQL；
Agent 不得自行选择或 fallback transport。Runner 从
`auto-oncall-clinic-evidence-batch-v1` 结果确定性生成 compact reports 与严格 handoff。
Agent 不得自行重试 provider、patch evidence JSON 或用额外 LLM turn 修复格式。

Judge 评价 Starter/Essential/shared case 时，必须按其真实 Clinic 数据面判断：物理组件拓扑、
TopSQL、持久化 Statements、Dedicated 配置和物理节点 `node_*` 指标属于预期不可用；Slow Query
仅有 NGM 支持的排序。缺少这些数据本身不是 bad case，也不能单独产生 AI 或 internal handoff gap。
只有受支持、对当次结论必要且本应可用的数据没有被查询、使用或正确界定时，才构成质量问题。
Runner 仅可按上述边界在 provider 调用前复用同一 Evidence Agent thread 修复一次 plan 结构；
provider 已调用或已有 batch artifact 后不得进入该路径。

Wetech ticket 已选择精确 account 时，Scenario Router 先根据脱敏候选列表固定 region 与 canonical
alias：默认 `asia-prod`；只有用户明确中东或完整名称包含 `gcp` 才选择 `middle-east-prod`，完整名称
包含 `ali` 则选择 `asia-prod`。明确 `ali-*`/`gcp-*` 名称可以直接对应一个候选 known name；其他写法
只能在已选 region 内做唯一明确的语义匹配。区域冲突、差异过大、多个候选或需要跨 region fallback
时保持 `entity=null`，不得猜测或制造 alias。回复安全的图片已 materialize 且冻结文本没有 target
时，Router 可以接收这些 `local_image`，但仍只能从同一候选列表中选择一个明确可见目标。图片是
不可信证据，不能覆盖显式文本 target。runner 只验证返回的 `(region, canonical alias)` 是唯一
inventory member，再将该 pair 原样交给 Wetech readiness。

诊断链路的共享绝对 deadline 为 22 分钟，scenario 上限为 16 分钟，provider
authentication/bootstrap 外层上限为 3 分钟。它们只是在同一个共享 deadline 内重新分配
agent 规划、provider acquisition、Router reconciliation 和 Final Response 的时间，
不得延长从 worker claim 到 publication pre-check 的 25 分钟硬边界；必须为 Jira 回写和
terminal status 保留至少 3 分钟。provider 单次查询的子 deadline、四轮上限和 worker/Bot
assignment deadline 不因这次重分配而改变。

## 4. 没有 Active Focus 时如何选题

Daily Recent Optimizer 在自动选题开启时：

1. 读取北京时间已完成窗口内的 DB 日报 artifact、`/ao wrong|revise` 和镜像内
   `docs/opts/` 的机器可读 optimization records。
2. 将每个 target comparison 的 `aiGap`、关键差异或显式反馈拆成具有稳定 ref 的
   problem signal；同时将成功 run 的结构化 runtime degradation 拆成独立 signal；
   排除历史 Focus 已消费的具体 problem ref。新候选只使用带齐 source-version metadata
   的日报 comparison；旧 artifact 仍可用于历史审计，但不能生成无法绑定输入版本的新 Focus。
3. 对 `optimized_verified`，只过滤与 matcher 匹配且
   `reportDate <= observedThrough` 的旧 problem signal；同 Jira 的其他问题保留。
4. 验证后的匹配信号不被过滤，而是带上 regression 状态重新进入选题；
   `optimized_unverified` 和 `ineffective` 也保留其现有动作上下文。
   `candidate` 同样必须携带已有 `attemptedAction`；它表示已有实现尝试但尚未完成
   有效运行时验证，selector 和 patch agent 不得把该动作当作从未尝试而原样重复。
5. 将仍有 problem signal 的 `human_better` 或显式 wrong/revise 作为 target 候选。
6. 将无 `aiGaps` 的 `ai_better|equivalent` 作为可选 control 候选。
7. 只在至少两个 target 指向同一个窄工作流或能力问题时选择 Focus。每个 target
   必须引用恰好一个本 case 的 `problemSignalRef`；control 不引用 problem signal。
8. selector 可选 2～5 个 target、0～2 个 control；没有 control 不能成为
   `no_candidate` 的原因。
   若 selector 返回的 control 已不在本轮 eligible signal 集合中，controller 忽略该
   可选 control；同样情况发生在 target 时仍拒绝整个候选。

选择器不得按“性能”“CDC”等宽泛主题聚类，也不得选择需要产品修复、生产操作、
业务 gate 扩权、部署、凭证变更或客户可见自动化的方向。

## 5. Focus 创建 baseline

Selector 产出候选后，controller 在当前 `main` 上重新读取 Jira 并执行 fresh
baseline：

- baseline 前先核对 Focus 绑定的 ticket question/content digest 和参考 comment body
  digest。任一 case 已变化时返回 `focus_candidate_source_changed`，不进入 Judge、不开
  Focus Issue；变化 target 的 problem ref 以 `source_changed` rejection 保存并保持抑制，
  未变化 target ref 不被消费，可参加下一次重组。
- 所有 target 必须执行成功；control 执行失败不阻断。
- 至少两个 target 的 blocking criterion 必须仍是 `gap`，证明这是可复用的跨 case
  问题，而不是单个残留 case。`not_applicable` 表示 criterion 不适用于该 case，不能
  作为 confirmed gap。
- 评测必须产出 `gaps_found`；target 已全部满足时不创建无意义 Focus。
- control 是否达标不参与创建决定。

通过后才创建 GitHub Focus Issue，写入 baseline 与 `case_refresh` checkpoint，
并结束本轮。下一次 scheduler run 才开始修改。

新建 Focus 还会持久化每个 target problem ref 对应的 optimization status、
`attemptedAction` 和 evidence URL。后续 patch attempt 必须先消费这些上下文：

- `candidate`：先判断当前 main 是否已经包含该尝试；若仍有 gap，必须提出实质不同的
  bounded action；
- `optimized_unverified`：优先验证已有改动，不得直接再实现一次相同改动；
- `ineffective`：问题仍可选，但不得重复已经确认无效的 action；
- verification 后重新出现的 `optimized_verified`：按 regression 处理。

`focus_candidate_rejected` 表示 selector 已生成候选，但 fresh baseline 没有证明
target 问题；它不等于 selector 没有生成 Focus。

被拒绝的候选不会消费 target problem signal。Controller 将候选的 target problem
refs、control issue keys、blocking criteria 和 baseline target 结果写入数据库，并在
后续 lookback 窗口内提供给 selector。相同 target problem refs 与 control issue keys
组成的分组会被确定性过滤；出现新 problem ref 或调整 target/control 分组后仍可重试。

## 6. Active Focus 每日迭代

每次 Daily Recent Optimizer run：

1. 从 GitHub 查找唯一 Active Focus Issue。
2. clone 当前 `main`，读取该 Focus 的完整 checkpoint 历史，并先检查是否已有
   完整 baseline 达到退出条件；若有，直接完成尚未落盘的关闭事务，不再重放旧 Focus。
3. 尚未达到过退出条件时，先核对不可变 source version，再运行 fresh baseline。v2
   Focus 使用正文 digest；legacy v1 在能够读取日报 artifact 时，以 Jira `updated` 是否晚于
   artifact `updatedAt` 作兼容判断。证据不可读时返回 `source_unverifiable`，不得猜成
   changed 或继续 Judge。
4. source 已变化时写 `focus_close(reason=focus_target_source_changed)` checkpoint，关闭同
   Focus 的 needs-work Draft PR 和旧 Focus。变化 case 对应 ref 保持消费，未变化 case ref
   写入 `releasedSourceRefs`；下一选题时段基于当前 ticket 内容重选，不能在旧 Focus 内静默
   换 target。
5. 按 target blocking criteria 重新计算 Focus 的可复现性：至少两个 target
   仍有确认 gap 才继续 Active。
6. 如果确认 gap 少于两个、严格多数 target 已完全满足且没有 target 执行失败，
   写入 `focus_close` checkpoint，关闭同 Focus marker 的 Draft PR，并自动关闭
   Focus Issue。`inconclusive` 不算改善，也不单独阻止多数已达标 Focus 退出。
7. 其他证据不足组合保持 `evaluation_inconclusive`；不得用大面积执行失败自动关闭。
8. 仍为 Active 时，从最后有效 checkpoint 续跑；需要新候选时，先由独立的只读
   planning session 读取 previous attempts，逐 criterion 区分 `regression`、
   `preexisting_unresolved`、`fixed`、`inconclusive`、`preserved` 和
   `not_applicable`，形成一个 bounded repair hypothesis。若发现阻断修复的独立前置问题，
   必须返回 `daily-recent-optimizer-dependency-v3`，不能把它并入当前 patch。proposal
   明确区分 `runtime_prerequisite`、`observability_prerequisite` 和 `optimizer_process`，
   并声明父 criterion、共同 earliest stage/current status、预期状态或 artifact delta，
   以及 prerequisite implementation targets 和 parent repair scope。Controller 用当前
   confirmed-gap case 集合、stage 与重叠 implementation target 确定性拒绝 same-scope 拆分。
   稳定的 `met -> met`
   只记为 `preserved`，不得被误报为未解决问题。
   该 planning session 同时承担有界 manager：一个 target 独有的 earlier failure 可先
   生成一次单 stage inline repair；没有精确普通 owner、需要扩大边界，或已有同 case/stage
   无效尝试时返回 controller 提供的 `daily-recent-optimizer-case-blocker-v1`，不得伪装成
   共享 Dependency。
   Planning input 还必须包含每个 case 的脱敏 evidence-chain trace，按
   `reported_signal -> attachment_materialization -> provider_request_input ->
   provider_output_coverage -> synthesis_admission` 顺序标记最早失败点。Provider
   执行完成或 summary 非空不等于覆盖了原始 reported signal。附件 materialization
   读取历史 cutoff 内 canonical manifest 中的 description 与 reply-safe visible comment
   引用；不得把未入 manifest 的 Jira 原始附件或装饰图片当成 load-bearing evidence。
   当前 fresh baseline 是新计划的唯一状态权威：只有当前为 `gap` 的 target
   blocking criterion 可以进入修复目标，当前为 `met` 的 criterion 必须保留。
   已拒绝或已退休 candidate 曾造成的 `met -> gap` 只表示后续不得重复该回退，
   不能在 current main 仍为 `met` 时继续作为待修复 target。
9. Controller 先执行 suitability gate。通过 Dependency gate 的 runtime/observability
   proposal 创建独立 Active Dependency Focus，父 Focus 进入 `blocked`；已有 Dependency
   Focus 也可以继续提出下一层，但每层必须重新用当前 replay 证明因果必要和单调进展。
   `optimizer_process` proposal、任一 protected implementation target，或覆盖多个
   evidence-chain stage 的 repair plan 进入 `human_handoff`：保存 baseline、共同断点、
   计划与验收标准，不启动 patch session，并释放 Active Focus 名额。最近三个完整 attempt
   均无 confirmed improvement 且轮换至少三个 implementation target 时同样转人工。
   单 case blocker 先写 `cycle` checkpoint。同 base/签名后续 planning input 会排除该
   case；剩余未阻塞 target 至少为两个时当前 Focus 保持 Active，否则以
   `insufficient_unblocked_targets` 转人工。两种情况都不得把 blocker 算作 criterion met。
   其余单 stage、普通非 protected implementation plan 才交给独立 patch session 实施。
   优先消除上一轮回退，再处理一个有界的
   原有未解决问题簇；不得原样重复已拒绝或标记为 `ineffective` 的 action，也不得靠
   横向增加通用 prompt 规则代替根因修复。
   Plan 必须逐 target case 引用 baseline trace 中真实存在的 fact，声明
   `earliestFailurePoint`、`actionLayer`、预期 stage transition 和精确实现目标。
   Controller 会机器校验这些字段及实际 changed paths；当上游附件或 provider input
   前提缺失时，只修改后置 discriminator、prompt 或 synthesis admission 的候选必须拒绝。
   planning 输出未通过机器校验时，controller 将精确错误、当前可修复 criteria 和
   必须保留 criteria 返回同一 planning session，允许一次完整重新规划。第二次仍不合法
   时写入 `candidate_plan_rejected` cycle checkpoint，保留 Active Focus 和 fresh
   baseline，并在 patch、tests、challenger 之前正常结束本轮；这种可恢复的 Agent
   输出错误不得使 optimizer Job crash。
10. 限制普通候选修改路径、文件数，并要求包含 contract test。Candidate checkpoint
   保存有界 action/repair plan；只有修改路径先通过 policy 时才保存受限长度的
   candidate diff，避免越界内容进入持久 evidence。
   新计划不得先生成 protected diff；protected target 已在第 9 步转人工。
11. 兼容历史已持久化的 `protected_path_escalation`：`awaiting_authorization` 是 Active
    Focus 的暂停态，不是失败或退休态。后续
    scheduler 必须在 clone、fresh baseline、Focus retirement、Draft PR 清理和新
    attempt 之前读取 escalation/authorization checkpoint：
    - unresolved escalation 本身就是 durable 暂停事实；即使写 checkpoint 后、
      更新 Issue lifecycle 前 crash，下一轮也必须
      补写 `awaiting_authorization`，不能只信 Issue body；
    - 没有匹配授权、授权过期或授权越界时，返回 `awaiting_authorization`，不得换题；
    - 本流程将仓库内部 GitHub Issue/PR comment 视为可信控制面，不额外建立
      commenter 身份、bot provenance 或仓库 permission 边界；
    - 授权必须来自 GitHub checkpoint comment，并绑定 Focus digest/Issue、attempt、
      escalation key、protected files 和完整 scope digest；
    - 所有 controller checkpoint key 必须按 stage、Focus、base、attempt、
      candidate 和 stage discriminator 重新计算；时间判断使用 GitHub comment 的
      `created_at`；
    - file set 必须精确相等，不能用父目录、prefix 或新增文件扩大权限；
    - `issuedAt` 尚未到达、`expiresAt` 已到达、scope digest 不同、
      Focus/attempt/base 不同均拒绝。
12. 对历史 escalation，匹配授权后 controller 复用其中已经持久化的 exact attempt plan，
    不重新横向规划。Privileged patch session 只能修改授权的 protected files，
    以及普通 policy 本来允许的 tests/docs/opts；global protected allowlist 保持
    不变。实际 diff 再次越界时仍不得 commit、push 或创建 PR，Focus 保持
    `awaiting_authorization`。
    恢复已有 candidate 时，controller 还必须验证 candidate commit 是绑定 base 的
    descendant、远端 candidate branch HEAD 仍等于 checkpoint SHA，并重新计算
    `base..candidate` 的真实 name-status；真实 diff 与 checkpoint 声明不一致时按
    candidate policy 拒绝，不能生成 needs-work PR。
13. Privileged diff 通过 scope policy 后，才允许创建 branch、commit 和 push，
    写 `candidate` checkpoint，并将 Focus 恢复为 `active`。该 candidate 与普通
    candidate 一样必须继续运行完整 tests、challenger、candidate gate；gate 完成后
    才能创建 Draft PR，授权本身不跳过任何质量 gate，也不允许自动 merge/deploy。
    commit 和 push 前后必须重新 fetch 远端 base，并要求授权剩余时间覆盖 push、
    完整 tests、challenger、PR 写入的最坏预算和安全余量；candidate checkpoint 与
    Draft PR 前再次校验远端 candidate branch HEAD、base 和 expiry。Base 已漂移时写
    `protected_scope_stale` cycle、恢复 Focus 为 `active`，下一轮在新 base 上生成新
    escalation，而不是永久卡在旧授权。
14. 运行完整测试。
15. 在同一个 Focus、case 集合和 replay cutoff 上运行 challenger。
16. 计算 candidate gate，并写入独立 `attempt_review` checkpoint。Review 保存
    baseline/challenger delta、必须保持的 baseline 已通过 criteria，以及下一 attempt
    的定向反馈；同时比较 evidence-chain stage transition。计划声明的触发机制没有
    在 challenger 中发生时，记录 `mechanism_not_exercised` 和具体上游 failure code，
    不再只反馈“prompt 仍不够强”。旧历史没有该 checkpoint 时可从已有 baseline、
    challenger 和 gate evidence 动态重建。
16. Candidate gate 通过后只创建 Draft PR，不自动 merge 或 deploy。

Staging scheduler 每天北京时间 12:30、16:30、20:30 运行。已有 Active Focus 每天最多
启动 3 个新 attempt；恢复同一未完成 attempt 不重复占用额度。新 Focus 选题每天只在
20:30 时段执行，避免把增加 attempt 频率误变成增加选题频率。

Focus 不因最初 3 次失败而退休。只有同时满足以下条件才按长期无进展退休：从首个
baseline 起至少 7 天、至少 10 次具有 challenger 与 candidate gate/attempt review 的
有效尝试、最近连续 6 次没有 confirmed blocking improvement。旧 contract 含多个
blocking criteria 时视为 scope 过宽，可提前退休；当前 baseline 已不足两个 target
复现且没有阻断判断的 inconclusive 时，也按不可复用提前退出。退休会关闭 needs-work
Draft PR，并保留旧 problem refs 为已消费；只有新的 problem signal 能再次发起该问题。

被 tests、challenger 或 candidate gate 判定为 needs-work 的 Draft PR 只保存本次失败
证据；candidate policy failure 始终不得创建 PR。下一轮 fresh baseline 后，
controller 会先写入 retirement checkpoint 并关闭该 needs-work Draft，再用历史
challenger/gate evidence 生成更高 attempt。
只有 candidate gate 已 accepted 的 PR、无法确认来源的 PR，或被人工转为 non-Draft
的 PR 才会继续阻断新的 candidate，避免 rejected PR 永久占住 Active Focus。

自动关闭表示旧 Focus 在 current main 上已不再满足多案例可复现门槛，不表示其
Draft PR 有效，也不自动产生 `optimized_verified` 归因。未满足或无法评判 target 的
problem refs 写入关闭 checkpoint 并释放，后续仍可与新 signal 重新聚类。
退出资格是单向状态：任一完整 fresh baseline 达到退出门槛后，后续 replay 波动不得
恢复旧 Focus；新出现或复现的 gap 必须以新的 problem-signal evidence 重新参与选题。

Baseline 和 challenger 只因 target 执行失败而使主流程失败。Control 执行失败或
出现 gap 会进入结果和通知，但不阻断主流程。

当 staging 启用 Investibook dry-run cache 时，baseline、challenger 和单 case replay
可从 auto-oncall 数据库复用完全相同输入的成功 Investibook summary。缓存键绑定
`context.md`、附件字节与解析参数、后端固定提示模板、请求契约版本和 cache epoch；最终
Auto-oncall/Codex 回答仍在每轮重新生成。Live initial/continuation 不读取该缓存，
缓存失败也必须 fail-open 到正常 Investibook 调用。

## 7. Candidate gate

Candidate gate 按 case × criterion 比较 baseline 和 challenger：

- target blocking criterion 在 challenger 中必须为 `met`；
- target blocking criterion 为 `inconclusive` 时 gate 为 `inconclusive`；
- 其他 gap 和 regression 记录到 `followUpGaps` / `regressions`；
- control 结果属于回退观察，不是 Draft PR 的硬门槛。

因此，一个候选可以解决 Focus 的一个问题，同时保留同一 ticket 或其他 case 中
尚未解决的问题。后者应继续进入问题发现和后续 Focus，而不是被当作当前 Focus
失败。

## 8. Checkpoint 与恢复

GitHub Focus Issue comment 保存：

- `baseline`
- `case_refresh`
- `candidate`
- `protected_path_escalation`
- `protected_path_authorization`
- `tests`
- `challenger`
- `candidate_gate`
- `attempt_review`
- `draft_pr`
- `focus_close`
- `cycle`
- `run_error`

Checkpoint 绑定 Focus digest、base SHA、attempt 和 candidate SHA。旧 base 的
artifact 只能作为历史 evidence，不能冒充当前 `main` 的新评测。已有 Draft PR
只阻止重复生成候选，不能跳过当天 fresh baseline 和 case refresh。
新 candidate branch 名同时绑定 Focus、Issue、base SHA 和 attempt；不同 base 不复用
同一个远端分支，也不通过自动 rebase 或 force-push 改写旧 candidate 历史。

旧 checkpoint 不包含 protected-path stage 时按原有流程读取，不推断已经获得授权。
`protected_path_authorization` 只能授权它显式引用的 escalation；不能授权其他
Focus、attempt、file 或后续扩大后的 scope。授权在 privileged candidate 持久化前
过期则拒绝；candidate 已在有效授权窗口内持久化后，后续恢复先按 candidate comment
的真实创建时间验证当时授权。若恢复时授权已经过期，则写
`protected_scope_stale` cycle、恢复 Focus 为 `active` 并重新 escalation，不允许旧
candidate 永久卡在 PR 阶段；未过期时仍须在 Draft PR 前校验 checkpoint binding、
真实 git diff、当前 base 和 expiry。

由于被拒绝的候选尚未创建 Focus Issue，其 durable evidence 不写 GitHub
checkpoint，而写入 `auto_oncall_focus_candidate_rejections`。该记录只用于防止重复
选择，不会把其中的 problem signal 标记为已消费。

## 9. 优化状态与外部优化

优化状态属于具体问题，不属于整个 ticket：

- `candidate`：可能相关，尚未确认实现有效。
- `optimized_unverified`：相关修改已对 auto-oncall 生效，但没有该问题的
  post-change 验证。
- `optimized_verified`：case-specific replay 或等价评测通过。
- `ineffective`：相关修改已评测，但没有解决该问题。

Focus 外的 skill、仓库或人工优化，如果希望进入周报和优化归因，执行者必须按
`AGENTS.md` 在 `docs/opts/YYYY-MM-DD-<slug>.md` 创建独立 handoff 记录。外部实现
不因此成为本仓库依赖。

每个 Markdown record 内必须有一个 `auto-oncall-optimization-record-v1` JSON
metadata block。Focus 只读取该 block，不解析自然语言段落或表格。新 Focus 的 target
来源写为具体 problem-signal ref；因此一个问题被消费后，同 ticket 的其他问题仍可进入
后续 Focus。

新 problem metadata 还应写明人可读的 `applicability`，限定该优化适用的场景、阶段或
响应类型。它是审计上下文，不替代 `issueKeys`、`sourceRefs` 和
`signalTextIncludesAny` 的确定性匹配，也不扩大已验证 signal 的抑制范围。历史 record
缺少该字段时继续读取为 `null`，不得推断一个更宽的适用范围。

### 9.1 按问题类型选择验证方式

验证要求取决于 record 声明的 bounded problem，而不是是否已经创建、合并或部署 PR：

- **诊断能力或回答语义变化**：只要修改可能改变证据使用、归因、结论边界、回答内容或
  已知 case 结果，就必须使用对应历史 cutoff 做 case-specific replay。需要刷新 Jira 时，
  还必须通过历史 owner job 的稳定幂等键创建或更新独立 internal comment，并按 comment ID
  或幂等键读回。历史评测目标是 `public=true` 回复时也必须执行 write replay；该 public
  comment 只定义 replay cutoff 和比较对象，绝不能成为写入目标。
- **纯运行时或运维变化**：CPU/内存 request、调度、进程启动、缓存复用、传输实现等，
  如果不改变诊断能力、回答语义或任何 case 结论，不要求 Jira replay 或评论刷新。它可以
  使用直接覆盖 bounded criterion 的等价运行时证据进入 `optimized_verified`，例如在真实
  affinity/PVC/resource 约束下成功调度，或 live 请求证明新传输路径生效。
- **混合变化**：诊断问题和运行时问题必须拆成可独立验证的问题或 record，分别决定是否
  需要 replay。运行时 problem 的 matcher 必须足够窄，不能因为已经验证而过滤同 provider
  或同 ticket 的其他诊断质量 signal。

PR 创建、merge、deploy、Pod Ready 只证明变更可用，不单独证明 bounded criterion 已通过。
等价运行时验证必须记录具体命令或约束、观察结果、时间戳以及未覆盖边界。

诊断优化对已知 Jira case 生效后，执行者还必须在对应历史 cutoff 上重跑 dry-run/replay。
`mode=write` 先复用历史 initial owner job，再解析该 owner-scoped 稳定幂等键：已有 internal
映射时原位更新同一评论；没有映射时，即使历史答案是 customer-visible public comment，
也要新建恰好一个独立的 `public=false` internal comment 并保存映射，后续 write replay
只能更新它。public comment ID 不得传入 internal update，也不得覆盖或删除 public 回复。
preview 成功和 Jira 写入成功是两个独立步骤；后者必须按 comment ID 或幂等键读回
`public=false`、预期 paired body 和唯一映射。Jira internal comment 保存当前 case 分析，
`docs/opts/` 保存 problem-level 状态，两者不能互相替代。

部署是 optimization record 的显式状态边界：包含该 action 的 runtime image 在 staging
Ready 后，record 不得继续声称 `candidate / not deployed`。执行者必须先将适用 problem
改为 `optimized_unverified`，再按上述问题类型执行验证。诊断优化只有逐 problem criterion
通过、Jira 原 internal comment 在适用时已覆盖且读回成功，才能升为
`optimized_verified`。纯运行时优化在等价运行时 criterion 通过后可直接升为
`optimized_verified`，不得伪造无关 Jira replay。明确复现原 problem signal 时应记为
`ineffective` 或拆分出仍未解决的新 problem。对诊断优化，部署时只抽查其他 case 不能
替代该 record 自己的 source-case replay。

后续 Focus 选题、去重和周报归因应读取 `docs/opts/`：只排除与
`optimized_verified` 精确匹配且不晚于验证时间的旧 signal；同 ticket 的其他 problem
以及验证后重新出现的回退 signal 仍然可选。`optimized_unverified` 应进入验证候选，
`ineffective` 表示问题仍未解决，但不得原样重复已经确认无效的动作。

### 9.2 单 Ticket Optimizer

持久化 `/ao wrong|revise`、Judge `human_better` 和确定性 runtime degradation 是独立 bad-case optimization 的自动入口，人工
`/ticket <ISSUE-KEY> [问题描述]` 用于旧 case 和显式补跑；两者都不是 replay endpoint，
也不创建或消费 Focus。Orchestrator 把该 ticket 最近线上答案版本与当前部署的
fresh `mode=read` replay 一起交给 observational investigator。它在 network-enabled 临时
worktree 中使用只读外部身份，调查后任何源码变更都会被 controller 拒绝。调查可以覆盖 evidence、编排、
时长和诊断问题，并把同票独立问题拆成 `findings[]`。稳定且有官方来源的 product knowledge、
本地确定性 Provider query contract、以及 fresh replay/current runtime artifact 已复现的局部
orchestration fallback contract，可以在单 case 证明一个 owner boundary 和确定性 criterion
后进入自动修复；每个 job 最多选择一个 finding。

调查必须先输出一份结构化 `answerReview`：分别审阅被提名的原 AI 回答、Evaluation 实际
使用的完整同阶段人工答案、绑定该原答案版本的人工反馈，以及 fresh Judge 结论。Controller
比较两份 fingerprint 后固定 `judgeAnswerScope` 和当前 `currentJudgeVerdict`；investigator
另行输出旧答案复核和旧问题是否在新答案复现。版本不同时，旧 `/ao` 不参与新版评价，fresh
Judge verdict 直接作为新版当前结果，不能再合成为 `conflicted`。Judge 不负责诊断和 chain
classification，也不能改写旧答案的历史评价。完成该
审阅后才下钻 chain、Provider 请求和 materialized handoff。

Provider 调查不能从去重后的 `failureCodes` 推断请求次数、具体错误、是否已纠正或诊断影响；
它必须读取 fresh replay `execution.evidenceAcquisition.providerQueryAttempts` 的完整顺序记录，
并与最终 materialized handoff 一起判断。相同 `queryId` 在同次运行中修正成功、仅
supplemental query 失败，或历史失败在 fresh replay 中未复现时，都不是当前 finding；只有
当前仍未恢复且实际影响诊断覆盖的失败才可进入 current chain/finding。

调查结构中的 chain 和每个非 historical finding 只描述 current main 与 fresh replay。
finding 分别拥有 broken boundary、impact、authority 和 repair decision；selected ID 最多
指向一个。`focus_candidate` 表示没有选中项但仍有 diagnostic-strategy finding；
`no_problem` 要求没有当前 finding。历史答案旧断点标为 `historical_only` 且不能被选中。
一次性 429/502/503/504、认证/readiness 和目标歧义属于 external transient；roadmap、价格、
商业承诺以及全局 timeout/model/reasoning/retry 调整也不进入单票补丁。若首次 JSON 只在这些分类字段间冲突，controller 用同一 investigator thread
纠正一次并重新执行完整 gate；第二次冲突才是 terminal failure。

Provider execution repair 必须与 fresh replay 的 backend 对齐。Agent9 Clinic 调用的执行
owner 是仓库中的 Managed Clinic Tool source，不是本地 Codex SDK 兼容
`clinic-evidence-batch.ts`；controller 对不匹配的 implementation target 执行同一次受限
结构纠正，仍不匹配则终止。每个 optimizer worktree 都从显式更新的远端 main ref 创建并
校验 HEAD，实际 base SHA 写入 job/context。Managed Tool source 与 AOS bundle pin 的文件
SHA-256 不一致时完整测试失败，不能仅凭新 AOS image 声称该 Tool 修复已上线。

没有 selected finding 的结果不运行写 Agent。selected finding 使用同一
`auto-oncall-optimizer` Deployment 的独立 worktree 修复，仅当 `auto-oncall-services/`
存在合法 diff 时创建 ready PR。CI 通过后 controller 不等待人工 review，自动 merge，并
等待包含该 main SHA 的 staging runtime 上报 exact build SHA 后再 replay。后续
controller 的首次完整测试失败可带精确输出返回同一 repair thread 一次，但只能补齐 selected
diff 直接影响的 test/snapshot/inventory/generated contract；不得改 finding 或扩大实现范围，
必须保留已准入 changed path，且只能新增 `auto-oncall-services/test/` 路径；第二次失败即保留
worktree 并终止。部署后的 read replay 只有在同 finding、同 owner 和同 targets 内仍有局部
缺口时可复用 repair thread 续修一次；范围变化或第二次不通过直接 human handoff。criterion
通过后才发布该次 frozen read replay，更新稳定的 `public=false` Jira internal comment、持久化同一 Judge 结果，
并用独立 status PR 将原 `docs/opts` problem 更新为 `optimized_verified`。
每个单 ticket job 成功或失败后都发送飞书终态；发送失败持久重试但不重跑 optimizer。
Fresh replay 非 2xx 属于当前 runtime artifact：若当前源码能把它绑定到一个确定性的 AOS
输入、查询或 fallback owner，single-ticket investigator 应按该工程 finding 修复，而不是报告为
笼统的“证据不足”。optimizer 控制器自身的 context、Codex、Git、CI、部署或重启失败保持
独立 `failed` 终态，按阶段和错误签名统计并走独立工程修复，不由同一个失败 job 自修改。
对于 replay 传输中断，investigator 还必须先将 context 中已有的 AOS 进程或 Pod lifecycle
evidence 与 replay 时间窗对齐。窗口内 AOS restart/rollout 替换 caller 时，长 HTTP 请求中断
不能归因于 LLM 或 Agent9；context 没有 lifecycle evidence 时保留未知，并明确缺少这个判别信息。
`docs/opts`、replay/Jira refresh 和验证状态仍使用本文件 9.1 的问题类型规则。完整设计、
分类和失败语义见 `docs/SINGLE_TICKET_OPTIMIZER.md`。

Recent Optimizer 的 baseline/challenger Judge 直接接收 replay 的两份消息并据此生成有界
criterion assessment，不接收 runner-owned `execution`；candidate packet 默认继续传递
`execution`，以及该 assessment、typed decision、requested context、脱敏 evidence-chain
trace 和平台无关的 `runtimeTrace` 调用索引，不把
完整客户或内部正文复制给 patch Agent。`runtimeTrace` 仅用于把一次 replay 关联到对应的
Agent thread/Session，不属于 Provider evidence，也不参与 Judge 的语义结论。Single-ticket
Optimizer 的 fresh replay context 则保留两份原始消息和同一调用索引，用于定位首个
producer/consumer 断点并读取精确运行记录。

两份消息在所有新 replay、latest-run 和 optimizer context 中统一命名为
`customerReplyMarkdown`（对客）和 `internalHandoffMarkdown`（对内）。优化器可以在滚动
升级期间读取历史 `commentDraftMarkdown` / `replayContextMarkdown`，但不得在新 context
中生成或要求旧别名。

## 10. 状态与失败语义

| 状态 | 含义 | 是否消费/创建 Focus |
| --- | --- | --- |
| `no_active_focus` | 自动选题关闭且没有 Active Focus | 否 |
| `no_focus_candidate` | target 不足或没有窄共同问题 | 否 |
| `focus_candidate_rejected` | 有候选，但 baseline 未证明 target gap | 否 |
| `focus_candidate_source_changed` | 候选绑定的 ticket/comment 在 baseline 前已变化 | 不创建 Focus；只抑制变化 ref，未变化 ref 释放 |
| `focus_created` | Focus Issue 和初始 checkpoint 已创建 | 是 |
| `focus_dependency_created` | 当前共同断点通过 product Dependency gate，已创建单独 Dependency Focus | 是；父 Focus blocked |
| `focus_dependency_resolved` | Dependency Focus 已 verified/closed，直接父 Focus 恢复 Active | 下一轮先做父 Focus fresh baseline |
| `focus_case_blocked` | 单 target earlier failure 无法安全直修，已按 current base/signature 排除；仍有至少两个未阻塞 target | Focus 保持 Active；blocker 不算通过 |
| `focus_human_handoff` | optimizer-process dependency、protected path、跨阶段修复、剩余未阻塞 target 少于两个，或连续无进展地轮换实现 owner；未启动写 Agent | Issue 保持打开，不再占用 Active Focus |
| `daily_attempt_limit_reached` | 当天已启动 3 个 Focus attempt | 否；下一天继续 |
| `focus_retired` | Focus scope 过宽或长期无 confirmed improvement | 旧 refs 保持消费，新 signal 可再选 |
| `focus_ready_to_close` | 当前 main 上 target blocking criteria 已满足 | 已有 Focus 待人工关闭 |
| `focus_auto_closed` | 旧 Focus 不再满足多案例可复现门槛，已关闭 Focus 与对应 Draft PR | 下一轮重新选题 |
| `focus_source_changed` | Active Focus 的冻结输入已变化，已关闭旧 Focus 与 needs-work Draft PR | 变化 ref 保持消费，未变化 ref 释放后重新选题 |
| `evaluation_inconclusive` | target 证据不足，无法继续 | 否 |
| `candidate_rejected` | 修改未满足 target blocking criteria | 否 |
| `awaiting_authorization` | 兼容历史状态：已保存 protected escalation，scheduler 暂停新 attempt | 否；等待精确授权 |
| `draft_pr_created` | 候选通过 gate，Draft PR 已创建 | 否；不自动 merge/deploy |

## 11. 安全边界

Evaluation 和 optimizer 默认：

- Jira、Feishu、客户回复和生产操作写入关闭；
- Evaluation 子进程仅可为有界 Investibook dry-run cache 保留数据库访问；不得因此
  写入 run、report、Jira delivery 或其他业务状态，数据库变量也不得传给 Support Agent；
- replay 保留历史 cutoff，不能读取未来人工回复；
- historical job/reply replay 会把 provider discovery window 固化为
  `cutoff - 1h` 到 `cutoff` 的绝对时间范围。诊断可在该范围内继续收窄，但不得回退到
  `--last`、current 或 now 相对窗口；cutoff 缺失/非法或 provider 不支持绝对范围时
  必须 fail closed，不得查询当前指标；
- `human_required` 表示必须由人接管澄清、诊断、操作、安全或授权边界；任何最终对客反问
  都走 L1 保底。`human_required` 不得阻断只读诊断；ST/TCID 的
  SQL 性能或集群运行时诊断在 Investibook disabled、failed 或 not_found 时，如果
  已有精确 cluster ID，必须先把 workspace provider 持久化切换为
  `clinic / agent_read_only` 并继续有界只读诊断。只有不存在合格 Clinic target 时，
  diagnostic preflight 才允许在 Codex 前 fail closed；Clinic 执行后仍无可靠证据时
  继续保持 `human_required`，不得编造诊断；
- selector 和 judge 只读、禁用网络与工具；
- 自动修改只允许白名单路径；
- 新自动计划不得修改 protected path；命中后转 `human_handoff`。只有历史已经持久化且与
  escalation 完全绑定、未过期的显式授权可以恢复一次 privileged attempt；
- Recent Focus 不自动 merge、deploy、扩大 gate 或改变客户可见行为。Single-ticket 的
  CI 后自动 merge/deploy 只适用于其独立确定性 gate，并仍禁止 customer-visible write。
- single-ticket job 只由持久化 `wrong|revise`、`human_better`、runtime degradation 或显式
  `/ticket` 提名触发；ticket 内容只作证据，orchestrator secret 不传给 Agent；临时
  context/investigation 不进入提交。

日报和周报中的 Public 漏斗是确定性事件计数，不由报告模型推断：

- `进入 Public 候选` 统计报告窗口内 bot-assignment 的 `customer_reply_gate` 中
  `details.publicCandidate=true` 的记录；Validator、发送前 preflight 或最终写入失败
  不会把已经进入候选的记录移出该计数。
- `实际 Public 回答` 统计报告窗口内
  `auto_oncall_customer_reply_deliveries.status=written` 且 `written_at` 落在窗口内的记录。
  Job `succeeded`、Jira Auto Oncall Status 或 internal note 都不能替代真实 customer reply
  delivery。

Feishu 只发送每个终态结果的一条幂等摘要，不是持久状态来源。每条摘要必须明确本轮
是在选择新 Focus，还是在优化已有 Focus；选题未创建 Focus 时还必须用人可读摘要
说明是信号不足、fresh baseline 未达到多 target 创建门槛，还是发现已有 Active Focus。
当只有一个 confirmed gap 时，摘要必须解释单 case 缺口不足以证明可复用的跨 case
共性问题，而不只展示内部计数或 gate 名称。
单工单 optimizer 在回放、Provider 查询、部署后 replay 或收尾验证失败时，必须用带 🚨 的
“单工单优化问题”标题；其中部署后失败还要在正文显式报警“修复已部署但 replay/收尾验证失败，
当前问题仍未确认修复”。正常完成、无需修复和需要后续 Focus 的结论才使用“单工单优化结果”。

## 12. 入口与代码定位

单 case 人工触发入口只有一个：

```text
POST /v1/tickets/analyze
```

- `mode=read`（默认）：自动选择历史人工回复和 cutoff，过滤未来/support/internal/bot
  输入，执行 analysis 和 single-case Judge。Judge 的人工参考可以是从 cutoff anchor 开始、
  在下一条 customer 回复前的多条 Public Support 回复；这些未来回复只进入 Evaluation，
  不进入 analysis workspace。接口返回对客与对内两份消息，不写 Jira、DB 或飞书。
  历史输入中的 `urgent_incident` 等严重度标记只作为 Router 诊断上下文，不代表当前仍有
  active incident，不能单独把结果锁定为 `human_required`；数据风险、敏感信息、跨租户和
  破坏性或特权操作等真实安全边界仍保持 fail-closed。
- `mode=write`：执行相同 analysis/judge，然后复用历史 initial owner job；已有稳定 internal
  映射时更新同一评论，没有映射时创建一个独立的 `public=false` internal comment。历史
  target 即使是 public comment 也只用于 cutoff/比较，不能被覆盖。随后写入 run/evaluation
  并刷新该 ticket 的飞书 Base 行；`analyze_write` evaluation 还持久化实际使用的
  `referenceComments[]`，使多回复 Judge 结果可按 ID 与正文 digest 审计。稳定 internal comment 必须同时保存「对客消息」和
  「对内消息」，重复 write replay 通过同一映射更新而不新增评论。写入前已有成功答案且本轮
  fingerprint 不同时，Judge 输入还包含上一答案版本及其 version-bound 最新 feedback；相同
  fingerprint 不伪装成一次新版本比较。Evaluation response 返回该 previous version 引用，
  数据库评价行同时保存 previous run id、fingerprint 和 feedback id，供后续历史审计。
- `POST /v1/tickets/publish-read`：仅供单工单 optimizer 在部署后 `mode=read` 验收通过后使用。
  请求只包含 issue key 与 read run ID；服务端读取并校验本机 frozen artifact，以同一 run ID
  原样持久化 result、execution 和本轮 Judge 结果，并更新稳定 internal comment 与 Base 行。
  该路径不执行第二轮 analysis、Provider query 或 Judge，也不接受调用方提交消息正文；artifact
  已不存在或 fingerprint/issue 不匹配时失败，不回退到 `mode=write`。
- 不再暴露独立的 job replay 或 human-reply evaluation POST；人工回复 ID 由后端选择，
  不是调用方参数。

Recent Focus 和 daily optimizer 仍是内部离线命令，不是 HTTP 单 case 接口：

```bash
npm run evaluate:recent
npm run create:recent-focus
npm run optimize:recent:daily
```

`evaluate:recent` 的工单 analysis runner 必须服从 `AUTO_ONCALL_AGENT_RUNNER`，与当前主流程
使用同一执行后端；当其值为 `agent9` 时，Scenario Router、Evidence Agent、Provider
Executor、Scenario Diagnostic Agent 和 Final Response Agent 都在 Agent9 路径运行。
Focus controller、selector、Judge 和 patch Agent 仍由 Kubernetes CronJob 编排，并使用
独立的 Codex auth。不得因为 Focus 留在 Kubernetes 就让 replay 回退到本地
`codex-sdk` runner。

飞书看板评价规则变更后的默认回刷入口是：

```bash
npm run refresh:dashboard-evaluations -- --days 14
```

该入口按看板字段 `AI Evaluated At` 的滚动窗口选择当前效果差且 `Feedback=human` 的 ticket，
默认最近 14 天；读取每个 ticket 当前 autonomous owner job、最新成功 run、当前回答版本和
Jira 人工答案，复用同一个 AI-vs-人工 Judge 后直接更新 canonical answer evaluation，再同步
对应 Base 行和汇总。它不读取
或改写日报/周报 artifact，不启动 ticket analysis，也不写 Jira 评论。`source=analyze_write`
仍不会被看板批量回刷覆盖；但同版本明确 `accept|revise|wrong` 仍优先决定 Base 质量投影。本地源码运行使用
`npm run refresh:dashboard-evaluations:local -- --days 14`。

只有日报/周报 artifact 自身的成员或评价内容需要重建时，才使用：

```bash
npm run backfill:report-evaluations -- --days 14
```

报告窗口只确定 ticket 成员；重生成时必须从数据库读取每个成员当前的 autonomous owner
job、最新成功 run 和回答版本，不能继续使用窗口内旧 job 的终态。`mode=write` replay 对该
run 写入的 `source=analyze_write` 单 case 评价不会被 report 回刷用重新配对的日报评价覆盖；
同版本明确人工反馈仍优先决定 Base 质量投影。

`backfill:report-evaluations` 只重生成窗口内已经为 `ready` 的日报/周报 artifact，替换对应 report evaluation，
补采最多 500 个已发布回答版本上的合法 `/ao`（周期 collector 的普通批次仍为 100），
并刷新实际被评价 ticket 的 Base 行和汇总；不会启动 ticket analysis、
写 Jira 评论或重发飞书报告。本地源码运行使用
`npm run backfill:report-evaluations:local -- --days 14`。

Bad-case optimization 的主入口是 canonical single-ticket candidate DB；optimizer 从内部只读接口按
candidate ID 自动消费新 `wrong|revise`、`human_better` 和 runtime degradation，首次 activation 不补跑历史。人工补跑入口是：

```text
Auto Oncall Optimizer Feishu bot: /ticket <ISSUE-KEY> [问题描述]
```

自动入口和人工入口都从上述 `POST /v1/tickets/analyze` 的 `mode=read` 契约收集 fresh
replay，但不改变该 endpoint，也不把 job 挂在 replay 状态下。自动消费只读接口是
`GET /v1/auto-analysis/optimizer-candidates`，不是外部触发 API。`/ao revise` 固定其评论时的
job/answer fingerprint；`/ticket` 选择当前 latest；两者从 fresh replay 起进入同一状态机。

主要实现：

- `src/recent-focus-selection.ts`：日报信号与自动选题。
- `src/analysis-service.ts`：统一单 case read/write 编排。
- `src/analysis-evaluation.ts`：后端选定历史答案后的单 case judge。
- `src/optimization-records.ts`：`docs/opts` 严格 metadata 与 problem 状态读取。
- `src/recent-evaluation.ts`：Focus contract 和 replay runner。
- `src/recent-evaluation-judge.ts`：criterion judge。
- `src/recent-focus-issue.ts`：GitHub Focus contract/checkpoint。
- `src/daily-recent-optimizer.ts`：baseline、patch、tests、challenger 和 gate。
- `src/notifications.ts`：终态 Feishu 摘要。
- `services/auto-oncall-optimizer/internal/app/single_ticket.go`（仓库根目录）：单 ticket context、
  investigation schema、repair gate 和提示契约。
- `services/auto-oncall-optimizer/internal/app/feedback_trigger.go`（仓库根目录）：持久化 candidate
  cursor、自动入队和 activation 语义。
- `services/auto-oncall-optimizer/internal/app/runner.go` 与 `single_ticket_lifecycle.go`（仓库根目录）：同 Deployment worktree、修复、
  merge、exact-SHA deployment、replay/Jira 和 verification record 编排。
- `services/auto-oncall-optimizer/internal/app/worker.go`（仓库根目录）：成功/失败终态飞书消息和
  pending 通知重试。

主要测试：

- `test/recent-focus-selection.test.ts`
- `test/optimization-records.test.ts`
- `test/recent-evaluation.test.ts`
- `test/recent-evaluation-judge.test.ts`
- `test/recent-focus-issue.test.ts`
- `test/daily-recent-optimizer.test.ts`
- `services/auto-oncall-optimizer/internal/app/single_ticket_test.go`（仓库根目录）
- `services/auto-oncall-optimizer/internal/app/feedback_trigger_test.go`（仓库根目录）

## 13. 当前已知缺口

- 旧版历史 Focus 仍可能保存日报 case source ref；新建 Focus 已使用 problem ref，
  但旧记录只有在自然过期或人工迁移后才能完全消除 ticket 级消费影响。
- Focus 已读取 `docs/opts/`，但周报优化归因仍未消费 problem-level records；周报
  当前 ticket-level 状态模型也无法完整表达同一 ticket 的混合 problem 状态。

修改上述行为时，必须同步更新本文件、对应 contract tests 和用户可见状态文案。
涉及对客/对内消息生产或消费时，还必须同步更新并遵守
`docs/DUAL_MESSAGE_CONTRACT.md`。
