@mudraforge/statutory 2.10.0 → 2.12.1

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 (95) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/CONTRIBUTING.md +3 -2
  3. package/README.md +42 -39
  4. package/SECURITY.md +2 -2
  5. package/SKILL.md +1 -1
  6. package/bin/cli.js +288 -29
  7. package/docs/ACCOUNTING_ASSURANCE_AUDIT_DOSSIER.md +276 -0
  8. package/docs/ARCHITECTURE.md +14 -14
  9. package/docs/ARCHITECTURE_DECISIONS.md +3 -3
  10. package/docs/CASE_01_FORM_TEXT.txt +48 -0
  11. package/docs/CATALOG.md +877 -111
  12. package/docs/CA_PILOT_BENCHMARK_CASES.md +282 -0
  13. package/docs/CORPUS_QUALITY.md +33 -16
  14. package/docs/DATA_LICENSING.md +1 -1
  15. package/docs/DOMAIN_BREADTH_AND_DEPTH_COMPARISON.md +36 -34
  16. package/docs/OKF_MAINTENANCE_SOP.md +12 -12
  17. package/docs/PROVENANCE.md +2 -2
  18. package/docs/VERIFICATION.md +6 -6
  19. package/okf/corporate_ma_restructuring/business_combinations_indas_103/circulars/mca_notification_indas_103_business_combinations.md +41 -0
  20. package/okf/corporate_ma_restructuring/business_combinations_indas_103/forms/purchase_price_allocation_schedule.json +110 -0
  21. package/okf/corporate_ma_restructuring/business_combinations_indas_103/section.json +65 -0
  22. package/okf/corporate_ma_restructuring/impairment_of_assets_indas_36/circulars/mca_notification_indas_36_impairment.md +45 -0
  23. package/okf/corporate_ma_restructuring/impairment_of_assets_indas_36/forms/cgu_impairment_testing_register.json +53 -0
  24. package/okf/corporate_ma_restructuring/impairment_of_assets_indas_36/section.json +61 -0
  25. package/okf/corporate_ma_restructuring/share_based_payments_indas_102/circulars/icai_guidance_share_based_payments.md +37 -0
  26. package/okf/corporate_ma_restructuring/share_based_payments_indas_102/forms/esop_graded_vesting_amortization_schedule.json +49 -0
  27. package/okf/corporate_ma_restructuring/share_based_payments_indas_102/section.json +60 -0
  28. package/okf/corporate_ma_restructuring/tax_clearance_sec281/circulars/cbdt_circular_04_2011_sec281_clearance.md +57 -0
  29. package/okf/corporate_ma_restructuring/tax_clearance_sec281/forms/form_281_tax_clearance_application.json +42 -0
  30. package/okf/corporate_ma_restructuring/tax_clearance_sec281/section.json +70 -0
  31. package/okf/direct_tax/income_taxes_deferred_tax_indas_12/circulars/mca_notification_indas_12_income_taxes.md +40 -0
  32. package/okf/direct_tax/income_taxes_deferred_tax_indas_12/forms/deferred_tax_asset_liability_reconciliation_schedule.json +46 -0
  33. package/okf/direct_tax/income_taxes_deferred_tax_indas_12/section.json +61 -0
  34. package/okf/direct_tax/statutory_disallowance_43b/circulars/supreme_court_checkmate_services_2022.md +64 -0
  35. package/okf/direct_tax/statutory_disallowance_43b/forms/tax_audit_form_3cd_clause_26_schedule.json +71 -0
  36. package/okf/direct_tax/statutory_disallowance_43b/section.json +77 -0
  37. package/okf/direct_tax/tds_commission_194h/section.json +5 -4
  38. package/okf/direct_tax/tds_contractor_194c/section.json +3 -3
  39. package/okf/direct_tax/tds_ecommerce_194o/circulars/cbdt_circular_20_2020_guidelines_194o.md +36 -0
  40. package/okf/direct_tax/tds_ecommerce_194o/forms/form_26q_ecommerce_schedule.json +75 -0
  41. package/okf/direct_tax/tds_ecommerce_194o/section.json +65 -0
  42. package/okf/direct_tax/tds_goods_194q/circulars/cbdt_circular_13_2021_guidelines.md +2 -2
  43. package/okf/direct_tax/tds_goods_194q/section.json +9 -3
  44. package/okf/direct_tax/tds_goods_393/section.json +6 -4
  45. package/okf/direct_tax/tds_individual_contract_194m/circulars/finance_act_2024_194m_rate_cut_memo.md +24 -0
  46. package/okf/direct_tax/tds_individual_contract_194m/forms/form_26qd_contractor_statement.json +64 -0
  47. package/okf/direct_tax/tds_individual_contract_194m/section.json +58 -0
  48. package/okf/direct_tax/tds_interest_194a/circulars/cbdt_circular_03_2010_interest_tds.md +28 -0
  49. package/okf/direct_tax/tds_interest_194a/forms/form_15g_15h_interest_declaration.json +55 -0
  50. package/okf/direct_tax/tds_interest_194a/forms/form_26q_interest_schedule.json +72 -0
  51. package/okf/direct_tax/tds_interest_194a/section.json +67 -0
  52. package/okf/direct_tax/tds_perquisites_194r/forms/form_26q_perquisites_schedule.json +83 -0
  53. package/okf/direct_tax/tds_perquisites_194r/section.json +2 -2
  54. package/okf/direct_tax/tds_property_194ia/circulars/cbdt_notification_67_2022_property_tds.md +57 -0
  55. package/okf/direct_tax/tds_property_194ia/forms/form_26qb_property_tds_challan.json +43 -0
  56. package/okf/direct_tax/tds_property_194ia/section.json +73 -0
  57. package/okf/direct_tax/tds_rent_194i/section.json +5 -4
  58. package/okf/direct_tax/tds_rent_individual_194ib/circulars/finance_act_2024_rent_rate_cut_memo.md +24 -0
  59. package/okf/direct_tax/tds_rent_individual_194ib/forms/form_26qc_challan_cum_statement.json +74 -0
  60. package/okf/direct_tax/tds_rent_individual_194ib/section.json +57 -0
  61. package/okf/direct_tax/tds_services_194j/circulars/cbdt_circular_03_2020_fts_rate_cut.md +1 -1
  62. package/okf/direct_tax/tds_services_194j/section.json +10 -3
  63. package/okf/indirect_tax_gst/common_itc_reversal_rule42_43/circulars/cbic_circular_170_2022_itc_reporting.md +30 -0
  64. package/okf/indirect_tax_gst/common_itc_reversal_rule42_43/circulars/cbic_notification_18_2022_cutoff_amendment.md +26 -0
  65. package/okf/indirect_tax_gst/common_itc_reversal_rule42_43/forms/gstr_3b_table_4b1_reversal_schedule.json +101 -0
  66. package/okf/indirect_tax_gst/common_itc_reversal_rule42_43/forms/rule_42_43_annual_reconciliation_worksheet.json +87 -0
  67. package/okf/indirect_tax_gst/common_itc_reversal_rule42_43/section.json +65 -0
  68. package/okf/indirect_tax_gst/itc_reversal_rule37_37a/circulars/cbic_circular_192_2023_ecl_interest_calculation.md +36 -0
  69. package/okf/indirect_tax_gst/itc_reversal_rule37_37a/circulars/cbic_notification_19_2022_rule37.md +31 -0
  70. package/okf/indirect_tax_gst/itc_reversal_rule37_37a/forms/gstr_3b_table_4b_reversal.json +81 -0
  71. package/okf/indirect_tax_gst/itc_reversal_rule37_37a/section.json +71 -0
  72. package/okf/indirect_tax_gst/rcm_liability_sec9_3/circulars/cbic_notification_07_2025_composition_rent_exclusion.md +41 -0
  73. package/okf/indirect_tax_gst/rcm_liability_sec9_3/circulars/cbic_notification_09_2024_renting_rcm.md +37 -0
  74. package/okf/indirect_tax_gst/rcm_liability_sec9_3/circulars/gst_council_55th_meeting_renting_rcm_regularization.md +31 -0
  75. package/okf/indirect_tax_gst/rcm_liability_sec9_3/section.json +24 -2
  76. package/okf/international_tax/financial_instruments_ecl_indas_109/circulars/mca_notification_indas_109_financial_instruments.md +43 -0
  77. package/okf/international_tax/financial_instruments_ecl_indas_109/forms/indas_109_ecl_provision_matrix_schedule.json +43 -0
  78. package/okf/international_tax/financial_instruments_ecl_indas_109/section.json +62 -0
  79. package/okf/manifest.json +108 -15
  80. package/okf/msme_commercial/lease_accounting_indas_116/circulars/mca_notification_indas_116_leases.md +48 -0
  81. package/okf/msme_commercial/lease_accounting_indas_116/forms/lease_rou_asset_and_liability_schedule.json +55 -0
  82. package/okf/msme_commercial/lease_accounting_indas_116/section.json +67 -0
  83. package/okf/msme_commercial/provisions_contingencies_indas_37/circulars/mca_notification_indas_37_provisions.md +36 -0
  84. package/okf/msme_commercial/provisions_contingencies_indas_37/forms/provisions_and_contingent_liabilities_register.json +38 -0
  85. package/okf/msme_commercial/provisions_contingencies_indas_37/section.json +61 -0
  86. package/okf/msme_commercial/revenue_recognition_indas_115/circulars/mca_notification_indas_115_revenue_contracts.md +56 -0
  87. package/okf/msme_commercial/revenue_recognition_indas_115/forms/revenue_contract_5step_allocation_schedule.json +54 -0
  88. package/okf/msme_commercial/revenue_recognition_indas_115/section.json +69 -0
  89. package/package.json +7 -1
  90. package/src/calculators.js +7898 -638
  91. package/src/constants.js +1 -1
  92. package/src/index.js +604 -23
  93. package/src/tally.js +812 -0
  94. package/src/zoho_gstr2b.js +2964 -0
  95. package/types/index.d.ts +516 -0
package/bin/cli.js CHANGED
@@ -25,6 +25,17 @@ import {
25
25
  getStatutoryOutcomes,
26
26
  explainStatutoryDisposition,
27
27
  ignorePackageUpdate,
28
+ parseTallyDaybookCsv,
29
+ parseTallyDaybookXml,
30
+ reconcile194QDaybook,
31
+ generateTally194QJournalXml,
32
+ generateAuditMarkdownReport,
33
+ parseZohoBillsCsv,
34
+ parseZohoBillsJson,
35
+ parseGstr2bJson,
36
+ reconcileZohoGstr2b,
37
+ generateGstr2bAuditMarkdownReport,
38
+ runStatutoryWatchtower,
28
39
  STATUTORY_EXIT_CODES,
29
40
  STATUTORY_CLIENT_VERSION,
30
41
  DEFAULT_LOCAL_OKF_DIR
@@ -174,6 +185,52 @@ async function main() {
174
185
  handleDecodeId(args[1]);
175
186
  break;
176
187
 
188
+ case 'reconcile':
189
+ case 'reconcile-daybook':
190
+ case 'audit-daybook': {
191
+ const filePath = (args[1] && !args[1].startsWith('-')) ? args[1] : getNamedArg(['--file', '-f'], rawArgs);
192
+ const format = getNamedArg(['--format'], rawArgs);
193
+ const xmlOut = getNamedArg(['--xml-out'], rawArgs);
194
+ const reportOut = getNamedArg(['--report-out', '--out'], rawArgs);
195
+ const buyerTurnover = getNamedArg(['--buyer-turnover'], rawArgs);
196
+ if (!filePath) {
197
+ console.error('[ERROR] Please specify a daybook file to reconcile, e.g. npx @mudraforge/statutory reconcile daybook.csv');
198
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
199
+ }
200
+ await handleReconcileDaybook(filePath, { format, xmlOut, reportOut, buyerTurnover: buyerTurnover ? parseFloat(buyerTurnover) : null });
201
+ break;
202
+ }
203
+
204
+ case 'reconcile-gstr2b':
205
+ case 'reconcile-zoho': {
206
+ const zohoPath = getNamedArg(['--zoho', '--books', '-b'], rawArgs) || (args[1] && !args[1].startsWith('-') ? args[1] : null);
207
+ const gstr2bPath = getNamedArg(['--gstr2b', '--2b', '-g'], rawArgs) || (args[2] && !args[2].startsWith('-') ? args[2] : null);
208
+ const reportOut = getNamedArg(['--report-out', '--out'], rawArgs);
209
+ const tolerance = getNamedArg(['--tolerance'], rawArgs);
210
+ const asOfDate = getNamedArg(['--as-of', '--date'], rawArgs);
211
+ const gstin = getNamedArg(['--gstin'], rawArgs);
212
+
213
+ if (!zohoPath || !gstr2bPath) {
214
+ console.error('[ERROR] Please specify both Zoho Books and GSTR-2B files:');
215
+ console.error(' npx @mudraforge/statutory reconcile-gstr2b --zoho <zoho_bills.csv|json> --gstr2b <gstr2b.json>');
216
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
217
+ }
218
+ await handleReconcileZohoGstr2b(zohoPath, gstr2bPath, {
219
+ reportOut,
220
+ toleranceInr: tolerance ? parseFloat(tolerance) : 1.0,
221
+ asOfDate,
222
+ recipientGstin: gstin
223
+ });
224
+ break;
225
+ }
226
+
227
+ case 'watchtower':
228
+ case 'freshness':
229
+ case 'attest': {
230
+ await handleWatchtower();
231
+ break;
232
+ }
233
+
177
234
  case 'help':
178
235
  default:
179
236
  printHelp();
@@ -899,6 +956,198 @@ function handleDecodeId(rawId) {
899
956
  console.log('───────────────────────────────────────────────────────────────────────────\n');
900
957
  }
901
958
 
959
+ async function handleReconcileDaybook(filePath, opts = {}) {
960
+ const resolvedPath = path.resolve(process.cwd(), filePath);
961
+ if (!fs.existsSync(resolvedPath)) {
962
+ console.error(`[ERROR] Daybook file not found: ${resolvedPath}`);
963
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
964
+ }
965
+
966
+ const rawContent = fs.readFileSync(resolvedPath, 'utf8');
967
+ const ext = path.extname(resolvedPath).toLowerCase();
968
+ const format = (opts.format || (ext === '.xml' ? 'xml' : (ext === '.json' ? 'json' : 'csv'))).toLowerCase();
969
+
970
+ let vouchers = [];
971
+ try {
972
+ if (format === 'xml') {
973
+ vouchers = parseTallyDaybookXml(rawContent);
974
+ } else if (format === 'json') {
975
+ vouchers = JSON.parse(rawContent);
976
+ } else {
977
+ vouchers = parseTallyDaybookCsv(rawContent);
978
+ }
979
+ } catch (parseErr) {
980
+ console.error(`[ERROR] Failed to parse daybook file (${format}):`, parseErr.message);
981
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
982
+ }
983
+
984
+ const reconciliation = reconcile194QDaybook(vouchers, {
985
+ buyerTurnoverCr: opts.buyerTurnover || null
986
+ });
987
+
988
+ if (opts.xmlOut) {
989
+ const xmlOutPath = path.resolve(process.cwd(), opts.xmlOut);
990
+ const xmlContent = generateTally194QJournalXml(reconciliation);
991
+ fs.writeFileSync(xmlOutPath, xmlContent, 'utf8');
992
+ if (!isJsonMode) {
993
+ console.log(`[INFO] Tally compensating XML journal written to: ${xmlOutPath}`);
994
+ }
995
+ }
996
+
997
+ if (opts.reportOut) {
998
+ const reportOutPath = path.resolve(process.cwd(), opts.reportOut);
999
+ const reportContent = generateAuditMarkdownReport(reconciliation);
1000
+ fs.writeFileSync(reportOutPath, reportContent, 'utf8');
1001
+ if (!isJsonMode) {
1002
+ console.log(`[INFO] Audit Markdown memorandum written to: ${reportOutPath}`);
1003
+ }
1004
+ }
1005
+
1006
+ if (isJsonMode) {
1007
+ console.log(JSON.stringify(reconciliation, null, 2));
1008
+ process.exit(0);
1009
+ }
1010
+
1011
+ const { auditSummary, exceptionVendors } = reconciliation;
1012
+ const fmtInr = (n) => '₹' + Number(n || 0).toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
1013
+
1014
+ console.log('\n===========================================================================');
1015
+ console.log('TALLY / ERP SECTION 194Q RECONCILIATION & 40(a)(ia) EXPOSURE AUDIT');
1016
+ console.log('===========================================================================');
1017
+ console.log(`File: ${resolvedPath}`);
1018
+ console.log(`Format: ${format.toUpperCase()}`);
1019
+ console.log(`Vouchers Audited: ${auditSummary.totalVouchersScanned}`);
1020
+ console.log(`Unique Vendors / PANs: ${auditSummary.uniqueVendorsCount}`);
1021
+ console.log(`Vendors > ₹50L Threshold: ${auditSummary.vendorsExceeding50LCount}`);
1022
+ console.log(`Non-Compliant Vendors: ${auditSummary.vendorsWithExceptionsCount}`);
1023
+ console.log(`Total Purchases: ${fmtInr(auditSummary.totalPurchasesInr)}`);
1024
+ console.log(`Taxable Base (> ₹50L): ${fmtInr(auditSummary.totalExcessPurchasesOver50LInr)}`);
1025
+ console.log(`Required TDS @ 0.1%: ${fmtInr(auditSummary.totalTdsPayableInr)}`);
1026
+ console.log(`Actual TDS Deducted: ${fmtInr(auditSummary.totalTdsDeductedInr)}`);
1027
+ console.log(`Unwithheld TDS Shortfall: ${fmtInr(auditSummary.totalTdsShortfallInr)}`);
1028
+ console.log(`---------------------------------------------------------------------------`);
1029
+ console.log(`Section 40(a)(ia) Risk: ${fmtInr(auditSummary.totalSection40aDisallowanceInr)} (30% Expenditure Disallowed)`);
1030
+ console.log(`Estimated Income Tax Hit: ${fmtInr(auditSummary.totalEstimatedTaxImpactInr)} (@ 30% Corporate Tax)`);
1031
+ console.log(`Sec 201(1A) Interest: ${fmtInr(auditSummary.totalSection201InterestInr)}`);
1032
+ console.log(`TOTAL AUDIT EXPOSURE: ${fmtInr(auditSummary.totalAuditExposureInr)}`);
1033
+ console.log('===========================================================================');
1034
+
1035
+ if (exceptionVendors.length > 0) {
1036
+ console.log('\nNON-COMPLIANT VENDOR SCHEDULE (Form 3CD Clause 21(b) Working Papers):');
1037
+ console.log('─'.repeat(75));
1038
+ for (const v of exceptionVendors) {
1039
+ console.log(`• ${v.primaryVendorName} (PAN: ${v.pan || 'MISSING'})`);
1040
+ console.log(` Purchases: ${fmtInr(v.totalPurchasesInr)} | Excess: ${fmtInr(v.excessPurchasesOver50LInr)} | Shortfall: ${fmtInr(v.tdsShortfallInr)} | 40(a)(ia) Risk: ${fmtInr(v.section40aDisallowanceInr)}`);
1041
+ }
1042
+ console.log('─'.repeat(75));
1043
+ console.log(`Tip: Pass --xml-out vouchers.xml to generate Tally Prime auto-import XML.`);
1044
+ } else {
1045
+ console.log('\n[PASS] 100% Statutory Compliance. Zero Section 40(a)(ia) disallowance risk.\n');
1046
+ }
1047
+ }
1048
+
1049
+ async function handleReconcileZohoGstr2b(zohoPath, gstr2bPath, opts = {}) {
1050
+ const resolvedZoho = path.resolve(process.cwd(), zohoPath);
1051
+ const resolved2b = path.resolve(process.cwd(), gstr2bPath);
1052
+
1053
+ if (!fs.existsSync(resolvedZoho)) {
1054
+ console.error(`[ERROR] Zoho Books file not found: ${resolvedZoho}`);
1055
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
1056
+ }
1057
+ if (!fs.existsSync(resolved2b)) {
1058
+ console.error(`[ERROR] GSTR-2B file not found: ${resolved2b}`);
1059
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
1060
+ }
1061
+
1062
+ const zohoContent = fs.readFileSync(resolvedZoho, 'utf8');
1063
+ const gstr2bContent = fs.readFileSync(resolved2b, 'utf8');
1064
+
1065
+ const zohoExt = path.extname(resolvedZoho).toLowerCase();
1066
+ const zohoBills = zohoExt === '.json' ? parseZohoBillsJson(zohoContent) : parseZohoBillsCsv(zohoContent);
1067
+ const gstr2bRecords = parseGstr2bJson(gstr2bContent);
1068
+
1069
+ const reconciliation = reconcileZohoGstr2b({
1070
+ zohoBills,
1071
+ gstr2b: gstr2bRecords,
1072
+ options: {
1073
+ toleranceInr: opts.toleranceInr || 1.0,
1074
+ asOfDate: opts.asOfDate || new Date().toISOString().slice(0, 10),
1075
+ recipientGstin: opts.recipientGstin || null
1076
+ }
1077
+ });
1078
+
1079
+ if (opts.reportOut) {
1080
+ const reportOutPath = path.resolve(process.cwd(), opts.reportOut);
1081
+ const reportContent = generateGstr2bAuditMarkdownReport(reconciliation);
1082
+ fs.writeFileSync(reportOutPath, reportContent, 'utf8');
1083
+ if (!isJsonMode) {
1084
+ console.log(`[INFO] GSTR-2B Audit Markdown report written to: ${reportOutPath}`);
1085
+ }
1086
+ }
1087
+
1088
+ if (isJsonMode) {
1089
+ console.log(JSON.stringify(reconciliation, null, 2));
1090
+ process.exit(0);
1091
+ }
1092
+
1093
+ const s = reconciliation.summary;
1094
+ const fmt = n => 'INR ' + Number(n || 0).toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
1095
+
1096
+ console.log('\n===========================================================================');
1097
+ console.log('ZOHO BOOKS & GSTR-2B AP RECONCILIATION AUDIT');
1098
+ console.log(`Status: ${reconciliation.status} | Disposition: ${s.reconciliationStatus}`);
1099
+ console.log('===========================================================================');
1100
+ console.log(`Zoho Books File: ${resolvedZoho}`);
1101
+ console.log(`GSTR-2B File: ${resolved2b}`);
1102
+ console.log(`Total Zoho Books Bills: ${s.totalBooksBillsCount}`);
1103
+ console.log(`Total GSTR-2B Records: ${s.totalGstr2bRecordsCount}`);
1104
+ console.log(`---------------------------------------------------------------------------`);
1105
+ console.log(`100% Eligible ITC: ${s.matchedEligibleCount} bills (${fmt(s.eligibleItcInr)})`);
1106
+ console.log(`At-Risk Missing in 2B: ${s.missingIn2bCount} bills (${fmt(s.atRiskUnfiledItcInr)}) [Withhold]`);
1107
+ console.log(`Sec 17(5) Blocked ITC: ${s.blocked17_5Count} bills (${fmt(s.blocked17_5ItcInr)}) [Table 4(B)(1)]`);
1108
+ console.log(`Place of Supply Mismatch: ${s.posMismatchCount} bills (${fmt(s.posMismatchItcInr)}) [Dispute]`);
1109
+ console.log(`Value Discrepancies: ${s.amountMismatchCount} bills (${fmt(s.mismatchedItcInr)})`);
1110
+ console.log(`Missing in Books (Unrec): ${s.missingInBooksCount} bills (${fmt(s.missingInBooksTaxInr)})`);
1111
+ console.log(`---------------------------------------------------------------------------`);
1112
+ console.log(`Rule 37 Overdue (>180 Days):${s.rule37OverdueCount} bills (Reversal: ${fmt(s.rule37ReversalAmountInr)})`);
1113
+ console.log(`Rule 37 Delayed Interest: ${fmt(s.rule37InterestExposureInr)} (@ 18% p.a. u/s 50(1))`);
1114
+ console.log('---------------------------------------------------------------------------');
1115
+ console.log(`isAuthorizedToDisburse: ${s.isAuthorizedToDisburse} (Statutory calculation never moves money)`);
1116
+ console.log('===========================================================================\n');
1117
+ }
1118
+
1119
+ async function handleWatchtower() {
1120
+ try {
1121
+ const report = await runStatutoryWatchtower({ verbose: !isJsonMode });
1122
+ if (isJsonMode) {
1123
+ console.log(JSON.stringify(report, null, 2));
1124
+ } else {
1125
+ console.log('\n===========================================================================');
1126
+ console.log('MUDRAFORGE REGULATORY WATCHTOWER & FRESHNESS ATTESTATION');
1127
+ console.log('===========================================================================');
1128
+ console.log(`Status : ${report.status}`);
1129
+ console.log(`Sections Scanned : ${report.checks.schemaValidation.sectionsScanned}`);
1130
+ console.log(`Circulars Scanned : ${report.checks.schemaValidation.circularsScanned}`);
1131
+ console.log(`Forms Scanned : ${report.checks.schemaValidation.formsScanned}`);
1132
+ console.log(`Citations Verified : ${report.checks.citationIntegrity.validCitations} (0 failures)`);
1133
+ console.log(`Merkle Root : ${report.checks.merkleImmutability.computedRoot}`);
1134
+ console.log(`Pinned Root Match : ${report.checks.merkleImmutability.matchesPinnedRoot}`);
1135
+ console.log(`Freshness Benchmarks : ${report.checks.freshnessHorizon.benchmarksPassed}/${report.checks.freshnessHorizon.benchmarksEvaluated} passed`);
1136
+ console.log(`Certificate ID : ${report.certificate?.certificateId}`);
1137
+ console.log(`Empanelment Score : ${report.certificate?.empanelmentComplianceScore}`);
1138
+ console.log(`Disbursement Invariant : isAuthorizedToDisburse === ${report.certificate?.isAuthorizedToDisburse}`);
1139
+ console.log(`Execution Duration : ${report.executionDurationMs}ms`);
1140
+ console.log('===========================================================================\n');
1141
+ }
1142
+ if (report.status !== 'SUCCESS') {
1143
+ process.exit(STATUTORY_EXIT_CODES.SUBSTRATE_CORRUPT || 1);
1144
+ }
1145
+ } catch (err) {
1146
+ console.error('[FAIL] Watchtower execution failed:', err);
1147
+ process.exit(1);
1148
+ }
1149
+ }
1150
+
902
1151
  function printHelp() {
903
1152
  console.log(`
904
1153
  MudraForge Statutory Commons CLI (@mudraforge/statutory)
@@ -907,39 +1156,49 @@ Usage:
907
1156
  npx @mudraforge/statutory <command> [options]
908
1157
 
909
1158
  Commands:
910
- doctor [--offline] Run full diagnostic check of runtime, substrate integrity, & edge status
911
- verify [path] Cryptographically verify OKF substrate authenticity & file integrity
912
- crosswalk <section> Dual-act 1961 <-> 2025 bridge (earlier of credit vs payment)
913
- diff Semantic regulatory changelog (--section, --since, --domain)
914
- outcomes [provision] Inspect API dispositions, statutory states, trigger conditions & actions
915
- explain <code/status> In-depth explanation, legal rationale & remediation steps for a disposition
916
- browse Interactively browse local OKF statutory filesystem
917
- lookup <section> [date] Look up section details & temporal status (e.g. 194Q 2025-06-01)
918
- decode-id <pan_or_gstin> Offline ISO Mod-36 checksum, state name, and PAN entity decoding
919
- check-update [--ignore] Check edge updates; pass --ignore to snooze notices for current version
920
- sync [path] Download/sync latest versioned OKF bundle to disk (default: package okf/ or custom dir)
921
- list List all indexed statutory sections
922
- init-skill [path] Install SKILL.md into your agent workspace (defaults to .agents/skills/)
923
- help Show this help message
1159
+ watchtower Run regulatory surveillance & generate Empanelment Freshness Certificate
1160
+ reconcile <file> Reconcile Tally/ERP daybook (CSV/XML/JSON) for Section 194Q & 40(a)(ia)
1161
+ reconcile-gstr2b [options] Reconcile Zoho Books AP bills with GST Portal Form GSTR-2B
1162
+ doctor [--offline] Run full diagnostic check of runtime, substrate integrity, & edge status
1163
+ verify [path] Cryptographically verify OKF substrate authenticity & file integrity
1164
+ crosswalk <section> Dual-act 1961 <-> 2025 bridge (earlier of credit vs payment)
1165
+ diff Semantic regulatory changelog (--section, --since, --domain)
1166
+ outcomes [provision] Inspect API dispositions, statutory states, trigger conditions & actions
1167
+ explain <code/status> In-depth explanation, legal rationale & remediation steps for a disposition
1168
+ browse Interactively browse local OKF statutory filesystem
1169
+ lookup <section> [date] Look up section details & temporal status (e.g. 194Q 2025-06-01)
1170
+ decode-id <pan_or_gstin> Offline ISO Mod-36 checksum, state name, and PAN entity decoding
1171
+ check-update [--ignore] Check edge updates; pass --ignore to snooze notices for current version
1172
+ sync [path] Download/sync latest versioned OKF bundle to disk (default: package okf/ or custom dir)
1173
+ list List all indexed statutory sections
1174
+ init-skill [path] Install SKILL.md into your agent workspace (defaults to .agents/skills/)
1175
+ help Show this help message
924
1176
 
925
1177
  Options:
926
- --credit <YYYY-MM-DD> Date of credit to vendor/payee account in books (used in crosswalk)
927
- --payment <YYYY-MM-DD> Date of actual payment/disbursement (used in crosswalk)
928
- --since <YYYY-MM-DD> Filter amendments taking effect on or after date (used in diff)
929
- --section, -s <section> Filter amendments by section code (used in diff)
930
- --domain <domain> Filter amendments by statutory domain (used in diff)
931
- --verbose, -v Display full remediation steps, parameter schemas, and consequences in outcomes
932
- --no-update-check Bypass automated background npm package update checks
933
- --json, -j Emit clean, machine-parseable JSON to stdout (suppresses banners)
934
- --offline, -o Bypass outbound network checks (air-gapped / offline environment mode)
935
- --json, -j Emit clean, machine-parseable JSON to stdout (suppresses banners)
936
- --offline, -o Bypass outbound network checks (air-gapped / offline environment mode)
1178
+ --zoho, -b <file> Zoho Books bills CSV or JSON export path
1179
+ --gstr2b, -g <file> GST Portal Form GSTR-2B JSON file path
1180
+ --tolerance <amount> Reconciliation tolerance in INR (default: 1.00)
1181
+ --as-of, --date <date> Audit as-of date (YYYY-MM-DD) for Rule 37 180-day aging
1182
+ --gstin <gstin> Recipient taxpayer GSTIN (used for Place of Supply validation)
1183
+ --format <csv|xml|json> Explicit daybook file format parser
1184
+ --xml-out <path> Output path for Tally Prime compensating journal voucher XML
1185
+ --report-out <path> Output path for executive Markdown audit memorandum
1186
+ --buyer-turnover <Cr> Preceding FY buyer turnover in ₹ Crores (default: assumes > ₹10 Cr)
1187
+ --credit <YYYY-MM-DD> Date of credit to vendor/payee account in books (used in crosswalk)
1188
+ --payment <YYYY-MM-DD> Date of actual payment/disbursement (used in crosswalk)
1189
+ --since <YYYY-MM-DD> Filter amendments taking effect on or after date (used in diff)
1190
+ --section, -s <section> Filter amendments by section code (used in diff)
1191
+ --domain <domain> Filter amendments by statutory domain (used in diff)
1192
+ --verbose, -v Display full remediation steps, parameter schemas, and consequences in outcomes
1193
+ --no-update-check Bypass automated background npm package update checks
1194
+ --json, -j Emit clean, machine-parseable JSON to stdout (suppresses banners)
1195
+ --offline, -o Bypass outbound network checks (air-gapped / offline environment mode)
937
1196
 
938
1197
  Exit Code Conventions:
939
- 0 Success / Verification passed
940
- 1 Usage or operational error (invalid syntax / parameters)
941
- 2 Cryptographic authenticity or integrity violation (mismatch/revocation)
942
- 3 Statutory policy violation (e.g. missing baseline provision)
1198
+ 0 Success / Verification passed
1199
+ 1 Usage or operational error (invalid syntax / parameters)
1200
+ 2 Cryptographic authenticity or integrity violation (mismatch/revocation)
1201
+ 3 Statutory policy violation (e.g. missing baseline provision)
943
1202
  `);
944
1203
  }
945
1204
 
@@ -0,0 +1,276 @@
1
+ # MudraForge Accounting Assurance & Statutory Audit Defense Dossier
2
+
3
+ This document serves as the authoritative, permanent reference manual and verification catalog for the enterprise Accounts Payable (AP) reconciliation, numerical hygiene, and statutory assurance capabilities implemented in `@mudraforge/statutory`.
4
+
5
+ External technical, financial, and tax audits (e.g. Big-4 accounting firms, statutory auditors, tax counsel) frequently probe automated financial platforms for theoretical shortcuts, unhandled edge cases, and legal misinterpretations. This dossier establishes the legal ground truth, mathematical definitions, error boundaries, and corresponding automated regression tests (Tests 120 through 146 in `packages/statutory/test.js`) that guarantee deterministic audit defensibility.
6
+
7
+ ---
8
+
9
+ ## 1. Architectural Philosophy: From Statutory Calculation to Accounting Assurance
10
+
11
+ A statutory calculation engine that merely implements standalone formulas (e.g. `turnover * 0.001`) fails when exposed to real enterprise ERP exports. Raw corporate accounting data is inherently messy: it contains parenthesized credits, trailing minus signs, inconsistent currency formatting, conflicting tax allocations, multi-state branch structures, and varying payment appropriation policies.
12
+
13
+ MudraForge implements **Transaction-Level Accounting Assurance**:
14
+
15
+ ```
16
+ Messy Accounting Ingestion (Zoho Books / Tally Daybooks / GSTR-2B)
17
+ ↓
18
+ Four-State Numeric Classification & Integer-Paise Normalization (Zero Drift)
19
+ ↓
20
+ Epistemic Uncertainty Gate (ISO Mod-36 Checksums, Duplicate Billing, Defective Tax Splits)
21
+ ↓
22
+ 4-Way Decoupled Jurisdictional Evaluation (Tax Classification, Jurisdiction, Eligibility, Routing)
23
+ ↓
24
+ Statutory Provisos & Accounting Math (Rule 37 Proportional Allocation, Rule 88B ECL Audit)
25
+ ↓
26
+ Actionable Exception Register & Executive Audit Memorandum (isAuthorizedToDisburse: false)
27
+ ```
28
+
29
+ ---
30
+
31
+ ## 2. Numerical Hygiene & Input Boundary Hardening
32
+
33
+ ### 2.1 Four-State Numeric Classification Model
34
+ Standard JavaScript type coercion (`Number(x) || 0`) introduces catastrophic statutory failures: malformed strings (e.g. `"₹ 10,00,000"`, `"#VALUE!"`) silently evaluate to `NaN` and collapse to `0`, preventing mandatory tax deductions and creating massive penal exposure under Section 40(a)(ia).
35
+
36
+ MudraForge's `cleanNumericAmount(val, options)` classifies every numeric input into one of four distinct states:
37
+
38
+ | Input State | Example | Engine Behavior | Statutory Rationale |
39
+ |---|---|---|---|
40
+ | **Valid Numeric** | `100000`, `"₹ 10,00,000"`, `"(₹ 50,000)"` | Deterministic float or integer paise | Legitimate transaction amount. |
41
+ | **Valid Zero** | `0`, `"0"`, `"₹ 0.00"` | Returns `0` (or `0` paise) | Explicit non-taxable base or zero-rated voucher. |
42
+ | **Missing Optional** | `undefined`, `null`, `""` (when optional) | Returns `options.defaultValue` | Unused optional fields (e.g. surcharge, cess). |
43
+ | **Missing Mandatory** | `undefined`, `null`, `""` (when mandatory) | Throws `MissingMandatoryParameterError` | Essential statutory threshold inputs cannot be guessed. |
44
+ | **Malformed Representation** | `"100 200"`, `"1,,000"`, `"#VALUE!"` | Throws `MalformedNumericInputError` | Prevents corrupt ERP exports from silently distorting tax calculations. |
45
+
46
+ ### 2.2 Integer-Paise Arithmetic & Max Safe Integer Boundary
47
+ To eliminate floating-point drift across cumulative annual purchases and multi-invoice allocations:
48
+ - **Integer Representation**: All intermediate thresholds, allocations, and variances are converted to integer paise using `toIntegerPaise(amount)`.
49
+ - **Ceiling Boundary**: Values exceeding `Number.MAX_SAFE_INTEGER` (9,007,199,254,740,991 paise = ₹90,071,992,547,409.91) are rejected fail-closed to prevent IEEE 754 precision degradation.
50
+ - **Sub-Paisa Rounding**: Half-up rounding (`roundToPaisa(amount)`) is applied consistently.
51
+
52
+ ### 2.3 Accounting Format Ingestion
53
+ - **Parenthesized Negatives**: Accounting conventions representing negative balances as `(₹ 50,000.00)` or `INR (25,000)` are parsed as negative numbers.
54
+ - **Trailing Minus**: ERP formats such as `50,000.00-` are normalized to `-50000.00`.
55
+ - **Ledger-Aware CR Credits**: Credit indicators (`CR`) are not blindly negated; credit balances are preserved as positive balances unless `{ interpretCreditAsNegative: true }` is explicitly requested by the ledger parser.
56
+
57
+ ---
58
+
59
+ ## 3. Four-Way Decoupled Jurisdictional Matrix
60
+
61
+ Enterprise ERP workflows cannot rely on a single binary eligibility flag (`ELIGIBLE` vs `INELIGIBLE`). Real tax assurance requires decoupling four orthogonal decisions on every transaction:
62
+
63
+ ```
64
+ Transaction Evaluation
65
+ │
66
+ ┌──────────────────┬──────────────┴─────┬─────────────────┐
67
+ ▼ ▼ ▼ ▼
68
+ 1. Tax Determination 2. Recipient 3. ITC 4. Operational
69
+ (IGST Act Sec 5/10) Jurisdiction Eligibility Routing
70
+ (CGST Sec 25(4)) (Sec 16/17(5)) (ERP Action)
71
+ ```
72
+
73
+ ### 3.1 Decision Taxonomy
74
+
75
+ #### 1. Tax Determination (`taxClassification`)
76
+ - `INTRASTATE_CORRECT`: Supplier state equals POS state; local CGST + SGST charged correctly.
77
+ - `INTERSTATE_CORRECT`: Supplier state differs from POS state; IGST charged correctly.
78
+ - `ERRONEOUS_INTRASTATE_LEVY`: Supplier state differs from POS, but supplier erroneously charged local CGST/SGST.
79
+ - `ERRONEOUS_INTERSTATE_LEVY`: Supplier state equals POS, but supplier erroneously charged IGST.
80
+ - `INDETERMINATE`: Missing Place of Supply or conflicting tax split.
81
+
82
+ #### 2. Recipient Jurisdiction (`recipientJurisdiction`)
83
+ - `FILING_GSTIN_MATCHES_POS`: The filing entity's registered state matches the Place of Supply.
84
+ - `REGISTERED_DISTINCT_PERSON_BRANCH`: Recipient's corporate enterprise maintains a valid distinct-person GSTIN under Section 25(4) in the POS state.
85
+ - `UNREGISTERED_IN_POS_STATE`: Recipient has no GST registration in the POS state.
86
+ - `INDETERMINATE`: Missing recipient or POS state code.
87
+
88
+ #### 3. ITC Eligibility (`itcEligibility`)
89
+ - `ELIGIBLE_NORMAL`: Valid tax invoice, populated in GSTR-2B, no statutory blocks.
90
+ - `ELIGIBLE_IN_BRANCH_RETURN`: Valid tax credit, but must be claimed in the branch GSTIN's GSTR-3B.
91
+ - `INELIGIBLE_STRANDED_LOCAL_LEVY`: Mandatory local supply under Section 12(3)/12(4) (e.g. hotel, catering) in a state where recipient is unregistered.
92
+ - `INELIGIBLE_BLOCKED_SEC_17_5`: Blocked under Section 17(5) (motor vehicles, outdoor catering, employee personal perks).
93
+ - `INELIGIBLE_DEFECTIVE_INVOICE`: Defective tax split or erroneous jurisdiction.
94
+ - `INELIGIBLE_PORTAL_FLAGGED`: Flagged ineligible by GSTN portal in Form GSTR-2B (e.g. Section 16(4) time-bar).
95
+ - `PROVISIONAL_PENDING_FILING`: Missing in current GSTR-2B, credit restricted under Section 16(2)(aa) and Rule 36(4).
96
+ - `INDETERMINATE`: Requires human review.
97
+
98
+ #### 4. Operational Routing (`operationalRouting`)
99
+ - `CLAIM_IN_CURRENT_GSTR3B_TABLE_4A5`: Avail in current tax period return.
100
+ - `ROUTE_TO_BRANCH_GSTIN`: Route accounting voucher to branch entity for inclusion in their state return.
101
+ - `BOOK_AS_EXPENSE_NO_ITC`: Absorb tax component as business operating expense; do not avail in ECL.
102
+ - `REPORT_IN_GSTR3B_TABLE_4B1_PERMANENT_REVERSAL`: Report permanent non-reclaimable reversal.
103
+ - `REQUEST_VENDOR_CREDIT_NOTE_AMENDMENT`: Issue commercial dispute notice demanding credit note and reissue.
104
+ - `WITHHOLD_CLAIM_PENDING_SUPPLIER_GSTR1`: Withhold claim until vendor files Form GSTR-1/IFF.
105
+ - `PHYSICAL_GOODS_RECEIPT_VERIFICATION_PENDING`: In GSTR-2B but missing in books (unrecorded AP or transit).
106
+ - `MANUAL_HUMAN_INVESTIGATION_REQUIRED`: Escalate to senior tax auditor.
107
+
108
+ ---
109
+
110
+ ## 4. Rule 37 Proportional Reversal & Rule 88B(3) ECL Audit
111
+
112
+ ### 4.1 Section 16(2) Second Proviso & Rule 37 Payment Appropriation
113
+ Section 16(2) second proviso requires a recipient to pay the supplier the value of supply along with tax within 180 days from the invoice date. Failure to pay triggers mandatory ITC reversal.
114
+
115
+ MudraForge implements three payment appropriation models:
116
+ 1. **`PROPORTIONATE` (Default Statutory Baseline)**:
117
+ $$\text{Unpaid Ratio} = \frac{\text{Balance Due}}{\text{Total Invoice Amount}}$$
118
+ $$\text{Reversal ITC} = \text{Total ITC} \times \text{Unpaid Ratio}$$
119
+ 2. **`VALUE_FIRST` (Contractual Preference)**:
120
+ Payments satisfy the taxable base first; remaining balance is attributed to unpaid tax.
121
+ 3. **`TAX_FIRST` (Tax Compliance Priority)**:
122
+ Payments satisfy tax liability first. Note: Failure to pay taxable consideration still triggers proportional reversal under Rule 37(1).
123
+
124
+ ### 4.2 Statutory Exemptions from Rule 37
125
+ - **Proviso 1 to Rule 37(1) — Reverse Charge (RCM)**: RCM supplies under Section 9(3)/9(4) are statutorily exempt because tax is paid directly to the Government, not the supplier.
126
+ - **Proviso 2 to Rule 37(1) — Schedule I Deemed Supplies**: Supplies without consideration between distinct or related persons are statutorily exempt.
127
+
128
+ ### 4.3 Rule 88B(3) Electronic Credit Ledger Audit & Section 50(1) Interest
129
+ Under Section 50(1) read with Rule 88B(3) (inserted retrospectively w.e.f. 1 July 2017), interest is levied **only when ITC has been wrongly availed and utilized**.
130
+
131
+ - **ECL Closing Balance Check**: If the minimum daily closing balance in the taxpayer's Electronic Credit Ledger (`minimumEclBalanceInr`) remained equal to or greater than the unreversed ITC throughout the default window:
132
+ $$\text{Wrongful Utilization} = \max(0, \text{Unreversed ITC} - \text{Minimum ECL Balance}) = ₹0.00$$
133
+ $$\text{Statutory Interest} = ₹0.00$$
134
+ - **Dipped Balance**: If the ECL balance dipped below the unreversed ITC, 18% annual interest is computed strictly on the utilized portion for the days elapsed past 180:
135
+ $$\text{Interest} = \text{Utilized Amount} \times \frac{0.18}{365} \times (\text{Days Elapsed} - 180)$$
136
+ - **Unavailable History**: If closing ledger balances are missing, the engine refuses to guess, issuing an advisory requiring human verification of ledger statements.
137
+
138
+ ---
139
+
140
+ ## 5. Epistemic Uncertainty & Fail-Closed Governance
141
+
142
+ When financial or legal evidence is incomplete, automated accounting engines must never fabricate certainty. MudraForge marks transactions as `REQUIRES_HUMAN_VERIFICATION` under five statutory conditions:
143
+
144
+ 1. **`INVALID_SUPPLIER_GSTIN_CHECKSUM`**: Supplier GSTIN fails ISO Mod-36 check digit calculation. Prevents claiming credits on invalid or fraudulent registrations.
145
+ 2. **`AMBIGUOUS_DUPLICATE_INVOICE_MATCH`**: Multiple candidate records share the identical supplier GSTIN and invoice number. Prevents guessing between duplicate billing and amended vouchers.
146
+ 3. **`CONTRADICTORY_TAX_SPLIT`**: Voucher contains concurrent CGST/SGST and IGST. Defective on its face under Section 31.
147
+ 4. **`MISSING_POS_DATA`**: Place of Supply is omitted or indeterminate in both Books and GSTR-2B.
148
+ 5. **`MISSING_ECL_HISTORY`**: Electronic Credit Ledger closing balances are omitted when evaluating delayed interest.
149
+
150
+ ---
151
+
152
+ ## 6. The Complete Verification Matrix: Tests 120 through 146
153
+
154
+ Every statutory capability and defensive boundary is continuously verified by deterministic regression tests in `packages/statutory/test.js`:
155
+
156
+ | Test # | Test Title | Statutory / Accounting Provision | Ground Truth Verified |
157
+ |---|---|---|---|
158
+ | **120** | Numerical Input Resilience & Currency Sanitization | Enterprise ERP Ingestion Standards | Normalizes `"₹ 10,00,000"`, `"1,23,456.78"`, whitespace, and non-finite inputs. |
159
+ | **121** | Excel Date Serial & Diverse Date Normalization | RFC 4180 / Microsoft Excel Standards | Normalizes Excel serial numbers (`45453` -> `2024-06-10`) and Indian date formats (`10/06/2024`). |
160
+ | **122** | Accounting Negative Formats: Parens, Minus & CR | GAAP / Ind AS Presentation Rules | Correctly identifies `(₹ 50,000.00)` as negative and preserves `50,000.00 CR` ledger credits. |
161
+ | **123** | Zero-Argument & Empty Destructuring Robustness | Safe API Contract Standards | Invocations with `{}` or zero arguments execute safely without unhandled TypeErrors. |
162
+ | **124** | UTF-8 BOM & European Delimiter Parsing | RFC 4180 CSV Ingestion | Strips UTF-8 BOM (`\uFEFF`) and automatically detects semicolon (`;`) and tab (`\t`) delimiters. |
163
+ | **125** | Parenthesized Negative Vouchers & Return Netting | CBDT Circular 13/2021 Question 4 | Parenthesized `(₹ 10,00,000)` return voucher reduces rolling purchase base to ₹45L, preventing wrongful Section 194Q alerts. |
164
+ | **126** | StatutoryClient Programmatic Parity for Daybooks | Package Architecture Parity | Verifies full client parity for `parseTallyDaybookCsv`, `reconcile194QDaybook`, XML, and reports. |
165
+ | **127** | Strict Malformed Numeric & Integer-Paise Precision | Financial Computation Integrity | Enforces 4-state classification, `Number.MAX_SAFE_INTEGER` bounds, and fractional sub-paisa rules. |
166
+ | **128** | Mandatory Parameter Enforcement across Calculators | Statutory Defensive Architecture | Asserts 12 core statutory calculators throw `MissingMandatoryParameterError` on incomplete data. |
167
+ | **129** | Real-World Tally Ingestion: Dual Columns & Quotes | TallyPrime Export Specifications | Dual Debit/Credit column netting, Particulars header lookup, blank-row filtering, and RFC 4180 quotes. |
168
+ | **130** | StatutoryClient Arithmetic and Precision Parity | Package Architecture Parity | Exposes `cleanNumericAmount`, `toIntegerPaise`, `fromIntegerPaise`, `roundToPaisa` on `StatutoryClient`. |
169
+ | **131** | Zoho Books Bills CSV Parsing | Zoho Books Export Specifications | Parses Zoho bill CSVs, extracting Section 17(5) categories, RCM flags, and Schedule I deemed supplies. |
170
+ | **132** | Zoho API JSON & GSTR-2B JSON Ingestion | GST Portal API Schema / Zoho REST API | Parses B2B invoices, CDNR credit/debit notes netting, date normalization, and item tax rollups. |
171
+ | **133** | 2-Way Reconciliation MATCHED_ELIGIBLE | CGST Act Section 16(2) | Fuzzy alphanumeric key matching resolves separator variance (`INV/2024-25/001` vs `INV-2024-25-001`). |
172
+ | **134** | Statutory Dispositions: Missing 2B, Books, Mismatch | CGST Act Sec 16(2)(aa) & Rule 36(4) | Categorizes `MISSING_IN_GSTR2B` (provisional restricted), `MISMATCH_AMOUNT_VALUE`, and `MISSING_IN_BOOKS`. |
173
+ | **135** | Section 17(5) Blocked Credit & POS Mismatch | CGST Act Sec 17(5) & IGST Act Sec 12 | Isolates blocked motor vehicle ITC for GSTR-3B Table 4(B)(1) and disallows out-of-state local tax. |
174
+ | **136** | Rule 37 180-Day Aging & Section 50(1) Delayed Interest | CGST Act Sec 16(2) 2nd Proviso & Rule 37 | Unpaid bill >180 days triggers Table 4(B)(2) reversal + 18% delayed interest exposure for overdue days. |
175
+ | **137** | StatutoryClient Parity & Executive Report Generation | Client API & Audit Memorandum | Verifies programmatic methods and renders executive Markdown audit memorandum with health matrix. |
176
+ | **138** | CLI Integration — reconcile-gstr2b | Command Line Interface | Executes CLI command `reconcile-gstr2b` with JSON pipeline and report output. |
177
+ | **139** | Multi-State POS Triangulation & Branch Routing | CGST Act Sec 25(4) & IGST Act Sec 12(3) | Routes distinct-person vouchers to branch GSTIN; absorbs stranded hotel local CGST/SGST as expense. |
178
+ | **140** | Rule 37 Exceptions, Proportional Netting & Rule 88B | Rule 37(1) Provisos & Rule 88B(3) | Validates RCM & Schedule 1 exemptions, 50% partial payment netting, and 0% interest on unutilized ECL. |
179
+ | **141** | GSTR-2B GSTN Ineligible Flag & Goods-In-Transit | CGST Act Sec 16(4) & Sec 16(2)(b) | Captures portal `itcavl: "N"` flag; classifies recent unrecorded invoices (<15 days) as goods in transit. |
180
+ | **142** | Zoho Books Vendor Credits Netting | Accounting Double-Entry Principles | Parses native `vendor_credits` array, performing negative taxable and tax netting against gross AP. |
181
+ | **143** | Explicit Uncertainty Routing (REQUIRES_HUMAN) | Audit Governance & Epistemic Honesty | Fails closed on invalid GSTIN checksum, contradictory tax splits, and duplicate invoice candidates. |
182
+ | **144** | Payment Appropriation Policies & Dipped ECL Math | Rule 37(1) & Rule 88B(3) Math | Verifies `VALUE_FIRST` vs `PROPORTIONATE` reversal math and computes 18% interest on dipped ECL balances. |
183
+ | **145** | Decoupled Jurisdictional Decisions Structure | Architectural Assurance | Asserts transaction-level 4-way decisions structure (`taxClassification`, `recipientJurisdiction`, etc.). |
184
+ | **146** | 50-Transaction Synthetic E2E Batch Test | Comprehensive Enterprise AP Simulation | 47 bills and 45 GSTR-2B records across 9 compliance groups evaluated in an end-to-end stress run. |
185
+ | **147** | Chronological Rule 88B(3) ECL Ledger History | CGST Act Section 50(1) & Rule 88B(3) | Evaluates day-by-day movements across 5 trajectories: zero dip, temporary dip, multiple dips/recoveries, partial dip, and post-utilization reversal. |
186
+ | **148** | Evidence Provenance Integrity & Audit Trail | Forensic Audit Reproducibility | Attaches cryptographic `evidenceProvenance` object with SHA-256 derived signature (`MF-PROV-...`), source references, 4-way decisions, and pinned Merkle root. |
187
+ | **149** | Section 12(3) Lodging vs Section 12(7) Event Management | IGST Act Place of Supply Triangulation | Distinguishes immovable lodging (property location -> stranded expense) from B2B event organizing (recipient location -> mandatory IGST / vendor credit note demand). |
188
+ | **150** | Zoho Books API Contract Hardening | Enterprise API Resilience | Validates pagination `page_context` retention, null/empty record resilience, and fail-closed handling of Zoho API error codes (e.g. Code 14). |
189
+ | **151** | Property-Based Fuzz Testing (500 Transactions) | Invariant Enforcement & Stress Resilience | Generates 500 randomized transactions, asserting double-entry accounting conservation, zero floating-point drift, and immutable `isAuthorizedToDisburse: false`. |
190
+
191
+ ---
192
+
193
+ ## 7. The 50-Transaction Synthetic E2E Batch Specification (Test 146)
194
+
195
+ Test 146 constructs an end-to-end multi-scenario corporate portfolio evaluating 47 Zoho purchase bills and 45 GST Portal GSTR-2B records across 9 orthogonal compliance groups:
196
+
197
+ | Group | Invoice Range | Transaction Character | Statutory Grounding | Resulting Engine Disposition |
198
+ |---|---|---|---|---|
199
+ | **Group 1** | 01–20 | Clean matched bills alternating intrastate (Maharashtra `27`) and interstate (Karnataka `29`). | CGST Act Section 16(2) | `MATCHED_ELIGIBLE` (Table 4A5 credit) |
200
+ | **Group 2** | 21–25 | Bangalore supplier (`29`) charging Karnataka local tax where recipient has a distinct-person branch in `29`. | CGST Act Section 25(4) | `MATCHED_ROUTABLE_TO_BRANCH_GSTIN` (`ROUTE_TO_BRANCH_GSTIN`) |
201
+ | **Group 3** | 26–30 | Chennai hotel (`33`) charging Tamil Nadu local tax where recipient has no branch in `33`. | IGST Act Section 12(3) | `MATCHED_INELIGIBLE_STRANDED_LOCAL_CGST_SGST` (`BOOK_AS_EXPENSE_NO_ITC`) |
202
+ | **Group 4** | 31–35 | Invoices dated 210 days ago, 50% paid balance remaining. | Rule 37(1) & Rule 88B(3) | `MATCHED_ELIGIBLE` with `rule37OverdueCount: 5`, proportional Table 4(B)(2) reversal, and ₹0.00 interest due to ₹10L ECL balance. |
203
+ | **Group 5** | 36–38 | Goods Transport Agency (GTA) freight invoices unpaid past 180 days. | Rule 37(1) Proviso 1 (RCM) | `MATCHED_ELIGIBLE` with `EXEMPT_RCM_SUPPLY` (zero reversal required). |
204
+ | **Group 6** | 39–41 | Invoices flagged `itcavl: false` by GSTN with reason `TIME_BARRED_SEC_16_4`. | CGST Act Section 16(4) | `GSTR2B_INELIGIBLE_FLAGGED_BY_GSTN` (`REPORT_IN_GSTR3B_TABLE_4B1_PERMANENT_REVERSAL`) |
205
+ | **Group 7** | 42–44 | Fresh invoices dated 5 days prior to audit date, absent in GSTR-2B. | CGST Act Section 16(2)(aa) | `MISSING_IN_GSTR2B_TIMING` (`PROVISIONAL_PENDING_NEXT_GSTR2B`) |
206
+ | **Group 8** | 45–47 | Invoices present in GSTR-2B dated 3 days ago, absent in Zoho Books. | CGST Act Section 16(2)(b) | `MISSING_IN_BOOKS` (`PHYSICAL_GOODS_RECEIPT_VERIFICATION_PENDING`) |
207
+ | **Group 9** | 48–50 | Corrupted checksum (48), contradictory tax split (49), missing Place of Supply (50). | Fail-Closed Governance | `REQUIRES_HUMAN_VERIFICATION` (with discrete `uncertaintyReason` codes). |
208
+
209
+ ---
210
+
211
+ ## 8. Advanced Accounting Assurance & Forensic Integrity (Tests 147–151)
212
+
213
+ ### A. Chronological Rule 88B(3) ECL Simulation
214
+ Under Explanation (1) to Rule 88B of the CGST Rules, wrongful utilization of input tax credit occurs **only when and to the extent that** the balance in the Electronic Credit Ledger (ECL) dips below the unreversed ITC amount. MudraForge models this day-by-day:
215
+ - **Trajectory 1 (Zero Dip)**: ECL balance remains above unreversed ITC -> 0% interest throughout.
216
+ - **Trajectory 2 (Temporary Dip)**: ECL dips below unreversed ITC for a 10-day window -> interest is calculated strictly for those 10 days on the dipped amount.
217
+ - **Trajectory 3 (Multiple Dips & Recoveries)**: Sum of day-weighted interest across each distinct dip interval.
218
+ - **Trajectory 4 (Partial Utilization)**: If the ECL balance remains positive (e.g. ₹3,00,000 against ₹5,00,000 unreversed ITC), interest is quantified strictly on the ₹2,00,000 shortfall.
219
+ - **Trajectory 5 (Post-Utilization Reversal)**: If the taxpayer reverses the ITC prior to assessment, interest calculation terminates on the exact reversal date.
220
+
221
+ ### B. Cryptographic Evidence Provenance (`MF-PROV-...`)
222
+ Every reconciliation item now bears an immutable, self-contained `evidenceProvenance` object:
223
+ ```json
224
+ {
225
+ "provenanceId": "MF-PROV-3A7F8B12C4E9D021",
226
+ "provenanceTimestamp": "2024-08-10T14:30:00.000Z",
227
+ "source": { "sourceSystem": "ZOHO_BOOKS", "billNumber": "INV-2024-001" },
228
+ "externalEvidence": { "sourceSystem": "GST_PORTAL_GSTR2B", "presentInGstr2b": true },
229
+ "matchingMethod": "EXACT",
230
+ "statutoryBasis": {
231
+ "governingStatute": "Central Goods and Services Tax Act, 2017 / Integrated Goods and Services Tax Act, 2017",
232
+ "primarySection": "CGST Act Section 16(2)"
233
+ },
234
+ "jurisdictionDecisions": {
235
+ "taxClassification": "INTRASTATE_CORRECT",
236
+ "recipientJurisdiction": "FILING_GSTIN_MATCHES_POS",
237
+ "itcEligibility": "ELIGIBLE_NORMAL",
238
+ "operationalRouting": "CLAIM_IN_CURRENT_GSTR3B_TABLE_4A5"
239
+ },
240
+ "uncertaintyAssessment": { "isCertain": true, "uncertaintyReason": "NONE" },
241
+ "governanceTrail": {
242
+ "requiresHumanReview": false,
243
+ "merkleSubstrateRoot": "sha256-f7709f6a77a3b5ae16d69baf49f6e5c69bb01e29a4f13a506eb757220bf68e03",
244
+ "isAuthorizedToDisburse": false
245
+ }
246
+ }
247
+ ```
248
+
249
+ ### C. Section 12(3) vs Section 12(7) Place of Supply Triangulation
250
+ - **Section 12(3)(a) Immovable Lodging**: Accommodation in hotels, guest houses, or campsites strictly fixes the Place of Supply at the property location. If the recipient has no GST registration in that state, the CGST/SGST is legally stranded and absorbed as an operating expense (`BOOK_AS_EXPENSE_NO_ITC`).
251
+ - **Section 12(7)(a)(i) B2B Event Management**: Organization of conferences, exhibitions, or corporate events provided to a registered person fixes the Place of Supply at the **location of the recipient**. If a local vendor charges venue state CGST/SGST, it is an `ERRONEOUS_INTRASTATE_LEVY`. The engine flags this as a defective invoice and instructs the AP team to demand a vendor credit note and corrected IGST invoice (`REQUEST_VENDOR_CREDIT_NOTE_AMENDMENT`).
252
+
253
+ ### D. Zoho Books API Contracts & Property-Based Fuzz Testing
254
+ - **API Pagination**: Preserves `page_context` (`page`, `per_page`, `has_more_page`, `total`) for multi-page batch ingestion.
255
+ - **Fail-Closed API Errors**: Throws explicit, actionable errors upon encountering Zoho API error codes (e.g. Code 14 invalid parameter).
256
+ - **500-Transaction Fuzz Invariants**: Validates that double-entry balance, disposition categorization, and disbursement lock (`isAuthorizedToDisburse: false`) hold across 500 randomized transactions.
257
+
258
+ ---
259
+
260
+ ## 9. Preserving Audit Defensibility in Production
261
+
262
+ To prove compliance to external auditors, execute the automated verification pipeline:
263
+
264
+ ```bash
265
+ # 1. Full statutory test suite (asserts all 151 tests pass)
266
+ npm test
267
+
268
+ # 2. Excel Add-in verification suite (asserts 25 custom functions pass)
269
+ npm -C packages/excel-addin test
270
+
271
+ # 3. OKF v0.2 Schema, Circular, and Form validator
272
+ npm run validate
273
+
274
+ # 4. Cryptographic Merkle Root integrity check (asserts 117/117 files match pinned hash)
275
+ npm run manifest:check
276
+ ```