@mudraforge/statutory 2.12.1 → 2.13.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.
- package/CHANGELOG.md +17 -0
- package/README.md +13 -0
- package/docs/ARCHITECTURE.md +70 -47
- package/docs/ARCHITECTURE_DECISIONS.md +22 -2
- package/docs/CORPUS_QUALITY.md +3 -3
- package/docs/DOMAIN_BREADTH_AND_DEPTH_COMPARISON.md +4 -4
- package/docs/ENTERPRISE_GOVERNANCE.md +2 -1
- package/docs/OKF_MAINTENANCE_SOP.md +5 -5
- package/docs/PILOT_EVALUATION_GUIDE.md +5 -4
- package/docs/PROVENANCE.md +6 -6
- package/docs/VERIFICATION.md +6 -6
- package/okf/corporate_ma_restructuring/business_combinations_indas_103/ast.json +20 -0
- package/okf/corporate_ma_restructuring/impairment_of_assets_indas_36/ast.json +20 -0
- package/okf/corporate_ma_restructuring/loss_carryforward_sec79/ast.json +33 -0
- package/okf/corporate_ma_restructuring/share_based_payments_indas_102/ast.json +20 -0
- package/okf/corporate_ma_restructuring/slump_sale_50b/ast.json +21 -0
- package/okf/corporate_ma_restructuring/tax_clearance_sec281/ast.json +21 -0
- package/okf/direct_tax/corporate_tax_115baa_115jb/ast.json +23 -0
- package/okf/direct_tax/income_taxes_deferred_tax_indas_12/ast.json +20 -0
- package/okf/direct_tax/special_rates_non_filer_206ab/ast.json +26 -0
- package/okf/direct_tax/statutory_disallowance_43b/ast.json +35 -0
- package/okf/direct_tax/tcs_goods_206c_1h/ast.json +69 -0
- package/okf/direct_tax/tds_commission_194h/ast.json +60 -0
- package/okf/direct_tax/tds_contractor_194c/ast.json +71 -0
- package/okf/direct_tax/tds_ecommerce_194o/ast.json +48 -0
- package/okf/direct_tax/tds_goods_194q/ast.json +71 -0
- package/okf/direct_tax/tds_goods_393/ast.json +59 -0
- package/okf/direct_tax/tds_individual_contract_194m/ast.json +59 -0
- package/okf/direct_tax/tds_interest_194a/ast.json +59 -0
- package/okf/direct_tax/tds_perquisites_194r/ast.json +47 -0
- package/okf/direct_tax/tds_property_194ia/ast.json +70 -0
- package/okf/direct_tax/tds_rent_194i/ast.json +60 -0
- package/okf/direct_tax/tds_rent_individual_194ib/ast.json +59 -0
- package/okf/direct_tax/tds_services_194j/ast.json +60 -0
- package/okf/indirect_tax_gst/blocked_itc_17_5/ast.json +26 -0
- package/okf/indirect_tax_gst/common_itc_reversal_rule42_43/ast.json +26 -0
- package/okf/indirect_tax_gst/composite_mixed_supplies_sec8/ast.json +21 -0
- package/okf/indirect_tax_gst/composition_levy_sec10/ast.json +23 -0
- package/okf/indirect_tax_gst/credit_debit_notes_sec34/ast.json +21 -0
- package/okf/indirect_tax_gst/e_invoicing_rule48_4/ast.json +20 -0
- package/okf/indirect_tax_gst/export_services_lut_sec16/ast.json +20 -0
- package/okf/indirect_tax_gst/gst_tds_sec51/ast.json +23 -0
- package/okf/indirect_tax_gst/itc_eligibility_16_2/ast.json +20 -0
- package/okf/indirect_tax_gst/itc_reversal_rule37_37a/ast.json +45 -0
- package/okf/indirect_tax_gst/rcm_liability_sec9_3/ast.json +26 -0
- package/okf/international_tax/cross_border_remittance_195/ast.json +39 -0
- package/okf/international_tax/financial_instruments_ecl_indas_109/ast.json +24 -0
- package/okf/international_tax/foreign_exchange_indas_21_109/ast.json +20 -0
- package/okf/international_tax/foreign_tax_credit_irc_901_904/ast.json +20 -0
- package/okf/international_tax/transfer_pricing_alp_92c/ast.json +25 -0
- package/okf/manifest.json +49 -3
- package/okf/msme_commercial/delayed_payments_15_16/ast.json +38 -0
- package/okf/msme_commercial/enterprise_classification_sec7/ast.json +25 -0
- package/okf/msme_commercial/lease_accounting_indas_116/ast.json +20 -0
- package/okf/msme_commercial/mca_msme_1_filing/ast.json +20 -0
- package/okf/msme_commercial/provisions_contingencies_indas_37/ast.json +20 -0
- package/okf/msme_commercial/revenue_recognition_indas_115/ast.json +20 -0
- package/okf/msme_commercial/statutory_disclosures_sec22/ast.json +21 -0
- package/package.json +16 -1
- package/src/constants.js +1 -1
- package/src/index.js +16 -2
- package/src/payroll.js +506 -0
- package/src/usvm/evaluation_vm.js +504 -0
- package/src/usvm/index.js +65 -0
- package/src/usvm/math_rational.js +165 -0
- package/src/usvm/rules/sec_115baa_115jb_mat.json +23 -0
- package/src/usvm/rules/sec_192_salary_tds.json +23 -0
- package/src/usvm/rules/sec_194a_interest.json +59 -0
- package/src/usvm/rules/sec_194c_contractors.json +71 -0
- package/src/usvm/rules/sec_194h_commission.json +60 -0
- package/src/usvm/rules/sec_194i_rent.json +60 -0
- package/src/usvm/rules/sec_194ia_property.json +70 -0
- package/src/usvm/rules/sec_194ib_rent_ind.json +59 -0
- package/src/usvm/rules/sec_194j_services.json +60 -0
- package/src/usvm/rules/sec_194m_contract_ind.json +59 -0
- package/src/usvm/rules/sec_194o_ecommerce.json +48 -0
- package/src/usvm/rules/sec_194q_goods.json +71 -0
- package/src/usvm/rules/sec_194r_perquisites.json +47 -0
- package/src/usvm/rules/sec_195_cross_border.json +39 -0
- package/src/usvm/rules/sec_206ab_non_filer.json +26 -0
- package/src/usvm/rules/sec_206c1h_tcs.json +69 -0
- package/src/usvm/rules/sec_281_tax_clearance.json +21 -0
- package/src/usvm/rules/sec_393_goods.json +59 -0
- package/src/usvm/rules/sec_43bh_disallowance.json +35 -0
- package/src/usvm/rules/sec_50b_slump_sale.json +21 -0
- package/src/usvm/rules/sec_79_loss_continuity.json +33 -0
- package/src/usvm/rules/sec_92c_transfer_pricing.json +25 -0
- package/src/usvm/rules/sec_ftc_dtaa_relief.json +20 -0
- package/src/usvm/rules/sec_gst_blocked_itc_17_5.json +26 -0
- package/src/usvm/rules/sec_gst_composite_mixed_8.json +21 -0
- package/src/usvm/rules/sec_gst_composition_levy_10.json +23 -0
- package/src/usvm/rules/sec_gst_credit_debit_notes_34.json +21 -0
- package/src/usvm/rules/sec_gst_einvoicing_rule48_4.json +20 -0
- package/src/usvm/rules/sec_gst_ewaybill_rule138.json +21 -0
- package/src/usvm/rules/sec_gst_export_lut_16.json +20 -0
- package/src/usvm/rules/sec_gst_itc_eligibility_16_2.json +20 -0
- package/src/usvm/rules/sec_gst_itc_reversal_rule37_37a.json +45 -0
- package/src/usvm/rules/sec_gst_rcm_liability_9_3.json +26 -0
- package/src/usvm/rules/sec_gst_rule42_43_apportionment.json +26 -0
- package/src/usvm/rules/sec_gst_tds_sec51.json +23 -0
- package/src/usvm/rules/sec_indas102_esop.json +20 -0
- package/src/usvm/rules/sec_indas103_mna.json +20 -0
- package/src/usvm/rules/sec_indas109_ecl.json +24 -0
- package/src/usvm/rules/sec_indas115_revenue.json +20 -0
- package/src/usvm/rules/sec_indas116_leases.json +20 -0
- package/src/usvm/rules/sec_indas12_deferred_tax.json +20 -0
- package/src/usvm/rules/sec_indas21_fx_reval.json +20 -0
- package/src/usvm/rules/sec_indas36_impairment.json +20 -0
- package/src/usvm/rules/sec_indas37_provisions.json +20 -0
- package/src/usvm/rules/sec_msme_classification_sec7.json +25 -0
- package/src/usvm/rules/sec_msme_delayed_payments_15_16.json +38 -0
- package/src/usvm/rules/sec_msme_disclosures_sec22.json +21 -0
- package/src/usvm/rules/sec_msme_mca_form_1.json +20 -0
- package/src/usvm/schemas/statutory_ast_schema.js +203 -0
- package/src/usvm/usvm_domain_evaluators.js +1021 -0
- package/types/index.d.ts +39 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
3
|
+
* MUDRAFORGE UNIVERSAL STATUTORY VIRTUAL MACHINE (USVM) - AST SCHEMA VALIDATOR
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
5
|
+
*
|
|
6
|
+
* Implements strict, typed schema validation and operator allowlists for
|
|
7
|
+
* declarative statutory AST packages. Rejects dynamic code execution, unknown
|
|
8
|
+
* operators, and unconstrained arithmetic.
|
|
9
|
+
*
|
|
10
|
+
* Specification: RFC-009 (Revision 2.1)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const SUPPORTED_NODE_TYPES = Object.freeze([
|
|
14
|
+
'PREDICATE',
|
|
15
|
+
'TEMPORAL_VALIDITY',
|
|
16
|
+
'SNAPSHOT_VERIFY',
|
|
17
|
+
'THRESHOLD_TEST',
|
|
18
|
+
'DELTA',
|
|
19
|
+
'SELECT',
|
|
20
|
+
'OVERRIDE',
|
|
21
|
+
'PRECEDENCE',
|
|
22
|
+
'ARITHMETIC',
|
|
23
|
+
'QUANTIZATION',
|
|
24
|
+
'ASSESSMENT_ROUND'
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
export const TYPED_OPERATORS = Object.freeze([
|
|
28
|
+
'EQ',
|
|
29
|
+
'NEQ',
|
|
30
|
+
'IN',
|
|
31
|
+
'NOT_IN',
|
|
32
|
+
'GT',
|
|
33
|
+
'GTE',
|
|
34
|
+
'LT',
|
|
35
|
+
'LTE',
|
|
36
|
+
'IS_TRUE',
|
|
37
|
+
'IS_FALSE',
|
|
38
|
+
'EXISTS',
|
|
39
|
+
'NOT_EXISTS'
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
export const TRIGGER_POLICIES = Object.freeze([
|
|
43
|
+
'EARLIER_OF',
|
|
44
|
+
'PAYMENT_ONLY',
|
|
45
|
+
'DEBIT_OR_RECEIPT',
|
|
46
|
+
'TRANSACTION_DATE',
|
|
47
|
+
'INVOICE_DATE',
|
|
48
|
+
'DUE_DATE',
|
|
49
|
+
'FISCAL_YEAR_END'
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
export const MATH_ARCHETYPES = Object.freeze([
|
|
53
|
+
'EXCESS_OVER_THRESHOLD',
|
|
54
|
+
'CLIFF_THRESHOLD',
|
|
55
|
+
'FLAT_RATE',
|
|
56
|
+
'PROGRESSIVE_SLAB',
|
|
57
|
+
'GROSS_UP_FACTOR',
|
|
58
|
+
'COMPOUND_INTEREST_MONTHLY_RESTS',
|
|
59
|
+
'MSME_FISCAL_BOUNDARY_43BH',
|
|
60
|
+
'ENTERPRISE_CLASSIFICATION_MSME',
|
|
61
|
+
'PROPORTIONAL_REVERSAL_180_DAYS',
|
|
62
|
+
'SUPPLIER_NON_FILING_RULE37A',
|
|
63
|
+
'COMMON_CREDIT_APPORTIONMENT_RULE42',
|
|
64
|
+
'CAPITAL_GOODS_60_MONTH_RULE43',
|
|
65
|
+
'DTAA_TREATY_TAX_HAVEN_MATRIX',
|
|
66
|
+
'TRANSFER_PRICING_PERCENTILE_ALP',
|
|
67
|
+
'VOTING_CONTINUITY_PERCENTAGE',
|
|
68
|
+
'TAX_CLEARANCE_VOID_TRANSFER_SEC281',
|
|
69
|
+
'CORPORATE_TAX_MAT_VS_CONCESSIONAL',
|
|
70
|
+
'SALARY_SLAB_PROGRESSIVE_TDS',
|
|
71
|
+
'NON_FILER_PENAL_RATE_206AB',
|
|
72
|
+
'DEFERRED_TAX_TIMING_DIFFERENCE',
|
|
73
|
+
'BLOCKED_CREDIT_GATE_17_5',
|
|
74
|
+
'ITC_ELIGIBILITY_GATE_16_2',
|
|
75
|
+
'RCM_LIABILITY_EVALUATION_9_3',
|
|
76
|
+
'COMPOSITE_MIXED_SUPPLY_SEC8',
|
|
77
|
+
'COMPOSITION_LEVY_SEC10',
|
|
78
|
+
'CREDIT_NOTE_TIMELINES_SEC34',
|
|
79
|
+
'EXPORT_LUT_ZERO_RATED_SEC16',
|
|
80
|
+
'EINVOICING_MANDATE_RULE48_4',
|
|
81
|
+
'EWAYBILL_CONSIGNMENT_RULE138',
|
|
82
|
+
'GST_TDS_DEDUCTION_SEC51',
|
|
83
|
+
'MCA_MSME_1_AGING_BIFURCATION',
|
|
84
|
+
'MSME_DISCLOSURES_SEC22',
|
|
85
|
+
'LEASE_AMORTIZATION_INDAS116',
|
|
86
|
+
'REVENUE_ALLOCATION_INDAS115',
|
|
87
|
+
'PROVISIONS_CONTINGENCY_INDAS37',
|
|
88
|
+
'FX_SPOT_REVALUATION_INDAS21_109',
|
|
89
|
+
'EXPECTED_CREDIT_LOSS_INDAS109',
|
|
90
|
+
'FOREIGN_TAX_CREDIT_RELIEF',
|
|
91
|
+
'SLUMP_SALE_NET_WORTH_50B',
|
|
92
|
+
'BUSINESS_COMBINATIONS_INDAS103',
|
|
93
|
+
'IMPAIRMENT_TESTING_INDAS36',
|
|
94
|
+
'SHARE_BASED_PAYMENTS_INDAS102'
|
|
95
|
+
]);
|
|
96
|
+
|
|
97
|
+
export const ROUNDING_POLICIES = Object.freeze([
|
|
98
|
+
'COMMERCIAL_PAISA',
|
|
99
|
+
'INCOME_TAX_ACT_1961_SEC288B',
|
|
100
|
+
'INCOME_TAX_ACT_2025_SEC516',
|
|
101
|
+
'NONE'
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
export class StatutoryAstValidationError extends Error {
|
|
105
|
+
constructor(message, details = {}) {
|
|
106
|
+
super(`[USVM_AST_VALIDATION_ERROR] ${message}`);
|
|
107
|
+
this.name = 'StatutoryAstValidationError';
|
|
108
|
+
this.details = details;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Validates a declarative statutory AST rule package against RFC-009 Revision 2.1 contracts.
|
|
114
|
+
* Throws StatutoryAstValidationError if any contract is violated.
|
|
115
|
+
*/
|
|
116
|
+
export function validateStatutoryAst(ruleAst) {
|
|
117
|
+
if (!ruleAst || typeof ruleAst !== 'object') {
|
|
118
|
+
throw new StatutoryAstValidationError('Rule AST must be a non-null object', { ruleAst });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 1. Mandatory Identity Fields
|
|
122
|
+
if (!ruleAst.sectionId || typeof ruleAst.sectionId !== 'string') {
|
|
123
|
+
throw new StatutoryAstValidationError('Rule AST must contain a valid string sectionId', { ruleAst });
|
|
124
|
+
}
|
|
125
|
+
if (!ruleAst.version || typeof ruleAst.version !== 'string') {
|
|
126
|
+
throw new StatutoryAstValidationError('Rule AST must contain a valid string version', { sectionId: ruleAst.sectionId });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 2. Trigger Policy Validation
|
|
130
|
+
if (ruleAst.triggerPolicy) {
|
|
131
|
+
if (!TRIGGER_POLICIES.includes(ruleAst.triggerPolicy.type)) {
|
|
132
|
+
throw new StatutoryAstValidationError(
|
|
133
|
+
`Unsupported triggerPolicy type: '${ruleAst.triggerPolicy.type}'. Must be one of: ${TRIGGER_POLICIES.join(', ')}`,
|
|
134
|
+
{ triggerPolicy: ruleAst.triggerPolicy }
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (ruleAst.triggerPolicy.type === 'EARLIER_OF' && (!Array.isArray(ruleAst.triggerPolicy.events) || ruleAst.triggerPolicy.events.length < 2)) {
|
|
138
|
+
throw new StatutoryAstValidationError(
|
|
139
|
+
"Trigger policy 'EARLIER_OF' requires at least 2 events to compare",
|
|
140
|
+
{ triggerPolicy: ruleAst.triggerPolicy }
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 3. Guards Allowlist Validation
|
|
146
|
+
if (ruleAst.guards) {
|
|
147
|
+
if (!Array.isArray(ruleAst.guards)) {
|
|
148
|
+
throw new StatutoryAstValidationError('guards must be an array', { guards: ruleAst.guards });
|
|
149
|
+
}
|
|
150
|
+
for (const guard of ruleAst.guards) {
|
|
151
|
+
if (!guard.field || typeof guard.field !== 'string') {
|
|
152
|
+
throw new StatutoryAstValidationError('Guard must define a string field path', { guard });
|
|
153
|
+
}
|
|
154
|
+
if (!TYPED_OPERATORS.includes(guard.operator)) {
|
|
155
|
+
throw new StatutoryAstValidationError(
|
|
156
|
+
`Operator '${guard.operator}' in guard '${guard.id || guard.field}' not in typed allowlist: ${TYPED_OPERATORS.join(', ')}`,
|
|
157
|
+
{ guard }
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 4. Threshold & Math Archetype Validation
|
|
164
|
+
if (ruleAst.computation) {
|
|
165
|
+
const comp = ruleAst.computation;
|
|
166
|
+
if (comp.archetype && !MATH_ARCHETYPES.includes(comp.archetype)) {
|
|
167
|
+
throw new StatutoryAstValidationError(
|
|
168
|
+
`Unsupported math archetype '${comp.archetype}'. Must be one of: ${MATH_ARCHETYPES.join(', ')}`,
|
|
169
|
+
{ computation: comp }
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
if (comp.thresholdPaisa !== undefined && typeof comp.thresholdPaisa !== 'string' && typeof comp.thresholdPaisa !== 'number') {
|
|
173
|
+
throw new StatutoryAstValidationError(
|
|
174
|
+
'thresholdPaisa must be a valid decimal string or number',
|
|
175
|
+
{ thresholdPaisa: comp.thresholdPaisa }
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
if (comp.standardRateBps !== undefined && (typeof comp.standardRateBps !== 'number' || comp.standardRateBps < 0)) {
|
|
179
|
+
throw new StatutoryAstValidationError(
|
|
180
|
+
'standardRateBps must be a non-negative number',
|
|
181
|
+
{ standardRateBps: comp.standardRateBps }
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 5. Rounding Policy Validation
|
|
187
|
+
if (ruleAst.rounding) {
|
|
188
|
+
if (ruleAst.rounding.transactionLine && !ROUNDING_POLICIES.includes(ruleAst.rounding.transactionLine)) {
|
|
189
|
+
throw new StatutoryAstValidationError(
|
|
190
|
+
`Unsupported transactionLine rounding policy: '${ruleAst.rounding.transactionLine}'`,
|
|
191
|
+
{ rounding: ruleAst.rounding }
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
if (ruleAst.rounding.assessmentTotal && !ROUNDING_POLICIES.includes(ruleAst.rounding.assessmentTotal)) {
|
|
195
|
+
throw new StatutoryAstValidationError(
|
|
196
|
+
`Unsupported assessmentTotal rounding policy: '${ruleAst.rounding.assessmentTotal}'`,
|
|
197
|
+
{ rounding: ruleAst.rounding }
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return true;
|
|
203
|
+
}
|