Files
Toolbox/dev_test_scripts/debug/debug_rail_replay_wuyuan.js

112 lines
5.2 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.
/* ============================================================
* debug_rail_replay_wuyuan.js —— 用真实失败案例回放,验证修复有效
*
* 背景:2026-09-30 生成「婺源」时返回 payload_invalid,唯一 error 是
* 「第一天缺「夜逛」环节(night_stroll)」——但 AI 其实排了 19:00 的夜逛。
* 根因是校验器写死了 day.label 含「第一天」,而 AI 标的是「周六/周日」。
*
* 本脚本把那次失败响应的 payload 原样取出来,走一遍「修复 → 校验」,
* 用来证明修复后不再误报(同时也顺带检查其余 warning 是否已消除)。
*
* 用法:
* node dev_test_scripts/debug/debug_rail_replay_wuyuan.js 只回放校验,不写任何文件
* node dev_test_scripts/debug/debug_rail_replay_wuyuan.js --save 额外把这份结果写回
* 技能私有 data/last_result.json,
* 这样用户可在页面上点「载入最近一次生成」
* 直接看到并导出这份婺源行程(不必重烧 token)
*
* 为什么需要 --save:服务端只在「校验 0 errors」时才落盘,那次因误判被丢弃,
* 用户 4 分钟的生成白费了。这个开关是给「已经拿到完整 payload、只想补落盘」的补救场景用的。
* ============================================================ */
const fs = require('fs')
const path = require('path')
const os = require('os')
const SRC = path.join(
os.homedir(), 'AppData', 'Roaming', 'Trae CN', 'User', 'workspaceStorage',
'540d38674b58f7802a478abf6956abc7', 'long-text', '6ab1e0ff40ac82e5fecf1de9',
'munlta58-u92r', '当前状态__失败__....txt'
)
const SKILL = path.join(process.cwd(), 'src', 'server', 'thought_lab', 'labs', 'travel_citytour', 'skills', 'sh_2d_rail_hike')
const skillIndex = require(path.join(SKILL, 'index.js'))
const { validatePayload } = require(path.join(SKILL, 'validate.js'))
const { repairPayload } = require(path.join(SKILL, 'repair.js'))
if (!fs.existsSync(SRC)) {
console.log('找不到失败响应文件(可能已被清理):' + SRC)
process.exit(0)
}
const raw = fs.readFileSync(SRC, 'utf-8')
// 响应体从「返回结果」后的第一个 '{' 开始,到「错误信息」之前结束
const startMark = raw.indexOf('返回结果')
const start = raw.indexOf('{', startMark)
const endMark = raw.indexOf('错误信息', start)
const text = raw.slice(start, endMark > 0 ? endMark : undefined).trim()
let envelope = null
try {
envelope = JSON.parse(text)
} catch (e) {
// 兜底:按大括号配平截取
let depth = 0, endIdx = -1
for (let i = start; i < raw.length; i++) {
if (raw[i] === '{') depth++
else if (raw[i] === '}') { depth--; if (depth === 0) { endIdx = i; break } }
}
envelope = JSON.parse(raw.slice(start, endIdx + 1))
}
const payload = envelope.payload
const bundle = skillIndex.loadBundle()
console.log('===== 婺源失败案例回放 =====')
console.log('原文 error:' + JSON.stringify(envelope.check && envelope.check.errors))
console.log('day.label 实际写法:' + ((payload.timeline && payload.timeline.days) || []).map((d) => JSON.stringify(d.label)).join(' / '))
console.log('AI 是否排了夜逛行:' + ((payload.timeline && payload.timeline.days) || [])
.reduce((a, d) => a.concat(d.rows || []), [])
.some((r) => r.anchor_id === 'night_stroll'))
console.log('')
const repaired = repairPayload(JSON.parse(JSON.stringify(payload)), bundle)
const chk = validatePayload(repaired.payload, bundle)
console.log('— 修复说明 —')
repaired.fixes.forEach((f) => console.log(' · ' + f))
console.log('')
console.log('— 修复后校验结果 —')
console.log('errors : ' + chk.errors.length + (chk.errors.length ? '\n ✗ ' + chk.errors.join('\n ✗ ') : ''))
console.log('warnings: ' + chk.warnings.length + (chk.warnings.length ? '\n ! ' + chk.warnings.join('\n ! ') : ''))
console.log('')
console.log(chk.errors.length === 0
? '✓ 回放通过:这份真实失败的 payload 修复后 0 errors,不再被误判'
: '✗ 仍有 error,需继续排查')
// --save:把修复后的结果补落盘,供页面「载入最近一次生成」使用
if (process.argv.indexOf('--save') >= 0) {
if (chk.errors.length) {
console.log('\n⚠ 仍有 error,拒绝落盘(避免把不合格结果写进 last_result)')
process.exit(1)
}
const outEnvelope = {
ok: true,
payload: repaired.payload,
report_spec: bundle.report_spec || {},
destination_override: null,
check: chk,
meta: Object.assign({}, envelope.meta, {
repairs: repaired.fixes,
recovered_from: 'payload_invalid 误判(校验器已修复)'
})
}
const dataDir = path.join(SKILL, 'data')
fs.mkdirSync(dataDir, { recursive: true })
const out = path.join(dataDir, 'last_result.json')
fs.writeFileSync(out, JSON.stringify(outEnvelope), 'utf-8')
console.log('\n✓ 已补落盘:' + out)
console.log(' 下一步:打开本技能页面 → 点「载入最近一次生成」即可查看/导出这份婺源行程')
}
process.exit(chk.errors.length === 0 ? 0 : 1)