Skip to content

Reason codes

Reference for the short tokens validation findings carry — what each one means, what triggers it, and how it shifts severity or behavior.

Available on Plus Pro Small Team Studio Production Enterprise
Updated May 15, 2026

Validation findings sometimes carry short chips like state-contradiction or belief_unaware (rendered as STATE_CONTRADICTION and BELIEF_UNAWARE on findings chips in the SPA — see A note on spelling below). These are reason codes — small tokens that explain why the validator demoted, surfaced, or specially-weighted a finding. This page is the reference for every code you might see.

What reason codes are

When PlotLens runs validation, the underlying pipeline runs the six-stage validation funnel: Stage 0/1 coref-window enrichment, Stage 1 rule recall, Stage 2 cross-encoder reranking, Stage 3 negation guard with POV/temporal soft-fail, Stage 4 LLM arbiter, and Stage 5 knowledge-violation detection. Along the way, individual candidate rules get annotated with reason codes that tell the rest of the pipeline (and you) why a given rule is being treated a certain way:

  • A reason code can soften a finding — for example, a rule drawn from a character’s dream sequence should not be treated as authoritative canon.
  • A reason code can demote a candidate — for example, a rule on a sibling narrative branch is not relevant to the active branch, so it gets pushed into the secondary “priority signals” list rather than failing the user.
  • A reason code can explain a finding’s origin — for example, the validator may have matched a rule via a pronoun resolved by the coref pass, rather than a direct mention; the chip lets you tell those two cases apart at a glance.

Reason codes appear on validation findings (especially in the Knowledge state section described in Belief vs Fact) as short, uppercase chips. They are also visible in the API response on reason_codes arrays and in the admin debug retrieval payload for the priority Quick Check tier.

You don’t have to memorize them. This page is here so that when one shows up next to a finding, you can look it up and decide whether the validator’s reasoning matches your authorial intent.

Reason code reference

The table below is the complete list of reason codes PlotLens emits today, plus reserved codes that the pipeline is prepared to surface as new detection paths ship. Every code here corresponds 1:1 to a value in the canonical ReasonCode enum in the backend, so anything you can see on a finding is documented here.

Code (exact API string)NameWhat triggers itSeverity / behavior impactExample excerpt
negation_polarityNegation polarityThe Stage 1 negation-guard channel matched a polarity flip between the passage and the rule.Surfaced to the LLM arbiter as a deterministic hint so it can weight the rule appropriately. Does not by itself promote or demote — it tells the arbiter “this rule and this passage disagree on a polarity flip.”Rule: “Maren is alive at the end of Act 2.” Passage: “Maren was never alive.” — emitted alongside the contradiction so the arbiter knows the disagreement is a deliberate negation.
pronoun_windowPronoun windowThe Stage 1 pronoun-window soft filter matched: the candidate rule’s entity overlaps a pronoun-resolved mention from the Stage 0 coref pass, not an explicit mention.The LLM arbiter weights coref-derived matches differently from direct ones — typically more conservative, because pronoun resolution is heuristic.Passage mentions “she”; the coref pass resolves it to Aldric’s mother. A rule about Aldric’s mother is matched via that pronoun rather than a direct name reference.
branch-incompatibleBranch incompatibleThe legacy detector found the candidate rule lives on a different narrative branch than the active branch.Severity is downgraded — a sibling-branch rule is not authoritative for the current branch. Surfaced as priority signal rather than a hard finding.Active branch is “final-draft”; the rule is canonical only on the “alt-ending” branch.
temporal-distanceTemporal distanceThe detector or Quick Validator decided the rule’s valid_from / valid_until ordinals exclude the passage’s story position.Demotes the candidate to priority signals rather than failing the user — the rule may simply not apply at this point in the narrative.Rule: “Maren is the queen, valid from chapter 8.” Passage is in chapter 3 — Maren has not yet been crowned, so the rule is set aside.
pov-out-of-scopePOV out of scopeThe detector or Quick Validator found the rule is bound to a POV entity that is not the active POV for this validation run.Demotes the candidate to priority signals — the rule is real, but it’s a fact this POV cannot know about.Active POV is Aldric; the rule is scoped to Maren’s POV only and describes something Maren saw alone.
state-contradictionState contradictionThe detector found a direct attribute / fact / state contradiction between the passage and the rule.High-confidence deterministic hit — surfaced as a finding (not just a priority signal).Rule: “Aldric has blue eyes.” Passage: “His green eyes narrowed.”
epistemic_rumorEpistemic — rumorThe candidate rule itself is marked epistemic_status = RUMOR (see Canon rules).Surfaced to the arbiter so a finding against the rule lands as INFO, not ERROR. Rumors should not be treated as authoritative canon.A rule was extracted from gossip in a tavern scene; the passage contradicts it, but it’s a rumor by design.
epistemic_lieEpistemic — lieThe rule’s epistemic_status = LIE — the rule captures an in-narrative lie a character told.The rule is not authoritative; findings against it should not block. The validator weights it as deliberately wrong.A rule says “Aldric was in the capital that night” because Aldric claimed it; the passage shows him at the docks. The lie is the point — no finding emitted.
epistemic_dreamEpistemic — dreamThe rule’s epistemic_status = DREAM — drawn from a dream or hallucination sequence.Softens to INFO at most. Dream content is not authoritative canon.A rule was extracted from a prophetic dream sequence; the passage in waking-life chapters contradicts it.
pov_unreliablePOV unreliableThe rule is from a POV the author has marked as unreliable.Severity softens accordingly — an unreliable narrator’s “facts” are not authoritative.A rule was extracted from a first-person chapter narrated by a character the author flagged as unreliable; the contradiction is downgraded to INFO.
temporal_futureTemporal — futureThe passage’s story-position ordinal is before the rule’s valid_from_ordinal.The rule does not yet apply at this point in the narrative; the candidate is demoted rather than failing the user.Rule: “Aldric is married to Maren, from chapter 14.” Passage is in chapter 2 — they haven’t met yet.
temporal_pastTemporal — pastThe passage’s story-position ordinal is after the rule’s valid_until_ordinal.The rule has lapsed; the candidate is demoted.Rule: “The Eastern Gate stands, until chapter 20.” Passage is in chapter 25 — the gate has fallen.
branch_siblingBranch siblingThe rule belongs to a sibling branch (different branch_id from the active branch).Companion to the legacy branch-incompatible code, used by the soft-filter layer. Demotes to priority signal.Rule comes from the “alt-ending” branch, the active branch is “final-draft”.
belief_unawareBelief — unawareThe character’s belief state at this story position is UNAWARE of the fact referenced by the rule, but the action under validation demonstrates knowledge of it.Paired with ConflictType.KNOWLEDGE_VIOLATION — surfaced in the Knowledge state section of POV-mode validation results.Aldric has not yet been told the queen is alive (belief: UNAWARE); the passage shows him acting on that knowledge. See Belief vs Fact.
belief_forgottenBelief — forgottenThe character’s belief state at this story position is BELIEVES_TRUE for the fact, but the action under validation shows ignorance of it.Paired with ConflictType.FORGOTTEN_REVEAL — surfaced in the Knowledge state section of POV-mode validation results.Maren was told the killer’s identity in chapter 3 (belief: BELIEVES_TRUE); the passage in chapter 8 has her speculating about who the killer might be. See Belief vs Fact.

A note on spelling

You may notice some codes use hyphens (branch-incompatible, temporal-distance, pov-out-of-scope, state-contradiction) and others use underscores (negation_polarity, epistemic_rumor, belief_unaware). That inconsistency is intentional and historical — the legacy detector path emits hyphenated codes and the newer soft-filter and knowledge-violation paths emit underscored ones. Both spellings are stable parts of the API contract, so we preserve them verbatim rather than normalizing one to the other.

If you’re parsing reason codes in your own tooling, match the exact spelling listed in the table above.

Where reason codes appear

  • Validation findings in the SPA. Each finding’s reason codes show up as a row of small uppercase chips next to the citation. Hover or tap a chip for its short description.
  • The Knowledge state section. Belief vs Fact findings (belief_unaware, belief_forgotten) always carry the matching reason code so you can tell knowledge violations from forgotten reveals at a glance.
  • API responses. Validation results returned by the API include a reason_codes array on each finding — the strings in that array are exactly the codes listed in the table above.
  • Admin debug retrieval. For accounts on the priority Quick Check tier, the admin debug-retrieval payload exposes the per-candidate reason codes from the recall and soft-filter stages, not just the final finding. See quick-check API documentation for the request shape.
  • Validation — how findings are produced and surfaced
  • Belief vs Fact — the belief_unaware and belief_forgotten codes in context, and the Knowledge state section that displays them
  • Canon rules — how rule-level epistemic status (fact, rumor, lie, dream, unreliable_pov) maps onto the epistemic_* reason codes