Summary
Savings Plans collection can return success after dropping malformed details or failed plan types. Discovered while working #54 and PR #169.
Current behavior
At commit 8d4be0d1a9286036f8df5f2384becc384480597f:
parseSavingsPlansRecommendations logs a detail parse error and continues, returning only a slice. fetchSPAllPages therefore returns the surviving recommendations with a nil error. A malformed HourlyCommitmentToPurchase, EstimatedMonthlySavingsAmount, or UpfrontCost reaches this branch through parseSavingsPlanDetail.
getSavingsPlansRecommendations propagates API errors for a single requested plan type, but the umbrella path logs failed plan types and returns nil error. This also reports success when every attempted plan type fails.
GetAllRecommendations calls the umbrella ServiceSavingsPlansAll path. Consumers cannot distinguish these results from complete collections. Strict interactive consumers can display a shortened menu, and batch consumers lack the diagnostic needed to avoid treating missing rows as confirmed absent.
This is separate from #18 and the Provider M1/M2 item in #119, which concern malformed monetary values becoming zero. #18 explicitly permits skipping a rejected detail with a warning; neither issue requires collection-completeness propagation. Some monetary fields now correctly return detail errors, but the collection layer still swallows those errors. This issue does not claim all monetary parsing findings are resolved.
#54 and #169 address RI-origin diagnostics and aggregation of errors that reach the collector. Their scope explicitly leaves Savings Plans parser error swallowing unchanged.
Steps to reproduce
- Supply a real SDK fixture response containing a valid Savings Plans detail and a second detail with malformed HourlyCommitmentToPurchase.
- Call GetRecommendations for a selected Savings Plans service and observe the surviving row with a nil error.
- Call the umbrella Savings Plans service with one successful plan type and one failed API response. Observe success without an incomplete-collection diagnostic. Repeat with all plan types failing.
Expected behavior and acceptance
- Return valid SP survivors with an explicit incomplete-collection diagnostic when any detail or requested plan type fails. Reuse the existing diagnostic contract, keeping failed-detail and failed-scope counts distinct and avoiding double counting across pages, plan types, combinations, and services.
- Preserve ordinary fatal errors when all attempted plan types fail at the API level. Cancellation remains terminal. Clean empty responses remain successful; all-invalid detail responses remain incomplete.
- Verify single-plan-type and umbrella calls, including multi-page responses. Use real SDK fixture transport and demonstrate parent-code failure with valid-plus-malformed details and successful-plus-failed plan types.
- Verify a registered MCP call rejects the incomplete result without a structured short menu, and batch consumers retain valid survivors with diagnostics while excluding incomplete collections from authoritative eviction.
- Keep this change focused on completeness propagation; do not fold monetary-field policy or offering-selection fixes into it.
Proposed fix
Propagate the existing IncompleteRecommendationsError through parseSavingsPlansRecommendations, fetchSPAllPages and getSavingsPlansRecommendations in providers/aws/recommendations/parser_sp.go. Count rejected details and failed requested plan types separately. Preserve surviving rows while retaining terminal cancellation and all-API-failed semantics. Exercise downstream strict and batch policies through their real SDK/protocol/persistence paths.
References
Severity
High: an incomplete offer menu can affect purchase decisions, and an incomplete batch collection can wrongly treat missing rows as confirmed absent.
Summary
Savings Plans collection can return success after dropping malformed details or failed plan types. Discovered while working #54 and PR #169.
Current behavior
At commit
8d4be0d1a9286036f8df5f2384becc384480597f:parseSavingsPlansRecommendationslogs a detail parse error and continues, returning only a slice.fetchSPAllPagestherefore returns the surviving recommendations with a nil error. A malformedHourlyCommitmentToPurchase,EstimatedMonthlySavingsAmount, orUpfrontCostreaches this branch throughparseSavingsPlanDetail.getSavingsPlansRecommendationspropagates API errors for a single requested plan type, but the umbrella path logs failed plan types and returns nil error. This also reports success when every attempted plan type fails.GetAllRecommendationscalls the umbrellaServiceSavingsPlansAllpath. Consumers cannot distinguish these results from complete collections. Strict interactive consumers can display a shortened menu, and batch consumers lack the diagnostic needed to avoid treating missing rows as confirmed absent.This is separate from #18 and the Provider M1/M2 item in #119, which concern malformed monetary values becoming zero. #18 explicitly permits skipping a rejected detail with a warning; neither issue requires collection-completeness propagation. Some monetary fields now correctly return detail errors, but the collection layer still swallows those errors. This issue does not claim all monetary parsing findings are resolved.
#54 and #169 address RI-origin diagnostics and aggregation of errors that reach the collector. Their scope explicitly leaves Savings Plans parser error swallowing unchanged.
Steps to reproduce
Expected behavior and acceptance
Proposed fix
Propagate the existing IncompleteRecommendationsError through parseSavingsPlansRecommendations, fetchSPAllPages and getSavingsPlansRecommendations in providers/aws/recommendations/parser_sp.go. Count rejected details and failed requested plan types separately. Preserve surviving rows while retaining terminal cancellation and all-API-failed semantics. Exercise downstream strict and batch policies through their real SDK/protocol/persistence paths.
References
Severity
High: an incomplete offer menu can affect purchase decisions, and an incomplete batch collection can wrongly treat missing rows as confirmed absent.