docs(plans): 流水线待办三矛盾修复实施计划——触点②补源(assessable+t≥2 上待办)+评审页落选原因行+工厂页可判 tooltip+一问文案对齐,四编码任务+spec 注记+factor 域转单,10-08 窗口后派发 [nas]
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,387 @@
|
||||
# 流水线待办三矛盾修复 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 修复 VPS 流水线控制台三处矛盾——待办板补「因子晋级评审候选」源(真 bug)、评审页显示落选原因、工厂页可判徽标语义说明、一问文案对齐数据实况。
|
||||
|
||||
**Architecture:** 纯展示层+聚合层修补,判定语义(五问内容、t≥2 门槛、状态机)零改动。后端在 `routes_pipeline.py` 的 `todos()` 加第五聚合源(复用 `factors()` 已有的注册表+eval 库读取路径);前端抽共享过滤模块 `promotionFilter.ts` 供评审页下拉与落选行共用,工厂页加 tooltip。
|
||||
|
||||
**Tech Stack:** FastAPI + pytest(后端);Vue3 + vitest + @vue/test-utils(前端)。
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- **commit 标签**:每个代码 commit 末尾带 `[vps]`(VPS 常驻 sanguo-api 中招)+ `[no-doc]`(spec 更新由 Task 5 同 push 承担);Task 5 的 docs commit 带 `[vps]` 不带 `[no-doc]`。commit 用 `git commit -F -` heredoc 式。
|
||||
- **共享树纪律**:`git add` 必须 pathspec 精确列出文件,禁 `git add -A`/`git add .`。
|
||||
- **判定语义不动**:`REVIEW_T_GATE = 2` 只是显式常量化现有门槛(前后端各持同值,注释互相引用),不是改门槛。
|
||||
- **测试命令**:后端 `./venv310/bin/python -m pytest tests/portfolio/test_routes_pipeline.py -q`(工作目录=repo 根);前端 `cd frontend && npx vitest run <文件>`。
|
||||
- **范围外**(勿顺手做):sources 健康度块/as_of 新鲜度/前端 catch 错误态分流(未拍板);fa_gross_margin 状态机自查(转 factor 域,见 Task 7);登录页 L1。
|
||||
- **背景速览**(为何改):因子工厂显示 3 个「可判」因子(composite_quant12 t=10.2 / fa_gross_margin t=None / fund_gross_margin t=-0.21),评审页下拉只收 t≥2 的 1 个(`PromotionReview.vue:13` 过滤),待办板却说「0 件等你决策」——三页各说各话。
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 后端 todos 补「因子晋级评审候选」源
|
||||
|
||||
**Files:**
|
||||
- Modify: `sanguo_api/routes_pipeline.py:270-349`(`todos()` 函数)
|
||||
- Test: `tests/portfolio/test_routes_pipeline.py`(文件末尾追加)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `_factor_registry_path()`(:352 已有)、`_eval_latest_points()`(:357 已有,返回 `{factor_name: {"t": float|None}}`)
|
||||
- Produces: todos items 新形状 `{id: "review-{name}", touchpoint: "promotion", title, detail, path: "/pipeline/review", severity: "warn", updatedAt}`;常量 `REVIEW_T_GATE = 2.0`
|
||||
|
||||
- [ ] **Step 1: 写失败测试**——在 `tests/portfolio/test_routes_pipeline.py` 末尾追加:
|
||||
|
||||
```python
|
||||
def test_todos_factor_review_candidates(client, token, env, tmp_path, monkeypatch):
|
||||
# 三矛盾②:触点②补源——assessable 且近窗 t≥2 → 待办「待晋级评审」;
|
||||
# 无 IC 数据/t 不显著/非 assessable 一律不上板(与评审页下拉同门)
|
||||
monkeypatch.setenv("SANGUO_FACTOR_REGISTRY",
|
||||
str(tmp_path / "factor_registry.yaml"))
|
||||
with open(tmp_path / "factor_registry.yaml", "w", encoding="utf-8") as f:
|
||||
yaml.safe_dump({"factors": {
|
||||
"fa_hot": {"name": "fa_hot", "hypothesis": "H-1",
|
||||
"status": "assessable", "versions": []},
|
||||
"fa_nodata": {"name": "fa_nodata", "hypothesis": "H-2",
|
||||
"status": "assessable", "versions": []},
|
||||
"fa_weak": {"name": "fa_weak", "hypothesis": "H-3",
|
||||
"status": "assessable", "versions": []},
|
||||
"fa_prom": {"name": "fa_prom", "hypothesis": "H-4",
|
||||
"status": "promoted", "promotion_t": 3.0,
|
||||
"versions": []},
|
||||
}}, f, allow_unicode=True)
|
||||
monkeypatch.setenv("SANGUO_FACTOR_EVAL_DB",
|
||||
str(tmp_path / "no_such_eval.db"))
|
||||
from datetime import date
|
||||
from sanguo_api.routes_pipeline import set_pipeline_eval_db_path
|
||||
from sanguo_factor import eval_store
|
||||
inj_db = str(tmp_path / "factor_eval.db")
|
||||
eval_store.init_db(inj_db)
|
||||
end = date.today().isoformat()
|
||||
run_id = eval_store.create_run(inj_db, "monthly_2026-09", "sz", 10, 1,
|
||||
"2025-10-01", end, {})
|
||||
eval_store.save_results(inj_db, run_id, [
|
||||
{"factor": "fa_hot", "category": "fundamental", "expression": "x",
|
||||
"metrics": {"1": {"t_stat": 3.4, "ic_mean": 0.03, "count": 240}}},
|
||||
{"factor": "fa_weak", "category": "fundamental", "expression": "y",
|
||||
"metrics": {"1": {"t_stat": -0.2, "ic_mean": 0.001, "count": 240}}},
|
||||
])
|
||||
eval_store.finish_run(inj_db, run_id, "done", 1)
|
||||
set_pipeline_eval_db_path(inj_db)
|
||||
try:
|
||||
r = client.get("/api/v1/pipeline/todos", headers=_h(token))
|
||||
assert r.status_code == 200
|
||||
items = r.json()["items"]
|
||||
rev = [i for i in items if i["id"] == "review-fa_hot"]
|
||||
assert len(rev) == 1
|
||||
assert rev[0]["touchpoint"] == "promotion"
|
||||
assert rev[0]["path"] == "/pipeline/review"
|
||||
assert rev[0]["severity"] == "warn"
|
||||
assert "3.40" in rev[0]["detail"] or "3.4" in rev[0]["detail"]
|
||||
ids = [i["id"] for i in items]
|
||||
assert "review-fa_nodata" not in ids # 无 IC 数据不上板
|
||||
assert "review-fa_weak" not in ids # t<2 不上板
|
||||
assert "review-fa_prom" not in ids # 非 assessable 不上板
|
||||
finally:
|
||||
set_pipeline_eval_db_path("")
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑测试确认失败**:`./venv310/bin/python -m pytest tests/portfolio/test_routes_pipeline.py::test_todos_factor_review_candidates -q` → 预期 FAIL(`review-fa_hot` 不存在,`rev` 为空)
|
||||
|
||||
- [ ] **Step 3: 实现**——`sanguo_api/routes_pipeline.py` 两处改动:
|
||||
|
||||
(a) 模块级常量(放在 `_monthly_dir()` 之后):
|
||||
|
||||
```python
|
||||
# 因子晋级评审门:近窗 t≥2 才值得人评五问(与前端 PromotionReview 的
|
||||
# promotionFilter.REVIEW_T_GATE 同值镜像,改门须两处同改+spec 注记)
|
||||
REVIEW_T_GATE = 2.0
|
||||
```
|
||||
|
||||
(b) `todos()` 内,在「# ② 因子衰减告警」注释行之前插入:
|
||||
|
||||
```python
|
||||
# ①′ 因子晋级评审候选(触点②另一半,10-08 补源):可判且近窗 t≥2
|
||||
# = 评审页下拉同门——待办板与评审页从此同口径,「N 件等你决策」说真话
|
||||
from sanguo_factor import version_registry as vr
|
||||
from sanguo_portfolio.strategy_registry import ensure_runtime_registry
|
||||
try:
|
||||
freg = vr.load_registry(ensure_runtime_registry(
|
||||
_factor_registry_path(),
|
||||
os.path.join("config", "factor_registry.yaml")))
|
||||
points, _ = _eval_latest_points()
|
||||
for fname, fe in freg["factors"].items():
|
||||
if fe.get("status") != "assessable":
|
||||
continue
|
||||
t = (points.get(fname) or {}).get("t")
|
||||
if t is None or t < REVIEW_T_GATE:
|
||||
continue
|
||||
items.append({"id": f"review-{fname}", "touchpoint": "promotion",
|
||||
"title": f"{fname} 待晋级评审(五问)",
|
||||
"detail": f"可判且近窗 t={t:.2f}≥{REVIEW_T_GATE:.0f},"
|
||||
"评审页等你判定",
|
||||
"path": "/pipeline/review", "severity": "warn",
|
||||
"updatedAt": now})
|
||||
except Exception: # noqa: BLE001 注册表/eval 库异常不拖垮待办聚合
|
||||
pass
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 跑测试确认通过**:同 Step 2 命令 → PASS;再跑全文件 `./venv310/bin/python -m pytest tests/portfolio/test_routes_pipeline.py -q` 全绿(不碰旧测试)
|
||||
|
||||
- [ ] **Step 5: Commit**:
|
||||
|
||||
```bash
|
||||
git add sanguo_api/routes_pipeline.py tests/portfolio/test_routes_pipeline.py
|
||||
git commit -F - <<'EOF'
|
||||
feat(pipeline): todos 补「因子晋级评审候选」源——触点②另一半上板(assessable 且近窗 t≥REVIEW_T_GATE=2,与评审页下拉同门);待办板「N 件等你决策」与评审页待办同口径,修三矛盾②(评审页等五问/待办却 0 件) [vps] [no-doc]
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 前端共享过滤模块 + 评审页落选原因行
|
||||
|
||||
**Files:**
|
||||
- Create: `frontend/src/views/pipeline/promotionFilter.ts`
|
||||
- Create: `frontend/src/views/pipeline/promotionFilter.spec.ts`
|
||||
- Modify: `frontend/src/views/pipeline/PromotionReview.vue`
|
||||
- Test: `frontend/src/views/pipeline/PromotionReview.spec.ts`(追加一测)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `PipelineFactor`(`@/api/pipeline` 已有,含 `status: string`、`icRecentT: number | null`)
|
||||
- Produces: `REVIEW_T_GATE = 2`、`isReviewCandidate(f): boolean`、`exclusionReason(f): string`(非 assessable 返回 `''`)
|
||||
|
||||
- [ ] **Step 1: 写失败测试**——新建 `frontend/src/views/pipeline/promotionFilter.spec.ts`:
|
||||
|
||||
```typescript
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { isReviewCandidate, exclusionReason, REVIEW_T_GATE } from './promotionFilter'
|
||||
import type { PipelineFactor } from '@/api/pipeline'
|
||||
|
||||
const f = (over: Partial<PipelineFactor>): PipelineFactor => ({
|
||||
id: 'x', category: 'fundamental', version: '1', status: 'assessable',
|
||||
icRecentT: null, icFullT: null, promotedAtT: null, decayMonths: 0,
|
||||
lastEvalDate: '', ...over,
|
||||
})
|
||||
|
||||
describe('promotionFilter', () => {
|
||||
it('候选门=assessable 且近窗 t≥2', () => {
|
||||
expect(REVIEW_T_GATE).toBe(2)
|
||||
expect(isReviewCandidate(f({ icRecentT: 10.2 }))).toBe(true)
|
||||
expect(isReviewCandidate(f({ icRecentT: 2.0 }))).toBe(true)
|
||||
})
|
||||
it('无数据/不显著/非可判都不是候选', () => {
|
||||
expect(isReviewCandidate(f({ icRecentT: null }))).toBe(false)
|
||||
expect(isReviewCandidate(f({ icRecentT: -0.21 }))).toBe(false)
|
||||
expect(isReviewCandidate(f({ status: 'promoted', icRecentT: 9 }))).toBe(false)
|
||||
})
|
||||
it('落选原因可读:无数据 vs 未达门', () => {
|
||||
expect(exclusionReason(f({ icRecentT: null }))).toContain('无近窗 IC 数据')
|
||||
expect(exclusionReason(f({ icRecentT: -0.21 }))).toContain('未达 +2')
|
||||
expect(exclusionReason(f({ status: 'incubating' }))).toBe('')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑测试确认失败**:`cd frontend && npx vitest run src/views/pipeline/promotionFilter.spec.ts` → FAIL(模块不存在)
|
||||
|
||||
- [ ] **Step 3: 实现模块**——新建 `frontend/src/views/pipeline/promotionFilter.ts`:
|
||||
|
||||
```typescript
|
||||
import type { PipelineFactor } from '@/api/pipeline'
|
||||
|
||||
// 评审门:与后端 routes_pipeline.REVIEW_T_GATE 同值镜像,改门须两处同改+spec 注记
|
||||
export const REVIEW_T_GATE = 2
|
||||
|
||||
export function isReviewCandidate(f: PipelineFactor): boolean {
|
||||
return f.status === 'assessable' && (f.icRecentT ?? 0) >= REVIEW_T_GATE
|
||||
}
|
||||
|
||||
/** 可判却进不了评审页的原因(三矛盾①:鸿沟可见);非可判返回空串 */
|
||||
export function exclusionReason(f: PipelineFactor): string {
|
||||
if (f.status !== 'assessable') return ''
|
||||
if (f.icRecentT == null) return '无近窗 IC 数据'
|
||||
return `近窗 t=${f.icRecentT.toFixed(2)} 未达 +${REVIEW_T_GATE}`
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 跑模块测试确认通过**:同 Step 2 → PASS
|
||||
|
||||
- [ ] **Step 5: 改 PromotionReview.vue**——三处:
|
||||
|
||||
(a) script 区(`const factors = ref...` 到 `reload` 段)替换为:
|
||||
|
||||
```typescript
|
||||
import { isReviewCandidate, exclusionReason } from './promotionFilter'
|
||||
|
||||
const all = ref<PipelineFactor[]>([])
|
||||
const factors = computed(() => all.value.filter(isReviewCandidate))
|
||||
const excluded = computed(() =>
|
||||
all.value.filter((f) => f.status === 'assessable' && !isReviewCandidate(f)))
|
||||
const picked = ref('')
|
||||
onMounted(async () => {
|
||||
all.value = await getFactors().catch(() => [])
|
||||
picked.value = factors.value[0]?.id ?? ''
|
||||
})
|
||||
```
|
||||
|
||||
(`reload` 同步改 `all.value = ...` 两行;`current` 的 computed 不动。)
|
||||
|
||||
(b) template 区,在 `<div v-if="!factors.length" class="empty">` 之前插一行:
|
||||
|
||||
```html
|
||||
<div v-if="excluded.length" class="excluded">
|
||||
另有 {{ excluded.length }} 个可判因子未达评审门:{{
|
||||
excluded.map((f) => `${f.id}(${exclusionReason(f)})`).join('、')
|
||||
}}
|
||||
</div>
|
||||
```
|
||||
|
||||
(c) style 区追加:
|
||||
|
||||
```css
|
||||
.excluded { color: var(--text-3); font-size: 11px; margin-bottom: 8px; font-family: var(--mono); }
|
||||
```
|
||||
|
||||
- [ ] **Step 6: 页面测试**——`PromotionReview.spec.ts` 追加:
|
||||
|
||||
```typescript
|
||||
it('落选可见:可判但未达 t 门的因子显示原因行', async () => {
|
||||
const mock = [
|
||||
...factorsMock,
|
||||
{ id: 'fa_nodata', category: 'fundamental', version: '1',
|
||||
status: 'assessable', icRecentT: null, icFullT: null,
|
||||
promotedAtT: null, decayMonths: 0, lastEvalDate: '' } as never,
|
||||
]
|
||||
vi.mocked(api.getFactors).mockResolvedValue(mock)
|
||||
const w = mount(PromotionReview, { global: { plugins: [ElementPlus] } })
|
||||
await flushPromises()
|
||||
expect(w.text()).toContain('另有 1 个可判因子未达评审门')
|
||||
expect(w.text()).toContain('fa_nodata(无近窗 IC 数据)')
|
||||
})
|
||||
```
|
||||
|
||||
(若 `factorsMock` 里已有 assessable 低 t 项导致计数≠1,按实际 mock 调整断言数字——先读 `frontend/src/mock/pipelineData.ts` 的 `factorsMock` 再定。)
|
||||
|
||||
- [ ] **Step 7: 跑全部相关前端测试**:`cd frontend && npx vitest run src/views/pipeline/` → 全绿
|
||||
|
||||
- [ ] **Step 8: Commit**:
|
||||
|
||||
```bash
|
||||
git add frontend/src/views/pipeline/promotionFilter.ts frontend/src/views/pipeline/promotionFilter.spec.ts frontend/src/views/pipeline/PromotionReview.vue frontend/src/views/pipeline/PromotionReview.spec.ts
|
||||
git commit -F - <<'EOF'
|
||||
feat(pipeline): 评审页落选原因行+过滤逻辑抽共享模块——可判却未达 t 门(无数据/t 不显著)的因子在下拉下方列明原因,3 可判 vs 1 可评的鸿沟可见;isReviewCandidate/exclusionReason 供下拉与落选行共用单一口径,修三矛盾① [vps] [no-doc]
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: 工厂页可判徽标语义说明
|
||||
|
||||
**Files:**
|
||||
- Modify: `frontend/src/views/pipeline/FactorFactory.vue:54-56`(状态列)
|
||||
|
||||
- [ ] **Step 1: 改状态列模板**——把:
|
||||
|
||||
```html
|
||||
<el-table-column label="状态" width="90">
|
||||
<template #default="{ row }"><StatusChip :label="FACTOR_LABEL[row.status as PipelineFactor['status']]" :tone="FACTOR_TONE[row.status as PipelineFactor['status']]" /></template>
|
||||
</el-table-column>
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```html
|
||||
<el-table-column label="状态" width="90">
|
||||
<template #default="{ row }">
|
||||
<el-tooltip v-if="row.status === 'assessable'" content="可判=够格被评审;近窗 t≥2 才会出现在晋级评审页" placement="top">
|
||||
<span><StatusChip :label="FACTOR_LABEL[row.status as PipelineFactor['status']]" :tone="FACTOR_TONE[row.status as PipelineFactor['status']]" /></span>
|
||||
</el-tooltip>
|
||||
<StatusChip v-else :label="FACTOR_LABEL[row.status as PipelineFactor['status']]" :tone="FACTOR_TONE[row.status as PipelineFactor['status']]" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
```
|
||||
|
||||
(`el-tooltip` 是 ElementPlus 全局注册组件,FactorFactory 无需新增 import。)
|
||||
|
||||
- [ ] **Step 2: 跑工厂页现有测试**:`cd frontend && npx vitest run src/views/pipeline/FactorFactory.spec.ts` → 全绿(tooltip 不破坏现有断言;若断言 StatusChip 结构则按需微调 spec)
|
||||
|
||||
- [ ] **Step 3: Commit**:
|
||||
|
||||
```bash
|
||||
git add frontend/src/views/pipeline/FactorFactory.vue
|
||||
git commit -F - <<'EOF'
|
||||
feat(pipeline): 工厂页可判徽标悬停说明——「可判=够格被评审;近窗 t≥2 才进评审页」,两页标准差异摊开在徽标上,修三矛盾①另一面 [vps] [no-doc]
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: 一问文案对齐数据实况
|
||||
|
||||
**Files:**
|
||||
- Modify: `frontend/src/views/pipeline/PromotionReview.vue:20`(FIVE_QUESTIONS 第一问 hint)
|
||||
|
||||
- [ ] **Step 1: 改文案**——把:
|
||||
|
||||
```typescript
|
||||
{ q: '一问:IC 两窗都显著吗?', hint: '近窗 t≥2 且全史 t≥2,任一反号即否决(res_fwd_ep 先例)' },
|
||||
```
|
||||
|
||||
改为:
|
||||
|
||||
```typescript
|
||||
{ q: '一问:IC 两窗都显著吗?', hint: '近窗 t≥2(全史 t 暂无数据源,以月度批评全史表现为辅);任一反号即否决(res_fwd_ep 先例)' },
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑评审页测试**:`cd frontend && npx vitest run src/views/pipeline/PromotionReview.spec.ts` → 全绿
|
||||
|
||||
- [ ] **Step 3: Commit**:
|
||||
|
||||
```bash
|
||||
git add frontend/src/views/pipeline/PromotionReview.vue
|
||||
git commit -F - <<'EOF'
|
||||
fix(pipeline): 一问提示文案对齐数据实况——icFullT 无全史数据源(routes_pipeline 硬 None),文案不再承诺页面给不了的「全史 t≥2」,改以月度批评全史表现为辅,修三矛盾③ [vps] [no-doc]
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: 流水线 spec 补源注记(档随码走)
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/superpowers/specs/2026-09-22-research-to-trading-pipeline-design.md`(§4.5「P2 实现注记」段末)
|
||||
|
||||
- [ ] **Step 1: 定位**——找 `SANGUO_FACTOR_MONTHLY_DIR`(todos 聚合源)所在段落(「P2 实现注记(2026-09-24 计划落档)」),在段末追加一句:
|
||||
|
||||
```
|
||||
**驾驶舱 todos 聚合源清单(10-08 补源定案)**:①策略毕业候选(shadow 满+gate 过)+**①′因子晋级评审候选(assessable 且近窗 t≥REVIEW_T_GATE=2,与评审页下拉同门,前后端常量镜像)**②衰减告警 ③集体水位 ④数据缺口——触点②两半齐;评审页对可判未达门者列落选原因行(鸿沟可见原则)。
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Commit**:
|
||||
|
||||
```bash
|
||||
git add docs/superpowers/specs/2026-09-22-research-to-trading-pipeline-design.md
|
||||
git commit -F - <<'EOF'
|
||||
docs(pipeline): 驾驶舱 todos 聚合源清单入档——①′因子晋级评审候选补源定案(门=评审页同门常量镜像)+评审页落选原因行(鸿沟可见),档随码走随本批同 push [vps]
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: push + CI 三绿 + issue 勾单
|
||||
|
||||
- [ ] **Step 1: 全量回归**:`./venv310/bin/python -m pytest tests/portfolio/ -q` + `cd frontend && npx vitest run` → 双绿
|
||||
- [ ] **Step 2: push**:`git push origin master` → CI 跑 test→nas-deploy→nas-verify
|
||||
- [ ] **Step 3: 盯终态**:三绿后在 issue 勾任务清单+留 `@main-agent ✅ EXECUTE_DONE`
|
||||
|
||||
### Task 7: 转单 factor 域(不在本批编码)
|
||||
|
||||
在 Gitea issue 留 comment(或独立开单):fa_gross_margin 无任何近窗 IC 数据却处于 assessable 态——状态推进与数据验收脱节,请 factor 域自查孵化→可判的转移条件是否该含「至少一批 eval 数据」。
|
||||
|
||||
---
|
||||
|
||||
## Self-Review 结论
|
||||
|
||||
- 覆盖:三矛盾②=Task 1;①=Task 2+3;③=Task 4;根子=Task 7 转单。已批准范围无遗漏、无超范围。
|
||||
- 占位符:无 TBD;Step 2 的 mock 计数断言留了「先读 factorsMock 再定」的实读指令(数据依赖,非占位)。
|
||||
- 类型一致:`REVIEW_T_GATE` 后端 `2.0`/前端 `2`,`exclusionReason` 返回 `string`,`PipelineFactor` 复用既有类型。
|
||||
Reference in New Issue
Block a user