You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The AWS Effective % column on the Recommendations page still shows implausible / wrong percentages (e.g. ~85.9% on rows where the realistic 1y RI value is ~20–25%) for AWS rows, even after #312 / #277 landed the on_demand_cost plumbing. Root cause is a stale JSONB cache — the previous fix added the field but did not ship a cache-invalidation migration, so pre-#312 AWS rows in the DB still lack on_demand_cost and the frontend silently falls back to a known-broken reconstruction formula.
Frontend formula: frontend/src/recommendations.ts::effectiveSavingsPct — prefers r.on_demand_cost when populated, else falls back to reconstruction (savings - amortized) / (monthly_cost + savings + amortized) which double-counts amortization vs. how AWS computes the savings amount.
Backend RI source: providers/aws/recommendations/parser_ri.go:120-138 (parseAWSCostDetails reads EstimatedMonthlyOnDemandCost → rec.OnDemandCost).
The codebase already pins concrete cases as passing tests (frontend/src/__tests__/recommendations.test.ts:3185, 3252-3289). The illustrative numeric example:
Reconstruction-formula denominator wrong for AWS RIs (when the fallback fires). For AWS RIs, monthly_cost = RecurringStandardMonthlyCost is the discounted recurring charge, while AWS's EstimatedMonthlySavingsAmount (→ r.savings) is the savings delta vs. on-demand excluding upfront. Adding + amortized to reconstruct on-demand (recommendations.ts:686) double-counts amortization vs. how AWS computes savings, producing implausibly low denominators → inflated %.
nonZeroPtr zeroes legitimate baselines (scheduler.go:968-974): writes nil when OnDemandCost == 0. For SP rows where AWS returns CurrentAverageHourlyOnDemandSpend == 0 (fresh accounts, dormant workloads), the SP parser produces OnDemandCost = 0 → stored as nil → frontend falls back to reconstruction.
Lower-likelihood ruled-out: RI/SP overlap double-counting (effectiveSavingsPct is per-rec), currency/unit mismatch (parsers use correct units), partial-load race (bug is stable across reloads), off-by-one in usage window (only affects AWS-side input).
SELECT id, payload->>'provider', payload ? 'on_demand_cost', payload->>'on_demand_cost'FROM recommendations
WHERE payload->>'provider'='aws'LIMIT50;
Ship migration 000048_invalidate_aws_recs_missing_on_demand_cost.up.sql mirroring fix(db/azure): flush stale monthly_cost cache + Azure recurring cost (closes #252) #256's pattern: UPDATE recommendations SET payload = jsonb_set(payload, '{monthly_cost}', 'null'::jsonb) WHERE payload->>'provider'='aws' AND NOT (payload ? 'on_demand_cost'); so the frontend renders — for affected rows until the next scheduler tick repopulates with the canonical baseline. Include the .down.sql companion.
Add structured warn-logs in providers/aws/recommendations/parser_ri.go::parseAWSCostDetails (when EstimatedMonthlyOnDemandCost is nil/zero) and providers/aws/recommendations/parser_sp.go::parseSavingsPlanDetail (when CurrentAverageHourlyOnDemandSpend is nil/zero) so production visibility surfaces the gap rather than silently zeroing.
Optional follow-up (decide after migration verified in prod): make frontend/src/recommendations.ts::effectiveSavingsPct return null when the reconstruction fallback would fire on AWS rows, so the UI renders — instead of a silently-wrong %.
Files most likely changed
internal/database/postgres/migrations/000048_*.{up,down}.sql — NEW migration
providers/aws/recommendations/parser_sp.go — warn-log when CurrentAverageHourlyOnDemandSpend nil
providers/aws/recommendations/parser_ri.go::parseAWSCostDetails — warn-log when EstimatedMonthlyOnDemandCost nil
Migration 000048_* lands and runs cleanly in dev/staging.
Post-migration, AWS rows that lacked on_demand_cost render — until next collector tick.
Next scheduler tick repopulates on_demand_cost for AWS rows; Effective % then shows realistic values (verified manually for ≥3 RI + ≥3 SP rows across different terms/payments).
Warn-logs visible in AWS parser path when underlying API fields are nil/zero.
Summary
The AWS Effective % column on the Recommendations page still shows implausible / wrong percentages (e.g. ~85.9% on rows where the realistic 1y RI value is ~20–25%) for AWS rows, even after #312 / #277 landed the
on_demand_costplumbing. Root cause is a stale JSONB cache — the previous fix added the field but did not ship a cache-invalidation migration, so pre-#312 AWS rows in the DB still lackon_demand_costand the frontend silently falls back to a known-broken reconstruction formula.Where it's computed
frontend/src/recommendations.ts:1492-1494(buildVariantRowMarkup—effectiveSavingsPct(rec)→pct.toFixed(1) + '%').frontend/src/recommendations.ts:486(effective_savings_pct: 'Effective %').frontend/src/recommendations.ts::effectiveSavingsPct— prefersr.on_demand_costwhen populated, else falls back to reconstruction(savings - amortized) / (monthly_cost + savings + amortized)which double-counts amortization vs. how AWS computes the savings amount.providers/aws/recommendations/parser_ri.go:120-138(parseAWSCostDetailsreadsEstimatedMonthlyOnDemandCost→rec.OnDemandCost).providers/aws/recommendations/parser_sp.go:131-141, 198(parseSavingsPlanDetailderivesOnDemandCost = CurrentAverageHourlyOnDemandSpend × 730, landed in fix(recommendations/aws): plumb on_demand_cost for canonical Effective Savings % (closes #303) #312).pkg/common/types.go:148→internal/scheduler/scheduler.go:1063(OnDemandCost: nonZeroPtr(rec.OnDemandCost)) →internal/config/types.go:291→frontend/src/types.ts:84&frontend/src/api/types.ts:66.Reproduction
The codebase already pins concrete cases as passing tests (
frontend/src/__tests__/recommendations.test.ts:3185, 3252-3289). The illustrative numeric example:For AWS specifically: when the production JSONB row lacks
on_demand_cost(pre-#312 cache), the frontend renders the inflated reconstruction value.Top hypotheses (most → least likely)
on_demand_cost(highest). fix(recommendations): plumb provider on_demand_cost through to frontend (closes #274) #277 (Azure) shipped migration000046_invalidate_monthly_cost_cache.up.sql. fix(recommendations/aws): plumb on_demand_cost for canonical Effective Savings % (closes #303) #312 (AWS) did NOT ship an equivalent. Pre-fix(recommendations/aws): plumb on_demand_cost for canonical Effective Savings % (closes #303) #312 AWS rows inrecommendations.payloadJSONB column have noon_demand_costkey, so the frontend falls back to the broken reconstruction. The daily collector overwrites them eventually but in the meantime AWS rows render the wrong %.monthly_cost = RecurringStandardMonthlyCostis the discounted recurring charge, while AWS'sEstimatedMonthlySavingsAmount(→r.savings) is the savings delta vs. on-demand excluding upfront. Adding+ amortizedto reconstruct on-demand (recommendations.ts:686) double-counts amortization vs. how AWS computes savings, producing implausibly low denominators → inflated %.nonZeroPtrzeroes legitimate baselines (scheduler.go:968-974): writesnilwhenOnDemandCost == 0. For SP rows where AWS returnsCurrentAverageHourlyOnDemandSpend == 0(fresh accounts, dormant workloads), the SP parser producesOnDemandCost = 0→ stored asnil→ frontend falls back to reconstruction.Lower-likelihood ruled-out: RI/SP overlap double-counting (
effectiveSavingsPctis per-rec), currency/unit mismatch (parsers use correct units), partial-load race (bug is stable across reloads), off-by-one in usage window (only affects AWS-side input).Prior attempts (top 5)
fix(recommendations/aws): plumb on_demand_cost for canonical Effective Savings %— closes fix(recommendations/aws): incorrect Effective Savings % — plumb on_demand_cost like Azure (#277) #303. SP parser populatesOnDemandCost. Did not ship a cache-flush migration.fix(recommendations): plumb provider on_demand_cost through to frontend— closes bug(frontend/recs): Effective % shows implausible values (85.9% on Azure 1y RI, 54% on savings=$0 row) #274. Azure converters + scheduler + frontend types +effectiveSavingsPctupgrade. Also did not ship a cache-flush migration foron_demand_cost.fix(db/azure): flush stale monthly_cost cache + Azure recurring cost. Established the cache-flush-via-migration pattern (migration 000046).bug(frontend/recs): Effective % shows implausible values on Azure 1y RI. Closed in code by fix(recommendations): plumb provider on_demand_cost through to frontend (closes #274) #277, issue still open. Open issue fix(recommendations/aws): incorrect Effective Savings % — plumb on_demand_cost like Azure (#277) #303 (the AWS-specific instance) is also still listed OPEN despite fix(recommendations/aws): plumb on_demand_cost for canonical Effective Savings % (closes #303) #312 merging.Fix plan
000048_invalidate_aws_recs_missing_on_demand_cost.up.sqlmirroring fix(db/azure): flush stale monthly_cost cache + Azure recurring cost (closes #252) #256's pattern:UPDATE recommendations SET payload = jsonb_set(payload, '{monthly_cost}', 'null'::jsonb) WHERE payload->>'provider'='aws' AND NOT (payload ? 'on_demand_cost');so the frontend renders—for affected rows until the next scheduler tick repopulates with the canonical baseline. Include the.down.sqlcompanion.providers/aws/recommendations/parser_ri.go::parseAWSCostDetails(whenEstimatedMonthlyOnDemandCostis nil/zero) andproviders/aws/recommendations/parser_sp.go::parseSavingsPlanDetail(whenCurrentAverageHourlyOnDemandSpendis nil/zero) so production visibility surfaces the gap rather than silently zeroing.frontend/src/recommendations.ts::effectiveSavingsPctreturnnullwhen the reconstruction fallback would fire on AWS rows, so the UI renders—instead of a silently-wrong %.Files most likely changed
internal/database/postgres/migrations/000048_*.{up,down}.sql— NEW migrationproviders/aws/recommendations/parser_sp.go— warn-log whenCurrentAverageHourlyOnDemandSpendnilproviders/aws/recommendations/parser_ri.go::parseAWSCostDetails— warn-log whenEstimatedMonthlyOnDemandCostnilfrontend/src/recommendations.ts::effectiveSavingsPct— optional: return null on AWS reconstruction fallback (decide post-migration)Acceptance criteria
000048_*lands and runs cleanly in dev/staging.on_demand_costrender—until next collector tick.on_demand_costfor AWS rows; Effective % then shows realistic values (verified manually for ≥3 RI + ≥3 SP rows across different terms/payments)..down.sqlcompanion.Closes
Investigation by Opus agent on 2026-05-06; full evidence trail and file:line references above.