{"record":{"id":"1fb3c8a3c43e3dd5","repo":"HKUDS/Vibe-Trading","slug":"evidence-evidence-id-does-not-match-criterion-c","errorCode":null,"errorMessage":"evidence {evidence_id} does not match criterion {criterion.criterion_id}","messagePattern":"evidence (.+?) does not match criterion (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/goal/store.py","lineNumber":924,"sourceCode":"        for criterion in criteria:\n            if not criterion.required:\n                continue\n            row = rows_by_criterion.get(criterion.criterion_id)\n            if row is None:\n                raise ValueError(f\"missing audit row for criterion {criterion.criterion_id}\")\n            if row.result not in _COMPLETION_RESULTS:\n                raise ValueError(f\"criterion {criterion.criterion_id} is not satisfied\")\n            if row.result in {\"satisfied\", \"satisfied_with_caveat\"} and not row.evidence_ids:\n                raise ValueError(\"complete goals require verified evidence\")\n            if row.result == \"not_applicable_user_accepted\" and not row.notes.strip():\n                raise ValueError(\"not-applicable criteria require acceptance notes\")\n            has_verified_evidence = False\n            for evidence_id in row.evidence_ids:\n                evidence = self._get_evidence(evidence_id)\n                if evidence is None or evidence.goal_id != goal.goal_id:\n                    raise ValueError(f\"unknown evidence_id: {evidence_id}\")\n                if evidence.criterion_id != criterion.criterion_id:\n                    raise ValueError(\n                        f\"evidence {evidence_id} does not match criterion {criterion.criterion_id}\"\n                    )\n                if evidence.verification_status == \"verified\":\n                    has_verified_evidence = True\n            if row.result in {\"satisfied\", \"satisfied_with_caveat\"} and not has_verified_evidence:\n                raise ValueError(\"complete goals require verified evidence\")\n\n    def _get_evidence(self, evidence_id: str) -> EvidenceRecord | None:\n        row = self._conn.execute(\n            \"SELECT * FROM goal_evidence WHERE evidence_id = ?\",\n            (evidence_id,),\n        ).fetchone()\n        return self._evidence_from_row(row) if row else None\n\n    @staticmethod\n    def _goal_from_row(row: sqlite3.Row) -> GoalRecord:\n        return GoalRecord(\n            goal_id=row[\"goal_id\"],","sourceCodeStart":906,"sourceCodeEnd":942,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/goal/store.py#L906-L942","documentation":"A cited evidence record exists and belongs to the goal, but its criterion_id differs from the criterion of the audit row citing it. Evidence is scoped per criterion and cannot be reused across criteria in the audit.","triggerScenarios":"update_status where a row for criterion A lists evidence appended against criterion B (same goal).","commonSituations":"Reusing one strong piece of evidence to satisfy multiple criteria; criterion ids shifted after criteria were reordered/recreated.","solutions":["Append criterion-specific evidence for each criterion and cite only matching ids","If the evidence genuinely covers both criteria, append it once per criterion (or restructure criteria)","When building the audit, filter evidence by criterion_id"],"exampleFix":"// before\nAuditRow(criterion_id=\"c1\", result=\"satisfied\", evidence_ids=[ev_for_c2.evidence_id])\n// after\nev_c1 = store.append_evidence(session_id, goal_id, criterion_id=\"c1\", ...)\nAuditRow(criterion_id=\"c1\", result=\"satisfied\", evidence_ids=[ev_c1.evidence_id])","handlingStrategy":"validation","validationCode":"by_crit = {}\nfor e in store.list_evidence(goal_id):\n    by_crit.setdefault(e.criterion_id, []).append(e.evidence_id)\naudit = [AuditRow(criterion_id=cid, result=..., evidence_ids=by_crit.get(cid, [])) for cid in required]","typeGuard":"def evidence_matches_criterion(store, evidence_id: str, criterion_id: str) -> bool:\n    e = store._get_evidence(evidence_id)\n    return e is not None and e.criterion_id == criterion_id","tryCatchPattern":"except ValueError as e: if 'does not match criterion' in str(e): re-map evidence per criterion and retry update_status","preventionTips":["Append evidence with the exact criterion_id it should satisfy","Never reuse one evidence id across criteria","Group evidence by criterion when building audits"],"tags":["goal-store","completion-audit","evidence-criterion-mismatch","python"],"backgroundTag":"foreign-key-mismatch","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}