{"record":{"id":"29eb95b15c53f7cb","repo":"HKUDS/Vibe-Trading","slug":"tier-self-name-r-has-a-negative-label-of-valu","errorCode":null,"errorMessage":"tier {self.name!r} has a negative {label} of {value!r}","messagePattern":"tier (.+?) has a negative (.+?) of (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/fundmath.py","lineNumber":1026,"sourceCode":"    amount: float\n    lp_amount: float\n    gp_amount: float\n\n    def __post_init__(self) -> None:\n        \"\"\"Check that the tier's two shares account for the whole tier.\n\n        Raises:\n            ValueError: If ``lp_amount + gp_amount`` differs from ``amount``, or\n                if any figure is negative. A waterfall that does not conserve\n                cash is a bug, never a rounding artefact worth tolerating.\n        \"\"\"\n        for label, value in (\n            (\"amount\", self.amount),\n            (\"lp_amount\", self.lp_amount),\n            (\"gp_amount\", self.gp_amount),\n        ):\n            if value < -_ALLOCATION_TOLERANCE:\n                raise ValueError(\n                    f\"tier {self.name!r} has a negative {label} of {value!r}\"\n                )\n        if not math.isclose(\n            self.lp_amount + self.gp_amount,\n            self.amount,\n            rel_tol=_ALLOCATION_TOLERANCE,\n            abs_tol=_ALLOCATION_TOLERANCE,\n        ):\n            raise ValueError(\n                f\"tier {self.name!r} does not conserve cash: lp {self.lp_amount!r} \"\n                f\"+ gp {self.gp_amount!r} != {self.amount!r}\"\n            )\n\n\n@dataclass(frozen=True)\nclass WaterfallResult:\n    \"\"\"Outcome of a European whole-of-fund distribution waterfall.\n","sourceCodeStart":1008,"sourceCodeEnd":1044,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/fundmath.py#L1008-L1044","documentation":"Each waterfall tier's allocation dataclass validates in __post_init__ that amount, lp_amount, and gp_amount are non-negative (within _ALLOCATION_TOLERANCE). A negative allocation would corrupt the LP/GP split downstream.","triggerScenarios":"Constructing a tier (e.g. WaterfallTier(name=\"catch-up\", amount=-100.0, lp_amount=-60.0, gp_amount=-40.0)) with any negative field, or a builder that computes allocations which go negative on partial distributions.","commonSituations":"Rounding drift in generated tier splits; a carry/catch-up computation overshooting into negative remainders; hand-built fixtures with wrong signs.","solutions":["Clamp allocations to >= 0 (max(value, 0.0)) where a partial distribution legitimately yields zero","Audit the upstream split computation for overshoot (remaining cash exhausted before a tier fills)","Fix fixture data sign errors"],"exampleFix":"# before\ntier = Tier(name=\"catch_up\", amount=amount, lp_amount=lp, gp_amount=gp)  # gp < 0 on partial catch-up\n\n# after\nclamped = max(0.0, gp)\ntier = Tier(name=\"catch_up\", amount=lp + clamped, lp_amount=lp, gp_amount=clamped)","handlingStrategy":"validation","validationCode":"def safe_tier(name, lp, gp, tol=1e-9):\n    lp, gp = max(0.0, lp), max(0.0, gp)\n    return Tier(name=name, amount=lp + gp, lp_amount=lp, gp_amount=gp)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clamp sleeve values at zero in split builders","Round allocations consistently before constructing tiers"],"tags":["fund-math","waterfall","tier-allocation","invariant"],"backgroundTag":"data-invariant-violation","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}