Found reviewing PR #846 (head 2d92fb5).
load_config accepts a repeated allowlist entry (allowlist: [BTC, ETH, BTC, PAXG] loads as ['BTC', 'ETH', 'BTC', 'PAXG']). select_universe (keel/commands/dca_plan.py:283) iterates that list as-is, so the asset is allocated twice: its weight counts twice in the renormalisation, [E] prompts for it twice, and [Y] writes two candidate DCA rules for the same product. apply_dca_plan's stale check only compares against rules already in the table, not within the plan.
Reproduced: replace(config, allowlist=['BTC','BTC','ETH']) -> buys [('BTC', 37.63), ('BTC', 37.63), ('ETH', 28.22)], no blocker; apply_dca_plan writes rules (1, BTC-USD), (2, BTC-USD), (3, ETH-USD).
Fix: dedupe the allowlist in select_universe (order-preserving) or refuse it with a DcaPlanError naming the duplicate; add a test with a repeated entry asserting one allocation and one written rule per asset.
Found reviewing PR #846 (head 2d92fb5).
load_configaccepts a repeated allowlist entry (allowlist: [BTC, ETH, BTC, PAXG]loads as['BTC', 'ETH', 'BTC', 'PAXG']).select_universe(keel/commands/dca_plan.py:283) iterates that list as-is, so the asset is allocated twice: its weight counts twice in the renormalisation,[E]prompts for it twice, and[Y]writes twocandidateDCA rules for the same product.apply_dca_plan's stale check only compares against rules already in the table, not within the plan.Reproduced:
replace(config, allowlist=['BTC','BTC','ETH'])-> buys[('BTC', 37.63), ('BTC', 37.63), ('ETH', 28.22)], no blocker;apply_dca_planwrites rules(1, BTC-USD), (2, BTC-USD), (3, ETH-USD).Fix: dedupe the allowlist in
select_universe(order-preserving) or refuse it with a DcaPlanError naming the duplicate; add a test with a repeated entry asserting one allocation and one written rule per asset.