Files
admin 0593ff7e62
nginx serve /uploads direct (audio speed) / patch-nginx (push) Failing after 1m34s
数字我 Digital Me:全量入库(大文件走 Git LFS)
2026-10-10 16:24:43 +08:00

91 lines
5.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 采【加权求和版】引擎的产出 —— 这一刀的「旧版」参照。
//
// ★★ 这个脚本【只在改 dynasties.js 之前跑过一次】,跑完它采下来的 dynasties-weighted-sum.json
// 就是死的。★ 绝不要在改完引擎之后再跑它来「更新」参照 —— 那等于把被告改成原告。
//
// ⚠ 它自证真伪:采下来的五个单轨朝代,指纹必须与 dynasties-pre-multitrack.json 里
// 【旧代码采的那份】逐字相同。对得上 ⇒ 这份快照确实是旧引擎的产出,不是我编的。
// (本项目的铁律:最难发现的错是「假订正」。一份自己造的「旧版」参照,就是假订正的温床。)
//
// 跑:node scripts/capture-weighted-sum.mjs
//
// ⚠ 它住在 scripts/ 而不是 test/,是【故意的】:`node --test` 会把 test/ 底下的【每一个】文件
// 都当测试跑(不只是 *.test.js)。而本脚本的自证在引擎改完之后【必然抛异常】——
// 那是它设计上的正确行为,却会把 npm test 弄红。放在 scripts/ 下,它才是它该是的东西:
// 一次性的采集工具,不是测试。
import crypto from 'node:crypto';
import fs from 'node:fs';
import { DYNASTIES, computeRank, profileFromSubs } from '../src/dynasties.js';
import { SUB_REGISTRY } from '../src/talents.js';
// ⚠ 必须与 dynasties-tracks.test.js 的 matrix() 【完全同构】,否则指纹对不上。
function matrix() {
const ALL = SUB_REGISTRY.map((s) => s.id);
const combos = [[]];
for (const s of ALL) combos.push([s]);
for (let i = 0; i < ALL.length; i++) for (let j = i + 1; j < ALL.length; j++) combos.push([ALL[i], ALL[j]]);
combos.push(['rigorous', 'datadriven', 'concise', 'shortfirst', 'patient', 'calm']);
combos.push(['poetic', 'story', 'vivid']);
combos.push(['socratic', 'humor', 'poetic', 'story', 'vivid']);
combos.push(['blunt', 'motivate']);
combos.push(ALL);
const out = new Map();
for (const subs of combos) {
for (const wang of [0, 30, 55, 60, 75, 80, 90, 100]) {
out.set(`${subs.join('+') || '∅'}|w${wang}`, profileFromSubs(subs, { wang }));
}
}
return [...out.entries()];
}
// ── 自证:五个单轨朝代的指纹必须与【旧代码采的】 pre-multitrack fixture 对得上 ──
const PRE = JSON.parse(fs.readFileSync(new URL('../test/fixtures/dynasties-pre-multitrack.json', import.meta.url), 'utf8'));
const rows = matrix();
if (rows.length !== PRE._matrix.count) throw new Error(`矩阵变了:${rows.length} ≠ ${PRE._matrix.count}`);
const sorted = rows.slice().sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
for (const d of ['han', 'weijin', 'nanchao', 'tang', 'ming']) {
const h = crypto.createHash('sha256');
for (const [k, p] of sorted) h.update(k + '|' + JSON.stringify(computeRank(p, d)));
const got = h.digest('hex');
if (got !== PRE.hashes[d]) {
throw new Error(
`✗ ${d} 的指纹与 pre-multitrack 对不上 —— 当前代码【已经不是】加权求和版了。\n` +
' 这个脚本只能在改引擎【之前】跑。现在跑它,采到的是新引擎的产出,' +
'整个「新旧对照」就成了自己跟自己比。'
);
}
}
// ── 采:七朝 × 1128 profile 的【判定投影】──
// ⚠ 只采判定相关的格子,不采 reasons/cites(那是文案,几十 MB,且不参与判定)。
const proj = (r) => (r === null ? null : {
ch: r.channel ? r.channel.id : null,
tier: r.rank.tier,
title: r.rank.title,
grade: r.rank.grade,
unit: r.rank.unit,
ceil: r.ceiling ? r.ceiling.tier : null,
cat: r.category || '',
stig: !!r.stigma,
blk: r.blocked.length,
});
const out = {
_what: '【加权求和版】引擎(score += val(k)*weight → tier = round(score/100*5))的产出,七朝 × 1128 profile。',
_why:
'★ 这一刀【必须】让输出变(原文里没有加权求和的原型)。所以这个文件【不是迁移锁】—— ' +
'它是【被告】:新引擎每改动一格,都要在 dynasties-shape.test.js 里说清楚是哪条原文要求它这么改。',
_dontRegen:
'★★ 绝不要用新引擎重新生成本文件。它的全部价值在于它是【旧代码】的产出。' +
'重生成 = 把被告改成原告 = 本项目铁律里的「假订正」。' +
'自证:五个单轨朝代的指纹与 dynasties-pre-multitrack.json 逐字相同(采集时已校验并通过)。',
_capturedBy: 'scripts/capture-weighted-sum.mjs(2026-07-16,改引擎之前)',
_matrix: PRE._matrix,
_selfCheck: '✓ han/weijin/nanchao/tang/ming 五朝指纹 = dynasties-pre-multitrack.json 的指纹(采集时校验通过)',
rows: Object.fromEntries(
sorted.map(([k, p]) => [k, Object.fromEntries(DYNASTIES.map((d) => [d.id, proj(computeRank(p, d.id))]))])
),
};
fs.writeFileSync(new URL('../test/fixtures/dynasties-weighted-sum.json', import.meta.url), JSON.stringify(out));
console.log(`✓ 采到 ${sorted.length} 个 profile × ${DYNASTIES.length} 朝;五朝指纹自证通过。`);