zhouyang.xie 01ddb723e1 数据链补齐: 从 data/raw 重算/更新产物 (报警/工单/油样) + 等价验收 1 месяц назад
..
README.md 01ddb723e1 数据链补齐: 从 data/raw 重算/更新产物 (报警/工单/油样) + 等价验收 1 месяц назад
fix_guanlan_bom.py c5cb06a962 观澜·如东样板 v2 v0.2.0 基线入库 (含 2026-09-11 现场修复) 1 месяц назад
fix_guanlan_pythonpath.py c5cb06a962 观澜·如东样板 v2 v0.2.0 基线入库 (含 2026-09-11 现场修复) 1 месяц назад
fix_guanlan_startbat.py c5cb06a962 观澜·如东样板 v2 v0.2.0 基线入库 (含 2026-09-11 现场修复) 1 месяц назад
restore_release_rudong.py 10323a3507 bug-2: 恢复 v0.2.0 漏发的 release/如东/ 交付件 (门户 #documents 坏链) 1 месяц назад
scan_portal_links.py 10323a3507 bug-2: 恢复 v0.2.0 漏发的 release/如东/ 交付件 (门户 #documents 坏链) 1 месяц назад
verify_bug2.py 10323a3507 bug-2: 恢复 v0.2.0 漏发的 release/如东/ 交付件 (门户 #documents 坏链) 1 месяц назад
verify_guanlan_simsys.py c5cb06a962 观澜·如东样板 v2 v0.2.0 基线入库 (含 2026-09-11 现场修复) 1 месяц назад

README.md

观澜·如东样板 v2 (v0.2.0) 启动报错修复记录 — 2026-09-11

本目录不属于原始交付包, 是现场修完之后留下的记录: 每个脚本都可重复运行 (幂等), 用来复现 "改了什么" 或在别的机器/另一份拷贝上重放同一批修复。

现场现象

powershell -ExecutionPolicy Bypass -File install.ps1     -> 装完最后一步崩:
    json.decoder.JSONDecodeError: Unexpected UTF-8 BOM (decode using utf-8-sig)
start.bat                                                -> 同样崩; 随后
    [X] Server did not start (reason above). Not opening the browser

根因 (5 条, 前 3 条是同一个坑的不同后果)

# 位置 问题
1 install.ps1 第 4 步 Set-Content configs\serve.json -Encoding UTF8 Windows PowerShell 5.1 的 -Encoding UTF8 写出带 BOM 的 UTF-8; guanlan.py 用裸 utf-8 读 -> JSONDecodeError。启动器在解析配置时就死了, 所以 check/serve 全跑不起来。
2 同一行的 Get-Content configs\serve.json -Raw PS 5.1 对无 BOM 的 UTF-8 按 ANSI 代码页 (中文机 = GBK) 解码, 于是把文件里的中文注释读成乱码, 再 Set-Content 写回 -> _note / _note_raw 两个字段永久损坏 (部分字节被替换成 ?, 不可逆)。
3 机器全局 PYTHONPATH=D:\Program Files\Python\Lib\site-packages; ① pip 认为系统那套包 "已满足", 没把传递依赖装进 .venv -> venv 缺 urllib3/polars/pyyaml/jinja2/python-dotenv 等, 换个没设 PYTHONPATH 的 shell 直接 ModuleNotFoundError; ② PYTHONPATH 排在 sys.path 前面, 把 pin 住的版本顶掉 (实测 requests 2.33.0 顶掉 2.34.2)。
4 wheels\win_amd64\ 缺 colorama 轮子 (tqdm 在 Windows 上的依赖)。之前被根因 3 掩盖: pip 看到系统已有 colorama 就不下载, 于是离线轮子集不全; 一旦 PYTHONPATH 摘干净, pip install --no-index 直接 ERROR: No matching distribution found for colorama。
5 release/sim_sys_server.py 第 36 行 from scrub_rules import scrub, residual scrub_rules.py 根本没随包发出 (全盘搜不到, zip 里也没有) -> /sim/sys/ 仿真·四系统合页 502, logs/sim_sys.log 里是 ModuleNotFoundError; 网关因此 degraded, guanlan.py serve 退出码 1。

改了什么

文件 改动
guanlan.py 新增 jload() = utf-8-sig 读 JSON (兼容有/无 BOM), 5 处配置读取全部改走它; 配置坏了只打印提示并退回内置默认端口, 不再抛栈。新增 _hermetic(): 启动时把 PYTHONPATH 从 sys.path 与环境里摘掉 (子进程继承干净环境)。
install.ps1 第 4 步不再用 PS 的 cmdlet 碰配置, 改由 .venv 里的 Python 读写 (读 utf-8-sig / 写无 BOM 的 UTF-8), 并加注释说明为什么不能改回去; 顶部加 Remove-Item Env:PYTHONPATH, 让 pip 老老实实把包装进 .venv。文件仍保持 UTF-8 带 BOM + CRLF (PS 5.1 解码中文的前提)。
install.sh 同样加 unset PYTHONPATH (保持 LF/无 BOM)。
configs/serve.json 去掉 BOM; 还原 _note / _note_raw 两段中文注释 (依据残留可逆部分 + 说明书 §7 的措辞)。
wheels\win_amd64\colorama-0.4.6-py2.py3-none-any.whl 补上缺失的轮子, 离线安装才完整。
release/scrub_rules.py 恢复缺失文件: 不新写任何脱敏规则, 只把包内唯一那份规则表 src/windscada/deid_public.py 转出 scrub / residual(= audit) / scrub_or_die。若拿到交付方原版, 直接覆盖。
start.bat guanlan.py serve 的退出码 1 有两种含义 (网关没起来 / 网关起来了但有模块降级)。现在先探一次 /healthz 区分: 真没起来才报 [X] 并停下; 起来了但有降级则打 [!] 说明, 浏览器照常打开。

备份与回滚

原文件都留了副本, 直接改名覆盖即可回到改前状态:

guanlan.py.bak-bomfix      install.ps1.bak-bomfix     configs\serve.json.bak-bomfix
guanlan.py.bak-pyfix       install.ps1.bak-pyfix      install.sh.bak-pyfix
start.bat.bak-healthz

重放 / 验证

.venv\Scripts\python.exe fix_guanlan_bom.py          # 1 2 (BOM + 乱码)
.venv\Scripts\python.exe fix_guanlan_pythonpath.py   # 3
.venv\Scripts\python.exe fix_guanlan_startbat.py     # start.bat 判定
.venv\Scripts\python.exe verify_guanlan_simsys.py    # 5 个仿真页 200 + 脱敏回扫干净

三个 fix_* 都是幂等的 (已改过会打印 "已修过")。wheels\colorama*.whl 与 release\scrub_rules.py 属于新增文件, 没有对应的 fix_* 脚本。

bug-2 · #documents 页「如东液压系统治理清单 · 网页版」报 {"err":"not found"}

现象: 门户 http://127.0.0.1:28084/#documents 里那个 iframe 显示 {"err": "not found", "path": "/如东/如东治理清单_交付_20260901/02_治理清单/如东_液压系统治理清单_v1.2_2026-09-01.html"}。

根因: v0.2.0 发行包里没有 release/如东/ —— 0.2.0 的 zip 里 release/ 下只有 viewer/, 而门户那个 iframe 指的就是 release/如东/.../_液压系统治理清单_v1.2_2026-09-01.html; 网关 guanlan_gateway.py::_static() 在 release/ 里找不到文件就回那段 404 JSON (见 _static() 里 return self._json(dict(err="not found", path=path), 404))。 顺带核过: 门户里指向 release/如东/ 的引用只有这一条, 所以不是路径写错, 是交付件没随 v0.2.0 发出来。

修复: 从本机的 v0.1.0 全量包 F:\temp\guanlan-rudong-v2_0.1.0_all.zip(这份交付件在里面是齐的) 把整个 release/如东/ 恢复到 v0.2.0 安装目录 —— 75 个文件 / 51.0 MB (如东治理清单_交付_20260901/ 33 件、如东取数单_2026-08-21/ 18 件、观澜离线版.app/ 10 件、根下散件 14 件)。 release/如东/ 按 .gitignore 的既有约定不入库(客户交付物只在受保护工作区), 所以 git 里看不到这次恢复。

验收: iframe URL 走网关取 → [200] text/html, 103760 字节, 标题 如东液压系统治理清单, 正文 0 个外部相对引用(自包含); 同页另外两个引用 (127.0.0.1:18020 CMS、127.0.0.1:18033/v2) 均 200; 全门户扫一遍含「如东 / release」的静态引用 → 坏链 0。

脚本: restore_release_rudong.py (恢复) · verify_bug2.py (验收) · scan_portal_links.py (同类坏链全量扫描)

数据链补齐 · 让系统真正吃 data/raw/如东 (2026-09-11)

问题: 说明书 §11 写着「不含从原始数据重生成产物的链 (P0)」, 而维护页四条「摄入命令」指向的文件 在包里一个都不存在; 于是现场把新台账放进 data/raw/如东/… 也不会更新, 工单台账一直停在 2024-11-21。

新增 4 个脚本 (都在 scripts/; 维护页四条命令现在全部「命令可用=True」):

脚本 源 → 产物 关键实现
windscada_alarms_ingest.py 故障报警/*.xls → alarms.parquet .xls 实为 SpreadsheetML(XML); 累计快照件自动跳过 (2025年全年 = Q1..Q4 精确并集 20155 行)
windscada_workorder_ingest.py 风机故障记录/** → workorders.parquet 按场名过滤 (集团表里混着民勤/来福/宝力格等十来个场); 归并跨表重复 1085 行; 日期按 src/sop/ledger_dates.py 同一纪律解析, 解析不了的整行保留
windscada_watch_channels_build.py 油样报告/**/*.pdf → oil_samples_index.parquet 文件名解析 (日期/台号/部件/sample_id); 合并语义: 认不出的老行原样保留
rebuild_from_raw.py 总入口 --verify 等价验收; --scada 再跑包内 10 个 SCADA 侧构建器

等价验收 (python scripts/rebuild_from_raw.py --verify, 对 _pre_rebuild_20260911/ 随包基线):

报警事件       39211 行 / 39211 行   逐值完全一致            ✔
油液化验         506 行 /   506 行   逐值完全一致            ✔
检修工单台账    1574 种内容复现 1566 种; 8 种差异逐条定位:
   · 7 种 = 复位运行时间: 随包 NA、本链有值 — 旧链没认源列名「复位时间时间」这个错别字
   · 1 种 = 随包把 Excel 序列号当纳秒解析成 1970-01-01, 本链解析为 2023-05-13
   · 随包 78 行副本重复已归并; 另多出 69 行 = 旧链丢弃的日期不可解析行

效果 (/detail/v2#tab=system 数据层, 已重启服务实测):

行 改前 改后
检修工单台账 2020-01-03 ~ 2024-11-21, 1652 行 2020-01-03 ~ 2026-07-08, 5876 行
四条「摄入命令」命令可用 False True

依赖: requirements.txt 加 xlrd==2.0.2 (2023/2024 年总表是真 BIFF .xls, openpyxl 读不了), 轮子已放进 wheels/win_amd64/ (wheels/ 按 .gitignore 不入库, 随包分发)。

SCADA 侧: python scripts/rebuild_from_raw.py --scada 把 10 个构建器按依赖顺序跑一遍 (powercurve → loss_monthly → curves/control/stop_events/温度/偏航/液压/热链/系统辅助)。 抽验过等价性 (WTG01/WTG02 的 temp_bins 与随包件 1296/1296 行逐值相同、med 差 0.0), 但未整体重跑 —— 要跑建议先备份 outputs/rudong/windscada/ 再逐项比对覆盖区间。

仍然存在 (不是代码问题)

  • /local-ai/ 仍是 DOWN: 本机 Ollama 没运行, 且 %USERPROFILE%\.ollama 下没有任何模型 (manifests 都没有), 所以问答与本地审核页不可用。其余 6 个页面不受影响。 启用: 启动 Ollama, 按 configs\models.json 的 pull_commands 拉模型 (需联网/大流量), 或把有网机器的 %USERPROFILE%\.ollama\models 整个目录拷过来。
  • release\如东 (治理清单交付件) 本来就是可选项, 不影响页面。