@happyvertical/smrt-commerce 0.57.2 → 0.57.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/AGENTS.md +17 -0
  2. package/README.md +130 -0
  3. package/agents/accounting-snapshot-mapper.md +11 -0
  4. package/agents/contract-billing-schedules.md +67 -0
  5. package/agents/contract-money.md +81 -0
  6. package/agents/customer-funds.md +96 -0
  7. package/agents/historical-sales.md +132 -0
  8. package/agents/money-calculator.md +36 -0
  9. package/agents/money-model.md +6 -3
  10. package/agents/observed-purchase-prices.md +37 -0
  11. package/agents/payment-allocations.md +59 -0
  12. package/agents/received-sales-contract-money.md +38 -0
  13. package/dist/accounting-snapshot.d.ts +8 -1
  14. package/dist/accounting-snapshot.d.ts.map +1 -1
  15. package/dist/allocation-integrity.d.ts.map +1 -1
  16. package/dist/billing/period-close.d.ts.map +1 -1
  17. package/dist/chunks/{ContractLineItemCollection-BZcrlrrY.js → ContractLineItemCollection-J4xtRtzE.js} +6 -6
  18. package/dist/chunks/{ContractLineItemCollection-BZcrlrrY.js.map → ContractLineItemCollection-J4xtRtzE.js.map} +1 -1
  19. package/dist/chunks/DocumentTaxCollection-C42x0YLW.js +4385 -0
  20. package/dist/chunks/DocumentTaxCollection-C42x0YLW.js.map +1 -0
  21. package/dist/chunks/HistoricalCustomerFundsCollections-B5x8gTW3.js +170 -0
  22. package/dist/chunks/HistoricalCustomerFundsCollections-B5x8gTW3.js.map +1 -0
  23. package/dist/chunks/{InvoiceCollection-cinzAqt6.js → InvoiceCollection-BIcge9Wl.js} +131 -18
  24. package/dist/chunks/InvoiceCollection-BIcge9Wl.js.map +1 -0
  25. package/dist/chunks/{TaxCodeCollection-DaBOPG9c.js → TaxCodeCollection-RWdVaheF.js} +3 -4
  26. package/dist/chunks/TaxCodeCollection-RWdVaheF.js.map +1 -0
  27. package/dist/chunks/{TaxComponentCollection-C4zxnyVu.js → TaxComponentCollection-Dt2jeWiC.js} +3 -3
  28. package/dist/chunks/{TaxComponentCollection-C4zxnyVu.js.map → TaxComponentCollection-Dt2jeWiC.js.map} +1 -1
  29. package/dist/chunks/{allocation-integrity-WmWyXhtG.js → allocation-integrity-DJ7-LY1j.js} +7 -7
  30. package/dist/chunks/{allocation-integrity-WmWyXhtG.js.map → allocation-integrity-DJ7-LY1j.js.map} +1 -1
  31. package/dist/chunks/{contract-money-EuToOghh.js → contract-money-DSRTMoXm.js} +45 -12
  32. package/dist/chunks/contract-money-DSRTMoXm.js.map +1 -0
  33. package/dist/chunks/customer-funds-internal-BQzoJXK5.js +24 -0
  34. package/dist/chunks/customer-funds-internal-BQzoJXK5.js.map +1 -0
  35. package/dist/chunks/{detect-CY9ufaFb.js → detect-DAE-_NAk.js} +5 -2
  36. package/dist/chunks/{detect-CY9ufaFb.js.map → detect-DAE-_NAk.js.map} +1 -1
  37. package/dist/chunks/historical-commerce-internal-C9ButfuH.js +18 -0
  38. package/dist/chunks/historical-commerce-internal-C9ButfuH.js.map +1 -0
  39. package/dist/chunks/{invoice-posting-C2i5dOVZ.js → invoice-posting-BeTPw3h9.js} +5 -5
  40. package/dist/chunks/invoice-posting-BeTPw3h9.js.map +1 -0
  41. package/dist/chunks/retention-accounting-Brdj9x-V.js +2323 -0
  42. package/dist/chunks/retention-accounting-Brdj9x-V.js.map +1 -0
  43. package/dist/chunks/retention-accounting-internal-CBQRvd74.js +17 -0
  44. package/dist/chunks/retention-accounting-internal-CBQRvd74.js.map +1 -0
  45. package/dist/chunks/{tenant-money-barrier-6TlqUeVj.js → tenant-money-barrier-DoF6lR8h.js} +5 -5
  46. package/dist/chunks/{tenant-money-barrier-6TlqUeVj.js.map → tenant-money-barrier-DoF6lR8h.js.map} +1 -1
  47. package/dist/chunks/types-Bbm0Xflc.js.map +1 -1
  48. package/dist/collections/DocumentTaxCollection.d.ts +4 -1
  49. package/dist/collections/DocumentTaxCollection.d.ts.map +1 -1
  50. package/dist/collections/HistoricalCustomerFundsCollections.d.ts +10 -0
  51. package/dist/collections/HistoricalCustomerFundsCollections.d.ts.map +1 -0
  52. package/dist/collections/HistoricalSalesLineCollection.d.ts +6 -0
  53. package/dist/collections/HistoricalSalesLineCollection.d.ts.map +1 -0
  54. package/dist/collections/PaymentAllocationCollection.d.ts +2 -6
  55. package/dist/collections/PaymentAllocationCollection.d.ts.map +1 -1
  56. package/dist/collections/PurchasePriceObservationCollection.d.ts +6 -0
  57. package/dist/collections/PurchasePriceObservationCollection.d.ts.map +1 -0
  58. package/dist/collections/index.d.ts +1 -0
  59. package/dist/collections/index.d.ts.map +1 -1
  60. package/dist/contract-billing-schedule.d.ts +83 -0
  61. package/dist/contract-billing-schedule.d.ts.map +1 -0
  62. package/dist/contract-money.d.ts +2 -0
  63. package/dist/contract-money.d.ts.map +1 -1
  64. package/dist/customer-funds-internal.d.ts +6 -0
  65. package/dist/customer-funds-internal.d.ts.map +1 -0
  66. package/dist/customer-funds.d.ts +108 -0
  67. package/dist/customer-funds.d.ts.map +1 -0
  68. package/dist/document-money.d.ts +11 -0
  69. package/dist/document-money.d.ts.map +1 -1
  70. package/dist/historical-commerce-internal.d.ts +3 -0
  71. package/dist/historical-commerce-internal.d.ts.map +1 -0
  72. package/dist/historical-customer-funds-types.d.ts +113 -0
  73. package/dist/historical-customer-funds-types.d.ts.map +1 -0
  74. package/dist/historical-customer-funds.d.ts +23 -0
  75. package/dist/historical-customer-funds.d.ts.map +1 -0
  76. package/dist/historical-funds-internal.d.ts +5 -0
  77. package/dist/historical-funds-internal.d.ts.map +1 -0
  78. package/dist/historical-sales-money.d.ts +22 -0
  79. package/dist/historical-sales-money.d.ts.map +1 -0
  80. package/dist/historical-sales-reports.d.ts +31 -0
  81. package/dist/historical-sales-reports.d.ts.map +1 -0
  82. package/dist/historical-sales-types.d.ts +106 -0
  83. package/dist/historical-sales-types.d.ts.map +1 -0
  84. package/dist/historical-sales-validation.d.ts +12 -0
  85. package/dist/historical-sales-validation.d.ts.map +1 -0
  86. package/dist/index.d.ts +21 -0
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +1685 -1640
  89. package/dist/index.js.map +1 -1
  90. package/dist/invoice-accounting-sync.d.ts +0 -1
  91. package/dist/invoice-accounting-sync.d.ts.map +1 -1
  92. package/dist/invoice-mcp.d.ts.map +1 -1
  93. package/dist/invoice-posting.d.ts.map +1 -1
  94. package/dist/invoice-retention.d.ts +16 -0
  95. package/dist/invoice-retention.d.ts.map +1 -0
  96. package/dist/invoices.d.ts +2 -0
  97. package/dist/invoices.d.ts.map +1 -1
  98. package/dist/invoices.js +2 -2
  99. package/dist/manifest.json +7563 -4419
  100. package/dist/models/Contract.d.ts +14 -0
  101. package/dist/models/Contract.d.ts.map +1 -1
  102. package/dist/models/DocumentTax.d.ts +2 -0
  103. package/dist/models/DocumentTax.d.ts.map +1 -1
  104. package/dist/models/HistoricalCustomerFunds.d.ts +36 -0
  105. package/dist/models/HistoricalCustomerFunds.d.ts.map +1 -0
  106. package/dist/models/HistoricalCustomerFundsAllocation.d.ts +32 -0
  107. package/dist/models/HistoricalCustomerFundsAllocation.d.ts.map +1 -0
  108. package/dist/models/HistoricalSalesLine.d.ts +29 -0
  109. package/dist/models/HistoricalSalesLine.d.ts.map +1 -0
  110. package/dist/models/Invoice.d.ts +10 -1
  111. package/dist/models/Invoice.d.ts.map +1 -1
  112. package/dist/models/Payment.d.ts +7 -1
  113. package/dist/models/Payment.d.ts.map +1 -1
  114. package/dist/models/PaymentAllocation.d.ts +3 -1
  115. package/dist/models/PaymentAllocation.d.ts.map +1 -1
  116. package/dist/models/PaymentIntent.d.ts.map +1 -1
  117. package/dist/models/Payout.d.ts.map +1 -1
  118. package/dist/models/PurchasePriceObservation.d.ts +15 -0
  119. package/dist/models/PurchasePriceObservation.d.ts.map +1 -0
  120. package/dist/models/TaxCode.d.ts +1 -1
  121. package/dist/models/TaxCode.d.ts.map +1 -1
  122. package/dist/models/index.d.ts +1 -0
  123. package/dist/models/index.d.ts.map +1 -1
  124. package/dist/money.d.ts +5 -1
  125. package/dist/money.d.ts.map +1 -1
  126. package/dist/money.js +62 -15
  127. package/dist/money.js.map +1 -1
  128. package/dist/observed-purchase-price-internal.d.ts +3 -0
  129. package/dist/observed-purchase-price-internal.d.ts.map +1 -0
  130. package/dist/observed-purchase-price.d.ts +71 -0
  131. package/dist/observed-purchase-price.d.ts.map +1 -0
  132. package/dist/received-purchase-money.d.ts +87 -0
  133. package/dist/received-purchase-money.d.ts.map +1 -0
  134. package/dist/recipes.d.ts +4 -1
  135. package/dist/recipes.d.ts.map +1 -1
  136. package/dist/retention-accounting-internal.d.ts +3 -0
  137. package/dist/retention-accounting-internal.d.ts.map +1 -0
  138. package/dist/retention-accounting.d.ts +164 -0
  139. package/dist/retention-accounting.d.ts.map +1 -0
  140. package/dist/retention-money.d.ts +43 -0
  141. package/dist/retention-money.d.ts.map +1 -0
  142. package/dist/smrt-knowledge.json +1866 -113
  143. package/dist/tax/cookbook.d.ts.map +1 -1
  144. package/dist/tax-summary.d.ts +1 -0
  145. package/dist/tax-summary.d.ts.map +1 -1
  146. package/dist/types/index.d.ts +20 -1
  147. package/dist/types/index.d.ts.map +1 -1
  148. package/package.json +16 -16
  149. package/dist/chunks/CustomerCollection-BIPH2ZUx.js +0 -99
  150. package/dist/chunks/CustomerCollection-BIPH2ZUx.js.map +0 -1
  151. package/dist/chunks/DocumentTaxCollection-DDzlywMW.js +0 -1666
  152. package/dist/chunks/DocumentTaxCollection-DDzlywMW.js.map +0 -1
  153. package/dist/chunks/InvoiceCollection-cinzAqt6.js.map +0 -1
  154. package/dist/chunks/TaxCodeCollection-DaBOPG9c.js.map +0 -1
  155. package/dist/chunks/VendorCollection-D6ZcUYy8.js +0 -100
  156. package/dist/chunks/VendorCollection-D6ZcUYy8.js.map +0 -1
  157. package/dist/chunks/calculations-C9daQLsh.js +0 -82
  158. package/dist/chunks/calculations-C9daQLsh.js.map +0 -1
  159. package/dist/chunks/contract-money-EuToOghh.js.map +0 -1
  160. package/dist/chunks/document-money-DV5t4vlK.js +0 -1186
  161. package/dist/chunks/document-money-DV5t4vlK.js.map +0 -1
  162. package/dist/chunks/invoice-posting-C2i5dOVZ.js.map +0 -1
package/AGENTS.md CHANGED
@@ -31,6 +31,8 @@ recipes show carry `@field({ description })` text; keep both in plain
31
31
  language for end users and update them when a recipe's fields change. See
32
32
  [core recipes](../core/agents/recipes.md).
33
33
 
34
+ See [historical issued sales](agents/historical-sales.md) for exact original source
35
+ money, immutable source children and combined historical/live customer funds.
34
36
  See [payment allocation integrity](agents/payment-allocations.md) for atomic splits,
35
37
  retry identity, parent corrections and supported dialects.
36
38
  See [tax codes](agents/tax-codes.md) for tenant-owned rate components, default codes,
@@ -215,3 +217,18 @@ See [agents/purchasing-ui.md](agents/purchasing-ui.md) for caller responsibiliti
215
217
 
216
218
  Pure signed cost billing and explicit tax rounding are available through the
217
219
  independent `cost-billing` subpath; see [contract](agents/cost-billing.md).
220
+
221
+ See [contract billing schedules](agents/contract-billing-schedules.md) for exact
222
+ approved milestone capacity, immutable amendments and atomic canonical invoice issue.
223
+
224
+ ## Customer funds (#4079)
225
+
226
+ See [customer advances](agents/customer-funds.md) for explicitly configured
227
+ unapplied-AR/deposit-liability receipts, conserved application/refund capacity,
228
+ real liability reclassification, final-invoice attestation and mutation guards.
229
+ Use the public commands; `Payment.customerFundsJson` is command-owned.
230
+
231
+ See [observed purchase prices](agents/observed-purchase-prices.md) for incomplete
232
+ original supplier prices, explicit unknown totals and reviewed completion.
233
+ See [received sales agreement money](agents/received-sales-contract-money.md) for
234
+ exact complete source Order/Agreement evidence without synthetic lines or tax recognition.
package/README.md CHANGED
@@ -323,6 +323,10 @@ and retry only if it is still pending. An already completed payment retains the
323
323
  owner: if it rolls back after settlement returns, reload the payment before retry.
324
324
  These guarantees cover new postings, not orphaned journals written by older
325
325
  versions. The returned journal uses the caller's database executor.
326
+ Both payment and refund journal lines retain the payment's explicit currency and
327
+ exact amount; posting does not convert currencies or fall back to USD. When
328
+ reporting accounts that contain different currencies, use the public
329
+ `listPostedMovements` currency filter rather than combining their amounts.
326
330
 
327
331
  ### Cross-Package References
328
332
 
@@ -827,3 +831,129 @@ native POST of vendor, reference, notes, expected date and ship-to fields. Pass
827
831
  allocations and totals unchanged. `PurchaseOrder` stores `expectedDate` and
828
832
  `shipTo` in existing STI metadata. See [the purchasing contract](agents/purchasing-ui.md#purchase-order-header)
829
833
  for validation, retained values and transport details.
834
+
835
+ ### Invoice retention and release
836
+
837
+ `configureInvoiceRetention` freezes an explicit retained minor-unit amount on an
838
+ unpaid draft. Supply tenant, invoice, currency, expected invoice revision,
839
+ request identity, actor, reason, evidence reference, and versioned host policy.
840
+ The supported `creditPolicy: 'retained-first'` is an explicit caller choice:
841
+ issued credits reduce unreleased retention first, then current payable. Hosts
842
+ must choose and authorize their regional policy; Commerce supplies no legal
843
+ percentage or release date default. Configuration cannot be overwritten; replace
844
+ an unissued draft to change the original agreement.
845
+
846
+ `releaseInvoiceRetention` appends evidence under the invoice's transaction lock.
847
+ It cannot release more than the currently retained remainder. Exact request
848
+ replays are safe; changed payloads or stale revisions fail. Both commands retain
849
+ caller transaction affinity. Original gross, tax, line snapshots and approved
850
+ configuration stay unchanged. Credits and credit cancellation derive remaining
851
+ retention without rewriting release history.
852
+
853
+ `invoice.getPayableFacts()` separates `grossBalanceMinor`,
854
+ `retainedRemainingMinor`, `currentlyDueMinor`, and `allocationCapMinor`. The
855
+ allocation API enforces the current cap. `getAmountDue()` returns current due;
856
+ `getBalance()` remains the signed gross balance. An invoice with paid current
857
+ due and unreleased retention is not fully paid or overdue. Display gross and
858
+ current payable separately; pass explicit current due and remaining holdback to
859
+ the exact retained invoice UI props rather than treating gross as payable.
860
+ Stored money facts include `payable` for retained invoices; MCP projection honors
861
+ field visibility for every source of the payable alias.
862
+
863
+ Provider-controlled imports/automatic collection cannot acquire retention.
864
+ Accounting export refuses unreleased retention until the provider has an
865
+ explicit payable representation; it never silently requests collection of
866
+ gross. Fully released invoices use the existing gross accounting contract.
867
+
868
+ ## Retained invoice accounting
869
+
870
+ `loadRetainedInvoiceAccountingSnapshot` supplies a read-only frozen document for
871
+ reviewing item/tax mapping before posting; `toRetainedInvoiceAccountingInput`
872
+ validates that reviewed mapping against those frozen lines. Both preserve tenant and caller executor
873
+ scope and performs no provider operation. Generic accounting snapshot/export still
874
+ refuses unreleased retention. A supplied host-managed release due date may precede
875
+ the release date: preserving original past-due terms makes the released amount
876
+ immediately overdue rather than silently extending payment terms.
877
+
878
+ `loadRetainedCreditAccountingSnapshot` and `toRetainedCreditAccountingInput`
879
+ provide the equivalent review path for an issued calculated credit. The caller
880
+ supplies both original invoice and credit IDs; the owning API verifies tenant,
881
+ customer, currency and exact original lineage, then retains the existing frozen
882
+ reader's issue and provider-realm checks. Generic retained-credit export remains
883
+ blocked. Review never creates a credit adjustment or contacts a provider.
884
+
885
+ The public `syncRetainedInvoiceToAccounting`, `releaseRetainedInvoiceToAccounting`,
886
+ `syncRetainedCreditToAccounting`, and `syncRetainedRefundToAccounting` commands
887
+ implement an explicit QuickBooks accrual reclassification contract. They require
888
+ SDK `receivableTransfers` from the published SDK0.104.1 cohort
889
+ (happyvertical/sdk#1414 / #1415; absent from SDK0.104.0).
890
+ They are available from the Commerce root and `/invoices` entry points.
891
+
892
+ The tenant must review/version the realm, environment, customer, AR account,
893
+ retained-asset account and optional bank account mapping. Supported choices are
894
+ `accrual`, `invoice-tax-point` and `host-managed` release due dates. Verified home
895
+ currency only; no inferred FX, tax timing, recovery percentage or release date.
896
+ Hosts authorize actors before these server commands and provide an active tenant.
897
+
898
+ For gross10500/retained1000, the original approved invoice remains10500. A
899
+ withholding journal debits retained assets and credits customer AR1000; a
900
+ zero-cash application links that credit to the original invoice. A partial release
901
+ creates the opposite journal and an explicitly dated host collection obligation.
902
+ The original invoice and its tax snapshot are unchanged. Provider collections and
903
+ provider tax overrides are unsupported for this contract.
904
+
905
+ Initial export requires an issued, unpaid, uncredited, unreleased host-owned
906
+ invoice with no prior provider identity. Historical source-owned invoices require
907
+ a separate reconciled ownership contract and are rejected: importing history must
908
+ not duplicate its original journal. Existing local retention commands continue to
909
+ reject provider-controlled releases; use the provider release command instead.
910
+
911
+ Retained-first credits cancel the applicable retained asset through a release
912
+ journal, apply the exported credit memo to that journal, and apply any due portion
913
+ to the original invoice. Unapplied credit remains available for a refund. Refund
914
+ sync requires an already completed local refund Payment, its cash journal and one
915
+ exact source-credit allocation. It records the cash journal and applies the
916
+ existing credit; it performs no bank action and makes no settlement-certification
917
+ claim. That source payment/allocation becomes immutable. Provider-managed invoice
918
+ voids/write-offs, credit cancellation/reallocation and refund deletion are rejected
919
+ rather than silently erasing remote postings. Corrective reversal contracts are
920
+ not implemented by these commands.
921
+
922
+ ### Recovery and concurrency
923
+
924
+ Each external write has persisted request bytes/hash, attempt owner, status and
925
+ validated readback. Confirmed earlier steps survive a later failure. Unknown or
926
+ interrupted steps block new operations; `reconcileRetainedAccountingStep` requires
927
+ the observed request/attempt, a known remote ID for exact provider readback, or
928
+ explicit authoritative absence evidence. An interrupted in-flight owner must be
929
+ proven stopped. Reconciliation evidence and previous attempts remain recorded.
930
+ `reconcileRetainedBaseInvoice` wraps the existing frozen invoice recovery contract.
931
+ `reconcileRetainedCreditAccounting` resolves the reserved credit-memo creation step. Ordinary credit export is blocked for provider-retained sources.
932
+
933
+ The descriptor hash is not remote idempotency. The SDK uses documented QuickBooks
934
+ request-ID duplicate handling; never create a new request identity merely because
935
+ a response was lost. Exact local replays reuse confirmed steps. Competing commands
936
+ serialize under the tenant/source invoice locks, and releases check an observed
937
+ invoice revision. Source credits cannot change during an unfinished retention
938
+ operation. Commands reject caller-owned Commerce money transactions because a
939
+ provider write cannot be rolled back with local SQL.
940
+
941
+ `readRetainedInvoiceAccountingState` exposes the persisted operation/readback
942
+ history. Canonical `Invoice.getPayableFacts()` remains the source of local gross,
943
+ retained, released, credited and currently due amounts. Provider invoice
944
+ `TotalAmt - Balance` includes noncash applications and must never be labeled cash
945
+ received. SDK readback separates noncash applications, recorded cash journals and
946
+ unverified bank settlement.
947
+
948
+ Validation uses native SQLite/PostgreSQL persistence with mocked public provider
949
+ operations, plus the SDK's exact request/readback fixtures. No live provider call
950
+ or sandbox certification has been performed. Primary contract evidence and
951
+ provider-field limits are documented in the SDK Accounting README.
952
+
953
+ ### Incomplete supplier price evidence
954
+
955
+ Use `recordPurchasePriceObservation`, `readPurchasePriceObservation`, and
956
+ `completePurchasePriceObservation` for source quotes/orders that lack complete
957
+ net/tax/gross facts. Unknown totals remain null and no calculated or reportable
958
+ Contract exists until explicit reviewed completion. See
959
+ [observed purchase prices](agents/observed-purchase-prices.md).
@@ -109,3 +109,14 @@ example A is tax-exclusive and example B is tax-inclusive. Both cover line and
109
109
  document allocation; example B's document scope preserves line 3's allocated
110
110
  GST cent. Focused sync tests inspect the exact public SDK request inputs and
111
111
  persisted create descriptors without performing a provider network write.
112
+
113
+ ## Compound tax configuration
114
+
115
+ `FrozenQuickBooksTaxMapping.lines[lineId].taxComponents` may retain the
116
+ caller-verified ordered realm TaxCode configuration as `{taxRateRef, compound}`
117
+ entries. Compound frozen lines require that exact sequence and their stored
118
+ `taxableMinor` bases. The mapper projects `compound` and `taxableAmount` into the
119
+ public accounting SDK without changing statutory percentages or declared taxes.
120
+ Missing/mismatched configuration fails explicitly. Hosts own tenant-scoped review
121
+ and provenance of the existing realm code's applicability/order; a taxCodeRef
122
+ string alone is insufficient evidence. Use the SDK release containing sdk#1412.
@@ -0,0 +1,67 @@
1
+ # Contract milestone billing (#4074)
2
+
3
+ Use the public Commerce `approveContractBillingSchedule`,
4
+ `issueContractMilestoneInvoice`, `getContractBillingSchedule` and
5
+ `allocateContractMilestones` exports for fixed-value milestone billing. These
6
+ commands own monetary capacity. The host owns construction scope, estimated cost,
7
+ approval permissions, signed evidence, regional policy and UI.
8
+
9
+ Start with an accepted, frozen customer `Order` or `Agreement`. The first schedule
10
+ requires `amendmentMinor: 0`, `expectedRevision: 0`, currency, explicit `basis:
11
+ 'net' | 'gross'`, `approvalEvidenceRef`, `taxPolicyEvidenceRef` and exact milestone
12
+ `{ key, label, amountMinor }` entries. Their sum must equal the original Contract
13
+ subtotal for net basis or totalAmount for gross basis. There is no editable
14
+ schedule override of the accepted Contract value.
15
+
16
+ Each amendment supplies the current expected revision, a new request identity,
17
+ an explicit signed `amendmentMinor`, approval evidence and the complete next
18
+ schedule. Its ceiling is derived from the original frozen value plus all approved
19
+ amendments. Currency/basis cannot change. Already issued milestone keys, labels
20
+ and amounts must remain unchanged. Prior revisions and original Contract money
21
+ remain immutable. Unissued milestones can be rescheduled through an explicitly
22
+ approved revision. Net capacity is not a gross ceiling: each invoice's tax must
23
+ also be explicitly approved under the versioned policy.
24
+
25
+ `allocateContractMilestones(totalMinor, weights)` accepts positive integer
26
+ relative weights. All nonfinal shares truncate exact rational arithmetic; the
27
+ final entry receives the exact remainder. For example 100 with weights [1,1,1]
28
+ returns [33,33,34]. Zero amounts are allowed; negative/unsafe money and nonpositive
29
+ weights reject. The helper chooses no tax policy or commercial percentages.
30
+
31
+ Prepare a normal canonical draft Invoice and real line items through the public
32
+ Commerce collections. Draft preparation consumes no capacity; an unissued draft may be cancelled
33
+ without a claim. Then call:
34
+
35
+ ```ts
36
+ const claim = await issueContractMilestoneInvoice({
37
+ db, tenantId, contractId, requestId: 'issue:start:v1',
38
+ revision: 1, milestoneKey: 'start', invoiceId,
39
+ approvedMoney: { netMinor: 4000, taxMinor: 200, grossMinor: 4200 },
40
+ invoiceApprovalEvidenceRef: 'approved-invoice:123',
41
+ });
42
+ ```
43
+
44
+ The command checks same tenant/customer/currency/Contract, derives current line
45
+ money, verifies the exact approved net/tax/gross and schedule amount, freezes the
46
+ invoice and records the claim atomically. Tax-policy evidence is a host-owned
47
+ reviewed version reference, not an instruction to infer tax rates. Preserve the
48
+ approval's policy and original evidence in the host. Ordinary issue against a
49
+ scheduled Contract is refused, including direct creation in a non-draft state.
50
+ Existing issued contract invoices prevent adopting a schedule retroactively.
51
+
52
+ The explicit capacity policy is `issued-consumed`: cancellation, credits,
53
+ write-offs, payments, retention and refunds never reopen a claimed milestone.
54
+ Credits correct the canonical receivable and settlement continues through existing
55
+ Payment/PaymentAllocation facilities. Unapplied payments remain the deposit cash
56
+ authority. A replacement billing entitlement requires an explicit approved
57
+ amendment; this API does not infer that a credit authorizes re-billing. Applications
58
+ must explain that policy rather than present a hidden re-bill action. Issued
59
+ claims remain readable after later amendments and cancellations.
60
+
61
+ Every mutation requires the active tenant context and uses the tenant money
62
+ serialization barrier on the exact parent transaction executor. Identical request
63
+ replay returns the original evidence; a changed payload, stale revision or second
64
+ claim rejects. A parent rollback reverses both invoice issue and schedule claim.
65
+ A detached read DTO cannot modify persisted state. Ordinary Contract writes and
66
+ deletes cannot erase schedule history. Host authorization precedes these commands;
67
+ none is exposed as an unauthenticated generated mutation.
@@ -19,3 +19,84 @@ freeze just like other Contracts, but quote snapshots (including custom
19
19
  descendants) are excluded by their hydrated STI subtype, not the mutable
20
20
  `contractType` scalar, from report candidates and purchase tax facts. Awarding
21
21
  requires a separate PurchaseOrder.
22
+
23
+ ## Received supplier monetary evidence
24
+
25
+ `recordReceivedPurchaseMoney({ db, tenantId, contractId, requestId, evidenceRef,
26
+ facts, sourceQuote? })` records declared money on an existing empty draft
27
+ `SupplierQuote` or `PurchaseOrder`. Authorize the human in the host first and
28
+ call inside its active tenant context. The command locks tenant settings and
29
+ the document on its transaction executor; an outer transaction can include
30
+ creation of the quote/order. It returns a `ReceivedPurchaseMoneySnapshot`;
31
+ `getReceivedPurchaseMoney(contract)` returns that validated snapshot or `null`
32
+ for calculated documents. The public command is not an unguarded MCP action.
33
+
34
+ ```ts
35
+ await recordReceivedPurchaseMoney({
36
+ db, tenantId, contractId: quote.id, requestId: 'received-revision-1',
37
+ evidenceRef: 'supplier-document:revision-1',
38
+ facts: {
39
+ currency: 'CAD', netMinor: 10000, taxMinor: 537, grossMinor: 10537,
40
+ taxComponents: null,
41
+ detail: { kind: 'header-only' },
42
+ },
43
+ });
44
+ // Reload after the command; stale instances cannot overwrite its authority.
45
+ const received = await contracts.get({ id: quote.id }, { cache: false });
46
+ received.status = ContractStatus.ACCEPTED;
47
+ await received.save();
48
+ ```
49
+
50
+ This sets `moneyAuthority='received'`; aggregate headers retain exactly
51
+ 10000/537/10537 without guessing a tax rate. The default `calculated` mode and
52
+ its line/tax-code calculator are unchanged. Received facts become immutable
53
+ when recorded. Exact retries return the original snapshot even after acceptance;
54
+ changed requests need a new document revision. Direct authority/evidence writes,
55
+ header edits, calculated lines, party/type changes and deleting received history
56
+ are rejected. Acceptance sets the normal `moneySnapshotId` without recalculating
57
+ source amounts. A stable application quote identity may reference a distinct
58
+ canonical `SupplierQuote` for each immutable revision.
59
+
60
+ `detail` must explicitly be `header-only` or `lines`. The latter supplies complete
61
+ source `netMinor`, `taxMinor`, `grossMinor` per uniquely keyed line with exact
62
+ aggregate reconciliation. Optional `quantityText`/`unitRateText` retain original
63
+ decimal text, never drive recomputation. When source lines are incomplete, retain
64
+ them in the referenced source evidence and use header-only monetary facts; do
65
+ not invent `ContractLineItem` quantities, tax lines, or allocations.
66
+
67
+ `taxComponents:null` means unknown decomposition. `[]` means known zero tax,
68
+ which requires `taxMinor:0`, but does not classify that zero as exempt/zero-rated.
69
+ Each supplied component retains its source key, label, amount, explicit
70
+ `classification` (`taxable`, `zero-rated`, `exempt`, `out-of-scope`, or `null`)
71
+ and `recoverableMinor` (including explicit zero or unknown `null`). Optional
72
+ `taxCodeId`, `taxComponentId` and `taxableMinor` remain unknown when omitted. Values are exact
73
+ safe nonnegative minor units; sums use integer arithmetic. No recoverability,
74
+ rate, taxable basis or classification is inferred from a label or amount.
75
+
76
+ An order can include
77
+ `sourceQuote:{contractId,relationship:'copy'|'negotiated'}`. The quote must be
78
+ accepted, frozen, received, and match tenant/vendor/currency. `copy` requires
79
+ identical facts. `negotiated` requires separately supplied approved monetary
80
+ facts and a separate evidence reference; it never prorates a quote. The command
81
+ records lineage but does not manufacture acceptance or financial approvals.
82
+
83
+ Received SupplierQuotes remain excluded from incurred purchase-tax reporting.
84
+ PurchaseOrders retain their existing report eligibility. For a received order,
85
+ public document report facts project explicit source amounts without creating
86
+ calculated `DocumentTax` rows or fictitious rates. Each report component must
87
+ have an explicit classification, tenant-owned tax code, taxable basis, recoverable amount and, for
88
+ `taxable`, a tenant-owned `taxComponentId`. Missing facts raise
89
+ `ReceivedPurchaseTaxClassificationRequired` with code
90
+ `RECEIVED_PURCHASE_TAX_CLASSIFICATION_REQUIRED` and the affected order ID. This
91
+ blocks only a report whose tenant/date/currency window includes that order;
92
+ recording, accepting and awarding unknown-classification evidence remains valid.
93
+ Existing calculated PO reporting is unchanged. Correct classification through an
94
+ explicit reviewed replacement revision and cancellation of the superseded
95
+ report-eligible order, preserving its history; never rewrite frozen evidence or
96
+ silently omit the unknown order from a report.
97
+
98
+ The two added Contract fields use the normal generated schema/migration flow;
99
+ apply the generated migration before using the new public command on an existing
100
+ database. Native SQLite/PostgreSQL acceptance is in
101
+ `received-purchase-money.test.ts` / `received-purchase-money.optional.test.ts`.
102
+ DuckDB retains the existing unsupported native Contract foreign-key boundary.
@@ -0,0 +1,96 @@
1
+ # Customer advances and unallocated cash
2
+
3
+ The public `recordCustomerFunds`, `allocateCustomerFunds`, `refundCustomerFunds`,
4
+ `reverseCustomerFundsAllocation` and `getCustomerFundsFacts` commands reuse
5
+ Payment, PaymentAllocation and smrt-ledgers journals. They do not create invoice
6
+ revenue, issue credit notes, transmit money to a bank or call a provider.
7
+ Applications authorize each command and supply human/source evidence.
8
+
9
+ A receipt requires an explicit immutable policy version:
10
+
11
+ - `mode`: `unapplied-ar` or `deposit-liability`.
12
+ - `taxTiming: 'invoice-tax-point'`: the caller has explicitly reviewed that tax
13
+ belongs on the eventual invoice. This is the only supported timing. The API
14
+ does not assume that every jurisdiction treats deposits as untaxed; other
15
+ timing policies are rejected and need a separate supported accounting model.
16
+ - `releaseEligibility`: `any-issued-invoice` or `final-invoice-only`.
17
+ - Distinct cash and receivables asset accounts, plus a liability account only
18
+ for liability mode. Every account must be active in the same tenant chart.
19
+
20
+ Ledgers currently has no separate Ledger entity or currency-restricted Account
21
+ field. The ledger boundary is its tenant-owned chart; currency is explicit on
22
+ this receipt and every journal entry. The legacy `RecordPaymentOptions.ledgerId`
23
+ is unused by existing Payment settlement. These commands neither pretend it
24
+ validates an independent ledger nor invent account metadata conventions.
25
+
26
+ | Operation | Unapplied AR | Deposit liability |
27
+ | --- | --- | --- |
28
+ | Receipt | DR cash / CR AR | DR cash / CR customer liability |
29
+ | Application | Existing settlement allocation | DR customer liability / CR AR |
30
+ | Unallocated refund | DR AR / CR cash | DR customer liability / CR cash |
31
+ | Application reversal | Reverse settlement allocation | DR AR / CR customer liability |
32
+
33
+ All amounts are positive safe integer minor units. Available capacity is exactly
34
+ `received - active applications - settled source-linked refunds`. A refund is a
35
+ positive outgoing Payment with immutable source-receipt lineage; it is not an
36
+ invoice credit refund. Reversal retains the original application and appends an
37
+ inverse operation and journal, removing only the active settlement row. An issued
38
+ invoice credit or credit refund blocks application reversal so previously spent
39
+ cash cannot become refundable a second time. Resolve that invoice correction
40
+ through its own authority first.
41
+
42
+ Each request carries `effectiveOn` (calendar date), `evidenceRef`, `actorId` and a
43
+ stable `requestId`. Effective dates are distinct from recording timestamps and
44
+ must be chronological within a receipt's movements. Receipt/refund `paidAt` and
45
+ journal dates use the explicitly supplied effective date. Exact replays return
46
+ current conserved facts; changing the request payload fails. Refund/application
47
+ races serialize on the tenant money boundary and receipt revision. Caller-owned
48
+ transactions include the payment, journals, allocation, status and audit evidence.
49
+
50
+ Application requires a matching issued invoice, customer, currency, optional
51
+ sales contract and actual `moneySnapshotId`. `release` also names the frozen
52
+ receipt policy version and the host's immutable invoice-approval evidence. Under
53
+ final-only policy, the host must verify and attest `kind: 'final-invoice'` from
54
+ that frozen approval. This is an application authorization responsibility, not a
55
+ user-supplied checkbox or inference from invoice numbering. The generic library
56
+ checks the attestation shape and exact canonical monetary snapshot; it does not
57
+ know construction milestone/finality rules.
58
+
59
+ `Payment.customerFundsJson` is command-owned. Ordinary saves, deletes,
60
+ PaymentAllocation create/update/delete, collection allocation helpers, payment
61
+ intent settlement and supplier payouts cannot repurpose managed advances or
62
+ bypass required journal entries. Managed refunds cannot be allocated to invoice
63
+ credits. `getUnallocatedFromPayment` subtracts managed refunds and requires the
64
+ persisted receipt amount. Direct SQL and administrative ledger mutations remain
65
+ outside this domain authority; facts refuse missing/voided journal evidence.
66
+
67
+ ```ts
68
+ await withTenant({ tenantId }, async () => {
69
+ const received = await recordCustomerFunds({
70
+ db, tenantId, customerId, currency: 'CAD', amountMinor: 10000,
71
+ method: PaymentMethod.BANK_TRANSFER, requestId: receiptRequestId,
72
+ effectiveOn: '2026-10-01', evidenceRef: bankReceiptRef, actorId,
73
+ policy: {
74
+ version: reviewedPolicyVersion, mode: 'deposit-liability',
75
+ taxTiming: 'invoice-tax-point', releaseEligibility: 'final-invoice-only',
76
+ cashAccountId, receivablesAccountId, liabilityAccountId,
77
+ },
78
+ });
79
+ await allocateCustomerFunds({
80
+ db, tenantId, paymentId: received.paymentId, invoiceId, amountMinor: 8000,
81
+ requestId: applicationRequestId, effectiveOn: '2026-10-10',
82
+ evidenceRef: applicationEvidenceRef, actorId,
83
+ release: {
84
+ kind: 'final-invoice', invoiceSnapshotId,
85
+ approvalEvidenceRef: frozenFinalInvoiceApprovalRef,
86
+ policyVersion: reviewedPolicyVersion,
87
+ },
88
+ });
89
+ });
90
+ ```
91
+
92
+ Native `customer-funds.test.ts` and `customer-funds.optional.test.ts` prove exact
93
+ journals, both modes, direct-path protections, dates, finality evidence,
94
+ conservation, invoice-credit interaction, retries, caller rollback and a real
95
+ PostgreSQL post-journal write fault plus refund/application race. Run PostgreSQL
96
+ through the standard managed database wrapper; never use an application's schema.
@@ -0,0 +1,132 @@
1
+ # Historical issued sales and original customer funds (#4081)
2
+
3
+ Historical intake is a separate source authority, not a new sale, send, or cash
4
+ posting. Hosts must authorize the reviewer/importer, preserve original evidence,
5
+ and call these public commands with the explicit active tenant. All writes use
6
+ one caller-affine transaction and the existing tenant money serialization lock.
7
+
8
+ `recordHistoricalSalesMoney({ db, tenantId, invoiceId, requestId, evidenceRef,
9
+ review, source, facts, creditedSource? })` adopts an empty draft Invoice. Supply
10
+ original integer minor-unit net/tax/gross, explicit signed-versus-magnitude
11
+ polarity, original issue calendar date/time zone, and a nullable unknown due date.
12
+ Normal calculated Invoice construction still defaults its due date as before.
13
+ Historical invoices expose `moneyAuthority: 'historical'` and a frozen source
14
+ snapshot. They create no InvoiceLineItems, fake quantities/rates, delivery event,
15
+ AR/revenue journal, or provider invoice.
16
+
17
+ A `detail: { kind: 'lines', lines }` source creates immutable
18
+ `HistoricalSalesLine` children. The returned `{ snapshot, lines }` binds every
19
+ source key to a concrete `lineId`; use these IDs for consumer crosswalks.
20
+ Unknown line tax, gross, quantity and rate remain null. Signed real adjustment
21
+ lines retain their source values. The line net sum and every fully known other
22
+ sum must exactly equal its corresponding original header.
23
+
24
+ Historical credits specify the exact original invoice/money snapshot and
25
+ optional concrete original child IDs. Independent net, tax and gross capacity
26
+ checks never prorate a header. `getHistoricalSalesMoney` and
27
+ `readHistoricalSalesLines` validate immutable retained authority.
28
+ `getInvoiceMoneyFacts` includes the historical source projection. Exact header
29
+ reports remain available through `listHistoricalSalesHeaderFacts` even when tax
30
+ classification is unknown. Breakdown-dependent tax reports require explicit
31
+ reviewed component identities, taxable and net bases and classification; they
32
+ never infer a percentage from the source amount or borrow today's rate.
33
+
34
+ Optional original `source.retention` records exact retained cents, an explicit
35
+ retained-first credit policy, source actors/evidence and original calendar-dated
36
+ releases. This contract represents retention configured at original issue; its
37
+ original effective date must equal the issue calendar date. A later retention
38
+ configuration requires its own supported source event contract. Derived retention
39
+ events retain actual `recordedAt` and separate
40
+ `effectiveOn`; as-of original cash eligibility uses the original dates. Ordinary
41
+ current retention configuration/release commands keep their existing behavior.
42
+ Original credit/release sequencing rejects a release whose retained-first
43
+ capacity was already consumed; same-day ordering must be explicitly reviewed.
44
+ Release payment terms remain the original invoice due date, including an
45
+ explicitly unknown date. No jurisdiction terms are invented.
46
+
47
+ `recordHistoricalCustomerFunds` retains original receipt/refund evidence and
48
+ explicit original deposit/release policy without creating a Payment or journal.
49
+ Original accounting ownership and journal references are evidence, not authority
50
+ to create duplicate original cash. Refunds identify either conserved unapplied
51
+ funds or one exact issued credit. Their headers immediately reserve refund
52
+ capacity, even before their original allocation row is imported.
53
+
54
+ `recordHistoricalCustomerAllocation` records exact source allocation identities.
55
+ Receipt applications affect the shared invoice paid balance once. Same-original
56
+ credit allocation rows and refund allocation rows audit their already-recorded
57
+ economic effects and do not reduce balances again. Cross-invoice transferable
58
+ credits are not represented by this contract. Same-day cash/credit chronology
59
+ requires explicit reviewed ordering; earlier original cash remains preserved
60
+ when a later credit creates owed/refundable overpayment. Original cash dates
61
+ remain separate from current balances and import timestamps.
62
+
63
+ `getHistoricalCustomerFundsPosition` returns exact received/allocated/refunded/
64
+ available minor units. `applyHistoricalCustomerFunds` and
65
+ `refundHistoricalCustomerFunds` perform NEW movements against remaining original
66
+ funds using explicit current active same-tenant accounts and the pinned original
67
+ policy terms. Applications use the existing liability-to-AR reclassification;
68
+ refunds use the existing journal-backed Payment command and retain the historical
69
+ receipt ID. Original receipts are never forged into completed Payments. Shared
70
+ live/historical paid/refund capacity prevents a second allocation or refund.
71
+
72
+ Stable source namespace/key identities replay exact facts across import runs
73
+ without replacing the original importer or evidence. Changed facts/policy or
74
+ source-version reuse conflicts. Ordinary/generated model writes and deletion
75
+ cannot mutate these immutable records. Provider synchronization and new revenue
76
+ recognition reject historical authority until an explicit supported historical
77
+ accounting representation is supplied; exact original money is still readable.
78
+
79
+ Focused evidence covers source/header immutability, concrete children, original
80
+ cash/credit/refund chronology, conservation, CAD journals for new movements,
81
+ caller rollback and isolated PostgreSQL execution. Consumer historical adapters
82
+ must still map every source table and prove full-cohort reconciliation; adopting
83
+ these public facts alone is not full reference-import acceptance.
84
+
85
+ Current explicitly dated retention releases append after the immutable original
86
+ release prefix. Both remain readable without changing original dates or source
87
+ authority; replay binds the explicit date and caller rollback restores the
88
+ complete release history. Provider releases retain their effective date in the
89
+ canonical retention history as well as provider evidence. Shared SQLite and
90
+ PostgreSQL retention suites verify reload, exact retry, original-prefix tamper
91
+ refusal, and transactional rollback.
92
+
93
+ Historical cash allocations are validated as dated payment prefixes, independent
94
+ of source import order. Backdated insertion rechecks later application dates;
95
+ ordinary public allocations retain their canonical allocatedAt chronology.
96
+ Same-day credit ordering remains explicit. Later credits alone do not
97
+ retroactively invalidate cash received before their issue date.
98
+
99
+ Current `releaseInvoiceRetention` commands retain optional `sameDayCreditOrder`
100
+ in their immutable evidence, alongside the effective calendar date. An exact
101
+ retry must preserve that ordering; changing or removing it is a changed request.
102
+ A later original credit import on the release date uses the retained ordering:
103
+ `release-before-credit` releases first, while `credit-before-release` applies
104
+ the retained-first credit before checking remaining release capacity. Missing
105
+ ordering remains ambiguous and is refused rather than inferred from record time.
106
+ ### Bounded historical report scope
107
+
108
+ Historical header and tax reports apply the explicit tenant, historical money
109
+ authority, inclusive issue-date period, optional currency, and non-draft/non-cancelled
110
+ status predicates in the collection query before enforcing the 100,000-document
111
+ scope limit. Unrelated archived invoices do not consume a smaller report's limit;
112
+ more than 100,000 matching documents is refused rather than truncated.
113
+
114
+ Regression design (#4063, PR #4101 comment 4300513731):
115
+
116
+ | Invariant / trigger | Positive / refusal | Actor and executor | Runtime / evidence |
117
+ | --- | --- | --- | --- |
118
+ | Small matching period in a large tenant archive | Query-boundary fixture returns the single matching row only when all predicates precede the limit; matching scope above the cap still refuses | Explicit tenant and caller database; reads only | Focused Vitest; sparse overflow result avoids creating an archive |
119
+ | Native collection scope | Exact inclusive boundaries, optional currency, historical authority and tenant isolation; draft/cancelled excluded | Active tenant, native test database | Focused SQLite and isolated PostgreSQL public historical-money + report proof |
120
+
121
+ No persistence behavior changes; rollback/retry and external-provider edges are
122
+ not applicable to this read-only query correction. The coordinator owns broader
123
+ cohort validation and exact-head review under the resumed four-comment batch.
124
+
125
+ Evidence on Node26/pnpm11.25.0: the focused archive-query regression failed against
126
+ 78f3ac856 (two failures, one pass), then passed after this query fix. The standard
127
+ `node scripts/run-with-ci-postgres.mjs -- pnpm --filter @happyvertical/smrt-commerce exec vitest run src/__tests__/historical-sales-report-scope.test.ts src/__tests__/historical-sales-report-scope-native.test.ts`
128
+ proof passed all five cases in9.80seconds, including actual SQLite and isolated
129
+ PostgreSQL scope/tenant checks. No100,000-row fixture, production writes or schema
130
+ changes were needed. Full logs remain external at the2026-10-16 MVP session's
131
+ `nonfinancial-import/scoped-sales-regression-base.log`, `scoped-sales-focused.log`
132
+ and `scoped-sales-postgres.log`. Native token usage was unavailable.
@@ -42,3 +42,39 @@ fraction. It takes no options. Its discount is signed minor units and passes
42
42
  through unchanged, and its ties round half away from zero for negative
43
43
  lines too. Editor magnitude normalization happens before constructing that
44
44
  input. See [invoice line calculation](invoice-calculations.md).
45
+
46
+ ## Ordered compound taxes
47
+
48
+ `TaxComponentInput.compound: true` uses every preceding component in the same
49
+ ordered tax code. Different applicable line/category subsets use different codes;
50
+ no missing predecessor is invented. Exclusive and explicit-net credit inputs use
51
+ prior rounded taxes at line scope or prior allocated taxes at document scope.
52
+ Shared components retain one rate. Contradictory dependency orders across codes
53
+ fail with `TAX_COMPONENT_DEPENDENCY_CYCLE`.
54
+
55
+ Inclusive extraction computes exact ordered rational factors, then rounds or
56
+ allocates the extracted component taxes. Net is the gross-minus-tax residual.
57
+ This is not a promise that an inclusive extraction reverses an exclusive rounded
58
+ calculation penny-for-penny. Signed reversals use the same symmetric rules.
59
+
60
+ Compound result components and frozen line snapshots carry `compound: true` and
61
+ `taxableMinor`. Component tax rows preserve this actual basis, with `netMinor`
62
+ separate so kind/revenue summaries do not include tax-on-tax as net revenue.
63
+ Historical additive snapshots omit these optional fields. Credits reconstruct the
64
+ frozen ordered components; a final credit consumes the remaining frozen bases and
65
+ taxes. The compatibility line `taxRate` is the observed effective tax/net ratio
66
+ for compound lines, not a flattened statutory rate; never use it to reconstruct
67
+ a document. Use component snapshots and canonical minor-unit totals.
68
+
69
+ `DocumentTax.netMinor` is a nullable generated-schema field. Additive records use
70
+ null and retain their previous reporting shape. Upgrade schemas before projecting
71
+ reports. Received purchase components may declare a taxable basis above net;
72
+ when that occurs their explicit `netMinor` is required for report classification.
73
+ Recording evidence remains allowed without that classification.
74
+
75
+ Compound accounting synchronization uses the public SDK ordered snapshot contract
76
+ ([SDK #1412](https://github.com/happyvertical/sdk/issues/1412)). The mapper preserves
77
+ original rates, exact taxable bases and caller-verified realm TaxCode ordering.
78
+ Missing or mismatched reviewed mapping still raises `ACCOUNTING_SYNC_UNSUPPORTED`.
79
+ It never substitutes a flattened rate. Deployment requires the SDK release that
80
+ contains this public contract; the prior additive-only SDK cannot accept it.
@@ -27,7 +27,7 @@ line-ID code-unit order breaking ties. It leaves no document residual. Across
27
27
  `n` small lines, the two scopes can differ by up to `ceil(n / 2)` minor units
28
28
  per component. Store the chosen scope; do not silently substitute a later
29
29
  setting. `MoneyValidationError.code` is the public branch point for invalid
30
- money, discounts, tax-code state and scope, unsupported compound tax, frozen
30
+ money, discounts, tax-code state and scope, contradictory compound dependencies, frozen
31
31
  records, and unsafe values.
32
32
 
33
33
  Tax-code resolution is pure once the caller has loaded authorized codes. It
@@ -105,5 +105,8 @@ mapper](accounting-snapshot-mapper.md).
105
105
  Upgrading data written by an earlier version is documented in
106
106
  [money data upgrade](money-upgrade.md). Contract money persistence remains a separate aggregate contract; production report
107
107
  hosting is an application opt-in over the public host described above. The
108
- model also does not provide currency conversion, cash-basis/deposit accounting,
109
- partial recoverability, period locking, or compound tax.
108
+ model also does not provide currency conversion or general cash-basis accounting,
109
+ partial recoverability or period locking. Ordered compound taxes are supported as
110
+ documented in [money calculator](money-calculator.md). Explicit invoice-tax-point
111
+ customer deposits and unallocated cash are provided by the separate
112
+ [customer-funds authority](customer-funds.md), not by invoice pricing.