⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
src/orb/outcomes.ts:63-84's getOrbGlobalStats is called via Promise.all([getOrbGlobalStats(env), computeFleetAnalytics(env)]) in src/review/public-stats.ts:431. computeFleetAnalytics (src/orb/analytics.ts:218-245) wraps its DB reads in try/catch and degrades to an all-null/zero report on any DB error. getOrbGlobalStats has no such guard -- a D1 error on its join query throws straight out of the Promise.all. The only safety net is the route-level catch in src/api/routes.ts:1247-1259, which then 503s the entire /v1/public/stats payload (accuracyTrend, reuseRateTrend, reviewVolumeTrend, rulePrecision all lost) instead of degrading just the orb aggregate the way its neighbor does. No test in test/integration/orb-outcomes.test.ts currently exercises a DB-throw path for it.
Requirements
Wrap getOrbGlobalStats's query in try/catch, returning {merged:0, closed:0, total:0} on failure, matching computeFleetAnalytics's existing degrade-gracefully posture exactly.
Deliverables
All of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/** -- 99%+ patch coverage, branch-counted, on the new try/catch path.
Expected Outcome
A DB error on the orb-stats join query degrades just that aggregate to zero values, instead of 503ing the entire /v1/public/stats payload including unrelated trend data.
Links & Resources
src/orb/outcomes.ts:63-84
src/orb/analytics.ts:218-245
src/review/public-stats.ts:431
src/api/routes.ts:1247-1259
test/integration/orb-outcomes.test.ts
Context
src/orb/outcomes.ts:63-84'sgetOrbGlobalStatsis called viaPromise.all([getOrbGlobalStats(env), computeFleetAnalytics(env)])insrc/review/public-stats.ts:431.computeFleetAnalytics(src/orb/analytics.ts:218-245) wraps its DB reads in try/catch and degrades to an all-null/zero report on any DB error.getOrbGlobalStatshas no such guard -- a D1 error on its join query throws straight out of thePromise.all. The only safety net is the route-level catch insrc/api/routes.ts:1247-1259, which then 503s the entire/v1/public/statspayload (accuracyTrend, reuseRateTrend, reviewVolumeTrend, rulePrecision all lost) instead of degrading just the orb aggregate the way its neighbor does. No test intest/integration/orb-outcomes.test.tscurrently exercises a DB-throw path for it.Requirements
Wrap
getOrbGlobalStats's query in try/catch, returning{merged:0, closed:0, total:0}on failure, matchingcomputeFleetAnalytics's existing degrade-gracefully posture exactly.Deliverables
getOrbGlobalStatscatches a DB error and returns{merged:0, closed:0, total:0}instead of throwingtest/integration/orb-outcomes.test.tsexercising a DB-throw path and asserting the degraded zero-value result, not an unhandled rejectionAll of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/**-- 99%+ patch coverage, branch-counted, on the new try/catch path.Expected Outcome
A DB error on the orb-stats join query degrades just that aggregate to zero values, instead of 503ing the entire
/v1/public/statspayload including unrelated trend data.Links & Resources
src/orb/outcomes.ts:63-84src/orb/analytics.ts:218-245src/review/public-stats.ts:431src/api/routes.ts:1247-1259test/integration/orb-outcomes.test.ts