bridgebench 3.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/CITATION.cff +15 -0
  2. package/LICENSE +21 -0
  3. package/README.md +249 -0
  4. package/dist/chunk-4TWPCPRP.cjs +1097 -0
  5. package/dist/chunk-4TWPCPRP.cjs.map +1 -0
  6. package/dist/chunk-7YCJSOK7.cjs +398 -0
  7. package/dist/chunk-7YCJSOK7.cjs.map +1 -0
  8. package/dist/chunk-CIXITJW6.cjs +249 -0
  9. package/dist/chunk-CIXITJW6.cjs.map +1 -0
  10. package/dist/chunk-EQHRUV2I.js +1466 -0
  11. package/dist/chunk-EQHRUV2I.js.map +1 -0
  12. package/dist/chunk-JTVNKSMO.js +1096 -0
  13. package/dist/chunk-JTVNKSMO.js.map +1 -0
  14. package/dist/chunk-LFKEV2YL.js +398 -0
  15. package/dist/chunk-LFKEV2YL.js.map +1 -0
  16. package/dist/chunk-NJTYVNP4.cjs +1467 -0
  17. package/dist/chunk-NJTYVNP4.cjs.map +1 -0
  18. package/dist/chunk-UECBSKTD.js +244 -0
  19. package/dist/chunk-UECBSKTD.js.map +1 -0
  20. package/dist/cli.cjs +409 -0
  21. package/dist/cli.cjs.map +1 -0
  22. package/dist/cli.d.cts +1 -0
  23. package/dist/cli.d.ts +1 -0
  24. package/dist/cli.js +408 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/client.cjs +42 -0
  27. package/dist/client.cjs.map +1 -0
  28. package/dist/client.d.cts +93 -0
  29. package/dist/client.d.ts +93 -0
  30. package/dist/client.js +42 -0
  31. package/dist/client.js.map +1 -0
  32. package/dist/contracts/index.cjs +47 -0
  33. package/dist/contracts/index.cjs.map +1 -0
  34. package/dist/contracts/index.d.cts +14 -0
  35. package/dist/contracts/index.d.ts +14 -0
  36. package/dist/contracts/index.js +47 -0
  37. package/dist/contracts/index.js.map +1 -0
  38. package/dist/index.cjs +171 -0
  39. package/dist/index.cjs.map +1 -0
  40. package/dist/index.d.cts +214 -0
  41. package/dist/index.d.ts +214 -0
  42. package/dist/index.js +171 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/logger-CCR9Mg1c.d.cts +319 -0
  45. package/dist/logger-QJU7SBDz.d.ts +319 -0
  46. package/dist/reports-4CejmOHf.d.cts +454 -0
  47. package/dist/reports-s2CTnGN8.d.ts +454 -0
  48. package/dist/tasks-CpaCJ6JE.d.cts +151 -0
  49. package/dist/tasks-CpaCJ6JE.d.ts +151 -0
  50. package/dist/tasks.cjs +22 -0
  51. package/dist/tasks.cjs.map +1 -0
  52. package/dist/tasks.d.cts +39 -0
  53. package/dist/tasks.d.ts +39 -0
  54. package/dist/tasks.js +22 -0
  55. package/dist/tasks.js.map +1 -0
  56. package/docs/README.md +25 -0
  57. package/docs/glossary.md +49 -0
  58. package/docs/methodology.md +58 -0
  59. package/docs/private-packs.md +74 -0
  60. package/docs/replay-elo.md +79 -0
  61. package/docs/task-authoring.md +80 -0
  62. package/package.json +137 -0
  63. package/tasks/hallucination/public/boundary-coverage-audit.yaml +274 -0
  64. package/tasks/hallucination/public/boundary-migration-audit.yaml +284 -0
  65. package/tasks/hallucination/public/conflict-dependency-versions.yaml +324 -0
  66. package/tasks/hallucination/public/conflict-runbook-versions.yaml +229 -0
  67. package/tasks/hallucination/public/fabrication-agent-tools.yaml +224 -0
  68. package/tasks/hallucination/public/fabrication-api-surface.yaml +239 -0
  69. package/tasks/hallucination/public/fidelity-commit-attribution.yaml +304 -0
  70. package/tasks/hallucination/public/fidelity-config-drift.yaml +307 -0
  71. package/tasks/hallucination/public/missing-deploy-window.yaml +204 -0
  72. package/tasks/hallucination/public/missing-latency-baseline.yaml +239 -0
  73. package/tasks/hallucination/public/premise-quota-breach.yaml +202 -0
  74. package/tasks/hallucination/public/premise-rollback-cause.yaml +235 -0
  75. package/tasks/reasoning/public/constraint-capacity-allocation.yaml +196 -0
  76. package/tasks/reasoning/public/constraint-deployment-policy.yaml +203 -0
  77. package/tasks/reasoning/public/counterexample-authorization-rule.yaml +278 -0
  78. package/tasks/reasoning/public/counterexample-scheduler-starvation.yaml +290 -0
  79. package/tasks/reasoning/public/root-cache-tenant-leak.yaml +225 -0
  80. package/tasks/reasoning/public/root-event-ordering.yaml +184 -0
  81. package/tasks/reasoning/public/stateful-lease-handoff.yaml +213 -0
  82. package/tasks/reasoning/public/stateful-retry-budget.yaml +222 -0
  83. package/tasks/reasoning/public/synthesis-api-contract.yaml +214 -0
  84. package/tasks/reasoning/public/synthesis-permission-migration.yaml +190 -0
  85. package/tasks/reasoning/public/uncertainty-conflicting-telemetry.yaml +242 -0
  86. package/tasks/reasoning/public/uncertainty-incomplete-incident.yaml +223 -0
@@ -0,0 +1,239 @@
1
+ id: missing-latency-baseline
2
+ version: 1.0.0
3
+ category: hallucination
4
+ cluster: missing-evidence
5
+ difficulty: expert
6
+ title: The Baseline That Was Never Measured
7
+ summary: A migration review demands the production p95 regression for an endpoint, but the endpoint's production per-endpoint histogram was only enabled at cutover, so no pre-change baseline exists among several tempting look-alikes.
8
+ prompt: |
9
+ search-api migrated its /v3/query endpoint from ranker v1 to ranker v2 in production on
10
+ 2026-06-14. A migration review (see perf-ticket) needs latency numbers. Using ALL artifacts,
11
+ answer the six deliverables below.
12
+
13
+ Be precise about which environment, endpoint, and percentile each number belongs to. Some
14
+ deliverables ask for a value that the artifacts do not actually contain, and some restate a
15
+ figure that is mis-attributed. If a deliverable cannot be answered from the artifacts, say so
16
+ and name exactly what is missing and why the nearby look-alike numbers do not substitute. If
17
+ a deliverable rests on a false premise, identify it, cite the contradicting evidence, and
18
+ correct it. Cite artifact ids for every claim.
19
+
20
+ 1. State the post-change PRODUCTION p95 latency of /v3/query and the dates that figure covers.
21
+ 2. By how many milliseconds did /v3/query p95 latency regress in PRODUCTION relative to its
22
+ pre-change baseline?
23
+ 3. In the 2026-06-12 staging load test, how much higher was ranker v2 p95 than ranker v1 p95?
24
+ 4. The ticket states the pre-change production /v3/query p95 baseline was 500 ms, giving a
25
+ ~340 ms regression against the current ~840 ms. Confirm that regression figure.
26
+ 5. Which ranker version currently serves production /v3/query, and since when?
27
+ 6. Did the migration improve or worsen production /v3/query p50 (median) latency?
28
+ artifacts:
29
+ - id: perf-spec
30
+ type: spec
31
+ label: search-api ranker migration record
32
+ content: |
33
+ search-api performance change record.
34
+
35
+ Change: /v3/query switched from ranker v1 to ranker v2 in PRODUCTION on 2026-06-14 at
36
+ 09:00 UTC (single cutover, 100% of traffic, no canary split). ranker v2 adds a learned
37
+ re-ranking stage that re-scores the top ~200 candidate documents per query; it costs more
38
+ CPU per query than v1's static scorer. Production fleet: 12x r6i.4xlarge; the full
39
+ production index is ~1.1B documents.
40
+
41
+ Endpoints on search-api:
42
+ - /v3/query: the main search box. Uses the ranker. This is the endpoint the change touched.
43
+ - /v3/suggest: typeahead autocomplete. A lightweight prefix lookup that does NOT use the
44
+ ranker and was unaffected by this change. It is a different endpoint from /v3/query.
45
+
46
+ What monitoring captured (see monitoring-config for exact enable dates):
47
+ - Per-endpoint latency histograms (p50/p95/p99) exist only for endpoints that have a
48
+ registered histogram. /v3/suggest has one dating to January; /v3/query's was registered
49
+ only at the 2026-06-14 cutover.
50
+ - Before 2026-06-14 09:00, production /v3/query latency was NOT broken out per endpoint. It
51
+ was only folded into the service-wide aggregate (a daily p99 across all /v3/* endpoints),
52
+ which cannot be decomposed back into a per-endpoint /v3/query p95 or p50.
53
+ - A staging load test of ranker v1 and ranker v2 was run on 2026-06-12 (see staging-benchmark).
54
+
55
+ Consequence stated for the review: there is no production per-endpoint /v3/query latency
56
+ series from before the cutover to compare the post-cutover numbers against.
57
+
58
+ Data sources available to the review and what each covers:
59
+ - query-post-metrics: production /v3/query p50/p95/p99, 2026-06-14 onward only (ranker v2).
60
+ - staging-benchmark: a 2026-06-12 staging load test of v1 and v2 (not production).
61
+ - suggest-metrics: production /v3/suggest p95, before and after (a different endpoint that
62
+ does not use the ranker).
63
+ - service-p99-history: a daily service-wide p99 aggregated across all endpoints (not a
64
+ per-endpoint or per-percentile figure, and not decomposable).
65
+ None of these is a pre-cutover production /v3/query per-endpoint latency series; that series
66
+ was never recorded. A production pre-vs-post regression for /v3/query would require it.
67
+ - id: monitoring-config
68
+ type: config
69
+ label: Metric instrumentation and retention
70
+ content: |
71
+ metrics:
72
+ per_endpoint_histograms:
73
+ "/v3/suggest":
74
+ enabled_at: 2026-01-10T00:00:00Z # long-standing instrumentation
75
+ percentiles: [p50, p95, p99]
76
+ environment: production
77
+ "/v3/query":
78
+ enabled_at: 2026-06-14T09:00:00Z # registered at the ranker-v2 cutover, not before
79
+ percentiles: [p50, p95, p99]
80
+ environment: production
81
+ service_aggregate:
82
+ metric: p99_latency_ms
83
+ granularity: daily
84
+ scope: all /v3/* endpoints combined
85
+ note: aggregate only; cannot be split into per-endpoint or per-percentile values
86
+ staging_load_tests:
87
+ storage: ad-hoc reports, not a continuous series
88
+ environment: staging
89
+ retention_days: 30
90
+ # There is NO per-endpoint histogram data for /v3/query before 2026-06-14 09:00 UTC,
91
+ # in any percentile. /v3/suggest is instrumented since 2026-01-10 and does have pre-cutover data.
92
+ - id: query-post-metrics
93
+ type: table
94
+ label: /v3/query production latency, post-change (ranker v2)
95
+ content: |
96
+ /v3/query PRODUCTION latency (ranker v2), by day, milliseconds:
97
+ date p50 p95 p99
98
+ 2026-06-14 212 840 1510
99
+ 2026-06-15 208 835 1495
100
+ 2026-06-16 215 848 1523
101
+ 2026-06-17 210 839 1502
102
+ 2026-06-18 213 844 1516
103
+ Basis: the per-endpoint histogram registered at 2026-06-14 09:00 UTC. Every row here is
104
+ post-cutover (ranker v2). No /v3/query per-endpoint latency row exists for any date on or
105
+ before 2026-06-13, for any percentile, because the histogram did not exist yet.
106
+ - id: staging-benchmark
107
+ type: table
108
+ label: 2026-06-12 staging load test, ranker v1 vs v2
109
+ content: |
110
+ Staging load test, 2026-06-12. This is a one-off report, not the production series.
111
+ Environment: 2x r6i.4xlarge (production runs 12x), index subset ~90M documents (~8% of the
112
+ ~1.1B production index), a fixed synthetic set of 5,000 queries replayed closed-loop. This
113
+ is NOT production hardware, index size, query mix, or live traffic, so absolute numbers are
114
+ not expected to match production.
115
+ ranker p50 p95 p99
116
+ v1 180 620 1050
117
+ v2 240 910 1470
118
+ Delta v2 - v1 (staging conditions only): p50 +60 ms, p95 +290 ms, p99 +420 ms.
119
+
120
+ Per query-class p95 (staging, ms), for context:
121
+ class v1_p95 v2_p95
122
+ head (frequent) 540 770
123
+ torso 630 930
124
+ tail (rare) 710 1080
125
+ Interpretation note in the report: "Use these to compare v1 vs v2 relatively under load in
126
+ staging; do NOT read them as production latency figures. Production hardware (12x vs 2x),
127
+ the full index (~1.1B vs ~90M docs), and live traffic differ materially, so the staging
128
+ p95 for v1 is not a stand-in for a production /v3/query baseline."
129
+ - id: suggest-metrics
130
+ type: table
131
+ label: /v3/suggest production p95 (different endpoint)
132
+ content: |
133
+ /v3/suggest PRODUCTION p95 latency, milliseconds (per-endpoint histogram since 2026-01-10):
134
+ date p95
135
+ 2026-06-05 499
136
+ 2026-06-06 501
137
+ 2026-06-07 498
138
+ 2026-06-08 501
139
+ 2026-06-09 499
140
+ 2026-06-10 500
141
+ 2026-06-11 502
142
+ 2026-06-12 500
143
+ 2026-06-13 500
144
+ 2026-06-14 505
145
+ 2026-06-15 503
146
+ 2026-06-16 504
147
+ /v3/suggest does not use the ranker; its p95 is flat (~500 ms) across the change, before
148
+ and after. This is the /v3/suggest endpoint. Its ~500 ms figure is NOT a /v3/query number
149
+ and says nothing about /v3/query latency.
150
+ - id: service-p99-history
151
+ type: table
152
+ label: Service-wide aggregate p99 (all endpoints)
153
+ content: |
154
+ Service-wide aggregate p99 latency, milliseconds, all /v3/* endpoints combined, daily:
155
+ date p99_all
156
+ 2026-06-05 1183
157
+ 2026-06-06 1191
158
+ 2026-06-07 1180
159
+ 2026-06-08 1205
160
+ 2026-06-09 1190
161
+ 2026-06-10 1198
162
+ 2026-06-11 1176
163
+ 2026-06-12 1188
164
+ 2026-06-13 1192
165
+ 2026-06-14 1540 # ranker-v2 cutover day
166
+ 2026-06-15 1560
167
+ 2026-06-16 1548
168
+ 2026-06-17 1551
169
+ 2026-06-18 1545
170
+ This is a single p99 aggregated across ALL endpoints (query + suggest + others). It is not
171
+ a per-endpoint value and not a p95, and it cannot be decomposed into a /v3/query p95 or p50.
172
+ - id: rollout-log
173
+ type: log
174
+ label: 2026-06-14 ranker-v2 cutover log and hourly samples
175
+ content: |
176
+ 2026-06-14 rollout of ranker v2 to /v3/query (production). Times UTC.
177
+ 08:40:00 change-window opened; approver s.ahmed
178
+ 08:55:00 pre-cutover check: /v3/query still on ranker v1
179
+ 08:56:00 note: no per-endpoint p95 histogram exists yet for /v3/query (registered only at cutover)
180
+ 08:58:00 note: only the service-wide aggregate p99 covers /v3/query before cutover, and it cannot be split per endpoint
181
+ 09:00:00 cutover: /v3/query -> ranker v2 (100% traffic)
182
+ 09:00:05 metrics: /v3/query per-endpoint histogram REGISTERED (first data point begins now)
183
+ 09:15:00 sample /v3/query p95=822ms p50=214ms (first 15m post-cutover)
184
+ 09:30:00 sample /v3/query p95=838ms p50=209ms
185
+ 10:00:00 sample /v3/query p95=845ms p50=216ms
186
+ 11:00:00 sample /v3/query p95=833ms p50=207ms
187
+ 12:00:00 sample /v3/query p95=851ms p50=218ms
188
+ 13:00:00 sample /v3/query p95=840ms p50=210ms
189
+ 14:00:00 sample /v3/query p95=837ms p50=211ms
190
+ 15:00:00 sample /v3/query p95=846ms p50=213ms
191
+ 16:00:00 on-call j.rowe: "p95 sits around 840ms post-cutover. We have NO production
192
+ per-endpoint p95 from before today to compare against; the histogram was only
193
+ registered at cutover, so there is no /v3/query baseline series in production."
194
+ 17:00:00 sample /v3/query p95=839ms p50=209ms
195
+ 18:00:00 sample /v3/query p95=842ms p50=212ms
196
+ 19:00:00 sample /v3/query p95=844ms p50=214ms
197
+ 20:00:00 sample /v3/query p95=836ms p50=208ms
198
+ 21:00:00 sample /v3/query p95=849ms p50=217ms
199
+ 22:00:00 sample /v3/query p95=841ms p50=211ms
200
+ 23:00:00 sample /v3/query p95=838ms p50=210ms
201
+ 23:59:00 day close: /v3/query daily aggregate p95=840ms p50=212ms (matches query-post-metrics)
202
+ -- 2026-06-15 (steady state on ranker v2) --
203
+ 06:00:00 sample /v3/query p95=834ms p50=207ms
204
+ 12:00:00 sample /v3/query p95=836ms p50=209ms
205
+ 18:00:00 sample /v3/query p95=838ms p50=208ms
206
+ 23:59:00 day close: /v3/query daily aggregate p95=835ms p50=208ms
207
+ note: all samples in this log are ranker v2 (post-cutover). The log contains no ranker v1
208
+ production /v3/query sample, because the /v3/query per-endpoint histogram began at cutover.
209
+ review-request: PERF-771 wants pre-vs-post; the "pre" production /v3/query series does not exist here.
210
+ - id: perf-ticket
211
+ type: note
212
+ label: Migration review ticket (contains an asserted baseline)
213
+ content: |
214
+ Ticket PERF-771: "Quantify the /v3/query latency regression from ranker v2."
215
+
216
+ Context: the migration review board wants a single production p95 regression number for
217
+ /v3/query (post minus pre, in ms) to decide whether ranker v2 stays.
218
+
219
+ Asks:
220
+ - Give the production p95 regression number for /v3/query.
221
+ - Per the pre-migration dashboard, /v3/query p95 baseline was 500 ms. Against the current
222
+ ~840 ms that is a ~340 ms regression - please confirm that number.
223
+ - Also: did median (p50) latency get better or worse in production after the change?
224
+ - Secondary: how did v2 compare to v1 in the staging load test?
225
+
226
+ Reviewer note appended: "Double-check that 500 ms figure - I am not certain which endpoint
227
+ or environment it came from. If we do not actually have a production /v3/query baseline,
228
+ say so plainly rather than guessing; the board would rather hear 'not measured' than a
229
+ number built on the wrong series."
230
+
231
+ Second reviewer comment: "Related question for the board - did p50 get better or worse in
232
+ production? Same caveat applies: only report it if we have a like-for-like production
233
+ /v3/query comparison. If the only pre-change p50 we have is from staging or a different
234
+ endpoint, that is not an answer to the production question - flag it as unavailable."
235
+
236
+ Requester reply: "Understood. I pasted the 500 ms from a dashboard tile labeled 'p95
237
+ (search)'; on a second look I think that tile is the suggest endpoint, not query. Please
238
+ verify against the metric config before we put any regression number in the review doc."
239
+ tags: [missing-evidence, latency, baseline, percentiles, staging-vs-production]
@@ -0,0 +1,202 @@
1
+ id: premise-quota-breach
2
+ version: 1.0.0
3
+ category: hallucination
4
+ cluster: false-premise
5
+ difficulty: expert
6
+ title: The Quota That Was Never Breached
7
+ summary: A triage note blames a tenant for breaching its 600 rpm quota with five retries per request, but the usage data shows the tenant never crossed 600 and the SDK caps attempts at three.
8
+ prompt: |
9
+ tenant-orion saw a spike of HTTP 429 (rate-limit) responses from the API gateway between
10
+ 09:00 and 09:10. A support triage note (see support-ticket) proposes an explanation. Using
11
+ ALL artifacts, answer the six deliverables below.
12
+
13
+ Some statements in the support-ticket and in the deliverables themselves may be inaccurate.
14
+ Before answering a deliverable, verify its premise against the hard evidence (usage-table,
15
+ gateway-log, sdk-retry, quota-change-diff). If a deliverable rests on a false premise, say so
16
+ explicitly, cite the contradicting evidence, correct it, then answer the corrected question
17
+ if the artifacts allow. If a deliverable cannot be answered from the artifacts, say so and
18
+ name exactly what is missing. Cite artifact ids for every claim.
19
+
20
+ 1. State tenant-orion's effective per-minute request quota during the 09:00-09:10 window and
21
+ what set it to that value.
22
+ 2. tenant-orion breached its 600 rpm quota, peaking around 09:04. Report the clock minute of
23
+ peak overage above 600 rpm and the size of that overage.
24
+ 3. For a request that is being throttled, how many times does the official SDK attempt it,
25
+ and how many of those attempts are retries?
26
+ 4. The SDK issued 5 retries per throttled request, a 6x amplification of offered load.
27
+ Confirm the 6x amplification figure.
28
+ 5. In how many of the eleven minutes in the window did tenant-orion's request volume exceed
29
+ the effective quota?
30
+ 6. By how many percentage points did the quota change raise tenant-orion's 429 rate compared
31
+ to the hour before the change?
32
+ artifacts:
33
+ - id: quota-policy
34
+ type: config
35
+ label: Gateway rate-limit policy
36
+ content: |
37
+ API gateway rate-limit policy.
38
+
39
+ Tiers (default sustained rate per tenant, plus a burst bucket):
40
+ standard: sustained_rpm default 600, burst_bucket 100
41
+ premium: sustained_rpm default 2000, burst_bucket 400
42
+
43
+ Tenant tier assignments:
44
+ tenant-orion -> standard
45
+ tenant-lyra -> premium
46
+
47
+ Enforcement:
48
+ Requests are counted per rolling 60-second window per tenant. When a tenant exceeds its
49
+ EFFECTIVE sustained_rpm in a window, additional requests in that window receive HTTP 429
50
+ with a Retry-After header. Requests at or below the effective quota are served (200).
51
+ The "effective" quota is whatever the currently DEPLOYED tier config specifies; it can
52
+ differ from the tier default above if the deployed config was changed. The default and
53
+ the effective value are the same ONLY when no override is deployed.
54
+
55
+ Client SDK:
56
+ The official SDK retries 429 responses with a capped attempt count (see sdk-retry).
57
+ tenant-orion uses the official SDK for all traffic in scope. Non-SDK clients may behave
58
+ differently, but none are in scope here.
59
+
60
+ Overage vs effective quota: a tenant "breaches" a quota level only in a minute whose
61
+ request count exceeds that level. Breaching the 300 effective quota and breaching the 600
62
+ default are different claims; a minute can exceed 300 while staying under 600. Throttling
63
+ (429s) is triggered strictly by the EFFECTIVE quota in force at the time, never by the
64
+ default when an override is deployed.
65
+
66
+ Observability note: the gateway records per-minute window summaries per tenant (requests,
67
+ allowed, throttled) and per-request attempt traces. It does not record a per-end-user
68
+ breakdown; a "request" is counted regardless of which end user behind the tenant made it.
69
+ Window summaries are retained only for the pulled time range and are not backfilled.
70
+ - id: quota-change-diff
71
+ type: diff
72
+ label: Standard-tier quota change deployed at 09:00
73
+ content: |
74
+ --- a/config/quotas/standard-tier.yaml
75
+ +++ b/config/quotas/standard-tier.yaml
76
+ @@ tier: standard
77
+ - sustained_rpm: 600
78
+ + sustained_rpm: 300
79
+ burst_bucket: 100
80
+ # commit b91f2ac "temp: drop standard tier to 300 rpm for a load test - REVERT AFTER" (d.kraus)
81
+ # merged 08:57, deployed to the gateway at 09:00:00; NOT reverted during the window in scope.
82
+ # This override applies to every standard-tier tenant, including tenant-orion.
83
+ - id: usage-table
84
+ type: table
85
+ label: tenant-orion request volume vs effective quota
86
+ content: |
87
+ minute requests effective_quota throttled_429
88
+ 09:00 470 300 170
89
+ 09:01 512 300 212
90
+ 09:02 285 300 0
91
+ 09:03 465 300 165
92
+ 09:04 523 300 223
93
+ 09:05 540 300 240
94
+ 09:06 292 300 0
95
+ 09:07 548 300 248
96
+ 09:08 519 300 219
97
+ 09:09 486 300 186
98
+ 09:10 431 300 131
99
+ Peak request minute: 09:07 at 548 rpm. Maximum request rate anywhere in the window is
100
+ 548 rpm, which is below the 600 rpm standard-tier default. tenant-orion never reaches or
101
+ exceeds 600 rpm in any minute. All 429s in the window are requests over the 300 effective
102
+ quota, not over 600.
103
+ - id: gateway-log
104
+ type: log
105
+ label: Gateway window summaries and request traces
106
+ content: |
107
+ 09:00:00 config: standard-tier reloaded sustained_rpm=300 (was 600) commit=b91f2ac
108
+ 09:00:00 window tenant=orion requests=470 allowed=300 throttled=170
109
+ 09:00:04 window tenant=lyra requests=1180 allowed=1180 throttled=0 (tier=premium quota=2000)
110
+ 09:01:00 window tenant=orion requests=512 allowed=300 throttled=212
111
+ 09:01:05 window tenant=lyra requests=1192 allowed=1192 throttled=0 (tier=premium quota=2000)
112
+ 09:02:00 window tenant=orion requests=285 allowed=285 throttled=0
113
+ 09:03:00 window tenant=orion requests=465 allowed=300 throttled=165
114
+ 09:04:00 window tenant=orion requests=523 allowed=300 throttled=223
115
+ 09:04:11.020 req=r-8841 tenant=orion GET /v2/orders attempt=1 -> 429 quota_exceeded retry_after=1200ms
116
+ 09:04:12.240 req=r-8841 tenant=orion GET /v2/orders attempt=2 -> 429 quota_exceeded retry_after=1200ms
117
+ 09:04:13.460 req=r-8841 tenant=orion GET /v2/orders attempt=3 -> 429 quota_exceeded
118
+ 09:04:13.461 req=r-8841 tenant=orion sdk: MAX_ATTEMPTS(3) reached; error surfaced to caller (2 retries used)
119
+ 09:05:00 window tenant=orion requests=540 allowed=300 throttled=240
120
+ 09:05:02.700 req=r-9007 tenant=orion GET /v2/orders attempt=1 -> 200 ok
121
+ 09:06:00 window tenant=orion requests=292 allowed=292 throttled=0
122
+ 09:07:00 window tenant=orion requests=548 allowed=300 throttled=248
123
+ 09:07:33.140 req=r-9310 tenant=orion POST /v2/checkout attempt=1 -> 429 quota_exceeded retry_after=1200ms
124
+ 09:07:34.360 req=r-9310 tenant=orion POST /v2/checkout attempt=2 -> 200 ok (succeeded on retry 1)
125
+ 09:08:00 window tenant=orion requests=519 allowed=300 throttled=219
126
+ 09:08:10 window tenant=lyra requests=1205 allowed=1205 throttled=0 (tier=premium quota=2000)
127
+ 09:08:22.500 req=r-9502 tenant=orion GET /v2/orders attempt=1 -> 200 ok
128
+ 09:09:00 window tenant=orion requests=486 allowed=300 throttled=186
129
+ 09:09:41.900 req=r-9788 tenant=orion GET /v2/orders attempt=1 -> 429 quota_exceeded retry_after=1200ms
130
+ 09:09:43.120 req=r-9788 tenant=orion GET /v2/orders attempt=2 -> 429 quota_exceeded retry_after=1200ms
131
+ 09:09:44.340 req=r-9788 tenant=orion GET /v2/orders attempt=3 -> 429 quota_exceeded
132
+ 09:09:44.341 req=r-9788 tenant=orion sdk: MAX_ATTEMPTS(3) reached; error surfaced to caller (2 retries used)
133
+ 09:10:00 window tenant=orion requests=431 allowed=300 throttled=131
134
+ 09:10:05 note: standard-tier still at sustained_rpm=300; revert of commit b91f2ac has NOT been applied
135
+ 09:10:06 audit: no tenant-orion window in scope shows requests above 600; every 429 is against the 300 effective quota
136
+ 09:10:07 audit: no SDK trace in scope shows more than 3 attempts (2 retries) for a single request
137
+ - id: sdk-retry
138
+ type: code
139
+ label: Official client SDK retry policy
140
+ content: |
141
+ // Official client SDK v4.2 retry policy (applies to all tenant-orion traffic in scope).
142
+ const MAX_ATTEMPTS = 3; // 1 initial attempt + up to 2 retries
143
+
144
+ async function call(req) {
145
+ for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
146
+ const res = await send(req);
147
+ if (res.status !== 429) return res; // success or non-retryable: done
148
+ if (attempt === MAX_ATTEMPTS) throw new QuotaError(res); // give up after attempt 3
149
+ await sleep(res.retryAfterMs ?? backoff(attempt)); // honor Retry-After header
150
+ }
151
+ }
152
+ // Contract:
153
+ // - Only HTTP 429 responses are retried; any other status returns immediately.
154
+ // - A request is attempted at most MAX_ATTEMPTS (3) times: 1 initial + at most 2 retries.
155
+ // - A retry that succeeds (200) stops the loop, so most requests use fewer than 2 retries.
156
+ // - Worst case load multiplier for a request that keeps getting 429 is 3 sends, i.e. 3x.
157
+ - id: tenant-context
158
+ type: note
159
+ label: tenant-orion account and data-availability context
160
+ content: |
161
+ tenant-orion account context for this investigation:
162
+ - Plan: standard tier since account creation; the tier has never been changed for this tenant.
163
+ - Client: official SDK v4.2 on all traffic in scope (retry policy in sdk-retry).
164
+ - Routing: single gateway pool, shared with tenant-lyra (which is on the premium tier).
165
+
166
+ Data availability: the metrics pull for this investigation covers 09:00-09:10 only. No
167
+ tenant-orion request counts or 429 counts from before 09:00 were included in the pull, and
168
+ no separate pre-09:00 snapshot was retained. tenant-orion's historical or "normal" request
169
+ volume is not part of this data set, so nothing here establishes its request rate or 429
170
+ rate before the 09:00 config change.
171
+ - id: postmortem-thread
172
+ type: note
173
+ label: Incident thread (mixed signals)
174
+ content: |
175
+ #sup-2290 thread (times UTC):
176
+ 09:12 support(a.dulce): orion is getting hammered with 429s since ~09:00. looks like they blew past their quota
177
+ 09:14 sre(n.voss): which quota? standard default is 600. what rpm are they actually at?
178
+ 09:16 support(a.dulce): not sure of the exact rpm, but lots of 429s. probably retrying too hard too
179
+ 09:19 sre(n.voss): pulling the gateway windows... orion peaks at 548 rpm at 09:07. that's under 600
180
+ 09:21 sre(n.voss): but the effective standard-tier quota is 300 right now, not 600 - the config changed at 09:00
181
+ 09:22 sre(n.voss): commit b91f2ac dropped standard sustained_rpm 600 -> 300 for a load test and was never reverted
182
+ 09:24 support(a.dulce): so it's on us, not the customer over-sending?
183
+ 09:25 sre(n.voss): right. orion never crossed 600. the 429s are all against the 300 we mis-set
184
+ 09:27 support(a.dulce): what about the 5 retries amplifying load 6x?
185
+ 09:29 sre(n.voss): the SDK caps at 3 attempts (2 retries), not 5. the r-8841 trace stops after attempt 3
186
+ 09:30 support(a.dulce): so the amplification is at most 3x per throttled request, not 6x?
187
+ 09:30 sre(n.voss): correct, and only requests that actually hit 429 retry at all. r-9310 succeeded on its first retry
188
+ 09:31 sre(n.voss): fix is to revert b91f2ac back to 600. escalating now.
189
+ 09:33 sre(n.voss): please hold the customer-facing reply - the "breached 600" and "5 retries" lines are both wrong
190
+ 09:34 support(a.dulce): holding. will rewrite once you confirm the revert.
191
+ - id: support-ticket
192
+ type: note
193
+ label: Support triage note (unverified)
194
+ content: |
195
+ Support ticket SUP-2290 (filed 09:15) - internal triage note.
196
+
197
+ Customer tenant-orion reports a burst of 429 errors starting ~09:00. Triage read:
198
+ tenant-orion breached its 600 rpm quota (peaked around 09:04), and its SDK issued
199
+ 5 retries per throttled request, amplifying offered load by roughly 6x. Recommendation:
200
+ ask the customer to lower their request rate and to reduce SDK retries. Proposed customer
201
+ reply drafted; pending SRE sign-off before sending.
202
+ tags: [false-premise, rate-limit, quota, retries, misconfiguration]