# v0.30 策略准入、版本冻结与影子观察

## 入口与范围

`/research/lifecycle` 提供工作区隔离的固定策略版本、历史证据引用、状态审核、独立前向观察及完整证据导出。支持 C01 / C02 / C03 / C04 / C06，自选已登记币种，4h / UTC 日线，冻结单一 Binance 或 OKX 来源。

C03、C04 首次可以保存独立影子研究事件。影子事件使用单独表与 `trendlab-shadow-observation-v1` 格式，不进入原有三策略事件、投递队列或模拟账户。所有记录 `executionAllowed=false`。研究准入不是投资建议、策略盈利认证或实盘授权。

本版只冻结各策略现有固定参数基线，不冻结滚动选参结果，不叠加动态仓位或组合权重。候选库原文和历史研究版本保持不变。独立 OIDC 真实部署、收费、C07 独立信号、M03 严格风险平价仍待后续工作。

## 生命周期与权限

| 当前状态 | 可进入状态 | 条件 |
|---|---|---|
| 候选 candidate | validation / paused | 验证需关联本工作区已成功完成的实验 |
| 已关联验证 validation | shadow / paused | 管理员审核理由；参数和证据保持冻结 |
| 影子观察 shadow | approved / paused | 准入需满足当前期前向观察门槛，并人工审核 |
| 研究准入 approved | paused | 继续按原冻结规则观察，不触发执行 |
| 已暂停 paused | 有证据则 shadow，否则 validation | 重新观察总是新一期；不直接恢复 approved |

所有者和管理员可以审核状态；研究员可以创建候选、手动观察；查看者可读及导出。API 密钥只能读或触发已有版本的影子观察，不能创建、审核或更改版本。每次写入在同一数据库事务内复查成员角色与会话 / API 密钥；行情获取期间暂停版本或撤销权限，会阻止结果写入。

创建时冻结完整策略规则、研究版本、币种、周期、来源与观察协议并计算 SHA-256。变更需创建新版本；已有定义没有编辑接口。状态使用修订号比较更新，过时操作返回 409，每次审核保存操作者、理由、时间与前后状态。工作区最多 50 个版本；每个版本最多 90 次常规状态变更，达到上限仍可最后暂停，不能再次启动。

## 历史证据与前向门槛

验证引用必须与冻结版本的币种、周期、交易所一致，且实验已成功结束。复算不一致的结果不能采用。支持 v0.27 / v0.28 / v0.29 实验，但始终提取其中固定参数基线的统计，不能用滚动选择参数或动态仓位的收益替代。

最低证据量：固定参数至少 1 个完整测试窗口、5 笔完成交易。此门槛仅检查样本数量，不判断盈利或投资价值；管理员仍需核查净收益、成本、最差窗口和完整研究包。结果来自客户端计算，服务端验证结构和引用，不重新计算历史收益。页面明确标注 `client_computed`，不得称为服务端认证的绩效。

审核为研究准入还需要当前连续启用期：

- 距启用至少 30 天；
- 至少 20 次有效收盘观察；
- 按时观察数 / 应观察数 ≥90%；
- 所有者或管理员填写至少 5 字审核理由并提交。

满足门槛不会自动改变状态；也不要求特定收益，因为影子层不计算成交和盈亏。当前门槛验证运行覆盖及证据积累，不代表策略具备盈利能力。历史窗口、前向观察及两者证据性质分开展示。

## 观察时序、去重与缺口

只记录当前最新、已确认的收盘，且收盘时间必须严格晚于当前期启用时间。收盘后等待 60 秒；观察时刻在收盘后 10 分钟内为按时，之后在下一收盘前为延迟。行情须属于当前周期边界，抓取时间距离观察小于 120 秒；校验 OHLC、连续性、预热和来源快照哈希。

每个版本 / 观察期 / 收盘仅一条不可覆盖记录，事件编号由这些字段确定。并发请求通过条件更新和数据库唯一约束去重。重复已记录收盘不重新获取行情。开始观察时已有的最近收盘不会倒填；用户不能提交 `asOf`、K 线或历史事件。

交易所锁定：影子观察直接读取冻结版本指定的 Binance 或 OKX 公共行情，不经过未区分交易所的共享缓存，也不切换备用交易所。指定来源不可用时拒绝记录并保留原持仓目标；若返回结果的来源不符同样拒绝写入。普通研究页面仍保留既有 Binance / OKX 自动备用机制。

漏掉的收盘永远记作漏采，不回放为前向证据；下一次实际观察保存缺口根数，从空仓研究目标重新开始。重置不是实际卖出或清仓成交。暂停停止新记录，旧记录保留；重新启用增加期号、清空当前目标、从新启用时间计算覆盖，不拼接暂停前记录。

当前期应观察数为收盘确认时间已到、且严格在启用之后的完整收盘个数。已观察和按时数量从不可变记录计算；暂停后以暂停时间作为统计截止。观察期满 30 天指日历时间跨度，不等同于 30 天都有记录。

## 影子研究目标

服务器用当前已确认行情计算冻结固定策略的方向条件。空仓且入场成立、退出不成立时，记录 `ENTER_LONG` 及收盘参考价、固定 ATR 保护价；已有多仓时按已收盘高低价核对保护条件，止损优先于止盈，再检查策略退出；否则 `HOLD`。

这些是收盘观察与研究目标，没有订单数量、下一开盘成交、现金账户、手续费扣款或净值。OHLC 保护触及只作为收盘后的退出观察，不声称真实柱内执行。页面不会据此展示虚构实时收益；与历史回测的下一开盘成交模型分开。

每条记录保留版本哈希、期号、行情源、抓取时间、快照哈希、最后一根 K 线、指标条件、观察时刻、触发方式、延迟、缺口和前后研究目标。没有保存完整 300–500 根实时快照，因此导出可核对记录与状态链，但不能仅凭最后一根 K 线独立重算全部指标。哈希不认证第三方行情来源。

## 运行与额度

页面的「观察最新收盘」只调用一次。刷新页面只读，不采样，不产生观察心跳。持续观察需运行独立脚本；本次发布没有替用户创建 API 密钥、启动常驻进程或积累真实 30 天证据。

下载 `public/integration/trendlab-shadow-runner.py` 和 `trendlab-runner.py` 放在同一目录。使用现有私有环境文件格式：`TRENDLAB_SITE_URL`、`TRENDLAB_API_KEY`；私有 Sites 入口额外使用 `TRENDLAB_SITE_TOKEN`。给工作区 API 密钥授予 `research:observe`，只读查询可加 `research:read`。运行器需要 Python 3.10+：

```sh
python trendlab-shadow-runner.py --env-file /private/shadow.env --once
python trendlab-shadow-runner.py --env-file /private/shadow.env --interval 30
```

Windows 可使用自己的受 ACL 保护路径；Linux/macOS 环境文件仅限所有者读写。真实凭证不写入命令参数或日志。脚本复用既有 HTTPS、禁止重定向、两层凭证分离和退避逻辑，仅输出状态和观察时间。它不投递消息或执行交易。

每轮最多处理一个到期版本，优先最近尝试最早的版本；已记录、冷却中或尚未到确认时间的版本跳过。每工作区最多 6 次观察请求 / 分钟，单版本重试间隔至少 30 秒。50 个版本是保存上限，不是 10 分钟内全部按时完成的容量保证。

手动观察计入 `manual_evaluations`；运行器计入 `scheduled_scans`。同一触发类别下的版本 / 期号 / 收盘重试只计一个配额单位，首次失败仍占用该单位；配额不足会回滚请求领取且不获取行情。空闲轮询和已记录收盘不计入计算配额。两种触发类别的配额独立。

工作区累计最多 5000 条影子记录，不自动清理或覆盖；达到上限停止新增并提示。需要管理员导出和安排后续归档，不提供删除证据绕过门槛。当前完整数据库备份仍限每表 5000 行、文件 8 MiB，文件体积可能先达到限制；超限使用管理员原生备份。

## 接口

网页登录接口使用同源校验和工作区角色；API 接口必须使用独立 Bearer 密钥。所有接口继承工作区隔离，不接受调用者指定 owner。

| 方法与路径 | 权限 / 输入 |
|---|---|
| GET `/api/console/research/releases` | 所有成员，返回工作区版本列表 |
| POST `/api/console/research/releases` | 所有者 / 管理员 / 研究员；id（UUID）、strategy、asset、horizon、venue |
| POST `/api/console/research/releases/state` | 所有者 / 管理员；id、revision、state、note；进入 validation 另需 experimentId |
| GET `/api/console/research/releases/detail?id=…&before=…` | 所有成员；每页 50 条观察、当前期统计及完整审核链 |
| POST `/api/console/research/releases/export` | 所有成员；`{"id":"UUID"}`；导出该版本全部期次和哈希 |
| POST `/api/console/research/shadow/observe` | 所有者 / 管理员 / 研究员；`{"id":"UUID"}` |
| GET `/api/v1/research/releases` | `research:read` |
| GET `/api/v1/research/releases/detail?id=…&before=…` | `research:read` |
| POST `/api/v1/research/shadow/tick` | `research:observe`；只接受 `{}`，每轮最多一个版本 |

观察状态：`recorded` 已记录、`duplicate` 已存在、`waiting` 等待下一收盘、`cooldown` 重试间隔内、`idle` 无到期任务。失败记录最后错误码及请求时间；完整状态审核记录另存。分页查询限制合法游标及参数；导出在单一事务内读取，避免不同状态快照混合。

## 迁移、恢复与回退

新增迁移 `0016_strategy_lifecycle.sql`，三张业务表：`research_releases`、`research_release_events`、`research_shadow_observations`。备份由 35 表扩为 38 表，登录会话、行情缓存仍不进入业务备份。

当前离线恢复需要同目录五个文件：`trendlab-recovery.mjs`、`recovery-codec.mjs`、`recovery-schema.json`、`lifecycle-recovery.mjs`、`lifecycle-rules-v030.json`。校验冻结规则、工作区归属、证据引用、状态链、期号、观察时间、目标持仓衔接以及准入门槛；恢复后对 shadow / approved 版本追加暂停记录。副本不会自动继续观察，原记录保留；重新启用需人工操作并开始新一期。

旧 v0.29 三文件恢复工具已冻结于 `public/integration/v029/`，用于旧结构备份。新发布清单增加 `strategy-lifecycle-v1` 和新 schema hash，禁止直接回退到不支持三张新表的旧程序。已应用迁移不删除，发生问题使用兼容修复版本。

自动验证使用合成行情、隔离身份与数据库，证明程序行为及恢复逻辑；不代表真实策略盈利、真实持续运行或生产灾备验收。当前无可用浏览器自动化能力，页面仅完成构建和 HTTP 渲染检查，尚未进行浏览器点击或视觉验收。
