112 lines
5.2 KiB
JavaScript
112 lines
5.2 KiB
JavaScript
/* ============================================================
|
||
* 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) |