<?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: Olga Dimitrova</title>
    <description>The latest articles on DEV Community by Olga Dimitrova (@olgadimitrova).</description>
    <link>https://dev.to/olgadimitrova</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%2F4147933%2Fb51b277d-ee9a-4636-94aa-921038a31c08.png</url>
      <title>DEV Community: Olga Dimitrova</title>
      <link>https://dev.to/olgadimitrova</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olgadimitrova"/>
    <language>en</language>
    <item>
      <title>Why a pay-gap cost calculator should make zero network calls</title>
      <dc:creator>Olga Dimitrova</dc:creator>
      <pubDate>Wed, 30 Sep 2026 03:47:06 +0000</pubDate>
      <link>https://dev.to/olgadimitrova/why-a-pay-gap-cost-calculator-should-make-zero-network-calls-2n38</link>
      <guid>https://dev.to/olgadimitrova/why-a-pay-gap-cost-calculator-should-make-zero-network-calls-2n38</guid>
      <description>&lt;p&gt;I maintain a small open-source calculator that prices what it costs to close an unexplained gender pay gap under the EU Pay Transparency Directive (2023/970). You give it a CSV of employees (salary, gender, grade, tenure, category), and it prices two options: minimum compliance and full equalisation. It ships as a static HTML page and, separately, as an Excel workbook with the same calculation in live formulas.&lt;/p&gt;

&lt;p&gt;The page makes no network requests at all. It doesn't promise to skip logging or to encrypt your data on a server, because there is no server. Open the browser's Network tab while you use it and it stays empty. Most of the design follows from that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The input is some of the most sensitive data a company holds
&lt;/h2&gt;

&lt;p&gt;A pay-gap calculation needs individual salaries by gender, category, grade and tenure. Most HR and reward teams would rather not let that leave the company, even briefly, even to a vendor with a data processing agreement and a SOC 2 report. A web app that uploads the CSV to a server asks every user to trust a company they have probably never audited, for a calculation their laptop does in milliseconds.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;index.html&lt;/code&gt; is the whole application. HTML, CSS and JavaScript sit in one file. There is no build step to run it and no backend to operate or patch, and nobody's salary file ends up on a server.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "no network calls" requires in practice
&lt;/h2&gt;

&lt;p&gt;"Runs in your browser" is easy to say. Keeping it true means giving up a few conveniences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No CDN for fonts or libraries. A dependency is either vendored into the file or not used. The chart is plain SVG, not a charting library.&lt;/li&gt;
&lt;li&gt;No analytics, error reporting or telemetry, including the "just to see if people use it" kind. Each of those is a network call.&lt;/li&gt;
&lt;li&gt;The CSV comes in through an &lt;code&gt;&amp;lt;input type="file"&amp;gt;&lt;/code&gt; and is read into memory with the FileReader API. The page computes the result, and the data is gone on refresh. Nothing is written anywhere unless the user downloads a result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The repo has two checks for this. &lt;code&gt;check-render.js&lt;/code&gt; scans the built page and fails (exit 1) if it references any external script, stylesheet or image. &lt;code&gt;check-meta.js&lt;/code&gt; opens the page in headless Chrome, records every network request made while it loads, and fails (exit 1) if there is even one. Without a test that can fail, "no network calls" only means "no network calls that we noticed."&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Excel workbook exists
&lt;/h2&gt;

&lt;p&gt;If you can't read JavaScript, the web page is hard to verify. Without developer tools, how do you see what it does with your data? So the same calculation also exists as an Excel workbook, all in live formulas: medians by rank, and the OLS regression written out with explicit sums and Cramer's rule instead of an array formula or a macro. Click a cell, read the formula, change an input and watch every downstream number move. There is no VBA and nothing hidden behind a button.&lt;/p&gt;

&lt;p&gt;I cross-checked the web version, the workbook and a third, independent Python port on the demo dataset, and they agree to 1e-9. The port is in the repo at &lt;code&gt;pay-gap-calculator/build/excel/reference_calc.py&lt;/code&gt;. It follows &lt;code&gt;pay-gap-calculator/build/calc.js&lt;/code&gt; step by step in a different language and prints every category, so you can rerun the comparison yourself instead of taking the README's word for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this doesn't solve
&lt;/h2&gt;

&lt;p&gt;Open source and zero network calls answer "can I trust this with my data." They don't answer "is this the right method." The calculator prices the unexplained residual after controlling for grade and tenure (OLS) and remediates only that residual. It doesn't decide whether a gap is lawful, and it doesn't group work of equal value into categories for you. Categories too small to be statistically reliable get flagged rather than hidden. Those are choices, and someone else building the same tool could reasonably make different ones. Whether your salary data should touch a server to find out is a separate question, and I think it has one answer.&lt;/p&gt;

&lt;p&gt;Repo, workbook, sample CSV and the checks: &lt;a href="https://github.com/OlgaDimitrovaGit/comp-budget-lab/tree/main/pay-gap-calculator" rel="noopener noreferrer"&gt;https://github.com/OlgaDimitrovaGit/comp-budget-lab/tree/main/pay-gap-calculator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>hr</category>
      <category>privacy</category>
    </item>
  </channel>
</rss>
