1. 17 Aug, 2026 3 commits
    • Data Governance Dev's avatar
      fix(web2): 修 start.py GBK 启动崩溃 + app.py SPA fallback + LOG_DIR NameError · 97a82545
      Data Governance Dev authored
      背景(按踩坑时间线):
      1. start.py 用 print("✓ 关键依赖齐全"),Windows 默认 GBK console 抛 UnicodeEncodeError,
         整个启动流程在 09:45 死在第一行
      2. app.py main() 函数引用 LOG_DIR 但没 import,跑 main() 直接 NameError;
         之前走 uvicorn 启动不跑 main() 所以没暴露
      3. 浏览器访问 http://localhost:8766/#/id-card 时页面空白 —— FastAPI 对 SPA
         路由(hash 路由 path 是 /,history 路由会触发 404)没有兜底,Vue Router
         没机会接管
      
      改动:
      - start.py:入口处 sys.stdout.reconfigure(encoding='utf-8', errors='replace');
        ✓ → [OK],✗ → [FAIL](Windows GBK 永远安全)
      - app.py:同上加 stdout reconfigure;从 _logging 多 import LOG_DIR;
        加 @app.exception_handler(404) 做 SPA fallback:
          · /api/* 404 → JSON(前端 fetch 期待 JSON)
          · 其他路径 404 → dist/index.html(让 Vue Router 接管)
      
      顺手:
      - CLAUDE.md 加规则:「永远不要使用数据操作语句,本工具只做查询!」
      
      验证:
      - start.py 启动不再因为 ✓ 崩
      - GET /id-card 现在返回 200 + index.html(之前 404)
      - GET /api/nonexistent 仍返回 404 JSON
      
      踩坑见 work-logs/2026-08-17.md 第五、七章。
      97a82545
    • Data Governance Dev's avatar
      docs: 简化 CLAUDE.md 移除已迁移到 README 的项目说明 · 8627b77b
      Data Governance Dev authored
      清理内容:
      - 移除项目目标 / 字段对象 / 大致流程等已过时的工作流描述
      - 移除 LLM 依赖矩阵(已分散到 web/README 等具体文件)
      - 移除「下一阶段」段落
      - 新增 web2 与 web 的关系说明(web/ 是参考实现,web2/ 是新开发)
      - 保留 4 条总体要求(记录工作 / 不自动提交 / 写清内容 / 记踩坑)
      8627b77b
    • Data Governance Dev's avatar
      feat(web2): 初始化前端 + 后端完整骨架 + 数据库连接 popover · 26704c67
      Data Governance Dev authored
      前端 (Vue 3.5 + Element Plus 2.9 + Vite 6, 端口 5174):
      - 脚手架: package.json / vite.config.js / index.html / main.js / App.vue
      - 路由 + 布局: router/index.js + layouts/MainLayout.vue + views/IdCardTool.vue
      - 状态: stores/useDbConnection.js (响应式单例 + localStorage 持久化)
      - UI: components/DbConnectionPopover.vue (数据库名 + 真实 logo + 测试/切换)
      - 配置: config/dbPresets.js (后端不通兜底) + config/dbBranding.js (logo/icon/颜色)
      
      后端 (FastAPI, 端口 8766):
      - 入口: app.py + _logging.py (idempotent logger + RotatingFileHandler)
      - API: routes/db.py (GET /api/db-defaults 读 web/configs/db_defaults.yaml,
        POST /api/connect/test 复用 web.core.db_adapter.test_connection)
      - 启动: start.py (依赖检查 + uvicorn) / backend/start.bat
      
      一键启动: web2/start.bat / web2/start.sh 同时拉起前后端两个窗口
      
      数据流:
      - 前端启动 → 异步 GET /api/db-defaults → 覆盖 presets (4s 超时 fallback)
      - 点击测试 → POST /api/connect/test → 后端复用 web.core.db_adapter
      
      安全策略:
      - dbPresets.js 中 password 字段留空(真实密码不入库)
      - 运行时由 GET /api/db-defaults 注入;后端不通时测试连接因密码空失败(预期)
      
      配套改动:
      - .gitignore: 忽略 web2/logs/ (start 脚本的 console 输出目录)
      26704c67
  2. 14 Aug, 2026 2 commits
    • Data Governance Dev's avatar
      refactor(web): 「字段长度检查」按字段类型拆 7 个独立 step + 3 层嵌套 · 53f6205d
      Data Governance Dev authored
      后端:
        - step6_length_check.py: LENGTH_RULES 扁平列表 → 7 个 _BUILTIN_CATEGORIES
          (len_id_card / len_uscc / len_mobile / len_xzqh / len_postal / len_email / len_bank_card)
          每个分类独立 rules + UI 元数据 + expected_length + standard
        - orchestrator.py: 单 length_check step → 7 个 len_* 独立 step
          (工厂函数 _run_length_check_category(cat_id));旧的 length_check 保留为 hidden
        - match_config.py: 新增 get_length_categories_rules(cat_id);旧 get_length_rules() 保留为兜底
        - standards_match.yaml: step6_length.rules → step6_length.categories.<cat_id>.rules
          每分类 1 个 name_pattern + 1 个 comment_keyword(区划留 2 个)
        - routes.py /api/analysis-tree: 加递归 3 层嵌套(group → subgroup → leaf)
          新增 is_subgroup: True 显式标记(避免靠 step_id 缺失推断)
          /api/match-config: 给每个 len_* 单独返回 names/comments 默认值
      
      前端:
        - analysis_tree.json: 「字段长度检查」从 leaf 改为 subgroup
          (key=length_check_group, 含 7 个 len_* 子 step)
        - index.html: flatCheckRows + flatResultRows 支持 3 层(_level 0/1/2)
          toggleGroupCheck / setAllChecks / setAllGroupsExpanded 改为递归处理子组叶子
          flatResultRows fallback 分支抽出 _push_leaf_row(item, level) 助手
        - style.css: 加 .tree-row--subgroup / .subgroup-title / .subgroup-count / .subgroup-description
      
      Bug fix:
        - step_id vs tab_key 混用导致 displayedTabs 过滤掉 7 个 length tab
          section_key='length_len_id_card' / tab_key='length_len_id_card' / step_id='len_id_card' 三者分离
          _wrap() 加 step_id 参数(默认沿用 tab_key,向后兼容旧 length_check)
      
      WORKLOG 记录所有改动 + 5 个踩坑(subgroup 识别 / YAML 关键词精简 / fallback 分支复用 /
      CSS .tree-row--subgroup / LengthRule.__dict__ 转 dict 抛错 / step_id 与 tab_key 混用)
      53f6205d
    • Data Governance Dev's avatar
      feat(standards): 细化违规原因 + 异常值字符位高亮 + tooltip 换行 + 合并 bug · 1bb3ca98
      Data Governance Dev authored
      合并两轮迭代的修改:
      
      1) 违规原因细化(来自「细化所有目前显示的分析对象的错误信息」)
         - 21 个 IND validator + step4/5/6 的 reason 加上:
           · 标准来源编号(GB/T 2260 / GB 11643-1999 / 工信部 / GB 32100-2015 等)
           · 常见错因 ①②③(末位错填 / 出生日期段 / 地址码舍 0 等)
           · 建议核对原始证件 / 用脚本批量重算
         - reason 字符串内含 \n 换行符(前后端一起生效)
      
      2) 异常值字符位高亮(用户截图反馈「异常值要指出哪里错了」)
         - standards/base.py:ValidationResult 新增 bad_positions 字段
         - 11 个 validator populate bad_positions:
           · IND-001/002/003/004/005/006 按字段类型填具体错位
           · IND-016 银行卡 Luhn 错:暴力枚举找出「单字符修正」位
         - web/core/step_impl/step7_standards.py:_build_value_highlighted
           · 区间合并(重叠/相邻)+ HTML escape → <mark class='bad-pos'>...
         - web/static/index.html:
           · .bad-pos CSS(淡红 + 红字 + 下划线 + cursor:help)
           · kind='code' 渲染分支 v-html='row.value_highlighted'
      
      3) tooltip 多行修复(用户截图反馈「[a] [b] [c] 三个子检查挤在一行」)
         - 上一轮 .el-popper { white-space: pre-line !important } 看着对实际不生效
           · Element Plus 2.x show-overflow-tooltip 内部 normalize 文本,外层 CSS 救不回来
         - 本轮改用自渲染路线:放弃 show-overflow-tooltip,用 <el-tooltip> + #content 槽
           · escapeTooltipHtml():HTML escape + \n → <br>
           · cell 内 text-overflow: ellipsis 保持单行布局
           · 没 \n 的列无感升级
      
      4) IND-003 / IND-004 合并步骤 TypeError 修复(用户截图反馈「有报错」)
         - 报错:TypeError: 'NoneType' object is not iterable
         - 根因:_merge_violations_by_tuple 里的死循环
           for p in (r.get('value_highlighted') and [])
           · 当 value_highlighted 为 None/空串时短路返回 None,
             for p in None 抛错
           · IND-003-b / IND-004-b 不填 bad_positions 时必触发
         - 修复:直接删这段死代码(loop 里只有 pass,真正 fallback 在下面)
      
      5) 其他
         - docs/WORKLOG.md:四段工作记录(细化 / 高亮 / tooltip / 合并 bug)
         - scripts/reformat_reasons.py:AST-based 批量加 \n 工具,留作下轮兜底
      
      未提交产物(生成报告 + tmp 脚本,不入库):
        - data_dictionary/standard_fields_violations_report.md
        - scripts/_tmp_build_violations_md.py
      
      踩坑见 WORKLOG:
        - .el-tooltip__popper vs .el-popper(Element Plus 2.14.3 选择器)
        - and [] 短路求值返回 None(应为 or [] 或干脆删除)
        - show-overflow-tooltip 不可控,normalize 文本外层 CSS 救不回来
      1bb3ca98
  3. 13 Aug, 2026 19 commits
    • Data Governance Dev's avatar
      feat(web): 数据库类型切换自动套用预设 + 杀 8765 脚本 · 5db40025
      Data Governance Dev authored
      ## db_defaults 三套化
      
      用户反馈:「@db_defaults.yaml 现在这个文件里面由三套数据库配置,
      现在页面要改成切换数据库类型同时也要切换默认IP,端口,账户密码和数据库」
      
      ### 改动
      - web/configs/db_defaults.yaml —— 旧单 dict → 新三键 dict
        (mysql / dameng / oracle 各一套,含 port 字段;文件已在 .gitignore 安全)
      - web/api/routes.py /api/db-defaults —— 返回三套 JSON;
        兼容旧格式单 dict(用 _flat 包裹,前端识别后只填 mysql)
      - web/static/index.html —— 加 dbDefaults ref + DB_FALLBACK_PRESETS 兜底
        + _applyPreset(t);onDbTypeChange 之前只切 port(保留用户自定义),
        现在无条件套用预设全部 6 个字段(host/port/user/password/database/oracle_client_dir);
        loadDbDefaults 先缓存三套再按当前 db_type 套用
      
      ## scripts/kill_web.{sh,bat}
      
      杀掉 web 服务(默认端口 8765,可自定义):
      - kill_web.sh —— Git Bash + Linux/macOS 通用(netstat.exe / lsof 自动分支)
      - kill_web.bat —— Windows 原生 cmd 兼容
      
      退出码:
        0 杀掉占用进程成功 / 端口空闲
        1 端口已空闲(无需处理)
        2 杀进程失败
      
      ## 验证
      - curl /api/db-defaults 返回三套预设(端口 3306/5236/1521)✓
      - kill_web.sh 空闲端口返 1 / 占用端口返 0(实测杀 18999 PID 23160)✓
      - 静态资源 200 ✓
      - JS 结构平衡 ✓
      
      ## 踩坑
      - API 旧格式兼容:YAML 老结构(单 dict 平铺)→ 检测 value 不是 dict 时用 _flat 包裹
      - oracle_client_dir 仅 Oracle 有效,三套配置统一保留 key 占位
      - password 空串语义:'password' in preset 判定(保持与之前一致)
      5db40025
    • Data Governance Dev's avatar
      refactor(web): 去掉「部分|全量」radio,所有检查都跑全量 · 98604b82
      Data Governance Dev authored
      用户反馈:partial/full 选项不再需要,所有检查(包括用户自定义规则)
      都跑全量扫描。
      
      改动:
      - 删除每条 IND leaf 行的 <el-radio-group class="sample-scope">
      - 删除自定义规则卡片 header 的 <el-radio-group>
      - 删除 sampleScope ref / SAMPLE_PARTIAL_LIMIT / buildSampleLimitsForSubmit()
      - 删除 watch(analysisTree.groups) 里初始化 sampleScope 的循环
      - startJob() payload 不再发 sample_limits 字段
      - 删除 setup return 中的 sampleScope 相关导出
      - 删除 .sample-scope / .sample-scope--leaf / .custom-rule-sample CSS
      - .tree-row--group .group-description max-width 从 280px 放宽到 560px
        (radio 让位消失后,description 可以更长)
      
      后端零改动:sample_limit 参数链(models → job_manager → orchestrator
      → step7/step9)保留。前端不发 sample_limits → 后端默认 None = 全量扫描。
      
      附带 UI 改进:进度区显示「失败 N 步(...)」行 + 进度条部分失败变
      warning + 状态 tag 显示「completed (N 失败)」,避免静默失败误导用户。
      (对应 step6 length_check TypeError 的 bug 修复,wrapper 签名
      修改在 3dfd038c commit 已包含)
      98604b82
    • Data Governance Dev's avatar
      feat(standards): 表注释关键词默认值 + IND-016 去掉 -b 后缀 · 3dfd038c
      Data Governance Dev authored
      本次会话累计改动(5 个文件):
      
      standards_match.yaml — 表注释匹配关键词
        - IND-001-a/b/c/d (身份证)        : comment_keywords 默认 [身份证, 证件号码]
        - IND-002-a/b/c (统一社会信用代码) : comment_keywords 默认 [信用代码]
        - IND-004-a/b (行政区划)          : comment_keywords 默认 [行政区划]
        - IND-013-a (UI 显示 IND-017 单位类型) : 单位类别 → 单位性质
        - IND-013-c (UI 显示 IND-019 行业代码) : 关键词精简到 3 个
                                                (去掉 行业分类 / 国民经济行业)
        - IND-016-b → IND-016             : YAML key 改名
      
      standards/ind_016b_bank_account_format.py — standard_id 同步
        - standard_id 'IND-016-b' → 'IND-016'
        - docstring 同步更新
      
      web/core/orchestrator.py — 描述字典 key 同步
        - 'IND-016-b' → 'IND-016'
      
      web/configs/analysis_tree.json — UI step_id 同步
        - 'std_ind_016_b' → 'std_ind_016'
      
      docs/WORKLOG.md — 记录改动 + 踩坑
        - 单位性质重复问题
        - IND-016 改名后 smoke 验证结果
        - 行业单字被移除风险
      
      注:standards_match.yaml / orchestrator.py 里还有其他未提交的 keyword 精简
      (如 IND-003-a / IND-005-a / IND-006-a / IND-013-b / IND-101 / IND-201 / IND-202
      / IND-401 / IND-402),看着是之前会话留下没提交的,本 commit 一并带走。
      3dfd038c
    • Data Governance Dev's avatar
      feat(web): 自定义规则卡加「开始分析」按钮(与配置卡互为冗余入口) · f0802827
      Data Governance Dev authored
      需求:分析配置卡折叠时不必再点开它启动分析 → 自定义规则卡也加一个同样的按钮。
      
      实现(web/static/index.html 卡 2.5):
      - 复用 startJob(),disabled/loading 逻辑与配置卡完全一致
      - 按钮放在 <div v-show="!customConfigCollapsed"> 外面 → 卡片折叠时按钮也可见
      - 同时附「取消任务」按钮(运行中显示)
      
      CSS(web/static/style.css):
      - 新增 .card-footer-action(margin-top: 18px, flex row, gap 8px)
        视觉对齐配置卡里 <el-form-item> 的默认间距
      f0802827
    • Data Governance Dev's avatar
      docs(worklog): 数据字典浏览器分页改造 + EP 滚动事件 bug 修复记录 · 1398b020
      Data Governance Dev authored
      包含两段工作:
      1. 2026-08-13 数据字典浏览器动态分页 + 后端缓存复用
         - 后端 3 个分页端点
         - 前端状态机重写(删 tableSummary/dataDict 全量 ref)
         - selectAllTables/Invert 改调 all-table-names
         - CSS 隐藏两边表格的全选 checkbox
      2. 2026-08-13 数据字典浏览器滚动到底不增量刷新(bug fix)
         - 现象:滚到底不拉第二页
         - 根因:EP 2.14.3 + height 时内部 <el-scrollbar> 包裹 body,
           scroll 不冒泡到 el-table 根
         - 修复:直接在 .el-scrollbar__wrap 上挂原生 scroll 监听
      1398b020
    • Data Governance Dev's avatar
      feat(web): 数据字典浏览器动态分页(滚动加载 + 筛选重读 + 隐藏全选) · a0b10c06
      Data Governance Dev authored
      状态机重构:
      - 删 tableSummary / dataDict 全量 ref + 4 个前端过滤 computed
      - 新增 tableList/fieldList + page/hasMore/total/loading 共 10 个 ref
      - 新增 fetchTablesPage/fetchFieldsPage(防 stale 响应 + nextTick 后重挂 scroll)
      - 新增 onTablesScroll/onFieldsScroll:EP 2.14.3 + height 时 scroll 不冒泡到 el-table 根,
        改在 .el-scrollbar__wrap 上挂原生 addEventListener('scroll', { passive: true })
      - 新增 rebindDictScroll:每次 fetch + nextTick 后重挂兜底(el-table 重建 wrap 时失效)
      - 筛选 commit 时从后端重读第 1 页(applyTableSearch/applyFieldSearch)
      - watch(form.tables) 触发 fetchFieldsPage(1, true)(勾选表变化自动更新字段表)
      
      跨页勾选同步:
      - onTableSelectionChange 改为 set 合并(visible 名 + 新选中 → add;visible - 未选中 → delete;
        不在 visible 的保留)—— 旧实现会丢跨页勾选
      - 新增 restoreTableSelection:数据刷新后把 el-table 可见勾选与 form.tables 对齐
        (reserve-selection 在 :data 整体替换时失效,必须手动同步)
      
      按钮重写:
      - 全选 / 反选:调 /api/dict/all-table-names 拿全量匹配名字 → 设 form.tables
        → fetchTablesPage(1, true) 把所有匹配表拉回首屏
      - 清空:form.tables = [] + clearSelection()
      
      CSS:web/static/style.css
      - .dict-tables-table thead .el-checkbox, .dict-fields-table thead .el-checkbox
        { visibility: hidden; pointer-events: none; }
        (display:none 会算错表头高度)
      
      addCustomRule:去除 tableSummary 兜底(后端 /api/dict/fields 每行附 table_comment)
      
      踩坑:
      - EP 2.14.3 + height → <el-scrollbar> 包裹 body → @scroll 不触发,必须原生监听
      - selection-change 只返 visible 选中行,直接赋值丢跨页勾选 → set 合并
      - reserve-selection 在 :data 整体替换时失效 → 自写 restoreTableSelection
      a0b10c06
    • Data Governance Dev's avatar
      feat(backend): /api/dict/{tables,fields,all-table-names} 分页端点 + cache 复用 · 6cb0ffa7
      Data Governance Dev authored
      DataDictCache 之前只在 connect/test 写入;这次新增 3 个 GET 端点让前端按需切片:
      - GET /api/dict/tables?db_type=&host=&port=&user=&database=&page=&page_size=&q=
        → 分页返回 table_summary,每项附加 field_count(前端不再算)
      - GET /api/dict/fields?...&tables=t1,t2&page=&page_size=&q=
        → 分页返回 data_dictionary(按 tables 参数过滤),每项附加 table_comment
      - GET /api/dict/all-table-names?...&q=
        → 仅返名字列表,供前端「全选 / 反选」按钮使用(不分页)
      
      实现要点:
      - 全部走 DataDictCache.get_instance().get(cfg),命中即 list[a:b] 切片(微秒级)
      - cache miss 时现场抽一次(缺 password 抛 warning 让前端提示重连)
      - 多连接并存按 5 元组 (db_type, host, port, database, user) 区分 key
      - 排序:tables 按 table_name 字典序;fields 按 (table_name, ordinal_position)
        与旧前端 filteredFields 排序保持一致
      
      踩坑:
      - port=3306 默认参数必须放最末位(Python SyntaxError)
      - list_dict_fields 重复定义 host 别名导致 FastAPI 参数解析歧义 → 简化为单一 host 参数
      - list_columns SQL 不带 table_comment,/api/dict/fields 响应里要手动从 table_summary 关联
      6cb0ffa7
    • Data Governance Dev's avatar
      fix(custom-rules): 自定义规则结果「规则」列显示可读 SQL(替代 'tree' 字面量) · 21170b4b
      Data Governance Dev authored
      用户反馈:自定义规则命中明细表里「规则」列只显示 'tree',没有信息量。
      
      ## 改动
      - step9_custom_rules.py: 新增 _serialize_rule_human(group) 递归把条件树
        序列化为可读 SQL 形态字符串
        - 叶子: col LIKE '%X%' / col NOT LIKE '%Y%' / col > 10 / col < '2026-01-01'
        - 顶层组: children 用 AND/OR 串接;单 child 不加括号
        - 嵌套组: (children) 加括号让优先级清晰
      - 每条 entry 增加 rule_text 字段(common dict);删除无意义的 rule_type 赋值
      - ColumnSpec: prop 'rule_type' → 'rule_text';render tag → code(等宽字体)
        ;min_width 120 → 240
      - step8_report._md_custom_value_check / docx 版同步:
        - 去掉「关键字」列(v1 字段,v2 已不存在)
        - 「规则」列改用 rule_text
      
      ## 端到端验证
      mock DB 跑一条含嵌套组的规则:
        输入: AND(contains(X), OR(contains(Y), not_contains(Z)))
        rule_text: 'col LIKE \'%X%\' AND (col LIKE \'%Y%\' OR col NOT LIKE \'%Z%\')'
        真实 SQL: '... WHERE (`id_card` LIKE %s ESCAPE \'!\' AND (`id_card` LIKE %s ESCAPE \'!\' OR `id_card` NOT LIKE %s ESCAPE \'!\')) LIMIT 100'
      显示与真实 SQL 语义一致;区别仅是显示用 'col' 占位列名(方便看),真实 SQL 用 quote_ident。
      
      ## 踩坑
      第一版递归在父循环对子组额外包括号 '(" + walk() + ")',而 walk(is_top=False)
      内部对嵌套组已经返回带括号形式 → 嵌套组变成 '((col < 5 OR col = 100))'。
      修法:用 is_top 参数让递归本身决定是否加括号,调用方不再重复加。
      教训:写递归字符串拼接时给一个 is_root / is_top 参数控制顶层 vs 嵌套行为。
      21170b4b
    • Data Governance Dev's avatar
      feat(governance): 抽样范围 partial/full radio(per-IND 独立控制) · 23ebacc6
      Data Governance Dev authored
      用户需求:针对特定字段的分析(国标字段规范、业务字段规范、用户自定义规则)
      希望可切换「部分(前 1000 行)抽样 / 全量扫描」,且每个分析项独立配置(A 项选部分,
      B 项可独立选全量)。
      
      ## 后端
      - 新增 web/core/sql_utils.py: apply_sample_limit(sql, sample_limit, db_type)
        - sample_limit=None  → 移除末尾 LIMIT N / AND ROWNUM <= N(全量扫描)
        - sample_limit=int   → 保留原样(partial 模式)
        - 三方言均覆盖:MySQL / 达梦(标准 LIMIT)/ Oracle 11g(AND ROWNUM <= N)
      - models.ConnectRequest 新增 sample_limits: dict[str, int | None]
      - job_manager.submit 透传 sample_limits 给 orchestrator
      - orchestrator.run_governance_workflow 新增 sample_limits kwarg;按 step_id 取值
        分发给各 _run_* 闭包
      - step7_standards._run_round1/2/3_* 全部加 sample_limit 参数:渲染 SQL 后用
        apply_sample_limit 二次处理(partial→加 LIMIT 1000,full→剥 LIMIT)
      - step9_custom_rules.run_step_custom_value_check 加 sample_limit 参数:
        SQL 构造按 None / oracle / else 三分支
      
      ## 前端
      - index.html sampleScope ref + SAMPLE_PARTIAL_LIMIT 常量
      - 每个 IND-XXX leaf 行(checkbox 之后、字段名输入框之前)加 partial/full radio
        - key = step_id(每个 IND 独立),不再按 group 共享
        - 标签去掉了「1000」后缀,仅显示「部分 / 全量」
      - 自定义规则卡片保持 card-level 单个 radio(共享 custom_value_check step_id):
        step9 后端所有规则共用一个 LIMIT,要下沉需另改接口
      - watch(analysisTree.groups) 加载后为每个 step_id 初始化 sampleScope='partial'
      - buildSampleLimitsForSubmit() 把 sampleScope 转成后端要的 {step_id: int|None}
      - startJob() payload 加 sample_limits 字段
      - style.css 新增 .sample-scope--leaf(margin-left: 8px,紧贴字段名输入框)
      
      ## 端到端验证
      - 用户在 IND-001/002/003 选全量、IND-004 选部分 → payload 正确:
        {std_ind_001: None, std_ind_002: None, std_ind_003: None, std_ind_004: 1000}
      - Pydantic ConnectRequest 解析通过;类型 [(str, 'NoneType'/'int'), ...]
      - 三方言 × partial/full × 多种 SQL 形态,行为符合预期
      
      ## 踩坑
      edit 工具改函数签名+docstring 时只换首行 → 留孤儿 """ → SyntaxError。
      教训:edit 改函数签名 + docstring 时,把整个 docstring 完整贴一遍。
      23ebacc6
    • Data Governance Dev's avatar
      docs(worklog): Oracle 自定义规则踩坑(ORA-01036/00933)+ 多 tab UX 改造 · 39f5a4fb
      Data Governance Dev authored
      新增 2026-08-13 条目,覆盖 6 块改动:
      
      1) ORA-01036: illegal variable name/number
         - sql_builder 历史 Oracle 路径输出 qmark ?,但 python-oracledb 不支持
         - Bind.next_idx 加 numbered :1/:2/... 占位符
      
      2) ORA-00933: SQL command not properly ended
         - step9 无条件 LIMIT 200,Oracle 11g 不支持
         - 截断子句分支:Oracle 走 WHERE ROWNUM <= N
      
      3) 中间 bug:Oracle 分支漏 WHERE 关键字
         - 静态验证三方言 SQL 时暴露,立即补 WHERE
         - 教训:跨方言分支必须同一组测试数据验证
      
      4) evalPathExpr 不支持 dict 索引
         - 设计 data.matches_rule_<idx> 扁平字段避开 this.x[key] 语法
         - 教训:协议路径表达式先看支持语法再设计数据结构
      
      5) flatResultRows 折叠表聚合踩坑
         - 顶层 summary 是 section 共享的,按 tab key 前缀识别 custom_value_check_<idx>
      
      6) UX:默认名「自定义规则N」
         - nextDefaultRuleName() 扫已用名,找最小可用 N
         - 后端兜底回落 <table>.<column>(不再用 (未命名))
      39f5a4fb
    • Data Governance Dev's avatar
      feat(backend+web): 自定义规则每条独立 tab + 默认名「自定义规则N」 · 90e89ed5
      Data Governance Dev authored
      两个用户反馈:
      
      1) 自定义规则命中明细:原来 N 条规则塞进 1 个 tab,规则一多翻不到。
         改为每条规则单独占 1 个 tab:
           - key = custom_value_check_<idx>(idx 从 1 开始,与前端卡片顺序一致)
           - title = <rule_name>(<table>.<column>)
           - summary alert:成功显示"本规则命中 N 行";失败显示"执行失败:**错误**"(红 alert)
           - table source = this.matches_rule_<idx>(扁平命名)
         失败规则也出 tab(alert 显示错误),用户能直接看到为什么失败。
      
      2) 新建自定义规则时输入框默认「自定义规则N」,N 从已用编号集合里找最小可用,
         用户手动改名后 N 仍递增不会撞名。
      
      数据 / 前端配套:
      - 后端 data 顶层加 matches_rule_<idx> / error_rule_<idx> / matched_rule_<idx> 三组扁平字段
      - 为什么不走 dict 索引(this.by_rule['rule_X']):前端 evalPathExpr 是简单属性路径
        (this.x.y.z),不识别 [key] 语法,扁平命名最干净
      - 前端 flatResultRows 识别 custom_value_check_<idx> 前缀的 tab:命中数从
        matched_rule_<idx> 取,检查数固定 1(每条规则 = 1 个字段)
      
      静态验证(mock 两条规则,1 ok + 1 ORA-00933 失败)已通过:
        tabs: [
          {key:custom_value_check_1, type:info,  vars:{matched:this.matched_rule_1}},
          {key:custom_value_check_2, type:error, vars:{error:this.error_rule_2}}
        ]
      
      WORKLOG 待用户在 Oracle 端实跑自定义规则验证后追加(不阻塞提交)
      90e89ed5
    • Data Governance Dev's avatar
      fix(backend): Oracle 自定义规则 ORA-01036 + ORA-00933 · f4903d81
      Data Governance Dev authored
      两个 Oracle 专属问题,连续两次跑自定义规则暴露:
      
      1) ORA-01036: illegal variable name/number
         - 原因:sql_builder._placeholder 旧版 Oracle 路径输出 '?',但 python-oracledb
           不支持 qmark 占位符(thin 模式不会自动转 :N,必须显式给 numbered)
         - 修复:Bind 加 next_idx;Oracle 路径按递增编号输出 :1, :2, ...,与
           bind.params 顺序一一对应
      
      2) ORA-00933: SQL command not properly ended
         - 原因:step9_custom_rules 无条件拼 'LIMIT 200',Oracle 11g 不支持 LIMIT
           (12c 引入 FETCH FIRST;11g 只能用 WHERE ROWNUM <= N)
         - 修复:截断子句按 db_type 分支,Oracle 走 WHERE ROWNUM <= 200
      
      中间 bug:Oracle 分支漏写 WHERE 关键字(FROM "tbl" "col" LIKE :1 ...),
      静态验证脚本(三个方言各跑一遍)暴露后补上 WHERE。
      
      静态验证 SQL:
        MySQL  : SELECT `COL` FROM `TBL` WHERE `COL` LIKE %s ESCAPE '!' LIMIT 200
        达梦   : SELECT "COL" FROM "TBL" WHERE "COL" LIKE ?  ESCAPE '!' LIMIT 200
        Oracle : SELECT "COL" FROM "TBL" WHERE "COL" LIKE :1 ESCAPE '!' AND ROWNUM <= 200
      
      WORKLOG 待用户在 Oracle 端跑自定义规则验证后追加(不阻塞提交)
      f4903d81
    • Data Governance Dev's avatar
      refactor(web): 连接数据库卡片重排版(拆双 form + 两行布局 + 端口 input + 紧凑化) · ce27e205
      Data Governance Dev authored
      把原本 3 行布局的「连接数据库」卡片重排为 2 行独立 form,结构更清晰
      且整体更紧凑。
      
      主要改动:
      
      1. 拆成两个独立的 <el-form>
         - 第一个 form 只包「数据库类型」(3 个 radio-button)
         - 第二个 form 包「主机 IP / 端口 / 用户名 / 密码 / 数据库名 / 字符集」+
           测试连接按钮 + 结果 alert
         - 共享同一个 reactive form 对象,校验 / 重置不受影响
         - 两个 form 之间用 margin-top: 12px 留白(不用 hr 不用 divider)
      
      2. 切到 inline form 模式
         - :inline="true" + label-width="auto" + label-position="right"
         - label 和控件同一行(不再是 label 上方 + 控件下方占两行)
      
      3. span 重新分配(合计 24)
         - 主机 IP: 5(缩到刚好显示 192.168.20.196)
         - 端口: 3(数字 input)
         - 用户名: 2(用户名通常短)
         - 密码: 3(含眼睛图标)
         - 数据库名: 4(schema 名长度可变)
         - 字符集: 7(select + 下拉箭头占空间)
      
      4. 端口字段改造
         - 从 el-input-number 改 el-input(用户偏好)
         - v-model.number 保证后端拿到 int(Pydantic cfg.port: int 兼容)
         - @input 过滤非数字字符(避免 Pydantic "not a valid integer")
      
      5. 解决 inline form 下 select/input 撑不满 col 的问题
         - 给每个 el-form-item 加 display: inline-flex; align-items: center; width: 100%
         - 让 form-item 强制撑满 el-col 内部,input/select width:100% 才能真正展开
         - 之前只加 width:100% 不够,因为 inline form 下 form-item 默认 inline-block
           宽度 = max(label, content),select 会按内容自适应而不是 col 宽
      
      6. gutter 从 20 → 12(列间距减半)
      
      调整过程踩坑(避免再走):
      - inline form 下 el-form-item 默认 inline-block → 不会撑满 el-col
      - 单纯给 input 加 width:100% 不够 → form-item 本身也要撑满
      - 终极方案是 form-item 用 inline-flex + width:100% 让内部 flex 自动展开
      ce27e205
    • Data Governance Dev's avatar
      docs(worklog): Oracle 端到端打通踩坑汇总(4 项) · b427992c
      Data Governance Dev authored
      之前已分别记录了 5 个 Oracle 相关条目(放开 Oracle / connect_timeout /
      DPY-3010 / 路径外置 / DPI-1047 PE 解析)。本条目汇总本轮新加的 4 个修复:
      
      1. health SQL 不分方言 → ORA-00923(SELECT 1 不 FROM)
      2. 前端 UI 隐藏 Oracle Client 输入框
      3. 抽数据字典 ORA-00904 → 11g ALL_TABLES 实际可用列清单
      4. 抽数据字典 0 行 → service_name vs schema 名混淆
      
      含关键对照表:
      - MSVC 版本 vs MSVCR DLL(VC++ 2013 Redist 是关键)
      - MySQL/达梦/Oracle 的 schema 名语义差异
      b427992c
    • Data Governance Dev's avatar
      feat(web): 隐藏前端 Oracle Client 输入框(路径改走 db_defaults.yaml) · 2a9cf418
      Data Governance Dev authored
      Oracle Instant Client 路径不再让用户在 UI 填,改为:
      - 配置文件:web/configs/db_defaults.yaml 的 oracle_client_dir
      - 前端通过 GET /api/db-defaults 读取,注入 form.oracle_client_dir
      - 测试连接时 ...form 展开自动带上,后端 cfg.oracle_client_dir 拿到值
      - UI 上完全看不到该输入框
      
      修改路径的新流程:改 yaml → 重启 web 服务(sql_loader/db_defaults 不热加载) → 测连接。
      
      state 字段 form.oracle_client_dir 保留(作为 form 数据载体);
      loadDbDefaults() 注入逻辑保留(只是 UI 不展示)。
      2a9cf418
    • Data Governance Dev's avatar
      feat(backend): Oracle 端到端打通(thick + health + 11g 兼容 + schema 名修正) · fd098416
      Data Governance Dev authored
      Oracle 11g (11.2.0.4) 数据库连接抽数据字典端到端跑通,解决 4 个独立问题:
      
      1. connect_timeout → tcp_connect_timeout
         oracledb 1.4.2+ 移除了 connect_timeout kwarg(之前误以为兼容),
         改成 tcp_connect_timeout;报错日志加 inspect 自动定位兼容 kwarg。
      
      2. thick 模式加载 + DPI-1047 深度诊断
         - _ensure_oracle_client() 解析 oci.dll 的 PE 导入表,自动列出
           实际依赖的运行时 DLL(如 MSVCR120.dll → VC++ 2013 Redist)
         - DPY-3010(thin 不支持老 Oracle)日志加针对性安装指引
         - 11.2.0.4 必须 thick 模式(thin 不支持 11.2)
      
      3. 健康检查 SQL 分方言
         新建 check_connection.oracle.sql 写 SELECT 1 FROM dual;
         Oracle 严格执行 SQL 标准,不像 MySQL/达梦 兼容裸 SELECT 1。
         sql_loader 按 <name>.<dialect>.sql 优先 + .sql 回退 自动分流。
      
      4. ALL_TABLES 11g 列兼容性
         修 list_tables.oracle.sql:
         - data_length 用 t.BLOCKS * 8192 估算(11g 没 BYTES 列,12c+ 才有)
         - create_time / update_time 取 NULL(11g 没 CREATED/LAST_DDL_TIME,12c+ 才有)
         - 注释贴了 11.2.0.4 ALL_TABLES 完整可用列清单(用户 DESC 确认)
      
      5. schema 名传递修正
         data_dict.py 之前对所有数据库都传 cfg.database 给 list_tables/list_columns,
         但 Oracle 体系里 ALL_TABLES.OWNER 是用户名(=cfg.user),不是 service_name。
         加 cfg.db_type == 'oracle' 分支:schema_name = cfg.user
      
      6. /api/db-defaults 加 oracle_client_dir
         路径从 web/configs/db_defaults.yaml 预填,前端可隐藏输入框。
      
      验证日志:
        [DB] Oracle Instant Client 已加载(thick 模式)lib_dir=...
        [DB] 连接已建立(耗时 ~100ms)
        [DB] 测试连接成功
        [Cache] 写入数据字典: (表 N 张, 字段 M 个)
      
      踩坑详见 docs/WORKLOG.md(2026-08-13 Oracle 端到端打通条目)。
      fd098416
    • Data Governance Dev's avatar
      refactor(web): 收敛分析项 UI 至 3 组(hide/merge/rename 6 轮) · e7fb2a8c
      Data Governance Dev authored
      UI 从 7 组 / 30+ step 收敛到 3 组 / 15 step;隐藏 27 个 indicator。
      
      合并 / 改名为独立 IND 号(移入 standards 组):
      - IND-401 / IND-402 → std_ind_401(姓名校验,2 子检查合一)
      - IND-006-b → std_ind_006(邮政编码)
      - IND-013-a / -b / -c → std_ind_017 / -018 / -019
        (单位类别 GB/T 12402 / 经济类型 国统字〔2011〕86 号 / 行业代码 GB/T 4754)
      
      隐藏 27 个 indicator(_HIDDEN_SUBS,暂离 UI,按需恢复):
      - IND-016-a / -101 / -201..-204 / -301 / -302 / -501 / -502
      - IND-601..-603 / -901 / -902
      - IND-006-a / -008-a..-011-a(其他业务字段整组下架)
      - IND-013-a..-c(已改名)
      - IND-012-a / -014-a / -014-b / -015-a(单位法人经办人整组下架)
      
      整组下架(5 个 group):
      - 单位对公账户 字段规范
      - 民政信息
      - 证件信息
      - 其他业务字段
      - 单位 / 法人 / 经办人 字段规范
      
      新增 / 重命名 group:
      - 业务字段规范(含 std_ind_401 姓名 + std_ind_007_a 公积金账号)
      
      后端改动:
      - 抽 _run_standards_ind_renamed(source_id, target_step_id, target_title) 工厂
        合并 IND-005/006/013 的改名逻辑
      - _run_standards_combined factory 处理 std_ind_401 合并子检查
      - _IND_COMBINED['ind_401'] 配置(IND-401/IND-402 字符集 + 长度合一)
      - _MERGED_SUBS / _HIDDEN_SUBS / mapped_step 同步更新
      
      前端 / 配置:
      - analysis_tree.json: 7 组 → 3 组;description / default_expand 同步精简
      - routes.py /api/match-config: _COMBINED_GROUPS 聚合 + IND-005/006/013 改名映射
      
      docs(WORKLOG): 6 轮完整记录 + 踩坑(log 闭包 bug 修复、sub_prefix 对无后缀 ID 的适配等)
      
      UI 顺序:基础检查 → 国标字段规范(10 step)→ 业务字段规范(2 step)
      e7fb2a8c
    • Data Governance Dev's avatar
      feat(standards): IND-002/003/004 合并 + IND-005 改名(去 -a) · a72a2ec1
      Data Governance Dev authored
      需求:把 IND-002(USCC 3 子)/ IND-003(手机号 2 子)/ IND-004(行政区划 2 子)
      也和 IND-001 一样合并成单 step;IND-005(固定电话,1 子)UI 不再显示 -a 后缀。
      
      改动:
      - step7_standards.py: 把 IND-001 专属的合并逻辑通用化为配置驱动
        - _IND_COMBINED: {parent_id: {sub_ids, title, format}} 配置表(覆盖 ind_001/-002/-003/-004)
        - _wrap_combined_ind_001 → _wrap_combined_indicator(parent_id, ...)
        - run_step7_for_ind_001 → run_step7_combined(parent_id, ...)
        - 旧名保留为薄包装(backward compat)
      - orchestrator.py:
        - _MERGED_SUBS 扩展到 12 个子指标(4+3+2+2+1)
        - _run_standards_combined(parent_id) 工厂 + _COMBINED_STEP_META 注册表
        - 循环注册 std_ind_001/-002/-003/-004 四个 step
        - _run_standards_ind_005 端到端改 4 处:section_key / step_id / tab.key / tab.title
      - analysis_tree.json: 标准组 7 行 → 5 行(去掉 -a/-b/-c 后缀)
      - routes.py: _COMBINED_GROUPS 4 组聚合 + IND-005 单独处理(YAML key 仍叫 IND-005-a)
      - WORKLOG 追加整段记录 + 踩坑说明(IND-005 改名必须 4 处一致)
      a72a2ec1
    • Data Governance Dev's avatar
      feat(standards): IND-001 a/b/c/d 合并为单分析项目 + 4 子检查合一 · ba75ed1b
      Data Governance Dev authored
      需求:勾一个 IND-001 checkbox 跑全部 4 子检查;
      结果合并展示,单条违规里显示「哪些子检查失败」。
      
      改动:
      - step7_standards.py: 新增 _IND_001_SUB_IDS / _merge_violations_by_tuple
        / _wrap_combined_ind_001 / run_step7_for_ind_001,单 (table,col,value)
        多子检查失败行合并,rule_type 列改为 'IND-001-a, IND-001-b',
        error 列改为 '[a] 长度 19 ≠ 18\n[b] 校验位错误' 拼接原文
      - orchestrator.py: 注册 std_ind_001 step(order=100,llm=none),
        跳过 IND-001-a/b/c/d 自动注册,避免 4 个独立 section 还在
      - analysis_tree.json: 国标字段规范组删 4 行 IND-001-a/b/c/d,加 1 行 std_ind_001
      - routes.py: /api/match-config 过滤未注册为 step 的子 indicator;
        把 IND-001 a/b/c/d 的 applies_to_fields / comment_keywords 聚合到 std_ind_001
        的输入框,避免合并后前端输入框丢失
      - 修复 double-wrap bug:_run_standards_ind_001 不再二次包裹
        run_step7_for_ind_001 原返回值(已含 {section_key, data})
      - WORKLOG 追加 4 段:合并设计 / 关键词输入框回归 / 标题 '合并 a/b/c/d' 去除 /
        结果不显示修复(double-wrap 根因 + 烟测)
      ba75ed1b
  4. 12 Aug, 2026 13 commits
    • Data Governance Dev's avatar
      docs(worklog): 自定义规则 icon + 卡片 header 点击折叠 + 后端 2 bug 修复记录 · b968bb24
      Data Governance Dev authored
      - 改 1:自定义规则卡 icon 换 Operation(之前 MagicStick 渲染不出来)
      - 改 2:4 个卡片 header 点击折叠 + 按钮 .stop(卡 1 / 2 / 2.5 / 3)
      - 改 3:sql_builder 数值比较符强制 float 避免达梦字符串解析为 0.0 坑
      - 改 4:step9 SummarySpec template 改双花括号与前端 renderSummary 匹配
      b968bb24
    • Data Governance Dev's avatar
      fix(backend): step9 SummarySpec template 改双花括号与前端 renderSummary 匹配 · 57c088a1
      Data Governance Dev authored
      - 现象:「自定义规则命中明细」tab 顶部 alert 显示「执行 **{total}** 条规则...」花括号没替换
      - 根因:step9 template 用单花括号 {total},前端 renderSummary 正则只匹配 {{ var }} 双花括号
      - 修复:template 改 {{total}} 双花括号(与其他 step 风格一致:step4 / step5 / step6 / step7)
      - 修后:执行 **1** 条规则,有效 **1** 条,命中 **0** 行(...)
      57c088a1
    • Data Governance Dev's avatar
      fix(backend): sql_builder 数值比较符强制 float 避免达梦隐式转换坑 · 3c2ac416
      Data Governance Dev authored
      - 现象:自定义规则 GRJCJS > 5000 命中 38 行全是 0.0
      - 根因:value 是字符串 '5000',达梦 SQL WHERE GRJCJS > ? 收到字符串 '5000' 后做字符串 vs
        DECIMAL 比较,部分达梦版本把 '5000' 解析为 0.0(字符串解析失败回退),变成 WHERE GRJCJS > 0.0
      - 修复:编译 gt/lt/eq 时 bind.params.append(float(val)) 强制数值化;非法值返回空字符串
        让上层跳过
      - 日期:date_before / date_after 保持 str(val)(达梦 / Oracle DATE 比较认字符串 YYYY-MM-DD)
      3c2ac416
    • Data Governance Dev's avatar
      refactor(web): 自定义规则 icon 换 Operation + 卡片 header 点击折叠 · e68c46a8
      Data Governance Dev authored
      - 自定义规则卡 icon:MagicStick SVG 渲染不出来 → 改用 Operation(扳手+齿轮,贴合自定义规则语义)
      - 4 个卡片 header 点击折叠:连接数据库 / 分析配置 / 自定义规则 / 数据字典浏览器
        - CSS 加 .collapsible-header { cursor: pointer; user-select: none; } + hover 灰底
        - 整个 .card-header 是点击区,@click 切换折叠
        - 内部按钮加 @click.stop 防止冒泡(全选/清空/反选/折叠 按钮)
      - 分析进度 / 分析结果 卡片无折叠按钮,本轮不动
      e68c46a8
    • Data Governance Dev's avatar
      docs(worklog): 自定义规则 v2 条件树改造 + 端到端联调 3 bug 修复记录 · d83cf947
      Data Governance Dev authored
      - 记录需求、设计决策(多层递归 / 日期只支持具体日期 / 3 类字段 7 算子)
      - 记录 3 个新后端文件职责 + step9 重构 + NUMERIC_TYPES / DATE_TYPES + orchestrator 兼容
      - 记录前端 UI 重构(递归组件 <condition-tree> + field-block 排版 + addCustomRule 透传)
      - 记录端到端联调 3 个 bug 修复:
        1. fieldClassTagType 未 setup return 导致渲染崩溃
        2. 字段注释 / 表注释没显示(row 不带 → 兜底查 tableSummary)
        3. orchestrator 只认旧 payload user_input,v2 group 树不追加 custom_value_check 步骤
      d83cf947
    • Data Governance Dev's avatar
      feat(web): 自定义规则卡条件树 UI + 字段类型分类 + 字段注释排版 · cd2c1475
      Data Governance Dev authored
      把单条 el-table 行(含 1 个 el-input 关键字)重写为 div + CSS Grid 4 列布局。
      
      - 字段类型 → 比较符映射(前端镜像 web/core/rule_types.py)
        - NUMERIC_TYPES_FRONT / DATE_TYPES_FRONT / TEXT_TYPES_FRONT 三集合
        - classifyField(dataType) → text/numeric/date/unknown
        - COMPARATORS_FRONT / INPUT_HINT_FRONT 按字段类分发
        - fieldClassTagType(dataType) → 数值 warning / 日期 info / 字符 success
      
      - 全新递归组件 <condition-tree>
        - app.component('condition-tree', { name: 'ConditionTree', ... })
        - props: node(默认空 group) / column / dataType / depth
        - 渲染:group 节点显示 AND/OR radio + 项数 + 「+ 子条件 / + 嵌套组」按钮
        - 渲染:leaf 节点显示 comparator select + value input + × 删除
        - emits: change / remove
      
      - 列表 div 替代 el-table
        - 4 列 grid:规则名称 / 对象·字段·类型 / 条件树 / 操作
        - .field-block 容器:表名 + 表注释 / 字段名 + 类型 + 字段注释 inline 排
        - .field-block--field dashed border-top 视觉分隔两行
      
      - addCustomRule 改造
        - 透传 row.data_type / row.column_type(决定可用比较符)
        - 初始化 group = { kind: 'group', op: 'AND', children: [] }
        - table_comment 兜底查 tableSummary(字段行 row 不带)
        - 自动展开卡片(customConfigCollapsed = false)
      
      - buildCustomRulesForSubmit 改读新结构
        - hasValidLeaf(node) 递归判断:跳过空树
        - 输出包含 {rule_name, table_name, column_name, data_type, group_op, group}
      
      - 修复 2 个调试 bug
        - fieldClassTagType 是模块作用域函数,模板调用须 setup() return 出来
        - <condition-tree> props.node 加 default 兜底,避免 rule.group undefined 渲染崩溃
      cd2c1475
    • Data Governance Dev's avatar
      feat(backend): NUMERIC_TYPES / DATE_TYPES + orchestrator 识别 v2 条件树 payload · 0967e522
      Data Governance Dev authored
      - web/core/db_adapter.py
        - 新增 NUMERIC_TYPES / DATE_TYPES frozenset(紧挨 TEXT_TYPES)
        - 覆盖 MySQL / 达梦 / Oracle 三方言的常见数值 + 日期类型
      
      - web/core/orchestrator.py
        - 修 bug:"自动追加 custom_value_check 步骤" 判断只认旧 payload {user_input}
        - v2 payload 用 group 树结构 → 永远 False → main_steps=[] → 0 步跑
        - 新增 _has_effective_leaf(node) 递归判断:新旧 payload 都认
        - 修后:steps=[] + 1 条有效规则 → 自动追加 custom_value_check → 跑 200 行命中
      0967e522
    • Data Governance Dev's avatar
      feat(backend): 新增 rule_types / like_util / sql_builder + step9 重构支持条件树 · 7563ac51
      Data Governance Dev authored
      自定义规则 v2 后端核心:把单条 LIKE 升级为递归条件树。
      
      - web/core/rule_types.py(新)
        - classify_field(data_type) → text/numeric/date/unknown
        - COMPARATORS_BY_CLASS / DEFAULT_COMPARATOR / INPUT_HINT_BY_CLASS
        - 文本 2 算子(contains / not_contains);数值 3 算子(gt / lt / eq);日期 2 算子(date_before / date_after)
      
      - web/core/like_util.py(新)
        - escape_like(s) + ESCAPE_CHAR = '!'(跨 DB 一致,避开达梦 [CODE:-6106])
        - 从 step9 内嵌函数上提,从此模块 import
      
      - web/core/sql_builder.py(新)
        - build_where(node, bind, column_quoted, db_type) 递归编译 group 树
        - _placeholder(db_type) MySQL %s / 达梦+Oracle ?
        - 顶层 compile_rule(group, column_quoted, db_type) → (clause, params)
      
      - web/core/step_impl/step9_custom_rules.py
        - 主循环重写:每条规则编译 group 树 → 跑 SQL → LIMIT 200 命中
        - _normalize_rule 自动包旧 payload {rule_type, user_input} → 新 group 树,兼容旧调用
        - 摘要字段补齐:total_rules / executed_rules / skipped_empty_keyword / skipped_no_valid_leaf / failed_rules / total_matched_rows / violations / fields_checked
      7563ac51
    • Data Governance Dev's avatar
      refactor(web): 自定义规则卡 startJob 后自动折叠 + Filter 换 MagicStick ✨ · 02a8c7ab
      Data Governance Dev authored
      【折叠】
      [web/static/index.html:1619-1624](web/static/index.html#L1619-L1624) startJob()
      成功回调里追加 customConfigCollapsed.value = true,跟另外 3 张配置卡
      (连接 / 分析配置 / 数据字典浏览器)行为一致 —— 让视觉焦点落到
      「分析进度」和「分析结果」上。
      
      注释里的「3 张」改为「配置卡」(表述更准确)。
      
      【icon】
      [web/static/index.html:366](web/static/index.html#L366) 自定义规则 header
      icon 从 Filter(漏斗)换成 MagicStick ✨(魔法棒):
      - 视觉权重更高,16px 下也比 Filter 显眼
      - 语义贴合「自定义 = 用户施展的小魔法」
      - 不与其他三张卡冲突:Connection / Setting / Document / MagicStick ✨
      - 已 grep 确认 Element Plus icons-vue v2.3.2 IIFE bundle 导出 MagicStick
      
      【WORKLOG】
      docs/WORKLOG.md 顶部追加两条记录说明上述两个改动。
      02a8c7ab
    • Data Governance Dev's avatar
      feat(web): 自定义规则端到端 + 空 steps 区分 None/[] · 4b694b62
      Data Governance Dev authored
      将「数据字典浏览器 → 字段表 + 号 → 累积自定义规则 → 后端跑 LIKE 检索」打通完整链路。
      
      【新增】
      - web/core/step_impl/step9_custom_rules.py:每条规则 SELECT col FROM tbl
        WHERE col LIKE '%kw%' ESCAPE '!' LIMIT 200;跨 DB 占位符
        (mysql=%s / dmPython=oracledb=?)、统一 '!' 避免达梦 [CODE:-6106];
        每条 SQL 命中行 = 1 个 entry(不做 distinct,重复值并列展示)
      - orchestrator 注册 custom_value_check 步骤(hidden=True,前端不展示;
        提交 non-empty custom_rules 时自动追加)
      - models.ConnectRequest.custom_rules 字段
      
      【修改】
      - job_manager:区分 None(跑全部)vs [](显式空选择),同步 orchestrator 语义
      - orchestrator.run_governance_workflow:同上 + 接受 custom_rules 参数
      - step8_report:自定义规则报告渲染改读 matches[](7 列:规则名称/表名/
        字段名/匹配值/规则/关键字/错误;删除「命中行」列)
      - index.html:分析配置卡 + 自定义规则卡 UI 联动
      - docs/WORKLOG.md:上述变更的工作记录
      
      【为什么需要整体提交】
      orchestrator 的 steps 语义修正 + custom_rules 注入 + job_manager 同步 +
      step9 执行 + step8 渲染 + models 字段,每一块独立提交都会留下 broken
      intermediate commit。
      4b694b62
    • Data Governance Dev's avatar
      feat(web): 字段匹配规则外置到 YAML + 检查项自定义输入框 + 卡片折叠 · b95def37
      Data Governance Dev authored
      匹配规则外置:
      - 新增 web/configs/standards_match.yaml(44 个 indicator + 14 条 length 规则)
      - 新增 web/core/match_config.py:线程安全加载 + get_indicator_match / get_length_rules / merge_user_override
      - step6 / step7 走 YAML + 用户运行时 override 三级 fallback(用户输入追加而非替换)
      - ConnectRequest 新增 match_overrides: dict[str, dict[str, list[str]]]
      - 新增 GET /api/match-config:返回前端输入框默认值(逗号分隔格式)
      
      前端检查项 2 个输入框:
      - 每行 leaf 后挂「字段名 / 字段注释」2 个 el-input
      - loadMatchConfig() 启动时拉 YAML 默认值灌进 form.match_overrides
      - buildMatchOverridesForSubmit() 提交时把字符串转 list(Pydantic 期望 list[str])
      - 跨字段 indicator(IND-301/302/901/902)UI 隐藏输入框(_skip: true)
      
      卡片折叠 + 动画:
      - 连接数据库 / 分析配置 / 数据字典浏览器 三张卡都加折叠按钮 + Vue transition
      - startJob() 成功后三张卡自动折叠,焦点落到「分析进度」
      - el-card__body 折叠时 padding 上下 1px(默认 20px),padding 加 0.28s 过渡
      - el-card__header 折叠时 padding 6px,margin-bottom 折叠时 8px
      - i 图标移到输入框右侧
      - progress-block margin 改为 0
      
      Bug fix:
      - testConnection 也走 buildMatchOverridesForSubmit()(否则 names/comments 是 string → 422)
      - inline <style> 全局 CSS 不能用 :deep(),全部改为直接选择器
      
      WORKLOG 详细记录所有决策点。
      b95def37
    • Data Governance Dev's avatar
      refactor(web): 布局调整 + 还原字段名/注释关键字匹配 + 删除字段 checkbox · a0c39eb1
      Data Governance Dev authored
      按 2026-08-12 用户反馈:
      - 「分析配置」卡片上移到「连接数据库」下方、「数据字典浏览器」上方
      - 还原回旧版「字段名 + 字段注释关键字模糊匹配」自动选字段行为
      - 删除右表格字段 checkbox 及全链路 column_filter
      
      前端 (web/static/index.html):
      - 卡片顺序:连接数据库 → 分析配置 → 数据字典浏览器 → 进度 → 结果
      - 删右表格 selection 列、工具栏(全选/清空/反选)、fieldsTableRef、form.columns
      - startJob() 不再带 columns,只看 tables.length
      
      后端:
      - web/core/models.py: 删 ConnectRequest.columns
      - web/core/job_manager.py: 不再透传 columns
      - web/core/orchestrator.py: 移除 columns / column_filter 构造与参数
      - 6 个 step 文件(step2/4/5/6/7)移除 column_filter 参数
      - step7_standards.py: 恢复 _collect_hit_columns + has_name/has_cmt 守卫
      
      文档:
      - docs/WORKLOG.md: 追加本次记录
      a0c39eb1
    • Data Governance Dev's avatar
      refactor(web): 分析配置默认全部不勾选 + 默认全部折叠(含实时日志) · 8728514f
      Data Governance Dev authored
      - loadSteps():去掉 form.steps 默认全选,只保留 hidden step 兜底过滤
        required 步骤仍在 startJob() 里自动补勾
      - expandedGroups:初始化为空 Set,原 watcher 不再消费
        analysisTree.json 的 default_expand 自动展开
      - logExpanded:ref(true) → ref(false),实时日志面板默认折叠
      
      工具栏的「全选 / 清空 / 全部展开 / 全部折叠」按钮照常可用,
      用户想一键操作仍然可以。
      
      .gitignore:追加 Session.vim(Vim 会话临时文件)
      8728514f
  5. 11 Aug, 2026 3 commits
    • Data Governance Dev's avatar
      feat(web): 数据字典右表格字段 checkbox + column_filter 端到端 · 02de2a61
      Data Governance Dev authored
      后端
      - models.py: ConnectRequest 加 columns: list[{table_name, column_name}]
        (空 = 走选中表全量字段;非空 = 仅跑用户勾选字段)
      - orchestrator.py: run_governance_workflow 接 columns,构造
        column_filter: set[(table, column)] 传给每个 step
      - job_manager.py: _run_job 透传 columns
      - step2/4/5/6: 加 column_filter 参数 + 按 (table, column) 过滤
      - step7 (核心): 删除 _collect_hit_columns 关键字推断
        (applies_to_fields / comment_keywords 不再用于挑选目标字段),
        改为 _select_target_columns 直接返回上游 column_filter 后的字段;
        run_step7_for_indicator 单值类分支去掉 has_name/has_cmt 守门
      
      前端
      - index.html: 右表格加 checkbox 列 + 全选/清空/反选 工具栏
      - form.columns: Set<table||column>,勾上表时联动勾上表所有字段、
        取消表时移除该表所有字段,用户手动调整不联动回表
      - startJob(): Set → [{table_name, column_name}] 后提交
      - 启动按钮增加 columns.size === 0 守门 + 新 alert
      - disconnectDataDict / testConnection 成功 后清空 form.columns
      
      修复
      - testConnection() 不再传 Set 类型的 columns(JSON.stringify 会变 {}
        导致 Pydantic 422),改为显式传空 list
      - data_dict.py: 达梦环境下 ALL_TAB_COLUMNS / ALL_COL_COMMENTS 视图
        可能返回 N 倍重复行(B_ZJZX 12 字段实测 78 行),Python 端按
        (table_name, column_name) 兜底去重,命中时打 WARN 日志
      02de2a61
    • Data Governance Dev's avatar
      refactor(web): Step 5 去 LLM 推测 + Step 2 UI 隐藏 + hidden step 提交过滤 · 50b48135
      Data Governance Dev authored
      本批 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)。
      50b48135
    • Data Governance Dev's avatar
      feat(web): 三数据库适配(MySQL/达梦/Oracle)+ 连接默认值独立配置 · 9646cd1a
      Data Governance Dev authored
      【Oracle 适配 — 端到端接入】
      - web/core/db_adapter.py
        · 新增 to_oracle_kwargs(),oracledb 1.4.x 关键字映射
        · _select_driver() 新增 oracle 分支,未安装 oracledb 时给中文友好报错
        · _ensure_oracle_client() 自动检测 Instant Client,老 Oracle 切 thick 模式
        · DBConfig.oracle_client_dir 字段(显式 lib_dir)
        · TEXT_TYPES 补 Oracle 类型(nclob / long)
      - web/sql/info_schema/list_columns.oracle.sql + list_tables.oracle.sql
        · 新增 Oracle 方言的字典查询模板(ALL_TAB_COLUMNS / ALL_TABLES)
        · 表注释 LEFT JOIN ALL_TAB_COMMENTS(同达梦结构)
      - web/sql/standards/{sample_field_groups,sample_field_groups_single,
        sample_field_pairs,sample_field_pairs_two_text}.sql
        · \`\${col}\` → \${col | quote} 跨方言重构,加新数据库零 SQL 改动
      - web/sql/loader.py:dialect 白名单加 "oracle"
      - web/requirements.txt:锁定 oracledb>=1.4.2,<2.0(兼容 Oracle 11.2)
      - web/start.py:start 脚本新增 oracledb / dmPython 可选组件检测
      - web/app.py / web/core/__init__.py / web/core/step_impl/__init__.py /
        web/core/models.py / web/configs/defaults.yaml / web/README.md
        · 描述/注释/枚举更新为「MySQL / 达梦 / Oracle」
        · models.ConnectRequest 加 oracle_client_dir 字段
        · README 加 Oracle 行 + 三端口映射说明
      
      【达梦适配 — 跑通实测】
      - web/core/db_adapter.py
        · to_dm_kwargs() 改用 server= 关键字(不是 host=),删 dmPython 不支持的
          schema / charset / connect_timeout 参数(C 扩展传错会 SystemError 吞真实异常)
        · _rows_as_dicts() 统一 PyMySQL Dict / tuple 两种行格式
        · fetchall / fetchone 从 cur.description 取列名兜底
        · dmPython SystemError 增强日志(提示真实原因 + 给排查脚本路径)
      - web/sql/info_schema/list_columns.dameng.sql
        · 列注释 LEFT JOIN ALL_COL_COMMENTS(修 [CODE:-2207] C.COMMENTS)
      - web/sql/info_schema/list_tables.dameng.sql
        · BYTES → NULL(达梦 ALL_TABLES 无此列)
        · COMMENTS → LEFT JOIN ALL_TAB_COMMENTS(达梦 ALL_TABLES 无此列)
        · CREATED / LAST_DDL_TIME → NULL(达梦 ALL_TABLES 无时间戳)
          真要看时间戳得 LEFT JOIN ALL_OBJECTS,按 OBJECT_TYPE='TABLE' 过滤
      
      【UI 改进】
      - web/static/index.html
        · 数据库类型三选项(MySQL / 达梦 / Oracle)
        · onDbTypeChange 端口切换改用 DB_DEFAULT_PORTS 映射表
          (mysql:3306 / dameng:5236 / oracle:1521),加守卫保留用户自定义端口
        · loadDbDefaults() 启动时从 /api/db-defaults 读连接默认值填表单
        · charset 下拉新增 al32utf8 / zhs16gbk(Oracle NLS 字符集)
        · Oracle radio 暂未实装完成,先注释隐藏(后端代码保留,放开零成本)
      
      【连接默认值独立配置】
      - web/configs/db_defaults.yaml(新增,.gitignore 排除,存真实凭据)
      - web/api/routes.py:新增 GET /api/db-defaults 端点
      - .gitignore:补 web/configs/db_defaults.yaml 防止真实凭据误提交
      
      【诊断与日志】
      - scripts/_probe_dm.py:达梦连接独立诊断工具(C 扩展吞异常时排查用)
      - docs/WORKLOG.md:本次任务完整工作记录(含三库字典表差异表)
      
      【未提交】
      - web/configs/db_defaults.yaml(真实密码,gitignore 排除)
      - scripts/_tmp_build_violations_md.py(一次性调试脚本,硬编码绝对路径)
      - data_dictionary/standard_fields_violations_report.md(生成报告,非源码)
      9646cd1a