139 lines
9.0 KiB
Markdown
139 lines
9.0 KiB
Markdown
|
|
# Round 66 工作计划:Windows 求解器进程隔离与 Fail-Closed
|
|||
|
|
|
|||
|
|
日期:2026-08-03
|
|||
|
|
|
|||
|
|
## 1. 背景与方向选择
|
|||
|
|
|
|||
|
|
- Round 65 已完成并通过独立复审。完成矩阵下一优先级为 P0 可信试点基线。
|
|||
|
|
- 并行只读审计比较了三条候选:全量 P2/P3 证据封套、共享审批存储可靠性、Windows 求解器 fatal。
|
|||
|
|
- 本轮选择 Windows 求解器进程隔离,因为它可直接杀死后端主进程、绕过 Python 异常/审计,并曾出现“测试 passed 且 exit 0,但输出 Windows fatal”的假绿色。
|
|||
|
|
- 全量 P2/P3 证据封套与共享审批迁移 token/损坏源问题登记为后续 P0 轮次,不以本轮完成替代。
|
|||
|
|
|
|||
|
|
## 2. 已确认事实
|
|||
|
|
|
|||
|
|
- 默认 PATH `python` 来自 Anaconda,用户 site OR-Tools 与 Conda pandas/pyarrow/DLL 混装可复现 `0xc0000139 / WinError 127`。
|
|||
|
|
- `.venv` 与 `.sidecar-venv` 的独立求解探针当前通过,但 `.venv` base 仍属于 Anaconda,不能作为发布运行时证明。
|
|||
|
|
- CP/HYBRID 目前在后端主进程调用 `optimize_line_assignment()`;OR-Tools 时限不能隔离导入崩溃、C++ abort、native deadlock 或进程级 fatal。
|
|||
|
|
- 默认标准排产使用 HYBRID,rush/LNS/敏感性/鲁棒性等也通过引擎动态分派进入该边界。
|
|||
|
|
|
|||
|
|
## 3. 本轮目标
|
|||
|
|
|
|||
|
|
建立唯一的求解器进程边界:父进程构造不可变请求,子进程只执行 CP-SAT 优化并返回版本化 JSON;父进程验证退出码、fatal marker、协议、运行时身份和超时后,才允许在父进程物化世界状态。任何 native/runtime/timeout/protocol 失败都结构化失败关闭,不能杀死 8003,不能留下 PO/WO/可发布版本,HYBRID 不能伪装成 RULE 成功。
|
|||
|
|
|
|||
|
|
## 4. 范围
|
|||
|
|
|
|||
|
|
### In scope
|
|||
|
|
|
|||
|
|
- 新增 solver subprocess request/response 协议、fatal marker 检测、OS 级 timeout、进程树回收和运行时身份。
|
|||
|
|
- CP 与 HYBRID 的 `optimize_line_assignment` 改由子进程执行;健康路径保持原 ordered entries、gap、cumulative 和物化语义。
|
|||
|
|
- 子进程失败时父进程 world 深比较不变;CP/HYBRID 返回结构化 `SOLVER_*` 阻断,不做静默成功降级。
|
|||
|
|
- Sidecar 增加 `--solver-child`;普通 CPython 使用 `-I -B -X faulthandler -m server.engines.solver_worker`。
|
|||
|
|
- 强化 `scripts/check_solver_runtime.py`:内部 timeout、模块来源、base executable、user-site、版本和 fatal marker,即使 returncode=0 也拒绝。
|
|||
|
|
- 桌面 child env 清理 Conda PATH 段,继续设置 `PYTHONNOUSERSITE=1`。
|
|||
|
|
- 增加固定服务器运行时锁/身份说明,但不在本轮擅自重建用户 `.venv`。
|
|||
|
|
|
|||
|
|
### Out of scope
|
|||
|
|
|
|||
|
|
- 不修改 `get_engine()` 全局工厂。
|
|||
|
|
- 不把真实 Windows CI、干净离线机或签名冻结产物冒充本地完成;这些保留外部验收。
|
|||
|
|
- 不在本轮同时重构全部 P2/P3 evidence resolver、审批 outbox 或真实 MySQL 多主机。
|
|||
|
|
- 不提交、不推送、不合并、不发布。
|
|||
|
|
|
|||
|
|
## 5. 失败代码与产品语义
|
|||
|
|
|
|||
|
|
父进程统一识别:
|
|||
|
|
- `SOLVER_RUNTIME_UNSAFE`:运行时身份/模块来源不可信。
|
|||
|
|
- `SOLVER_NATIVE_FATAL`:stderr/stdout 命中 fatal marker,包括 returncode=0。
|
|||
|
|
- `SOLVER_PROCESS_EXITED`:非零退出且非特定 runtime 失败。
|
|||
|
|
- `SOLVER_PROCESS_TIMEOUT`:超过求解时限 + 启动宽限。
|
|||
|
|
- `SOLVER_RESPONSE_INVALID`:JSON 截断、缺成功标记、协议版本或 schema 不匹配。
|
|||
|
|
- `SOLVER_VERSION_MISMATCH`:父子协议或引擎版本不一致。
|
|||
|
|
|
|||
|
|
规则:
|
|||
|
|
1. 子进程失败前后 world 完全一致。
|
|||
|
|
2. 显式 CP 失败不降级 RULE。
|
|||
|
|
3. HYBRID native/runtime 失败默认阻断;若未来允许降级,必须是显式策略且不可发布。
|
|||
|
|
4. 只有验证通过的 ordered entries 才进入 `materialize_schedule()`。
|
|||
|
|
5. 失败必须可写算法失败审计或返回结构化阻断;父进程和 8003 必须继续存活。
|
|||
|
|
|
|||
|
|
## 6. 验收标准
|
|||
|
|
|
|||
|
|
- 健康 `.venv`:CP/HYBRID subprocess 与现有 in-process 基准产生等价可行性、工序顺序、line assignment、gap/cumulative 元数据。
|
|||
|
|
- 故障注入:非零退出、returncode=0+fatal marker、超时、非法 JSON、缺 success marker、协议不匹配全部 fail-closed。
|
|||
|
|
- 故障前后 world 深比较一致,0 新 PO/WO/VL,不产生可发布版本。
|
|||
|
|
- 当前默认 Anaconda 探针稳定返回不安全/失败证据;`.venv`、`.sidecar-venv` 探针连续通过。
|
|||
|
|
- 冻结 Sidecar(若现有产物可用)`--solver-child` 冒烟通过;若产物需重打包,记录为构建后验证而不伪造。
|
|||
|
|
- 8003/5173 在模拟 child crash/timeout 后继续 HTTP 200。
|
|||
|
|
- focused、全量黄金、Node、Web build 通过;`git diff --check` 与 `detect_changes(compare main)` 完成。
|
|||
|
|
|
|||
|
|
## 7. 真实运行证据
|
|||
|
|
|
|||
|
|
- 保留默认 Anaconda 失败探针、固定运行时通过探针和产品 API child-failure 存活证据。
|
|||
|
|
- 测试所有 APS_HOME、DB、world、日志输出重定向到临时目录;不写 `server/data/**`。
|
|||
|
|
- 记录当前 MOM world hash,运行前后必须一致。
|
|||
|
|
|
|||
|
|
## 8. 风险与外部阻断
|
|||
|
|
|
|||
|
|
- GitNexus 对 `get_engine` 为 CRITICAL;本轮避免修改。
|
|||
|
|
- 动态引擎分派会低估 `CpSatEngine.solve` / `HybridEngine.solve` 的上游影响,因此按高风险验证。
|
|||
|
|
- 真正 Windows CI、干净 Win10/11、签名冻结产物、Defender 和客户机 DLL 环境需要外部基础设施。
|
|||
|
|
- `.venv` 重建属于运行环境变更,不在未获授权时执行。
|
|||
|
|
|
|||
|
|
## 9. Pre-target-merge 停止点
|
|||
|
|
|
|||
|
|
实现、验证和独立审计完成后,先报告:协议覆盖、失败注入、健康求解等价性、运行时来源、现场数据保护、共享 dirty 基线和残余外部环境。未经用户明确授权,不执行 commit/merge/push/publish。
|
|||
|
|
|
|||
|
|
## 10. 计划可行性审计
|
|||
|
|
|
|||
|
|
PLAN AUDIT: PASS
|
|||
|
|
|
|||
|
|
Blocking issues: none
|
|||
|
|
|
|||
|
|
Clarification needed: none(persistent goal 已授权继续推进最高优先级本地项;默认采用 fail-closed、不静默 RULE 降级)
|
|||
|
|
|
|||
|
|
Non-blocking improvements: 真实冻结产物 smoke 取决于现有 artifact;若需重新打包则只记录为外部/后续构建证据。
|
|||
|
|
|
|||
|
|
|
|||
|
|
## 11. 执行结果与验收收口
|
|||
|
|
|
|||
|
|
状态:实现与真实运行门禁通过;最终全量黄金计数待主 agent 在新增源码 Sidecar `-I` 回归后复跑确认。
|
|||
|
|
|
|||
|
|
### 已完成
|
|||
|
|
|
|||
|
|
- 子进程协议、request/response digest、fatal marker、OS timeout、进程树回收和运行时身份已落地,协议为 `aps.solver-process.v1`。
|
|||
|
|
- CP/HYBRID 仅在 child 执行优化,父进程负责校验与物化;fatal/timeout 时均 `UNAVAILABLE`、0 PO/WO、不可发布,且无 RULE 静默降级。
|
|||
|
|
- 复制 `world.json` 的 CP/HYBRID 均 `OPTIMAL`,1 PO / 10 WO / 10 operationSlots,`runtimeSafe=true`。
|
|||
|
|
- 复制 MOM 数据的 CP/HYBRID 均可完成求解,但现有业务主数据阻断为 0 PO/WO、1 slot/1 conflict;不宣称完成现场主数据。
|
|||
|
|
- fatal 注入后父进程与 8003 存活,业务世界原子;timeout 15.633 秒并回收 grandchild 进程树。
|
|||
|
|
- 默认 PATH Anaconda 探针稳定拒绝;`.venv`、`.sidecar-venv` 各连续 5 次通过。
|
|||
|
|
- 8003 PID `21576`、5173 PID `9808` healthy;浏览器 title/root 正常且无 warning/error。
|
|||
|
|
- Node 60 passed、Web build passed、ruff/compile/node check/diff-check passed。
|
|||
|
|
|
|||
|
|
### 源码 Sidecar `-I` 补充发现
|
|||
|
|
|
|||
|
|
- 真实源码 `--solver-child` 在 Python `-I` 下最初因源码 import root 被移除而失败。
|
|||
|
|
- 经 GitNexus LOW impact 门禁,仅 bootstrap 已解析的 trusted source root,并新增 `test_source_solver_child_entry_runs_under_isolated_python`。
|
|||
|
|
- 修复后实际源码 Sidecar child 为 CP `OPTIMAL`、1 PO / 10 WO / 10 slots、协议 v1、`runtimeSafe=true`。
|
|||
|
|
- 最新 focused 为 80 passed;最终全量黄金为 1029 passed / 2 warnings(300.23 秒)。
|
|||
|
|
|
|||
|
|
### 数据与发布边界
|
|||
|
|
|
|||
|
|
- `world.json` hash:`C6E7FF090719DB505AF5C3B0D8ADD376CBA7843D6E6982A68C1BA02C342052FA`;MOM hash:`6B64ADF6F29A43A518D89718610EE71FAD60E86D3F38CD5CFF26F1740CC53F7D`;JSON 业务源前后不变。
|
|||
|
|
- `server/data/**`、`.env` 无 Git 状态;`master.db` 可能因 license `last_seen` 等运行元数据更新,不以文件 hash 证明业务不变。
|
|||
|
|
- 现有冻结 EXE 仅旧 `--probe-child` 通过;未重建,故新 `--solver-child` 的打包验收仍是构建后停止点。
|
|||
|
|
- 不提交、不推送、不合并、不发布。
|
|||
|
|
|
|||
|
|
### 后续 P0
|
|||
|
|
|
|||
|
|
全量 P2/P3 evidence 封套与审批迁移可靠性(token 摘要、损坏源 fail-closed、DB clock/TTL、CAS 并发)成为下一最高优先级本地项。
|
|||
|
|
|
|||
|
|
|
|||
|
|
### 首轮独立审计修复
|
|||
|
|
|
|||
|
|
- 首轮 `AUDIT: FAIL` 指出成功响应摘要未被父进程验证,且非空请求可被伪造成 `OPTIMAL + 空 entries`。
|
|||
|
|
- 父进程现强制重算 `responseDigest`,校验条目完整排列/业务字段、pipeline/status、可行解 objective/gap 与 operationSlots 覆盖;8 个新增负向用例全部通过。
|
|||
|
|
- 源码冻结路由现按 `sys.frozen` 自动执行自身 `--solver-child`;旧 EXE 未重建,仍为构建后验收边界。
|
|||
|
|
- 最终独立只读复审 `AUDIT: PASS`。
|
|||
|
|
|
|||
|
|
- 复审补强:请求先落自动清理临时文件并作为 child stdin,避免 Windows 管道背压绕过 deadline;slot 越界/订单产品错绑、错误 pipeline/status 均失败关闭。
|