M12 宽表上游修复验收¶
本页保留上一轮内存改造的原始测量和限制。 2026 年 10 月 23 日独立验收后的修补与复测另记在文末;历史计数和容量数字不代表本轮结果。
本轮在 Windows 当前工作区修改 MARS,未运行 M12 Agent、预测模型训练或 Runtime 恢复流程。 真实 M12 的 257,997 行风险画像和 297,440 行 selector 容量均未运行。 仓库中的 Home Credit 公开案例为另一份 119 候选输入,不能替代 1,111 候选验收。
源码与环境¶
工作区为 D:/Desktop/credit-risk/mars-risk,分支 main,初始工作树干净。
实现与验收时 HEAD 为 625de258deb75d8d95a7e2bd36e9ae1774b8c6a2。
完成验收时未提交工作树的 Python 源码内容 SHA256 为
1fba73c237a2ef03ce60dd5152858dfdd7fdc9982cb909b8151b99597083c852;版本仍为 0.0.28。
用户指定的基线 c937fbfadbe083e39d3425ea1af206b8907fd0ff 已通过只读获取提交对象取得;
它比验收时本地 HEAD 多一个文档提交,计算源码相同。实现与验收阶段没有切分支、reset、commit、push、发布或改版本号。
随后用户明确授权提交推送;推送前将 main 快进到该基线,仅合入规则生成器返回值的 docstring 说明,
未改变任何计算实现、版本号或本轮验收结论。
Git 确认的历史完整 SHA 为 847a23053b1cbc2ba1be14fbc0c494eacecf8596。
当前目录及祖先和相关源码目录未发现适用的 AGENTS.md。
所有最终回归将 PYTHONPATH 设置为当前仓库的绝对 src 路径,mars.__file__ 指向该目录下的 mars/__init__.py。
这是必要的环境隔离:本机 mars38 默认会导入 site-packages 中的旧安装包。
| 环境 | Python | Polars | Pandas | 用途 |
|---|---|---|---|---|
| mars38 | 3.8.20 | 1.8.2 | 2.0.3 | 冻结旧环境、公开 API 和多 chunk 回归 |
| mars | 3.10.19 | 1.37.1 | 2.3.3 | 合成容量和分箱回归 |
| mars312 | 3.12.13 | 1.42.0 | 3.0.3 | 现代公开 API、静态检查、画像回归及正式公开案例生成 |
单线程缺陷回归在导入 Polars 前设置 POLARS_MAX_THREADS=1。
容量 worker 在导入 NumPy/Polars 前设置全部既有线程环境,n_jobs=1,两侧配置相同。
未将 n_jobs 解释为 Polars 或 BLAS 线程数。
根因与修改¶
| 项目 | 修前行为 | 本轮实现与证据 |
|---|---|---|
| P01 | 旧 Polars 的纯 literal select 可按 chunk 返回多行,transpose 只有一个 total 名称 | 非适用统计和常量用 typed 标量聚合;PSI 独立计算,保留不可算表和状态 |
| P02 | eager 样本先 with_columns/join,最后才转 lazy;fit 和 benchmark schema 校验提前物化 | 执行前选定 LazyFrame;schema 不执行样本转换,映射和非法规则校验仍保留 |
| P03 | Quality/Rough 未贯通列批宽;先过滤完整宽表;benchmark eager long 表驻留 | 贯通既有参数;每批先投影再过滤、转换、聚合;expected distribution 使用 lazy 聚合 |
| P04 | 完整监督人口的 WOE、填 null 副本和 NumPy 中心化工作数组同时存在 | 私有行块和列批生成 WOE,Float64 中心矩合并完整 Pearson;保留全 P² 报告 |
| P05 | 历史总量和临时外层分批无法定位实际阶段峰值 | 扩展现有 fresh-worker harness,连续公开调用记录阶段、人口、survivors 和报告保存 |
| P06 | 需同时防止旧环境回退、报告合同退化和案例指纹陈旧 | 旧版与现代回归、静态检查、文档及正式案例生成器验收,结果见下文 |
主要源码为 analysis/_profiling/{metrics,pivot,psi}.py、analysis/profiler.py、
feature/binning/base.py、analysis/_evaluation/aggregation.py、
feature/selection/stats.py 和 compute/_correlation.py。
新增回归进入既有 batching 套件及 test_binner_execution.py、test_stats_blocked_correlation.py。
P01 修前在真实 Python 3.8.20 / Polars 1.8.2 保存了四条 ShapeError:公开 mixed PSI、PSI-only、
单指标字符串 mean 和 zeros。新测试显式构造不等长 [2, 5, 1] chunks 并断言 n_chunks()>1。
280 组公开多 chunk/rechunk 对照覆盖单/多特征、Float32/64、String/Categorical、全 null、空表、
分组、时间、独立 benchmark 和缓存路径。还验证真实 null、文字 null 和 (空分组) 不混淆。
源值、dtype、行序和输入 chunk 结构均保持,PSI-only overview 保留身份。
P02 修前结构回归有八条失败。修后 guard 分开检查计划构建、schema 和 collect,允许小型映射表构造, 禁止 schema 阶段分配全行派生列及 eager 高基数 join。数值、replace、join、未知类别、Missing/Special/Other、 失败 refit、规则保存/新进程加载和 WOE 子集复用均覆盖。首次 WOE 的必要监督统计仍可能执行。
P03 的完整顺序为 Quality → Rough Fit → fit schema → benchmark schema → Rough Performance → Fine(启用时)→ Stability PSI/RC → WOE Corr → 报告冻结/缓存清理 → 保存。 质量与分布使用完整当前人口;无监督拟合使用完整拟合人口;监督拟合仅使用原定义已表现标签。 独立 benchmark 继续提供切点和 expected 分布,当前监督统计和 WOE 来源没有改变。 真实 M12 关闭 Fine,本轮 Fine 回归不能算作真实失败热点的修复证据。
必要的 _cache_X/_cache_y 支持公共 update_bins() 和首次 WOE,不能为降低图中 RSS 清空。
投影通常共享原列 buffer;CART 的监督过滤先投影需要的特征和标签,再分配过滤结果。
表现统计和 expected long 表不跨批保留样本,跨批只累计小统计。
selector 保留已有清理 Stage 3 缓存的行为,未引入循环 GC 或外层补偿流程。
全局 Pearson 的空间与数值合同¶
设监督人数 N、候选数 P、内部行块 R、特征列批宽 B。内部 R 为 min(4096, max(1, 8 MiB / (8P)))。
生产代码保留常数份 Float64 R×P WOE/中心化块、当前列批和 O(P²) 的中心矩/临时乘积。
生成器交接时前后块可短暂共存,不能将空间解释为仅一份 8 MiB 缓冲区。
首次 WOE 还可需要拟合数据的监督统计。原表、训练缓存、规则、稳定性报告和完整相关性报告另计。
这不是总内存硬上限。极宽输入的最小一行也可超过 8 MiB。
时间为 O(NP²),累计状态和全局输出为 O(P²),块工作内存为 O(RP+RB)。没有临时落盘。 先减去首行原点,再按 Chan 公式合并块中心矩;不使用不稳定的平方和相减,也不以 Float32 累计。 仅 WOE null 填零,NaN/inf 传播;常量和零/单样本 helper 的不可用对角线不补 1。 公共 selector 仍拒绝不满足二分类合同的标签。
与旧 dense NumPy 参考存在浮点累计差。接近阈值舍入误差界的少量 pair,使用完整监督人口、
两列 WOE 的 np.corrcoef 复核,再按原 > 比较。误差界仅触发复核,不改变业务阈值。
复核为 O(N×2) 工作内存,即使列批宽为 1 也转换两列;阈值处于大量 pair 的舍入邻域时会增加运行时间。
实数结果沿用 NumPy 的 [-1, 1] 截限。跨列批的正负关系、IV/ID 优先级、白名单、完整低相关边、
signed 值和实际决策顺序均保留,最终名单仍按原候选顺序返回。
阈值大于等于 1 时,由于严格比较和截限不可能触发淘汰,直接跳过窄列复核。
这避免完全重复的 1,111 候选在阈值 1 时触发 616,605 次不必要的完整人口 pair 转换。
报告继续使用紧凑 Enum endpoint 构造完整上三角,不新增平方级长特征名 Python 字典列表。 保存、加载、局部矩阵、pairs、decisions、分页和 AI 查询仍使用原合同。
连续阶段容量测量¶
复用 benchmark_core_capacity.py 和 benchmark_core_workloads.py。每个预热/正式轮次独立 worker,
一次公开调用内连续记录所有阶段及对象共存。阶段隔离不是本轮容量通过的依据。
selection_survivors 要求至少 80% 候选进入全局 corr;selection_attrition 覆盖实际质量/PSI 淘汰。
两者含混合 Float32/64、null/sentinel、多 chunk、长特征名及完整分组,均使用独立 Train benchmark。
记录包括源码/依赖/参数、输入与 benchmark 人数、非空监督人数、dtype/chunks、候选进出、
实际转换批边界、wall time、RSS 起止/采样峰值、worker lifetime peak、父子进程及退出状态。
RSS 树可重复计共享页,10 ms 采样可漏瞬时峰值,lifetime 高水位不能当阶段增量。
Linux ru_maxrss 常见 KiB 转 bytes,Darwin 原生 bytes;Windows 使用进程 peak working set。
Darwin footprint/compressed/swap 与 RSS 分列,当前 Windows 没有对应 macOS 实测。
失败保持真实状态,不把包装器退出码、worker 退出码和内核终止证据混为一谈。
同合同中型 A/B 使用 Python 3.10.19 / Polars 1.37.1 / Pandas 2.3.3,Windows 11(build 26200),
24 逻辑 CPU、63.7 GiB 物理内存。两侧 50,000 行、200 候选、3 chunks、160 Float32/40 Float64,
benchmark 30,000 行,实际非空监督 28,965 行,列批宽 16、n_jobs=1、全部原生线程环境为 1。
每侧一轮排除预热和一轮正式测量,时间只作探索性观察,不估计 P95 或保证普遍加速。
本机另有回归进程运行,未声称独占 CPU 或内存;背景负载也是单次时间观察的限制。
| 场景 | 两版各阶段候选去向 | public 秒,旧→新 | public 采样峰 MiB,旧→新 | lifetime 峰 MiB,旧→新 |
|---|---|---|---|---|
| survivors | Quality/Rough/Stability/Corr 输入均 200,最终 198 | 7.974→8.037 | 872.5→526.0 | 872.57→526.08 |
| attrition | 200→Quality 175→IV 150→PSI 125→最终 123 | 6.556→5.753 | 751.5→521.9 | 751.79→522.05 |
两场景最终名单顺序和 funnel 均一致。survivors 确实完成 200 候选的全局相关性,未用提前缩小到少数 特征替代容量。相同公开参数下,survivors 峰值下降约 39.7%,attrition 约 30.6%; survivors 总耗时基本持平,全局相关性本身变慢,不能据此宣称所有阶段提速。
完整输出语义另做辅助复算,不计入性能样本。两场景所有表的身份、行序、schema、null 和非浮点列
精确相同;完整 pairs 最大绝对差为 1.5543122344752192e-15,对角和决策相关值最大差约 2.22e-16。
IV 优先级和阈值差为零,分箱切点、WOE、mappings、fit_report 等 10 项状态精确一致。
因此完整表 hash 不逐位相同,不能用 hash 不同宣称名单或业务口径改变,也不能把它们写成完全相同。
细节见 .artifacts/m12_capacity_semantic_comparison.json 及对应的小型合成快照/规则 JSON。
下表为 survivors 的连续阶段。峰值是该阶段所在完整 worker 的绝对 RSS,不能相加,也不是阶段独占增量。 fine 本场景关闭。报告 freeze 已包含完整 pairs 构造;后续 get report 只读取已冻结对象。
| 阶段 | 秒,旧→新 | 采样 RSS 峰 MiB,旧→新 |
|---|---|---|
| 输入准备 | 0.169→0.192 | 313.4→313.3 |
| Quality | 0.449→0.475 | 442.2→354.9 |
| Rough Fit(包含末尾 schema) | 2.294→2.245 | 440.3→380.9 |
| fit schema 观察子阶段 | <0.001→0.003 | 375.3→380.5 |
| benchmark schema 校验 | 0.309→0.026 | 375.3→380.5 |
| Rough Performance | 0.655→0.590 | 683.6→420.7 |
| Rough 整体 | 3.303→2.908 | 683.6→421.5 |
| Stability PSI/RC | 3.408→2.957 | 872.5→518.1 |
| WOE + 全局 corr | 0.618→1.496 | 758.0→526.0 |
| 完整报告冻结 | 0.015→0.021 | 678.2→512.3 |
| 报告保存 | 0.015→0.021 | 679.0→511.4 |
schema 子阶段只观察 collect_schema() 的时间。旧版的 eager 派生分配发生在它之前,计入
Rough Fit,不能从 schema 子计时推断旧版没有隐藏物化。执行路径回归另有 guard 证明这一点。
新旧变换边界明确记录:旧 Rough Performance 一次计划 200 特征,旧 benchmark 校验 eager 200 特征;
新 Rough Performance 实际批宽不超过 16,benchmark 校验只建计划;全局 corr 只生成内部行块的列批。
fit 的 schema 计划可以引用全部规则,仍不分配样本派生数组。
完整 JSON 在忽略目录 .artifacts/m12_capacity_{baseline,current}_standard_v2.json,
简表为 .artifacts/m12_capacity_acceptance_summary.json。旧侧来自 .artifacts/m12_reference_c937/src,
修后本轮测量源码内容 SHA256 为 42c0ac6ef11bc2c9c9a9a3270822132915d1572499b1a920e568e0ebe10786c6。
随后画像跨 Float32/64 批次的 overview concat 修复另有实际回归;该变更不改变本轮 selector 的质量字段口径。
python benchmarks/benchmark_core_capacity.py --case selection_survivors selection_attrition --scale standard --source .artifacts/m12_reference_c937/src --backend polars --threads 1 --n-jobs 1 --batch-size 16 --repeats 1 --timeout 600 --output .artifacts/baseline.json
python benchmarks/benchmark_core_capacity.py --case selection_survivors selection_attrition --scale standard --baseline-json .artifacts/baseline.json --backend polars --threads 1 --n-jobs 1 --batch-size 16 --repeats 1 --timeout 600 --output .artifacts/current.json
在小型/中型验证后,另运行修后单个 fresh worker 的 200,000×1,000 survivors 场景,未再运行大规模旧版。
Train benchmark 120,000 行、实际监督 115,862 行,1,000 候选全部进入 Stability 和全局 corr,最终 998。
同为 Windows、Float32/64、3 chunks、列批 16、n_jobs=1 和线程 1。
公开调用 191.250 秒,完整 worker 203.502 秒;主/树采样峰约 2,634.31 MiB,lifetime 2,634.316 MiB。
完整 499,500 对关系保存为 7,466,447 bytes 的快照。
| 扩容阶段 | 秒 | 采样 RSS 峰 MiB |
|---|---|---|
| Quality | 9.161 | 2,489.2 |
| Rough | 43.318 | 2,351.7 |
| Stability PSI/RC | 51.585 | 2,634.2 |
| WOE + 完整全局 corr | 86.542 | 2,305.4 |
| 已冻结报告读取 | 0.015 | 见原始 JSON |
| 完整快照保存 | 0.057 | 见原始 JSON |
Rough Performance 和 Stability 的实际列批均不超过 16。相关性共 12,033 次列批转换,每次不超过
609 个已表现行、16 特征;fit/benchmark 的 1,000 特征请求均为 lazy schema 计划。
该轮正常退出 0,无重试、取消或内核终止。单侧数据不能计算同条件降峰比例,也不能证明 Mac/16 GiB
真实数据容量。原始记录为 .artifacts/m12_capacity_current_large.json,测量源码内容 SHA256 为
3e6e45ba5260cde3a68b3a58d4132e2b1855edc9e73ffd796540620661cd1130。
随后的阈值 ≥1 复核早返不影响该轮默认 0.95 的行为。
真实输入复现¶
没有在当前工作区取得 M12 冻结 Prepared/manifest。未扫描用户主目录、上传原始数据或启动 Agent。 公开案例的 Home Credit 原文件可用于案例一致性检查,不能拼造 M12 的 1,111 个冻结特征。 请为现有冻结 Parquet/IPC 文件准备一个小 JSON 配置,路径可以是外部绝对路径,候选必须完整显式列出:
{
"input_path": "/local/frozen/selector.parquet",
"benchmark_path": "/local/frozen/train.parquet",
"features": ["original_feature_1", "original_feature_2"],
"target": "frozen_target",
"group_col": "dataset_flag",
"supervision_group": "Train",
"selector_parameters": {
"skip_fine_scan": true,
"psi_thr": 0.25,
"corr_thr": 0.95
}
}
这里的特征名只说明配置格式,实际必须使用原 1,111 候选、角色和参数。读取只保留冻结值与 dtype,
不做外层 rechunk、标签补齐或重试。supervision_group 校验非 Train 标签已经物理为 null,违规即拒绝。
读取成本独立计时,不重新执行 Agent bootstrap、人口准备或模型训练。
冻结 selector 入口只默认传入 CLI 的列批宽和 n_jobs,其余参数遵循配置及库默认,
不会继承合成场景的 sentinel、粗分箱箱数或关闭 RC 等配置。实际复现时应从原计划完整复制这些业务选项。
python benchmarks/benchmark_core_capacity.py --case frozen_selection --input-config /local/selector.json --backend polars --threads 1 --n-jobs 1 --batch-size 16 --repeats 1 --output .artifacts/m12-selector.json
风险画像应另用开发人口 257,997 行及 Train benchmark 180,893 行的配置,不能与 selector 全人口混算。 实际非空监督人数从冻结输入读取,不强行等于 Train 分区行数。
python benchmarks/benchmark_core_capacity.py --case frozen_risk --input-config /local/development-risk.json --backend polars --threads 1 --n-jobs 1 --batch-size 16 --repeats 1 --output .artifacts/m12-development-risk.json
frozen_risk 使用 MarsBinEvaluator.evaluate() 单次公开风险画像;frozen_profile 单独验证统计画像。
风险配置使用 risk_parameters 与 risk_call_parameters 保存原分箱/评估选项,文件路径及完整候选仍使用上面的结构。
回归与公开案例¶
定向缺陷、执行路径和数值回归在 Python 3.8/Polars 1.8.2 与 Python 3.12/Polars 1.42 均为 80 passed。分箱相关既有套件在旧环境及 Python 3.10 各 121 passed;最终新增分箱执行测试各 19 passed。 容量 harness 现代环境最终 43 passed,包含 frozen_profile/risk/selection 三个不同公开入口的 fresh worker 测试。 基础套件完成后,仅对 benchmark 冻结配置隔离新增两条回归;旧环境重跑这两条及三个 fresh 入口,5 passed。 下表基础套件计数不包含最后新增的这两条测试。 测试规模只证明对应合同,不能当作真实 M12 容量结论。
最终基础套件均正常退出 0,0 failed:
| 环境 | passed | skipped | deselected | 秒 |
|---|---|---|---|---|
| Python 3.8.20 / Polars 1.8.2 / Pandas 2.0.3 | 1233 | 13 | 7 | 294.29 |
| Python 3.12.13 / Polars 1.42.0 / Pandas 3.0.3 | 1332 | 3 | 7 | 323.92 |
旧/现代定向套件各 80 passed。日志为 .artifacts/m12-upstream/verified{38,312}.log 和
final-targeted{38,312}.log,包含外部 protobuf、统计模型数值和系统中文字体等 warning,未屏蔽警告。
Ruff、Mypy(159 source files)、公共 pydoclint、私有 docstring checker 和 git diff --check 通过。
私有 checker 的简单 helper 长 docstring 提示为既有 warning,无阻断错误。
Python 3.9/3.11 未在本轮重跑完整套件,既有 Python 3.8–3.12 CI 矩阵和约束保持原样。
正式基础套件使用下列命令,环境变量在解释器启动前设置。PYTHONPATH 必须为绝对源码路径,
以保证下载 ZIP 在仓库外的新进程也读取本轮源码。Windows 的文本子进程统一设置 PYTHONUTF8=1。
python -m pytest -q -m "not docs_ml and not optional_ml" --ignore=benchmarks/_artifacts --basetemp=.artifacts/m12-upstream/verified
python -m ruff check src tests scripts benchmarks
python -m mypy src/mars
pydoclint src/mars
python scripts/check_private_docstrings.py src/mars
git diff --check
python -m mkdocs build --strict --site-dir .artifacts/m12-upstream/site
python scripts/check_case_assets.py --mode public --site-dir .artifacts/m12-upstream/site
--ignore 仅排除本机历史生成的 benchmark 测试产物,正式 tests/ 没有跳过。
最初逐字运行不带 ignore 的命令,在收集旧产物时因 Windows ACL 失败;未改文件权限或删除旧数据来隐藏失败。
初次显式 tests 套件还发现相对 PYTHONPATH 的子进程导入旧包及 GBK 解码问题,已用环境配置纠正,未放宽断言。
新 nullable WOE 测试最初给浮点映射传入 None,触发既有合法性错误;随后改为合法映射和测试边界的
nullable 输出注入,产品仍拒绝非法映射。所有初始日志保留,不将中间失败写成正常退出。
独立附加 sandbox 的 frozen_profile 一次在 report_save 停留后被人工取消,worker exit 15, pytest 记录失败,不能计作成功或 OOM;其前段 public_compute 完成并不代表整链成功。 正式解除已确认的沙箱临时目录/硬链接限制后的 harness 测试正常退出,不改 worker 回收或保存合同。 案例生成最初的 Python 3.10 wrapper 也曾人工取消,无产物;正式过程沿用原 Python 3.12 环境。
公开 Home Credit 案例通过正式 compute all → consume → finalize,最后 Stats 变更后重算 case 3。
共更新 59 个相互依赖的生成产物,约 42.4 MB,未手填指纹或身份。
准备摘要、元数据、预览与两张原生 PNG 逐字节不变;五份快照的 47 张查询表、9,325 行按正式容差对照通过。
全部既有 summary 业务字段保持,仅增加四个 WOE 算法描述参数。
源码指纹一致,public/site checker 通过 72 files、11 snapshots、seven cases;严格文档构建通过。
此处没有重跑 README/官网视觉,也没有将公开 119 候选案例误计为 M12 的 1,111 候选。
历史证据和 Agent 适配边界¶
历史 development risk 的 70 批成功是 257,997 行、1,111 特征、基准 180,893 行,日志 155.83 秒、 worker lifetime RSS 7,770,259,456 bytes;它没有证明 297,440 行原生 selector 成功。 v12 包装器返回 1,并报告 abnormal termination/Invalid signal。日志最大 RSS 为 9,058,844,672 bytes, peak footprint 为 34,313,599,264 bytes,两个口径不同。最近失败位于 rough performance 后、stability 完成前; 没有瞬间分配栈,不能把尚未开始的全局 corr 当成唯一原因,也不能把所有退出码写成 137。
单线程旧 Polars 的多 chunk 上游缺陷及 schema eager 物化已有可撤除外层 workaround 的定向证据。 真实 1,111 特征完整风险画像和 selector 尚未跑通本轮独立验收,70 批外层拼报告及 Runtime 适配的 整体撤除仍需另行验证。Runtime Snapshot/Registry/审批/预算/身份/恢复策略、冷恢复 IPC hash 和 准备报告未持久化造成的重算均未修改,不能列为 MARS 已修复。
2026 年 10 月 23 日独立验收修补¶
本次起点为 main 的 ff0a0fd2251215bfd8e788b58dcde052ed866a2a,工作树干净。
未发现适用的 AGENTS.md。本节记录当前未提交修改,包版本仍为 0.0.28。
以上历史容量与回归记录保持原样,不能自动升级为本次新比较合同的验收证据。
已只读核对该提交的远端 CI: 3.9 和 3.11 的 WOE 用例失败,3.10 和 3.12 取消; Docs 构建、部署成功。 用户提供的 1235 passed、1234 passed / 1 failed、1333 passed / 1 failed 只属于该次远端任务。 本次未推送,不能宣称修后远端 CI 全绿。
Join 行序和监督标签¶
现代 Polars streaming Hash Join 可以重排左表。原表现统计在 Join 后按外部 Series 的位置挂标签,
同时改变了数值特征和类别特征的逐箱坏样本数。普通 collect 或单线程可能掩盖错误。
mars._compat._left_join_preserving_order 按实际 Join 签名使用 maintain_order="left";
没有该参数的旧 Polars 使用内部行身份恢复左表行序。数值、Replace 和多个 Join 路径均保序。
无需唯一业务 ID,完全重复行仍保留原位置和行数。
MarsBinnerBase.profile_bin_performance 先投影本批特征,再绑定已规范化标签,
随后按该标签过滤已观测人口、转换并聚合。新增成本为本批一列标签,不复制全宽已观测表。
临时列名统一避让原字段、请求特征、派生列和已有内部列,并在输出前清理。
MarsStatsSelector._woe_row_blocks 和临界 pair 复核使用项目真实 streaming 入口;
各列批在同一已观测行序上写入 NumPy 行块。全局 Float64 Pearson、严格 > 阈值、IV/ID 优先级、
白名单、事件顺序及最终候选原序保持原合同。
Python 3.12.13 / Polars 1.42.0、导入前线程 4 的独立修前重放中, Join 重排 68/70 个已观测位置,按位置挂载外部标签有 38/70 个错配;标签随样本携带时为 0。 修后重排和错配均为 0。下表按 bin_index 展示同一数值特征;修后 Join 与 Replace 完全一致。
| bin_index | count(两版相同) | 修前 Join bad | 修后 bad | 修前 Join WOE | 修后 WOE |
|---|---|---|---|---|---|
| -3 | 10 | 6 | 10 | 0.117782 | 12.429220 |
| -1 | 10 | 5 | 0 | -0.287680 | -12.716901 |
| 0 | 10 | 6 | 0 | 0.117782 | -12.716901 |
| 1 | 10 | 5 | 10 | -0.287680 | 12.429220 |
| 2 | 10 | 5 | 0 | -0.287680 | -12.716901 |
| 3 | 20 | 13 | 20 | 0.331356 | 13.122365 |
IV 从错误的约 0.070260 恢复为 Replace 参考的约 25.492693。
Hash Join 的错误排列不保证每次相同,这些数字只描述已保存的这一轮重放。
原远端失败用例保留;未改变期望 WOE、数值容差或最终统计表排序来消除失败。
详细修前/后记录为本机 .artifacts/p01-streaming-evidence.json。
空 PSI 的校验和状态¶
原画像入口按当前表 height 跳过整个 PSI 流程,也跳过了 benchmark 结构校验。
现在由 get_psi_trend 在空人口早返之前校验既有 active feature 范围;缺特征、类型不兼容和
空 benchmark 均保留原 ValueError 与说明,不要求基准携带当前 group/time 角色。
空当前人口不拟合分箱;结构合法的全 null 基准也不会触发无用拟合。
有 group、time 或合法 benchmark 的空人口返回 Float64 typed null,具体 PSI 状态行为
not_computed / empty_current_population。没有任何参考时继续使用
not_computed / no_group_or_benchmark。零候选不生成虚构特征。
身份、原 dtype、中文名、来源、单位和列序保持;其他指标状态和诊断继续保留。
状态可经目录、查询、AI 上下文、Notebook、HTML 以及保存后新进程加载读取。
修前/后小证据为 .artifacts/p02-empty-psi-{before,after}.json。
容量比较的自动门¶
benchmark_core_workloads.py 为 frozen current 和 benchmark 各做读前/读后 1 MiB 分块 SHA256,
并检查读入期间文件属性是否改变。记录算法、大小、实际路径和 reader/rechunk 配置;
路径只作本机溯源,相同字节复制到其他目录仍可比较。
合同绑定完整特征顺序、角色、业务参数、监督范围;合成场景绑定 fixture 版本、seed 与有效生成参数。
源码 SHA 仅作溯源,不作为同业务实现的拒比依据。
候选用完整特征表中的整数位置记录,覆盖 Quality、Rough、Fine、Stability、PSI、RC 和全局 Corr 的实际去向、corr 候选原序、最终名单原序及计算状态。至少 80% 进入 corr 仍只是规模 guard。 200→161、最终 198→159,同数量但字段或顺序不同,以及任一预热/正式轮漂移,均不得输出普通比例。
新增单个私有 _capacity_evidence.py,复用既有 ReportSnapshot 保存聚合语义证据。
每个预热和正式轮保留一个有大小边界的私有 .marsreport,先校验完整性、报告身份及本轮表签名,
再对照完整目录、逻辑 schema、行序、null、非浮点值、名单、动作、触发特征、保护状态与事件顺序。
有限浮点指标和决策系数采用 atol=rtol=1e-12;null、NaN、正负无穷分别核验。
阈值严格相等,容差不重做业务判定。约 1e-15 的相关系数差可以通过,WOE 12→0.1 必须拒绝。
仅排除已登记的报告身份和实现参数,以及画像报告自身的生成时间;未知元数据差异继续拒绝。
sidecar 默认位于已有忽略目录 .artifacts,可用 --evidence-dir 指定本机位置。
独占创建唯一文件名,失败清理本轮文件,重复执行不覆盖旧结果。后续比较必须保留 JSON 引用的快照;
缺身份、缺文件、损坏或语义证据不足的旧 JSON 明确为 incomparable,不补造历史身份或验收结论。
真实业务报告只留本机忽略目录,不提交或上传。
整个公开调用、生产必要的完整报告构造仍在一个 fresh worker 连续计量。 输入身份、报告签名/保存/完整性与 baseline 语义校验分别记录时间,不计入 public_compute。 资源策略有目的的比较保留既有规则,业务工作变化仍然拒比。 历史 39.7% / 30.6% 是上一轮人工复核的中型观察,没有被新门追认或推翻。 如需新的实现 A/B,必须用同一修正 harness 在两侧重新生成 baseline/current。
本次验证范围¶
tests/test_binner_streaming.py 每项启动新解释器,并在首次导入 Polars 前设置线程 1 或 4,
断言真实线程池大小。每组覆盖 eager、普通 collect、项目 collect_streaming、两个类别 Join、
19 特征和列批 1/16/100、非等长多 chunk、重复行、未表现标签、Missing/Special/Other、未知类别、
独立逐行计数和 Replace 数值参考、完整 dense WOE 矩阵、pairs、decisions、名单、cache/refit,
以及正式规则和报告保存后新进程加载查询。五组各 2 passed,均退出 0,无跳过:
| Python | Polars | Pandas | 新线程/引擎测试 |
|---|---|---|---|
| 3.8.20 | 1.8.2 | 2.0.3 | 2 passed |
| 3.9.20 | 1.36.1 | 2.3.3 | 2 passed |
| 3.10.19 | 1.37.1 | 2.3.3 | 2 passed |
| 3.11.15 | 1.42.0 | 3.0.3 | 2 passed |
| 3.12.13 | 1.42.0 | 3.0.3 | 2 passed |
这些均为本机 Windows 实测;未运行 Polars 1.44.2 或 Linux/macOS 矩阵。 既有 Python 3.8~3.12 CI 和 frozen constraints 未改变,未把 CI 全部任务改为单线程。 空 PSI 新增 83 项在 Python 3.8 / Polars 1.8.2 通过;现代画像关联组共 151 passed,均正常退出 0。 早期测试曾因旧 Categorical dtype 显示和子进程误导入旧安装包失败,最终测试显式使用当前 src。 沙箱内报告 hardlink 保存另曾触发 WinError 5;首次失败未计为通过,受影响检查随后在获准的限制外执行。
公开 Home Credit 三份原始 CSV 可用,已用正式生成器重算 all,随后 consume、finalize。
11 份快照的 80 张表、10,138 行通过正式语义对照,最大浮点绝对差为 2.7755575615628914e-17。
两张原生 PNG 逐字节相同;SVG 为正式重新导出,图形布局和字体代码未修改。
这份公开输入是 356,255 行、119 候选,不能替代真实 M12 的 1,111 候选容量验收。
本次没有取得 M12 冻结 Prepared/manifest,未运行真实 257,997 风险画像或 297,440 selector,
未启动 Runtime/Agent、训练预测模型、改业务输入、改包版本、提交、推送、发布或部署。
本次 fresh-worker smoke 包含 survivors 与 frozen_profile 各自的 baseline/current、预热/正式轮,
验证保存 JSON 后的下一次命令能读取保留 sidecar。另用同一个新 harness 在 c937fbf 旧 dense
源码和当前源码各生成一个独立 survivors smoke worker,二者均 passed、退出 0;
输入、执行、资源合同和阶段集合一致,完整 Report 内容核验通过。
这些 smoke 只证明比较门可用,没有重新测量或替代前文中型容量比例。
正式命令使用各环境的实际解释器,并在启动前设置当前源码路径及 UTF-8。
完整基础套件的 --ignore 只排除本机历史生成的 benchmark 产物,没有跳过正式 tests:
$env:PYTHONPATH = (Join-Path $PWD 'src')
$env:PYTHONUTF8 = '1'
$env:POLARS_MAX_THREADS = '4'
python -m pytest -q -m "not docs_ml and not optional_ml" --ignore=benchmarks/_artifacts --basetemp=.artifacts/acceptance-full
python -m pytest -q tests/test_binner_streaming.py tests/test_binner_execution.py tests/test_analysis_batching.py tests/test_stats_blocked_correlation.py tests/test_profile_empty_psi.py tests/test_core_capacity_benchmark.py
python -m ruff check src tests scripts benchmarks docs/snippets
python -m mypy src/mars
pydoclint src/mars
python scripts/check_private_docstrings.py src/mars
python -m mkdocs build --strict --site-dir .artifacts/acceptance-site
python scripts/check_case_assets.py --mode public --site-dir .artifacts/acceptance-site
git diff --check
独立线程测试仍在其子进程内分别覆盖 1 和 4,不以父进程的线程值冒充两个环境。
案例正式流程为 task_cases.py --phase compute --case all、--phase consume 和 --phase finalize;
先在忽略目录完整生成并对照,再同步正式报告、manifest、ZIP 和下载资源,共更新 59 份生成文件。
公开 checker 通过 72 files、11 snapshots、seven cases;文档/案例回归为 100 passed、2 deselected,退出 0。
Ruff、Mypy(159 source files)、公共/私有 docstring 检查和 diff check 均通过。
私有 checker 的简单 helper 提示、外部依赖弃用及既有字体 warning 未屏蔽。
源码与测试冻结后,完整基础套件结果如下,failed 均为 0,进程退出码均为 0:
| 环境 | passed | skipped | deselected | 秒 |
|---|---|---|---|---|
| Python 3.8.20 / Polars 1.8.2 / Pandas 2.0.3 | 1361 | 13 | 7 | 436.48 |
| Python 3.12.13 / Polars 1.42.0 / Pandas 3.0.3 | 1460 | 3 | 7 | 503.14 |
日志分别为 .artifacts/acceptance-full38-frozen.txt 和 .artifacts/acceptance-full312-final.txt。
7 deselected 来自既定 not docs_ml and not optional_ml 范围;skipped 保留实际报告,未计作通过。
最初旧环境整套为 1306 passed、12 failed、13 skipped、7 deselected,退出 1,
12 项均为新增测试对旧 Categorical 字符串的错误假设。该日志仍保留在
.artifacts/acceptance-full38.txt,不与最终结果合并计数。
最终容量文件在 Python 3.8 / Polars 1.8.2 和 Python 3.9 / Polars 1.36.1 各 84 passed,
无 skipped/deselected,退出 0;包含两个真实多 worker A/B 闭环及本轮自身表签名校验。
Python 3.11.15 / Polars 1.42.0 / Pandas 3.0.3 的分箱、列批、全局相关性、空 PSI 和容量
关联组为 241 passed,退出 0,日志 .artifacts/acceptance-target311-final.txt。
Python 3.9 和 3.10 的原分箱/列批/相关性/兼容定向组各 80 passed,退出 0。
本次未在 3.9、3.10、3.11 重跑完整基础套件,不以这些定向结果冒充整套或远端 CI。
交付时仍为 main,HEAD 未变化。工作区共有 75 个变更文件,
其中 59 个为正式生成的案例资源,16 个为实现、测试和文档;3 个新文件尚未跟踪。
CI 矩阵、constraints、包版本、原生图字体/布局、raw/binned KS 和 Excel 模板均未修改。
验收完成后,用户另行授权提交并推送本轮修复。上文未提交、未推送的说明以验收截止时点为准; 新提交的远端 CI 和 Docs 结果须另行核对,不沿用本机或旧提交的通过记录。
推送后的 Linux CI 修正¶
提交 4068c7a 的 CI
在 Python 3.9 和 3.12 各失败两项容量闭环,Docs 成功。
增加完整拒比诊断后的 CI
确认失败来自 native_threadpools 枚举顺序,库集合、线程数与架构实际相同。
Linux 的库加载枚举次序在不同 fresh worker 间变化,原比较误将列表位置当作资源策略。
例如同一组 libopenblas/SkylakeX/4、libgomp/4、libopenblas/Prescott/1 和
libscipy_openblas/SkylakeX/4 在各轮换序,导致拒比;这不是计算结果差异。
现在仅对比较用的既有线程池字段投影按稳定内容排序,保留全部记录及重复次数,
原始 effective_native_threadpools 仍原样保存。
线程数、库身份/API、架构、库增减和重复数量变化继续触发原资源策略门,
有明确对照目的时仍标为 resource_strategy_comparison。
输入身份、实际工作量、表顺序、sidecar 完整性及数值容差均未改变。
本次仅修改 benchmark、回归和说明,案例计算源码指纹未改变,无需重生成业务报告。
修后完整容量回归在 Python 3.8 / Polars 1.8.2、Python 3.9 / Polars 1.36.1 和 Python 3.12 / 隔离 Polars 1.44.2 各为 94 passed,均退出 0,无 skipped/deselected。 其中新增 10 项锁定换序、线程数、库身份/API、架构、字段缺失、增减及重复库数量的边界。 Ruff、diff check 和严格 MkDocs 构建通过;本机结果不代替后续新提交的远端结果。