# v0.39 研究包服务端归档

入口 `/research/archives`。在多策略组合 `/research/multi` 或 C07 多币种 `/research/basket` 完成计算/复算后，可保存当前完整研究包，也可在归档历史直接上传这两类完整包。账本局部导出和旧单币实验包不属于本版归档格式。

## 范围与身份

支持 `trendlab-multi-package-v1`（multi-research-0.38.0）和 `trendlab-basket-package-v1`（basket-research-0.37.0）。既有计算定义和完整报告不修改。归档是计算后的不可变文件收据，不是计算前预登记或后台研究任务，不构成策略准入或前向证据。

服务端检查包格式、完整内容哈希、报告哈希、冻结规则、成本/预算/仓位、数据快照与连续性。**不在服务器重跑收益计算**，索引明确标记 `verification: client_computed`、`serverRecomputed: false`，历史列表不展示归档文件自报的收益。文件自身 `serverRegistered: false` 保留原研究协议语义：没有实验预登记；不能把文件归档解释成实验注册。

“打开并复算”先核对索引与下载文件哈希，随后在对应研究台的独立计算线程重新计算全部结果，报告哈希完全一致才展示。仅伪造收益并重算包哈希可以作为未验证的客户文件归档，但不能通过该完整复算。下载按钮只验证文件一致性，不宣称已经验证收益或行情来源真实。

## 存储、重试与权限

D1 保存工作区、创建者、类型、完整配置、配置哈希、包/报告/规范化文件 SHA-256、文件字节数和存储状态；R2 存放规范化完整 JSON，包含全部行情源、数量、现金、成交和内部转移。对象没有公开链接，只通过带身份与工作区校验的下载接口读取。

同工作区按完整研究包哈希去重。JSON 空白/对象键顺序不同不会新增记录；源数组顺序不同可能形成不同包身份，即使报告相同。重复上传不改变原创建者、时间和冻结配置；不同工作区分别拥有索引和对象。

每包上传和规范化后均最多 8 MiB；每工作区最多 20 份、80 MiB，待重试和待补传记录也占容量。浏览器原 24/64 MiB 本地研究包功能保留，超出归档上限的包请本地保管。当前没有删除或自动清理归档，不将归档容量计为扫描/投递用量。

先在 D1 原子预留索引和容量，再写 R2，最后确认 `stored`。R2 写入失败时保留一条 `pending` 记录，重试相同包继续上传；中间失败不显示为已存文件。并发同包使用同一个对象键，不会相互删除文件。缺失或损坏的文件下载会失败，重新上传相同包后可修复。D1 与 R2 不是跨服务原子事务，确认状态前可能已有未确认对象；不会自动开放该对象下载。

所有者、管理员和研究员可归档；浏览者可列出、查询、下载和复算。写入仅允许同源浏览器会话；`research:read` 独立 API 密钥可读，不可上传。自选币种需在当前工作区启用后才可归档。角色、密钥及客户会话在异步对象读写后再次检查，权限撤销阻止后续提交或下载返回。归档本身不启用消息、自动研究或交易。

## 接口

| 方法 | 路径 | 说明 |
| --- | --- | --- |
| POST | `/api/console/research/archives` | application/json 原始完整研究包；最多 4 次/分钟/工作区；返回文件收据，重试可重复返回 201 |
| GET | `/api/console/research/archives?before=0` | 倒序每页 10 条、nextCursor、工作区容量 |
| GET | `/api/console/research/archives/detail?id=UUID` | 冻结索引详情，不接受 owner 或任意工作区查询参数 |
| GET | `/api/console/research/archives/download?id=UUID` | 私有 JSON 附件；no-store/nosniff，`X-TrendLab-Archive-SHA256` 为规范化文件哈希 |

三个 GET 同时提供 `/api/v1/research/archives...` 独立密钥入口，要求 `research:read`，工作区由密钥固定。console 工作区沿用 `X-TrendLab-Workspace`；未知/重复查询参数均拒绝，外工作区编号返回 404。存储未配置 503、容量超限 409、文件待补传/损坏 409、请求超大 413。不通过 URL 或用户输入指定 R2 对象键。

## 备份、恢复与部署

新增迁移 `0019_gigantic_stone_men.sql`，业务备份 44 张表，完整迁移共 20 个。发布清单 `release-v039.json` 新增 `research-package-archives-v1` 模型及 `DB`/`BUCKET` 绑定要求；现有 `.openai/hosting.json` 声明私有 R2 绑定 `BUCKET`，由托管流程配置。独立客户部署模板增加 R2 桶名占位，需配置独立私有桶。

数据库加密备份只包含归档索引，**不包含 R2 文件**。请另行下载每份完整研究包；整站灾备还需要管理员对数据库和对象存储分别备份。恢复演练检查配置身份、审计、容量和归属，恢复全部索引后标记 `requires_reupload`，即使旧桶仍有文件也不会自动读取。登录恢复后的工作区，上传原完整包，核对包/报告/配置/文件哈希一致后恢复原归档编号及可下载状态。丢失原包时，数据库索引不能重建原始行情和结果文件。

当前离线工具共十八文件，在原十六文件基础上增加 `archive-recovery.mjs`、`archive-rules-v039.json`。旧十六文件逐字节冻结于 `/integration/v038/`，用于旧 43 表备份；新旧结构不能混用。当前恢复仍撤销凭证、禁用客户账号和自动动作；文件补传不恢复自动处理或策略准入。

回退检查要求相同数据库结构、既有模型、归档模型、密钥和存储绑定。旧 v0.38 不理解新表/模型，不支持直接回退。没有在本轮演练真实生产数据库恢复、真实身份提供商、客户 72 小时运行或真实组合前向表现。

## 验证与后续

代码测试使用独立 D1/R2；编译产物检查覆盖真实 HTTP 路由和下载后原计算线程的精确复算。证据见 `verification-v039.json`。未进行浏览器点击验收。

后续优先完成冻结预算的组合独立前向观察，再做组合滚动训练/测试验证和正式信号准入；服务端异步计算任务、归档保留/删除策略与对象存储灾备自动化另行推进。
