@mudraforge/statutory 2.12.1 → 2.14.0

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 (134) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +19 -0
  3. package/okf/corporate_ma_restructuring/business_combinations_indas_103/ast.json +20 -0
  4. package/okf/corporate_ma_restructuring/impairment_of_assets_indas_36/ast.json +20 -0
  5. package/okf/corporate_ma_restructuring/loss_carryforward_sec79/ast.json +33 -0
  6. package/okf/corporate_ma_restructuring/share_based_payments_indas_102/ast.json +20 -0
  7. package/okf/corporate_ma_restructuring/slump_sale_50b/ast.json +21 -0
  8. package/okf/corporate_ma_restructuring/tax_clearance_sec281/ast.json +21 -0
  9. package/okf/direct_tax/corporate_tax_115baa_115jb/ast.json +23 -0
  10. package/okf/direct_tax/income_taxes_deferred_tax_indas_12/ast.json +20 -0
  11. package/okf/direct_tax/special_rates_non_filer_206ab/ast.json +26 -0
  12. package/okf/direct_tax/statutory_disallowance_43b/ast.json +35 -0
  13. package/okf/direct_tax/tcs_goods_206c_1h/ast.json +69 -0
  14. package/okf/direct_tax/tds_commission_194h/ast.json +60 -0
  15. package/okf/direct_tax/tds_contractor_194c/ast.json +71 -0
  16. package/okf/direct_tax/tds_ecommerce_194o/ast.json +48 -0
  17. package/okf/direct_tax/tds_goods_194q/ast.json +71 -0
  18. package/okf/direct_tax/tds_goods_393/ast.json +59 -0
  19. package/okf/direct_tax/tds_individual_contract_194m/ast.json +59 -0
  20. package/okf/direct_tax/tds_interest_194a/ast.json +59 -0
  21. package/okf/direct_tax/tds_perquisites_194r/ast.json +47 -0
  22. package/okf/direct_tax/tds_property_194ia/ast.json +70 -0
  23. package/okf/direct_tax/tds_rent_194i/ast.json +60 -0
  24. package/okf/direct_tax/tds_rent_individual_194ib/ast.json +59 -0
  25. package/okf/direct_tax/tds_services_194j/ast.json +60 -0
  26. package/okf/indirect_tax_gst/blocked_itc_17_5/ast.json +26 -0
  27. package/okf/indirect_tax_gst/common_itc_reversal_rule42_43/ast.json +26 -0
  28. package/okf/indirect_tax_gst/composite_mixed_supplies_sec8/ast.json +21 -0
  29. package/okf/indirect_tax_gst/composition_levy_sec10/ast.json +23 -0
  30. package/okf/indirect_tax_gst/credit_debit_notes_sec34/ast.json +21 -0
  31. package/okf/indirect_tax_gst/e_invoicing_rule48_4/ast.json +20 -0
  32. package/okf/indirect_tax_gst/export_services_lut_sec16/ast.json +20 -0
  33. package/okf/indirect_tax_gst/gst_tds_sec51/ast.json +23 -0
  34. package/okf/indirect_tax_gst/itc_eligibility_16_2/ast.json +20 -0
  35. package/okf/indirect_tax_gst/itc_reversal_rule37_37a/ast.json +45 -0
  36. package/okf/indirect_tax_gst/rcm_liability_sec9_3/ast.json +26 -0
  37. package/okf/international_tax/cross_border_remittance_195/ast.json +39 -0
  38. package/okf/international_tax/financial_instruments_ecl_indas_109/ast.json +24 -0
  39. package/okf/international_tax/foreign_exchange_indas_21_109/ast.json +20 -0
  40. package/okf/international_tax/foreign_tax_credit_irc_901_904/ast.json +20 -0
  41. package/okf/international_tax/transfer_pricing_alp_92c/ast.json +25 -0
  42. package/okf/manifest.json +49 -3
  43. package/okf/msme_commercial/delayed_payments_15_16/ast.json +38 -0
  44. package/okf/msme_commercial/enterprise_classification_sec7/ast.json +25 -0
  45. package/okf/msme_commercial/lease_accounting_indas_116/ast.json +20 -0
  46. package/okf/msme_commercial/mca_msme_1_filing/ast.json +20 -0
  47. package/okf/msme_commercial/provisions_contingencies_indas_37/ast.json +20 -0
  48. package/okf/msme_commercial/revenue_recognition_indas_115/ast.json +20 -0
  49. package/okf/msme_commercial/statutory_disclosures_sec22/ast.json +21 -0
  50. package/package.json +16 -4
  51. package/src/calculators.js +139 -3
  52. package/src/constants.js +1 -1
  53. package/src/index.js +16 -2
  54. package/src/payroll.js +506 -0
  55. package/src/usvm/evaluation_vm.js +504 -0
  56. package/src/usvm/index.js +65 -0
  57. package/src/usvm/math_rational.js +165 -0
  58. package/src/usvm/rules/sec_115baa_115jb_mat.json +23 -0
  59. package/src/usvm/rules/sec_192_salary_tds.json +23 -0
  60. package/src/usvm/rules/sec_194a_interest.json +59 -0
  61. package/src/usvm/rules/sec_194c_contractors.json +71 -0
  62. package/src/usvm/rules/sec_194h_commission.json +60 -0
  63. package/src/usvm/rules/sec_194i_rent.json +60 -0
  64. package/src/usvm/rules/sec_194ia_property.json +70 -0
  65. package/src/usvm/rules/sec_194ib_rent_ind.json +59 -0
  66. package/src/usvm/rules/sec_194j_services.json +60 -0
  67. package/src/usvm/rules/sec_194m_contract_ind.json +59 -0
  68. package/src/usvm/rules/sec_194o_ecommerce.json +48 -0
  69. package/src/usvm/rules/sec_194q_goods.json +71 -0
  70. package/src/usvm/rules/sec_194r_perquisites.json +47 -0
  71. package/src/usvm/rules/sec_195_cross_border.json +39 -0
  72. package/src/usvm/rules/sec_206ab_non_filer.json +26 -0
  73. package/src/usvm/rules/sec_206c1h_tcs.json +69 -0
  74. package/src/usvm/rules/sec_281_tax_clearance.json +21 -0
  75. package/src/usvm/rules/sec_393_goods.json +59 -0
  76. package/src/usvm/rules/sec_43bh_disallowance.json +35 -0
  77. package/src/usvm/rules/sec_50b_slump_sale.json +21 -0
  78. package/src/usvm/rules/sec_79_loss_continuity.json +33 -0
  79. package/src/usvm/rules/sec_92c_transfer_pricing.json +25 -0
  80. package/src/usvm/rules/sec_ftc_dtaa_relief.json +20 -0
  81. package/src/usvm/rules/sec_gst_blocked_itc_17_5.json +26 -0
  82. package/src/usvm/rules/sec_gst_composite_mixed_8.json +21 -0
  83. package/src/usvm/rules/sec_gst_composition_levy_10.json +23 -0
  84. package/src/usvm/rules/sec_gst_credit_debit_notes_34.json +21 -0
  85. package/src/usvm/rules/sec_gst_einvoicing_rule48_4.json +20 -0
  86. package/src/usvm/rules/sec_gst_ewaybill_rule138.json +21 -0
  87. package/src/usvm/rules/sec_gst_export_lut_16.json +20 -0
  88. package/src/usvm/rules/sec_gst_itc_eligibility_16_2.json +20 -0
  89. package/src/usvm/rules/sec_gst_itc_reversal_rule37_37a.json +45 -0
  90. package/src/usvm/rules/sec_gst_rcm_liability_9_3.json +26 -0
  91. package/src/usvm/rules/sec_gst_rule42_43_apportionment.json +26 -0
  92. package/src/usvm/rules/sec_gst_tds_sec51.json +23 -0
  93. package/src/usvm/rules/sec_indas102_esop.json +20 -0
  94. package/src/usvm/rules/sec_indas103_mna.json +20 -0
  95. package/src/usvm/rules/sec_indas109_ecl.json +24 -0
  96. package/src/usvm/rules/sec_indas115_revenue.json +20 -0
  97. package/src/usvm/rules/sec_indas116_leases.json +20 -0
  98. package/src/usvm/rules/sec_indas12_deferred_tax.json +20 -0
  99. package/src/usvm/rules/sec_indas21_fx_reval.json +20 -0
  100. package/src/usvm/rules/sec_indas36_impairment.json +20 -0
  101. package/src/usvm/rules/sec_indas37_provisions.json +20 -0
  102. package/src/usvm/rules/sec_msme_classification_sec7.json +25 -0
  103. package/src/usvm/rules/sec_msme_delayed_payments_15_16.json +38 -0
  104. package/src/usvm/rules/sec_msme_disclosures_sec22.json +21 -0
  105. package/src/usvm/rules/sec_msme_mca_form_1.json +20 -0
  106. package/src/usvm/schemas/statutory_ast_schema.js +203 -0
  107. package/src/usvm/usvm_domain_evaluators.js +1021 -0
  108. package/types/index.d.ts +134 -0
  109. package/conformance/README.md +0 -54
  110. package/conformance/fixtures/invalid_malformed_temporal_dates.json +0 -10
  111. package/conformance/fixtures/invalid_missing_effective_period.json +0 -6
  112. package/conformance/fixtures/invalid_missing_section_code.json +0 -9
  113. package/conformance/fixtures/valid_circular_frontmatter.md +0 -16
  114. package/conformance/fixtures/valid_full_section.json +0 -35
  115. package/conformance/fixtures/valid_minimal_section.json +0 -11
  116. package/conformance/test_conformance.js +0 -129
  117. package/docs/ACCOUNTING_ASSURANCE_AUDIT_DOSSIER.md +0 -276
  118. package/docs/ADESHA_ASSURANCE_OVERVIEW.md +0 -166
  119. package/docs/ARCHITECTURE.md +0 -750
  120. package/docs/ARCHITECTURE_DECISIONS.md +0 -138
  121. package/docs/CASE_01_FORM_TEXT.txt +0 -48
  122. package/docs/CATALOG.md +0 -1901
  123. package/docs/CA_PILOT_BENCHMARK_CASES.md +0 -282
  124. package/docs/CORPUS_QUALITY.md +0 -106
  125. package/docs/DATA_LICENSING.md +0 -73
  126. package/docs/DOMAIN_BREADTH_AND_DEPTH_COMPARISON.md +0 -209
  127. package/docs/ENTERPRISE_GOVERNANCE.md +0 -159
  128. package/docs/OKF_MAINTENANCE_SOP.md +0 -286
  129. package/docs/PILOT_EVALUATION_GUIDE.md +0 -214
  130. package/docs/PROVENANCE.md +0 -33
  131. package/docs/VERIFICATION.md +0 -106
  132. package/examples/README.md +0 -56
  133. package/examples/invoice_deduction_trace.json +0 -149
  134. package/examples/simulate_end_to_end_trace.js +0 -106
@@ -0,0 +1,504 @@
1
+ /**
2
+ * ═══════════════════════════════════════════════════════════════════════════
3
+ * MUDRAFORGE UNIVERSAL STATUTORY VIRTUAL MACHINE (USVM) - EVALUATION KERNEL
4
+ * ═══════════════════════════════════════════════════════════════════════════
5
+ *
6
+ * Implements the stateless evaluation kernel for declarative statutory AST packages.
7
+ * Evaluates predicates, triggers, thresholds, rational math, and dual-Act regimes
8
+ * with sub-microsecond latency and zero external dependencies.
9
+ *
10
+ * Specification: RFC-009 (Revision 2.1)
11
+ */
12
+
13
+ import { validateStatutoryAst } from './schemas/statutory_ast_schema.js';
14
+ import {
15
+ toBigIntPaise,
16
+ fromBigIntPaise,
17
+ multiplyRational,
18
+ quantizeCurrencyPaisa,
19
+ roundStatutoryAssessment
20
+ } from './math_rational.js';
21
+ import {
22
+ evaluateMsmeDelayedPaymentCompoundInterest,
23
+ evaluateSection43bHFiscalBoundary,
24
+ evaluateMsmeEnterpriseClassification,
25
+ evaluateGstRule37ProportionalReversal,
26
+ evaluateGstRule37ASupplierNonFiling,
27
+ evaluateGstRule42CommonCreditApportionment,
28
+ evaluateCrossBorderDtaaMatrix,
29
+ evaluateTransferPricingPercentileAlp,
30
+ evaluateSection79VotingContinuity,
31
+ evaluateSection281VoidTransfer,
32
+ evaluateCorporateTaxMatVsConcessionalUsvm,
33
+ evaluateSalaryProgressiveTds,
34
+ evaluateNonFilerPenalRate206AB,
35
+ evaluateDeferredTaxIndAs12Usvm,
36
+ evaluateBlockedCreditSection17_5,
37
+ evaluateItcEligibilitySection16_2,
38
+ evaluateRcmLiabilitySection9_3,
39
+ evaluateCompositeMixedSuppliesSection8,
40
+ evaluateCompositionLevySection10,
41
+ evaluateCreditDebitNotesSection34,
42
+ evaluateExportLutSection16,
43
+ evaluateEInvoicingRule48_4,
44
+ evaluateEWayBillRule138,
45
+ evaluateGstTdsSection51,
46
+ evaluateMcaMsme1Aging,
47
+ evaluateMsmeDisclosuresSection22,
48
+ evaluateLeaseAmortizationIndAs116Usvm,
49
+ evaluateRevenueAllocationIndAs115Usvm,
50
+ evaluateProvisionsAndContingenciesIndAs37Usvm,
51
+ evaluateForeignExchangeRevaluationUsvm,
52
+ evaluateExpectedCreditLossIndAs109Usvm,
53
+ evaluateForeignTaxCreditRelief,
54
+ evaluateSlumpSaleSection50B,
55
+ evaluateBusinessCombinationsIndAs103Usvm,
56
+ evaluateImpairmentIndAs36Usvm,
57
+ evaluateShareBasedPaymentsIndAs102Usvm
58
+ } from './usvm_domain_evaluators.js';
59
+
60
+ /**
61
+ * Safely extracts a nested property using dot-separated notation.
62
+ */
63
+ function getNestedValue(obj, path) {
64
+ if (!obj || !path) return undefined;
65
+ const parts = String(path).split('.');
66
+ let curr = obj;
67
+ for (const part of parts) {
68
+ if (curr === null || curr === undefined) return undefined;
69
+ curr = curr[part];
70
+ }
71
+ return curr;
72
+ }
73
+
74
+ /**
75
+ * Evaluates a typed comparison operator against fact value and target value.
76
+ */
77
+ function evaluateOperator(factValue, operator, targetValue) {
78
+ switch (operator) {
79
+ case 'EQ':
80
+ return factValue === targetValue;
81
+ case 'NEQ':
82
+ return factValue !== targetValue;
83
+ case 'GT':
84
+ return factValue > targetValue;
85
+ case 'GTE':
86
+ return factValue >= targetValue;
87
+ case 'LT':
88
+ return factValue < targetValue;
89
+ case 'LTE':
90
+ return factValue <= targetValue;
91
+ case 'IN':
92
+ return Array.isArray(targetValue) && targetValue.includes(factValue);
93
+ case 'NOT_IN':
94
+ return Array.isArray(targetValue) && !targetValue.includes(factValue);
95
+ case 'IS_TRUE':
96
+ return Boolean(factValue) === true;
97
+ case 'IS_FALSE':
98
+ return Boolean(factValue) === false;
99
+ case 'EXISTS':
100
+ return factValue !== undefined && factValue !== null;
101
+ case 'NOT_EXISTS':
102
+ return factValue === undefined || factValue === null;
103
+ default:
104
+ return false;
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Resolves the statutory crystallization date and governing regime (1961 vs 2025 Act)
110
+ * based on the provision's trigger policy and transaction facts.
111
+ */
112
+ export function resolveTemporalCrystallization(triggerPolicy, facts, cutoverDate = '2026-04-01') {
113
+ const creditDate = facts.creditDate || facts.temporalFacts?.bookCreditDate || null;
114
+ const paymentDate = facts.paymentDate || facts.temporalFacts?.paymentDate || null;
115
+ const transactionDate = facts.transactionDate || facts.temporalFacts?.transactionDate || null;
116
+
117
+ let crystallizedDate = null;
118
+ let crystallizationEvent = 'UNDETERMINED';
119
+ let isStraddling = false;
120
+
121
+ const policyType = triggerPolicy?.type || 'EARLIER_OF';
122
+
123
+ if (policyType === 'EARLIER_OF') {
124
+ if (creditDate && paymentDate) {
125
+ if (creditDate <= paymentDate) {
126
+ crystallizedDate = creditDate;
127
+ crystallizationEvent = 'BOOK_CREDIT';
128
+ } else {
129
+ crystallizedDate = paymentDate;
130
+ crystallizationEvent = 'PAYMENT_DISBURSEMENT';
131
+ }
132
+
133
+ const creditIsPre = creditDate < cutoverDate;
134
+ const paymentIsPre = paymentDate < cutoverDate;
135
+ if (creditIsPre !== paymentIsPre) {
136
+ isStraddling = true;
137
+ }
138
+ } else if (creditDate) {
139
+ crystallizedDate = creditDate;
140
+ crystallizationEvent = 'BOOK_CREDIT';
141
+ } else if (paymentDate) {
142
+ crystallizedDate = paymentDate;
143
+ crystallizationEvent = 'PAYMENT_DISBURSEMENT';
144
+ } else if (transactionDate) {
145
+ crystallizedDate = transactionDate;
146
+ crystallizationEvent = 'TRANSACTION_DATE';
147
+ }
148
+ } else if (policyType === 'PAYMENT_ONLY') {
149
+ crystallizedDate = paymentDate || transactionDate || null;
150
+ crystallizationEvent = 'PAYMENT_DISBURSEMENT';
151
+ } else {
152
+ crystallizedDate = transactionDate || creditDate || paymentDate || null;
153
+ crystallizationEvent = 'TRANSACTION_DATE';
154
+ }
155
+
156
+ const hasDate = Boolean(crystallizedDate);
157
+ const isAct2025 = hasDate ? crystallizedDate >= cutoverDate : false;
158
+ const governingRegime = hasDate ? (isAct2025 ? 'ACT_2025' : 'ACT_1961') : 'INDETERMINATE_PENDING_TRANSACTION_DATE';
159
+
160
+ return {
161
+ crystallizedDate,
162
+ crystallizationEvent,
163
+ isAct2025,
164
+ governingRegime,
165
+ isStraddling,
166
+ creditDate,
167
+ paymentDate
168
+ };
169
+ }
170
+
171
+ /**
172
+ * Pure stateless evaluation kernel for the Universal Statutory Virtual Machine (USVM).
173
+ * Evaluates an approved declarative AST rule package against transaction facts.
174
+ *
175
+ * @param {Object} ruleAst - Validated declarative AST package
176
+ * @param {Object} facts - Ingress transaction facts
177
+ * @returns {Object} Fiduciary statutory evaluation voucher
178
+ */
179
+ export function evaluateStatutoryAst(ruleAst, facts = {}) {
180
+ // 1. Strict AST validation
181
+ validateStatutoryAst(ruleAst);
182
+
183
+ const trace = [];
184
+
185
+ // 2. Fiduciary base result initialization
186
+ const result = {
187
+ isAuthorizedToDisburse: false, // Fiduciary invariant: computation NEVER authorizes money movement
188
+ ruleId: ruleAst.sectionId,
189
+ ruleVersion: ruleAst.version,
190
+ disposition: 'EVALUATING',
191
+ isTdsApplicable: false,
192
+ isSectionApplicable: false,
193
+ invoiceAmountInr: 0,
194
+ taxableBase: 0,
195
+ tdsRatePercent: 0,
196
+ calculatedTdsInr: 0,
197
+ netWireInr: 0,
198
+ executionTrace: trace
199
+ };
200
+
201
+ // 3. Temporal Crystallization & Dual-Act Resolution
202
+ const cutoverDate = ruleAst.transitionalCutoverDate || '2026-04-01';
203
+ const temporal = resolveTemporalCrystallization(ruleAst.triggerPolicy, facts, cutoverDate);
204
+
205
+ result.isAct2025 = temporal.isAct2025;
206
+ result.effectiveDate = temporal.crystallizedDate;
207
+ result.regimeStatus = temporal.governingRegime === 'INDETERMINATE_PENDING_TRANSACTION_DATE' ? 'INDETERMINATE_PENDING_TRANSACTION_DATE' : 'DETERMINED';
208
+
209
+ if (temporal.isStraddling) {
210
+ result.temporalStraddlingAnalysis = {
211
+ crystallizedDate: temporal.crystallizedDate,
212
+ crystallizationEvent: temporal.crystallizationEvent,
213
+ governingRegime: temporal.governingRegime,
214
+ creditDate: temporal.creditDate,
215
+ paymentDate: temporal.paymentDate,
216
+ legalRule: 'Under Indian direct tax jurisprudence, tax deduction attaches at the earlier of credit or payment. Pre-1 April 2026 crystallization event cements Income-tax Act, 1961 regime.'
217
+ };
218
+ }
219
+
220
+ const governingSection = temporal.isAct2025
221
+ ? `${ruleAst.successorStatute || 'Income-tax Act, 2025'} ${ruleAst.successorSection || ''}`.trim()
222
+ : `${ruleAst.governingStatute || 'Income-tax Act, 1961'} ${ruleAst.statutorySection || ''}`.trim();
223
+
224
+ result.governingWithholdingSection = governingSection;
225
+ result.governingSection = governingSection;
226
+ result.governingStatute = temporal.governingRegime;
227
+
228
+ // 4. Evaluate Guards (Pre-conditions & Penalties)
229
+ let overrideRateBps = null;
230
+ let panPenaltySection = null;
231
+
232
+ if (Array.isArray(ruleAst.guards)) {
233
+ for (const guard of ruleAst.guards) {
234
+ // Check direct fact or nested path (supporting legacy and normalized facts)
235
+ let factValue = getNestedValue(facts, guard.field);
236
+ if (factValue === undefined && guard.field.startsWith('payee.')) {
237
+ // Support flat legacy keys (e.g. payee.isResident -> isResident or hasPan)
238
+ const flatKey = guard.field.replace('payee.', '');
239
+ if (flatKey === 'isPanValid' && facts.hasPan !== undefined) {
240
+ factValue = Boolean(facts.hasPan) && !Boolean(facts.isPanInoperative);
241
+ } else if (facts[flatKey] !== undefined) {
242
+ factValue = facts[flatKey];
243
+ }
244
+ }
245
+ if (factValue === undefined && guard.field === 'payee.isResident' && facts.sellerIsNonResident !== undefined) {
246
+ factValue = !Boolean(facts.sellerIsNonResident);
247
+ }
248
+
249
+ const isMatch = evaluateOperator(factValue, guard.operator, guard.value);
250
+
251
+ if (isMatch) {
252
+ trace.push(`Guard matched: ${guard.id}`);
253
+ const onMatch = guard.onMatch;
254
+
255
+ if (onMatch?.action === 'HALT_EXEMPT') {
256
+ const rawInvoice = Number(facts.invoiceAmount || facts.grossAmountInr || facts.lineItem?.grossAmountPaisa || 0);
257
+ result.disposition = onMatch.disposition || 'EXEMPT';
258
+ result.statutoryDisposition = onMatch.disposition || 'EXEMPT';
259
+ result.statutoryReason = onMatch.reason || 'Guard halted computation as exempt';
260
+ result.isExemptForeignImport = Boolean(facts.isImportOfGoods || facts.sellerIsNonResident);
261
+ result.invoiceAmountInr = rawInvoice;
262
+ result.netWireInr = rawInvoice;
263
+ result.governingSection = temporal.isAct2025
264
+ ? 'CBDT Circular No. 13 of 2021 Question 3 (Read with Section 393(2))'
265
+ : 'CBDT Circular No. 13 of 2021 Question 3 (Read with Section 195)';
266
+ return result;
267
+ }
268
+
269
+ if (onMatch?.action === 'OVERRIDE_RATE') {
270
+ overrideRateBps = onMatch.overrideRateBps;
271
+ panPenaltySection = temporal.isAct2025
272
+ ? onMatch.governingSection2025
273
+ : onMatch.governingSection1961;
274
+ trace.push(`Override applied: rate set to ${overrideRateBps} bps (${overrideRateBps / 100}%)`);
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ result.governingPanPenaltySection = panPenaltySection || (temporal.isAct2025 ? 'Section 397 (PAN compliant)' : 'Section 206AA (PAN compliant)');
281
+
282
+ const archetype = ruleAst.computation?.archetype || 'EXCESS_OVER_THRESHOLD';
283
+
284
+ // Advanced Domain Archetype Dispatches
285
+ if (archetype === 'COMPOUND_INTEREST_MONTHLY_RESTS') {
286
+ return evaluateMsmeDelayedPaymentCompoundInterest(ruleAst, facts, trace);
287
+ }
288
+ if (archetype === 'MSME_FISCAL_BOUNDARY_43BH') {
289
+ return evaluateSection43bHFiscalBoundary(ruleAst, facts, trace);
290
+ }
291
+ if (archetype === 'ENTERPRISE_CLASSIFICATION_MSME') {
292
+ return evaluateMsmeEnterpriseClassification(ruleAst, facts, trace);
293
+ }
294
+ if (archetype === 'PROPORTIONAL_REVERSAL_180_DAYS') {
295
+ return evaluateGstRule37ProportionalReversal(ruleAst, facts, trace);
296
+ }
297
+ if (archetype === 'SUPPLIER_NON_FILING_RULE37A') {
298
+ return evaluateGstRule37ASupplierNonFiling(ruleAst, facts, trace);
299
+ }
300
+ if (archetype === 'COMMON_CREDIT_APPORTIONMENT_RULE42') {
301
+ return evaluateGstRule42CommonCreditApportionment(ruleAst, facts, trace);
302
+ }
303
+ if (archetype === 'DTAA_TREATY_TAX_HAVEN_MATRIX') {
304
+ return evaluateCrossBorderDtaaMatrix(ruleAst, facts, temporal, trace);
305
+ }
306
+ if (archetype === 'TRANSFER_PRICING_PERCENTILE_ALP') {
307
+ return evaluateTransferPricingPercentileAlp(ruleAst, facts, trace);
308
+ }
309
+ if (archetype === 'VOTING_CONTINUITY_PERCENTAGE') {
310
+ return evaluateSection79VotingContinuity(ruleAst, facts, trace);
311
+ }
312
+ if (archetype === 'TAX_CLEARANCE_VOID_TRANSFER_SEC281') {
313
+ return evaluateSection281VoidTransfer(ruleAst, facts, trace);
314
+ }
315
+ if (archetype === 'CORPORATE_TAX_MAT_VS_CONCESSIONAL') {
316
+ return evaluateCorporateTaxMatVsConcessionalUsvm(ruleAst, facts, trace);
317
+ }
318
+ if (archetype === 'SALARY_SLAB_PROGRESSIVE_TDS') {
319
+ return evaluateSalaryProgressiveTds(ruleAst, facts, trace);
320
+ }
321
+ if (archetype === 'NON_FILER_PENAL_RATE_206AB') {
322
+ return evaluateNonFilerPenalRate206AB(ruleAst, facts, trace);
323
+ }
324
+ if (archetype === 'DEFERRED_TAX_TIMING_DIFFERENCE') {
325
+ return evaluateDeferredTaxIndAs12Usvm(ruleAst, facts, trace);
326
+ }
327
+ if (archetype === 'BLOCKED_CREDIT_GATE_17_5') {
328
+ return evaluateBlockedCreditSection17_5(ruleAst, facts, trace);
329
+ }
330
+ if (archetype === 'ITC_ELIGIBILITY_GATE_16_2') {
331
+ return evaluateItcEligibilitySection16_2(ruleAst, facts, trace);
332
+ }
333
+ if (archetype === 'RCM_LIABILITY_EVALUATION_9_3') {
334
+ return evaluateRcmLiabilitySection9_3(ruleAst, facts, trace);
335
+ }
336
+ if (archetype === 'COMPOSITE_MIXED_SUPPLY_SEC8') {
337
+ return evaluateCompositeMixedSuppliesSection8(ruleAst, facts, trace);
338
+ }
339
+ if (archetype === 'COMPOSITION_LEVY_SEC10') {
340
+ return evaluateCompositionLevySection10(ruleAst, facts, trace);
341
+ }
342
+ if (archetype === 'CREDIT_NOTE_TIMELINES_SEC34') {
343
+ return evaluateCreditDebitNotesSection34(ruleAst, facts, trace);
344
+ }
345
+ if (archetype === 'EXPORT_LUT_ZERO_RATED_SEC16') {
346
+ return evaluateExportLutSection16(ruleAst, facts, trace);
347
+ }
348
+ if (archetype === 'EINVOICING_MANDATE_RULE48_4') {
349
+ return evaluateEInvoicingRule48_4(ruleAst, facts, trace);
350
+ }
351
+ if (archetype === 'EWAYBILL_CONSIGNMENT_RULE138') {
352
+ return evaluateEWayBillRule138(ruleAst, facts, trace);
353
+ }
354
+ if (archetype === 'GST_TDS_DEDUCTION_SEC51') {
355
+ return evaluateGstTdsSection51(ruleAst, facts, trace);
356
+ }
357
+ if (archetype === 'MCA_MSME_1_AGING_BIFURCATION') {
358
+ return evaluateMcaMsme1Aging(ruleAst, facts, trace);
359
+ }
360
+ if (archetype === 'MSME_DISCLOSURES_SEC22') {
361
+ return evaluateMsmeDisclosuresSection22(ruleAst, facts, trace);
362
+ }
363
+ if (archetype === 'LEASE_AMORTIZATION_INDAS116') {
364
+ return evaluateLeaseAmortizationIndAs116Usvm(ruleAst, facts, trace);
365
+ }
366
+ if (archetype === 'REVENUE_ALLOCATION_INDAS115') {
367
+ return evaluateRevenueAllocationIndAs115Usvm(ruleAst, facts, trace);
368
+ }
369
+ if (archetype === 'PROVISIONS_CONTINGENCY_INDAS37') {
370
+ return evaluateProvisionsAndContingenciesIndAs37Usvm(ruleAst, facts, trace);
371
+ }
372
+ if (archetype === 'FX_SPOT_REVALUATION_INDAS21_109') {
373
+ return evaluateForeignExchangeRevaluationUsvm(ruleAst, facts, trace);
374
+ }
375
+ if (archetype === 'EXPECTED_CREDIT_LOSS_INDAS109') {
376
+ return evaluateExpectedCreditLossIndAs109Usvm(ruleAst, facts, trace);
377
+ }
378
+ if (archetype === 'FOREIGN_TAX_CREDIT_RELIEF') {
379
+ return evaluateForeignTaxCreditRelief(ruleAst, facts, trace);
380
+ }
381
+ if (archetype === 'SLUMP_SALE_NET_WORTH_50B') {
382
+ return evaluateSlumpSaleSection50B(ruleAst, facts, trace);
383
+ }
384
+ if (archetype === 'BUSINESS_COMBINATIONS_INDAS103') {
385
+ return evaluateBusinessCombinationsIndAs103Usvm(ruleAst, facts, trace);
386
+ }
387
+ if (archetype === 'IMPAIRMENT_TESTING_INDAS36') {
388
+ return evaluateImpairmentIndAs36Usvm(ruleAst, facts, trace);
389
+ }
390
+ if (archetype === 'SHARE_BASED_PAYMENTS_INDAS102') {
391
+ return evaluateShareBasedPaymentsIndAs102Usvm(ruleAst, facts, trace);
392
+ }
393
+
394
+ // 5. Ingress Invoice Consideration Quantization
395
+ let currentInvoicePaise = 0n;
396
+ let rawInvoiceInr = 0;
397
+
398
+ if (facts.lineItem?.grossAmountPaisa !== undefined) {
399
+ currentInvoicePaise = BigInt(facts.lineItem.grossAmountPaisa);
400
+ rawInvoiceInr = fromBigIntPaise(currentInvoicePaise);
401
+ } else {
402
+ rawInvoiceInr = Number(facts.invoiceAmount ?? facts.grossAmountInr ?? 0);
403
+ const gstAmountInr = Number(facts.gstAmountInr || 0);
404
+ const isAdvancePayment = Boolean(facts.isAdvancePayment);
405
+ const creditNoteInr = Number(facts.creditNoteInr || 0);
406
+ const creditNoteTiming = facts.creditNoteTiming || 'BEFORE_TAX_DEDUCTION';
407
+
408
+ // CBDT Circular No. 13 of 2021 Question 1: GST excluded when separately indicated & not advance
409
+ const effectivePurchaseInr = isAdvancePayment
410
+ ? rawInvoiceInr
411
+ : Math.max(0, rawInvoiceInr - gstAmountInr);
412
+
413
+ // CBDT Circular No. 13 of 2021 Question 4: Credit Note treatment
414
+ const isCreditNoteBefore = creditNoteTiming !== 'AFTER_TAX_DEDUCTION';
415
+ const amountInr = isCreditNoteBefore
416
+ ? Math.max(0, effectivePurchaseInr - creditNoteInr)
417
+ : effectivePurchaseInr;
418
+
419
+ currentInvoicePaise = toBigIntPaise(amountInr);
420
+ }
421
+
422
+ // 6. Cumulative Threshold Consideration Evaluation
423
+ let priorPurchasesPaise = 0n;
424
+ if (facts.aggregateSnapshot?.aggregatePaisa !== undefined) {
425
+ priorPurchasesPaise = BigInt(facts.aggregateSnapshot.aggregatePaisa);
426
+ } else {
427
+ const priorPurchasesInr = Number(
428
+ facts.priorPurchasesInCurrentFyInr ??
429
+ facts.currentFyPriorPurchasesInr ??
430
+ facts.priorFyPurchases ??
431
+ 0
432
+ );
433
+ priorPurchasesPaise = toBigIntPaise(priorPurchasesInr);
434
+ }
435
+
436
+ const thresholdPaise = ruleAst.computation?.thresholdPaisa !== undefined
437
+ ? BigInt(ruleAst.computation.thresholdPaisa)
438
+ : 500000000n; // Default ₹50L = 500,000,000 paise
439
+
440
+ const cumulativeBeforePaise = priorPurchasesPaise;
441
+ const cumulativeAfterPaise = priorPurchasesPaise + currentInvoicePaise;
442
+
443
+ let taxableBasePaise = 0n;
444
+ let isThresholdBreached = false;
445
+
446
+ if (archetype === 'EXCESS_OVER_THRESHOLD') {
447
+ if (cumulativeAfterPaise <= thresholdPaise) {
448
+ taxableBasePaise = 0n;
449
+ isThresholdBreached = false;
450
+ } else if (cumulativeBeforePaise >= thresholdPaise) {
451
+ // Threshold was already fully breached by prior purchases; entire current invoice is in excess
452
+ taxableBasePaise = currentInvoicePaise;
453
+ isThresholdBreached = true;
454
+ } else {
455
+ // Breaches threshold during this specific invoice: tax strictly on the incremental excess
456
+ taxableBasePaise = cumulativeAfterPaise - thresholdPaise;
457
+ isThresholdBreached = true;
458
+ }
459
+ } else if (archetype === 'CLIFF_THRESHOLD') {
460
+ if (cumulativeAfterPaise > thresholdPaise) {
461
+ taxableBasePaise = currentInvoicePaise;
462
+ isThresholdBreached = true;
463
+ }
464
+ } else if (archetype === 'FLAT_RATE') {
465
+ taxableBasePaise = currentInvoicePaise;
466
+ isThresholdBreached = true;
467
+ }
468
+
469
+ // 7. Rate Resolution & 5-Stage Rational Arithmetic
470
+ const standardRateBps = ruleAst.computation?.standardRateBps ?? 10; // Default 10 bps (0.1%)
471
+ const effectiveRateBps = overrideRateBps !== null ? overrideRateBps : standardRateBps;
472
+
473
+ let lineItemTdsPaise = 0n;
474
+
475
+ if (taxableBasePaise > 0n && effectiveRateBps > 0) {
476
+ // Stage 1 & 2: Exact Rational Multiplication & Remainder Extraction
477
+ const { quotientPaise, subPaisaRemainder } = multiplyRational(taxableBasePaise, effectiveRateBps, 10000n);
478
+
479
+ // Stage 3: Currency Quantization (Commercial Paisa Rounding)
480
+ lineItemTdsPaise = quantizeCurrencyPaisa(quotientPaise, subPaisaRemainder, 10000n);
481
+ }
482
+
483
+ // Stage 4: Statutory Assessment Rounding (Section 288B / 516)
484
+ const assessmentRoundingPolicy = temporal.isAct2025 ? 'INCOME_TAX_ACT_2025_SEC516' : 'INCOME_TAX_ACT_1961_SEC288B';
485
+ const assessmentTdsPaise = roundStatutoryAssessment(lineItemTdsPaise, assessmentRoundingPolicy);
486
+
487
+ // 8. Final Fiduciary Return Formulation
488
+ const taxableBaseInr = fromBigIntPaise(taxableBasePaise);
489
+ const calculatedTdsInr = fromBigIntPaise(lineItemTdsPaise);
490
+ const netWireInr = Math.max(0, rawInvoiceInr - calculatedTdsInr);
491
+
492
+ result.invoiceAmountInr = rawInvoiceInr;
493
+ result.taxableBase = taxableBaseInr;
494
+ result.tdsRatePercent = effectiveRateBps / 100;
495
+ result.calculatedTdsInr = calculatedTdsInr;
496
+ result.assessmentRoundedTdsInr = fromBigIntPaise(assessmentTdsPaise);
497
+ result.netWireInr = netWireInr;
498
+ result.isTdsApplicable = calculatedTdsInr > 0;
499
+ result.isSection194QApplicable = isThresholdBreached;
500
+ result.disposition = isThresholdBreached ? 'TAX_DEDUCTIBLE' : 'THRESHOLD_NOT_BREACHED';
501
+ result.statutoryDisposition = isThresholdBreached ? 'SECTION_194Q_DEDUCTION_MANDATORY' : 'EXEMPT_BELOW_STATUTORY_THRESHOLD';
502
+
503
+ return result;
504
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * MUDRAFORGE UNIVERSAL STATUTORY VIRTUAL MACHINE (USVM)
3
+ * Zero-dependency declarative calculation runtime for statutory tax & accounting.
4
+ */
5
+
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ export {
11
+ evaluateStatutoryAst,
12
+ resolveTemporalCrystallization
13
+ } from './evaluation_vm.js';
14
+
15
+ export {
16
+ validateStatutoryAst,
17
+ StatutoryAstValidationError,
18
+ MATH_ARCHETYPES,
19
+ TRIGGER_POLICIES,
20
+ ROUNDING_POLICIES,
21
+ TYPED_OPERATORS
22
+ } from './schemas/statutory_ast_schema.js';
23
+
24
+ export {
25
+ toBigIntPaise,
26
+ fromBigIntPaise,
27
+ multiplyRational,
28
+ quantizeCurrencyPaisa,
29
+ roundStatutoryAssessment
30
+ } from './math_rational.js';
31
+
32
+ const __filename = fileURLToPath(import.meta.url);
33
+ const __dirname = path.dirname(__filename);
34
+
35
+ const RULE_MAP = new Map();
36
+
37
+ /**
38
+ * Loads and caches an AST rule by section key.
39
+ */
40
+ export function getStatutoryAst(sectionKey) {
41
+ const key = String(sectionKey || '').toUpperCase().trim();
42
+ if (RULE_MAP.has(key)) return RULE_MAP.get(key);
43
+
44
+ const rulesDir = path.resolve(__dirname, 'rules');
45
+ if (!fs.existsSync(rulesDir)) return null;
46
+
47
+ // Search rules dir for matching sectionId or filename
48
+ const files = fs.readdirSync(rulesDir).filter(f => f.endsWith('.json'));
49
+ for (const f of files) {
50
+ try {
51
+ const raw = fs.readFileSync(path.join(rulesDir, f), 'utf8');
52
+ const ast = JSON.parse(raw);
53
+ if (
54
+ ast.sectionId?.toUpperCase() === key ||
55
+ ast.statutorySection?.toUpperCase().includes(key) ||
56
+ f.toUpperCase().includes(key.replace(/[^A-Z0-9]/g, '_'))
57
+ ) {
58
+ RULE_MAP.set(key, ast);
59
+ return ast;
60
+ }
61
+ } catch (_) {}
62
+ }
63
+
64
+ return null;
65
+ }