11
73 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

    The claim-checking problem is why I don't think "better chatbot" is the real product anymore. Once the agent has a computer and a job, the failure mode isn't a wrong paragraph — it's a wrong action taken while you're asleep. I wrote that up here: https://pub.towardsai.net/elon-musk-is-coming-for-your-job-with-grok-bot-1663d1d010f7?sk=eee5346352708c68c485cc65a11ccf0b Curious if your checker is in the loop before the agent is allowed to hit send / publish / update a CRM.

    1. 1

      No it's deliberately human-in-the-loop. Verdicts get shown to a person who accepts or rejects them; nothing is gated on the result automatically.

      Your framing of the failure mode is the right one though. A wrong paragraph gets caught on read-through. A wrong action taken at 3am doesn't get read at all, and by the time anyone looks the CRM already has the wrong number in it.

      The reason I haven't put it in an agent loop is that I'm not confident enough in the miss rate to make it a gate. A checker that's right most of the time is fine as an advisory layer for a human, and actively dangerous as an automated approval step the failures stop being visible at exactly the point you'd be relying on them most. That would need a much better answer on recall than I currently have.

  2. 1

    This mirrors what we just went through almost exactly. Our citation-fidelity gate started as pure similarity scoring, and we found the same failure shape you describe — claims that read clean and confident while quietly diverging from the source. We ended up adding a deterministic pre-check (exact entity/number token matching) in front of the probabilistic layer, same spirit as your verbatim-quote requirement: turn "did it represent the source correctly" into "does this exact thing appear in the source" wherever possible.

    The top comment on your post nails something we learned the hard way too: we ran an adversarial red-team pass against our own gate specifically to attack it, not just validate it, and found real gaps — relational changes (reordering, negation, causal swaps) that don't touch any token our gate checks, so they sail through undetected. "A checker nobody has attacked is a checker whose miss rate you don't know" is exactly right, and it's a different exercise from writing more passing tests.

    1. 1

      The deterministic-first split is the right instinct and it's where I'd put effort next. Turning "did this represent the source correctly" into "does this exact string appear in the source" wherever the claim allows it that's a much cheaper and much more debuggable question.

      On the red-teaming: I ran a pass on the standalone version a few days after this post, and the shape of what I found matches yours more than I expected. Every attack that argued for a wrong verdict failed the task grounding held. What got through were attacks on structure: one that redefined the job entirely rather than disputing any claim, and one where crafted input could shift where the tool considered the text to end and the source to begin.

      Your relational-change gap and my structural gap are the same lesson from opposite ends the checks were aimed at the content of claims, and both classes of miss came from somewhere else entirely.

      "A checker nobody has attacked is a checker whose miss rate you don't know" that's going in my notes. Writing more passing tests genuinely is a different exercise, and I'd been doing the easy one.

      1. 1

        That's a sharp way to put it — "a checker nobody has attacked is a checker whose miss rate you don't know" is going straight into how I think about this too.

        The boundary-shifting attack is especially interesting to me — I hadn't tested for that class at all. Did it exploit formatting/delimiters, or something about how the tool infers where claims end and source begins? Curious if a fix there generalizes, or if it's as narrow as the entity/number gate turned out to be.

        1. 1

          Formatting/delimiters, and it generalized better than the entity/number gate did.

          The attack planted fake structural markers inside the untrusted text things that looked like the delimiters the tool uses internally to separate "source" from "output." If the tool trusts those markers wherever it finds them, crafted input can convince it the boundary is somewhere other than where it actually is, and content that should still count as "output" gets read as if it were "source" (or vice versa).

          The fix was to stop trusting any boundary marker that shows up inside the untrusted text itself strip/neutralize anything that looks like a structural marker before it ever reaches the part of the pipeline that decides where source ends and output begins, so the only markers that matter are the ones the tool itself inserts after that point.

          That one generalized decently well precisely because it's structural rather than content-based it's not looking for a specific string or pattern the way the entity/number gate hunts for tokens, it's closing a class of "the model doesn't actually know who's talking" problem. Doesn't mean it's bulletproof against every framing of the same idea, but it held up better under variation than I expected going in.

          1. 1

            That's a clean way to frame it — "the model doesn't know who's talking" is a good name for the whole bug class. Stripping/neutralizing anything that looks like a structural marker before the source/output split is exactly the kind of structural fix that should generalize, since it doesn't care what the marker says, only where it came from.

            One thing I'd be curious about: did you find any residual gap with lookalike markers — unicode homoglyphs, or a marker split across two chunks so neither half matches your strip pattern on its own? That's usually where these sanitization fixes leak for me.

            1. 1

              Yes to both, and they split into two different answers depending on which layer you're asking about.

              On the sanitization step itself the part that strips lookalike markers before anything gets processed unicode homoglyphs are a real gap I haven't fully closed. A full-width or Cyrillic stand-in for the marker characters, or a zero-width character spliced into the middle of one, slips past a strict pattern match. Same story with your split-across-chunks case: if a document ever gets processed in pieces, a half-marker sitting in each piece defeats a check that only looks within one piece at a time.

              But that turned out to be the wrong layer to fix it at. The actual fix I shipped was structural, not more sanitization: instead of concatenating source and output into one blob with a text marker and parsing it back apart, the two now get sent as separate fields from the start. There's no split happening at all on that path anymore nothing for a homoglyph to fool, because there's no pattern-match standing between the attacker and the boundary decision in the first place.

              The sanitization step is still there as a second layer mainly so the person using the tool gets an honest notice if their own pasted text happened to contain something that looked like an internal marker but it's not doing the real defensive work anymore. So: gap acknowledged on the pattern-matching layer, but the question got a lot less important once the boundary itself stopped being inferred from content at all.

              1. 1

                That's the real lesson here — moving the source/output split out of band entirely (separate fields instead of a delimited blob) doesn't just patch the homoglyph gap, it deletes the whole category of question. No parsing step means no place for a forged marker, however well-disguised, to have any effect. That's a cleaner fix than anything I would have tried at the sanitization layer.

                Going to go check whether my own pipeline is actually doing that, or just doing string-level delimiter sanitization and calling it done. Appreciate you laying out why the fix works instead of just what it is.

  3. 1

    A useful way to evaluate this feature is to treat hallucinations as controlled mutations rather than rely only on naturally occurring examples.

    Build a small test set where each rewrite contains exactly one known change: number or unit drift, negation reversal, entity swap, dropped hedge, invented timeline, omitted constraint, or unsupported causal claim. Add correct paraphrases as hard negatives. Then measure detection and repair separately, because a verifier can flag the right sentence and still generate the wrong correction.

    I would also split the pipeline by failure class. Numbers, dates, currencies, percentages, units, and explicit negations can often be checked deterministically. The model can focus on semantic entailment and ambiguity. That usually gives you better recall per unit of latency and makes the result easier to debug.

    The auto-fix step is where I would be most conservative. For high-impact claims, I would show the source span and proposed correction, require acceptance, and then re-run verification against the immutable original source — never against the verifier's previous response. Otherwise the fix can introduce a second error that inherits confidence from the first verdict.

    Are you logging the original claim, verdict, proposed fix, final text, and whether the user accepted it? That feedback could become a much more representative evaluation set than hand-written cases alone.

    1. 1

      This is basically the methodology I ended up building into a tool after this post — a library of exactly-one-known-change rewrites (reordering, negation, entity swaps, etc.) plus faithful paraphrases as hard negatives, so you can measure what a checker actually catches instead of assuming. If you want to try the pattern set: https://guardrail-redteam-690339828002.asia-northeast1.run.app/en

      The failure-class split matches what I landed on too — deterministic gate for entities/numbers, semantic layer for everything relational. Your auto-fix point is the part I haven't solved yet though: re-verifying against the immutable source rather than the verifier's own prior output is exactly right, and I don't currently have that safeguard in the correction path. Going to think about that.

    2. 1

      The controlled-mutation set is the most useful thing anyone has said to me about evaluating this. Naturally occurring examples are what I've been testing on, which means my coverage is whatever the model happened to break that week rather than anything systematic. One known change per case, plus correct paraphrases as hard negatives, is a real evaluation rather than a demo.

      Measuring detection and repair separately is a distinction I hadn't drawn sharply enough. Flagging the right sentence and proposing the wrong correction are genuinely different failures and I've been treating a pass as a pass.

      On auto-fix — that's the one part where I think I'm already close to where you'd want me. It proposes rather than applies, shows the source span behind each change, requires per-change acceptance, and re-verifies afterwards. The point about re-verifying against the immutable original rather than the verifier's own previous response is one I want to check rather than assume; inheriting confidence from the first verdict is exactly the trap and I'd rather look than claim.

      To your last question, honestly: no, that isn't logged today. Which means the evaluation set you're describing is one I could be building passively from real usage and currently am not. That's the most actionable thing in this thread for me.

  4. 1

    You’ve found a real gap in the current design.

    Right now the checker is output-first: it extracts claims from the rewritten text and checks each one against the source. We don’t yet do the symmetric pass you’re describing where the source is decomposed first and then compared against the rewrite for missing claims. So yes, a qualifier or clause that disappears completely can avoid being judged because there’s no output claim left to trigger the check.

    I like the DROPPED framing because it doesn’t require the model to decide whether the omission is “wrong.” It just surfaces that something material existed in the source and no longer has a counterpart, then leaves the decision to the user. That fits the same principle we’ve been leaning toward elsewhere: compare mechanically where possible, judge only where necessary.

    Translation is probably where this deserves the most care. We already know hedges and qualifiers are a weak spot even within one language, so crossing languages makes that harder rather than easier. I don’t want to pretend we’ve solved that part more rigorously than we have.

    The symmetric source/output claim diff is a strong suggestion though. It closes a class of failures the current four labels simply can’t see.

    1. 1

      The mechanically-compare-first principle is the one I'd defend hardest, and it took me longer than it should have to arrive at. The instinct with a language model is to ask it to judge, because it can. Most of the improvements that actually held were the opposite replacing a judgment with a comparison wherever the question allowed it.

      The part I'd add to the translation point: it isn't only that hedges are a weak spot crossing languages. It's that a dropped qualifier in a translation is invisible in a way it isn't within one language. Same-language, a missing "may" leaves a sentence that reads slightly too confident. Cross-language, it reads like a competent translator made a natural choice. There's no surface oddness to notice, which removes the last line of defence the human rereading it.

  5. 1

    The gap I'd flag is the one your four labels structurally can't express: Supported / Contradicted / Not found / Unclear are all properties of claims that exist in the output. A rewrite that deletes a material qualifier outright -- not "may" softening into "does," but the entire clause "excludes one-time charges" disappearing -- scores 100% Supported, because the thing that would have been wrong is no longer in the text to be judged. That's a recall failure in a checker that is architecturally precision-only, and it's the failure mode I'd expect most from tools whose job description is literally "cleaner and shorter," since compression is what the model was asked to do. The fix is symmetric extraction: run the same claim decomposition over the source, diff the two claim sets, and flag source claims with no counterpart in the output as DROPPED for the user to accept or reject -- no verdict needed, it's a set difference, which puts it on the cheap side of the recompute-vs-judge line others in this thread have drawn. I'd also single out "translate" among your 19 as where this bites hardest, because hedges and modality don't map one-to-one across languages, so a lost qualifier reads as idiomatic phrasing rather than an error. Do you extract claims from the source today, or only from the output -- and for translate specifically, is the check run in the source language, the target, or both?

    1. 1

      Output-only. Claims come from the rewritten text and get checked against the source; the source is never decomposed on its own. So your example holds a clause that disappears leaves nothing behind to trigger anything, and the run scores clean.

      The precision-only framing is the useful part. I'd been thinking of gaps as things the labels got wrong. This is a class they can't express, which no amount of extra test cases would have surfaced.

      On translate I checked rather than guessed, and the answer is neither of your two options. It runs across both. The original-language input is what the translated output gets checked against, in one pass, using a prompt written for same-language rewrites. Nothing in it acknowledges the two texts aren't in the same language. It doesn't fail loudly — it just does a harder job than it knows it's doing.

      Which makes your point sharper than you put it. It isn't only that a lost qualifier reads as idiomatic phrasing; there's no representation of modality mapping at all, so it's inferring across languages unaided. I wouldn't claim anything about reliability there until I've watched it handle a German pair with a deliberately dropped hedge.

  6. 1

    Interesting implementation. We’re building GeekBye, an AI assistant used in live interview conversations, and the same principle matters there: when the system lacks enough grounding, a confident answer is worse than a clear “I don’t know.”

    I like the requirement to show the exact source span behind each verdict. Have you measured how much latency that verification step adds in real workflows, and whether users choose to enable it when speed matters?

    1. 1

      Agreed on the principle under-grounded confidence is worse than an explicit "not enough here to say," and in a live interview setting the cost of getting that wrong is much higher than in a writing tool.

      On latency: I don't have measured numbers to give you, and I'd rather say that than estimate. It's a separate call from the generation step, so it's additive rather than inline, and the span-quoting itself is part of the same response rather than a second round trip. But I haven't instrumented it.

      On whether people enable it when speed matters I don't have enough usage to answer honestly yet. Too little traffic for that to be a signal rather than noise.

  7. 1

    We run into this exact failure mode at SocialPost.ai when AI rewrites a caption for brand voice: it's rarely a fact getting flipped outright, it's a hedge quietly turning into a confident claim. The 'Unclear is a real, allowed output' choice is the detail most teams skip, forcing every claim into Supported/Contradicted just relocates the ambiguity instead of removing it.

    1. 1

      That's a useful confirmation, because it means this isn't a one-off report three different people have now landed on the same specific gap from three different directions, and you're describing it from actually shipping something, not theorizing.

      Agreed on the relocation point, and it's the sharper way to put it. Supported/Contradicted is a real distinction when a claim gets flipped, but a hedge sliding into confidence doesn't flip anything the claim is still technically true, so it gets waved through as Supported. Forcing a binary onto that doesn't resolve the ambiguity, it just gives it a label that looks resolved.

      Curious how you're handling it on your end for brand-voice rewrites specifically — are you catching it with a separate pass, or is it still an open gap for you too? Would be useful to compare notes, since "confident hedge drift" seems to be the thing every team building this kind of check runs into independently, which suggests it's a property of the problem rather than something any one of us just hasn't gotten around to yet.

  8. 1

    This is actually very interesting... I didn't quite understand how you trained it though. What was the data you used to train it? Although, I really liked the project and can clearly see how useful it can be..

    1. 1

      Appreciate that, and good question but there's actually no training involved. This isn't a custom-trained model; it's a general-purpose AI given a very narrow, specific job: compare the output text against your source document, claim by claim, and say whether each one is supported, contradicted, not found, or genuinely unclear.

      The reliability comes from constraining what it's allowed to do, not from training data. It can only compare against the document you give it no outside knowledge, no judging whether something's true in the real world, just "does this specific document support this specific claim." And every claim it flags has to point to the exact phrase in your source that backs its verdict, which we then verify is actually a real, verbatim quote rather than just trusting the model's word for it.

      So it's less "trained on a dataset" and more "given a narrow task and boxed in from making things up." Turns out that constraint does more work than a bigger model would.

      1. 1

        Oh that makes sense.. Thank you!

  9. 1

    https://x.com/compose/post
    The failure mode I'd watch for is the checker being confidently wrong in the same direction as the rewriter, since they usually share a model family and therefore share blind spots. When I built an internal QA pass over generated summaries, the biggest accuracy win wasn't a better prompt — it was forcing the verifier to quote the exact source span for each claim and marking anything unquotable as "unsupported" instead of letting it reason its way to a verdict. Numbers and negations were where almost all real errors lived: dropped units, "up to 40%" becoming "40%", "not recommended" flipping polarity, so deterministic number/negation diffs alongside the model caught more per dollar than the model did. I'd also track a false-positive rate, because a checker that flags fine sentences trains users to ignore it within a week. For trust, show the diff and the source span inline rather than a confidence score; people accept corrections they can verify in two seconds. Did you evaluate against a labelled set, or eyeball outputs? That number is the thing worth publishing.

    1. 1

      Your span-quoting point is the architecture, not an improvement on it. Every claim carries the source phrase it was checked against, and that phrase is verified as an actual substring of the document rather than trusted as written if it can't be found, it isn't presented as a quote. Same principle on the fix side: a correction only applies if its "before" text matches your text exactly.

      Numbers and negations matching your experience exactly. Those are where the real errors are, and they're the ones deterministic comparison handles better than judgment.

      False-positive rate is the right thing to watch over-flagging kills the feature faster than missing something, because people stop reading the flags.

      On evaluation: constructed cases with known-correct answers plus real usage, not a labelled set with a published rate. I know which failure classes we test for and which we don't. You're right that the number is what's worth publishing, and I'd rather say that plainly than imply one exists.

  10. 1

    The narrow, source-grounded scope feels like the right tradeoff. There’s a similar failure mode in code refactoring: the output compiles and looks cleaner, but silently changes behavior.

    Have you considered creating a machine-readable claim ledger before rewriting — subject, value, qualifier, and source span — then checking both coverage and entailment afterward? That could make dropped hedges visible without relying entirely on a second model’s prose judgment.

    I’m also curious how you handle claims implied across multiple source sentences rather than stated verbatim.

    1. 1

      The refactoring parallel is a good one compiles clean, behaves differently, nothing visibly wrong.

      A structured claim ledger is the more rigorous version of what we do. Currently each claim carries its subject, verdict, and the verified source span, but as parsed fields rather than a ledger built before the rewrite and diffed after. Building it first would make coverage checkable rather than inferred. Worth thinking about properly.

      Claims spread across multiple source sentences are the honest weak spot. The check asks for the smallest span supporting a verdict, which suits directly-stated claims and fits multi-sentence entailment less well. Those tend to land as UNCLEAR rather than being resolved which is the safe failure, not a solved one.

  11. 1

    This is a really interesting problem. As AI tools become more common, trust and accuracy are becoming just as important as generation quality. Curious how you handle the balance between improving accuracy and keeping the workflow fast for users.

    1. 1

      The way we resolved it was not making it automatic. Verification is a separate, deliberate step you trigger when the text matters, so normal generation stays fast and the slower analytical pass only runs when you want it.

      Auto-fix works the same way: it proposes changes for review rather than applying them, so the time cost lands where you've already decided accuracy is worth it.

  12. 1

    The hedge flattening is the part that rings true — qualifiers like 'preliminary' are the first thing a rewrite drops, because to the model they read as filler. Curious how you handle decomposition: when one sentence packs a stat plus a hedge, do you check it as one claim or split it? I'd expect splitting to be where most of the label noise comes from.

    1. 1

      "Preliminary" reads as filler to a model that's exactly it. Qualifiers get dropped because they look like padding rather than load-bearing.

      On decomposition: one claim per block, restricted to specific and checkable statements, each tied to the smallest source span supporting its verdict. Whether a stat-plus-hedge sentence becomes one claim or two is the model's call within that structure, not an explicit splitting rule.

      You're right that it's a noise source. A hedge attached to a stat is a different claim from the stat itself, and treating them as one means a verdict on the number can quietly cover the qualifier too.

  13. 1

    The "unclear is a valid output" call is what most people get wrong — forcing a verdict on ambiguous claims ships confident-sounding lies. Same failure mode in analytics: an AI answering "why did traffic drop" with a confident guess instead of "can't tell from this data". Honest uncertainty is the trust feature.

    1. 1

      Agreed, and the analytics parallel is apt a confident guess at "why did traffic drop" is worse than useless because it's actionable and wrong.

      UNCLEAR also carries a reason code: ambiguous wording, insufficient detail in the source, or partially supported. "I don't know" is more useful when it says which kind of not-knowing it is.

      The design rule behind it: a false accusation of fabrication is worse than missing a real one. When in doubt, say unclear and explain what would be needed to check it.

  14. 1

    the confidence-calibration-on-unclear problem in your last reply is the one I'd want to sit with, because it's structurally the same problem I have with confirmation, not fact-checking. right now my system has exactly two states before acting: confident enough to just show the plan, or genuinely unsure enough to ask a clarifying question first. collapsing "the model is 90% sure but technically hedged" and "the model is genuinely guessing" into one bucket has the same information-loss risk as your unclear label, a user who gets asked to clarify something the system was actually pretty confident about starts trusting the clarification prompts less

    no clean answer from me either, but one partial idea: instead of a confidence score (which you've already correctly ruled out as false precision), maybe the distinguishing signal is whether multiple independent passes/samples agree with each other. genuine 50/50 ambiguity should produce disagreement across repeated attempts at the same claim, while "probably fine but not fully certain" should mostly agree but with minor phrasing variance. agreement-rate-across-samples isn't a confidence score exactly, it's closer to a measurable proxy for it without asking the model to self-report certainty, which is the thing that tends to be unreliable

    this whole thread is genuinely one of the best resources I've read on this problem, going to reread the numerical-modifier testing exchange a few more times

    1. 1

      The cry-wolf failure mode is the right thing to name, and it's the one I'd actually worry about more than a missed flag. A checker that over-flags trains people to skim past the flags at which point the label stops doing any work at all.

      Agreement-across-samples is a genuinely better idea than a self-reported confidence score, and for the reason you gave: it's measured rather than asked. Self-reported certainty is the least trustworthy thing you can query a model for.

      Where I have real data on it though, and it cuts both ways. On a separate project I ran repeated enrichment passes over the same items with cross-model verification, thousands of them. Two findings: genuine ambiguity did produce disagreement across runs, which supports your idea. But agreement across runs turned out not to be reliable evidence of correctness two near-identical inputs got different verdicts, and the verdict tracked which model pair happened to run more than it tracked the claim. So agreement is a usable signal for unstable, but a weak one for correct. Asymmetric which might be fine, since unstable is exactly the thing you're trying to detect.

      The other cost is unglamorous: N samples is N times the spend on something already rate-limited. Worth it if agreement-rate genuinely separates the two cases, not worth it as a maybe.

      Not solved on my end either. But "disagreement across repeated attempts" is a measurable thing rather than another judgment call, and that's the same shift that made the verbatim check work so it's the direction I'd try first.

      1. 1

        the model-pair confound is the part I wouldn't have thought to check for, and it's a real methodological trap, if agreement tracks which models happened to run rather than the claim's actual stability, that's not measurement noise, it's a systematic bias hiding inside what looked like a clean signal. good thing to know before building something on top of an assumption that hadn't been stress-tested that hard

        the asymmetric framing (usable for unstable, weak for correct) is the right way to salvage the idea rather than discard it, since "flag this as needing a human look" and "assert this is true" are genuinely different claims requiring different evidence bars. sounds like agreement-rate earns the former, not the latter, which happens to be exactly the bar my confirmation step needs too, I'm not trying to assert correctness, just trying to catch instability before it reaches someone as a confident action

        the N-samples-cost point is the practical constraint that would've bitten me eventually anyway, worth being honest that "just sample more" isn't free even when it's the right technical answer

        1. 1

          That's the trade I keep landing on too: catching instability and asserting correctness are different claims and shouldn't share an evidence bar. Most of the mistakes I've made on this have come from treating a signal that earns the first as though it earned the second.

          On cost worth adding that the honest version of "just sample more" is usually "sample more on the subset where it matters." Running N passes on every claim is what makes it unaffordable. Running them only on claims that already landed in the ambiguous bucket is a much smaller number, and that's the only place the agreement signal would tell you anything you don't already know. Whether that subset is small enough to be worth it is an empirical question I haven't answered.

          Your confirmation step might actually be the better place to test the idea than my checker is. You have a natural decision boundary already ask or don't ask so a wrong call is immediately visible as an unnecessary prompt. Mine surfaces a label in a list, where the cost of over-flagging is real but slower to notice. Easier to measure whether it's working on your side.

          1. 1

            "sample more only where it matters" is the fix that actually makes this affordable, running N passes only on claims already flagged ambiguous turns an expensive blanket cost into a targeted one. that's the kind of refinement that makes an idea go from theoretically interesting to actually shippable

            you're right that my confirmation step is probably the better test bed too, and I hadn't thought about why until you said it. an unnecessary clarifying question is an immediate, visible cost, the user notices right then, whereas your mislabeled claim just sits quietly in a list until someone happens to check it against reality. I have a faster feedback loop for free, just by the nature of what a confirmation step is

            think I'm actually going to try this, sample agreement only on borderline-confidence cases, before asking for clarification, and see if disagreement rate correlates with cases where I would've asked unnecessarily. will report back whether the subset is small enough to be worth the extra latency, that's the empirical question on my end too now

            1. 1

              Looking forward to hearing how that goes the borderline-confidence subset feels like exactly the right place to test it, for the reason you both landed on: it's the one spot where you get a fast, visible read on whether the signal is worth the latency instead of it sitting unverified in a list.

              On my end, confidence calibration inside "unclear" is still sitting exactly where this thread left it genuinely unsolved, not parked because I stopped caring but because I don't have a cheap way to test a fix without risking the same cry-wolf failure mode you named. Self-reported certainty is out for the reason you said, and agreement-sampling has the cost problem you and Farrukh worked through. I'd rather leave the label honest and slightly coarse than add a confidence layer I can't actually validate yet.

              If your borderline-subset test does show disagreement-rate correlating with unnecessary-ask cases, that's the first real evidence either of us will have that the idea earns its keep instead of just sounding right. Tag me if you post results genuinely useful thread either way.

              1. 1

                Haven't run it yet, but the plan going in: sample 3-5 times only on cases that already sit in the "ambiguous" bucket, before the system decides whether to ask a clarifying question. Then check whether disagreement rate actually predicts the cases where I would've asked unnecessarily.

                One thing your model-pair confound made me add: I'm going to hold the sampling config fixed (same model, same temperature) across the repeated passes, specifically so I'm not accidentally measuring "which run happened to fire" instead of genuine claim instability. Wasn't planning to control for that until you flagged it.

                Will actually tag you both once there's a real number instead of a hunch. Might be a week or two given how much else is queued.

              2. 1

                This comment was deleted 3 days ago

  15. 1

    This is a problem I didn't expect to run into outside of software: I publish books (KDP), and every marketplace now requires an explicit AI-use declaration — what got AI-generated vs. AI-edited vs. fully human. The tricky part isn't the declaration itself, it's that once an AI rewrite tool touches a description or a claim in the text, you genuinely don't always notice what shifted unless you diff it against the original. A claim-level check across the pipeline (rather than a single grammar-pass sanity check at the end) seems like the right layer for that. Are you flagging semantic drift even when the rewrite is grammatically/stylistically fine, or only when it changes something checkable like a number or a fact?

    1. 1

      Good question, and the honest answer has a real boundary in it.

      Every claim gets checked against the source, independent of grammar or style so yes, we catch semantic drift on non-numeric claims too, not just checkable facts. The clearest case: a hedge quietly turning into flat certainty ("may improve" becoming "improves") gets flagged even though both sentences are grammatically perfect. That's exactly the "reads fine but the claim moved" case you're describing.

      Where it's weaker: a hedge sliding into a stronger hedge ("suggests" becoming "indicates") isn't reliably caught yet. Both are technically still hedges, so a binary supported/contradicted check has no clean trigger even though "indicates" reads as more confident to a reader. We know this gap exists and haven't shipped a fix for it.

      For your KDP use case specifically: it'll catch a rewrite that turns a qualified claim into an assertion. It won't yet catch subtler confidence creep between two hedged phrasings. Worth knowing before you rely on it for a compliance declaration.

  16. 1

    The difference between cleanup and rewriting matters more than most AI writing tools admit. With DictaFlow, refinement means cleaning up the transcript. We can fix punctuation, repeated words, and filler, but we don't change the user's meaning. Checking the result against the source is a sensible safeguard. It helps prevent a cleaner sentence from quietly turning a cautious claim into a stronger one.

    1. 1

      That's the right distinction to draw, and it matters. A rewrite is explicitly restructuring ideas; cleanup explicitly isn't supposed to.

      One thing worth naming though: cleanup isn't automatically safe just because it's not rewriting. Spoken hedges ("I think, kind of, maybe...") and spoken filler ("um, like, you know...") often look structurally identical repeated words, soft qualifiers, disfluencies. A cleanup pass aimed purely at filler could plausibly strip a genuine hedge right along with it, without ever touching the sentence's actual claim. Same failure shape as a rewrite, smaller surface, not zero.

      That's actually a good argument for checking cleanup output too, not just rewrites the risk isn't about how aggressive the transformation was, it's about whether anything carrying epistemic weight got touched, intentionally or not.

  17. 1

    Ran into exactly this from a different direction: a pipeline where an AI writes landing-page teardown reports. Every finding quotes the text it's criticizing before proposing a rewrite, and review kept catching the same shape of failure you opened with — clauses that read clean and confident and weren't quite what the page showed. In one report, five separate clauses failed that check. Nothing about them looked wrong.

    The design change that did the most work: shape the output so the biggest class of claims stops needing a judge at all. The format requires the "before" text to be a verbatim quote of the source, not a paraphrase of it. That one constraint turns "did the model represent the source correctly," which is a judgment call, into "does this exact string appear in the source," which is a comparison. For that whole class there's no second model and no verdict label — the residual failure modes are things like curly quotes and whitespace, not judgment. Your Supported/Contradicted/Unclear labels then only carry the claims that genuinely need judging, which shrinks the surface where the checker itself can be confidently wrong.

    Numbers get the same treatment: a claim like "this element covers 43% of the screen" gets recomputed from the source — screenshot pixels, in our case — rather than a model being asked whether it sounds supported. Recompute where you can, judge only where you must. And the gate fails closed: three attempts, then the piece goes to a human instead of shipping. The cap-plus-exit is what makes a green light mean something; your 2-attempt fix cap is the same instinct.

    One caution from running this for a while: the gate itself becomes something you have to test. One of ours passed an input that satisfied the letter of the check while missing its point entirely; a real case exposed it, and our first fix then failed the harder failure cases we built to prove the second one. A checker nobody has attacked is a checker whose miss rate you don't know.

    1. 1

      Already load-bearing on one side: the fix step only applies a correction if its "before" text is an exact match in your document not a paraphrase, a real string check, rejected if it doesn't match.

      Your comment exposed we only built it on one side. The source excerpt shown on every claim isn't verified the same way currently trusted as written, never checked against the real document. Same fix, other half of the pipeline. Real, specific gap, logged to close.

      Recompute-vs-judge doesn't map directly for us (text claims, not pixel measurements), but the principle clearly generalizes past quotes.

      Cap-plus-exit matches design intent fails closed, reports honestly rather than looping or claiming success. Your adversarial-testing point is the harder one though: everything tested so far is real usage plus constructed cases, not deliberate red-teaming built to break it. Fair gap, not claiming otherwise.

  18. 1

    Your narrow-scope decision is the whole reliability story, and it's the same principle the rewrite tools themselves violate: the checker is trustworthy precisely because it's not allowed to be the source of truth, only to compare against a document you control. That's why "Unclear" as an allowed output matters so much, you built a checker that admits ignorance instead of fabricating a verdict, which is exactly the discipline the rewriters lack. A tool that can say "I don't know" is more trustworthy than one that always answers, and most of this category ships the second kind.

    But here's the thing you might be underselling: this isn't a feature you added to 19 tools, it's a different and better product than the 19 tools. Paraphrase, humanize, grammar-fix are commodities, everyone has them. "The only AI writing tools that can't silently change what you claimed" is rare, because the whole category was built ignoring this exact failure. You've got it inverted, positioning it as "our rewrite tools now also fact-check." The fact-check is the reason to choose you. It should be the headline; the 19 tools are the surface it runs on.

    One technical push on your open question, because your example is subtler than your four labels catch. "Preliminary result, more time needed" becoming "proven" isn't Contradicted and isn't Not-found, the claim is present, and factually the finding is real. What changed is its epistemic status, the certainty got silently upgraded. That's a fifth failure type: not the claim changing, but the confidence around it changing. It's the most dangerous one, because the fact checks out and only the hedge died, so a label set looking for factual mismatch sails right past it.

    Do you flag certainty-shifts as their own category, or do they currently fall through as "Supported" because the underlying fact is technically still there?

    1. 1

      The positioning point lands, and I don't have a confident counter to it "our rewrite tools also fact-check" may genuinely be burying the real differentiator. Worth sitting with properly, not answering in a comment thread.

      On the technical question: two different things could count as a "certainty shift," and only one is caught right now.

      Hedge collapsing to a flat claim caught. It's a core rule, not something that slips through just because the fact is technically still present. Your exact example is close to one already tested: a source calling a result "preliminary, needs more time" got rewritten to claim it "proves" something "permanently." Flagged correctly, with the explanation pointing straight at the dropped hedge.

      Hedge weakening not caught. "Suggests" quietly becoming "indicates" is still a hedge either way, so nothing currently distinguishes "dropped entirely" from "got a little stronger." No clean fix yet a confidence score risks the same false-precision problem this design is built to avoid.

      So: certainty collapsing to zero, caught. Certainty creeping up while staying technically hedged, not yet.

      1. 1

        squintpage's verbatim-quote point is the right backbone, so I'll add the one failure mode that survives even a perfect quote-check, because it's hiding in your own opening example and nobody's named it yet.

        Your four labels (Supported / Contradicted / Not found / Unclear) all assume the failure is about which claim appears. But your best example is a different species: "preliminary result, more time needed" becoming a flat claim of proof. Check that against the source and it passes as Supported, the finding is real, it's in the document, the quote can even be verbatim. What changed isn't the claim, it's the epistemic status around it, a hedge got deleted and certainty got manufactured. The fact is intact; the confidence is a fabrication.

        That's a fifth category, and it's the most dangerous one precisely because every other check waves it through. Contradiction detection looks for a claim that fights the source; this claim agrees with the source, it just agrees too confidently. Same for numbers, "up to 40%" becoming "40%" is a certainty-shift, not a factual error, so a recompute confirms 40% appears and misses that the ceiling became a point estimate.

        The tell is linguistic, not factual: it's the disappearance of hedges (may, preliminary, up to, in some cases) and modal downgrades (could → does, suggests → proves). Worth a check that specifically diffs the modality and hedging between source and rewrite, separate from claim-matching, because the whole class reads as Supported to a checker looking for factual mismatch.

        Does your auto-fix preserve hedges when it rewrites, or can the correction step itself quietly upgrade certainty the same way the original rewrite did?

        1. 1

          Good question, and the answer has a real edge to it.

          The fix step is built to avoid this structurally: the preferred repair puts back the source's own wording rather than composing new phrasing, so a dropped hedge is restored as the hedge. That's not just intent in testing, a correction fixing a changed quarter also restored the qualifier attached to it, without being asked to. Constructing new phrasing is the fallback, used only when no source phrase exists to substitute, and it's instructed to stay as vague as the source is.

          There's also a verification pass after changes are applied, so a fix that collapsed a hedge into flat certainty would get flagged on the way out.

          But here's the honest part: that pass uses the same checker, so it inherits the same blind spot you identified. A fix that weakened a hedge rather than removing it the suggests/indicates case would pass re-verification cleanly. So no, the correction step can't manufacture certainty from nothing. Yes, it could creep in the same narrow direction, and the safety net wouldn't catch it.

          Same gap, not a worse one. Which is fair — a checker can't validate a fix against a failure mode it can't see.

          1. 1

            The reason hedge-weakening feels unsolvable is that you're reaching for a confidence score, and you're right to reject it, a numeric certainty scale reintroduces exactly the false precision this whole design exists to avoid. But you don't need a score. You need the same move that made everything else here reliable: don't judge, compare.

            The insight is that certainty is ordered, not measured. You don't have to assert "indicates = 0.7." You only have to assert that hedges fall in a rough strength order, may < suggests < indicates < shows < demonstrates < proves, and then check one thing: did the rewrite's modal move UP that ladder relative to the source's? That's not a magnitude claim, it's a direction claim, and direction is comparable where magnitude isn't. "Suggests became indicates" is detectable as an upward step without ever committing to how certain either word is. You're not scoring confidence, you're checking monotonicity, did the modality strengthen against the source, yes or no.

            And this dodges the blind-spot inheritance you flagged. Your re-verification fails on hedge-weakening because it's the same claim-checker asking "is this supported," and a weakened hedge is still supported. A modal-ordering check is a different question entirely, "did the hedge attached to this claim move up the ladder," so it doesn't inherit the claim-matcher's blindness, it's orthogonal to it. Run it as a separate pass: pull the modal/hedge token bound to each claim in source and rewrite, flag any upward step. Cheap, and closer to deterministic than anything involving a certainty judgment.

            The one hard part is building the ladder, hedges are partially ordered, not totally, some pairs genuinely aren't comparable. But you only need the confident edges (proves > suggests is safe; two words on the same rung you just treat as equal and pass). Does a rough hand-built hedge ordering feel tractable for your domain, or do the incomparable pairs dominate enough to make even direction ambiguous?

            1. 1

              The direction-not-magnitude reframe is the part I want to sit with properly rather than answer quickly, because it's a genuinely different move from the two things I'd already ruled out not a variation on the ranked-list idea, which needed a complete ordering to work at all. A partial order where incomparable pairs are just skipped rather than forced onto a scale answers the brittleness objection directly, and I hadn't separated those two things in my head until you put it this way.

              Your own question back is the one I don't have an answer to yet: whether the incomparable pairs dominate. That's not a small caveat hedge strength reads differently depending on context ("may" in a disclaimer isn't "may" in casual prose), and a hand-built ladder has no way to know which one it's looking at. I don't want to guess at that ratio.

              So: small ladder, run against real output pairs I already have, count how often it actually catches a genuine shift versus how often there's nothing comparable to say. If it's mostly the second, the idea's dead cheaply and I'll know why. If not, this is a considerably smaller build than anything score-based, which is worth a lot on its own.

              Appreciate you pushing on this one specifically it's the gap I had the least idea what to do with.

  19. 1

    Same failure mode shows up in spreadsheets: the answer can look perfectly clean while the model mapped the wrong column or quietly skipped rows. What helps most isn’t another confidence score—it’s showing the source cells, formulas, and a before/after diff so a human can verify the change. I like that you scoped this to a document the user controls; that makes the result much easier to audit.

    1. 1

      That's the right frame, and it maps closely to the same principle behind how this actually works for text: a confidence score tells you the system is unsure, but it doesn't tell you where to look. What actually helps is being able to check the work yourself.

      Concretely every flagged claim shows the specific source excerpt it was checked against, not just a verdict. You see the actual text it's being compared to, so you can judge the call yourself instead of re-reading the whole source. And when a fix is proposed, it's never a silent rewrite: it's shown as an explicit diff, original next to corrected, labeled as either restoring the source's own wording (safer) or generating new phrasing, and you accept or reject each one individually before anything is applied.

      Your spreadsheet framing is actually a sharper way to state the same underlying principle. The failure mode isn't "the model was wrong" it's "the model was wrong in a way that looked identical to being right." Source cells and formulas are your version of what a source excerpt is for text: something concrete a human can check against, instead of a score they're asked to trust.

      Genuinely curious about one thing though does the spreadsheet version need a different kind of diff? A formula and its computed value can both look individually reasonable while the underlying cell reference is just wrong, which seems like a harder thing to visualize than a straightforward text substitution.

      1. 1

        Yes, definitely. I’d show the formula change and highlight the cells it references. Two results can both look right even when one formula points to the wrong column—that’s the dangerous part.

        1. 1

          Makes sense highlighting the referenced cells alongside the formula diff gives you the same thing the source excerpt gives on the text side: not just "here's what changed" but "here's exactly what it's pointing at, go check that reference yourself." Same principle, just a different unit of "the thing a human can verify against."

          Appreciate you working through this with me the spreadsheet framing is a good one to keep in my back pocket for explaining why verdict-only output isn't enough, even outside spreadsheets specifically.

  20. 1

    The hedge to flat claim failure is the one that scares me most, and it is the hardest to catch by eye. A changed number looks wrong when you reread it. "Preliminary result, more time needed" becoming "results show" reads better than the original, so the author approves it. The rewrite improved the prose by removing exactly the epistemics that made it honest.

    I ship a rewrite action too, and my mitigation is weaker than yours: the instruction tells it to preserve meaning, and my separate fact check action is explicitly told not to invent facts, only to flag what needs verification. That is prompt discipline, not verification. Yours actually compares output claims against a source, which is a different category of thing.

    The design question I would want answered before trusting it: what does the checker do when the source itself is hedged and the rewrite is hedged differently but not wrongly? Strength of claim lives on a spectrum, and Supported versus Contradicted is binary. If "suggests" becomes "indicates" you probably get Supported, and that is where the drift accumulates without ever tripping a label.

    Have you looked at whether the check catches hedge weakening specifically, as opposed to facts changing?

    1. 1

      Real distinction, and it's sharper than the general "hedges matter" point worth answering precisely rather than in general terms.

      The check does specifically target hedge-to-flat-certainty as one of its explicit failure modes "may improve" quietly becoming "improves" is exactly the case it's built to catch, and it catches it well.

      But your exact scenario "suggests" becoming "indicates" is a real gap, not something the design currently targets. Both are still hedges, so there's no obvious reason for a binary Supported/Contradicted check to flag the swap, even though "indicates" reads as meaningfully more confident. You're right that strength-of-claim sits on a spectrum, and the current labels don't.

      Honestly don't have a clean fix for this yet. A confidence-spectrum check risks reintroducing exactly the false-precision problem this whole design has been trying to avoid elsewhere. A ranked hedge-word list gets brittle fast against real writing. Neither feels right. This is a genuine open question, not one I have a confident answer to appreciate you separating "hedge weakening" from "hedge inversion," since I hadn't drawn that line as cleanly before.

      1. 1

        Maybe the way out is to stop trying to rank strength at all.

        You do not actually need to know that "indicates" is stronger than "suggests". You need to know that the qualifier changed. So instead of classifying claims on a confidence spectrum, diff the hedging: for each claim, collect the qualifier tokens present in the source and in the output, and flag any claim where those sets differ. You assert nothing about direction or magnitude, which is exactly the false precision you are trying to avoid. The label is not Supported or Contradicted, it is "the qualification on this claim is not the same as the source" and the human decides.

        Two things make that cheaper than it sounds. It is asymmetric: hedges getting stronger is almost always harmless, hedges getting weaker or disappearing is the dangerous direction, so most of the value comes from detecting removal and substitution, not from ordering the whole vocabulary. And the natural presentation is a diff highlight on the qualifier tokens rather than a verdict, which sidesteps the binary entirely.

        Where it breaks: hedging that lives in sentence structure rather than a word. "Results show X" versus "X was observed under conditions Y" has no token to diff. That may just be out of scope.

        Would a "qualification changed, look here" signal be useful to your users, or does anything short of a verdict get ignored in practice?

        1. 1

          The reframe away from ranking entirely is the cleanest version of this I've seen yet you don't need to know that "indicates" outranks "suggests," you just need to know the qualifier isn't the one that was there. That sidesteps the exact problem I don't have an answer to on a different version of this idea someone else raised (whether a hand-built strength ordering holds up or collapses into mostly-incomparable pairs). Yours doesn't need an ordering at all.

          The asymmetry point is the one I'll actually act on first hedges getting stronger rarely matters, weakening or vanishing is the dangerous direction, so the useful version of this might be much smaller than a general diff: just "is the source's qualifier still present," not a full comparison.

          Your own caveat is the real ceiling though. Anything where the hedge lives in sentence structure rather than a single word — your "results show X" example has nothing for a token diff to catch, and I'd guess that's a meaningful share of real hedging, not an edge case. So the honest scope is probably "catches word-level qualifier loss, structural hedging is a different problem I don't have a plan for."

          To your question: yes, I think a "qualification changed here" signal is more useful than it sounds even without a verdict it's the same principle that made the source-quote requirement work elsewhere, showing the reader the specific thing rather than asserting a conclusion about it. Worth testing against real output before I'd trust that instinct though.

  21. 1

    "A false accusation of fabrication is worse than a miss" is the trade every classifier
    makes and almost nobody states, and it implies a number: the false-accusation rate
    you'll tolerate. Once pilot volume exists, publishing that (even roughly) will do more
    for trust than any accuracy claim. The 2 attempt cap on self verifying corrections is
    a smart circuit breaker.

    1. 2

      That's a sharper way to put it than I had you're right that "false accusation is worse than a miss" is a philosophy standing in for a number we don't actually have yet. We haven't run at real pilot volume, so publishing a false-accusation rate right now would just be a guess dressed up as a statistic, which is exactly the kind of false precision we've been trying to avoid elsewhere in this design.

      But you've named the actual next milestone clearly: once there's real usage, track how often "Unclear" or a flag turns out to be wrong versus how often a real issue gets missed, and publish that number, roughly, rather than a vague accuracy claim. That's a more concrete version of a tracking gap we'd already flagged internally this just gives it the right shape.

      Appreciate the circuit-breaker read on the 2-attempt cap too that was a deliberate design choice specifically to avoid a system that either loops forever or quietly claims success when it hasn't actually resolved something.

      1. 1

        Agreed on all of that. A rate without the underlying volume would just be the kind of fake precision you’re trying to avoid.
        The one thing you can publish before the data exists is the definition: exactly what counts as a false accusation and what you’re using as the denominator. Writing that down now means that when the number eventually ships, nobody can reasonably suspect the definition was chosen after seeing the data.
        It costs almost nothing to do, and it’ll make the eventual number a lot more credible.

  22. 1

    The "Unclear" as a real allowed output is the smart part — most systems get pushed toward always giving a confident answer, so building in the option to say "not enough info" instead of forcing a verdict is a good instinct. I run into a version of this in automation work too — an AI step that qualifies a lead or summarizes a website can sound completely convincing while quietly getting a detail wrong, and there's no source doc to check it against the way you have here. Did you consider extending "Unclear" logic to cases with no clean source document, or is that intentionally out of scope for now?

    1. 1

      Yes, we did consider it this is actually the fork we hit directly building this. What you're describing is what we ended up calling "Mode 2" internally: checking a claim (like a lead-qualifier's summary of a website) against the open web instead of a document the user hands you.

      We looked hard at it and deliberately scoped it out for now, for a reason close to what you're pointing at: without a source document to anchor against, the verification step itself becomes another AI judgment call with its own fabrication risk you're trusting a model to correctly judge open-ended claims against the internet, which is a meaningfully harder and less reliable problem than "does this specific document support this specific sentence." We didn't want to ship something that looks equally confident but is actually on much shakier ground underneath.

      It's not permanently off the table, just intentionally sequenced the plan is to get real usage data on the source-document version first, then revisit whether the no-source case is worth the added risk. Your lead-qualifier example is a genuinely good concrete case for it though — that's a real gap in a way "just add web search" hand-waves usually aren't.

  23. 1

    The unclear category may need reason codes more than a confidence score.

    Missing evidence, conflicting sources, ambiguous wording, and an unverifiable source can all produce “unclear,” but they require different next actions. A single percentage could turn uncertainty into false precision.

    I would show the evidence gap and route it: request another source, ask for human interpretation, or leave the claim unresolved. That would also produce a more useful evaluation set because you could measure whether each unclear case reached the right resolution path.

    1. 2

      Real gap, well spotted. We deliberately skipped a confidence score for the reason you'd guess false precision, same trap as AI-detector percentages but we stopped one step short of your idea: splitting UNCLEAR by why, not just flagging it flat.

      Your last point is the one that'll stick with us: an unclear case isn't a failure by itself, only if there's no way to later check it reached the right resolution. Right now we have zero way to measure that. Going into the actual backlog, not just a thanks-noted.

  24. 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.

  25. 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.

  26. 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.