@mudraforge/statutory 2.6.0 → 2.8.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/bin/cli.js CHANGED
@@ -18,6 +18,11 @@ import {
18
18
  getLocalManifest,
19
19
  checkForPackageUpdate,
20
20
  decodeTaxIdentifier,
21
+ verifyLocalSubstrate,
22
+ runStatutoryDoctor,
23
+ crosswalkStatute,
24
+ getStatutoryDiff,
25
+ STATUTORY_EXIT_CODES,
21
26
  STATUTORY_CLIENT_VERSION,
22
27
  DEFAULT_LOCAL_OKF_DIR
23
28
  } from '../src/index.js';
@@ -25,11 +30,65 @@ import {
25
30
  const __filename = fileURLToPath(import.meta.url);
26
31
  const __dirname = path.dirname(__filename);
27
32
 
28
- const args = process.argv.slice(2);
33
+ const rawArgs = process.argv.slice(2);
34
+ const isJsonMode = rawArgs.includes('--json') || rawArgs.includes('-j');
35
+ const isOfflineMode = rawArgs.includes('--offline') || rawArgs.includes('-o');
36
+ const args = rawArgs.filter(a => a !== '--json' && a !== '-j' && a !== '--offline' && a !== '-o');
29
37
  const command = args[0] ? args[0].toLowerCase() : 'help';
30
38
 
39
+ function getNamedArg(nameList, argList) {
40
+ for (let i = 0; i < argList.length; i++) {
41
+ const item = argList[i];
42
+ for (const name of nameList) {
43
+ if (item === name && i + 1 < argList.length && !argList[i + 1].startsWith('-')) {
44
+ return argList[i + 1];
45
+ }
46
+ if (item.startsWith(`${name}=`)) {
47
+ return item.slice(name.length + 1);
48
+ }
49
+ }
50
+ }
51
+ return null;
52
+ }
53
+
31
54
  async function main() {
32
55
  switch (command) {
56
+ case 'doctor':
57
+ case 'diagnose':
58
+ await handleDoctor();
59
+ break;
60
+
61
+ case 'verify':
62
+ case 'audit':
63
+ case 'check':
64
+ await handleVerify(args[1]);
65
+ break;
66
+
67
+ case 'crosswalk':
68
+ case 'bridge':
69
+ case 'transition': {
70
+ const section = (args[1] && !args[1].startsWith('-')) ? args[1] : getNamedArg(['--section', '-s'], rawArgs);
71
+ const creditDate = getNamedArg(['--credit', '-c'], rawArgs);
72
+ const paymentDate = getNamedArg(['--payment', '-p'], rawArgs);
73
+ const asOfDate = getNamedArg(['--date', '-d', '--as-of'], rawArgs);
74
+ if (!section) {
75
+ console.error('[ERROR] Please specify a section to crosswalk, e.g. npx @mudraforge/statutory crosswalk 194Q --credit 2026-03-25 --payment 2026-04-10');
76
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
77
+ }
78
+ await handleCrosswalk(section, { creditDate, paymentDate, asOfDate });
79
+ break;
80
+ }
81
+
82
+ case 'diff':
83
+ case 'changelog':
84
+ case 'amendments': {
85
+ const section = (args[1] && !args[1].startsWith('-')) ? args[1] : getNamedArg(['--section', '-s'], rawArgs);
86
+ const since = getNamedArg(['--since'], rawArgs);
87
+ const domain = getNamedArg(['--domain'], rawArgs);
88
+ await handleDiff({ section, since, domain });
89
+ break;
90
+ }
91
+
33
92
  case 'init-skill':
34
93
  case 'install-skill':
35
94
  await handleInitSkill(args[1]);
@@ -43,9 +102,16 @@ async function main() {
43
102
 
44
103
  case 'sync':
45
104
  case 'pull':
46
- case 'update':
47
- await handleSync(args[1]);
105
+ case 'update': {
106
+ let target = args[1];
107
+ if (target === '--dest' || target === '-d') {
108
+ target = args[2];
109
+ } else if (target && target.startsWith('--dest=')) {
110
+ target = target.slice(7);
111
+ }
112
+ await handleSync(target);
48
113
  break;
114
+ }
49
115
 
50
116
  case 'browse':
51
117
  case 'nav':
@@ -83,7 +149,7 @@ async function main() {
83
149
  }
84
150
 
85
151
  // Non-intrusive background npm package update notice
86
- if (!['check-update', 'status', 'version'].includes(command)) {
152
+ if (!isJsonMode && !['check-update', 'status', 'version', 'verify', 'audit', 'check', 'crosswalk', 'bridge', 'transition', 'diff', 'changelog', 'amendments'].includes(command)) {
87
153
  try {
88
154
  const updateInfo = await checkForPackageUpdate();
89
155
  if (updateInfo && updateInfo.updateAvailable) {
@@ -96,23 +162,244 @@ async function main() {
96
162
  }
97
163
  }
98
164
 
165
+ async function handleVerify(targetDir) {
166
+ try {
167
+ let dest = DEFAULT_LOCAL_OKF_DIR;
168
+ if (targetDir) {
169
+ dest = path.resolve(process.cwd(), targetDir);
170
+ }
171
+ const report = verifyLocalSubstrate(dest);
172
+ if (isJsonMode) {
173
+ console.log(JSON.stringify(report, null, 2));
174
+ process.exit(report.exitCode);
175
+ }
176
+
177
+ console.log('\n===========================================================================');
178
+ console.log(`MUDRAFORGE OPEN KNOWLEDGE FORMAT (OKF) — CRYPTOGRAPHIC VERIFIER [v${report.okfVersion || 'Unknown'}]`);
179
+ console.log('===========================================================================');
180
+
181
+ if (report.integrity.valid) {
182
+ console.log(`[OK] Integrity: ${report.integrity.totalFilesChecked} files verified against Merkle manifest.`);
183
+ console.log(` Root Merkle Hash: ${report.integrity.computedRoot}`);
184
+ } else {
185
+ console.error(`[FAIL] Integrity: Mismatches: ${report.integrity.mismatches.length}, Missing: ${report.integrity.missingFiles.length}, Untracked: ${report.integrity.untrackedFiles.length}`);
186
+ for (const m of report.integrity.mismatches) {
187
+ console.error(` • ${m.file} (Expected ${m.expected.slice(0, 10)}..., actual ${m.actual.slice(0, 10)}...)`);
188
+ }
189
+ for (const mf of report.integrity.missingFiles) {
190
+ console.error(` • Missing: ${mf}`);
191
+ }
192
+ }
193
+
194
+ if (report.authenticity.valid) {
195
+ console.log(`[OK] Authenticity: Provenance authenticated via ${report.authenticity.method}.`);
196
+ if (report.authenticity.keyId) {
197
+ console.log(` Signer Key ID: ${report.authenticity.keyId}`);
198
+ }
199
+ } else {
200
+ console.error(`[FAIL] Authenticity: Root hash "${report.integrity.computedRoot}" is neither pinned nor signed by an authorized MudraForge trust anchor.`);
201
+ }
202
+
203
+ if (report.baselineCheck.valid) {
204
+ console.log(`[OK] Statutory Policy: All mandatory baseline provisions present (${report.baselineCheck.baselineSections.join(', ')}).`);
205
+ } else {
206
+ console.error(`[FAIL] Statutory Policy: Missing mandatory baseline provisions: ${report.baselineCheck.missingBaseline.join(', ')}`);
207
+ }
208
+
209
+ console.log('───────────────────────────────────────────────────────────────────────────');
210
+ if (report.valid) {
211
+ console.log(`[PASS] Statutory substrate is authentic, intact, and compliant (Exit ${report.exitCode}).\n`);
212
+ } else {
213
+ console.error(`[FAIL] Verification failed with Exit Code ${report.exitCode}.\n`);
214
+ }
215
+ process.exit(report.exitCode);
216
+ } catch (err) {
217
+ if (isJsonMode) {
218
+ console.log(JSON.stringify({ valid: false, exitCode: STATUTORY_EXIT_CODES.USAGE_ERROR, error: err.message }, null, 2));
219
+ } else {
220
+ console.error(`[ERROR] Verification error: ${err.message}`);
221
+ }
222
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
223
+ }
224
+ }
225
+
226
+ async function handleDoctor() {
227
+ try {
228
+ const report = await runStatutoryDoctor({ offline: isOfflineMode });
229
+ if (isJsonMode) {
230
+ console.log(JSON.stringify(report, null, 2));
231
+ process.exit(report.exitCode);
232
+ }
233
+
234
+ console.log('\n===========================================================================');
235
+ console.log(`MUDRAFORGE STATUTORY DIAGNOSTIC DOCTOR [v${report.clientVersion}]`);
236
+ console.log('===========================================================================');
237
+
238
+ console.log('── 1. RUNTIME & HOST ENVIRONMENT ──');
239
+ console.log(`Node.js: ${report.runtime.nodeVersion} ${report.runtime.isSupportedNode ? '(Supported: v18+)' : '[UNSUPPORTED]'}`);
240
+ console.log(`Platform: ${report.runtime.platform} (${report.runtime.arch})`);
241
+ console.log(`Environment: ${report.runtime.environment}${report.runtime.isCI ? ' (CI Active)' : ''}`);
242
+ console.log(`API Key Config: ${report.runtime.hasApiKey ? 'CONFIGURED (Enterprise Tier Enabled)' : 'NOT_CONFIGURED (Free Commons Mode)'}`);
243
+
244
+ console.log('\n── 2. LOCAL OKF SUBSTRATE HEALTH ──');
245
+ if (report.substrate.valid) {
246
+ console.log(`Directory: ${DEFAULT_LOCAL_OKF_DIR}`);
247
+ console.log(`Manifest Version: v${report.substrate.okfVersion} (Published: ${report.substrate.publishedAt})`);
248
+ console.log(`Files Checked: ${report.substrate.integrity.totalFilesChecked} (0 mismatches, 0 missing, 0 untracked)`);
249
+ console.log(`Root Merkle Hash: ${report.substrate.integrity.computedRoot}`);
250
+ console.log(`Integrity: PASS`);
251
+ console.log(`Provenance: AUTHENTIC (${report.substrate.authenticity.method})`);
252
+ console.log(`Statutory Policy: PASS (All ${report.substrate.baselineCheck.baselineSections.length} mandatory baselines present)`);
253
+ } else {
254
+ console.error(`Substrate: FAILED (Exit Code ${report.substrate.exitCode})`);
255
+ if (report.substrate.error) console.error(`Error: ${report.substrate.error}`);
256
+ if (!report.substrate.integrity.valid) {
257
+ console.error(`Integrity Failure: ${report.substrate.integrity.mismatches.length} mismatch(es), ${report.substrate.integrity.missingFiles.length} missing files.`);
258
+ }
259
+ if (!report.substrate.authenticity.valid) {
260
+ console.error(`Authenticity: Root hash not authenticated.`);
261
+ }
262
+ if (!report.substrate.baselineCheck.valid) {
263
+ console.error(`Missing Baselines: ${report.substrate.baselineCheck.missingBaseline.join(', ')}`);
264
+ }
265
+ }
266
+
267
+ console.log('\n── 3. CLOUDFLARE ANYCAST EDGE CONNECTIVITY ──');
268
+ console.log(`Endpoint: ${report.edge.baseUrl}`);
269
+ if (report.edge.status === 'REACHABLE') {
270
+ console.log(`Status: REACHABLE (Latency: ${report.edge.latencyMs}ms)`);
271
+ } else if (report.edge.status === 'SKIPPED_AIR_GAPPED') {
272
+ console.log(`Status: SKIPPED (Air-Gapped / Offline Flag Enabled)`);
273
+ } else {
274
+ console.log(`Status: ${report.edge.status} (Offline-first local mode operative)`);
275
+ }
276
+ console.log(`Advisory: ${report.edge.advisory}`);
277
+
278
+ console.log('───────────────────────────────────────────────────────────────────────────');
279
+ if (report.healthy) {
280
+ console.log(`[PASS] All diagnostic checks passed with zero defects (Exit 0).\n`);
281
+ } else {
282
+ console.error(`[FAIL] Diagnostic doctor flagged health violations (Exit ${report.exitCode}).\n`);
283
+ }
284
+ process.exit(report.exitCode);
285
+ } catch (err) {
286
+ if (isJsonMode) {
287
+ console.log(JSON.stringify({ healthy: false, exitCode: STATUTORY_EXIT_CODES.USAGE_ERROR, error: err.message }, null, 2));
288
+ } else {
289
+ console.error(`[ERROR] Doctor diagnostic error: ${err.message}`);
290
+ }
291
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
292
+ }
293
+ }
294
+
295
+ async function handleCrosswalk(section, options) {
296
+ try {
297
+ const result = crosswalkStatute(section, options);
298
+ if (isJsonMode) {
299
+ console.log(JSON.stringify(result, null, 2));
300
+ process.exit(0);
301
+ }
302
+
303
+ console.log('\n===========================================================================');
304
+ console.log('MUDRAFORGE DUAL-ACT STATUTORY CROSSWALK (1961 ACT <-> 2025 ACT)');
305
+ console.log('===========================================================================');
306
+ console.log(`Query Section: ${result.querySection}`);
307
+ console.log(`Governing Statute: ${result.governingAct}`);
308
+ console.log(`Applicable Section: ${result.applicableSection}`);
309
+ console.log(`Temporal Status: ${result.temporalStatus}`);
310
+
311
+ console.log('\n── TEMPORAL CRYSTALLIZATION (EARLIER OF CREDIT OR PAYMENT) ──');
312
+ if (result.creditDate) console.log(`Credit in Books: ${result.creditDate}`);
313
+ if (result.paymentDate) console.log(`Payment Rail: ${result.paymentDate}`);
314
+ console.log(`Trigger Date: ${result.triggerDate}`);
315
+ console.log(`Trigger Event: ${result.triggerReason}`);
316
+ console.log(`Event Context: ${result.triggerDescription}`);
317
+
318
+ console.log('\n── STATUTORY BRIDGE & DUAL-ACT MAPPING ──');
319
+ console.log(`Predecessor (1961): ${result.crosswalk.predecessor.statutorySection} (${result.crosswalk.predecessor.title})`);
320
+ console.log(` Rate: ${result.crosswalk.predecessor.standardRate} | Challan: ${result.crosswalk.predecessor.challan} | Return: ${result.crosswalk.predecessor.returnForm}`);
321
+ console.log(`Successor (2025): ${result.crosswalk.successor.statutorySection} (Effective ${result.crosswalk.successor.effectiveDate})`);
322
+ console.log(` Rate: ${result.crosswalk.successor.standardRate} | Return: ${result.crosswalk.successor.returnForm}`);
323
+
324
+ console.log('\n── STATUTORY SAVINGS & LEGAL GROUNDING ──');
325
+ console.log(`Primary Authority: ${result.crosswalk.savingsAuthority.statute}`);
326
+ console.log(`Subsidiary Principle: ${result.crosswalk.savingsAuthority.subsidiary}`);
327
+ console.log(`Legal Analysis: ${result.legalAnalysis}`);
328
+
329
+ console.log('───────────────────────────────────────────────────────────────────────────');
330
+ console.log('[PASS] Statutory crosswalk resolved successfully (Exit 0).\n');
331
+ process.exit(0);
332
+ } catch (err) {
333
+ if (isJsonMode) {
334
+ console.log(JSON.stringify({ status: 'ERROR', exitCode: STATUTORY_EXIT_CODES.USAGE_ERROR, error: err.message }, null, 2));
335
+ } else {
336
+ console.error(`[ERROR] Crosswalk failure: ${err.message}`);
337
+ }
338
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
339
+ }
340
+ }
341
+
342
+ async function handleDiff(options) {
343
+ try {
344
+ const result = getStatutoryDiff(options);
345
+ if (isJsonMode) {
346
+ console.log(JSON.stringify(result, null, 2));
347
+ process.exit(0);
348
+ }
349
+
350
+ console.log('\n===========================================================================');
351
+ console.log('MUDRAFORGE STATUTORY REGULATORY CHANGELOG & AMENDMENT TRACKER');
352
+ console.log('===========================================================================');
353
+ console.log(`Filter Section: ${result.filterSection || 'ALL SECTIONS'}`);
354
+ console.log(`Filter Since: ${result.filterSince || 'ALL TIME'}`);
355
+ console.log(`Filter Domain: ${result.filterDomain || 'ALL DOMAINS'}`);
356
+ console.log(`Total Amendments: ${result.totalAmendments}`);
357
+
358
+ if (result.amendments.length === 0) {
359
+ console.log('\n[NOTICE] No statutory amendments matched the specified query filters.');
360
+ } else {
361
+ for (const am of result.amendments) {
362
+ console.log(`\n── [${am.id}] ${am.sectionCode} (${am.domain}) ──`);
363
+ console.log(`Title: ${am.title}`);
364
+ console.log(`Effective Date: ${am.effectiveDate} (${am.amendmentType})`);
365
+ console.log(`Governing Statute: ${am.statute}`);
366
+ console.log(`Enacted By: ${am.legalAuthority}`);
367
+ console.log(`Previous Baseline: ${am.previousValue}`);
368
+ console.log(`Amended Baseline: ${am.amendedValue}`);
369
+ console.log(`Summary: ${am.changeSummary}`);
370
+ console.log(`Statutory Impact: ${am.statutoryImpact}`);
371
+ }
372
+ }
373
+
374
+ console.log('───────────────────────────────────────────────────────────────────────────');
375
+ console.log(`[PASS] Statutory diff completed successfully (${result.totalAmendments} amendment(s) found) (Exit 0).\n`);
376
+ process.exit(0);
377
+ } catch (err) {
378
+ if (isJsonMode) {
379
+ console.log(JSON.stringify({ status: 'ERROR', exitCode: STATUTORY_EXIT_CODES.USAGE_ERROR, error: err.message }, null, 2));
380
+ } else {
381
+ console.error(`[ERROR] Statutory diff failure: ${err.message}`);
382
+ }
383
+ process.exit(STATUTORY_EXIT_CODES.USAGE_ERROR);
384
+ }
385
+ }
386
+
99
387
  async function handleCheckUpdate() {
100
388
  try {
101
- console.log('\n[INFO] Checking npm package version against registry.npmjs.org...');
389
+ let pkgUpdate = null;
102
390
  try {
103
- const pkgUpdate = await checkForPackageUpdate({ cacheTtlMs: 0 });
104
- if (pkgUpdate && pkgUpdate.updateAvailable) {
105
- console.log('───────────────────────────────────────────────────────────────────────────');
106
- console.log(`[WARN] New npm package version available: v${pkgUpdate.latestVersion} (installed: v${pkgUpdate.currentVersion})`);
107
- console.log(`Run: npm install @mudraforge/statutory@latest`);
108
- console.log('───────────────────────────────────────────────────────────────────────────');
109
- } else if (pkgUpdate) {
110
- console.log(`[OK] npm package code is up to date (v${pkgUpdate.currentVersion}).`);
111
- }
391
+ pkgUpdate = await checkForPackageUpdate({ cacheTtlMs: 0 });
112
392
  } catch (_) {}
113
393
 
114
- console.log('\n[INFO] Checking OKF knowledge substrate status against Cloudflare edge...');
115
394
  const status = await checkUpdates();
395
+
396
+ if (isJsonMode) {
397
+ console.log(JSON.stringify({
398
+ packageUpdate: pkgUpdate,
399
+ substrateStatus: status
400
+ }, null, 2));
401
+ process.exit(0);
402
+ }
116
403
  console.log('───────────────────────────────────────────────────────────────────────────');
117
404
  console.log(`Local OKF Version: ${status.localVersion}`);
118
405
  console.log(`Latest Edge Version: ${status.latestVersion}`);
@@ -179,6 +466,18 @@ async function handleSync(targetDir) {
179
466
  async function handleBrowse() {
180
467
  const manifest = getLocalManifest();
181
468
 
469
+ if (isJsonMode) {
470
+ console.log(JSON.stringify(manifest ? {
471
+ okfVersion: manifest.okfVersion,
472
+ publishedAt: manifest.publishedAt,
473
+ rootHash: manifest.rootHash,
474
+ totalSections: manifest.totalSections,
475
+ domains: manifest.domains,
476
+ sections: manifest.sections
477
+ } : { okfVersion: null, sections: [] }, null, 2));
478
+ process.exit(0);
479
+ }
480
+
182
481
  console.log('\n===========================================================================');
183
482
  console.log(`OPEN KNOWLEDGE FORMAT (OKF) — LOCAL BROWSER [v${manifest ? manifest.okfVersion : 'Local'}]`);
184
483
  console.log('===========================================================================');
@@ -276,18 +575,28 @@ async function handleLookup(section, asOfDate) {
276
575
  let temporalStatus = 'ACTIVE';
277
576
 
278
577
  if (s) {
279
- console.log(`\n[LOCAL OKF CACHE] Loaded section [${cleanSection}] from disk.`);
578
+ if (!isJsonMode) console.log(`\n[LOCAL OKF CACHE] Loaded section [${cleanSection}] from disk.`);
280
579
  if (asOfDate) {
281
580
  if (asOfDate < s.effectivePeriod.validFrom) temporalStatus = 'PRE_EFFECTIVE';
282
581
  else if (s.effectivePeriod.validTo && asOfDate > s.effectivePeriod.validTo) temporalStatus = 'SUNSET_SUPERSEDED';
283
582
  }
284
583
  } else {
285
- console.log(`\n[EDGE LOOKUP] Querying MudraForge Live Commons for [${cleanSection}]${asOfDate ? ` (as-of: ${asOfDate})` : ''}...`);
584
+ if (!isJsonMode) console.log(`\n[EDGE LOOKUP] Querying MudraForge Live Commons for [${cleanSection}]${asOfDate ? ` (as-of: ${asOfDate})` : ''}...`);
286
585
  const remote = await lookupStatute(cleanSection, { asOfDate });
287
586
  s = remote.statute;
288
587
  temporalStatus = remote.temporalStatus;
289
588
  }
290
589
 
590
+ if (isJsonMode) {
591
+ console.log(JSON.stringify({
592
+ status: 'SUCCESS',
593
+ sectionCode: cleanSection,
594
+ temporalStatus,
595
+ statute: s
596
+ }, null, 2));
597
+ process.exit(0);
598
+ }
599
+
291
600
  console.log('───────────────────────────────────────────────────────────────────────────');
292
601
  console.log(`Section: ${s.statutorySection} (${s.governingStatute})`);
293
602
  console.log(`Title: ${s.title}`);
@@ -317,6 +626,14 @@ async function handleLookup(section, asOfDate) {
317
626
  }
318
627
  console.log('───────────────────────────────────────────────────────────────────────────\n');
319
628
  } catch (err) {
629
+ if (isJsonMode) {
630
+ console.error(JSON.stringify({
631
+ status: 'ERROR',
632
+ error: err.message,
633
+ availableSections: err.availableSections || []
634
+ }, null, 2));
635
+ process.exit(1);
636
+ }
320
637
  console.error(`[ERROR] Lookup failed: ${err.message}`);
321
638
  if (err.availableSections) {
322
639
  console.log(`Available sections: ${err.availableSections.join(', ')}`);
@@ -327,8 +644,13 @@ async function handleLookup(section, asOfDate) {
327
644
 
328
645
  async function handleList() {
329
646
  try {
330
- console.log('\n[INFO] Fetching indexed statutory sections from MudraForge Commons...');
331
647
  const sections = await listSections();
648
+ if (isJsonMode) {
649
+ console.log(JSON.stringify({ sections, total: sections.length }, null, 2));
650
+ process.exit(0);
651
+ }
652
+
653
+ console.log('\n[INFO] Fetching indexed statutory sections from MudraForge Commons...');
332
654
  console.log('───────────────────────────────────────────────────────────────────────────');
333
655
  for (const s of sections) {
334
656
  const displayValidTo = (s.validTo === 'OPEN_ENDED' || s.validTo === '2099-12-31') ? 'In Force' : s.validTo;
@@ -336,6 +658,10 @@ async function handleList() {
336
658
  }
337
659
  console.log('───────────────────────────────────────────────────────────────────────────\n');
338
660
  } catch (err) {
661
+ if (isJsonMode) {
662
+ console.error(JSON.stringify({ status: 'ERROR', error: err.message }, null, 2));
663
+ process.exit(1);
664
+ }
339
665
  console.error(`[ERROR] Failed to list sections: ${err.message}`);
340
666
  process.exit(1);
341
667
  }
@@ -343,6 +669,11 @@ async function handleList() {
343
669
 
344
670
  function handleDecodeId(rawId) {
345
671
  const res = decodeTaxIdentifier(rawId);
672
+ if (isJsonMode) {
673
+ console.log(JSON.stringify(res, null, 2));
674
+ process.exit(res.isValid ? 0 : 1);
675
+ }
676
+
346
677
  console.log('\n===========================================================================');
347
678
  console.log('INDIAN TAX IDENTIFIER DECODER & OFFLINE MOD-36 VALIDATOR');
348
679
  console.log('===========================================================================');
@@ -375,6 +706,10 @@ Usage:
375
706
  npx @mudraforge/statutory <command> [options]
376
707
 
377
708
  Commands:
709
+ doctor [--offline] Run full diagnostic check of runtime, substrate integrity, & edge status
710
+ verify [path] Cryptographically verify OKF substrate authenticity & file integrity
711
+ crosswalk <section> Dual-act 1961 <-> 2025 bridge (earlier of credit vs payment)
712
+ diff Semantic regulatory changelog (--section, --since, --domain)
378
713
  browse Interactively browse local OKF statutory filesystem
379
714
  lookup <section> [date] Look up section details & temporal status (e.g. 194Q 2025-06-01)
380
715
  decode-id <pan_or_gstin> Offline ISO Mod-36 checksum, state name, and PAN entity decoding
@@ -383,6 +718,21 @@ Commands:
383
718
  list List all indexed statutory sections
384
719
  init-skill [path] Install SKILL.md into your agent workspace (defaults to .agents/skills/)
385
720
  help Show this help message
721
+
722
+ Options:
723
+ --credit <YYYY-MM-DD> Date of credit to vendor/payee account in books (used in crosswalk)
724
+ --payment <YYYY-MM-DD> Date of actual payment/disbursement (used in crosswalk)
725
+ --since <YYYY-MM-DD> Filter amendments taking effect on or after date (used in diff)
726
+ --section, -s <section> Filter amendments by section code (used in diff)
727
+ --domain <domain> Filter amendments by statutory domain (used in diff)
728
+ --json, -j Emit clean, machine-parseable JSON to stdout (suppresses banners)
729
+ --offline, -o Bypass outbound network checks (air-gapped / offline environment mode)
730
+
731
+ Exit Code Conventions:
732
+ 0 Success / Verification passed
733
+ 1 Usage or operational error (invalid syntax / parameters)
734
+ 2 Cryptographic authenticity or integrity violation (mismatch/revocation)
735
+ 3 Statutory policy violation (e.g. missing baseline provision)
386
736
  `);
387
737
  }
388
738
 
@@ -3,7 +3,7 @@
3
3
  > **Format Reference**: Inspired by Google's *Data Cards Playbook* and the OpenSSF Project Quality Standards.
4
4
  > **Target Package**: `@mudraforge/statutory` v2.4.0
5
5
  > **Evaluation Mode**: Machine-audited against primary sources, official gazettes, and test fixtures.
6
- > **Generated Timestamp**: 2026-10-24T15:20:46.069Z
6
+ > **Generated Timestamp**: 2026-10-25T14:51:51.929Z
7
7
 
8
8
  ---
9
9
 
@@ -11,11 +11,11 @@
11
11
 
12
12
  | Dimension | Metric | Denominator / Baseline | Coverage Rate | Status |
13
13
  | :--- | :--- | :--- | :--- | :--- |
14
- | **Primary Source Citations** | 30 resolvable gazette URLs | 30 total citations declared | **100.0%** | VERIFIED |
15
- | **Temporal Validity Bounds** | 11 sections with explicit dates | 11 total bundled sections | **100.0%** | VERIFIED |
16
- | **Dual-Act 2025 Transition Bridges** | 6 direct tax provisions mapped | 7 direct tax provisions | **85.7%** | VERIFIED |
17
- | **Attached Administrative Circulars** | 11 official circulars | 6 sections across 4 domains | **100% Attached** | VERIFIED |
18
- | **Attached Return/Compliance Schemas** | 14 schemas/templates | 6 sections across 4 domains | **100% Attached** | VERIFIED |
14
+ | **Primary Source Citations** | 61 resolvable gazette URLs | 61 total citations declared | **100.0%** | VERIFIED |
15
+ | **Temporal Validity Bounds** | 24 sections with explicit dates | 24 total bundled sections | **100.0%** | VERIFIED |
16
+ | **Dual-Act 2025 Transition Bridges** | 8 direct tax provisions mapped | 9 direct tax provisions | **88.9%** | VERIFIED |
17
+ | **Attached Administrative Circulars** | 25 official circulars | 6 sections across 4 domains | **100% Attached** | VERIFIED |
18
+ | **Attached Return/Compliance Schemas** | 22 schemas/templates | 6 sections across 4 domains | **100% Attached** | VERIFIED |
19
19
  | **Cryptographic Merkle Verification** | 20 bundle files verified | SHA-256 Merkle root digest | **0 Mismatches** | VERIFIED |
20
20
 
21
21
  ---
@@ -49,16 +49,29 @@
49
49
  | Section Code | Statutory Provision | Governing Statute | Temporal Window | Status | Citations | Circulars | Forms | 2025 Act Successor |
50
50
  | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
51
51
  | **50B** | Special provision for computation of capital gains in case of slump sale | Income-tax Act, 1961 (Act No. 43 of 1961) | `2000-04-01` to `OPEN_ENDED` | `ACTIVE` | 3 | 2 | 2 | Income-tax Act, 2025 (Section 78 (Capital gains on slump sale of undertakings)) |
52
+ | **206AB** | Special provision for deduction of tax at source for non-filers of income-tax return | Income-tax Act, 1961 (Act No. 43 of 1961) | `2021-07-01` to `OPEN_ENDED` | `ACTIVE` | 1 | 1 | 0 | Income-tax Act, 2025 (Section 397(3)) |
52
53
  | **206C(1H)** | Collection of tax at source by seller on receipt of consideration for sale of goods (Omitted effective 1 April 2025) | Income-tax Act, 1961 | `2020-10-01` to `2025-03-31` | `SUNSET_SUPERSEDED` | 2 | 1 | 0 | Finance Act, 2025 (Statutory Sunset) (Section 206C(1H) Omitted) |
53
54
  | **194H** | Deduction of tax at source on commission or brokerage | Income-tax Act, 1961 (Act No. 43 of 1961) | `2001-06-01` to `2026-03-31` | `SUNSET_SUPERSEDED` | 3 | 1 | 1 | Income-tax Act, 2025 (Section 393(1), Table 4, Item (i)) |
54
55
  | **194C** | Deduction of tax at source on payments to contractors and sub-contractors | Income-tax Act, 1961 (Act No. 43 of 1961) | `1972-04-01` to `2026-03-31` | `SUNSET_SUPERSEDED` | 3 | 1 | 2 | Income-tax Act, 2025 (Section 393(1), Table 3, Item (i)) |
55
56
  | **194Q** | Deduction of tax at source on payment of a certain sum for purchase of goods | Income-tax Act, 1961 (Act No. 43 of 1961) | `2021-07-01` to `2026-03-31` | `SUNSET_SUPERSEDED` | 2 | 2 | 2 | Income-tax Act, 2025 (Section 393(1), Table 8, Item (ii)) |
56
57
  | **393** | Deduction of tax at source on payment of a certain sum for purchase of goods | Income-tax Act, 2025 (Act No. 1 of 2025) | `2026-04-01` to `OPEN_ENDED` | `ACTIVE` | 3 | 0 | 0 | N/A |
58
+ | **194R** | Deduction of tax at source on benefit or perquisite in respect of business or profession | Income-tax Act, 1961 (Act No. 43 of 1961) | `2022-07-01` to `OPEN_ENDED` | `ACTIVE` | 2 | 1 | 0 | Income-tax Act, 2025 (Section 393(1), Table 8, Item 12) |
57
59
  | **194I** | Deduction of tax at source on payment of rent | Income-tax Act, 1961 (Act No. 43 of 1961) | `1994-06-01` to `2026-03-31` | `SUNSET_SUPERSEDED` | 3 | 1 | 1 | Income-tax Act, 2025 (Section 393(1), Table 5, Item (i)) |
58
60
  | **194J** | Fees for professional or technical services, royalty, and non-compete fees | Income-tax Act, 1961 | `1995-07-01` to `2026-03-31` | `SUNSET_SUPERSEDED` | 2 | 1 | 1 | Income-tax Act, 2025 (Section 393(1), Table 6, Item (iii)) |
59
61
  | **17(5)** | Apportionment of credit and blocked input tax credits | Central Goods and Services Tax Act, 2017 (Act No. 12 of 2017) | `2017-07-01` to `OPEN_ENDED` | `ACTIVE` | 3 | 1 | 1 | CGST Act, 2017 (In force) (Section 17(5)(b)(i) & (b)(iii)) |
62
+ | **8** | Tax liability on composite and mixed supplies and classification of bundled goods and services contracts | Central Goods and Services Tax Act, 2017 | `2017-07-01` to `OPEN_ENDED` | `ACTIVE` | 3 | 1 | 1 | N/A |
63
+ | **10** | Composition levy and ineligible tax invoice restrictions | Central Goods and Services Tax Act, 2017 (Act No. 12 of 2017) | `2017-07-01` to `OPEN_ENDED` | `ACTIVE` | 2 | 1 | 0 | N/A |
64
+ | **34** | Credit and debit notes statutory adjustments and return filing deadlines | Central Goods and Services Tax Act, 2017 (Act No. 12 of 2017) | `2017-07-01` to `OPEN_ENDED` | `ACTIVE` | 2 | 1 | 0 | N/A |
65
+ | **RULE-48(4)** | Mandatory electronic invoicing (E-Invoicing), IRN generation, and invoice validity | Central Goods and Services Tax Rules, 2017 | `2020-10-01` to `OPEN_ENDED` | `ACTIVE` | 2 | 1 | 0 | N/A |
66
+ | **51** | Tax deduction at source under Goods and Services Tax | Central Goods and Services Tax Act, 2017 (Act No. 12 of 2017) | `2018-10-01` to `OPEN_ENDED` | `ACTIVE` | 2 | 1 | 0 | N/A |
67
+ | **16(2)** | Eligibility and conditions for taking input tax credit and mandatory 180-day payment rule | Central Goods and Services Tax Act, 2017 (Act No. 12 of 2017) | `2017-07-01` to `OPEN_ENDED` | `ACTIVE` | 4 | 1 | 1 | CGST Act, 2017 (In force) (Section 16(2), (3), (4), (5), (6)) |
68
+ | **9(3)** | Reverse Charge Mechanism (RCM) mandatory tax liability on recipient, self-invoicing, payment voucher issuance, and electronic cash discharge | Central Goods and Services Tax Act, 2017 read with Notification No. 13/2017-Central Tax (Rate) | `2017-07-01` to `OPEN_ENDED` | `ACTIVE` | 3 | 1 | 1 | N/A |
69
+ | **195** | Deduction of tax at source on foreign cross-border payments to non-residents, DTAA treaty benefits, documentation, Form 15CA/15CB, and cloud software exemption | Income-tax Act, 1961 read with Double Taxation Avoidance Agreements (DTAA) under Section 90 | `1962-04-01` to `OPEN_ENDED` | `ACTIVE` | 3 | 2 | 1 | Income-tax Act, 2025 Section 393(2) (Section 393(2) of Income-tax Act, 2025) |
60
70
  | **IRC-901-904** | Foreign Tax Credit authorization, separate basket limitation, and partnership pass-through reporting (Form 1116 / Schedule K-3) | Internal Revenue Code of 1986 (Title 26, U.S. Code) | `2021-01-01` to `OPEN_ENDED` | `ACTIVE` | 2 | 0 | 2 | Title 26, U.S. Code (Continuous) (26 U.S.C. §§ 901, 904(d), 904(j), 469) |
61
71
  | **MSMED-15-16** | Statutory payment timelines to Micro & Small Enterprises, compound penal interest, and income tax deduction disallowance | Micro, Small and Medium Enterprises Development Act, 2006 read with Income-tax Act, 1961 Section 43B(h) | `2006-10-02` to `OPEN_ENDED` | `ACTIVE` | 4 | 1 | 2 | Income-tax Act, 2025 Section 37(2)(g) (Section 37(2)(g) of Income-tax Act, 2025) |
72
+ | **MSMED-SEC-7** | Composite criteria for classification of Micro, Small and Medium Enterprises, investment calculations, and statutory exclusion of export turnover | Micro, Small and Medium Enterprises Development Act, 2006 read with Ministry of MSME Notification S.O. 2119(E) | `2020-07-01` to `OPEN_ENDED` | `ACTIVE` | 2 | 1 | 1 | N/A |
73
+ | **MCA-MSME-1** | Mandatory half-yearly reporting of outstanding dues exceeding 45 days to Micro & Small Enterprises (Form MSME-1) | Companies Act, 2013 read with Specified Companies (Furnishing of information about payment to micro and small enterprise suppliers) Order, 2019 | `2019-01-22` to `OPEN_ENDED` | `ACTIVE` | 2 | 1 | 1 | N/A |
74
+ | **MSMED-SEC-22** | Mandatory statutory disclosures in annual audited financial statements regarding dues to Micro and Small Enterprises and tax non-deductibility of penal interest | Micro, Small and Medium Enterprises Development Act, 2006 read with Companies Act, 2013 Schedule III | `2006-10-02` to `OPEN_ENDED` | `ACTIVE` | 3 | 1 | 2 | N/A |
62
75
 
63
76
  ---
64
77
 
@@ -0,0 +1,33 @@
1
+ # Published Release & Provenance Ledger
2
+
3
+ This document records the cryptographic provenance, normative specifications, and formal assurance artifacts for `@mudraforge/statutory`.
4
+
5
+ ---
6
+
7
+ ## Release Baseline Ledger
8
+
9
+ | Item | Value |
10
+ |---|---|
11
+ | **Package Release** | **`v2.8.0`** (Stable Minor Release) |
12
+ | **Knowledge Specification** | **Google Open Knowledge Format (OKF v0.2) + MudraForge Statutory Schema Extension** |
13
+ | **Regulatory Snapshot** | **CBDT / CBIC / MCA / MSME Baseline: October 2026** |
14
+ | **Corpus Quality Card** | 100% Citation Resolution (15/15 URLs) in [`docs/CORPUS_QUALITY.md`](./CORPUS_QUALITY.md) |
15
+ | **Architecture Decision Records** | 6 Normative ADRs documented in [`docs/ARCHITECTURE_DECISIONS.md`](./ARCHITECTURE_DECISIONS.md) |
16
+ | **Vendor Conformance Suite** | 12/12 Passing Fixture Tests in [`conformance/`](../conformance/) |
17
+ | **End-to-End Execution Trace** | Audited 7-stage AP lifecycle in [`examples/`](../examples/) (`npm run example:trace`) |
18
+ | **Enterprise Assurance Preview** | Formal TLA+ & mutation defenses in [`docs/ADESHA_ASSURANCE_OVERVIEW.md`](./ADESHA_ASSURANCE_OVERVIEW.md) |
19
+ | **Integrity Root** | SHA-256 root manifest in [`okf/manifest.json`](../okf/manifest.json) (reproducible byte-level non-tampering proof) |
20
+ | **Temporal Framework** | Dual-Act Bridge: *Income-tax Act, 1961* & *Income-tax Act, 2025* |
21
+ | **Verification Gate** | 100% Pass across cumulative thresholds, legislative sunsets, and excess math |
22
+
23
+ ---
24
+
25
+ ## Cryptographic & Epistemic Scope
26
+
27
+ The SHA-256 root hash in `okf/manifest.json` provides mathematical verification of **byte-level integrity** (ensuring local files have not been corrupted, altered, or partially written). A hash certifies that bytes match the published release; it does not by itself constitute legal or statutory authority.
28
+
29
+ Epistemic authority is established strictly via:
30
+ 1. Primary gazette citations and statutory text enacted by Parliament.
31
+ 2. Executive circulars and notifications issued by the CBDT, CBIC, MCA, and Ministry of MSME.
32
+ 3. Cryptographic Ed25519 signatures anchored to the MudraForge Root Authority.
33
+ 4. Independent legal ground-truth test suites parameterizing effective dates and cumulative turnover thresholds.
package/okf/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "okfVersion": "2.6.0",
2
+ "okfVersion": "2.8.0",
3
3
  "publishedAt": "2026-10-25T09:18:32.261Z",
4
4
  "rootHash": "sha256-ce88c2255df1c30c15bfe184c8117336ebc302c2ac5ef25e96a6957402ae11ae",
5
5
  "totalSections": 24,
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://okf.dev/schema/v0.2/publication.json",
3
3
  "publicationId": "mudraforge-statutory-commons",
4
4
  "title": "MudraForge Statutory Knowledge Substrate (India & Cross-Border)",
5
- "version": "2.4.0",
5
+ "version": "2.8.0",
6
6
  "lifecycle": "PUBLIC_BETA",
7
7
  "specification": "OKF-0.2",
8
8
  "publisher": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mudraforge/statutory",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "description": "Open Knowledge Format (OKF) client & AI Agent Skill for Indian and cross-border statutory tax provisions. Zero dependencies.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -33,7 +33,8 @@
33
33
  "example:trace": "node examples/simulate_end_to_end_trace.js",
34
34
  "manifest": "node scripts/generate_manifest.js",
35
35
  "manifest:check": "node scripts/generate_manifest.js --check",
36
- "catalog": "node scripts/build_catalog.js"
36
+ "catalog": "node scripts/build_catalog.js",
37
+ "release": "node scripts/release.js"
37
38
  },
38
39
  "repository": {
39
40
  "type": "git",