| name | update-scramble-stats |
| description | 用户要更新 /scramble/stats(打乱难度 / 步数分布)的数据时执行本地手动增量刷新管道(按需触发,非定时)。覆盖三阶阶段难度(十字/F2L/EO/DR 等)+ 非 3x3 整解最优步数(二阶/金字塔/斜转/SQ1)+ 三阶整解最优 HTM(333 方法,cubeopt WASM,solver/333opt)三条管道。只能本地跑(三阶需 solver 34GB 表 / 333 需 cubeopt 表)。Triggers: "更新统计", "更新打乱统计", "重跑打乱统计", "更新打乱分布", "更新打乱难度", "update scramble stats", "全部刷新统计", "更新十字统计", "重跑十字统计", "跑十字管道", "更新 puzzle 统计", "更新二阶/金字塔/斜转统计", "更新 sq1 统计", "更新 SQ1 统计", "更新 sq1 分布", "刷新 sq1 精确分布", "sq1 精确分布", "sq1 精确档", "跑SQ1怪物", "跑 sq1 怪物", "啃怪物", "啃 sq1 怪物", "sq1 怪物", "grind sq1 monsters", "补 xcross 变体", "双色底 10f xcross", "backfill_xcross_variant", "pseudo_f2leo 回填", "难打乱补变体", "更新333统计", "更新 333 统计", "更新 333 整解统计", "333 整解最优", "333 HTM 分布", "333opt". |
更新打乱统计
一条龙:一个命令 update_cross_stats.ps1,-Jobs 选作业,跑完共享一次发布(commit+push + scp 换 static,覆盖三类产物)。三类作业都只能本地(stages 需 solver 34GB 表 / 333opt 需 cubeopt 表):
发布全增量(2026-06-25):所有作业都只传变化的文件。非 stages 小作业(333opt/puzzles)走 git status diff scp(.tmp+远端原子 mv),秒级;stages 走 publish_scramble_incremental.ps1——维护本地 sha1 内容清单(incremental/publish_manifest.sha1),每次只 diff 出内容真变的文件打小包 scp + 删远端孤儿,把过去每次 ~590MB 整包 tar(~35min)降到典型增量的 changed 小包(几十个 comp_steps + 变动 JSON,分钟级)。首次无清单(或 -Baseline)自动全量 tar 建基线。复用现有免密 ssh cuberoot,不引入 rsync。
PG 灌库也全增量(2026-06-25):wca_scramble_optimal + wca_scramble_steps 以前每次全量 DELETE+\copy / TRUNCATE 重灌(单次 ~270MB),现同样走行级 sha1 内容 diff(pg_incremental_diff.mjs + incremental/pg_*_manifest.tsv)——本地照常 build 全量 CSV,灌库只 UPSERT 内容真变的行 + DELETE 已消失自然键(典型增量几千行=KB,无变化=零传输只刷 meta)。manifest 仅在远端灌库成功后落盘(失败不更新,下次重试)。无 manifest=基线:走原全量路径并建基线;删对应 pg_*_manifest.tsv 即强制全量重建。重复自然键(steps 偶有,WCA dump 同场两套 scramble)diff 侧按首次出现去重 + 服务端 DISTINCT ON 双保险。
| job | 对象 | 内部 | 产物 |
|---|
stages | 3x3 阶段难度(十字/F2L/EO/DR 多阶段多变体) | 内置(取数→std→变体补缺) | distribution.json + wca_cross + comp_steps* + difficulty_first_appearance*(时间线) |
333opt | 3x3 整解最优 HTM(整个魔方最优解) | node solver/333opt/inject.mjs + inject_first_appearance.mjs(折 out.*.csv) | distribution.json + examples.json 的 variants['333'] + difficulty_first_appearance 的 333 注入 |
puzzles | 非3x3(二阶/金字塔/斜转/SQ1) | update_puzzle_stats.ps1 + build_puzzle_examples.ts + build_puzzle_first_appearance.ts | puzzle_distribution.json + puzzle_examples.json + puzzle_first_appearance.json(时间线) |
pwsh core/packages/scramble-stats-build/update_cross_stats.ps1 # = -Jobs all,全跑 + 发布
pwsh core/packages/scramble-stats-build/update_cross_stats.ps1 -Jobs 333opt # 只跑某作业
pwsh core/packages/scramble-stats-build/update_cross_stats.ps1 -Jobs stages,puzzles # 跑多个
pwsh core/packages/scramble-stats-build/update_cross_stats.ps1 -Jobs puzzles -Puzzles sq1 # 选 puzzle
pwsh core/packages/scramble-stats-build/update_cross_stats.ps1 -NoPublish # 只本地不发布
NL 映射(AI 按用户话传 flag):"更新统计"=-Jobs all;"只跑333"=-Jobs 333opt;"跑 X/Y"=-Jobs X,Y;"不跑 X"=去掉 X 后的列表;"不跑 eo" 等变体级=-Variants <去掉eo的列表>(仅 stages 内,见 A)。
要点:
- ⛔ 非 WCA 采样默认停用(2026-06-25 用户要求):
puzzles 作业不再为非 WCA puzzle(335 等 TIER C/D)跑离线采样分布 dist_<event>.json。update_puzzle_stats.ps1 采样步已默认关(加 -Sampled 才跑),一条龙 / 裸跑都不采样。别为「补全分布」把这默认去掉 / 加回采样;要恢复需用户显式说。详见 solver/NONWCA_PUZZLE_LOOP.md §0.0 #12。
- 333opt 只做 inject(折当前
solver/333opt/out.*.csv);那条 ~3.5 天全量求解仍是独立后台 node solver/333opt/solve_loop.mjs(按需续解,见 C),不在一条龙里。
- stages 的 build 会覆写 distribution/examples 的 '333' 变体 → 脚本在 stages build 之后自动补 333 inject 还原(不用再记得手跑;
willInject = run333opt 或 stages有变)。
- 三类作业共享发布;
-NoPublish 一起跳过。
「原始 / 最优打乱」开关数据(/scramble/stats 难度+长度 tab、/timer 真题):每条打乱可切「最优等价打乱」=invert(最优解),同状态最少步。
- 难度 tab puzzle(222/pyram/skewb):analyzer 开
PUZZLE_EMIT_SOLN=1 多产 soln 列(update_puzzle_stats.ps1 已固定开);build_puzzle_examples.ts 反推存第 3 元 [id,scr,opt]。改 analyzer 要 cargo build --release --bin {cube222,skewb,pyraminx}_analyzer。
- 难度 tab 三阶:333opt inject 已带(examples 第 4 元)。
- 长度 tab(3x3 面转族 + 222/pyram/skewb):
build_length_opt.mjs(一条龙 step 5c,增量)产 event_length_examples_opt.json(text→opt overlay);CI 日更的 base 不被覆盖。3x3 走 cube48opt5(972M 表),puzzle 走 analyzer。首跑慢(~1284 个 3x3 解,opt5 ~40min);增量再跑很快。
- /timer 真题最优:走 PG
wca_scramble_optimal(非 static)。一条龙自动灌库(2026-06-14 起,不再手动 \copy):333opt job 在 inject 后跑 solver/333opt/export_optimal.mjs 产 wca_optimal.csv,puzzles job 跑 export_puzzle_optimal.mjs 产 wca_optimal_puzzle.csv,发布步 6b 自动行级增量灌库(2026-06-25 起,见上「PG 灌库也全增量」):sha1 行清单 diff,只 UPSERT 变动行 + DELETE 删除键(无 manifest=基线走原 DELETE+\copy 全量);密码服务器端从 /root/core-api/.env 读(不入仓库脚本)。-NoPublish 一并跳过(只产 CSV 不灌)。前端 OPTIMAL_EVENTS(WcaSourceConfig)gate 开关显示;开关 ON 时 date 模式传 optimal=1(服务端只回有最优等态的真题)、comp 模式客户端过滤,不再静默回退原打乱(某项目覆盖率不足时该池空→回退随机生成)。sq1/魔表无(占位注明)。
「首次出现时间线」数据(/scramble/stats 难度+长度 tab 顶栏「图表 / 时间线」开关:每步数 / 长度第一次出现在哪场比赛,按 comp 开始日期升序、同日按 id):全部走一条龙自动产,无需手动。前端缺数据的组合显「数据生成中」提示(占位,后端照样跑)。
- 难度 stages(十字 / F2L / EO / DR 多变体 × 六/四/双/单色):
build:first-appearance(步骤 5,跟 distribution 一起)→ difficulty_first_appearance.json(顶层 wca 合并池)+ difficulty_first_appearance_wca_<event>.json per-event 分片(前端懒加载)。
- 难度 333 整解最优:
solver/333opt/inject_first_appearance.mjs(步骤 5b,跟 inject.mjs 同位)→ 注入 difficulty_first_appearance.json 的 sets.wca.variants['333']。语义 = 当前已解子集(out.*.csv)内最早,随 solve_loop 推进逼近真值,全量解完即真值。⚠️ stages build 会覆写该 FA 文件丢 333 变体 → 5b 自动重注入还原(同 inject.mjs 的 willInject 逻辑)。
- 难度 puzzle(222 / 金字塔 / 斜转 / SQ1 整解步数):
build_puzzle_first_appearance.ts(puzzles job,跟 build_puzzle_examples 同位)→ puzzle_first_appearance.json(sq1 含 slash 备口径 binsAlt,前端暂只展主口径 WCA 12c4)。
- 长度(3x3 面转族 + 222/pyram/skewb):
build_scramble_lengths.ts 产 event_length_first_appearance.json —— CI 日更自带(stats.yml,跟长度分布同管道),非本地 ps1。
- 前置:比赛日期必须灌好,
incremental.py refresh_competitions 读 WCA export 的 year/month/day+end_* 六列(非 start_date,2026-06-15 修;competitions.tsv 在 D:/cube/scramble/wca_scramble/)。日期空则时间线排序全乱。
- 改任一 FA 文件 shape 必须同步前端
stats/page.tsx 的 Fa*Json 类型 + memo;改 fetch 响应形 bump ?v=。
首页「近期打乱」数据(全自动, 跟一条龙):每跑 stages 或 puzzles 都会附带跑 build:recent-scrambles-events(ps1 步骤 E),产 stats/scramble/recent_scrambles_events.json —— 除 3x3 外所有项目的近期打乱(本次 export 新增, 靠单调 scramble-id watermark incremental/recent_events_watermark.txt 界定批次, 首次无 watermark 则取 export 日期前 30 天的比赛)。每项目按打乱长度分桶;222/金字塔/斜转额外按难度(整解最优步数, join puzzle CSV, 故须在 puzzles 之后)。3x3 本身仍走旧的 recent_scrambles.json(变体×类型×底色)。前端 components/RecentScrambles.tsx + lib/recent-scrambles-events.ts(改 shape 须同步 + bump V)。
下面 A/B/C 是各 job 的内部细节。
A. 三阶阶段难度(update_cross_stats.ps1)
一键(脚本名留 cross 是历史:十字是主阶段,实跑全阶段):
pwsh core/packages/scramble-stats-build/update_cross_stats.ps1
下 results export → 增量挑新打乱 → std_analyzer 全 5 阶段 → 追加 std.csv → 默认再跟 std 锁步补全 6 变体 eo/pseudo/pseudo_pair/pair/f2leo/pseudo_f2leo(按 id 缺补,分块可续)→ 重算 distribution/wca_cross/comp_steps → git push + scp static。
- 交互向导:真人终端裸跑(无参数)自动进向导,全程方向键菜单(↑↓ / Space 多选 / 数字字母快捷 / Enter / Esc)—— 取数前问「TSV 来源(下载官方最新 / 用本地缓存不联网)」,取数后列各变体待补 + 估时,多选「跑哪些变体」+ 单选「每变体几块 / 是否发布」,总览确认再跑;
-Interactive 强制开,-UseCached 单独走不联网取数。AI/带任意 flag/非交互终端不弹,走旧一键。
- 长操作都有进度:下载(每 5%)、解压大 TSV(每 128MB)、扫描(每 2M 行)、solver([PROG] 每 1%)、build(每 20 万行
\r)、scp(每 3s 远端字节)。
- 先
-DryRun 看新增规模(只读);落后多就大补、solver 跑几小时。
- pair / f2leo / pseudo_f2leo 已入默认(2026-06-09);增量只补 delta。瓶颈始终是 eo ~0.9/s。想快跑显式
-Variants eo,pseudo,pseudo_pair 跳过三重型项。
- f2leo/pseudo_f2leo 走大表快路径(
CUBE_ALLOW_HUGE_TABLES=1 已默认;f2leo huge ~31/s、pseudo_f2leo huge ~81/s)。
- 想本地看不发布:
-NoPublish。细节/开关/排错:core/packages/scramble-stats-build/RUNBOOK.md。
第二套数据集:xcross_2_col_10f(双色底 10f xcross)
/scramble/stats 三阶有两个 set(config.yml):wca(全 7 变体,走上面)+ xcross_2_col_10f(静态 1,271,727 条难打乱,数据在 D:\cube\scramble\xcross_2_col_10f\stat\,master=同目录 scrambles.txt)。后者只缺 f2leo/pseudo_f2leo,与 update_cross_stats 解耦,走独立脚本:
pwsh core/packages/scramble-stats-build/backfill_xcross_variant.ps1 -Variant pseudo_f2leo -Hours 5 -Threads 10
- 限时(
-Hours,到点 chunk 边界停 + 末块裁剪;省略=补满)/ 限线程 / 分块可续。两变体都要补:-Variant pseudo_f2leo(暖态 ~21/s,全集 ~17h)、-Variant f2leo(暖态 ~40/s,全集 ~8.8h,但 20GB pair huge 表冷启慢)。
- 只攒 csv,partial 千万别 build(否则该变体 sample_count 残缺误导)。补满 1,271,727 后才
pnpm -F @cuberoot/scramble-stats-build build → 验 distribution.json sets.xcross_2_col_10f.variants.pseudo_f2leo.sample_count==1271727 → push + tar/scp static。
- 进度:
D:\cube\scramble\xcross_2_col_10f\_backfill\backfill_<variant>.log。详见 memory project_xcross_2col_f2leo_backfill。
B. 非 3x3 整解步数(update_puzzle_stats.ps1)
二阶 / 金字塔 / 斜转 / SQ1 的整解步数分布 + 示例。前三个全表查表型精确最优(小表,百万/秒),全量分钟级;SQ1 = 精确双口径(WCA 12c4 可证最优 + slash 最优,均 0 残留全部可证最优),增量已自动接进一条龙(需本机 13GB sq1_wca_jsqfull.bin;详见末条)。
# 全部已注册 puzzle(增量补满,含 sq1)
pwsh core/packages/scramble-stats-build/update_puzzle_stats.ps1 -Puzzles pocket,pyraminx,skewb,sq1
# 再产示例 reservoir(每步数 bin 取 20 条真实比赛打乱 + 比赛名/轮次)
cd core/packages/scramble-stats-build; pnpm exec tsx src/build_puzzle_examples.ts
- 语料自动从三阶管道抽好的
incremental/tsv/Scrambles.tsv 按 event_id 过滤(222/pyram/skewb/sq1),增量落 D:\cube\scramble\puzzle\<key>\。-MaxNew N 限量验形,-BuildOnly 只重算 JSON。
- 产
stats/scramble/puzzle_distribution.json(直方图)+ puzzle_examples.json(示例卡片)。前端 /scramble/stats 难度 tab 选中二阶/金字塔/斜转/SQ1 即显示(PUZZLE_EVENT_MAP → PuzzleDistView)。
- 2×2 / 金字塔「按步数」多口径(2026-07-12):2×2 有 底面/底层/魔方/QTM(face/layer/htm/qtm)、金字塔有 V/魔方(v/cube)四/二个度量,
PuzzleDistView 顶部「度量」下拉切换(选项/标签复用计时器的 step-metrics.ts,单一源)。值由 core/packages/client/scripts/build_puzzle_metrics.mts(client 端,复用计时器求解器 lib/cube222-metric + timer/_lib/solver/pyra,不重造)预算进 D:\cube\scramble\puzzle\<key>\<key>_metrics.csv;update_puzzle_stats.ps1 步骤 2.9 增量跑它(只算 scrambles.txt 里新打乱),build_puzzle_dist.ts / build_puzzle_examples.ts 读该 CSV 产 metrics.<key>.dist / metrics.<key>.bins。同一份预计算同时喂计时器 /timer 的「按步数」WCA 真题筛选(wca_pool.ts 从 puzzle_examples.json 的稀有桶播种 → 稀有区间如底层=0 即时+可靠)。
- 性能:2×2 走
create222MetricEvaluator(全 3.67M 态 BFS 距离表一次 ~10s,之后每条 O(1) 查表),44 万全量 ~1min、增量秒级,单进程无需分片;金字塔逐条求解(~1000/s),增量 delta 秒级。
- 一键入口:
update_cross_stats.ps1 -Jobs puzzles(= update_puzzle_stats.ps1[含 2.9 metrics + 3 dist] → build_puzzle_examples → first_appearance → export_puzzle_optimal)。
- 改 dist/examples shape 须 bump
lib/puzzle-{distribution,examples}.ts 的 V(已 20260712bysteps)。
- SQ1 近最优(twophase)2026-06-18 退役:精确档上线后
update_puzzle_stats.ps1 不再解算 sq1(已移出 $PUZZLE 注册表,改走专门「SQ1 块」)。solver/src/sq1_twophase.rs 仅留作对照(cstimer-vs-TNoodle 上游说明在该模块头)。示例打乱仍用 SQ1 简写记号(formatScrambleForEvent('sq1',scr))。
- SQ1 精确双口径 = 增量自动接进一条龙(2026-06-18):
update_puzzle_stats.ps1 的「SQ1 块」(sq1 不在 $PUZZLE 注册表,单独处理)增量抽 sq1 语料 → 有新打乱且 13GB sq1_wca_jsqfull.bin 在场时,依次跑 inject_sq1_wca_exact.ps1(WCA 12c4 可证最优,Sq1WcaSolver,产 sq1/sq1_wca_exact.csv = id,wca_exact,opt_scramble)+ inject_sq1_slash_exact.ps1(slash 最优),两脚本都按 id 跳过已完成只解 delta。无新打乱→跳过不白载表;表缺失→Write-Warning 跳过(分布留旧值)。⇒ update_cross_stats.ps1 -Jobs puzzles(或 all)现已自动刷新 SQ1 精确双口径并发布。
- 想更准(deferred):双阶段迭代总长 / 更紧剪枝可逼近最优,代价回到长尾;见
solver/SOLVER_LOOP.md P5d。
- 发布:走一条龙共享发布(
update_cross_stats.ps1 -Jobs puzzles 跑完即一并 scp);单独手跑这两步则需手 scp。改 shape 须 bump lib/puzzle-distribution.ts / lib/puzzle-examples.ts 的 V。
- 加新 puzzle(如 SQ1)的全链路范式:
solver/VARIANT_PLAYBOOK.md §8。
C. 三阶整解最优 HTM(solver/333opt/)
整个 3x3 魔方的最优解 HTM 步数分布 —— 前端难度 tab 的 「333」方法(distribution.json 的 sets.wca.variants['333'],阶段只 333,带 HTM/QTM 钮)。完整 runbook 在 solver/333opt/README.md,跑前先读。
node solve_loop.mjs
node inject.mjs
node export_optimal.mjs --verify
- 不 pull:语料 = 管道 A 的 master
D:\cube\scramble\wca_scramble\wca_scrambles_no_wide_move.txt(跟 std_analyzer 同一份合并三阶池,盲拧/多盲的宽块定向已剥、mbf 已拆、带真实 id)。pull.mjs(MySQL 随机抽样)只作快速验形,生产别用。
- 续跑:每解
appendFileSync 即落盘 out.0.csv,断了最多丢正在算的 1 个,重启自动跳过已解(只赔重载表 ~56s)。长跑 detached + BelowNormal 起,挂 Monitor 数 out.0.csv 行数 / 1297444 报进度。
- unwind 崩溃:opt9 in-proc ~5000 解后必抛 emscripten
unwind(pthread 资源累积)。全量必须 solve_loop.mjs(崩了自动重启续跑,零损失),别裸跑 solve.mjs。
- 解法 + 最优打乱 → /timer:
debug=true 抓最优解,out.0.csv = id,htm,solution。最优打乱 = solution 逆序(同态最短打乱)。/timer 真题「原始/最优打乱」二选已建好:migration 0047_wca_scramble_optimal(自然键表)+ routes/wca_scrambles.ts LEFT JOIN 带 o + client wcaUseOptimal 开关(仅同态 333/oh/ft/fm)。update_cross_stats.ps1 -Jobs 333opt 现已自动跑 export_optimal.mjs + 自动灌库(步骤 5b+/6b,见上「原始/最优打乱」一节),不再手动 \copy(代码先部署安全,空表回退原打乱)。
- 实测:opt9 in-proc 12 线程 ~4/s,全量 ~3.5 天。低 CPU + 高内存(15G 表全程驻留 RAM)是大表搜索常态,非卡死。表 64M 分块灌 heap 防 OOM;Node 能 spawn emscripten pthreads(旧说法错的)→ in-proc 多线程是真并行。
MODULE/TABLE/CORPUS/INPROC 可覆盖(表 >4GB 自动 in-proc,≤4GB 走 fork)。
- inject 示例带比赛名:bin=
[真实id,scramble,''],并把这些 id 的比赛/轮次 merge 进 examples.json 的 sets.wca.{comps,idMeta}(源 wca_scrambles_split_mbf.csv+competitions.tsv,口径同 build.ts buildExampleCompMeta)。⚠️ 管道 A 重跑会覆写 examples.json 丢 '333' 变体 → A 之后补跑 node inject.mjs。
- 发布:走一条龙共享发布(
update_cross_stats.ps1 -Jobs 333opt 跑完即 commit+push + scp,且 stages 一跑会自动补 inject 还原 '333');单独手跑 node inject.mjs 则需手 scp。改 JSON shape 仍须 bump stats/page.tsx 的 ?v=;前端改动要 commit+push 才在生产显示。
- QTM 待做:
counts_qtm 暂空(前端 QTM 钮占位)。细节见 memory project_333_optimal_difficulty。