fix(report): persist longform appendix on self-hosted upsert (BUG-576)
Engine calls already returned markdown; the worker failed because local postgres upsert required onConflict and the appendix write omitted it. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -26,7 +26,7 @@ function envCheck(names: string[]): Check {
|
||||
: { status: "ok" };
|
||||
}
|
||||
|
||||
async function jyotishApiCheck(): Promise<Check> {
|
||||
async function jyotishApiCheck(): Promise<{ check: Check; gitCommit: string }> {
|
||||
const started = Date.now();
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 3000);
|
||||
@@ -35,16 +35,28 @@ async function jyotishApiCheck(): Promise<Check> {
|
||||
cache: "no-store",
|
||||
signal: controller.signal,
|
||||
});
|
||||
const body = response.ok
|
||||
? await response.json().catch(() => null) as { git_commit?: unknown } | null
|
||||
: null;
|
||||
const gitCommit = typeof body?.git_commit === "string" && body.git_commit.trim()
|
||||
? body.git_commit.trim()
|
||||
: "unknown";
|
||||
return {
|
||||
status: response.ok ? "ok" : "blocked",
|
||||
message: response.ok ? undefined : `http:${response.status}`,
|
||||
latencyMs: Date.now() - started,
|
||||
check: {
|
||||
status: response.ok ? "ok" : "blocked",
|
||||
message: response.ok ? undefined : `http:${response.status}`,
|
||||
latencyMs: Date.now() - started,
|
||||
},
|
||||
gitCommit,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
status: "blocked",
|
||||
message: error instanceof Error ? error.name : "jyotish_api_unavailable",
|
||||
latencyMs: Date.now() - started,
|
||||
check: {
|
||||
status: "blocked",
|
||||
message: error instanceof Error ? error.name : "jyotish_api_unavailable",
|
||||
latencyMs: Date.now() - started,
|
||||
},
|
||||
gitCommit: "unknown",
|
||||
};
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
@@ -148,7 +160,7 @@ export async function GET() {
|
||||
...databaseChecks,
|
||||
modelProviderEncryption: envCheck(["MODEL_PROVIDER_CONFIG_ENCRYPTION_KEY"]),
|
||||
modelCatalog,
|
||||
jyotishApi,
|
||||
jyotishApi: jyotishApi.check,
|
||||
rectificationMigrations: migrations.check,
|
||||
researchTruthSource: {
|
||||
status: truthSourceIdentity.status,
|
||||
@@ -162,6 +174,7 @@ export async function GET() {
|
||||
timestamp: new Date().toISOString(),
|
||||
deployment: {
|
||||
gitCommit,
|
||||
apiGitCommit: jyotishApi.gitCommit,
|
||||
},
|
||||
database: {
|
||||
latestMigration: migrations.database.latestMigration,
|
||||
|
||||
@@ -48,7 +48,7 @@ async function resolvePersistenceForUser() {
|
||||
persistence: null as PersonalReportService | null,
|
||||
jobs: null,
|
||||
listSections: undefined,
|
||||
loadLongformMarkdown: undefined,
|
||||
loadLongformAppendix: undefined,
|
||||
};
|
||||
}
|
||||
const persistence = createSupabasePersonalReportService(supabase);
|
||||
@@ -57,11 +57,11 @@ async function resolvePersistenceForUser() {
|
||||
userId: user.id,
|
||||
persistence,
|
||||
jobs: createSupabasePersonalReportJobService(supabase),
|
||||
listSections: async (ownerId: string, requestId: string) => {
|
||||
listSections: async (ownerId: string, requestId: string) => {
|
||||
const rows = await sections.list(ownerId, requestId);
|
||||
return rows.map((row) => ({ status: row.status, lastErrorCode: row.lastErrorCode }));
|
||||
},
|
||||
loadLongformMarkdown: async (input: Readonly<{ userId: string; reportId: string }>) => {
|
||||
loadLongformAppendix: async (input: Readonly<{ userId: string; reportId: string }>) => {
|
||||
const appendixRead = await supabase
|
||||
.from(LONGFORM_APPENDIX_TABLE)
|
||||
.select("report_id,user_id,request_id,status,markdown,content_sha256,attempt_count,last_error_code")
|
||||
@@ -70,14 +70,19 @@ async function resolvePersistenceForUser() {
|
||||
.maybeSingle();
|
||||
if (appendixRead.error) return null;
|
||||
const row = parseLongformAppendixRow(appendixRead.data);
|
||||
return row?.status === "ready" && row.markdown ? row.markdown : null;
|
||||
if (!row) return null;
|
||||
return {
|
||||
status: row.status,
|
||||
lastErrorCode: row.lastErrorCode,
|
||||
markdown: row.markdown,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function GET(request: Request, context: RouteContext) {
|
||||
try {
|
||||
const { userId, persistence, jobs, listSections, loadLongformMarkdown } = await resolvePersistenceForUser();
|
||||
const { userId, persistence, jobs, listSections, loadLongformAppendix } = await resolvePersistenceForUser();
|
||||
const { reportId } = await context.params;
|
||||
if (!uuidPattern.test(reportId)) {
|
||||
return NextResponse.json(
|
||||
@@ -103,7 +108,7 @@ export async function GET(request: Request, context: RouteContext) {
|
||||
// a substitute.
|
||||
jobs: jobs ?? undefined,
|
||||
listSections,
|
||||
loadLongformMarkdown,
|
||||
loadLongformAppendix,
|
||||
validateReadyDocument: (document) => {
|
||||
const parsed = safeParseServerReportDocument(document);
|
||||
return parsed.ok
|
||||
|
||||
Reference in New Issue
Block a user