Metadata-Version: 2.4
Name: mtsa-agent
Version: 0.6.0
Summary: 多源时序数据量化分析与可视化 Agent（课题 12 / S06）
License-Expression: Apache-2.0
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: pandas<4,>=3.0
Requires-Dist: numpy<3,>=2.5
Requires-Dist: scipy<2,>=1.18
Requires-Dist: statsmodels<0.16,>=0.15
Requires-Dist: plotly<8,>=7.1
Requires-Dist: kaleido<2,>=1.4
Requires-Dist: pydantic<3,>=2.13
Provides-Extra: docx
Requires-Dist: python-docx>=1.2; extra == "docx"
Provides-Extra: io
Requires-Dist: openpyxl>=3.1; extra == "io"
Requires-Dist: pyarrow>=25; extra == "io"
Requires-Dist: h5py>=3.16; extra == "io"
Provides-Extra: api
Requires-Dist: fastapi>=0.115; extra == "api"
Requires-Dist: uvicorn>=0.30; extra == "api"
Requires-Dist: python-multipart>=0.0.9; extra == "api"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Requires-Dist: fastapi>=0.115; extra == "dev"
Requires-Dist: python-multipart>=0.0.9; extra == "dev"
Dynamic: license-file

# 多源时序数据量化分析与可视化 Agent

> 本页是项目概览（一页看完）：它是什么、一条链路怎么走、做到哪一步、哪些没达标、从哪开始看。
> 完整手册（安装、全部命令、运行保护、能力边界）：[`doc/使用手册.md`](doc/使用手册.md)　|　首次运行：[`doc/安装与首次运行.md`](doc/安装与首次运行.md)

## 五分钟跑通

```bash
pip install mtsa-agent   # 从 PyPI 安装（发行名与命令名不同：装的是 mtsa-agent，用的是 mtsa）
# 或在仓库根目录：pip install .
mtsa demo            # 生成一份合成天气数据，跑完整链路，出报告
```

只读 CSV 就够用。要读 Excel / Parquet / HDF5，加可选依赖：
`pip install "mtsa-agent[io]"`（仓库内：`pip install ".[io]"`）。
要跑 `scripts/make_*.py` 生成 Word，另加 `pip install "mtsa-agent[docx]"`（仓库内 `".[docx]"`）。

`mtsa demo` **不需要模型、不需要联网、不需要准备数据**。跑完当前目录多出 `mtsa_demo/`：

| 文件 | 是什么 |
| --- | --- |
| `report.md` | 人读报告：数据体检、指标、异常、变化点、结论与证据 |
| `result.json` | 结构化结果：每条结论的证据链、质量问题的可定位区间、运行参数 |
| `input.csv` | 本次用的合成数据（2,211 行；内含一段持续高温、一个气压台阶、一段连续缺失、3 条重复时间戳） |

换成自己的数据：

```bash
mtsa run --scene weather --input 你的数据.csv --question "分析温度的趋势和异常"
```

数据格式（时间列、多列、多站点）见 [`doc/安装与首次运行.md`](doc/安装与首次运行.md)。

给别人用（HTTP 薄壳，可选装）：

```bash
pip install "mtsa-agent[api]"
export MTSA_API_TOKEN=dev          # PowerShell: $env:MTSA_API_TOKEN='dev'
mtsa-api --port 8000               # 提交 202 → 轮询状态 → 取 result.json / report.md
# 若提示 mtsa-api 找不到：venv 的 Scripts 不在 PATH，改用
#   python -m mtsa.api --port 8000
```

路由、环境变量与边界见 [`doc/使用手册.md`](doc/使用手册.md) 的「HTTP 接口（薄壳）」，字段契约见
[`doc/接口与字段.md`](doc/接口与字段.md) 第 7 节。

---

| 项 | 内容 |
| --- | --- |
| 任务标识 | `multi_source_timeseries_analysis`（课题 12，AI for Science，S06） |
| 当前版本 | **0.6.0**（仓库已就绪；PyPI `mtsa-agent` 线上仍为 0.5.0，2026-11-06） |
| 概要日期 | 2026-11-01（核对版；数字出处见各项「证据」列） |
| 一句话 | 输入一份带时间列的多源数据 + 一句自然语言问题，输出「每条结论都绑定证据、可复现、可回放」的分析报告；同一套引擎提供固定流水线与模型编排两种运行方式。 |
| 核心结论 | 工程链路已闭环、证据体系完整；**分析正确性只证到「统计异常」与「季节/趋势」**。官方灾害事件召回 0.071，经三个实验确认是方法边界而非可调参数问题（2026-11-01 拍板），因此本项目**不做灾害预警**。 |

> 本文只做「结论 + 索引」，不重复格式契约。
> 接口与字段以 `doc/接口与字段.md` 为准，任务状态以 `spec/当前开发任务.md` 为准。

---

## 1. 它是什么

**能回答的问题**

- 这份数据的结构是什么？时间轴连不连续，有没有缺失、重复、乱序、单位异常？
- 趋势方向、季节振幅、峰谷月份、主周期是多少？
- 哪些时刻是异常点、哪些区段是持续异常、变化点在哪里？
- 各列之间是否相关、是否存在滞后关系？
- 在给定假设下，下一个周期（默认 24 小时）大致是什么范围？（`--forecast`，仅天气）
- 结果能否复现？每条结论对应哪个数字、哪个文件、哪一行代码？

**明确不做**

- 不做因果推断，不做交易建议与自动交易；
- 不让模型参与任何数值计算（模型只决定「先跑哪个工具」）；
- 不改原始输入文件，所有产物写入独立 `artifacts/<run_id>/`；
- 股票场景只支持固定流水线，Agent 未实现（请求返回 `AGENT_SCENE_UNSUPPORTED`）；
- 彩票 / CSI 场景、多模型对比、对外 REST 服务，均未实现。

### 两种运行模式

| 模式 | 行为 | 无模型时 |
| --- | --- | --- |
| `pipeline`（默认） | 固定流程、逐节点执行；分析哪些项由计划器决定（规则计划为 12 项） | 正常 |
| `agent` | 天气场景下由模型在白名单 5 个工具里选下一步 | `AGENT_UNAVAILABLE` |
| `auto` | 天气且有模型才升级，否则回退 | 回退 pipeline 并写 warning |

**两个开关不要混**：`--mode` 决定「谁决定执行顺序」，`--planner`（或环境变量 `MTSA_PLANNER`）决定「分析哪些项」。

| 开关 | 控制什么 | 默认 | 改变方式 |
| --- | --- | --- | --- |
| 运行模式 | 固定流水线 / 模型选工具 | `pipeline` | `--mode agent`、`--mode auto`，或 `MTSA_AGENT` |
| 计划器 | 分析项清单由谁给出 | `auto`：配了模型就由模型出计划（命中缓存则直接复用），没配模型用规则计划 | 按请求 `--planner rule` / `llm` / `auto`（HTTP 同理传 `planner`）；或按部署设 `MTSA_PLANNER`。请求优先于环境变量 |

因此「pipeline 固定 12 项、结果确定」只在计划器为 `rule` 时成立。2026-10-25 实测：
同一份天气数据、同一问题，缺省参数下 `plan_source=llm`、只跑 **3 项**；
加 `--planner rule`（或 `MTSA_PLANNER=rule`）才是 **12 项**。要逐位复现，请显式指定。

只跑部分项时，报告第 8 节把未跑的小节写成「**未执行**（本次计划未选该项）」并附一条 warning，
不写成「未检出」——两者含义相反（没跑 ≠ 没发现问题）。极值（8b）同理：计划里既没 `extreme`
也没 `anomaly` 时 `data.extremes` 为空、8b 写「未执行」（2026-11-03 之前它无条件计算，
模型只选 trend/seasonal 也会打印整张极值表）。2026-11-03 实测：问题
「分析温度的趋势与季节性」下模型只选 `['trend','seasonal']`，旧实现会输出
「未发现异常点（…已对 2 条目标序列执行检测）」，而实际一次检测都没跑。

---

## 2. 一条链路的六个步骤

| 阶段 | 做什么 | 由谁决定 |
| --- | --- | --- |
| ① 体检 | 时间轴连续性、缺失、重复、乱序、量级与单位；只报告，不自动改数据 | 固定 |
| ② 计划 | 分析项、目标列、周期、阈值 | 规则；或模型选择（agent） |
| ③ 清洗 | 插补 / 丢弃 / 单位换算，动作逐条记账 | 固定 |
| ④ 分析 | 指标、频谱、统计检验、异常、变化点、极端值、泄漏检查 | pipeline 固定；agent 由模型选工具 |
| ⑤ 结论 | 把数字写成一句话，绑定证据（指标名 / 产物编号 / 计算位置） | 固定 |
| ⑥ 报告 | `result.json` + `report.md` + 图表 + 清洗数据 + 复现脚本 | 固定 |

**三个容易混的口径**：规则计划选中 **12 项**分析；计划层 `TOOL_SPECS` 有 **13 项**（多 `randomness`）；引擎内部 `ALL_ANALYSES` 有 **14 项**（再多 `volatility`）。评估里的「规则计划覆盖率」固定以 12 项为分母，「工具覆盖率」以 5 个白名单工具为分母，两者不可互换。

---

## 3. 现在做到哪里（按证据分级）

| 维度 | 结论 | 关键数字 | 证据 | 证据生成 |
| --- | --- | --- | --- | --- |
| 工程基线 | **通过** | 64 个测试文件 / 605 项 / 0 失败 / 652.1 s（2026-11-07 12:10） | `evals/test_logs/summary.json` | 2026-11-07 12:10 |
| 鲁棒性 | **通过** | 37 个坏输入与边界用例 37/37，0 崩溃；失败均带错误码与出错节点 | `evals/robustness_results.json` | 2026-11-04 |
| 结论级门禁（独立数据 v2） | **通过** | 24/24（10 pipeline + 10 agent + 4 非劣性）；事件级命中 R=0.9667、F1=0.9831；点级 P=1.000 / R=0.840 | `evals/conclusion_gate_v2_results.json` | 2026-11-04 |
| 真实数据验证（B） | **工程通过，正确性未证** | 10 份数据 × 4 问题 × 2 模式 = 80/80 成功，证据覆盖 1.000；14 项验收 13 项通过（此为 B 阶段口径；registry 已有 17 份，重跑会是 136 次，见 `doc/改进记录.md` 遗留问题汇总） | `evals/real_data_results.json` | **2026-10-25**（B 阶段基线） |
| 数据扩容（D3） | **部分通过** | 新增 7 份（3 大洲、4 份海拔 ≥1500 m），28/28 成功；registry 10 → 17 | `evals/d3_results.json` | **2026-10-24**（D3 阶段基线） |
| 预测（可选，仅天气） | **部分通过** | 17 份 / 94 列全部完成；90% 区间覆盖率 0.8799（125,160 点，每列 1440 点）；MASE≤1.0 占 68/94 = 0.723；零膨胀列「有雨时」条件覆盖率 13 列全部 0.840–0.936（F6 PASS）；**事件概率 F5 未通过**——13 列中 4 列 BSS ≤ 0 | `evals/forecast_results.json`、`doc/预测场景化.md` | 2026-11-04 |
| Agent 对照（13 用例） | **可用** | 13/13 成功；2.62 步；需求覆盖 1.00、规则计划覆盖 0.69；结论 40.15 vs 51.0（**−21.3%**）；token 55,031；墙钟 17.73 s vs 18.29 s（−3.1%） | `evals/mode_compare_results.json` | 2026-11-04 |
| 规模与性能 | **有明确上限** | 20 万行上限（`MTSA_MAX_ROWS`）；1e5 行 37.1 s、2e5 行 123.9 s、5e5 行 736 s、1e6 未完成 | `doc/评估设计.md`、`doc/改进记录.md` #4/#6 | —（文档口径） |
| 交付形态（E1 / E3） | **可用** | `mtsa-api` 9 个路由：7 个分析/产物接口 + 任务列表 `GET /analyses` + `GET /metrics`；SQLite 任务仓储（`MTSA_API_DB`）重启后仍能查状态与产物，重启前活跃任务标 `INTERRUPTED`；保留期 `MTSA_API_RETENTION_DAYS` 只清记录不删产物；25 项接口与仓储测试；真实 uvicorn 跨进程与运维面验证 | `tests/test_api.py`、`tests/test_api_store.py`、`tests/test_api_ops.py`、`doc/接口与字段.md` 第 7 节 | 2026-11-03 |

**证据时效**：`python scripts/evidence_freshness.py` 逐个比对「产物 mtime」与「它依赖源码的最后修改时间」。

2026-11-03 首次检查：**15 个产物只有 2 个新鲜**——`eval_results.json` 停在 10-25，其中
「结论级变化点F1」还是 0.5（A1/A3 修完是 1.0）。本轮刷新了 5 项（22 项主评估、结论级、鲁棒性、
预测、Agent 对照），结果 **7 新鲜 / 8 过期**（`--tol-hours 1` 口径）。8 项的性质：

| 未跟上 | 项 | 说明 |
| --- | --- | --- |
| 阶段基线（不重跑） | 真实数据 10-25、D3 10-24 | 重跑会因 registry 已 17 份而得到 17 份 / 136 次，与已发布的「80/80」不同源 |
| 未重跑的子评估 | `llm_eval`、`agent_eval`、`holdout`、`stability`、`probe`、`benchmark` | 前两项的输入在 A3/#27 改过（工具描述、`tool_ran`），**重跑数字可能变**；后四项与本轮改动无关，但未验证 |

> `eval_results.json` 的「结论级」几行读自 `artifacts/t212_compare`（在 `.gitignore` 里，未入库）。
> 复现顺序：`python -m evals.mode_compare --out-root artifacts/t212_compare`
> → `python -m evals.conclusion_eval` → `python -m evals.run_evals`。

**规模数字**（2026-11-03 实测）：`src/mtsa` 36 个 py / 9,979 行；`tests` 目录 65 个 py（63 个测试文件，逐文件入口统计；用例数见 `evals/test_logs/summary.json`）；`evals` 22 个 py / 8,433 行；真实数据 registry 17 份（5 个来源：Open-Meteo / NOAA GHCN-Daily / DWD / ECCC / ASOS；2 种频率：hourly 14、daily 3）。

**评估指标**：29 项 = 22 项规则模式阈值指标 + 3 项 LLM 模式指标（合法率、回退率、覆盖率）+ 4 项 Agent 指标（后 7 项仅在对应评估缓存存在时纳入判定）。LLM 覆盖率只统计合法计划，回退时不计入平均——否则「模型全挂」会被算成高覆盖。

---

## 4. 还没做到 / 没达标的（诚实清单）

| 编号 | 缺口 | 实测 | 影响 | 状态 |
| --- | --- | --- | --- | --- |
| R13 / E4 | 官方灾害事件召回 | **0.0714**（阈值 ≥0.50）；14 条事件只命中 1 条 | 本项目**只声称检测统计异常，不声称灾害预警**；这条边界已写进对外口径 | **已确认的方法边界**（2026-11-01 拍板，见 `doc/R13调查报告.md`） |
| D3-4 | 阵风是否有额外收益 | 阵风 3/4、小时平均风速 3/4（完全相同） | 假设被证伪；真正起作用的是「日均 → 小时」的时间分辨率，且样本只有 4 条事件 | 未通过，按原标准记录 |
| 变化点判据 | v2 上的 F1 | **0.50 → 1.0000**：召回 1.00、精确 0.333 → 1.000。三步分别是修过检（0.50→0.6667）、停用造假的方差通道（0.6667→1.0）；灵敏度网格 0.53 / Δ=18 1.00 **未变** | F1=1.0 只说明 v2 那 2 个注入跳变被准确找到且不再多报，**不代表检测器变强**：真实数据上均值通道仍 0 检出 | 已完成（`doc/A1变化点判据.md`、`doc/A3方差通道.md`） |
| 预测覆盖 | 区间覆盖率出界列 | **已收敛**：标定改「按 horizon 分箱 + conformal 分位」，origin 密度 40 → 150（每列测试点 384 → 1440），带外列 6 → 0，平均偏差 0.0311 → 0.0258 | 逐列覆盖率噪声从 ±2.4pp 降到 ±1.1pp | 已解决（`doc/预测场景化.md`） |
| 降水概率预报 | F5 事件技能 | **未通过**：13 列事件点 ≥100，其中 4 列 BSS ≤ 0（新加坡 −0.033、拉巴斯 −0.003、内罗毕 −0.002），中位数仅 +0.012 | 「能报降水概率」这句话**不成立**；气候频率 + 3 小时持续性没有稳定技能 | 未达标，需换信息源（`doc/预测场景化.md`） |
| 检测器能力 | 缓慢漂移与持续偏移 | 逐点判定检不出「单点不超阈、整段偏移」 | 传感器漂移类故障会漏 | 见 `doc/改进记录.md` 遗留问题汇总 |
| 变化点（真实数据） | 一年期序列里的台阶 | 17 份真实数据 0 检出；注入对照：R01 的 12 °C 台阶偏 6 点、日频数据全脱靶；三种候选生成器改法实测均不迁移 | 一年期数据里 5–12 °C 的台阶与年周期不可分离；且贪心递归被季节分界挡住 | 已量化，不做（`doc/A2变化点候选生成.md`） |
| 规模 | 百万行 | 1e6 超 300 s 未完成；ADF 不能截断滞后阶（实测会翻转平稳性判定） | 大文件只能拒绝或降采样 | 已设 20 万行上限 |
| 场景 | 股票 Agent | `AGENT_SCENE_UNSUPPORTED` | 「多场景 Agent」实际只有天气 | 用户明确暂缓 |
| 产品化 | E1 可观测性 / E2 金额换算 / E3 REST | 未立项 | 对外交付前必须先做 | 按需启动 |

**一条必须记住的口径**：`agent` 比 `pipeline` 少 20.4% 的结论（51.00 → 40.62），**100% 归因于「工具未执行」**，不是算错；但「没跑」也不能当成「没问题」——报告里必须写「未执行」，不能写「未检出」。

> 2026-11-03 重跑：此前的 −23.3%（39.00 → 29.92）是 10-23 基线，早于 C3/D2/D3 三个结论通道，
> 两侧都偏低且 pipeline 侧偏得更多。墙钟差也从 +5.6% 变成 **+0.4%**——不是 agent 变快，
> 是 pipeline 多了结论与图（12.09 → 15.30 s），agent 只从 12.77 → 15.37 s。

**R13 为什么定为「能力边界」而不是「待补缺口」**（2026-11-01）：三个实验——同期分位、降分位加持续性、异常通道的窗口×阈值 36 组网格——均未找到「覆盖达标且误报可接受」的参数组合。能达标的组合要求把 **23%–39%** 的观测判为异常（基线异常率 0.3%），即靠牺牲判别力换召回。根因是逐点稳健 Z 判据与真实灾害形态不匹配：灾害多为持续数天的区域高温/寒潮，不是单点离群；而持续高温会被滚动中位数吸收、短暂寒潮不会被吸收，于是同一站位 22 个温度异常点**全部指向低温方向、0 个高温**（方向性偏置，见报告第三节）。

因此本项目明确：**能检出的是统计异常，不是灾害事件**。若未来要做灾害事件检测，那是另一套方法（多尺度残差 / 持续段判据），必须先用同一标尺离线验证「异常率 ≤2% 下能否达到 7/14」，做不到就不立项。

---

## 5. 交付物与入口

### 运行

```bash
# 安装：pip install .（Python >= 3.12）；开发用 pip install -e .
# 未安装时也可用 PYTHONPATH=src
python -m mtsa.cli run --scene weather \
  --input fixtures/weather_v1.csv \
  --question "分析温度的趋势、季节性和异常点，并检测变化点"

python -m mtsa.cli run --mode agent --scene weather \
  --input fixtures/weather_v1.csv --question "分析温度的趋势、季节性和异常"

python -m mtsa.cli run --scene weather --input fixtures/weather_eval_v2.csv \
  --question "分析温度的趋势" --forecast --forecast-horizon 24

python -m mtsa.cli run --dry-run --scene weather --input fixtures/weather_v1.csv \
  --question "分析温度的趋势"      # 只预演：字段摘要 + 场景 + 计划 + 工具，不写盘

python -m mtsa.cli run --replay artifacts/<run_id>/result.json   # 离线重放，不调模型

# 要逐位复现（规则计划 12 项、不调模型），给这次运行指定计划器：
python -m mtsa.cli run --scene weather --input fixtures/weather_v1.csv \
  --question "分析温度的趋势" --planner rule
# （也可以按部署设置：bash 用 export MTSA_PLANNER=rule，PowerShell 用 $env:MTSA_PLANNER='rule'）
```

**判断成败看 `result.json` 的 `status`，不要以「产物目录非空」为准**——失败时也会落盘留档。

### 文档索引

| 文档 | 作用 |
| --- | --- |
| `doc/使用手册.md` | 全部命令与能力边界（最全） |
| `doc/项目说明书.md` | 对外说明书：能做什么、做到什么程度、怎么复现 |
| `doc/架构设计.md` | 12 个节点、两种模式的边界、依赖表 |
| `doc/接口与字段.md` | `result.json` 字段契约（含 `data.extremes` / `data.forecast`） |
| `doc/评估设计.md` | 每项指标的算法与口径（含 6.19 预测口径） |
| `doc/改进记录.md` | T1 起逐条改进账本 + 遗留问题汇总 |
| `doc/预测场景化.md` | 6 列覆盖率出界的诊断与收敛：两类毛病、分箱标定的对照实验、零膨胀列的事件概率（BSS 仅 0.02–0.04） |
| `doc/A3方差通道.md` | 方差突变通道为什么停用：量纲错、零膨胀下不可分、残差方案也不成立（三条独立证据） |
| `doc/A2变化点候选生成.md` | 三种候选生成器的实测与否决：中位数大窗口不定位、贪心递归被父节点挡住、真实数据的信噪比上限 |
| `doc/A1变化点判据.md` | 变化点 F1=0.50 的构成与三个同源缺陷、九个变体的对照（BIC/Pettitt 更差）、真实数据上的代价 |
| `doc/AI协作记录.md` | AI 改了什么的登记簿：人工复核方式、验证结论、出过的错 |
| `doc/技术栈对照.md` | 课程推荐栈逐项对照：用了 8 项、补了 FastAPI、其余 5 项为什么不引入 |
| `spec/当前开发任务.md` | 当前阶段状态与下一项候选 |
| `spec/未来规划.md` | **唯一的规划文件**：已完成 / 审计缺口 / 研究线 / 按需启动 |
| `spec/archive/` | 历史记录，不再维护：`项目承接已完成.md`（41 章执行记录、实测数字、取舍、限制）、`下一阶段任务规划.md`（A–D 阶段规划） |
| `spec/已完成任务.md` / `spec/任务书归档.md` | 各项验收表与遗留限制（「当时要求什么」的对照证据） |
| `doc/全链路Demo_柏林2024.docx` | 5 页演示：一份数据走完六步 + 三张结果图 |
| `doc/Agent一键Demo说明_2026-10-24.docx` | 一键 demo 的图文说明（含单位变化诊断案例） |
| `doc/第二阶段报告_上海2024.docx` / `.pdf` | 第二阶段报告（A4 十页，课堂汇报版）：拿上海 2024 逐小时天气从零跑一遍，含 4 张图、口播稿与 8 条问答；重跑 `python scripts/fetch_shanghai_2024.py` 后用 `python scripts/make_stage2_report.py` 重新生成 |
| `doc/Agent全流程Demo_2026-10-23.docx` | 10-23 旧版演示（历史留档，评审看上面两份） |
| `doc/articles/可审计性是一种产品能力.md` | 对外文章（约 2,400 字）：门禁 24/24 与真实事件 0.0714 并存的原因，讲证据绑定、阈值冻结与失败公开 |
| 同名 `.docx` / `.pdf` | 同一篇文章的排版版（A4 六页，含出处表）；改完 `.md` 后跑 `python scripts/make_article_doc.py` 重新导出（自带自检：段落或关键数字丢失时非零退出） |

---

## 6. 目录

```text
src/mtsa/            引擎：导入 / 摘要 / 质量 / 预处理 / 指标 / 频域 / 检验 / 异常 / 图表 / 报告 / 编排
  scenarios/         场景适配器（weather 主场景；stock 仅 pipeline）
scripts/             一键 demo、真实数据抓取与标注、Word/PDF 文档生成
tests/               63 个测试文件
evals/               22 个评估脚本与工具 + 结果 JSON + 评估记录
fixtures/            固定样例、真实数据 registry、标签与真值
artifacts/           运行产物（按 run_id 隔离，不入库）
spec/                任务书、状态、已完成记录、未来规划
doc/                 使用手册、架构、接口、评估、改进记录、报告与 Word 交付物
```

---

## 7. 复现与验收命令

```bash
# 一键演示：同一份数据跑完六步，不需要模型、不需要联网
python scripts/demo.py --mode pipeline

# 全量测试（逐文件独立进程，避免单进程卡死）
python run_tests.py --timeout 300

# 主评估：22 项核心阈值 + LLM 3 项 + Agent 4 项（缓存齐全时共 29 项）
python -m evals.run_evals

# 独立数据上的结论门禁（4 问题 × pipeline/agent，24 项）
python -m evals.conclusion_gate_eval --pipeline-only   # 离线；去掉参数会调模型

# 鲁棒性矩阵（37 用例，约 72 s）
python -m evals.robustness_eval

# 数据扩容与事件覆盖（约 7 分钟）
python -m evals.d3_expansion_eval

# 预测评估（17 份 / 94 列）
python -m evals.forecast_eval

# 重跑全链路 demo 并重新生成 Word 演示文档
python scripts/make_chain_demo_doc.py --rerun
```

---

## 8. 文档一致性（2026-10-24 已收敛）

C 阶段（交付卫生）修完以下不一致，记录在此防止回退：

| 位置 | 原问题 | 现状 |
| --- | --- | --- |
| `doc/项目说明书.md` | 「不做预测」与同文预测能力矛盾 | 改为「不做业务预测与因果推断；`--forecast` 只给点预测 + 经验区间」 |
| `doc/项目说明书.md` | 输出结构写成子目录 | 改为 `fig_*.png` / `fig_*.html` 直接写在运行目录 |
| `doc/项目说明书.md` 6.6 | 主表是 F 阶段 11 份 / 58 列 | 标注为「F 阶段口径」，并指向 6.8 的 17 份 / 94 列 |
| `spec/已完成任务.md` | 测试数停在 31 文件 / 304 项 | 改为指向 `evals/test_logs/summary.json`，不再写死条目数 |
| 三份 spec 的「下一步」 | 三个不同说法 | 统一到 `spec/未来规划.md` 的 C → B1 → B2 → B3 |
| 多站点 | 一直列为「待拍板」 | 已声明为正式支持（README、项目说明书） |

> `spec/archive/项目承接已完成.md` 里出现的旧数字（如「31 个文件 / 304 项」）是**历史记录**，
> 按项目规则不回改，只以当前文件为准。

## 9. 下一步（2026-10-24 已定：产品化优先）

用户决定「要给别人用」：先把产品做出来，再继续研究、迭代。

| 顺序 | 任务 | 状态 | 门槛 |
| --- | --- | --- | --- |
| C | 交付卫生：文档口径、三份规划收敛、多站点正式声明 | **已完成** | 文档与代码逐条对齐 |
| B1 | E1 可观测性：未执行原因 + 覆盖矩阵 | **已完成** | 每个 `not_run` / `failed` / `skipped` 都有原因；矩阵进 `report.md` 与 `coverage.tools[]` |
| B2 | E2 成本语义：token → 金额、预算前置 | **已完成**（2026-10-25 补金额预算） | 金额标「估算」、带价目表出处；无表不按 0 计价；token 预算预扣硬停；金额预算 `--max-cost` **只标记不中止**；随包 `prices/` 两模型两档 |
| B3 | 交付形态（当时选 C 档：只做 CLI） | **已完成** | `pip install .` 后 `mtsa run` 可用；从无关目录、无 PYTHONPATH 实测通过；Dockerfile 已由 CI 构建并跑通（`docker build` → `list-scenes` → 容器内一次真实分析）。HTTP 当时没做，2026-10-25 由 E1 补了薄壳（`mtsa-api`）：提交即返回 202、轮询取结果；状态只在内存里，没有持久化队列与多副本 |
| 之后 | A1/A2 检测器质量 | 挂起 | v2 F1 ≥0.55 且 22 项逐位不变 |

研究线（A1 变化点判据 → A2 持续段/漂移 → 预测场景化）在产品可用后启动，
详见 `spec/未来规划.md`。

2026-10-25 对照课程规则（S06 / 4.1 / 2.1–2.7）逐条核对：课题本体与评估闭环已完成，
另列 12 项缺口任务（6 项未完成 + 6 项需改善），批次、成本与验收见
`spec/未来规划.md` 的「审计缺口任务」。

---

## 10. 反馈与贡献

这个项目最需要的外部输入是「**你算错了**」，不是「做得不错」。

- **结论可疑** → [开一个结论可疑的 issue](https://github.com/qiaotong555/multi-source-timeseries-analysis/issues/new?template=conclusion-wrong.yml)。模板会追问三件事：跑的命令、`result.json` 里那条结论的原文、你期望的结果与依据。
- **跑不起来** → [运行问题](https://github.com/qiaotong555/multi-source-timeseries-analysis/issues/new?template=run-error.yml)。先跑 `mtsa demo --out mtsa-check`：它能跑通说明环境没坏，问题在输入或参数。
- **想知道能信到什么程度** → 先看第 4 节「还没做到」与 `doc/使用手册.md` 的能力边界。

改代码前请读 [`CONTRIBUTING.md`](CONTRIBUTING.md)。三条硬规矩：**可复现、带证据、不为好看改评估口径。**

> 这不是客套：真实事件召回只有 1/14，缓慢漂移与持续偏移检不出——这些短板已经写在上面的清单里。指出它们不会冒犯作者，回避它们才会让项目停在演示阶段。

---

## 11. 授权与使用

代码采用 **Apache License 2.0**：可自由使用、修改、分发，包括商业用途，条件是保留版权与许可声明。
完整条款见 [`LICENSE`](LICENSE)，版权归属见 [`NOTICE`](NOTICE)。

本项目同时是课程/课题「课题 12 · AI for Science · S06」的提交物（2026-10-24 首次提交）。

第三方材料的授权链独立，不受本许可证影响：

| 文件 | 管什么 |
| --- | --- |
| [`DATA_SOURCES.md`](DATA_SOURCES.md) | `fixtures/` 下 17 份外部数据的来源、许可证与**必须保留的署名文本** |
| [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md) | pandas / numpy / scipy / statsmodels / plotly 等依赖的许可证 |

> 数据署名（CC BY 4.0）是数据提供方的要求，与代码许可证无关；删掉署名即违反数据条款。
