fix(confidence-engine): log case-start failures
This commit is contained in:
@@ -16,10 +16,25 @@ export async function POST(request) {
|
|||||||
? result.statusCode
|
? result.statusCode
|
||||||
: 500;
|
: 500;
|
||||||
|
|
||||||
|
const diagnostics = {
|
||||||
|
status,
|
||||||
|
error: result.error ?? "Start case failed",
|
||||||
|
validationErrors: result.validationErrors,
|
||||||
|
analysisErrors: result.analysisErrors,
|
||||||
|
validationIssues: result.validationIssues,
|
||||||
|
rawResponse: result.rawResponse ?? undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (status >= 500) {
|
||||||
|
console.error("[api/cases/start] error response", diagnostics);
|
||||||
|
} else {
|
||||||
|
console.warn("[api/cases/start] error response", diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
success: false,
|
success: false,
|
||||||
error: result.error ?? "Start case failed",
|
error: diagnostics.error,
|
||||||
validationErrors: result.validationErrors,
|
validationErrors: result.validationErrors,
|
||||||
diagnostics: result.diagnostics,
|
diagnostics: result.diagnostics,
|
||||||
analysisErrors: result.analysisErrors,
|
analysisErrors: result.analysisErrors,
|
||||||
@@ -28,7 +43,12 @@ export async function POST(request) {
|
|||||||
},
|
},
|
||||||
{ status },
|
{ status },
|
||||||
);
|
);
|
||||||
} catch {
|
} catch (error) {
|
||||||
|
console.error("[api/cases/start] unhandled exception", {
|
||||||
|
message: error instanceof Error ? error.message : String(error),
|
||||||
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
|
error,
|
||||||
|
});
|
||||||
return Response.json(
|
return Response.json(
|
||||||
{
|
{
|
||||||
success: false,
|
success: false,
|
||||||
|
|||||||
@@ -57,6 +57,12 @@
|
|||||||
- This is a generation-time relationship-reference integrity defect. v0.5 now requires semantic units before relationships and exact reuse of emitted endpoint IDs; legitimate missing endpoint concepts must be materialised first under existing provenance rules.
|
- This is a generation-time relationship-reference integrity defect. v0.5 now requires semantic units before relationships and exact reuse of emitted endpoint IDs; legitimate missing endpoint concepts must be materialised first under existing provenance rules.
|
||||||
- The builder remains unchanged. Live compliance remains untested; next restart point is one production-default relationship-reference-integrity validation.
|
- The builder remains unchanged. Live compliance remains untested; next restart point is one production-default relationship-reference-integrity validation.
|
||||||
|
|
||||||
|
## Case-start error logging
|
||||||
|
|
||||||
|
- The latest live validation was blocked by an HTTP 500 route-level exception with generic client output. `/api/cases/start` now writes structured Next.js server-console diagnostics for every route-owned error response: 4xx at warning level and 5xx/502 at error level.
|
||||||
|
- Caught exceptions log their actual exception, message, and stack while the client response remains generic; successful responses are not logged. No reasoning, status, or response semantics changed.
|
||||||
|
- Next restart point: one production-default manufacturing call while observing the Next.js dev-server terminal.
|
||||||
|
|
||||||
## Current product architecture
|
## Current product architecture
|
||||||
|
|
||||||
Three distinct routes, not a single page:
|
Three distinct routes, not a single page:
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
const mockStartCase = vi.fn();
|
const mockStartCase = vi.fn();
|
||||||
|
let warnSpy;
|
||||||
|
let errorSpy;
|
||||||
|
|
||||||
vi.mock("@/lib/graph/orchestrator.js", () => ({
|
vi.mock("@/lib/graph/orchestrator.js", () => ({
|
||||||
startCase: (...args) => mockStartCase(...args),
|
startCase: (...args) => mockStartCase(...args),
|
||||||
@@ -10,6 +12,13 @@ describe("app/api/cases/start route", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.resetModules();
|
vi.resetModules();
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||||
|
errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
warnSpy.mockRestore();
|
||||||
|
errorSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("delegates request body to the orchestrator", async () => {
|
it("delegates request body to the orchestrator", async () => {
|
||||||
@@ -78,6 +87,8 @@ describe("app/api/cases/start route", () => {
|
|||||||
success: true,
|
success: true,
|
||||||
reconstruction,
|
reconstruction,
|
||||||
});
|
});
|
||||||
|
expect(warnSpy).not.toHaveBeenCalled();
|
||||||
|
expect(errorSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns 400 for invalid request input", async () => {
|
it("returns 400 for invalid request input", async () => {
|
||||||
@@ -102,6 +113,12 @@ describe("app/api/cases/start route", () => {
|
|||||||
success: false,
|
success: false,
|
||||||
error: "Invalid start-case request",
|
error: "Invalid start-case request",
|
||||||
});
|
});
|
||||||
|
expect(warnSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(warnSpy).toHaveBeenCalledWith(
|
||||||
|
"[api/cases/start] error response",
|
||||||
|
expect.objectContaining({ status: 400, error: "Invalid start-case request" }),
|
||||||
|
);
|
||||||
|
expect(errorSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns provider/internal failures as 5xx without stack traces", async () => {
|
it("returns provider/internal failures as 5xx without stack traces", async () => {
|
||||||
@@ -148,6 +165,18 @@ describe("app/api/cases/start route", () => {
|
|||||||
received: "undefined",
|
received: "undefined",
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
expect(errorSpy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
|
"[api/cases/start] error response",
|
||||||
|
expect.objectContaining({
|
||||||
|
status: 502,
|
||||||
|
error: "Provider unavailable",
|
||||||
|
analysisErrors: ["reconstruction: Required"],
|
||||||
|
validationIssues: expect.any(Array),
|
||||||
|
rawResponse,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(warnSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns structured 500 on malformed JSON", async () => {
|
it("returns structured 500 on malformed JSON", async () => {
|
||||||
@@ -163,5 +192,13 @@ describe("app/api/cases/start route", () => {
|
|||||||
success: false,
|
success: false,
|
||||||
error: "Internal server error",
|
error: "Internal server error",
|
||||||
});
|
});
|
||||||
|
expect(errorSpy).toHaveBeenCalledWith(
|
||||||
|
"[api/cases/start] unhandled exception",
|
||||||
|
expect.objectContaining({
|
||||||
|
message: "Unexpected token",
|
||||||
|
stack: expect.any(String),
|
||||||
|
error: expect.any(Error),
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user