feat: prepare ARR for controlled public deployment

This commit is contained in:
Wyndham ARR
2026-07-29 16:38:05 +08:00
commit a701de9f0e
271 changed files with 48472 additions and 0 deletions

104
AGENT_WRITEBACK_CONTRACT.md Normal file
View File

@@ -0,0 +1,104 @@
# Super Agent 结果回写与业务落库合同
更新时间2026-07-28
## 结论
业务系统已提供机器回写入口:
```text
POST /api/integrations/super-agent/results
Content-Type: application/json
```
请求体必须符合 `prompts/arr_opera_daily_processing_result.schema.json`,并由受信任的 Agent runtime adapter 使用独立 HMAC-SHA256 密钥签名。普通聊天文本、Agent 本地路径、未签名 JSON 或仅有 `run success` 的状态都不会入库。
## 完整链路
```text
业务任务已登记并绑定 remote_run_id
-> Agent 从 OSS 获取源 XML 并执行 arr-opera-daily-ingest
-> runtime adapter 校验 FROZEN_AGENT_RESULT 的输出目录
-> 将日报 / result.json / structured-result.json / 异常清单发布到 OSS 交换前缀
-> 生成稳定 file_handle、delivery_id 和签名回调
-> ARR 验签并核对 job / attempt / remote_run
-> 从 OSS 重新读取每个产物,重算 SHA-256 和大小
-> ARR 独立 validator 重放业务规则
-> PostgreSQL SERIALIZABLE 事务写 ingestion + finance
-> 最后切换 current_daily_versions
```
输入方向是 ARR 代码直接上传 XML 到私有 OSS然后在 Agent message 中传入一个 `oss_attachments` 描述对象。对象只含 bucket、endpoint、object key、哈希、字节数与任务 IDOSS AccessKey 只存在 ARR 进程与 `fetch_oss_file` 的 credential provider 中。
结果方向采用 runtime 主动回调,不依赖 Open API 的 `final_content`。后者在真实服务上可能为 `null`,也无法让 ARR 读取 Agent 沙箱的本地文件。
Agent 和 Super Agent 不持有 PostgreSQL 凭据。数据库写入只发生在 ARR 后端。
## ID 对应
- `job_id``ingestion.processing_runs.run_key`,由业务系统创建任务时生成。
- `attempt_no``ingestion.processing_attempts.attempt_no`,同一任务重试递增。
- `remote_run_id`:该 attempt 绑定的 Super Agent Run ID。
- `delivery_id`runtime adapter 按 job / attempt / remote run 稳定生成;重复发送同一 delivery 幂等。
- `file_handle`:只解析为 `ARR_AGENT_OUTPUT_PREFIX/<file_handle>`,不能携带 URL、OSS key 或本机路径。
- `source_file_id`:只用于 Agent 取源文件,不进入 Finance 事实表。
## 成功与失败
- HTTP `200`:结果已提交,或同一 delivery 已提交;响应 `data``status``job_id``business_date``daily_version_id``version_no``callback_replayed`
- HTTP `401`:签名错误、密钥 ID 不匹配或签名过期;不得盲目重试。
- HTTP `404`job / attempt 不存在;先修复任务登记和 ID 关联。
- HTTP `409`delivery、run 或现有任务状态冲突;必须人工核对身份。
- HTTP `422`Schema、文件身份或独立业务验收失败不得写 Finance current 事实。
- HTTP `503` / 网络失败 / `408` / `429`:使用完全相同的签名请求体有界重试。
Agent 的业务失败也可以回写,但只记录失败 delivery、工件和安全错误不会创建或激活日报版本。
## 运行配置
业务后端需要:
- `booking-test-db.env`:当前远程 `booking_test`
- 本机 LaunchAgent 可把下列回写变量放在 `/path/to/private/agent-writeback.env`;该文件必须为当前用户所有的普通文件且权限为 `0600`
- `ARR_AGENT_RESULT_HMAC_KEY_ID``ARR_AGENT_RESULT_HMAC_KEY_B64`
- `ARR_OSS_REGION``ARR_OSS_ENDPOINT``ARR_OSS_BUCKET`
- `ARR_OBJECT_PREFIX``ARR_AGENT_OUTPUT_PREFIX`
- OSS SDK 的 RAM/STS 凭据环境变量。
HMAC 密钥不能复用 `DEERFLOW_OPEN_API_KEY`。OSS bucket 必须配置服务端加密并保持 versioning Off允许部署方明确选择 `public-read` bucket但永远拒绝 `public-read-write`。每个 ARR 新对象都会显式设置 private ACL因此不会继承 bucket 的公开读取权限。
本机部署把 OSS AccessKey、Agent Open API key 和回调 HMAC 保存到 macOS 登录钥匙串,`agent-writeback.env` 只保存非敏感路由。LaunchAgent 固定使用 Keychain account `arr-web`,读取的 service 分别为 `com.chillishark.arr.oss-access-key-id``com.chillishark.arr.oss-access-key-secret``com.chillishark.arr.deerflow-open-api-key``com.chillishark.arr.agent-result-hmac`;任何交接文档、日志和项目文件都不得写出实际值。
当前本机 launchd label 仍为历史名 `com.chillishark.opera-arr-report`,实际 launcher 仍位于旧项目路径,但启动的是本项目 `arr_web.run`。后续应将 launcher/日志迁入目标项目或独立部署目录,避免路径归属混淆。
业务后端启动:
```bash
.venv/bin/python -m arr_web.run \
--host 0.0.0.0 \
--port 8765 \
--db-config /path/to/private/booking-test-db.env \
--enable-agent-writeback
```
Agent runtime 在 Skill 已完成并产出 `FROZEN_AGENT_RESULT` 后执行:
```bash
.venv/bin/python -m arr_processing.runtime_writeback \
--frozen-result /isolated/output/frozen-agent-result.json \
--output-root /isolated/output \
--attempt-no 1 \
--remote-run-id run_xxx \
--processor-version 3.0.0 \
--rule-set-sha256 <当前64位规则哈希>
```
`GET /api/health` 只有在数据库与 OSS/HMAC 装配都成功时才返回 `agent_writeback_ready=true`。该字段是“结果能真实落库”的运行门槛,而不是以代码存在或 Agent 能聊天来代替。
## 当前验证
- OSS SDK V2 adapter、前缀隔离、条件防覆盖和 versioning fail-closed 已有自动化测试。
- runtime 发布、HMAC 签名、同请求体重试和回调响应解析已有自动化测试。
- fake Agent -> 真实 Skill -> ARR 独立复验 -> 原子落库的全链路测试通过。
- 当前远程测试库已用合成 DeliveryEnvelope 完成幂等重放,表计数未增加重复数据。
- 真正线上竖切仍需注入实际 OSS region / bucket / RAM(STS) 与独立 HMAC 后执行一笔无隐私测试任务。