Originally created by: grynn-in
dbt-side fix for [#92] finding #2 (critical). (konsol-side findings #1/#4/#5/#6 are in companion PR grynn-in/konsol#48.)
gold_consolidated_trial_balance looked up the historical equity rate with row_number() … order by rate_date desc + rn = 1 — the most-recent tranche ever, ignoring period_date. Early periods got a future rate. The autoname carries rate_date precisely to allow multiple tranches, but only the latest was ever used.
Replace the rn=1 subquery with an ASOF LEFT JOIN on etb.period_date >= hr.rate_date — mirroring the ownership asof left join already used a few lines above. ASOF picks the closest rate_date not exceeding period_date, and yields NULL (→ closing_rate fallback via the existing case) for periods before the first tranche, instead of silently borrowing a future rate.
New tests/assert_equity_historical_rate_is_asof.sql — fails if a row applied a historical rate with no as-of-eligible tranche (the exact pre-fix bug) or if the applied rate ≠ the as-of expected rate (argMaxIf over tranches with rate_date <= period_date). The existing assert_equity_uses_historical_rate only checks that a rate was used, not the correct-period one.
ownership_staging join in the same model.dbt build/test not run from the isolated worktree (live dbt project is the mounted one); should run in CI. epm_staging.historical_equity_rates is empty in the current demo, so this is behaviour-correct on existing data and exercised once tranches exist.🤖 Generated with Claude Code
Originally posted by: grynn-in
Code review (×2 independent passes)
Review (ClickHouse ASOF / dbt): verified on the live CH 24.8:
>=picks latest tranche ≤ period) — correct, matches the proven ownership pattern.argMaxIfand thebuild_date_from_year_periodmacro call — valid; reconstructingperiod_datein the test is the right call (model doesn't expose it).toFloat64(historical_rate)returns 0.0, not NULL →hr.historical_rate is not nullwas always true → a period before the first tranche would translate equity at rate 0 (zeroing the balance) instead of closing_rate. Same defaulting trap the ownership block guards against.Fix applied (
66f734e): cast the rate toNullable(Float64)so an ASOF miss yields a true NULL — verified on CH 24.8 (miss→\N, match→value). This makes thecasefallback, the output column, and the test'sis not nullfilter all correct.Both ASOF-correctness and the defaulting bug are resolved. ⚠️ Full
dbt buildstill pending CI (can't run against the live mounted project from the isolated worktree).Ticket changed by: grynn-in