Skip to content

feat(automation): add durable monitoring and structured diagnostics - #115

Merged
Qiyuanqiii merged 5 commits into
mainfrom
codex/issue-105-scheduled-diagnostics
Aug 20, 2026
Merged

Qiyuanqiii merged 5 commits into
mainfrom
codex/issue-105-scheduled-diagnostics

Conversation

@Qiyuanqiii

@Qiyuanqiii Qiyuanqiii commented Aug 20, 2026 •

Copy link
Copy Markdown
Member

摘要

  • 新增严格版本化的 scheduled-job.v1:支持一次性/周期计划、IANA 时区元数据、稳定 UTC occurrence、deadline、停止条件、轮次/模型/elapsed 预算、retry/backoff、misfire、通知与显式 Run owner。
  • 新增 durable scheduler 与恢复语义:进程内固定并发 1,跨进程通过 SQLite transaction、lease generation、随机 fence token、稳定 occurrence operation key 与 CAS 实现单一权威轮次;重启会 reconcile 过期 claim,sleep/wake 可按 run_once|skip 收敛。
  • 新增默认只读的 loop-monitor 数据面。无新证据时不调用模型;approved_repair 只有在精确 Code/Deliver、operator-confirmed permission snapshot 和逐 Job 确认同时成立时才可进入 executor handoff。当前生产 wiring 不安装 repair/model executor,缺失 adapter 时明确 fail closed。
  • 新增结构化 doctor-snapshot.v1、debug-query.v1 与 diagnostic-bundle.v1:提供 readiness 原因、Run/Provider/Harness/Workspace/Sandbox/Browser/Network/Tool 投影、跨组件 correlation、单调时间线、cursor、时间窗、扫描/返回上限和字段级脱敏;原始 event payload、Prompt、终端输入与命令输入不可查询。
  • 打通 CLI、认证 HTTP/OpenAPI、Desktop control plane 和 React Scheduled Tasks:创建/查看/暂停/恢复/取消计划任务、worker health、next wake、最近 round/notification、doctor/debug 与诊断包下载使用同一协议和失败语义。
  • 修复超过 100 条事件时的 observation 水位尾窗:cursor 只推进到本轮实际读取的最后 envelope,第 101..latest 条留给下一权威轮次;单纯截断不再被视作新证据,也不会误耗模型预算。
  • 已同步最新 main be5e481(PR feat(ui-evidence): add source-bound real-browser verification #113 UI Evidence 与 PR feat(extensions): MCP Client、Plugin 包与受限生命周期 Hooks #114 Extension Runtime),冲突已全部解决;最终 schema 分配为 v119 UI Evidence、v120 MCP Client、v121 Plugin/Hook、v122 Scheduled Diagnostics。

Closes #105.

Durable Job 协议与状态语义

scheduled-job.v1 的 immutable spec 绑定:

  • 精确 owner Run、root Agent 与 target Run;V1 不允许跨 Run target;
  • once|periodic、IANA timezone、UTC anchor、interval 和 run_once|skip misfire policy;
  • deadline、stop_on_target_terminal、最大轮次、最大模型调用和最大 elapsed;
  • 有界 retry attempts、指数 backoff、all|failures|silent notification;
  • read_only|approved_repair execution mode。

Job 状态固定为 active|paused|completed|failed|cancelled|exhausted。每次 mutation 都要求 scheduled-job-control.v1、显式 idempotency key、request fingerprint、Run owner、expected revision 和 requester;相同 key/相同意图返回原结果,不同意图复用 key 冲突。pause/resume/cancel 通过 revision CAS,不能静默覆盖并发控制操作。

Schema v122 新增:

  • scheduled_jobs:spec、next wake、pending occurrence、预算、水位、最后结果、terminal reason 与公开 lease projection;
  • scheduled_job_authorizations:逐 Job、不可变、带 snapshot ID/revision 和 expiry 的 repair 授权;
  • scheduled_job_operations:不可变幂等控制账本;
  • scheduled_job_rounds:以 (job_id, occurrence_at) 为身份的 attempt/generation/fence/结果账本;
  • scheduled_job_notifications:按稳定 dedup digest 去重的有界通知。

authorization、operation、notification 使用 immutable trigger;FK、CHECK、digest、UTF-8/identity/时间/状态不变量在 domain、store 和 schema 多层校验。

Scheduler、lease、恢复与水位

Worker 默认关闭,只有显式 --enable-scheduled-job-worker 才启动;API/Desktop 还要求 scheduled control capability 与独立 control token。worker process-local 并发固定为 1,跨进程权威由 store transaction 决定:

  1. reconcile deadline、预算、terminal target 和过期 lease;
  2. 在 immediate transaction 内选择最早 due Job;
  3. 原子建立 occurrence、attempt、单调 generation、owner/fence digest 和 30 秒 lease;
  4. 读取目标 Run 的 bounded event-envelope metadata;
  5. 只允许当前 generation/fence 在 lease 内提交 completion/failure;
  6. 过期 worker 的 SQLite 写回被拒绝,replacement generation 按 retry policy 恢复。

周期身份由 immutable UTC anchor + elapsed seconds 推导,DST gap/fold 不会复制或删除 occurrence。长时间 sleep 后,run_once 收敛为一个 catch-up round,skip 记录明确 skipped round,不会无界 replay。

观察每轮最多读取 100 个 envelope。最终实现保证:

  • durable cursor 只推进到本轮实际读取的最后 sequence;
  • truncated=true 保留 overflow 事实,但未读 tail 不会被永久跳过;
  • executor 运行期间追加的事件不会被 completion 的后读水位覆盖;
  • 只有首次 observation 或本页存在非 scheduled_job.* 新证据才算 changed,单纯截断/自身审计事件不消耗模型。

权限与安全边界

时间到达只授予“尝试 claim 并重新检查”的权利,不授予 execution、network、approval 或 capability bypass。

read_only loop-monitor 要求当前 Plan phase;任何 tool fact 都会被拒绝,且 tool_called=true 必须同时有 model handoff。approved_repair 创建时必须满足:

  • 当前 mode 为精确 Code/Deliver;
  • execution permission 为 approval|full_access 且 operator_confirmed=true;
  • 请求持有独立 control authority 并显式 confirm_repair=true;
  • authorization 精确绑定 Job/Run、mode snapshot ID/revision、permission snapshot ID/revision、requester 和 expiry;
  • execution_bypass=false、network_bypass=false、approval_bypass=false。

Store 在 claim transaction 中重读 mode/permission;Application 在 executor handoff 前再次重读并逐字段比较。后续真实命令/修复 sink 仍必须复用普通 command/Job lifecycle 的 policy、approval、lease、operation-key 和 cancellation 门禁。本 PR 不实现任意 cron shell,也不因“监控”自动提权。

HTTP read bearer 与 control bearer 严格分离且启动时必须不同。scheduled mutation 使用 control bearer、POST、严格 JSON、bounded body、重复 key 拒绝、unknown field 拒绝、Run URL ownership 与 idempotency key;GET 使用 read bearer。listener 继续只允许 loopback。

结构化 doctor/debug/Bundle

doctor-snapshot.v1 是只读快照,不主动修改配置、安装依赖、放宽权限或执行网络/进程探测。它提供 build/schema、Provider/model route、Harness readiness、Run/Mission/profile、Workspace/root、surface/phase/permission、network mode/allow-target count、sandbox/browser/plugin/tool readiness 与明确 detail code/evidence level。

debug-query.v1:

  • 单次最多返回 100 条、最多扫描 500 条;
  • 时间窗最多 7 天,支持 after_sequence cursor;
  • 支持 Run/attempt/tool/process/request correlation 与 type/source prefix;
  • 将事件分类为 model/tool/policy/application/infrastructure;
  • 对乱序 wall-clock timestamp 生成单调 observed_at 并标记 adjustment;
  • 只读取 event envelope,payload 固定为 withheld。

公开 Type/Source/Subject ID 在输出前经过 UTF-8、长度、NUL/control-character 检查和 Secret redaction。Prompt、模型内容、Provider 原始错误、Tool 参数/输出、终端输入、命令输入、credential、fence token 和 operation fingerprint 均不进入公开 timeline 或 bundle。

CLI、HTTP、Desktop 与 Skill

CLI 新增:

cyberagent doctor [--run <id>] [--bundle] ...
cyberagent debug --run <id> [cursor/time/correlation/filter flags]
cyberagent run schedule create|list|show|pause|resume|cancel|tick ...

HTTP/OpenAPI 新增:

GET  /api/v1/scheduled-jobs
GET  /api/v1/scheduled-jobs/{job_id}
GET  /api/v1/runs/{run_id}/scheduled-jobs
POST /api/v1/runs/{run_id}/scheduled-jobs
POST /api/v1/runs/{run_id}/scheduled-jobs/{job_id}/pause|resume|cancel
GET  /api/v1/doctor
GET  /api/v1/debug
GET  /api/v1/diagnostic-bundle

Desktop control plane 负责 worker start/cancel/wait/store-close 顺序,并向 renderer 投影精确 capability 与 worker health。React Scheduled Tasks 支持 read-only 创建、列表/详情、revision-bound pause/resume/cancel、recent round/notification、next wake 与显式诊断包下载;客户端 capability 只影响 UI,server-side authorization 始终权威。

内置 doctor、debug 升级到 1.1.0;新增 loop-monitor@1.0.0,保持 root、explicit-only、non-model-invocable、无隐式 tool dependency。README 中英文、usage、HTTP API、独立 scheduled-jobs/diagnostics 指南、Project Status 和 ADR 0121 同步描述保证、失败语义与残余边界。

主线兼容性与冲突处理

最终 head 898f37b 已包含最新 main be5e481:

第一次同步 PR #113 解决 14 个冲突;第二次同步 PR #114 解决 9 个冲突,重点覆盖迁移版本、README ledger、OpenAPI 和 TypeScript parser/type 并集。两次均从合并后的 Go schema 重新生成 OpenAPI/TS,没有覆盖或降级 UI Evidence、MCP、Plugin/Hook 或 Scheduled Diagnostics。

最终 OpenAPI 为 139 paths / 155 operations / 389 schemas:

  • OpenAPI SHA-256:e3621910dc3bf1b6bc6f18b40fd413603e6b32d246170a4731eca0762bcacaef
  • TypeScript binding SHA-256:762d6431b16f6a8e05cee451327c1fe40df8881e96551ef7455cb9d1beb67c3e

验收条件对应

  • once/periodic、UTC occurrence、IANA timezone/DST、restart catch-up、sleep/wake、misfire 和 duplicate lease 的单一权威 round 语义已实现并测试。
  • deadline、最大轮次、target terminal、elapsed/model budget、retry exhaustion 和用户 cancel 都能 durable 终止并记录 stop reason。
  • loop-monitor 默认 Plan/Root/read-only;repair authorization 逐 Job 绑定并在重启后的 claim 与 handoff 重新核验,时间到达不授予新 authority。
  • doctor 返回版本化结构化快照和 actionable readiness reason,不修改系统。
  • debug 按 correlation 生成跨 model/tool/policy/process/app/infrastructure 的有界单调时间线。
  • cursor、7 天窗口、100 return/500 scan、metadata source、字段级脱敏和 payload withholding 已实现;Secret、Prompt、终端/命令输入不可查询。
  • 无状态变化时使用有界 backoff、不调用模型;notification 使用稳定 dedup key,可配置 all/failures/silent 并记录 recovery/completion。
  • Desktop Scheduled Tasks、CLI、OpenAPI、Skill、恢复语义和双语文档使用同一协议。
  • fake clock、DST、misfire、crash reconciliation、并发 lease/fence、长 sleep、executor 中追加事件、>100 backlog 和真实短周期 smoke 已覆盖。
  • 完整 repair/command executor adapter 仍依赖普通模式真实命令闭环;当前 production wiring 有意不安装 executor,changed approved-repair round 返回 unavailable、按有界 retry 收敛,绝不静默执行。

本地验证

在第一次主线同步后的完整矩阵:

  • go test ./internal/store -count=1 -timeout 30m:通过,695.010s;覆盖当时完整 migration/recovery、claim/fence/retry/notification/budget/stop 矩阵。
  • 除 Store 外完整 Go package 矩阵:Application 432.329s,CLI App 116.850s,HTTP 170.926s,Desktop 24.312s。
  • scheduler/application/store/http 定向 race、两 Store 并发 create/claim、崩溃 fencing、DST、misfire 与真实短周期 smoke 通过。

同步最新 PR #114 后重新验证最终组合树:

  • go test -run '^$' ./... 全仓编译通过。
  • v119→v122 migration/README ledger 定向测试通过,4.837s;对应 migration race 通过,3.805s。
  • 受影响 Go 包无缓存集成测试通过:Application 465.777s、HTTP 187.034s、CLI App 134.439s、Desktop 38.061s、Tool Gateway 13.987s;MCP、Plugin、Hook、Skill 均通过。
  • Windows Desktop CI tags:go test -tags "desktop,wv2runtime.error" -count=1 ./cmd/cyberagent-desktop ./internal/desktop ./internal/webui,全部通过。
  • go vet ./...、go mod verify、go mod tidy -diff、git diff --check 通过。
  • npm run typecheck、完整 npm test(63 files / 274 tests)、npm run build、npm run check:api 通过。
  • npm audit --audit-level=high:0 vulnerabilities。
  • OpenAPI/TypeScript 连续生成一致;计数与 hash 如上。
  • 真实 CLI isolated smoke:创建 Run + once Job、foreground tick 后 Job 为 once_completed,1 round、0 model calls;doctor/debug/bundle 均可读取。

原始 Scheduled Diagnostics 受影响包的 staticcheck -checks='SA*,S1*,QF*' 已通过。同步 PR #114 后的扩大扫描只命中 internal/plugins/package.go 使用 archive/tar.Header.SetModTime 的 SA1019,该行来自最新 main、不在本 PR 相对 main 的 diff 中;本 PR 不把它误写成自身零告警结论。

govulncheck ./... 在本机 Go 1.26.5 如实报告 5 项可达标准库 advisory:GO-2026-6218、GO-2026-6090、GO-2026-6089、GO-2026-5972、GO-2026-5026,均标记由 Go 1.26.6 修复。本 PR 未新增 Go module 依赖;远端固定 Go 1.25 当前补丁版的结果由 CI 给出,不能把本机结果写成 zero finding。

安全审计

  • Canonical security diff scan 覆盖原始实现 9fc824c..2c9200a:60/60 review rows,3 个候选全部完成 validation/attack-path 收敛,0 reportable finding;scan ID 08dc9192-a84b-46a9-9125-d840e5c43ee4。
  • event watermark correctness 候选不形成当前安全边界跨越,但已主动修复并增加 >100 回归。
  • crash-before-budget-accounting 与 external side-effect fencing 候选依赖尚不存在的 production executor;当前 shipped path fail closed,因此为 not_applicable,不是被遗漏。
  • 增量 canonical scan 覆盖 2c9200a..baa7fd2:2/2 文件、0 candidate / 0 reportable finding;scan ID 3b096ab7-6ab5-4400-8de5-a8b18e7a33ca。
  • 两份 sealed scan 精确覆盖原始实现 9fc824c..baa7fd2;随后两次主线集成通过逐冲突审阅、迁移定向/race、Go 集成和前端生成验证。这里不把原始 sealed range 扩大成未扫描的新范围。

非目标与残余边界

  • 不提供无限期无人值守 Agent、任意 cron Shell、系统服务自启动、远程控制平面或公网 scheduler。
  • doctor 只报告;debug 只读取有界脱敏 metadata;两者不会自动安装、修复、放宽 permission 或获得 Deliver/Debug authority。
  • 当前不接入真实 scheduled model/tool/repair executor。未来接入前必须增加 crash 前 durable model-call reservation/receipt,并证明 external mutation 使用 occurrence operation key 做 sink-side 幂等或等价强保证。
  • Lease/fence 保证 SQLite 中只有一个权威 completion;它不能撤销已经发生的外部副作用,因此未来 executor 仍必须尊重 cancellation、lease deadline 与 ordinary command lifecycle。

CI 状态与超时说明

旧 Go check 的失败是 go test -timeout 20m -count=1 ./... 在 migration-heavy Store 套件达到 20 分钟后被测试框架终止,并非测试断言失败。最新 main 已由 PR #114 独立把完整套件保留为无缓存执行并将有界 deadline 调整到 30 分钟,因此本 PR 的最终树不再额外修改 CI workflow,也没有通过跳过 Store、启用 cache 或删除测试来“变绿”。

最终 head 898f37b 的 GitHub Actions run 32349073450 已成功:完整无缓存 Go suite 用时 19m35s,随后 go vet 与 pinned govulncheck 通过;TypeScript、Rust、macOS Desktop、Windows Desktop、Real Edge UI evidence 也全部成功。Desktop release 的 dependency/license 与可复现 ZIP 检查成功,PR 上的发布步骤按设计 skipped。PR 当前为 MERGEABLE / CLEAN。

Audit

  • No credentials, tokens, raw prompts/tool output, local databases, local paths or runtime artifacts are included.
  • Policy, approval, budget, lease/fencing, recovery, idempotency, diagnostics redaction and UI/API boundaries were reviewed.
  • README、usage/API guide、standalone operations guide、ADR 和 Project Status 已同步;OpenAPI 与 TypeScript binding 从最终组合树确定性重建。

@Qiyuanqiii
Qiyuanqiii marked this pull request as ready for review August 20, 2026 07:16
@Qiyuanqiii
Qiyuanqiii merged commit cf37664 into main Aug 20, 2026
9 checks passed
@Qiyuanqiii
Qiyuanqiii deleted the codex/issue-105-scheduled-diagnostics branch August 20, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(automation): 定时 loop-monitor 与结构化 doctor/debug

1 participant