2
6 Comments

Built a claim-level fact-checker into our AI rewrite tools — here's how it actually works

Shipping something this week I think this group will find interesting: a fact-check + auto-fix step across 19 of our AI writing tools (paraphrase, humanize, grammar fix, tone, translate, etc).

The problem: any AI rewrite can quietly change what the text actually claims, not just how it sounds. Ran a real test fed in a paragraph with a specific stat, a hedge ("preliminary result, more time needed"), and a specific team size. Asked for a cleaner rewrite. The stat survived. The hedge became a flat claim of proof. The team size changed and picked up a timeline that was never mentioned. Nothing about the output looked wrong it read like clean, confident writing.

How the check works:

User provides (or the tool's own input doubles as) the source document
Each claim in the rewritten output gets checked against it and labeled: Supported / Contradicted / Not found in source / Unclear
"Unclear" is a real, allowed output false accusation of fabrication is worse than a miss, so ambiguous claims don't get forced into a verdict
Auto-fix then corrects flagged claims against the source and re-verifies its own correction

Deliberately scoped narrow: it only checks against the source you give it, doesn't search the web or rule on general truth. That's a reliability tradeoff I'd make again an AI checking a document you control beats an AI guessing at open-ended "truth."

Full writeup with the real before/after example: https://letsflw.com/blog/ai-hallucinations-catch-before-you-publish?utm_source=indiehackers&utm_medium=social&utm_content=ih_post

Curious if anyone else building AI writing/content tools has run into this specific failure mode rewrite reads perfectly, quietly changes a claim. How are you handling it, if at all?

on August 25, 2026
  1. 1

    A useful addition may be to preserve provenance for every extracted claim: the exact source span, the original wording, and the rewritten wording side by side. Then the auto-fix can show a small diff and let the writer accept or reject it instead of silently replacing text. That seems especially valuable for qualifiers like “preliminary” or “at least,” where the safest correction may be to restore the source wording rather than generate a new sentence. Do you expose that claim-level audit trail to users yet?

    1. 1

      Honest answer: not yet. Right now auto-fix rewrites the flagged claim and re-verifies automatically no side-by-side diff, no accept/reject step. The user sees the before, the after, and the claim-level labels, but not a granular "here's exactly what changed and why" view.

      Your qualifier point is the strongest part of this suggestion, and it's made me want to actually build it. "Preliminary" → "proven" isn't really a rewrite the model should be generating fresh the safest fix in that specific case probably is "restore the original word," not "generate a new sentence that's technically consistent." Right now the fix step doesn't distinguish between those two repair strategies; it just regenerates. A diff view would also make that distinction visible to the user in a way "trust the auto-fix" currently doesn't.

      No promises on timeline, but this moved from "interesting idea" to "actually on my list" while writing this reply, so, appreciated.

  2. 1

    This is a really useful distinction: a rewrite can preserve the general topic while quietly changing the strength or meaning of a claim.

    I especially like that “Unclear” is a valid result. Forcing the checker to make a binary decision could make it look more confident while actually reducing reliability.

    One test case I’d be interested in is numerical consistency: percentages, dates, sample sizes and words such as “approximately” or “at least.” Those small modifiers are easy to lose, but they can completely change the claim.

    Do you compare each corrected version with the original source again, or only re-check the claims that were previously flagged?

    1. 1

      Checked the actual code before answering rather than go from memory: it re-verifies the whole corrected output against the full source again, not just the previously-flagged claims. So if a fix to one claim accidentally introduced a new problem elsewhere (rare, but the kind of thing a narrower re-check would miss), the next pass would catch it too. Capped at 2 fix attempts if issues remain after that, it reports the honest remaining state rather than looping forever or silently claiming success.

      Numerical modifiers specifically good test case, and I actually went and ran it rather than guess. Built 6 real test cases through the actual production detection code: 3 outright changes (percentage, date, sample size all correctly caught as CONTRADICTED) plus the exact subtle case you're asking about dropping "approximately" from "approximately 500 participants" and dropping "at least" from "at least 10 participants per group." Both got correctly flagged as CONTRADICTED, with the note explicitly citing the dropped qualifier as the reason. Also tested the inverse — rounding "17.3%" down to "about 17%" which correctly passed as SUPPORTED, since adding an honest hedge word to a rounded number isn't actually a fabrication.

      So: yes, it's currently sensitive to modifier drops specifically, not just outright number swaps. That's a genuinely encouraging result and not one I was fully certain of going in appreciate the prompt to actually check instead of assume.

  3. 1

    The claim-level approach is interesting because rewrites can preserve the wording while quietly changing the underlying meaning. Treating “unclear” as a valid result also seems important—forcing every claim into supported or contradicted would create a different kind of reliability problem.

    1. 1

      Exactly, and the "unclear" case ended up mattering more in practice than I expected going in. Early on I assumed most claims would cleanly resolve to supported or contradicted, and unclear would be a rare edge case. It's actually a meaningful chunk of real output, mostly because source documents are often genuinely ambiguous or just don't address a specific detail one way or the other the model didn't necessarily get it wrong, the source just doesn't settle it.

      Forcing a binary verdict there would've pushed those into "contradicted" by default (safer-sounding, but wrong) or "supported" by default (which defeats the whole point). Either one trains the user to stop trusting the flags after a few false alarms. Letting it say "I don't have enough here to call this" turned out to be the thing that keeps the supported/contradicted labels actually meaningful when they do fire.

      The harder version of this problem, still not fully solved on my end: confidence calibration on the model's own "unclear" calls. Right now it's binary flagged unclear or not but there's probably a real difference between "genuinely 50/50 ambiguous" and "I can tell this is probably fine but I'm not fully certain," and collapsing those into one label loses information. Haven't found a clean way to surface that distinction without making the UI more confusing than it's worth yet.