Files
Neo-ZQYY/docs/_overview/04a-feedback/P0-1-sandbox-snapshot-design.md
Neo 509cf43284 chore(docs): Wave 0 调研产出 + P0/P1/P2 反馈调研
建立项目级标杆文档 docs/_overview/ 作为产品全景索引,
解决"PRD 零碎、文档膨胀、跨子系统调研无入口"的问题。

主要内容:
- 00-index 总索引 + 维护协议 + 与 CLAUDE.md 关系
- 01-product-overview 产品全景脑图(6 角色 / 6 子系统 / 数据流 /
  7 业务概念 / 8+1 AI 矩阵 / 22 术语)
- 02a-miniprogram-page-matrix 小程序 21 页业务指纹
- 02b-adminweb-page-matrix admin-web 19 路由业务指纹
- 03-test-spec 测试规范 (L1-L5 分层 + 走查模板 + 75-95 case 估算)
- 04-doc-conflicts 39 条冲突索引(P0×8 / P1×13 / P2×13 + 5 子项)
- 04a/b/c-conflicts-*-detail 业务故事卡(7 字段:关联/逻辑/影响/选项/判定)
- 05-orphan-pages-cleanup admin-web 6 孤儿页面处置(1 归档 + 4 保留)
- WAVES-MASTER-PLAN.md 全 Wave 主计划(0-5,共 22-32 工作日)
- WAVE-1-KICKOFF.md Wave 1 实施 kickoff
- GLOBAL-DECISION-DASHBOARD.md 全局决策仪表板

反馈调研产物:
- 04a-feedback/ P0 两轮反馈(8+8 项决策 + D-1/2/3 + F-1/2 子代理产出)
- 04b-feedback/ P1 两轮反馈(13+1+5 项 + E-1/2/3/4 + G-1/2 子代理产出)
- 04c-feedback/ P2 反馈(13 项 + 5 子项 + H-1/2/3 子代理产出)
- NEO-DECISIONS-LOG 累积决策记录

关键追加发现 8 处 D Bug(原蓝本 0):
- P0-3 看板沙箱接入(Wave 1 W1-T1)
- P0-5 致命 1 (4 处 fdw_etl 残留, 已修 commit 17f045a)
- P0-5 致命 2 (JWT aud 缺失, 已修 commit 17f045a)
- P0-6 clearAllTasks 守卫 (Wave 3)
- P0-8 DBViewer 黑名单漏 (已修 commit 17f045a)
- P1-3 task-detail 跳转传 task_id 而非 customer_id
- P2-7 board-finance 隐式 null
- 2 个独立 Bug (page_context.created_at + ClueCategory 字典)

参考: docs/_overview/00-index.md
2026-05-04 07:38:28 +08:00

347 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# P0-1 沙箱与参数快照机制设计调研
> 日期:2026-05-04
> 触发:Neo 在 P0-1 反馈中提出"沙箱模式下 SPI/全部参数是否每天都该有快照"
> 调研者:沙箱-参数快照专项子代理
> 状态:**调研 + Patch 建议草案**(不直接修改 P20 SPEC,不动代码 / 数据库)
> 调研边界:仅读测试库与仓库代码,产出文字结论
---
## 一、问题定义
沙箱回放历史日期(例如 `sandbox_date = 2026-03-01`)时,SPI 算法、绩效档位、奖金规则、助教等级定价等"门店级配置参数"应当使用**哪一版**?
- **A 方案(取最新)**:始终用今天的参数。简单,但 2026-03-01 当时跑出的真实分数无法在沙箱中复现 —— 沙箱失去"还原历史现场"的意义。
- **B 方案(取历史生效版)**:用 2026-03-01 当时生效的参数。准确,要求所有 cfg_* 表都有可按日期切片的版本机制,并且**所有读取入口都按业务日过滤**。
Neo 直觉:既然沙箱机制存在,SPI 参数和全部参数都应该每天都有快照吧?
**调研结论先行**:Neo 的直觉方向正确,但"每天快照"是次优方案;最优方案是**SCD2 区间(已有)+ 让所有读取入口都按业务日过滤(未做)**。当前 P20 已经在视图层为 4 个 cfg_* 表加了业务日上界,但 ETL 层的 SPI/绩效/工资任务直接读 `dws.cfg_*` 裸表绕过了视图,这是 P20 的隐藏裂缝。
---
## 二、当前实现状态
### 2.1 cfg_index_parameters 表结构(权威 DDL `db/etl_feiqiu/schemas/dws.sql:93-103`)
```sql
CREATE TABLE dws.cfg_index_parameters (
param_id integer PK,
index_type varchar(50) NOT NULL, -- WBI/NCI/RS/OS/MS/ML/SPI
param_name varchar(100) NOT NULL,
param_value numeric(14,6) NOT NULL,
description text,
effective_from date DEFAULT CURRENT_DATE NOT NULL,
effective_to date, -- 可空 = 至今仍生效
created_at timestamptz NOT NULL,
updated_at timestamptz NOT NULL
);
ALTER TABLE ... UNIQUE (index_type, param_name, effective_from);
CREATE INDEX idx_cfg_index_params_effective ON ... (effective_from, effective_to);
```
**结论**:已经具备 SCD2 区间能力。同名 `(index_type, param_name)` 可以有多行,通过 `effective_from / effective_to` 区间区分。无需新增 snapshot_date 列。
### 2.2 其他 cfg_* 表盘点
| 表 | 库.Schema | 区间字段 | UNIQUE 约束 | RLS 视图(app schema) | 视图业务日上界 |
|---|---|---|---|---|---|
| `cfg_index_parameters` | etl_feiqiu.dws | `effective_from / effective_to` | `(index_type, param_name, effective_from)` | `app.v_cfg_index_parameters` | 已加(20260502 迁移) |
| `cfg_assistant_level_price` | etl_feiqiu.dws | `effective_from / effective_to` | `(level_code, effective_from)` | `app.v_cfg_assistant_level_price` | 已加 |
| `cfg_performance_tier` | etl_feiqiu.dws | `effective_from / effective_to` | `(tier_code, effective_from)` | `app.v_cfg_performance_tier` | 已加 |
| `cfg_bonus_rules` | etl_feiqiu.dws | `effective_from / effective_to` | `(rule_type, rule_code, effective_from)` | `app.v_cfg_bonus_rules` | 已加 |
| `cfg_skill_type` | etl_feiqiu.dws | 无 | `(skill_id)` | 未单独建视图(`is_active=true`) | — |
| `cfg_area_category` | etl_feiqiu.dws | 无 | `(source_area_name)` | 未单独建视图 | — |
| `biz.cfg_task_generator_params` | zqyy_app.biz | 无(只有 `updated_at + updated_by`) | `(site_id, param_key)` | 无 RLS,后端直读 | — |
**结论**:7 张配置表中,5 张算法/财务相关的(SPI/RS/OS 参数、定价、档位、奖金)**已经有 SCD2 区间机制**。`cfg_skill_type / cfg_area_category` 是"枚举映射型"配置(技能 ID → 课程类型,区域名 → 分类),变更频率极低且无版本概念;`biz.cfg_task_generator_params` 是任务引擎运行时参数,只有最新值。
### 2.3 SPI 任务读参数的实际方式(关键裂缝)
**`apps/etl/connectors/feiqiu/tasks/dws/index/base_index_task.py:303-360`**:
```python
def load_index_parameters(self, index_type=None, force_reload=False):
...
sql = """
SELECT param_name, param_value
FROM dws.cfg_index_parameters -- 直接读裸表,不走 app.v_*
WHERE index_type = %s
AND effective_from <= CURRENT_DATE -- 用 CURRENT_DATE,不用 as_of
AND (effective_to IS NULL OR effective_to >= CURRENT_DATE)
ORDER BY effective_from DESC
"""
rows = self.db.query(sql, (index_type,))
...
```
**`spending_power_index_task.py:178-186`** 同时调用:
```python
as_of = (context.as_of_date if context and context.as_of_date else None) or _dt.now(self.tz)
db_params = self.load_index_parameters('SPI') # 不传 as_of
features = self._extract_spending_features(site_id, params, as_of=as_of) # 传 as_of
```
**问题**:
1. 数据特征(消费/充值/EWMA)的 SQL 查询用 `as_of` 参数化,具备回测能力;
2. **参数加载用 `CURRENT_DATE` 硬编码**,沙箱模式下拿到的是"今天生效的参数",不是 sandbox_date 当时生效的参数。
3. 视图层 `app.v_cfg_index_parameters` 已经按 `app.business_date_now()` 加上界,但 ETL 任务**直接读 `dws.cfg_index_parameters` 裸表绕过了视图**,GUC 不生效。
同样问题存在于 `base_dws_task.py:540-581``_load_perf_tiers` / `_load_level_prices` / `_load_bonus_rules`(绩效档位/工资任务用),这三个方法甚至连 `effective_from` WHERE 都没有,把所有历史区间的行全取出来,再让 Python 代码自己挑——一旦表里有重复 `tier_code`/`level_code` 的多区间数据,行为依赖 ORDER BY 和 Python 侧逻辑。
### 2.4 后端读参数的方式(已对接 P20)
后端通过 `app.v_cfg_*` 视图读取(如 `tenant_users.py` 走 v_cfg_assistant_level_price),`fdw_queries._fdw_context` 在事务内 `SET LOCAL app.current_business_date = sandbox_date`,视图自动按 `business_date_now()` 切片。**后端侧已经是 B 方案**。
---
## 三、参数与沙箱关联性矩阵
| 参数表 | 是否影响沙箱回放 | 当前是否有快照能力 | 后端读路径 | ETL 读路径 | 是否需要快照 |
|---|---|---|---|---|---|
| `cfg_index_parameters` (SPI/RS/OS/MS/ML/WBI/NCI 算法权重) | 是(分数会因参数变化而不同) | 有 SCD2 | 走 v_* 已切片 | **裸表绕过** | 必须 |
| `cfg_assistant_level_price` (助教等级定价) | 是(月薪计算结果不同) | 有 SCD2 | 走 v_* 已切片 | **裸表绕过** | 必须 |
| `cfg_performance_tier` (绩效档位区间) | 是(档位归属不同) | 有 SCD2 | 走 v_* 已切片 | **裸表绕过** | 必须 |
| `cfg_bonus_rules` (奖金规则) | 是(奖金金额不同) | 有 SCD2 | 走 v_* 已切片 | **裸表绕过** | 必须 |
| `cfg_skill_type` (技能 → 课程类型映射) | 否(枚举映射,业务定义不会因日期变) | 无 | 直读 `is_active=true` | 直读 | 不必 |
| `cfg_area_category` (区域名 → 分类) | 否(同上) | 无 | 直读 | 直读 | 不必 |
| `biz.cfg_task_generator_params` (任务引擎冷启动天数等) | 弱影响(沙箱演示新功能时一致即可) | 无 | 后端直读 | — | 可选(优先级 P3) |
**额外参数源**:
- AI prompt 模板版本(后端代码内常量,不在 DB)→ 沙箱演示新 prompt 时跨切换会有差异,但属于"prompt 工程版本"不属于业务参数。**优先级 P3**,通过 `prompt_version` 字段记录即可,无需快照。
- runtime_context 自身配置(`biz.site_runtime_context`)→ 是状态本身,不需要快照。
- `biz.scheduled_tasks` cron(全局调度)→ 设计共识保留真实时钟,不需要。
---
## 四、四个核心问题的答案
### Q1:A 方案 vs B 方案
**答案:B 方案**(用 2026-03-01 当时生效的参数)。
理由:
1. P20 § 1.2 沙箱设计目标是"假装今天是某个历史日期",参数是业务规则的一部分,用今天参数 = 历史现场不完整。
2. 后端走 v_* 视图已经隐式选了 B,如果 ETL 用 A,会出现"小程序看到的分数(后端取展示分)" 与 "重跑 ETL 后实际写入的分数"不一致。
3. SCD2 区间已经存在,迁移成本极低,只需改读取 SQL 的 WHERE 子句。
### Q2:B 方案的实现路径
**推荐 B-1 + 视图归一**(见 § 五):利用现有 SCD2 区间,把所有 cfg_* 读取入口统一到 `app.v_cfg_*` 视图(由 `app.business_date_now()` 自动切片),禁止 ETL 任务直读 `dws.cfg_*` 裸表。
为什么不选 B-2(每日快照表):
- 写入成本高(每天每门店复制全量参数行)。
- 实际参数变更频率极低(SPI 27 个参数自上线以来基本未变;BD 手册显示 cfg_assistant_level_price 历史只有 1-2 次区间切换),99% 快照都是冗余。
- SCD2 区间在数学上等价于"按需快照",且空间复杂度 O(变更次数) 而非 O(天数 × 门店数)。
为什么不选 B-3(变更日志重建):
- 重建逻辑复杂,需要在每个调用点应用变更日志,容易遗漏。
- SCD2 已经做了同样的事,无需再发明。
### Q3:哪些参数需要"快照"(SCD2 切片),哪些不需要
需要切片(已具备能力,只是读取入口未对齐):
- `cfg_index_parameters`(7 类指数算法参数)
- `cfg_assistant_level_price`(助教等级定价)
- `cfg_performance_tier`(绩效档位区间)
- `cfg_bonus_rules`(奖金规则)
不需要切片:
- `cfg_skill_type`(技能 → 课程类型),纯枚举映射,变更等同重命名。
- `cfg_area_category`(区域 → 分类),纯枚举映射。
- `biz.cfg_task_generator_params`(冷启动天数等),沙箱场景对其敏感度极低;若未来需要可补 SCD2,优先级 P3。
- AI prompt 版本(代码内常量),通过 `prompt_version` 标识即可。
- 调度 cron / runtime_context 自身 / 时间戳列(P20 § 1.3 已有设计共识)。
### Q4:是否已存在类似机制
存在,且**比 Neo 直觉的"每日快照"更优**:
1. SCD2 区间 `effective_from / effective_to`:5 张关键 cfg 表已有(2.2 矩阵)。
2. P20 视图层已经在 `app.v_cfg_*``app.business_date_now()` 切片(`db/etl_feiqiu/migrations/20260502__rls_views_business_date_upper_bound.sql:710-782`)。
3. 业务事实表(如 `dws_member_spending_power_index`)按 `business_date / calc_time` 已经天然形成"每日产出快照",这是事实层快照,不是参数快照。
**漏的不是机制,是读取入口的统一**
---
## 五、推荐设计方案
### 方案对比
| 方案 | 参数侧改造 | 读取入口改造 | 写入侧改造 | 工作量 | 推荐度 |
|---|---|---|---|---|---|
| **方案 1:统一视图入口** | 无(SCD2 已有) | ETL 全部 cfg 读取改走 `app.v_cfg_*` 视图 | 无 | 0.5 天(改 2-3 处 SQL) | **首选** |
| 方案 2:函数显式 as_of | 无 | 给 `load_index_parameters / _load_*``as_of` 参数 | 无 | 1 天(签名改造 + 调用方 7+ 处) | 备选 |
| 方案 3:每日快照表 | 新增 `dws.cfg_*_snapshot(snapshot_date, ...)` 6 张 | 改读 snapshot 表 | 新增日度生成 job | 3-5 天 + 持续维护 | 不推荐 |
### 推荐方案 1:统一视图入口(B-1 + 视图归一)
**核心思想**:cfg_* 表的"按业务日切片"语义封装在 `app.v_cfg_*` 视图里,所有读取入口(后端 + ETL + 后端 FDW)统一走视图。GUC `app.current_business_date` 由 ETL Loader / 任务引擎在事务起始处下发,沙箱模式下下发 sandbox_date,live 模式下不下发(回退 CURRENT_DATE)。
**实施步骤**:
1. **DB 侧**:确认 5 个 `app.v_cfg_*` 视图当前定义已经按 `effective_from <= app.business_date_now() AND effective_to >= app.business_date_now()` 切片(20260502 迁移已完成)。无需新增迁移。
2. **ETL Loader / 任务引擎入口**:在 `task_engine.py` / `flow_runner` 跑 dws 任务前,先按当前门店读 `biz.site_runtime_context.mode + sandbox_date`,在事务内执行:
```sql
SET LOCAL app.current_site_id = '<site_id>';
SET LOCAL app.current_business_date = '<sandbox_date or CURRENT_DATE>';
SET LOCAL app.current_runtime_mode = 'live' | 'sandbox';
```
live 模式下也建议显式 `SET LOCAL app.current_business_date = CURRENT_DATE::text`,使语义对称(无侧效应,函数已 STABLE)。
3. **代码侧改造**(3 处):
- `apps/etl/connectors/feiqiu/tasks/dws/index/base_index_task.py:335-342`: `FROM dws.cfg_index_parameters` → `FROM app.v_cfg_index_parameters`,移除 `effective_from <= CURRENT_DATE AND effective_to ...` WHERE(视图已切片)。
- `apps/etl/connectors/feiqiu/tasks/dws/base_dws_task.py:543-581`: `_load_perf_tiers / _load_level_prices / _load_bonus_rules` 改为 `FROM app.v_cfg_*`,删除不必要的 ORDER BY effective_from DESC(视图已只返回当前生效行)。
- `apps/etl/connectors/feiqiu/tasks/utility/seed_dws_config_task.py`(种子任务):写入仍然走裸表(写入永远是真实操作),无需改。
4. **测试**:
- 在测试库 `test_etl_feiqiu` 切沙箱到 `sandbox_date = 2026-03-01`,跑 SPI,验证读到的参数版本与裸表 `WHERE effective_from <= '2026-03-01' AND effective_to >= '2026-03-01'` 结果一致。
- 切回 live,跑 SPI,验证读到的参数 = `CURRENT_DATE` 切片结果。
- 同时跑两次(live → sandbox → live),三次结果中两次 live 必须一致。
5. **审计**:`docs/audit/changes/2026-MM-DD__sandbox_param_view_unify.md` + 更新 BD_Manual。
**工作量预估**:0.5 天(代码 ≤ 3 文件 / ≤ 30 行 + 1 篇审计 + 测试)。
**风险**:
- 视图层 SQL 复杂度上升微乎其微(简单 WHERE 子句)。
- 历史数据兼容性:cfg_* 表中 `effective_to` 应为 `'9999-12-31'` 表示"至今仍生效",当前 `cfg_index_parameters` 默认 `effective_to` 是 NULL,而 v_cfg_index_parameters WHERE 写的是 `effective_to >= app.business_date_now()`——**NULL 会被过滤掉**!这是一个真实存在的视图 bug,需要在执行方案 1 前先修视图(改为 `(effective_to IS NULL OR effective_to >= app.business_date_now())`)。
### 视图 NULL 兼容性补丁(前置必做)
`db/etl_feiqiu/migrations/20260502__rls_views_business_date_upper_bound.sql:782` 当前:
```sql
WHERE effective_from <= app.business_date_now()
AND effective_to >= app.business_date_now(); -- NULL 行被过滤
```
应改为:
```sql
WHERE effective_from <= app.business_date_now()
AND (effective_to IS NULL OR effective_to >= app.business_date_now());
```
这条修复独立于沙箱方案,任何"effective_to 留空" 的行都需要它(`cfg_index_parameters.effective_to` 是 nullable)。建议作为方案 1 的前置 P0 修复。
---
## 六、P20 SPEC Patch 建议(不实际修改,仅列出"应在 § X 加入以下内容")
### Patch P20-A:§ 1.3 沙箱不影响项 → 调整描述
当前 § 1.3 列出 7 项不被沙箱影响。建议**新增一段说明**澄清 cfg_* 配置:
```
### 1.4 沙箱影响项(配置参数版本)
下列配置表参与沙箱"业务日切片"语义,沙箱模式下读取 sandbox_date 当时生效的版本:
- cfg_index_parameters(指数算法权重 SPI/RS/OS/MS/ML/WBI/NCI)
- cfg_assistant_level_price(助教等级定价)
- cfg_performance_tier(绩效档位区间)
- cfg_bonus_rules(奖金规则)
下列不受沙箱影响:
- cfg_skill_type / cfg_area_category(纯枚举映射)
- biz.cfg_task_generator_params(任务引擎运行时参数)
- AI prompt 版本(代码常量)
```
### Patch P20-B:§ 3.5 RLS 视图业务日上界 → 修复 NULL 兼容性
§ 3.5 当前列 `v_cfg_*` 4 个视图"effective_from 与 effective_to 双向夹住"。应补充注释:
```
注:effective_to IS NULL 表示"至今仍生效",视图 WHERE 必须写为
`(effective_to IS NULL OR effective_to >= app.business_date_now())`,
不能写成 `effective_to >= app.business_date_now()`(NULL 会被过滤)。
当前 20260502 迁移生成的 4 个 v_cfg_* 视图存在此 bug,需在 P0 修复。
```
### Patch P20-C:新增 § 5.6 ETL 库读取约定
P20 § 5 当前覆盖了"后端服务层 / ETL 视图层 / 小程序 / AI 提示词 / admin-web",**没有覆盖 ETL 任务自身**。建议新增:
```
### 5.6 ETL 任务读取约定
ETL 任务(task_engine 调度的 DWS 计算任务)对 cfg_* 配置表的读取必须遵守:
1. 入口必须是 `app.v_cfg_*` 视图,禁止直读 `dws.cfg_*` 裸表(参数加载场景)。
- 例外:种子写入任务(seed_dws_config_task)写入裸表是必需的。
2. 任务事务开启后,`base_dws_task` 应在 SQL 执行前下发:
- `SET LOCAL app.current_site_id`
- `SET LOCAL app.current_business_date`(live 用 CURRENT_DATE,sandbox 用 sandbox_date)
- `SET LOCAL app.current_runtime_mode`
3. 任务上下文(TaskContext)必须能从 `biz.site_runtime_context` 读到当前模式;
live 模式下回退 live 默认行为。
当前已知未对齐(2026-05-04):
- `base_index_task.load_index_parameters` 直读 dws.cfg_index_parameters,需改走 v_*
- `base_dws_task._load_perf_tiers / _load_level_prices / _load_bonus_rules` 直读裸表,需改走 v_*
```
### Patch P20-D:§ 8 验收标准 → 新增 AC14 / AC15
```
| AC14 | sandbox 模式跑 SPI,读到的 cfg_index_parameters 版本 = sandbox_date 当时生效版本 | SQL: 对比 ETL 任务日志中 params dump 与 SELECT * FROM v_cfg_index_parameters 直查结果 |
| AC15 | sandbox 模式跑工资任务,读到的 cfg_performance_tier / cfg_bonus_rules / cfg_assistant_level_price 版本 = sandbox_date 当时生效版本 | 同上 |
```
### Patch P20-E:§ 11.2 已知 hack → 新增条目
```
- ETL DWS 任务直读 dws.cfg_* 裸表绕过 v_* 视图,沙箱模式下参数版本不切片 — 详见 P0-1-sandbox-snapshot-design.md
- v_cfg_index_parameters 视图 effective_to NULL 兼容性 bug — 详见 P0-1-sandbox-snapshot-design.md § 五
```
### Patch P20-F:§ 12 任务清单 → 新增 T16 / T17
```
- [ ] T16:修复 4 个 v_cfg_* 视图 effective_to NULL 兼容性(P0,前置)
- [ ] T17:ETL DWS 任务参数读取统一走 v_cfg_* 视图(P1,沙箱方案 1)
```
---
## 七、给 Neo 的决策清单
请就以下 6 项给出 GO / NO-GO / 修订意见:
1. **B 方案确认**:沙箱模式下,SPI/绩效/工资任务应使用 sandbox_date 当时生效的参数版本(而非今天的最新参数)。 → GO / NO-GO
2. **方案 1 vs 方案 3**:推荐方案 1(SCD2 + 视图归一,0.5 天),不推荐方案 3(每日快照表,3-5 天)。 → 同意 / 切方案 / 其他
3. **NULL 兼容性补丁前置**:`v_cfg_index_parameters` 视图 NULL 行被过滤是真实 bug,建议作为 P0 前置修复(独立审计)。 → GO / 合并到 T17 一起处理
4. **biz.cfg_task_generator_params 是否要 SCD2**:当前无版本机制,沙箱影响弱。建议优先级 P3,本轮不做。 → 同意 / 现在就要
5. **AI prompt 版本**:沙箱演示中切换 prompt 工程版本时,跨切换的 ai_run_logs 不可比。建议增加 `prompt_version` 字段标识(后续单独 SPEC),不快照 prompt 全文。 → 同意 / 其他
6. **是否直接产出 Patch SPEC**:本调研只列出 P20 应改章节,不实际修改。如果决策清单 1-5 项通过,是否授权按 § 六 patch 直接修改 `docs/prd/specs/P20-runtime-context-sandbox.md`,并产出 0.5 天的代码+测试改造? → GO / 先讨论
---
## 八、关键文件路径(便于 Neo 复核)
- `c:\Project\NeoZQYY\db\etl_feiqiu\schemas\dws.sql:93-103` — cfg_index_parameters 表定义
- `c:\Project\NeoZQYY\db\etl_feiqiu\migrations\20260502__rls_views_business_date_upper_bound.sql:710-782` — 4 个 v_cfg_* 视图(含 NULL bug)
- `c:\Project\NeoZQYY\apps\etl\connectors\feiqiu\tasks\dws\index\base_index_task.py:303-360` — load_index_parameters 直读裸表
- `c:\Project\NeoZQYY\apps\etl\connectors\feiqiu\tasks\dws\base_dws_task.py:540-581` — 工资任务三个 _load_* 直读裸表
- `c:\Project\NeoZQYY\apps\etl\connectors\feiqiu\tasks\dws\index\spending_power_index_task.py:178-186` — as_of 传入数据查询但参数加载未传
- `c:\Project\NeoZQYY\docs\prd\specs\P20-runtime-context-sandbox.md` — P20 SPEC 主体
- `c:\Project\NeoZQYY\docs\_overview\04a-feedback\P0-1-SPI-research.md` — P0-1 step1 调研(SPI 27 参数清单)
- `c:\Project\NeoZQYY\docs\_overview\04a-feedback\P0-7-runtime-context-todos.md` — 跨模块沙箱 todos
---
> 本调研产出由 Claude Opus 4.7(沙箱-参数快照专项子代理)生成于 2026-05-04,
> 不修改 P20 SPEC 主文,不动代码与数据库,仅产出决策建议。