Loading
Quote API: return service limits in the 422 error for overweight parcels
Summary
Overweight parcels now get a structured 422. error: "unserviceable" and message are kept, so existing clients don't break. The body adds:
reason: "overweight"serviceweight_kgmax_weight_kg, read from configsuggested_service:nullor{service, label, max_weight_kg}
suggested_service is the first service in config order (SDS, NXT, REG) that accepts the weight and serves the lane. This rule is a judgement call, since the issue doesn't specify one, and can be adjusted in review.
The lane check still runs first, so an unserved lane keeps the lane error and gets no weight fields. Validation errors, the X-LastMile-Version header and the lastmile_quotes_rejected_total{service} counter are unchanged.
Changes
- New
OverweightParcel, which extendsUnserviceableLane(no longerfinal). It carries the service, weight, max weight and suggestion. QuoteCalculatorthrows it from the weight check. A new puresuggestService()helper reads the services from config.QuoteControlleradds the fields to the 422 body.- No changes to ETA or price computation, invariants, config or policy. The rejection happens before a
Quoteexists.
Risk
Low. It only changes the body of an existing 4xx rejection.
Test evidence
php artisan test passed: 51 tests, 1619 assertions. vendor/bin/pint passed.
- Overweight 422 for SDS 20.5 kg, NXT 50.5 kg (including a long lane) and REG 100.5 kg, with limit and suggestion checked.
- 20, 50 and 100 kg are still accepted with
X-LastMile-Invariants: pass. - The version header and the rejected-quotes metric are checked on the overweight 422.
- The limit comes from config, not a hard-coded value.
- A lane error carries no weight fields.
- Unit tests cover the exception payload and the
suggestService()boundaries.
Closes #3 (closed)