{"record":{"id":"e44090c2eee87892","repo":"HKUDS/Vibe-Trading","slug":"fcffyear-year-self-year-nopat-self-nopat-r-do","errorCode":null,"errorMessage":"FCFFYear(year={self.year}).nopat={self.nopat!r} does not match ebit * (1 - tax_rate) = {expected_nopat!r}","messagePattern":"FCFFYear\\(year=(.+?)\\)\\.nopat=(.+?) does not match ebit \\* \\(1 - tax_rate\\) = (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/quantlib/valuation/dcf.py","lineNumber":562,"sourceCode":"    depreciation_amortization: float\n    capex: float\n    delta_nwc: float\n    fcff: float\n\n    def __post_init__(self) -> None:\n        \"\"\"Re-check the NOPAT and FCFF arithmetic.\n\n        Raises:\n            ValueError: If ``nopat`` or ``fcff`` do not match their formulas,\n                or ``year`` is not a positive integer.\n        \"\"\"\n        if self.year < 1:\n            raise ValueError(f\"FCFFYear.year must be >= 1, got {self.year!r}\")\n        expected_nopat = self.ebit * (1.0 - self.tax_rate)\n        if not math.isclose(\n            self.nopat, expected_nopat, rel_tol=_RECONCILIATION_TOLERANCE, abs_tol=1e-9\n        ):\n            raise ValueError(\n                f\"FCFFYear(year={self.year}).nopat={self.nopat!r} does not match \"\n                f\"ebit * (1 - tax_rate) = {expected_nopat!r}\"\n            )\n        expected_fcff = (\n            self.nopat + self.depreciation_amortization - self.capex - self.delta_nwc\n        )\n        if not math.isclose(\n            self.fcff, expected_fcff, rel_tol=_RECONCILIATION_TOLERANCE, abs_tol=1e-9\n        ):\n            raise ValueError(\n                f\"FCFFYear(year={self.year}).fcff={self.fcff!r} does not match the \"\n                f\"bridge total {expected_fcff!r}\"\n            )\n\n\ndef fcff_bridge(\n    *,\n    ebit: Sequence[float],","sourceCodeStart":544,"sourceCodeEnd":580,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/quantlib/valuation/dcf.py#L544-L580","documentation":"FCFFYear.__post_init__ recomputes nopat = ebit * (1 - tax_rate) and raises ValueError if the stored nopat differs beyond _RECONCILIATION_TOLERANCE. This is an internal reconciliation check preventing inconsistent forecast rows.","triggerScenarios":"Constructing FCFFYear with a hand-computed or rounded nopat (e.g. 60 instead of 60.0*0.75=45), or rounding nopat to fewer decimals than the tolerance allows.","commonSituations":"Importing forecasts from spreadsheets where nopat was independently entered/rounded rather than derived; unit tests building fixtures with approximate numbers.","solutions":["Compute nopat = ebit * (1 - tax_rate) in the caller and pass the unrounded result","Or build rows via fcff_bridge(), which derives nopat internally","Round inputs (ebit, tax_rate) before the call rather than rounding nopat after"],"exampleFix":"# before\nFCFFYear(year=1, ebit=100.0, tax_rate=0.25, nopat=75.1, ...)\n\n# after\nFCFFYear(year=1, ebit=100.0, tax_rate=0.25, nopat=100.0*(1-0.25), ...)","handlingStrategy":"validation","validationCode":"nopat = ebit * (1.0 - tax_rate)\nFCFFYear(year=1, ebit=ebit, tax_rate=tax_rate, nopat=nopat, ...)","typeGuard":null,"tryCatchPattern":"try:\n    FCFFYear(...)\nexcept ValueError as e:\n    if 'nopat' in str(e):\n        row['nopat'] = row['ebit'] * (1 - row['tax_rate'])\n    raise","preventionTips":["Derive nopat, never enter it independently","Round ebit/tax_rate upstream, not nopat downstream","Use fcff_bridge() for imported spreadsheets"],"tags":["valuation","fcff","reconciliation","rounding"],"backgroundTag":"derived-field-mismatch","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}