feat(consult): career answers don't guess the field — strength/resistance/timing + one ask; follow-up reads a stated job (BUG-1176 decision); goldens regenerated; rubric round-4 pass lines; backtest script career follow-up

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
Jesse_Chen
2026-10-02 09:12:06 +08:00
co-authored by Claude Opus 5.5
parent ffafa28b79
commit 6a02e5e91e
11 changed files with 82 additions and 35 deletions
@@ -29,6 +29,7 @@
* [--out <dir>] [--repeats 2] [--figures a,b] [--domains parents,marriage,health,career] \
* [--model deepseek-flash] [--base-url https://api.deepseek.com] [--concurrency 4] [--dump-cards]
* [--correction barack_obama,marilyn_monroe] [--correction-text 我爸其实没怎么管过我]
* [--correction-domain career] [--correction-texts "zinedine_zidane=我是足球运动员|barack_obama=我是政治家"]
*
* --dump-cards writes the model-visible tool result per figure x domain and
* calls no model. --correction adds, for each listed figure's parents answer,
@@ -130,6 +131,13 @@ function parseArgs(argv: readonly string[]) {
recheck: value("recheck"),
correction: value("correction")?.split(",").filter(Boolean) ?? [],
correctionText: value("correction-text") ?? "我爸其实没怎么管过我",
// Follow-up domain (default parents) and optional per-figure texts
// "figure=text|figure=text" (career follow-up: the user states the real job).
correctionDomain: value("correction-domain") ?? "parents",
correctionTexts: Object.fromEntries((value("correction-texts") ?? "").split("|").filter(Boolean).map((pair) => {
const at = pair.indexOf("=");
return [pair.slice(0, at), pair.slice(at + 1)];
})) as Record<string, string>,
};
}
@@ -544,22 +552,22 @@ async function main() {
return { figure: job.figure.id, domain: job.domain, run: job.run, chars: result.output.length, ...result, output: undefined, checks };
});
const corrections = await pool(
jobs.filter((job) => job.domain === "parents" && args.correction.includes(job.figure.id)),
jobs.filter((job) => job.domain === args.correctionDomain && args.correction.includes(job.figure.id)),
args.concurrency,
async (prior) => {
const priorFile = join(args.out, prior.figure.id, `parents-run${prior.run}.md`);
const priorFile = join(args.out, prior.figure.id, `${prior.domain}-run${prior.run}.md`);
const priorText = readFileSync(priorFile, "utf8");
const priorAnswer = priorText.slice(priorText.indexOf("\n---\n\n") + 6).trim();
const job: Job = { ...prior, question: args.correctionText, followUp: { priorQuestion: prior.question, priorAnswer } };
const job: Job = { ...prior, question: args.correctionTexts[prior.figure.id] ?? args.correctionText, followUp: { priorQuestion: prior.question, priorAnswer } };
let result: Awaited<ReturnType<typeof runJob>>;
try {
result = await runJob(job, resolved);
} catch (error) {
result = { output: "", failure: error instanceof Error ? error.message : String(error), executed: [], seconds: 0, usage: {}, cardChars: null, visibleChars: null, methodologySections: 0, lookups: 0, finish: null };
}
const file = join(args.out, job.figure.id, `parents-correction-run${job.run}.md`);
const file = join(args.out, job.figure.id, `${job.domain}-correction-run${job.run}.md`);
writeFileSync(file, [
`# ${job.figure.label} · parents 纠正追问 · run ${job.run}`,
`# ${job.figure.label} · ${job.domain} 纠正追问 · run ${job.run}`,
"",
`- 上一轮:${priorFile}`,
`- 追问:${job.question}`,
@@ -572,7 +580,7 @@ async function main() {
result.output || "(无回答)",
"",
].join("\n"));
console.log(`${job.figure.id} parents correction run${job.run}: ${result.output.length} chars, ${result.seconds.toFixed(0)} s${result.failure ? `, FAILED ${result.failure}` : ""}`);
console.log(`${job.figure.id} ${job.domain} correction run${job.run}: ${result.output.length} chars, ${result.seconds.toFixed(0)} s${result.failure ? `, FAILED ${result.failure}` : ""}`);
return { figure: job.figure.id, run: job.run, chars: result.output.length, seconds: result.seconds, failure: result.failure, usage: result.usage };
},
);