<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vishal Mundewadi</title>
    <description>The latest articles on DEV Community by Vishal Mundewadi (@vishal_mundewadi_56l).</description>
    <link>https://dev.to/vishal_mundewadi_56l</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4191611%2F54aceae8-fef3-437e-81dc-747c32940d5a.jpeg</url>
      <title>DEV Community: Vishal Mundewadi</title>
      <link>https://dev.to/vishal_mundewadi_56l</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vishal_mundewadi_56l"/>
    <language>en</language>
    <item>
      <title>Building a Payment Reconciliation Engine That Catches Fee Mismatches and Settlement Errors</title>
      <dc:creator>Vishal Mundewadi</dc:creator>
      <pubDate>Sun, 18 Oct 2026 07:16:17 +0000</pubDate>
      <link>https://dev.to/vishal_mundewadi_56l/building-a-payment-reconciliation-engine-that-catches-fee-mismatches-and-settlement-errors-3icl</link>
      <guid>https://dev.to/vishal_mundewadi_56l/building-a-payment-reconciliation-engine-that-catches-fee-mismatches-and-settlement-errors-3icl</guid>
      <description>&lt;p&gt;Every payment company has the same quiet problem: the money a customer paid, the fee that was charged, and the amount that finally settled to the merchant should all agree. When they don't, someone has to find out why, and that someone is usually looking through spreadsheets.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;AI Finance Controller&lt;/strong&gt;, a reconciliation engine that checks payments automatically and flags settlement discrepancies, fee mismatches, and payment lifecycle anomalies. On my adversarial validation datasets it reached &lt;strong&gt;100% precision and 93.7% recall&lt;/strong&gt;. This post covers how it works and how I tested it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What goes wrong in payment reconciliation
&lt;/h2&gt;

&lt;p&gt;A single payment passes through several states: created, authorized, captured, settled, and sometimes refunded. Errors appear in a few common ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fee mismatches:&lt;/strong&gt; the fee charged is not what the fee schedule says it should be.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Settlement discrepancies:&lt;/strong&gt; the amount settled to the merchant doesn't match the sum of the transactions it covers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle anomalies:&lt;/strong&gt; a payment skips a state, such as being settled without ever being captured, or is refunded twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[Replace with the exact anomaly types your rules cover, and delete any of the above that you didn't implement.]&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I used deterministic rules, not a model
&lt;/h2&gt;

&lt;p&gt;In finance, every flag has to be explainable. If a system tells an accountant that a transaction is wrong, the next question is "why?" A rule like "fee charged 2.4% but the schedule says 2.0%" answers it. A probability score doesn't.&lt;/p&gt;

&lt;p&gt;So I built the validation layer from &lt;strong&gt;deterministic rules&lt;/strong&gt;. Each rule checks one specific invariant, and each flag comes with the rule that raised it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The system is a set of small FastAPI services, each with one job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ingestion service:&lt;/strong&gt; accepts payment and settlement records through REST endpoints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation service:&lt;/strong&gt; runs the rule set against matched records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reporting:&lt;/strong&gt; returns flagged anomalies with the reason for each&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used a microservice layout so that rules can change without touching ingestion, and each service can be tested on its own. Everything is containerized with Docker, so the whole system starts the same way on any machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  A rule, in code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_fee_mismatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fee_schedule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fee_schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fee_charged&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tolerance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Anomaly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;payment_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FEE_MISMATCH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;charged &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fee_charged&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, expected &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[Replace with a short rule from your actual code.]&lt;/p&gt;

&lt;h2&gt;
  
  
  How I tested it
&lt;/h2&gt;

&lt;p&gt;Easy test data would only prove that the rules work on easy cases. So I built &lt;strong&gt;adversarial validation datasets&lt;/strong&gt;: records designed to be hard, with [describe yours, e.g. fees off by one paisa, partial settlements, out-of-order lifecycle events, duplicate refunds]. Each record is labeled with whether it is a real anomaly, so I can measure results exactly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Precision&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recall&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;93.7%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dataset size&lt;/td&gt;
&lt;td&gt;[N records, M injected anomalies]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In plain terms: every transaction the system flagged really was an anomaly (no false alarms), and it caught 93.7% of the anomalies I planted.&lt;/p&gt;

&lt;p&gt;In reconciliation, I'd rather have that than the reverse. A system that raises false alarms trains people to ignore it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6.3% I missed
&lt;/h2&gt;

&lt;p&gt;Recall of 93.7% means some anomalies got through. Looking at the missed cases was the most useful part of the project&lt;/p&gt;

&lt;p&gt;I covered these edge cases with functional and regression tests so that once a case is fixed, it stays fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/vishal-mundewadi/ai-finance-controller" rel="noopener noreferrer"&gt;https://github.com/vishal-mundewadi/ai-finance-controller&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live demo: &lt;a href="https://ai-finance-controller-ebon.vercel.app" rel="noopener noreferrer"&gt;https://ai-finance-controller-ebon.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you work on payments or finance operations and see edge cases I've missed, I'd like to hear about them in the comments.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building Access Learn AI: Turning Lectures into Text, Summaries, Audio and Braille</title>
      <dc:creator>Vishal Mundewadi</dc:creator>
      <pubDate>Sun, 18 Oct 2026 07:05:04 +0000</pubDate>
      <link>https://dev.to/vishal_mundewadi_56l/building-access-learn-ai-turning-lectures-into-text-summaries-audio-and-braille-4a8k</link>
      <guid>https://dev.to/vishal_mundewadi_56l/building-access-learn-ai-turning-lectures-into-text-summaries-audio-and-braille-4a8k</guid>
      <description>&lt;p&gt;A lecture is one of the most common ways we learn, and one of the least accessible. A student who is deaf can't follow the audio. A student who is blind can't read the slides. A student with a cognitive or attention difficulty may struggle with a 60-minute recording and no summary.&lt;/p&gt;

&lt;p&gt;Accessibility tools exist for each of these problems, but they are usually separate products. I wanted to see how far one pipeline could go, so I built &lt;strong&gt;AccessLearnAI&lt;/strong&gt;: upload a lecture, and get back a transcript, a concise summary, spoken audio, and Braille output.&lt;/p&gt;

&lt;p&gt;This post covers how it's built, the problems I ran into, and what I'd change.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea
&lt;/h2&gt;

&lt;p&gt;Students need different formats of the same content. So instead of building one feature per disability, I built one pipeline that produces every format from a single input:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Whisper (speech to text) → T5 (summarization) → edge-tts (text to speech) → Braille generation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each stage feeds the next:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Whisper&lt;/strong&gt; transcribes the lecture audio. I chose it because it is open source and holds up well on varied accents and recording quality, which matters for real classroom audio.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;T5&lt;/strong&gt; condenses the transcript into a short summary, so a student can review a lecture in minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;edge-tts&lt;/strong&gt; converts the summary back to natural-sounding speech for students who prefer to listen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Braille generation&lt;/strong&gt; converts the text into Braille for blind and low-vision users.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The system is split into three layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend: Fast API with PostgreSQL for storage&lt;/li&gt;
&lt;li&gt;Frontend: React with TypeScript&lt;/li&gt;
&lt;li&gt;Deployment: Docker containers on GCP, with the frontend on Vercel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used Fast API because the ML code is in Python, and it let me expose each pipeline stage as a clean API endpoint without a translation layer between the models and the web service.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard part: running four models on a free tier
&lt;/h2&gt;

&lt;p&gt;The pipeline works fine on a development machine. Production was a different problem.&lt;/p&gt;

&lt;p&gt;When I deployed the backend to Render's free tier, it kept running out of memory. The cause was that Whisper and T5 were both loaded into memory at the same time, and together they went over the free tier's limit.&lt;/p&gt;

&lt;p&gt;This was a useful lesson &lt;br&gt;
A model that works locally can still be unusable in production because of resource limits. Deploying an ML system means managing memory as carefully as you manage code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Code: &lt;a href="https://github.com/vishal-mundewadi/AccessLearnAI" rel="noopener noreferrer"&gt;https://github.com/vishal-mundewadi/AccessLearnAI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live demo: &lt;a href="https://access-learn-ai-seven.vercel.app" rel="noopener noreferrer"&gt;https://access-learn-ai-seven.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
