Commit 0746676
feat(safePushData): detailed error reporting and result tracking (#4)
* safePushData: log which fields failed on each retry round
Each failing round now reports the set of offending field paths (with the
AJV keyword) instead of just an item count, split into fields we repaired
and fields that forced a drop. The give-up log lists the fields still
failing.
The set is intentionally not a per-item breakdown: one bad field usually
appears on many items in a batch, and array indices collapse into `/tags/[]`
for the same reason. The list is capped at 20 entries with the overflow
counted.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ek1iV9QVKioLZ3EiL4cPYc
* safePushData: return pushFn's result, rename result fields, fix repair logic
BREAKING: the result shape now names what it holds — `pushed` -> `pushedCount`,
`dropped` -> `droppedItems`, `attempts` -> `attemptCount`. `*Count` is a
number, `*Items` is an array of objects.
Whatever `pushFn` resolves to is handed back as `pushResult` (the successful
call's value; absent when every item was dropped). `PushFn<T, R>` and
`SafePushDataResult<T, R>` carry the type through.
Logic fixes found while reviewing:
- Hitting the attempt cap used to drop the *entire* remaining batch, including
items the API never complained about — the exact data loss this wrapper
exists to prevent. Now only the items still failing are dropped and the
survivors get one final push of their own.
- Sibling array elements were spliced front-to-back, so the second `/tags/N`
path pointed at a shifted array: a valid element could be deleted while the
invalid one stayed. Errors are now applied deepest- and highest-index-first.
- A nested `required` deleted the whole parent object; it now gets the same
placeholder treatment as a root-level one, at any depth.
- An item whose errors are all unactionable (paths it doesn't have) was
re-pushed unchanged until the cap, burning every attempt for the rest of the
batch. It's dropped on the spot instead.
- Give-up drops reported stale errors from an earlier round; the per-item
errors are now reset each round, so they say why the item is failing *now*.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ek1iV9QVKioLZ3EiL4cPYc
* safePushData: broaden the test suite to 53 cases
Covers the gaps left by the previous round: additionalProperties at the root
and nested, mixed error kinds in a single round, JSON Pointer escaping on
placeholder paths, per-item state surviving a splice, dropped items reporting
the caller's original, non-object items, invalid items the API sends no errors
for, the salvage push (its pushResult, its rejection, non-schema errors from
it), maxAttempts: 1, the guard's negative cases, log label formatting, and an
end-to-end mixed batch.
Each of the five logic fixes was mutation-checked: reverting the repair
ordering, the pointer escaping, the salvage push, the no-progress drop, or the
nested `required` handling makes the corresponding tests fail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ek1iV9QVKioLZ3EiL4cPYc
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent f10f256 commit 0746676
3 files changed
Lines changed: 1109 additions & 160 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
27 | 34 | | |
28 | 35 | | |
29 | 36 | | |
| |||
38 | 45 | | |
39 | 46 | | |
40 | 47 | | |
41 | | - | |
42 | | - | |
| 48 | + | |
| 49 | + | |
43 | 50 | | |
44 | 51 | | |
45 | 52 | | |
| 53 | + | |
46 | 54 | | |
47 | 55 | | |
48 | 56 | | |
| |||
73 | 81 | | |
74 | 82 | | |
75 | 83 | | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
76 | 109 | | |
77 | 110 | | |
78 | | - | |
79 | | - | |
80 | | - | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
81 | 114 | | |
82 | 115 | | |
83 | 116 | | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
84 | 120 | | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
89 | 130 | | |
90 | 131 | | |
91 | 132 | | |
| |||
0 commit comments