we-promise/sure · error · Provenance::Citation::InvalidError
source citation does not match #{grammar}
Error message
source citation does not match #{grammar} What it means
Provenance::Citation.parse! raises InvalidError 'source citation does not match ...grammar' when the whole string fails the FORMAT regex: optional 'estimated: ' prefix, then citation text, then optional ' (grade: A|B|C)' suffix. Because earlier checks already handled blank, length, marker, and grade issues, hitting this usually means structural problems such as unbalanced parentheses that confuse the suffix match.
Source
Thrown at app/models/provenance/citation.rb:55
class << self
# Returns a Citation, or raises InvalidError with a message written for the
# caller that has to fix it (an agent, usually).
def parse!(raw)
value = raw.to_s.strip
raise InvalidError, "source citation is required" if value.blank?
raise InvalidError, "source citation must be #{MAX_LENGTH} characters or fewer" if value.length > MAX_LENGTH
if value.match?(ESTIMATED_MARKER) && !value.start_with?(ESTIMATED_PREFIX)
raise InvalidError, "estimated values must start with the exact prefix #{ESTIMATED_PREFIX.inspect}"
end
if (suffix = value.match(GRADE_SUFFIX)) && !GRADES.include?(suffix[:grade])
raise InvalidError, "reliability grade must be one of #{GRADES.join(", ")} (got #{suffix[:grade].inspect})"
end
match = value.match(FORMAT)
raise InvalidError, "source citation does not match #{grammar}" unless match
text = match[:text].to_s.strip
if text.length < MIN_TEXT_LENGTH
raise InvalidError, "source citation must name the document it came from"
end
estimated = match[:estimated].present?
grade = match[:grade]
if estimated && grade.blank?
raise InvalidError, "estimated values must carry a reliability grade, e.g. \"#{ESTIMATED_PREFIX}... (grade: C)\""
end
new(raw: value, text: text, estimated: estimated, grade: grade)
end
def valid?(raw)
parse!(raw)View on GitHub (pinned to e69894adb9)
Solutions
- Simplify to: document name, optionally ' (grade: X)' at the very end, e.g. 'Audited report 2025, p.12 (grade: B)'.
- Remove or balance parentheses that are not the grade suffix.
- Print Provenance::Citation.grammar in error output so the caller can self-correct: ["estimated: "] citation [" (grade: A|B|C)"].
- Round-trip check: parse, then to_s, then parse again.
Example fix
# before
Provenance::Citation.parse!("Payroll summary (Q1 (grade: B)")
# after
Provenance::Citation.parse!("Payroll summary Q1 (grade: B)") Defensive patterns
Strategy: try-catch
Validate before calling
Provenance::Citation.valid?(value)
Try / catch
begin Provenance::Citation.parse!(source) rescue Provenance::Citation::InvalidError => e # e.message embeds Provenance::Citation.grammar; surface it for self-correction correct_and_retry(source, e.message) end
Prevention
- Avoid stray parentheses in document names; reserve '(grade: X)' for the suffix.
- Echo the grammar in agent prompts and validation messages.
- Round-trip test: parse!(parsed.to_s) should succeed.
When it happens
Trigger: Citation like 'Statement (unaudited' (unbalanced paren), 'Doc ((grade: A))', trailing ')', or a string whose only content is consumed leaving no text; also text consisting solely of a grade suffix.
Common situations: Parentheses in the document name interacting with the grade suffix; agent output with stray parens; markdown emphasis leaking in.
Related errors
- source citation is required
- source citation must be #{MAX_LENGTH} characters or fewer
- estimated values must start with the exact prefix #{ESTIMATE
- reliability grade must be one of #{GRADES.join(", ")} (got #
- source citation must name the document it came from
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/dd408805e3984e8c.
Report an issue: GitHub.