fix(report): classify writer failures and size CJK section budgets
Staging personal_full died as report_schema_invalid after the first chapter blocked. Keep assertWriterOutput, stop treating refs mismatch as missing evidence, and surface section error codes on the report APIs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -19,6 +19,7 @@ type ReportListItem = Readonly<{
|
||||
themes: readonly string[];
|
||||
status: "generating" | "ready" | "failed";
|
||||
failureCode: string | null;
|
||||
failureSummary?: string | null;
|
||||
createdAt: string;
|
||||
completedAt: string | null;
|
||||
}>;
|
||||
@@ -57,6 +58,7 @@ function readReports(value: unknown): ReportListItem[] {
|
||||
: [],
|
||||
status: row.status as ReportListItem["status"],
|
||||
failureCode: typeof row.failureCode === "string" ? row.failureCode : null,
|
||||
failureSummary: typeof row.failureSummary === "string" ? row.failureSummary : null,
|
||||
createdAt: typeof row.createdAt === "string" ? row.createdAt : "",
|
||||
completedAt: typeof row.completedAt === "string" ? row.completedAt : null,
|
||||
}];
|
||||
@@ -207,7 +209,7 @@ export function PersonalReportCenter() {
|
||||
查看进度
|
||||
</Button>
|
||||
) : (
|
||||
<span className="report-center-failure">{report.failureCode ?? "生成失败"}</span>
|
||||
<span className="report-center-failure">{report.failureSummary ?? report.failureCode ?? "生成失败"}</span>
|
||||
)}
|
||||
</article>
|
||||
);
|
||||
|
||||
@@ -35,7 +35,7 @@ export type ReportLoadState =
|
||||
| { phase: "not-found" }
|
||||
| { phase: "generating"; progressPercent?: number; progressPhase?: string }
|
||||
| { phase: "timed-out" }
|
||||
| { phase: "failed"; failureCode: string | null }
|
||||
| { phase: "failed"; failureCode: string | null; failureSummary?: string | null }
|
||||
| { phase: "invalid"; message: string }
|
||||
| { phase: "network-error" }
|
||||
| { phase: "ready"; document: ReportDocument };
|
||||
@@ -48,6 +48,7 @@ export interface ReportEnvelopeView {
|
||||
presentationMode: string;
|
||||
status: string;
|
||||
failureCode: string | null;
|
||||
failureSummary?: string | null;
|
||||
createdAt: string;
|
||||
completedAt: string | null;
|
||||
progressPercent?: number;
|
||||
@@ -104,7 +105,14 @@ export function classifyReportEnvelope(statusCode: number, json: unknown): Repor
|
||||
const code = typeof view.failureCode === "string" && view.failureCode.length > 0
|
||||
? view.failureCode
|
||||
: null;
|
||||
return { phase: "failed", failureCode: code };
|
||||
const summary = typeof view.failureSummary === "string" && view.failureSummary.length > 0
|
||||
? view.failureSummary
|
||||
: null;
|
||||
return {
|
||||
phase: "failed",
|
||||
failureCode: code,
|
||||
...(summary ? { failureSummary: summary } : {}),
|
||||
};
|
||||
}
|
||||
default:
|
||||
return { phase: "invalid", message: "报告状态无法识别。" };
|
||||
@@ -293,12 +301,12 @@ export function PersonalReportPage({ reportId }: { reportId: string }) {
|
||||
<main className="flex min-h-svh flex-col items-center justify-center gap-4 px-4 text-center">
|
||||
<TriangleAlert aria-hidden="true" className="size-8 text-warning" />
|
||||
<h1 className="text-xl font-semibold text-ink">报告生成失败</h1>
|
||||
<p className="max-w-md text-sm text-ink-secondary">
|
||||
{state.failureSummary ?? "生成过程中出现问题,未产出可用报告。请稍后重试。"}
|
||||
</p>
|
||||
{state.failureCode && (
|
||||
<p className="font-mono text-xs text-ink-tertiary">错误码:{state.failureCode}</p>
|
||||
)}
|
||||
<p className="max-w-md text-sm text-ink-secondary">
|
||||
生成过程中出现问题,未产出可用报告。请稍后重试。
|
||||
</p>
|
||||
<Button render={<Link href="/reports" />} nativeButton={false} variant="outline">
|
||||
返回报告中心重新生成
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user