{"record":{"id":"22e381b55d31375d","repo":"we-promise/sure","slug":"estimated-values-must-carry-a-reliability-grade-e","errorCode":null,"errorMessage":"estimated values must carry a reliability grade, e.g. \"#{ESTIMATED_PREFIX}... (grade: C)\"","messagePattern":"estimated values must carry a reliability grade, e\\.g\\. \"#(.+?)\\.\\.\\. \\(grade: C\\)\"","errorType":"exception","errorClass":"Provenance::Citation::InvalidError","httpStatus":null,"severity":"error","filePath":"app/models/provenance/citation.rb","lineNumber":66,"sourceCode":"        end\n\n        if (suffix = value.match(GRADE_SUFFIX)) && !GRADES.include?(suffix[:grade])\n          raise InvalidError, \"reliability grade must be one of #{GRADES.join(\", \")} (got #{suffix[:grade].inspect})\"\n        end\n\n        match = value.match(FORMAT)\n        raise InvalidError, \"source citation does not match #{grammar}\" unless match\n\n        text = match[:text].to_s.strip\n        if text.length < MIN_TEXT_LENGTH\n          raise InvalidError, \"source citation must name the document it came from\"\n        end\n\n        estimated = match[:estimated].present?\n        grade = match[:grade]\n\n        if estimated && grade.blank?\n          raise InvalidError, \"estimated values must carry a reliability grade, e.g. \\\"#{ESTIMATED_PREFIX}... (grade: C)\\\"\"\n        end\n\n        new(raw: value, text: text, estimated: estimated, grade: grade)\n      end\n\n      def valid?(raw)\n        parse!(raw)\n        true\n      rescue InvalidError\n        false\n      end\n\n      def grammar\n        %([\"#{ESTIMATED_PREFIX}\"] citation [\" (grade: #{GRADES.join(\"|\")})\"])\n      end\n    end\n\n    def initialize(raw:, text:, estimated:, grade:)","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provenance/citation.rb#L48-L84","documentation":"Provenance::Citation.parse! raises InvalidError when the citation carries the 'estimated: ' prefix but no grade suffix: estimates must end with ' (grade: A|B|C)'. Grades encode reliability (C is a proxy that should be re-derived later), so an estimate without one cannot age out or be triaged. The error message embeds a copy-pasteable example.","triggerScenarios":"Citations like 'estimated: interpolated from anchors' with no suffix, or where the suffix failed to capture (e.g. '(Grade: C)' with capital G does not match FORMAT's '(grade:' literal, leaving grade nil).","commonSituations":"Agent told to mark estimates but not grades; human capitalizing 'Grade:'; suffix typo after earlier normalization.","solutions":["Append a grade suffix: 'estimated: interpolated from 2024 anchors (grade: C)'.","Use lowercase 'grade:' exactly — '(Grade: C)' will not capture.","If unsure of reliability, default to C (the designated proxy grade).","Validate with Provenance::Citation.valid? and prompt the caller with the example from the message."],"exampleFix":"# before\nProvenance::Citation.parse!(\"estimated: interpolated from 2024 anchors\")\n\n# after\nProvenance::Citation.parse!(\"estimated: interpolated from 2024 anchors (grade: C)\")","handlingStrategy":"validation","validationCode":"v = value.to_s\n!v.start_with?(\"estimated: \") || v =~ /\\(grade:\\s*[ABC]\\)\\s*\\z/","typeGuard":"def estimated_has_grade?(v)\n  v = v.to_s.strip\n  !v.start_with?(Provenance::Citation::ESTIMATED_PREFIX) || v.match?(/\\(grade:\\s*[ABC]\\)\\s*\\z/)\nend","tryCatchPattern":"begin\n  Provenance::Citation.parse!(source)\nrescue Provenance::Citation::InvalidError => e\n  errors.add(:source, e.message) # message contains a valid example to copy\nend","preventionTips":["Whenever a value is estimated, require 'estimated: ' prefix AND ' (grade: A|B|C)' suffix in prompts.","Default uncertain reliability to grade C.","Use lowercase 'grade:' exactly."],"tags":["provenance","validation","conditional-required","ruby"],"backgroundTag":"conditional-required-field-missing","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}