HKUDS/Vibe-Trading · error · ValueError

waterfall does not reconcile on {label}: tiers give {compute

Error message

waterfall does not reconcile on {label}: tiers give {computed!r}, expected {expected!r}

What it means

The waterfall-level reconciliation check in __post_init__ verifies that summing tiers for each reconciled label (e.g. contributed capital, distributions, carry) matches the expected totals supplied by the caller. A mismatch means the tier breakdown disagrees with the waterfall inputs.

Source

Thrown at agent/src/quantlib/fundmath.py:1087

        Raises:
            ValueError: If the tier amounts do not sum to ``distributable``, or
                if the per-side totals do not match the tier splits.
        """
        checks = (
            ("distributable", sum(tier.amount for tier in self.tiers), self.distributable),
            ("lp_total", sum(tier.lp_amount for tier in self.tiers), self.lp_total),
            ("gp_total", sum(tier.gp_amount for tier in self.tiers), self.gp_total),
            ("lp+gp", self.lp_total + self.gp_total, self.distributable),
        )
        for label, computed, expected in checks:
            if not math.isclose(
                computed,
                expected,
                rel_tol=_ALLOCATION_TOLERANCE,
                abs_tol=_ALLOCATION_TOLERANCE,
            ):
                raise ValueError(
                    f"waterfall does not reconcile on {label}: tiers give "
                    f"{computed!r}, expected {expected!r}"
                )

    def tier_amount(self, name: str) -> float:
        """Dollars that flowed through a named tier.

        Args:
            name: One of the ``TIER_*`` constants.

        Returns:
            The tier's ``amount``, or ``0.0`` if that tier is absent.
        """
        for tier in self.tiers:
            if tier.name == name:
                return tier.amount
        return 0.0

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Recompute expected totals from the same numbers used to build the tiers (single source of truth)
  2. Round both tiers and expected totals to the same decimal precision before constructing the waterfall
  3. Rebuild the entire waterfall from current inputs instead of reusing tier objects

Example fix

# before
tiers = split_tiers(cash, r=0.2)          # full precision
wf = Waterfall(tiers=tiers, contributed=round(paid_in, 2))  # mismatch -> raises

# after
tiers = [round_tier(t) for t in split_tiers(cash, r=0.2)]
wf = Waterfall(tiers=tiers, contributed=round(paid_in, 2))
Defensive patterns

Strategy: validation

Validate before calling

computed = sum(t.lp_amount + t.gp_amount for t in tiers)
assert math.isclose(computed, expected, rel_tol=1e-9, abs_tol=1e-9)

Prevention

When it happens

Trigger: Building a WaterfallResult where tiers were constructed from stale or differently-rounded inputs than the expected totals passed alongside them, so computed != expected beyond _ALLOCATION_TOLERANCE.

Common situations: Mixing tiers computed at full precision with expected totals rounded to cents; reusing tiers from a previous run after inputs changed; partial-distribution logic that fills tiers inconsistently with totals.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/232bcdcd1e92dbb9. Report an issue: GitHub.