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
{{ message }}
Repository navigation
fix(exchange): make PurchaseHistoryRecord.MonthlyCost a *float64 to distinguish absent from zero #1081
PurchaseHistoryRecord.MonthlyCost is float64 (not *float64), so a nil/unknown monthly cost is stored as 0. Per feedback_nullable_not_zero, an absent monthly cost coerced to 0 is indistinguishable from a real $0/mo commitment in any downstream sum or average.
File: internal/purchase/execution.go:601, 904-913
The derefFloat64 helper is honest about the coercion in its comment, but the table column type forces the information loss.
Compare: RecommendationRecord.MonthlyCost is already *float64 — this field should mirror that.
Fix
Change PurchaseHistoryRecord.MonthlyCost to *float64.
Add a nullable column migration for the history schema.
Update all readers/writers that currently dereference the field unconditionally.
Notes
This is migration-bearing — batch with the next history-schema change.
Out of scope for the immediate fix/exchange-fail-loud PR (L4 finding from docs/code-review/19-hardcoded-fallbacks-core.md).
Verification sweep against main (101f099fb) on 2026-07-27 finds this already resolved.
PurchaseHistoryRecord.MonthlyCost is now *float64 and migration 000063 dropped the NOT NULL constraint, so missing cost is representable as null rather than 0.
Evidence: commit 53c4900 (PR #848, under #255).
Recommending close.
Verified resolved at 3c0f8ac: PurchaseHistoryRecord.MonthlyCost is a *float64 backed by a nullable purchase_history.monthly_cost column, so an unknown monthly cost is stored as NULL rather than coerced to 0, and the exchange, scheduler and store writers pass the pointer through unchanged. Evidence: internal/config/types.go:809 and internal/database/postgres/migrations/000063_purchase_history_monthly_cost_nullable.up.sql (#848). Residual axes checked: internal/purchase/execution.go:907 and internal/scheduler/scheduler.go:1508 preserve nil; the analytics collector and validation nil-check before dereferencing; the derefFloat64 helper is gone. Closing as completed; reopen if the behaviour recurs.
Activity
cristim commentedon Jul 27, 2026
Verification sweep against
main(101f099fb) on 2026-07-27 finds this already resolved.PurchaseHistoryRecord.MonthlyCost is now *float64 and migration 000063 dropped the NOT NULL constraint, so missing cost is representable as null rather than 0.
Evidence: commit 53c4900 (PR #848, under #255).
Recommending close.
cristim commentedon Sep 2, 2026
Verified resolved at 3c0f8ac: PurchaseHistoryRecord.MonthlyCost is a *float64 backed by a nullable purchase_history.monthly_cost column, so an unknown monthly cost is stored as NULL rather than coerced to 0, and the exchange, scheduler and store writers pass the pointer through unchanged. Evidence: internal/config/types.go:809 and internal/database/postgres/migrations/000063_purchase_history_monthly_cost_nullable.up.sql (#848). Residual axes checked: internal/purchase/execution.go:907 and internal/scheduler/scheduler.go:1508 preserve nil; the analytics collector and validation nil-check before dereferencing; the derefFloat64 helper is gone. Closing as completed; reopen if the behaviour recurs.