Skip to content
Ritesh FirodiyaGet in touch

Work / Chitragupt / Wiki / Concepts

tax-recompute-engine

Conceptcanonicalverified 2026-07-12

CONCEPT.TAX-RECOMPUTE-ENGINE

Summary

The tax recompute engine is a single-pass, both-regime, statute-driven pipeline that turns confirmed ledger entries into the persisted tax_reviews/{ay} document read by the Tax Review pages.

Why it matters

Every tax number a user sees — the four-state hero (refund / owe / clear / incomplete), the recommended regime, the composition donut, the 15-Q Quick Check state — traces back to one call to runMode1ForAY in packages/shared/src/rules/v1/orchestrator.ts. When the engine is wrong, every user sees the same wrong tax; when it's right, staleness is bounded by the drain scheduler (user-identity-entry).

The July 2026 audit closed 30+ statute-correctness bugs across the tax pillar. Documenting the engine's shape here so subsequent audits can find and fix new bugs without re-deriving the pipeline.

Implications

  • AY tables are the single source of truth for statute values. Slab rates, §87A rebate, surcharge bands, cess, capital-gains sub-rules, §80CCD(2) caps, §71 loss-set-off cap, §80G donee-driven math, regime-recommendation thresholds, NRI basic exemption — all cells live in packages/shared/src/data/tax-tables/ay-*.ts. Zero statute values may be hardcoded in engine code.
  • Both regimes compute in one pass; recommendation picks the winner. runMode1ForAY calls computeTax twice (old / new) with the same inputs; the recommendation is the cheaper one. The recommendation_reason string is table-thresholded (see 2026-07-12-real-80g-donee-category-math for the pattern).
  • Position credits = TDS + advance-tax + self-assessment challans. The pre-Phase-2 engine only credited TDS. Challan credits come from the advance_tax_challan + self_assessment_challan ledger buckets.
  • §234A/B/C interest is stamped on Position. See 2026-07-12-234abc-interest-and-hra-min-of-three.
  • HRA is validated by min-of-three, not taken verbatim from Form 16. Same ADR.
  • Debt-MF gains route through their own tax buckets. See 2026-07-12-debt-mf-treated-independently-of-equity-cg.
  • Ledger AY comes from the transaction date, not the document. See 2026-07-12-per-txn-ay-bucketing-for-expense-ledger.
  • Position dedup on portfolio side. See 2026-07-12-portfolio-position-dedup.

Pipeline (per-AY)

  1. summariseIncome — aggregates ledger entries by bucket (salary / rental / CG / VDA / §80C / §80D / §80CCD(2) / §24(b) self+let-out / HRA inputs / advance-tax / etc.).
  2. applySalarySlipFallback — if no Form 16 for the AY but slips exist, annualises by distinct-month count from txn_date.
  3. applyHraValidation — overrides Form-16 HRA with §10(13A) min-of-three when basic salary + rent paid are known.
  4. capsFromTable — per-section Chapter VI-A caps (age-aware).
  5. chapterVIABreakdown — applies caps + §80G donee math + §80C aggregate with §80CCC + §80CCD(1).
  6. computeTax(regime: "old") + computeTax(regime: "new") — each applies standard deduction, §24(b) split (self-occupied vs let-out with regime-specific rules), §71 HP-loss cap, §80CCD(2) employer NPS, slab tax with NRI awareness, §111A/§112A equity CG, debt-MF split CG, §115BBH VDA, §87A rebate (with total-income ceiling that includes VDA + debt-MF), surcharge with marginal relief, cess.
  7. Position, composition, TDS reconciliation, per-Q quick_check.
  8. computeInterest234ForReview — §234A/B/C on the recommended tax.
  9. Return TaxReview. Persister writes to Firestore.

Related

Sources

  • packages/shared/src/rules/v1/orchestrator.ts — the entry point.
  • packages/shared/src/rules/v1/tax-computer.ts — the per-regime compute.
  • packages/shared/src/rules/v1/income-summary.ts — the aggregator.
  • packages/shared/src/rules/v1/hra-exemption.ts — §10(13A) min-of-three.
  • packages/shared/src/rules/v1/interest-234.ts — §234A/B/C.
  • packages/shared/src/data/tax-tables/schema.ts + ay-*.ts — the statute cell store.

Every project of mine is written down like this.

Read the résumé