Add calculated value discrepancy checks - #932
Draft
alvarolivie wants to merge 4 commits into
Draft
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #932 +/- ##
==========================================
- Coverage 94.99% 94.86% -0.14%
==========================================
Files 327 328 +1
Lines 17732 17847 +115
==========================================
+ Hits 16845 16930 +85
- Misses 547 563 +16
- Partials 340 354 +14 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
alvarolivie
force-pushed
the
correction-response
branch
from
August 18, 2026 09:23
98bc863 to
1c5e6e6
Compare
Replace the gobl.Calculate/WithDiscrepancies wrapper, which duplicated the Parse+Calculate orchestration Envelope and Object already provide, with FindCalculationDiscrepancies(data, calculated). Callers keep their existing Parse/Calculate flow and diff the original bytes against the result they already produced, instead of going through a second calculation entry point. Discrepancies are now returned as plain data rather than an error type, avoiding the errname nolint the previous shape needed. The comparison also walks a single reflect tree (the calculated result) instead of two, using reflect.VisibleFields for embedded fields instead of hand-rolled recursion. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Parse data a second time (without calculating) to recover the pre-calculation value, then diff it against the calculated result by walking both with reflection, rather than hand-rolling a JSON tree walk (byte-sniffing objects/arrays, re-unmarshalling fragments at each leaf) alongside a single typed value. Presence is now read off the parsed value itself (nil pointers, slice length) instead of a separate raw-JSON presence check. The one gap this leaves - a handful of non-pointer calculated fields (invoice type, currency, issue date, line index, payment total) where an explicit zero value is indistinguishable from an omitted one - is accepted deliberately: GOBL treats both the same way regardless. Also fixes a bug the new approach surfaced: num.Amount and similar types are Go structs but marshal through MarshalText rather than their (unexported) fields, so they must be compared as opaque leaves via reflect.Type.Implements, not walked field by field. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous version couldn't tell an omitted non-pointer calculated field (invoice type, currency, issue date, line index, payment total) apart from one explicitly supplied as its Go zero value, so it treated both as omitted. That's wrong whenever the zero value is a real, deliberate value that happens to differ from what GOBL calculated. Fix by decoding data a second time into a generic `any` tree solely to answer "was this key present and non-null" at each path, threaded alongside the two typed reflect trees. This generic tree is only ever used for that yes/no check, never as a source of values, so it carries none of the precision/formatting loss a naive read of it would. An explicit "" for invoice type is now correctly reported when GOBL replaces it with "standard", while a true omission still isn't. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
gobl.Calculate(data, options...)operationgobl.WithDiscrepancies()to reject supplied calculated values that GOBL changesCalculationDiscrepanciesthrough the error channel, including path, provided value, and calculated valueBehaviour
Calculated fields omitted by the caller continue to be populated normally. When discrepancy checking is enabled, only explicitly supplied fields marked with the existing
calculated=trueschema annotation are compared. Non-calculated normalization changes are ignored.Callers can inspect discrepancy errors with
errors.As.Testing
go test ./...go vet ./...git diff --check