Commit 03713b6
authored
fix(sources): never end a run early and call it Completed (ADR D72) (#264)
* fix(sources): never end a run early and call it Completed (ADR D72)
The runner's stuck-cursor guard (#263) bounds a source that makes no progress. This is
the opposite failure direction, which the §6 audit found in four places: a source that
stops early and reports the run Completed with rows missing. Nothing downstream can tell
that apart from a genuinely complete run — no exception, no partial capture, no warning —
which makes it the worst outcome the pipeline can produce.
- Elasticsearch answers a partial search with HTTP 200: it sets `timed_out`, or reports
failed shards under `_shards`, and returns what the responsive shards had. Neither
field was inspected, so the short page simply ended pagination. Both are now checked
before the hits are read, matching what GraphQL (D63) does with a 200 carrying `errors`
and this source's own "full page with no sort values" guard.
- `records.Count == pageSize` is no longer how "is there more?" is decided in OData's
`Skip` and the HTTP source's `Page`/`Offset`. Inferring it from a full page is wrong
whenever the service caps the page below what was requested — Dynamics, SAP Gateway and
Business Central all clamp, and many REST APIs silently reduce an over-max limit, so
against any of them the FIRST page comes back short and the run stopped there. They now
page until a response comes back empty: one extra request per run, and this class of
truncation becomes structurally impossible. NextLink and the cursor strategies are
unaffected, since they follow a real token.
- HubSpot and Airtable clamp the page size to the 100 their APIs accept rather than
sending the engine's 1000 default and failing the first request (maintainer decision,
D72). Safe because both derive HasMore from the server's own continuation token, so
clamping only means more requests — had they inferred it from a full page, clamping
alone would have been unsafe, which is exactly the bug above.
Also clears CodeQL cs/linq/missed-select (alert 292), opened on master by the
Link-header parsing in #262: the loop guards its split on the way in instead of
assigning then checking, which is what read as a missed `.Select`.
Eight tests, each verified to fail against the unfixed code. Three existing tests encoded
the old full-page semantics and are updated rather than deleted; a new one covers the
actual defect — a service that caps the page no longer truncates the report.
* refactor(sources): drop the page-size argument BuildPageResult no longer uses1 parent 32475d0 commit 03713b6
12 files changed
Lines changed: 257 additions & 26 deletions
File tree
- docs
- src/Sources
- NeoReports.Sources.Airtable
- NeoReports.Sources.Elasticsearch
- NeoReports.Sources.Http
- NeoReports.Sources.HubSpot
- NeoReports.Sources.OData
- tests
- NeoReports.Sources.Airtable.UnitTests
- NeoReports.Sources.Elasticsearch.UnitTests
- NeoReports.Sources.Http.UnitTests
- NeoReports.Sources.HubSpot.UnitTests
- NeoReports.Sources.OData.UnitTests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1149 | 1149 | | |
1150 | 1150 | | |
1151 | 1151 | | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
| 1167 | + | |
| 1168 | + | |
| 1169 | + | |
| 1170 | + | |
| 1171 | + | |
| 1172 | + | |
| 1173 | + | |
| 1174 | + | |
| 1175 | + | |
| 1176 | + | |
| 1177 | + | |
| 1178 | + | |
| 1179 | + | |
| 1180 | + | |
| 1181 | + | |
| 1182 | + | |
| 1183 | + | |
| 1184 | + | |
| 1185 | + | |
| 1186 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
199 | 199 | | |
200 | 200 | | |
201 | 201 | | |
202 | | - | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
203 | 206 | | |
204 | 207 | | |
205 | 208 | | |
206 | 209 | | |
207 | 210 | | |
208 | 211 | | |
209 | | - | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
210 | 215 | | |
211 | 216 | | |
212 | 217 | | |
| |||
252 | 257 | | |
253 | 258 | | |
254 | 259 | | |
255 | | - | |
256 | | - | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
257 | 265 | | |
258 | | - | |
259 | | - | |
260 | 266 | | |
261 | 267 | | |
262 | 268 | | |
| |||
Lines changed: 11 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
81 | 90 | | |
82 | 91 | | |
83 | | - | |
| 92 | + | |
| 93 | + | |
84 | 94 | | |
85 | 95 | | |
86 | 96 | | |
| |||
Lines changed: 41 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
| 86 | + | |
| 87 | + | |
86 | 88 | | |
87 | 89 | | |
88 | 90 | | |
| |||
154 | 156 | | |
155 | 157 | | |
156 | 158 | | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
157 | 198 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
100 | | - | |
101 | | - | |
| 100 | + | |
| 101 | + | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| |||
211 | 211 | | |
212 | 212 | | |
213 | 213 | | |
214 | | - | |
215 | | - | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
216 | 219 | | |
217 | 220 | | |
218 | 221 | | |
| |||
269 | 272 | | |
270 | 273 | | |
271 | 274 | | |
272 | | - | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
273 | 282 | | |
274 | 283 | | |
275 | | - | |
| 284 | + | |
276 | 285 | | |
277 | 286 | | |
278 | 287 | | |
279 | 288 | | |
280 | | - | |
| 289 | + | |
| 290 | + | |
281 | 291 | | |
282 | 292 | | |
283 | | - | |
| 293 | + | |
284 | 294 | | |
285 | 295 | | |
286 | 296 | | |
| |||
Lines changed: 11 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
81 | 90 | | |
82 | 91 | | |
83 | | - | |
| 92 | + | |
| 93 | + | |
84 | 94 | | |
85 | 95 | | |
86 | 96 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
100 | | - | |
| 100 | + | |
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
| |||
156 | 156 | | |
157 | 157 | | |
158 | 158 | | |
159 | | - | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
160 | 165 | | |
161 | 166 | | |
162 | | - | |
163 | | - | |
| 167 | + | |
164 | 168 | | |
165 | 169 | | |
166 | 170 | | |
| |||
Lines changed: 17 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
48 | 65 | | |
49 | 66 | | |
50 | 67 | | |
| |||
0 commit comments