fix(ai): only treat 404 as missing draft, surface real errors

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
centdix
2026-06-10 01:37:33 +02:00
parent 95942ca815
commit 80eeb07514
2 changed files with 23 additions and 9 deletions
@@ -208,6 +208,11 @@ const WORKSPACE = 'global-core-test'
// implementations re-wired in beforeEach.
type SimRow = Record<string, any>
// Mimic the generated client's ApiError shape so the code's `status === 404`
// not-found discrimination behaves the same against the sim.
function notFound(message: string): Error {
return Object.assign(new Error(message), { status: 404 })
}
const scriptRows = new Map<string, SimRow>()
const scriptDrafts = new Map<string, SimRow>()
const flowRows = new Map<string, SimRow>()
@@ -246,13 +251,13 @@ function resetDbSim(): void {
})
setImpl(ScriptService.getScriptByPathWithDraft, async ({ path }: any) => {
const row = scriptRows.get(path)
if (!row) throw new Error(`script "${path}" not found`)
if (!row) throw notFound(`script "${path}" not found`)
const draft = scriptDrafts.get(path)
return { ...row, draft, draft_created_at: draft ? DRAFT_TS : undefined }
})
setImpl(ScriptService.getScriptByPath, async ({ path }: any) => {
const row = scriptRows.get(path)
if (!row) throw new Error(`script "${path}" not found`)
if (!row) throw notFound(`script "${path}" not found`)
return row
})
setImpl(ScriptService.deleteScriptByPath, async ({ path }: any) => {
@@ -295,13 +300,13 @@ function resetDbSim(): void {
})
setImpl(FlowService.getFlowByPathWithDraft, async ({ path }: any) => {
const row = flowRows.get(path)
if (!row) throw new Error(`flow "${path}" not found`)
if (!row) throw notFound(`flow "${path}" not found`)
const draft = flowDrafts.get(path)
return { ...row, draft, draft_created_at: draft ? DRAFT_TS : undefined }
})
setImpl(FlowService.getFlowByPath, async ({ path }: any) => {
const row = flowRows.get(path)
if (!row) throw new Error(`flow "${path}" not found`)
if (!row) throw notFound(`flow "${path}" not found`)
return row
})
setImpl(FlowService.deleteFlowByPath, async ({ path }: any) => {
@@ -2339,6 +2339,13 @@ function finishDraftWrite(stored: WorkspaceItem, existed: boolean, ctx: WriteDra
type DbDraftKind = Extract<WorkspaceItemType, 'script' | 'flow'>
// A 404 from getXByPathWithDraft means the item genuinely doesn't exist (no
// deployed version and no draft). Any other error (network, 403, 5xx) is real
// and must surface rather than be silently swallowed as "no draft".
function isNotFoundError(e: unknown): boolean {
return (e as { status?: number } | undefined)?.status === 404
}
// Returns the localStorage draft ONLY when a live editor is currently mounted
// for the item (i.e. its draft is the live editor's working buffer). A stale,
// non-live localStorage draft is ignored so the DB draft stays authoritative.
@@ -2378,9 +2385,9 @@ async function loadDbDraftItem(
const item = flowToItem(src as Flow, true)
item.isDraft = true
return item
} catch {
// Item doesn't exist (never deployed and no draft row).
return undefined
} catch (e) {
if (isNotFoundError(e)) return undefined // never deployed and no draft row
throw e
}
}
@@ -2450,8 +2457,10 @@ async function deleteScriptFlowDbDraft(
const flow = await FlowService.getFlowByPathWithDraft({ workspace, path })
draftOnly = flow.draft_only === true
}
} catch {
// No backing row; nothing to delete server-side beyond the editor buffer.
} catch (e) {
// 404 = no backing row; nothing to delete server-side beyond the editor
// buffer. Any other error is real and should surface.
if (!isNotFoundError(e)) throw e
}
if (draftOnly) {