<?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: Murtaza haider</title>
    <description>The latest articles on DEV Community by Murtaza haider (@murtaza_haider_27f3707039).</description>
    <link>https://dev.to/murtaza_haider_27f3707039</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%2F4012520%2F0e344a9e-70d8-488f-9909-3396753ab9a1.jpg</url>
      <title>DEV Community: Murtaza haider</title>
      <link>https://dev.to/murtaza_haider_27f3707039</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/murtaza_haider_27f3707039"/>
    <language>en</language>
    <item>
      <title>How I Built an Anti-Fabrication Rule into Our CV Analysis Tool</title>
      <dc:creator>Murtaza haider</dc:creator>
      <pubDate>Thu, 02 Jul 2026 16:03:47 +0000</pubDate>
      <link>https://dev.to/murtaza_haider_27f3707039/how-i-built-an-anti-fabrication-rule-into-our-cv-analysis-tool-5f8k</link>
      <guid>https://dev.to/murtaza_haider_27f3707039/how-i-built-an-anti-fabrication-rule-into-our-cv-analysis-tool-5f8k</guid>
      <description>&lt;p&gt;When you build a tool that analyses CVs against job descriptions, one failure mode keeps you up at night: what if the system treats the job description as evidence about the candidate?&lt;/p&gt;

&lt;p&gt;It sounds obvious. Of course a job ad saying "must have Python experience" shouldn't become evidence that the candidate has Python experience. But when you're building matching logic that ingests both a CV and a JD, that boundary is easier to cross than you'd think — especially if you're using embeddings or similarity scores that don't distinguish the source of a piece of text.&lt;/p&gt;

&lt;p&gt;I built Wallbreak (&lt;a href="https://wallbreak.co.uk" rel="noopener noreferrer"&gt;https://wallbreak.co.uk&lt;/a&gt;), a UK job-search tool with CV analysis. Before I built any of the matching logic, I wrote what I called Gate B.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Gate B actually is
&lt;/h2&gt;

&lt;p&gt;Gate B is a hard rule in the analysis pipeline: job-description content cannot be promoted to candidate evidence. Ever.&lt;/p&gt;

&lt;p&gt;In practice, this means the analysis pipeline maintains two strictly separate stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;candidate_evidence&lt;/code&gt;: populated only from the CV the user uploads&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jd_requirements&lt;/code&gt;: populated only from the job description the user provides&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the matching logic runs, it compares these two stores against each other. It never reads from &lt;code&gt;jd_requirements&lt;/code&gt; to fill a gap in &lt;code&gt;candidate_evidence&lt;/code&gt;. A gap is a gap — it's surfaced as "your CV doesn't yet show this," not silently filled with requirement text.&lt;/p&gt;

&lt;p&gt;This sounds simple. But maintaining it required being explicit about data flow at every layer of the pipeline. Every function that writes to &lt;code&gt;candidate_evidence&lt;/code&gt; has to declare its source. If the source isn't the candidate's own CV, the write is rejected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why deterministic rules instead of embeddings
&lt;/h2&gt;

&lt;p&gt;Most CV analysis tools use similarity scoring: embed the CV, embed the JD, compute cosine similarity, output a percentage. The problem is that this is opaque. A 73% match score doesn't tell you what's missing. It doesn't tell you which specific criteria you do and don't evidence. And it's easy to game — put enough keywords in a CV and the score improves regardless of actual experience.&lt;/p&gt;

&lt;p&gt;I chose deterministic rule sets instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ATS readability: structured checks for common ATS failure patterns (tables, graphics, non-standard headings, missing contact fields)&lt;/li&gt;
&lt;li&gt;UK formatting: checks for UK-specific norms (no photo, no date of birth, 2-page norm, reverse-chronological order)&lt;/li&gt;
&lt;li&gt;STAR-pattern evidence: checks whether work history items follow a Situation-Task-Action-Result structure or read as a list of duties&lt;/li&gt;
&lt;li&gt;Target-role alignment: checks whether the candidate's evidence uses the same language as the role's essential criteria&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each rule produces a yes/no or a specific gap. The output is a list of findings, not a single score. You can read each finding, understand exactly what triggered it, and fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for trust
&lt;/h2&gt;

&lt;p&gt;The CV analysis is honest about what it can and can't know. It can tell you whether your CV has a STAR-pattern evidence gap for "project management." It can't tell you whether you're actually good at project management — and it doesn't try to.&lt;/p&gt;

&lt;p&gt;This is a product decision as much as a technical one. I think the job-search tool market has a credibility problem because too many tools make claims that sound authoritative but can't be substantiated. "You're a 91% match" sounds precise. It isn't.&lt;/p&gt;

&lt;p&gt;If you're building anything in this space, I'd encourage you to think carefully about what your tool actually knows versus what it's inferring. The distinction matters more than it might seem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;The backend is Python/FastAPI deployed on Railway. The CV parsing goes through a structured extraction layer before any analysis runs — that's also where Gate B is enforced. The frontend is React/Vite on Vercel.&lt;/p&gt;

&lt;p&gt;The product is in beta. The analysis is not a trained model. AI features may have usage limits; pricing is not yet finalised. Feedback from builders is genuinely useful right now, particularly on the rule logic and where the gap explanations are or aren't helpful.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I'm the founder of Wallbreak. This is a first-person account of technical decisions I made. I'm not paid to write this and I have an obvious stake.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>python</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
