Milestone v1.0: FamilySync MVP #1
@@ -333,7 +333,23 @@ async function dispatchRow(row: OutboxRow): Promise<DispatchResult> {
|
||||
return { success: true, conflict: false, hardFail: false, transient: false }
|
||||
}
|
||||
|
||||
// Unknown status — treat as transient to avoid silent data loss
|
||||
// IN-02: an unmapped 4xx (e.g. 405, 409, 422) is a permanent client error — retrying it
|
||||
// for the full backoff window just delays settling and burns the attempt budget before
|
||||
// dead-lettering. The transient-eligible 4xx codes (408 request timeout, 429 too many
|
||||
// requests) are already in TRANSIENT_STATUSES and handled above, so any remaining 4xx
|
||||
// here is a hard fail. 5xx, network failures, and truly unknown statuses still fall
|
||||
// through to transient so genuinely recoverable conditions keep their retries.
|
||||
if (status >= 400 && status < 500) {
|
||||
return {
|
||||
success: false,
|
||||
conflict: false,
|
||||
hardFail: true,
|
||||
transient: false,
|
||||
error: `Hard fail: HTTP ${status} for uid=${row.uid}`,
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown / 5xx status — treat as transient to avoid silent data loss
|
||||
return {
|
||||
success: false,
|
||||
conflict: false,
|
||||
|
||||
Reference in New Issue
Block a user