/** * Measure what the answer model sees after the evidence card * (TASK-consult-evidence-card-20260927 T3), on the research's own cached * engine responses (3 public AA charts x 10 questions, produced by * consult_evidence_card_run.py --cache ; evidence card v2 adds the annual * and timing questions, files `__annual.workflow.json` / * `__timing.workflow.json`). Read-only; runs the production * calculation tool with the cached workflow standing in for the engine. * * node frontend/node_modules/tsx/dist/cli.mjs scripts/research/measure_consult_evidence_card.ts [out.json] */ import { readdirSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { createConsultationRuntimeState, createConsultationTools, } from "../../frontend/src/mastra/consultation-tools.ts"; import type { ConsultationDomain } from "../../frontend/src/lib/consultation-domain-registry.ts"; const QUESTIONS: Record = { career: { domain: "career", question: "未来一年,事业和收入该关注什么?" }, marriage: { domain: "marriage", question: "我的关系模式是什么?" }, wealth: { domain: "wealth", question: "我的财富增长方式和风险点是什么?" }, health: { domain: "health", question: "我近期的身心压力模式和调节重点是什么?" }, education: { domain: "education", question: "我的学习优势、瓶颈和进阶方向是什么?" }, migration: { domain: "migration", question: "迁居、置业或海外发展更适合怎样规划?" }, family: { domain: "family", question: "我的家庭关系与责任边界该如何理解?" }, general: { domain: "general", question: "请综合说明我当前最值得关注的主题。" }, parents: { domain: "parents", question: "我和父母关系如何" }, children: { domain: "children", question: "我和子女的关系如何" }, annual: { domain: "annual", question: "未来一年重点是什么?" }, timing: { domain: "timing", question: "接下来一年哪些时间点重要?" }, }; const [cacheDir, outPath] = process.argv.slice(2); if (!cacheDir) { process.stderr.write("usage: measure_consult_evidence_card.ts [out.json]\n"); process.exit(2); } const serverChart = { name: "public", toolInput: { year: 2000, month: 1, day: 1, hour: 0, minute: 0, city: "cache", lat: 0, lon: 0, tz: 0, ayanamsa: "raman" }, truth: { birthTimeSource: "reported" }, }; async function main(dir: string) { const rows: Array> = []; for (const file of readdirSync(dir).filter((name) => name.endsWith(".workflow.json")).sort()) { const [chart, questionId] = file.replace(".workflow.json", "").split("__"); const question = QUESTIONS[questionId ?? ""]; if (!question) continue; const workflow = JSON.parse(readFileSync(join(dir, file), "utf8")); const state = createConsultationRuntimeState(); const tools = createConsultationTools({ userId: "u", sessionId: "s", requestId: `measure-${chart}-${questionId}`, consultationMode: "verified_chart", serverChart: serverChart as never, state, runWorkflow: async () => structuredClone(workflow), }); const view = await tools["run-jyotish-consultation"].execute!( { question: question.question, domains: [question.domain] } as never, { writer: { custom: async () => {} } } as never, ) as Record; const text = JSON.stringify(view); const methodology = view.methodology ? JSON.stringify(view.methodology).length : 0; const { claim_cards, evidence_card, methodology: _m, ...contract } = view; void _m; rows.push({ id: `${chart}__${questionId}`, chart, question: questionId, domain: question.domain, model_visible_chars: text.length, card_chars: JSON.stringify({ claim_cards, evidence_card }).length, contract_chars: JSON.stringify(contract).length, methodology_chars: methodology, without_methodology_chars: text.length - (methodology ? methodology + ",\"methodology\":".length : 0), token_estimate: Math.round(text.length / 3.5), gaps: (evidence_card as { gaps?: string[] }).gaps ?? [], technique_rows: state.techniqueAuditTable?.length ?? 0, }); } const summary = JSON.stringify(rows, null, 1); if (outPath) writeFileSync(outPath, summary); for (const row of rows) { process.stdout.write(`${row.id}\tvisible=${row.model_visible_chars}\tcard=${row.card_chars}\tcontract=${row.contract_chars}\tmethodology=${row.methodology_chars}\tgaps=${(row.gaps as string[]).join(",")}\n`); } } void main(cacheDir);