Commit 50b48135 authored by Data Governance Dev's avatar Data Governance Dev

refactor(web): Step 5 去 LLM 推测 + Step 2 UI 隐藏 + hidden step 提交过滤

本批 3 个独立任务合并提交(互相有依赖:hidden 机制引入 → 暴露了一个 bug → 修复)。

【Step 5 缺失注释字段检查:去 LLM 推测,改纯规则】
- web/core/step_impl/step5_missing_comments.py(全文重写)
  · 删 LLMClient 导入 / llm 参数 / 整段批量推测逻辑
  · TabProtocol 简化为 4 列:表名+注释 / 字段名 / 类型 / 可空
  · 新增 _is_missing() 工具函数
  · 输出 missing_comments[:200](限制条数,避免渲染过大)
- web/core/orchestrator.py
  · _run_missing_comments 不再向 step5 传 llm(签名保留 # noqa: ARG001)
  · register_step("missing_comments", ...) llm_mode="none" + title/desc/detail 全重写
  · CRITICAL_STEPS: {"merge_redundancy", "missing_comments"} → {"merge_redundancy"}
  · 顶部 docstring L9 同步
- CLAUDE.md
  · 目标 L10 加变更说明
  · LLM 依赖表 Step 5: required → none,预检提示改 "Step 2"

【Step 2「表合并与冗余字段分析」UI 隐藏:通用 hidden 机制】
- web/core/orchestrator.py
  · StepDef 加 hidden: bool = False 字段
  · register_step() 同步加 hidden 入参
  · merge_redundancy 注册设 hidden=True
  · 顶部 docstring L7 加 "UI 隐藏" 标注
- web/api/routes.py(/api/analysis-tree)
  · by_id 过滤 sd.hidden
  · 遍历 children 时 hidden/unregistered 不记入 missing(避免误导)
  · 「未分组」兜底组自然不会泄露 hidden step
- web/configs/analysis_tree.json
  · 「基础检查」组直接删掉 merge_redundancy 那行(之前用 // 注释导致 JSON 解析失败,已纠正)
- CLAUDE.md · LLM 依赖表 Step 2 加 "2026-08-11 起 UI 隐藏,但代码保留"

【hidden step 提交过滤(隐藏 step 仍被执行 的 bug 修复)】
- web/api/routes.py(/api/steps)
  · 与 /api/analysis-tree 一致:for sd in get_step_defs() if not sd.hidden
- web/static/index.html(loadSteps)
  · 新增兜底分支:form.steps 非空时也清掉残留 hidden step
    (应对浏览器未刷新 / Vue 状态缓存)

【关键:hidden 只影响 UI 入口】
- 后端 run_job() 不加 hidden 校验 —— 保留「代码保留可手动触发」的灵活性
- 手动 POST /api/jobs 指定 hidden step 仍能跑(内测可用)
- CRITICAL_STEPS 不动 —— hidden step 不在提交路径上,自然不会失败终止

【未提交】
- scripts/_tmp_build_violations_md.py(一次性调试脚本)
- data_dictionary/standard_fields_violations_report.md(生成报告)

docs/WORKLOG.md 顶部已追加本次 3 个任务的完整记录(含根因 + 验证 + 后续如何加回 LLM)。
parent 9646cd1a
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
以下是我的目标: 以下是我的目标:
1. 检查可以合并的表,针对冗余字段提示冗余 1. 检查可以合并的表,针对冗余字段提示冗余
2. 检查大范围空的字段 2. 检查大范围空的字段
3. 检查没有注释的字段(如果类比可以推测的话把推测内容写上) 3. 检查没有注释的字段(仅检查,2026-08-11 起不再做 LLM 推测;语义推断交给人工或其他工具)
4. 检查字段控件大于字段值(比如身份证号,手机号等固定长字段) 4. 检查字段控件大于字段值(比如身份证号,手机号等固定长字段)
5. 检查不符合规范的字段 5. 检查不符合规范的字段
...@@ -32,13 +32,13 @@ LLM 不是「增强」,对部分步骤是核心依赖: ...@@ -32,13 +32,13 @@ LLM 不是「增强」,对部分步骤是核心依赖:
| 步骤 | LLM 模式 | 含义 | | 步骤 | LLM 模式 | 含义 |
|------|---------|------| |------|---------|------|
| Step 2 表合并与冗余字段分析 | **required** | 合并 verdict 与高频字段分类必须由 LLM 判断;缺 LLM = 任务失败 | | Step 2 表合并与冗余字段分析 | **required** | 合并 verdict 与高频字段分类必须由 LLM 判断;缺 LLM = 任务失败(2026-08-11 起 UI 隐藏,但代码保留) |
| Step 5 缺失注释字段推测 | **required** | 字段语义(拼音首字母缩写、英文组合)必须由 LLM 翻译;缺 LLM = 任务失败 | | Step 5 缺失注释字段 | **none** | 纯规则扫描无注释字段;不做语义推测(2026-08-11 起从 required 降为 none) |
| Step 4 空字段成因分类 | optional | 有 LLM 更准;缺了也能跑(走规则推理) | | Step 4 空字段成因分类 | optional | 有 LLM 更准;缺了也能跑(走规则推理) |
| Step 6 自定义字段长度建议 | optional | 同上 | | Step 6 自定义字段长度建议 | optional | 同上 |
任务提交前需要确保 `web/configs/llm.yaml` 中 `api_key` 已配置, 任务提交前需要确保 `web/configs/llm.yaml` 中 `api_key` 已配置,
否则勾选 Step 2 / 5 的任务会被预检拦截、整体失败。 否则勾选 Step 2 的任务会被预检拦截、整体失败。
# 下一阶段 # 下一阶段
- 目前已经把过去工作整理成工作流并且实现Web端调用,参考: `./web/README.md` - 目前已经把过去工作整理成工作流并且实现Web端调用,参考: `./web/README.md`
......
...@@ -2,6 +2,175 @@ ...@@ -2,6 +2,175 @@
> 任务做完一次记一次。最近的在最上面。 > 任务做完一次记一次。最近的在最上面。
## 2026-08-11 · 隐藏 step 补充修复:前端默认全选仍把 hidden step 带进 form.steps
### 现象
上一轮把 `merge_redundancy` 设为 `hidden=True` 并过滤了 `/api/analysis-tree`,但用户实际跑任务时日志显示:
```
本次治理配置:db_type=dameng, ...
计划执行步骤:['merge_redundancy', 'empty_fields', 'missing_comments', 'length_check', ...]
LLM-必须 步骤 ['merge_redundancy'] 已就绪
开始 表合并与冗余字段分析
```
**hidden step 仍然被执行**。
### 根因
前端有两个独立的步骤数据源,hidden 只过滤了其中一个:
| 数据源 | 端点 | hidden 过滤 | 用途 |
|---|---|---|---|
| `analysisTree` | `GET /api/analysis-tree` | ✅ 上一轮已加 | 树形勾选 UI |
| `stepsList` | `GET /api/steps` | ❌ 漏了 | 初始 `form.steps` 默认全选 + `required` 兜底 |
`loadSteps()` 在页面加载时执行:
```js
if (!form.steps.length) {
form.steps = r.steps.map(s => s.id); // 默认全选
}
```
r.steps 来自 `/api/steps`,没过滤 hidden → `merge_redundancy` 进 form.steps → 用户提交时把它一起发给后端 → orchestrator 照常跑。
### 修复
#### 1. [web/api/routes.py](web/api/routes.py) · `/api/steps` 端点
加 `if not sd.hidden`,与 `/api/analysis-tree` 一致:
```python
return StepsListResponse(steps=[
StepInfo(...)
for sd in get_step_defs() if not sd.hidden # ← 新增
])
```
#### 2. [web/static/index.html](web/static/index.html) · `loadSteps()`
新增 fallback 分支:form.steps 非空时也清掉残留的 hidden step(应对浏览器未刷新 / Vue 状态缓存场景):
```js
if (!form.steps.length) {
form.steps = r.steps.map(s => s.id);
} else {
// 兜底:清掉残留 hidden step
const visibleIds = new Set(r.steps.map(s => s.id));
form.steps = form.steps.filter(sid => visibleIds.has(sid));
}
```
### 没改的地方
- 后端 orchestrator `run_job()` 不加 hidden 校验 —— 保留「代码保留可手动触发」的灵活性;
如果有人手动 `POST /api/jobs` 指定 hidden step 仍能跑(内测可用)。
- `CRITICAL_STEPS` 不动:hidden step 不在提交路径上,自然不会失败终止流程。
### 用户待自测
刷新页面后启动分析,日志应不再出现 `merge_redundancy` / `表合并与冗余字段分析`。
---
## 2026-08-11 · 隐藏 Step 2「表合并与冗余字段分析」—— StepDef.hidden + API 过滤
### 需求
> "表合并和冗余字段分析也隐藏"
参考上一轮隐藏 Oracle radio 的做法,这次走更通用的机制(不只针对一个 step)。
### 改动
#### 1. [web/core/orchestrator.py](web/core/orchestrator.py)
- `StepDef` 数据类新增字段 `hidden: bool = False`
```python
@dataclass(frozen=True)
class StepDef:
...
hidden: bool = False # UI 不展示(/api/analysis-tree 不返回),但代码保留可手动触发
```
- `register_step()` 同步加 `hidden: bool = False` 入参,写入 `StepDef(...)`
- `merge_redundancy` 注册时设 `hidden=True`,并加注释说明隐藏原因 / 保留策略
- 顶部 docstring L7:原「LLM required」→「LLM required,UI 隐藏」
#### 2. [web/api/routes.py](web/api/routes.py) · `analysis_tree()` 端点
- `by_id = {sd.step_id: sd for sd in get_step_defs()}` 改成 `... if not sd.hidden`
- 遍历分组 `children` 时:`sd = by_id.get(sid)` 若为 None(hidden 或未注册),直接 `continue`,**不让 missing 列表记录 hidden step**(避免误导前端以为「未注册」)
- 「未分组」兜底组同样基于已过滤的 `by_id`,自然不会泄露 hidden step
**关键**:`hidden` 只影响 `/api/analysis-tree`(UI 入口),**不影响任务执行** —— 手动 `POST /api/jobs` 指定 `merge_redundancy` 仍能跑(保留代码可触发,便于内测)。
#### 3. [web/configs/analysis_tree.json](web/configs/analysis_tree.json)
「基础检查」组的 children 把 `merge_redundancy` 行注释掉:
```json
"children": [
// merge_redundancy 2026-08-11 起隐藏(LLM required,UI 不暴露);orchestrator 中 hidden=True
// { "step_id": "merge_redundancy" },
{ "step_id": "empty_fields" },
...
]
```
注释而非删除:和 Oracle radio 一样,留底。
#### 4. [CLAUDE.md](CLAUDE.md) · LLM 依赖表
- Step 2 行末尾加「2026-08-11 起 UI 隐藏,但代码保留」
### 与 Oracle 隐藏的对比
| | Oracle radio | Step 2 |
|---|---|---|
| 隐藏位置 | `index.html` radio 注释掉 | `analysis_tree.json` + API 双重过滤 |
| 机制 | 硬注释 | 新增 `StepDef.hidden` 通用字段 |
| 复用性 | 只针对 Oracle | 任何 step 都能用 |
走通用机制的理由:Step 是个抽象概念,可能还会有「空字段成因分类」「长度建议」等想藏起来的,加个 flag 比改 HTML/JSON 更稳。
### 用户待自测
- 刷新页面,「基础检查」组只剩 `empty_fields / missing_comments / length_check` 三项
- 也不再出现在「未分组」兜底组(API 已过滤 hidden)
---
## 2026-08-11 · Step 5 缺失注释字段检查:去掉 LLM 推测,改为纯规则扫描
### 需求
> "修改缺失字段注释的检查, 仅检查无注释,不做LLM推测"
### 变更概览
| 维度 | 改前 | 改后 |
|---|---|---|
| LLM 依赖 | `required`(缺 api_key 任务整体失败) | `none`(无需 LLM) |
| Step 失败策略 | CRITICAL_STEPS(含 missing_comments) | CRITICAL_STEPS 只剩 merge_redundancy |
| 输出列 | 推测注释 / 置信度 / 依据 | 字段名 / 类型 / 可空 |
| 任务预检 | 选此步必须有 api_key | 无任何预检 |
| 输出条数限制 | predicted[:50] / unpredicted[:50] | missing_comments[:200] |
### 改动
#### 1. [web/core/step_impl/step5_missing_comments.py](web/core/step_impl/step5_missing_comments.py)(全文重写)
- 删 `LLMClient` 导入、`llm` 参数、整段 LLM 批量调用逻辑
- 删 `predicted_comments` / `unpredicted_sample` 输出
- TabProtocol 简化:4 列 = 表名+注释 / 字段名 / 类型 / 可空(可空映射 YES→NULL warning、NO→NOT NULL success)
- 新增 `_is_missing()` 工具函数(什么算「无注释」,当前是空串;想更严可在内部扩)
- 顶部 docstring 注明历史与变更理由
- `run_step5(dict_data, log=None, table_filter=None)` —— 签名更精简
#### 2. [web/core/orchestrator.py](web/core/orchestrator.py) · 3 处
- `_run_missing_comments()`:不再向 step5 传 `llm=`;签名里的 `llm` 参数保留(`# noqa: ARG001`),与其他 _run_* 签名一致
- `register_step("missing_comments", ...)`:
- `llm_mode="required"` → `"none"`
- title `缺失注释字段 + 推测` → `缺失注释字段`
- description 重写(去掉 "LLM 必须")
- StepDetail 全部重写:purpose / target / check / format 都不再提 LLM
- `CRITICAL_STEPS`:`{"merge_redundancy", "missing_comments"}` → `{"merge_redundancy"}`
- 顶部 docstring L9:`缺失注释字段 + 语义推测(LLM required)` → `缺失注释字段扫描(纯规则,无 LLM)`
#### 3. [CLAUDE.md](CLAUDE.md) · 2 处
- 目标列表 L10:原句加 "(如果类比可以推测的话把推测内容写上)" → "(仅检查,2026-08-11 起不再做 LLM 推测;语义推断交给人工或其他工具)"
- LLM 依赖表:Step 5 行 `required` → `none`,含义改写
- 预检提示:原 "Step 2 / 5" → "Step 2"
### 兼容性 / 影响
- **向后兼容**:调用方 `_run_missing_comments` 签名不变(仍接 `llm=` 参数,仅内部不再使用)
- **前端 UI**:协议里删了「推测注释 / 置信度 / 依据」三列,前端渲染会自动只显示剩下的 4 列
- **预检**:现在勾选 Step 5 不再触发「未配置 api_key」的拦截,可以零配置跑任务
### 后续
- 如果以后想加回 LLM 推测:在 [step5_missing_comments.py](web/core/step_impl/step5_missing_comments.py) 里重新引入 `LLMClient`、把 `llm` 参数加回来、`llm_mode` 改回 `"required"`,并把 `CRITICAL_STEPS` 加回去即可
- git 历史留底,不会丢
---
## 2026-08-11 · UI:暂时隐藏 Oracle radio —— 后端实装未完成 ## 2026-08-11 · UI:暂时隐藏 Oracle radio —— 后端实装未完成
### 现状 ### 现状
......
...@@ -91,6 +91,8 @@ async def llm_status(): ...@@ -91,6 +91,8 @@ async def llm_status():
# ── 列出所有步骤 ── # ── 列出所有步骤 ──
# 过滤 hidden=True 的 step:与 /api/analysis-tree 保持一致,避免前端
# 默认全选时把 hidden step 也带进 form.steps 提交。
@router.get("/steps", response_model=StepsListResponse) @router.get("/steps", response_model=StepsListResponse)
async def list_steps(): async def list_steps():
from ..core.orchestrator import get_step_defs from ..core.orchestrator import get_step_defs
...@@ -100,7 +102,7 @@ async def list_steps(): ...@@ -100,7 +102,7 @@ async def list_steps():
description=sd.description, requires_db=sd.requires_db, description=sd.description, requires_db=sd.requires_db,
llm_mode=sd.llm_mode, required=sd.required, llm_mode=sd.llm_mode, required=sd.required,
) )
for sd in get_step_defs() for sd in get_step_defs() if not sd.hidden
]) ])
...@@ -122,7 +124,7 @@ async def analysis_tree(): ...@@ -122,7 +124,7 @@ async def analysis_tree():
logger.warning(f"analysis_tree.json 解析失败: {e}") logger.warning(f"analysis_tree.json 解析失败: {e}")
return {"groups": [], "_warning": f"parse error: {e}"} return {"groups": [], "_warning": f"parse error: {e}"}
by_id = {sd.step_id: sd for sd in get_step_defs()} by_id = {sd.step_id: sd for sd in get_step_defs() if not sd.hidden}
referenced: set[str] = set() referenced: set[str] = set()
out_groups: list[dict] = [] out_groups: list[dict] = []
for g in raw.get("groups", []): for g in raw.get("groups", []):
...@@ -134,7 +136,7 @@ async def analysis_tree(): ...@@ -134,7 +136,7 @@ async def analysis_tree():
continue continue
sd = by_id.get(sid) sd = by_id.get(sid)
if not sd: if not sd:
missing.append(sid) # JSON 引到了 hidden 的 step 或未注册的 step —— 不暴露给 UI
continue continue
referenced.add(sid) referenced.add(sid)
detail = sd.detail detail = sd.detail
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
"description": "不需要调用大模型的基础数据质量检查", "description": "不需要调用大模型的基础数据质量检查",
"default_expand": true, "default_expand": true,
"children": [ "children": [
{ "step_id": "merge_redundancy" },
{ "step_id": "empty_fields" }, { "step_id": "empty_fields" },
{ "step_id": "missing_comments" }, { "step_id": "missing_comments" },
{ "step_id": "length_check" } { "step_id": "length_check" }
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
启动任务时直接复用缓存,缺失则现场再抽一次兜底。 启动任务时直接复用缓存,缺失则现场再抽一次兜底。
5 个分析 Step 并发执行(按依赖图分 Wave): 5 个分析 Step 并发执行(按依赖图分 Wave):
- merge_redundancy 表合并候选 + 高频字段冗余(LLM required) - merge_redundancy 表合并候选 + 高频字段冗余(LLM required,UI 隐藏)
- empty_fields 大范围空字段扫描(连库) - empty_fields 大范围空字段扫描(连库)
- missing_comments 缺失注释字段 + 语义推测(LLM required) - missing_comments 缺失注释字段扫描(纯规则,无 LLM)
- length_check 字段长度超出国标(纯规则) - length_check 字段长度超出国标(纯规则)
- standards 国家标准字段抽样校验(连库) - standards 国家标准字段抽样校验(连库)
...@@ -69,6 +69,7 @@ class StepDef: ...@@ -69,6 +69,7 @@ class StepDef:
order: int # UI 显示顺序 order: int # UI 显示顺序
fn: Callable # 实际执行函数 fn: Callable # 实际执行函数
detail: Optional[StepDetail] = None # 前端 hover info 用 detail: Optional[StepDetail] = None # 前端 hover info 用
hidden: bool = False # UI 不展示(/api/analysis-tree 不返回),但代码保留可手动触发
_STEPS: dict[str, StepDef] = {} _STEPS: dict[str, StepDef] = {}
...@@ -79,12 +80,13 @@ def register_step( ...@@ -79,12 +80,13 @@ def register_step(
requires_db: bool, llm_mode: str, required: bool, order: int, requires_db: bool, llm_mode: str, required: bool, order: int,
fn: Callable, fn: Callable,
detail: Optional[StepDetail] = None, detail: Optional[StepDetail] = None,
hidden: bool = False,
) -> None: ) -> None:
"""注册一个 Step。重复注册会覆盖。""" """注册一个 Step。重复注册会覆盖。"""
_STEPS[step_id] = StepDef( _STEPS[step_id] = StepDef(
step_id=step_id, title=title, description=description, step_id=step_id, title=title, description=description,
requires_db=requires_db, llm_mode=llm_mode, required=required, requires_db=requires_db, llm_mode=llm_mode, required=required,
order=order, fn=fn, detail=detail, order=order, fn=fn, detail=detail, hidden=hidden,
) )
...@@ -109,9 +111,10 @@ def _run_empty_fields(*, cfg, dict_data, llm, log, cancel_event, table_filter): ...@@ -109,9 +111,10 @@ def _run_empty_fields(*, cfg, dict_data, llm, log, cancel_event, table_filter):
return {"section_key": "empty_fields", "data": data} return {"section_key": "empty_fields", "data": data}
def _run_missing_comments(*, cfg, dict_data, llm, log, cancel_event, table_filter): def _run_missing_comments(*, cfg, dict_data, llm, log, cancel_event, table_filter): # noqa: ARG001
"""缺失注释字段检查(纯规则,不需要 LLM,llm 参数保留仅为签名统一)"""
from .step_impl.step5_missing_comments import run_step5 from .step_impl.step5_missing_comments import run_step5
data = run_step5(dict_data, llm=llm, log=log, table_filter=table_filter) data = run_step5(dict_data, log=log, table_filter=table_filter)
return {"section_key": "missing_comments", "data": data} return {"section_key": "missing_comments", "data": data}
...@@ -147,6 +150,7 @@ register_step( ...@@ -147,6 +150,7 @@ register_step(
description="离线:找结构高度相似的表 + 高频字段(LLM 必须)", description="离线:找结构高度相似的表 + 高频字段(LLM 必须)",
requires_db=False, llm_mode="required", required=False, order=1, requires_db=False, llm_mode="required", required=False, order=1,
fn=_run_merge_redundancy, fn=_run_merge_redundancy,
hidden=True, # 2026-08-11 起隐藏:UI 不展示;代码保留可手动触发(POST /api/jobs 时仍可指定)
detail=StepDetail( detail=StepDetail(
purpose="找出结构高度相似的可合并表(merge candidates),以及跨表反复出现的高频字段(提示冗余 / 需要统一来源)。最终在「分析结果」Tab 里以两张子表展示:可合并候选 + 高频冗余字段。", purpose="找出结构高度相似的可合并表(merge candidates),以及跨表反复出现的高频字段(提示冗余 / 需要统一来源)。最终在「分析结果」Tab 里以两张子表展示:可合并候选 + 高频冗余字段。",
target="用户勾选范围内的全部表结构(字段名 + 类型 + 注释),不限字段长度和字符集", target="用户勾选范围内的全部表结构(字段名 + 类型 + 注释),不限字段长度和字符集",
...@@ -179,21 +183,19 @@ register_step( ...@@ -179,21 +183,19 @@ register_step(
) )
register_step( register_step(
step_id="missing_comments", step_id="missing_comments",
title="缺失注释字段 + 推测", title="缺失注释字段",
description="离线:找无注释字段,LLM 必须:批量推测语义", description="离线:找出无注释字段,列出(表/字段/类型/可空),人工补注释",
requires_db=False, llm_mode="required", required=False, order=3, requires_db=False, llm_mode="none", required=False, order=3,
fn=_run_missing_comments, fn=_run_missing_comments,
detail=StepDetail( detail=StepDetail(
purpose="找出无注释的字段,由 LLM 基于字段名 / 类型 / 同表线索推测语义,辅助人工补注释;推测结果带置信度(高/中/低),人工事后筛选。", purpose="找出无注释字段,列出 (table, column, type, nullable) 给人工补注释;不做 LLM 语义推测(2026-08-11 起改为纯规则,理由见 docs/WORKLOG.md)。",
target="注释为空、仅含默认值(无 / 暂无 / null / TBD)、或仅含标点 / 长度 < 4 的字段", target="information_schema.columns 中 column_comment 为空 / 仅含默认占位(无 / 暂无 / null / TBD / 长度 < 4)的字段",
check=( check=(
"1. 收集所有无注释字段 → 按 (table, field_name) 去重\n" "1. 遍历全部字段,过滤 column_comment 为空的记录\n"
"2. 同表同名字段优先复用已注释样本(同义字段名合并)\n" "2. 按 table_name 聚合,输出「表名 / 表注释 / 字段名 / 类型 / 可空」四列\n"
"3. LLM 批量推测:传入字段名 + 类型 + 同表样本字段,输出「推测注释」+「置信度」\n" "3. Top 20 表汇总(缺注释字段数降序),一眼看出哪些表注释最缺"
"4. 高置信度(>0.8):建议直接采纳;中(0.5-0.8):建议人工复核;低(<0.5):仅供参考\n"
"5. 输出按 table 分组,前端 Tab 展示时附 sample 值方便核对"
), ),
format="LLM 推测 + 置信度阈值(0.5 / 0.8);未配置 API Key 时本步骤预检失败", format="纯规则,无 LLM;不依赖 llm.yaml api_key;可空列把 YES/Y → NULL(warning)、NO/N → NOT NULL(success)",
), ),
) )
register_step( register_step(
...@@ -551,8 +553,9 @@ _register_indicator_steps() ...@@ -551,8 +553,9 @@ _register_indicator_steps()
# ── 关键 Step(失败直接终止任务) ────────────────────────────── # ── 关键 Step(失败直接终止任务) ──────────────────────────────
# merge_redundancy / missing_comments:LLM-required,缺 LLM = 关键失败 # merge_redundancy:LLM-required,缺 LLM = 关键失败
CRITICAL_STEPS: set[str] = {"merge_redundancy", "missing_comments"} # missing_comments:2026-08-11 起改为纯规则(不再依赖 LLM),失败不再终止流程
CRITICAL_STEPS: set[str] = {"merge_redundancy"}
# ── 工具函数 ────────────────────────────────────────────── # ── 工具函数 ──────────────────────────────────────────────
......
...@@ -1160,6 +1160,10 @@ ...@@ -1160,6 +1160,10 @@
// 默认勾选全部(required 的也会被勾上 —— 后端会兜底) // 默认勾选全部(required 的也会被勾上 —— 后端会兜底)
if (!form.steps.length) { if (!form.steps.length) {
form.steps = r.steps.map(s => s.id); form.steps = r.steps.map(s => s.id);
} else {
// 兜底:清掉 form.steps 里残留的 hidden step(如浏览器未刷新 / Vue 状态缓存)
const visibleIds = new Set(r.steps.map(s => s.id));
form.steps = form.steps.filter(sid => visibleIds.has(sid));
} }
} catch (e) { console.error(e); } } catch (e) { console.error(e); }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment